# CoW Protocol + MycoFi: Quick Reference Card ## One-Page Overview ### What is CoW? **Intent-based DEX with batch auctions.** Users sign intents (not transactions). Solvers compete to execute batches. MEV-protected. Solvers pay gas. ### Your Integration ``` User Intent (private) ↓ Watch Tower polls ↓ MycoConditionalOrder.getTradeableOrder() ↓ BondingCurveAdapter.quoteBuy/quoteSell ↓ Solver competition ↓ GPv2Settlement.settle() executes ↓ User receives tokens (MEV-safe) ``` --- ## Contract Reference | Contract | Address (Base) | Role | |----------|---|---| | GPv2Settlement | `0x9008D19f...` | Settlement executor | | GPv2VaultRelayer | `0xc92e8bdf...` | Token pull intermediary | | MycoBondingCurve | `0x...` (deploy) | Pricing logic | | BondingCurveAdapter | `0x...` (deploy) | Pre-interaction hook | | MycoConditionalOrder | `0x...` (deploy) | Order type handler | --- ## Key Interfaces ### IConditionalOrder (implement this) ```solidity function getTradeableOrder( address owner, // Safe wallet address sender, // Usually Watch Tower bytes calldata staticInput, // Encoded params bytes calldata offchainInput // Encoded quote + expiry ) external view returns (GPv2Order.Data); function verify(...) external view; // Validation ``` ### GPv2Order.Data (return this) ```solidity struct Data { address sellToken; // USDC for buy address buyToken; // MYCO for buy address receiver; // Order recipient uint256 sellAmount; // Exact input uint256 buyAmount; // Minimum output uint32 validTo; // Expiry timestamp bytes32 appData; // Metadata uint256 feeAmount; // Usually 0 bytes32 kind; // KIND_SELL or KIND_BUY bool partiallyFillable; // Usually false bytes32 sellTokenBalance; // BALANCE_ERC20 bytes32 buyTokenBalance; // BALANCE_ERC20 } ``` --- ## Error Handling ```solidity // In getTradeableOrder(): // Temporary (retry next block) if (quote_expired) revert PollTryNextBlock("Quote expired"); if (insufficient_balance) revert PollTryNextBlock("Balance changed"); // Current state invalid (try later) if (quote_below_minimum) revert OrderNotValid("Quote below min"); // Stop polling (permanent issue) if (handler_misconfigured) revert PollNever("Config error"); ``` --- ## Stateless Handler Pattern ```solidity contract MycoConditionalOrder is IConditionalOrder { // NO state variables (except immutable refs) // All logic is view-only in getTradeableOrder() function getTradeableOrder( address owner, address, bytes calldata staticInput, // Order params bytes calldata offchainInput // Live quote from Watch Tower ) external view returns (GPv2Order.Data memory) { // 1. Decode staticInput (set once at order creation) OrderData memory params = abi.decode(staticInput, (OrderData)); // 2. Decode offchainInput (fresh quote from Watch Tower) OffchainData memory quote = abi.decode(offchainInput, (OffchainData)); // 3. Validate if (block.timestamp > quote.validTo) revert OrderNotValid("Expired"); if (quote.quotedOutput < params.minOutputAmount) revert OrderNotValid("Below min"); // 4. Generate order return GPv2Order.Data({ sellToken: params.direction == BUY ? USDC : MYCO, buyToken: params.direction == BUY ? MYCO : USDC, sellAmount: params.inputAmount, buyAmount: quote.quotedOutput, // From Watch Tower receiver: params.receiver, validTo: quote.validTo, // ... other fields }); } } ``` --- ## Watch Tower Polling Lifecycle ``` Every block (every 2 sec on Base): FOR each handler in registry: FOR each order: staticInput = stored params offchainInput = adapter.quoteBuy() + timestamp TRY getTradeableOrder(owner, sender, static, offchain) ✓ Valid? → Submit to solvers ✗ PollTryNextBlock? → Retry next block ✗ OrderNotValid? → Skip, retry later ✗ PollNever? → Remove from polling offchainInput = BondingCurveAdapter.quoteBuy() Submit to solver network ``` --- ## Token Flow During Settlement ``` Settlement.settle() called by solver: 1. BEFORE INTERACTIONS └─ Nothing (for basic buy/sell) 2. INPUT TRANSFERS (via VaultRelayer) └─ VaultRelayer pulls 500 USDC from user's Vault └─ Transfers to BondingCurveAdapter 3. INTERACTIONS └─ BondingCurveAdapter.executeBuyForCoW(500 USDC, 900 MYCO min) ├─ Calls curve.buy(500 USDC) ├─ Curve mints 1000 MYCO to adapter └─ Returns 1000 to settlement 4. OUTPUT TRANSFERS (via VaultRelayer) └─ VaultRelayer pulls 1000 MYCO from adapter └─ Transfers to user 5. AFTER INTERACTIONS └─ Nothing (for basic buy/sell) Result: User -500 USDC, +1000 MYCO ``` --- ## Critical Security Checklist - [ ] Users approve **Balancer Vault** (NOT Settlement) - [ ] Adapter has `onlySettlement` modifier - [ ] Quote expiry validated (block.timestamp <= quote.validTo) - [ ] Min output enforced (quote.output >= params.minOutputAmount) - [ ] Reentrancy guarded on hook functions - [ ] No permanent state in handler (stateless) - [ ] VaultRelayer can only transfer TO Settlement --- ## MEV Protection Summary | Mechanism | How it Works | |-----------|-------------| | **Private Order Flow** | Intents never in public mempool → Bots can't see you | | **Uniform Clearing Prices** | All USDC→MYCO trades in batch at same price → Order can't be reordered for profit | | **Coincidence of Wants** | Alice ↔ Bob direct match → No AMM slippage → No MEV possible | --- ## Testing Quick Start ```solidity // Test handler returns valid GPv2Order GPv2Order.Data memory order = handler.getTradeableOrder( owner, watchtower, staticInput, offchainInput ); assert(order.buyAmount >= minOutput); assert(order.validTo > block.timestamp); // Test adapter executes correctly usdc.transfer(adapter, 500e6); uint256 mycoOut = adapter.executeBuyForCoW(500e6, 900e18); assert(mycoToken.balanceOf(adapter) >= 900e18); // Test quote functions uint256 quote = adapter.quoteBuy(500e6); assert(quote == curve.calculateBuyReturn(500e6)); ``` --- ## Deployment Checklist Base Mainnet Addresses: ``` ✓ USDC: 0x833589fC4D06F649c466dB920d0135aa6Df1cDEA ✓ GPv2Settlement: 0x9008D19f58AAbD9eD0D60971565AA8510560ab41 ✓ VaultRelayer: 0xc92e8bdf79f0507f65a392b0ab4667716bfe0110 Deploy (in order): 1. MycoToken 2. MycoBondingCurve (set basePrice, coeff, exponent, fee, treasury) 3. BondingCurveAdapter 4. MycoConditionalOrder 5. Register in ComposableCoW (request Watch Tower access) ``` --- ## API Rate Limits ``` Quote requests: 10/second Order submission: 5/second General endpoints: 100/minute ``` --- ## Common Errors & Solutions | Error | Cause | Fix | |-------|-------|-----| | `OrderNotValid("Quote expired")` | Watch Tower quote >30min old | Fetch fresh quote | | `PollTryNextBlock("Insufficient balance")` | User moved tokens | Wait for balance recovery | | `OnlySettlement()` revert | Called adapter directly | Only Settlement can call | | `SlippageExceeded` | Quote < minOutputAmount | Increase minOut or retry | --- ## Links - Docs: https://docs.cow.fi/ - GitHub: https://github.com/cowprotocol/ - SDK: `@cowprotocol/sdk` (npm) - Forum: https://forum.cow.fi/ - API Base: https://api.cow.fi/base/ --- ## Key Metrics to Track ``` Per order: - Quote latency (target <100ms) - Time to execution (target <60s) - Actual price vs quote (should be >=) - Gas paid by solver (should be