### Start Anvil Local Blockchain Source: https://github.com/cowprotocol/composable-cow/blob/main/README.md Start an anvil local blockchain instance with a specified code size limit and block time. Useful for local integration testing. ```bash anvil --code-size-limit 50000 --block-time 5 ``` -------------------------------- ### Configure and Create a TWAP Order Source: https://context7.com/cowprotocol/composable-cow/llms.txt This example demonstrates how to configure and create a Time-Weighted Average Price (TWAP) order. It involves setting parameters like tokens, amounts, timing, and intervals, then registering the order with ComposableCoW. ```solidity import {TWAP, TWAPOrder} from "composable-cow/src/types/twap/TWAP.sol"; // Alice sells 12,000,000 DAI for WETH over 30 days, only during the first 12 hours of each day TWAPOrder.Data memory twapData = TWAPOrder.Data({ sellToken: IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F), // DAI buyToken: IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2), // WETH receiver: address(0), partSellAmount: 400_000e18, // 400,000 DAI per part (12M / 30) minPartLimit: 250e18, // minimum 250 WETH per part t0: 1700000000, // unix start timestamp n: 30, // 30 parts t: 86400, // 1 day interval span: 43200, // only trade first 12 hours of each day (60*60*12) appData: bytes32(0) }); IConditionalOrder.ConditionalOrderParams memory params = IConditionalOrder.ConditionalOrderParams({ handler: IConditionalOrder(0x6cF1e9cA41f7611dEf408122793c358a3d11E5a5), // TWAP mainnet salt: keccak256(abi.encodePacked(block.timestamp, msg.sender)), staticInput: abi.encode(twapData) }); // Approve CoW Protocol vault relayer for total sell amount (30 × 400,000 DAI) DAI.approve(GPv2VaultRelayer, 12_000_000e18); // Register with ComposableCoW (dispatch=true for watch tower auto-discovery) composableCow.create(params, true); ``` -------------------------------- ### Create GoodAfterTime Order Source: https://context7.com/cowprotocol/composable-cow/llms.txt Configures and creates a GoodAfterTime order. This order is valid only after a specified start time and expires at a given end time. An optional price checker can enforce slippage limits. ```solidity import {GoodAfterTime} from "composable-cow/src/types/GoodAfterTime.sol"; GoodAfterTime.Data memory gatData = GoodAfterTime.Data({ sellToken: IERC20(DAI_ADDRESS), buyToken: IERC20(WETH_ADDRESS), receiver: address(0), sellAmount: 50_000e18, // sell 50,000 DAI minSellBalance: 50_000e18, // require Safe to have at least 50,000 DAI startTime: block.timestamp + 1 days, // becomes valid in 24 hours endTime: block.timestamp + 8 days, // expires in 8 days allowPartialFill: false, priceCheckerPayload: "", // empty = no price checker, any buy amount accepted appData: bytes32(0) }); IConditionalOrder.ConditionalOrderParams memory params = IConditionalOrder.ConditionalOrderParams({ handler: IConditionalOrder(0xdaf33924925e03c9cc3a10d434016d6cfad0add5), // GoodAfterTime mainnet salt: keccak256("gat-order-v1"), staticInput: abi.encode(gatData) }); composableCow.create(params, true); // Watch tower calls getTradeableOrderWithSignature with offchainInput = abi.encode(buyAmount) // The buyAmount is proposed by the watch tower based on current market conditions // Before startTime: reverts with PollTryAtEpoch(startTime, "too early") // After startTime: returns a valid order using the off-chain proposed buyAmount ``` -------------------------------- ### Register Order with On-Chain Cabinet Value using createWithContext Source: https://context7.com/cowprotocol/composable-cow/llms.txt Use `createWithContext` to register an order and store a value from an `IValueFactory` in the cabinet. This is useful when the order's start time (`t0`) should be dynamically set from the block timestamp at creation time. ```Solidity import {CurrentBlockTimestampFactory} from "composable-cow/src/value_factories/CurrentBlockTimestampFactory.sol"; CurrentBlockTimestampFactory tsFactory = CurrentBlockTimestampFactory(0x52eD56Da04309Aca4c3FECC595298d80C2f16BAc); // Set t0 = 0 so TWAP.getTradeableOrder reads it from the cabinet at execution time TWAPOrder.Data memory twapData = TWAPOrder.Data({ sellToken: DAI, buyToken: WETH, receiver: address(0), partSellAmount: 100_000e18, minPartLimit: 60e18, t0: 0, // ← will be set from cabinet (block.timestamp at create time) n: 10, t: 3600, // hourly span: 1800, // active only first 30 min of each hour appData: bytes32(0) }); IConditionalOrder.ConditionalOrderParams memory params = IConditionalOrder.ConditionalOrderParams({ handler: IConditionalOrder(address(twapHandler)), salt: keccak256("twap-with-context"), staticInput: abi.encode(twapData) }); // factory.getValue("") returns bytes32(block.timestamp); stored in cabinet[safe][H(params)] composableCow.createWithContext(params, tsFactory, "", true); ``` ```Solidity // Later, TWAP.getTradeableOrder reads: twap.t0 = uint256(composableCow.cabinet(owner, ctx)) ``` -------------------------------- ### ComposableCoW.createWithContext Source: https://context7.com/cowprotocol/composable-cow/llms.txt Registers a single conditional order and stores a context value from an IValueFactory into the cabinet. This is useful for dynamic order parameters like start times based on creation block. ```APIDOC ## ComposableCoW.createWithContext ### Description Registers an order with an associated context value. The context value is sourced from an `IValueFactory` and stored in the cabinet, keyed by the hash of the order parameters. This allows for dynamic parameter setting, such as using the block timestamp as the order's start time (`t0`). ### Method `createWithContext(params, valueFactory, contextData, storeValue)` ### Parameters - **params** (`IConditionalOrder.ConditionalOrderParams` memory) - The parameters defining the conditional order. - **valueFactory** (`IValueFactory`) - An instance of an `IValueFactory` to generate the context value. - **contextData** (`bytes`) - Additional data to be passed to the `valueFactory`. - **storeValue** (`bool`) - If true, the value returned by the `valueFactory` will be stored in the cabinet. ### Request Example ```solidity // Assuming tsFactory and params are already defined composableCow.createWithContext(params, tsFactory, "", true); ``` ### Response - **Success**: The order is registered, and the context value (if `storeValue` is true) is stored in the cabinet. ``` -------------------------------- ### Generate Tradeable Order and Signature with ComposableCoW Source: https://context7.com/cowprotocol/composable-cow/llms.txt Called off-chain by a watch tower to get a ready-to-submit GPv2Order.Data and its EIP-1271 signature. Reverts with polling hints if the condition is not met. Supports Merkle proofs for order batches. ```solidity // Called off-chain by the watch tower (view call, no gas cost): (GPv2Order.Data memory order, bytes memory signature) = composableCow.getTradeableOrderWithSignature( safeAddress, // owner params, // ConditionalOrderParams (handler, salt, staticInput) "", // offchainInput (empty for TWAP) new bytes32[](0) // proof (empty array = single order; non-empty = Merkle proof) ); // Submit to CoW Protocol API: // POST https://api.cow.fi/mainnet/api/v1/orders // { // "sellToken": order.sellToken, // "buyToken": order.buyToken, // "receiver": order.receiver, // "sellAmount": order.sellAmount.toString(), // "buyAmount": order.buyAmount.toString(), // "validTo": order.validTo, // "appData": order.appData, // "feeAmount": "0", // "kind": "sell", // "partiallyFillable": false, // "signingScheme": "eip1271", // "signature": hexlify(signature), // "from": safeAddress // } // For Merkle-based order, pass the proof: bytes32[] memory merkleProof = [sibling0, sibling1]; // Merkle proof for this specific order (order, signature) = composableCow.getTradeableOrderWithSignature( safeAddress, params, "", merkleProof ); ``` -------------------------------- ### Register Merkle Root with Context Value using setRootWithContext Source: https://context7.com/cowprotocol/composable-cow/llms.txt Combines `setRoot` with a value factory call to store the factory's output in `cabinet[owner][bytes32(0)]`. This allows all orders in the Merkle tree with `t0=0` to use the context value, such as the block timestamp, as their start time. ```Solidity // Use the current block timestamp as the TWAP start time for all orders in this Merkle tree composableCow.setRootWithContext( root, proof, tsFactory, "" // no additional data needed by CurrentBlockTimestampFactory ); // cabinet[safeAddress][bytes32(0)] == bytes32(block.timestamp) // All TWAP orders in the tree with t0=0 will read this value as their start time ``` -------------------------------- ### ComposableCoW.getTradeableOrderWithSignature Source: https://context7.com/cowprotocol/composable-cow/llms.txt Called by the watch tower (off-chain) to get a ready-to-submit `GPv2Order.Data` and its EIP-1271 signature. Reverts with polling hints if the condition is not currently met. ```APIDOC ## `ComposableCoW.getTradeableOrderWithSignature` — Generate Discrete Order for Settlement Called by the watch tower (off-chain) to get a ready-to-submit `GPv2Order.Data` and its EIP-1271 signature. Reverts with polling hints if the condition is not currently met. ```solidity // Called off-chain by the watch tower (view call, no gas cost): (GPv2Order.Data memory order, bytes memory signature) = composableCow.getTradeableOrderWithSignature( safeAddress, // owner params, // ConditionalOrderParams (handler, salt, staticInput) "", // offchainInput (empty for TWAP) new bytes32[](0) // proof (empty array = single order; non-empty = Merkle proof) ); // Submit to CoW Protocol API: // POST https://api.cow.fi/mainnet/api/v1/orders // { // "sellToken": order.sellToken, // "buyToken": order.buyToken, // "receiver": order.receiver, // "sellAmount": order.sellAmount.toString(), // "buyAmount": order.buyAmount.toString(), // "validTo": order.validTo, // "appData": order.appData, // "feeAmount": "0", // "kind": "sell", // "partiallyFillable": false, // "signingScheme": "eip1271", // "signature": hexlify(signature), // "from": safeAddress // } // For Merkle-based order, pass the proof: bytes32[] memory merkleProof = [sibling0, sibling1]; // Merkle proof for this specific order (order, signature) = composableCow.getTradeableOrderWithSignature( safeAddress, params, "", merkleProof ); ``` ``` -------------------------------- ### Submit a Single Order on Anvil Source: https://github.com/cowprotocol/composable-cow/blob/main/README.md Simulate the creation of a single order on an anvil local environment. Requires the SAFE address obtained from deployment and the anvil RPC URL. ```bash source .env SAFE="address here" forge script script/submit_SingleOrder.s.sol:SubmitSingleOrder --rpc-url http://127.0.0.1:8545 --broadcast ``` -------------------------------- ### Deploy All Contracts with Forge Script Source: https://github.com/cowprotocol/composable-cow/blob/main/README.md Deploy all production stack contracts using a forge script. Ensure the .env file is sourced and ETH_RPC_URL is set. Includes broadcasting and verification. ```bash source .env forge script script/deploy_ProdStack.s.sol:DeployProdStack --rpc-url $ETH_RPC_URL --broadcast -vvvv --verify ``` -------------------------------- ### Run Forge Tests Source: https://github.com/cowprotocol/composable-cow/blob/main/README.md Execute different combinations of tests using the forge test command. Use `--no-match-test` to exclude specific test types like fork or fuzz tests. ```bash forge test -vvv --no-match-test "fork|[fF]uzz" ``` ```bash forge test -vvv --no-match-test "fork" ``` ```bash forge test -vvv ``` -------------------------------- ### Implement and Set Custom AllowlistGuard Source: https://context7.com/cowprotocol/composable-cow/llms.txt Defines and deploys a custom swap guard that only permits orders to buy from a pre-approved list of tokens. Requires inheriting from BaseSwapGuard. ```solidity import {ISwapGuard} from "composable-cow/src/interfaces/ISwapGuard.sol"; import {ReceiverLock} from "composable-cow/src/guards/ReceiverLock.sol"; import {BaseSwapGuard} from "composable-cow/src/guards/BaseSwapGuard.sol"; // --- Implementing a custom guard --- contract AllowlistGuard is BaseSwapGuard { mapping(address => bool) public allowedBuyTokens; constructor(address[] memory tokens) { for (uint i = 0; i < tokens.length; i++) { allowedBuyTokens[tokens[i]] = true; } } function verify( GPv2Order.Data calldata order, bytes32, // ctx IConditionalOrder.ConditionalOrderParams calldata, bytes calldata // offchainInput ) external view override returns (bool) { // Only allow buying from approved token list return allowedBuyTokens[address(order.buyToken)]; } } AllowlistGuard guard = new AllowlistGuard([WETH_ADDRESS, USDC_ADDRESS]); composableCow.setSwapGuard(guard); // supportsInterface(ISwapGuard.interfaceId) must return true (handled by BaseSwapGuard) ``` -------------------------------- ### ComposableCoW.setRootWithContext Source: https://context7.com/cowprotocol/composable-cow/llms.txt Registers a Merkle root for a batch of orders and stores a context value associated with the root. ```APIDOC ## ComposableCoW.setRootWithContext ### Description Combines the functionality of `setRoot` with `createWithContext`. It registers a Merkle root for a batch of orders and simultaneously stores a context value generated by an `IValueFactory` into a specific cabinet slot associated with the Merkle root. ### Method `setRootWithContext(root, proof, valueFactory, contextData)` ### Parameters - **root** (`bytes32`) - The Merkle root of the conditional orders. - **proof** (`ComposableCoW.Proof memory`) - The Merkle proof data. - **valueFactory** (`IValueFactory`) - An instance of an `IValueFactory` to generate the context value. - **contextData** (`bytes`) - Additional data to be passed to the `valueFactory`. ### Request Example ```solidity // Assuming root, proof, and tsFactory are defined composableCow.setRootWithContext(root, proof, tsFactory, ""); ``` ### Response - **Success**: The Merkle root is registered, and the context value is stored in `cabinet[owner][bytes32(0)]`. ``` -------------------------------- ### Deploy Individual Contracts with Forge Script Source: https://github.com/cowprotocol/composable-cow/blob/main/README.md Deploy specific contracts like ComposableCoW or OrderTypes using forge scripts. Requires sourcing .env and setting ETH_RPC_URL. ```bash # Deploy ComposableCoW forge script script/deploy_ComposableCoW.s.sol:DeployComposableCoW --rpc-url $ETH_RPC_URL --broadcast -vvvv --verify # Deploy order types forge script script/deploy_OrderTypes.s.sol:DeployOrderTypes --rpc-url $ETH_RPC_URL --broadcast -vvvv --verify ``` -------------------------------- ### Deploy Contracts to Anvil with Forge Script Source: https://github.com/cowprotocol/composable-cow/blob/main/README.md Deploy contracts to a local anvil instance using forge script. Specify the anvil RPC URL and omit the --verify flag. ```bash source .env forge script script/deploy_AnvilStack.s.sol:DeployAnvilStack --rpc-url http://127.0.0.1:8545 --broadcast -vvvv ``` -------------------------------- ### Verify Contracts on Block Explorer Source: https://github.com/cowprotocol/composable-cow/blob/main/README.md Verify deployed contracts on a block explorer using a dedicated script. Requires setting the ETHERSCAN_API_KEY and specifying the chain ID. ```bash export ETHERSCAN_API_KEY="your API key here" chain_id=1337 dev/verify-contracts.sh "$chain_id" ``` -------------------------------- ### Generate Forge Coverage Report Source: https://github.com/cowprotocol/composable-cow/blob/main/README.md Generate a summary coverage report for forge tests, excluding fork tests. ```bash forge coverage -vvv --no-match-test "fork" --report summary ``` -------------------------------- ### Register Merkle Root of Conditional Orders using setRoot Source: https://context7.com/cowprotocol/composable-cow/llms.txt Use `setRoot` to commit multiple conditional orders as leaves of a Merkle tree, which is gas-efficient for large batches. The `location` parameter in `ComposableCoW.Proof` determines if proofs are public or private. ```Solidity import {Murky} from "murky/src/Murky.sol"; // off-chain Merkle tree helper // Off-chain: build leaves for 3 conditional orders bytes32 leaf0 = keccak256(bytes.concat(composableCow.hash(params0))); bytes32 leaf1 = keccak256(bytes.concat(composableCow.hash(params1))); bytes32 leaf2 = keccak256(bytes.concat(composableCow.hash(params2))); // Compute Merkle root off-chain (e.g., using Murky or ethers.js MerkleTree) bytes32 root = computeMerkleRoot([leaf0, leaf1, leaf2]); // location = 1 → proofs are emitted in event payload for watch tower indexing // location = 0 → proofs are private (submit manually to CoW Protocol API) ComposableCoW.Proof memory proof = ComposableCoW.Proof({ location: 1, data: abi.encode([ [proof0_sibling], // Merkle proof for params0 [proof1_sibling], // Merkle proof for params1 [proof2_sibling] // Merkle proof for params2 ]) }); // Called from within a Safe transaction composableCow.setRoot(root, proof); // Emits: MerkleRootSet(safeAddress, root, proof) // roots[safeAddress] == root ``` -------------------------------- ### IValueFactory for On-Chain Dynamic Values Source: https://context7.com/cowprotocol/composable-cow/llms.txt Implement `IValueFactory` to inject on-chain derived values, such as block timestamps or oracle prices, into order parameters at creation time. This allows for dynamic, stateless orders. ```Solidity import {IValueFactory} from "composable-cow/src/interfaces/IValueFactory.sol"; import {CurrentBlockTimestampFactory} from "composable-cow/src/value_factories/CurrentBlockTimestampFactory.sol"; // Built-in: returns block.timestamp as bytes32 CurrentBlockTimestampFactory tsFactory = CurrentBlockTimestampFactory(0x52eD56Da04309Aca4c3FECC595298d80C2f16BAc); // Custom factory example: returns current price from an oracle contract OraclePriceFactory is IValueFactory { AggregatorV3Interface public oracle; constructor(AggregatorV3Interface _oracle) { oracle = _oracle; } function getValue(bytes calldata) external view override returns (bytes32) { (, int256 price,,,) = oracle.latestRoundData(); return bytes32(uint256(int256(price))); } } OraclePriceFactory priceFactory = new OraclePriceFactory(ETH_USD_ORACLE); // Store oracle price at order creation time in the cabinet // TWAP or custom handlers can read: composableCow.cabinet(owner, ctx) composableCow.createWithContext(params, priceFactory, "", true); // cabinet[safeAddress][H(params)] == bytes32(currentOraclePrice) ``` -------------------------------- ### Create StopLoss Order Source: https://context7.com/cowprotocol/composable-cow/llms.txt Configures and creates a StopLoss order. Triggers a sell if the sellToken price falls below a strike price, with staleness protection. Ensure oracle addresses and token addresses are correct for your network. ```solidity import {StopLoss} from "composable-cow/src/types/StopLoss.sol"; import {IAggregatorV3Interface} from "composable-cow/src/interfaces/IAggregatorV3Interface.sol"; // Stop loss: sell GNO for USDC if GNO/USD drops below $100 StopLoss.Data memory slData = StopLoss.Data({ sellToken: IERC20(0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb), // GNO (Gnosis Chain) buyToken: IERC20(0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83), // USDC (Gnosis Chain) sellAmount: 1e18, // sell 1 GNO buyAmount: 95e6, // minimum 95 USDC out appData: bytes32(0), receiver: address(0), // send proceeds to Safe isSellOrder: true, isPartiallyFillable: false, validTo: uint32(block.timestamp + 30 days), // order valid for 30 days sellTokenPriceOracle: IAggregatorV3Interface(0x22441d81416430A54336aB28765abd31a792Ad37), // GNO/USD on Gnosis buyTokenPriceOracle: IAggregatorV3Interface(0x6FC2871B6d9A94866B7260896257Fd5b50c09900), // USDC/USD on Gnosis strike: 100e18, // trigger if GNO/USD <= 100 (18 decimal scaled) maxTimeSinceLastOracleUpdate: 3600 // reject if oracle not updated in last hour }); IConditionalOrder.ConditionalOrderParams memory params = IConditionalOrder.ConditionalOrderParams({ handler: IConditionalOrder(0x412c36e5011cd2517016d243a2dfb37f73a242e7), // StopLoss mainnet salt: keccak256("stop-loss-gno-100"), staticInput: abi.encode(slData) }); composableCow.create(params, true); // When GNO/USD falls to or below $100, getTradeableOrderWithSignature returns a valid order // Otherwise it reverts with PollTryNextBlock("strike not reached") ``` -------------------------------- ### Configure PerpetualStableSwap Order Source: https://context7.com/cowprotocol/composable-cow/llms.txt Sets up an order to perpetually rebalance between two tokens, always selling the token held in greater quantity. Ideal for stablecoin liquidity provision. ```solidity import {PerpetualStableSwap} from "composable-cow/src/types/PerpetualStableSwap.sol"; // Perpetually swap between USDC and DAI, maintaining rough parity with a 0.1% spread PerpetualStableSwap.Data memory pssData = PerpetualStableSwap.Data({ tokenA: IERC20(USDC_ADDRESS), // 6 decimals tokenB: IERC20(DAI_ADDRESS), // 18 decimals validityBucketSeconds: 3600, // 1-hour validity buckets halfSpreadBps: 5, // 0.05% half-spread (0.1% round-trip) appData: bytes32(0) }); IConditionalOrder.ConditionalOrderParams memory params = IConditionalOrder.ConditionalOrderParams({ handler: IConditionalOrder(0x519BA24e959E33b3B6220CA98bd353d8c2D89920), // PSS mainnet salt: keccak256("perpetual-stable-swap-v1"), staticInput: abi.encode(pssData) }); composableCow.create(params, true); // If Safe holds 1,100 USDC (= 1,100 DAI equivalent) and 900 DAI: // → sells all 1,100 USDC, expects ≥ 1,100.55 DAI (spread applied) // Decimal normalization handles USDC (6) ↔ DAI (18) conversion automatically ``` -------------------------------- ### Implement EvenBlockOrder: Sell TokenA for TokenB on Even Blocks Source: https://context7.com/cowprotocol/composable-cow/llms.txt This contract implements a custom order type that sells a fixed amount of one token for another, but only when the current block number is even. It requires extending `BaseConditionalOrder` for validation. ```solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; import {BaseConditionalOrder} from "composable-cow/src/BaseConditionalOrder.sol"; import {IConditionalOrder, GPv2Order, IERC20} from "composable-cow/src/BaseConditionalOrder.sol"; /// @dev A custom order: sell a fixed amount of tokenA for tokenB when block.number is even contract EvenBlockOrder is BaseConditionalOrder { struct Data { IERC20 sellToken; IERC20 buyToken; uint256 sellAmount; uint256 minBuyAmount; uint32 validityBucketSeconds; } function getTradeableOrder( address, // owner (unused) address, // sender (unused) bytes32, // ctx (unused) bytes calldata staticInput, bytes calldata // offchainInput (unused) ) public view override returns (GPv2Order.Data memory order) { Data memory data = abi.decode(staticInput, (Data)); // Condition: only trade on even blocks if (block.number % 2 != 0) { revert IConditionalOrder.PollTryNextBlock("waiting for even block"); } order = GPv2Order.Data({ sellToken: data.sellToken, buyToken: data.buyToken, receiver: address(0), sellAmount: data.sellAmount, buyAmount: data.minBuyAmount, validTo: uint32(block.timestamp + data.validityBucketSeconds), appData: bytes32(0), feeAmount: 0, kind: GPv2Order.KIND_SELL, partiallyFillable: false, sellTokenBalance: GPv2Order.BALANCE_ERC20, buyTokenBalance: GPv2Order.BALANCE_ERC20 }); } } ``` -------------------------------- ### ComposableCoW.setRoot Source: https://context7.com/cowprotocol/composable-cow/llms.txt Registers a Merkle root representing a batch of conditional orders. This is a gas-efficient method for committing multiple orders simultaneously. ```APIDOC ## ComposableCoW.setRoot ### Description Commits a Merkle root of multiple conditional orders. This method is gas-efficient for batching orders, as it requires only one on-chain transaction to register the root of a Merkle tree containing many individual orders. ### Method `setRoot(root, proof)` ### Parameters - **root** (`bytes32`) - The Merkle root of the conditional orders. - **proof** (`ComposableCoW.Proof memory`) - The Merkle proof data, including location and sibling hashes, required to validate the root. ### Request Example ```solidity // Assuming root and proof are computed off-chain composableCow.setRoot(root, proof); ``` ### Response - **Success**: The Merkle root is registered. Emits a `MerkleRootSet` event. ``` -------------------------------- ### Compute Conditional Order Hash with ComposableCoW Source: https://context7.com/cowprotocol/composable-cow/llms.txt Pure utility function that returns keccak256(abi.encode(params)), uniquely identifying a ConditionalOrderParams struct. Used as keys in mappings. Checks authorization status and reads cabinet values. ```solidity IConditionalOrder.ConditionalOrderParams memory params = IConditionalOrder.ConditionalOrderParams({ handler: IConditionalOrder(address(twapHandler)), salt: keccak256("unique-salt"), staticInput: abi.encode(twapData) }); bytes32 h = composableCow.hash(params); // h == keccak256(abi.encode(params)) // Check authorization status: bool isAuthorized = composableCow.singleOrders(safeAddress, h); // Read cabinet value: bytes32 storedValue = composableCow.cabinet(safeAddress, h); ``` -------------------------------- ### Configure TradeAboveThreshold Order Source: https://context7.com/cowprotocol/composable-cow/llms.txt Sets up an order to sell an entire token balance to another token when the balance exceeds a specified threshold. Useful for automated treasury management. ```solidity import {TradeAboveThreshold} from "composable-cow/src/types/TradeAboveThreshold.sol"; // Sell entire USDC balance to ETH whenever balance exceeds 10,000 USDC TradeAboveThreshold.Data memory tatData = TradeAboveThreshold.Data({ sellToken: IERC20(USDC_ADDRESS), buyToken: IERC20(WETH_ADDRESS), receiver: address(0), // send to Safe validityBucketSeconds: 900, // 15-minute validity buckets (reduces order spam) threshold: 10_000e6, // 10,000 USDC threshold appData: bytes32(0) }); IConditionalOrder.ConditionalOrderParams memory params = IConditionalOrder.ConditionalOrderParams({ handler: IConditionalOrder(0x812308712a6d1367f437e1c1e4af85c854e1e9f6), // TAT mainnet salt: keccak256("tat-usdc-sweep"), staticInput: abi.encode(tatData) }); composableCow.create(params, true); // When USDC balance >= 10,000: order sells the *entire* USDC balance (not just the excess) // When below threshold: reverts with PollTryNextBlock("balance insufficient") // validityBucketSeconds ensures the same orderUid is returned within a 15-minute window ``` -------------------------------- ### Register a Single Conditional Order with ComposableCoW Source: https://context7.com/cowprotocol/composable-cow/llms.txt Authorizes a single conditional order for the calling Safe. Set `dispatch = true` to emit a `ConditionalOrderCreated` event for watch tower indexing. The order hash can be computed for later reference or removal. ```Solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0; import {IConditionalOrder, ComposableCoW} from "composable-cow/src/ComposableCoW.sol"; import {TWAP, TWAPOrder} from "composable-cow/src/types/twap/TWAP.sol"; import {IERC20} from "cowprotocol/contracts/interfaces/IERC20.sol"; // Deployed addresses (mainnet) ComposableCoW composableCow = ComposableCoW(0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74); TWAP twapHandler = TWAP(0x6cF1e9cA41f7611dEf408122793c358a3d11E5a5); IERC20 DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); IERC20 WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); // Build the TWAP static input: sell 400,000 DAI per day for 30 days TWAPOrder.Data memory twapData = TWAPOrder.Data({ sellToken: DAI, buyToken: WETH, receiver: address(0), // address(0) → proceeds go to Safe itself partSellAmount: 400_000e18, // 400,000 DAI per part minPartLimit: 250e18, // minimum 250 WETH per part t0: block.timestamp, // start immediately n: 30, // 30 parts t: 86400, // 1 part per day span: 0, // no intra-day restriction appData: bytes32(0) }); IConditionalOrder.ConditionalOrderParams memory params = IConditionalOrder.ConditionalOrderParams({ handler: IConditionalOrder(address(twapHandler)), salt: keccak256(abi.encodePacked("my-twap-order-v1")), staticInput: abi.encode(twapData) }); // Called from within a Safe transaction (msg.sender == Safe address) // dispatch = true → emits ConditionalOrderCreated so the watch tower picks it up composableCow.create(params, true); // The order hash can be computed for later reference or removal bytes32 orderHash = composableCow.hash(params); // singleOrders[safeAddress][orderHash] == true ``` -------------------------------- ### ComposableCoW.setSwapGuard Source: https://context7.com/cowprotocol/composable-cow/llms.txt Associates an ISwapGuard contract with the caller (Safe). Every order settlement attempt will call the guard's `verify` function before proceeding. To remove a guard, set it to the zero address. ```APIDOC ## `ComposableCoW.setSwapGuard` — Attach an Order Guard Associates an `ISwapGuard` contract with the caller (Safe). Every order settlement attempt will call the guard's `verify` function before proceeding. ```solidity import {ReceiverLock} from "composable-cow/src/guards/ReceiverLock.sol"; // ReceiverLock only allows orders where receiver == address(0) (ie. proceeds go to Safe itself) ReceiverLock lock = new ReceiverLock(); // Called from within a Safe transaction composableCow.setSwapGuard(lock); // swapGuards[safeAddress] == address(lock) // To remove a guard, set it to the zero address composableCow.setSwapGuard(ISwapGuard(address(0))); ``` ``` -------------------------------- ### ComposableCoW.remove Source: https://context7.com/cowprotocol/composable-cow/llms.txt Cancels a single conditional order by its hash and clears its associated cabinet slot. ```APIDOC ## ComposableCoW.remove ### Description Deauthorizes and cancels a specific conditional order identified by its hash. This action also clears any associated data stored in the order's cabinet slot. ### Method `remove(orderHash)` ### Parameters - **orderHash** (`bytes32`) - The hash of the conditional order to be canceled. ### Request Example ```solidity // Assuming params is defined and its hash is computed bytes32 orderHash = composableCow.hash(params); composableCow.remove(orderHash); ``` ### Response - **Success**: The order is marked as removed, and its cabinet slot is cleared. `singleOrders[safeAddress][orderHash]` becomes false. ``` -------------------------------- ### ComposableCoW.hash Source: https://context7.com/cowprotocol/composable-cow/llms.txt Pure utility function that returns `keccak256(abi.encode(params))`, uniquely identifying a `ConditionalOrderParams` struct. Used as the key in `singleOrders` and `cabinet` mappings. ```APIDOC ## `ComposableCoW.hash` — Compute Conditional Order Hash Pure utility function that returns `keccak256(abi.encode(params))`, uniquely identifying a `ConditionalOrderParams` struct. Used as the key in `singleOrders` and `cabinet` mappings. ```solidity IConditionalOrder.ConditionalOrderParams memory params = IConditionalOrder.ConditionalOrderParams({ handler: IConditionalOrder(address(twapHandler)), salt: keccak256("unique-salt"), staticInput: abi.encode(twapData) }); bytes32 h = composableCow.hash(params); // h == keccak256(abi.encode(params)) // Check authorization status: bool isAuthorized = composableCow.singleOrders(safeAddress, h); // Read cabinet value: bytes32 storedValue = composableCow.cabinet(safeAddress, h); ``` ``` -------------------------------- ### Attach and Remove Order Guard with ComposableCoW Source: https://context7.com/cowprotocol/composable-cow/llms.txt Associates an ISwapGuard contract with a caller (Safe). To remove a guard, set it to the zero address. Ensure ReceiverLock is imported if used. ```solidity import {ReceiverLock} from "composable-cow/src/guards/ReceiverLock.sol"; // ReceiverLock only allows orders where receiver == address(0) (ie. proceeds go to Safe itself) ReceiverLock lock = new ReceiverLock(); // Called from within a Safe transaction composableCow.setSwapGuard(lock); // swapGuards[safeAddress] == address(lock) // To remove a guard, set it to the zero address composableCow.setSwapGuard(ISwapGuard(address(0))); ``` -------------------------------- ### Set ReceiverLock Swap Guard Source: https://context7.com/cowprotocol/composable-cow/llms.txt Configures the Composable COW protocol to use the built-in ReceiverLock guard, ensuring all order settlements send proceeds directly to the Safe. ```solidity import {ISwapGuard} from "composable-cow/src/interfaces/ISwapGuard.sol"; import {ReceiverLock} from "composable-cow/src/guards/ReceiverLock.sol"; import {BaseSwapGuard} from "composable-cow/src/guards/BaseSwapGuard.sol"; // --- Using the built-in ReceiverLock --- ReceiverLock receiverLock = new ReceiverLock(); composableCow.setSwapGuard(receiverLock); // All subsequent order settlements must have order.receiver == address(0) ``` -------------------------------- ### TWAP Data Structure Definition Source: https://github.com/cowprotocol/composable-cow/blob/main/README.md Defines the structure for TWAP orders, specifying tokens, amounts, timing, and limits. Note that the direction of trade is assumed to be a sell order. ```solidity struct Data { IERC20 sellToken; IERC20 buyToken; address receiver; // address(0) if the safe uint256 partSellAmount; // amount to sell in each part uint256 minPartLimit; // minimum buy amount in each part (limit) uint256 t0; uint256 n; uint256 t; uint256 span; } ``` -------------------------------- ### ERC1271Forwarder for Non-Safe Contract Integration Source: https://context7.com/cowprotocol/composable-cow/llms.txt Use this abstract base contract for non-Safe wallets to implement ERC1271 signature validation, allowing them to act as conditional order owners. It forwards `isValidSignature` calls to `composableCow.isValidSafeSignature`. ```Solidity import {ERC1271Forwarder} from "composable-cow/src/ERC1271Forwarder.sol"; import {ComposableCoW, IConditionalOrder} from "composable-cow/src/ComposableCoW.sol"; contract MyTradingVault is ERC1271Forwarder { ComposableCoW public immutable composableCow; constructor(ComposableCoW _composableCow) ERC1271Forwarder(_composableCow) { composableCow = _composableCow; } // Register a conditional order — this vault is the owner function registerOrder( IConditionalOrder.ConditionalOrderParams calldata params ) external onlyOwner { composableCow.create(params, true); } // ERC1271: isValidSignature is inherited from ERC1271Forwarder // It decodes (GPv2Order.Data, PayloadStruct) from `signature` and // delegates to composableCow.isValidSafeSignature // signature format: abi.encode(order, ComposableCoW.PayloadStruct) } ``` ```Solidity // Watch tower calls getTradeableOrderWithSignature(myVaultAddress, params, "", proof) // Returns signature = abi.encode(order, PayloadStruct) ← ERC1271Forwarder format // Submit to CoW API with signingScheme: "eip1271" ``` -------------------------------- ### Cancel Single Conditional Order using remove Source: https://context7.com/cowprotocol/composable-cow/llms.txt Use `remove` to deauthorize a single conditional order by its hash and clear its associated cabinet slot. To cancel a Merkle-based order, you must remove the leaf from the off-chain tree, recompute the root, and call `setRoot` with the new root. ```Solidity // Compute the hash of the order to cancel bytes32 orderHash = composableCow.hash(params); // Called from within a Safe transaction (msg.sender == Safe address) composableCow.remove(orderHash); // singleOrders[safeAddress][orderHash] == false // cabinet[safeAddress][orderHash] == bytes32(0) // To cancel a Merkle-based order: // 1. Remove the leaf from the off-chain Merkle tree // 2. Recompute the new root // 3. Call setRoot with the new root → invalidates all pruned leaves composableCow.setRoot(newRootWithoutCancelledOrder, newProof); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.