COWShed is a user owned ERC1967 proxy deployed at a determininstic
address using create2 with the user address as the salt.
This deterministic deployment allows users to set the proxy address as the receiver for
cowswap orders with pre/post hooks. At the first execution of hooks, the proxy gets deployed
for the user and the hooks are executed.
User signs a EIP712 message for the pre/post hooks which gets validated and only user signed hooks are executed on the user's proxy. This allows users to confidently perform permissioned actions in the hooks like:
- transferring assets from the proxy to someone else.
- use the proxy to add collateral or repay debt on a maker CDP or a aave debt position, etc.
The signed message type looks like:
ExecuteHooks(Call[] calls,bytes32 nonce,uint256 deadline)
Call(address target,uint256 value,bytes callData,bool allowFailure,bool isDelegateCall)
The EOA signatures are expected to be 65 bytes long and to be encoded as abi.encodePacked(r, s, v).
Nonces are used to ensure signed hooks are only executed once and they also allow users to revoke the signed hooks in case they want to. And users must manage them.
The nonces are not constrained to be sequential, so multiple orders with hooks can be executed out of order, but still validated. However, nonces are implemented using a bitmap. And sequential nonces will save some gas.
The system also support smart contracts. In case of contracts, EIP1271 signatures are used to authenticate the signed hooks.
As cow-shed makes use of determinstic deployment, it has the same deployment address across all EVM-compatible chains. The contracts are deployed to the following addresses.
To run all the tests, execute the following command:
forge testTwo examples are included for reference:
./examples/mintDaiAndSwap.ts- In this example, the user approves the proxy contract to take actions on its behalf on the maker protocol and uses prehooks to just-in-time(JIT) borrow DAI right before the DAI gets swapped to COW../examples/swapAndBridge.ts- In this example, the user uses the proxy address as the receiver for the swapped tokens and in the posthook it bridges the exact amount of swap output(weiroll is used for this) to gnosis chain with user's address as the recipient../examples/claimAndSwap.ts- In this example, the user claims WETH from a Llama Pay vesting contract using a prehook right before swapping it to COW.
The examples can be ran as follows:
yarn ts-node examples/<example.ts>forge buildYou can simulate the deployment on a network where the contracts aren't present yet with the following command.
forge script 'script/Deploy.s.sol:DeployScript' --sig "run()" --rpc-url "$RPC_URL" -vvvvIf running on a network where the contracts are already deployed, the script is expected to revert.
You can also run the script without the --rpc-url parameter to see the expected deployment addresses.
The deployment consists of two steps: deploying verified contract code on-chain and saving the compiler standard JSON input.
forge script 'script/Deploy.s.sol:DeployScript' --sig "run()" --rpc-url "$RPC_URL" -vvvv --private-key "$PK" --broadcastexport ETHERSCAN_API_KEY='your API key here' # required only for etherscan based explorers
forge verify-contract --verifier etherscan --watch --rpc-url "$RPC_URL" 0x62d3a7ff48f9ae1c28a9552a055482f8c63787f8 COWShed --guess-constructor-args
forge verify-contract --verifier etherscan --watch --rpc-url "$RPC_URL" 0x4f4350bf2c74aacd508d598a1ba94ef84378793d COWShedFactory --guess-constructor-args
forge verify-contract --verifier etherscan --watch --rpc-url "$RPC_URL" 0x6773d5aa31a1ead34127d564d6e258e66254ebdb COWShedForComposableCoW --guess-constructor-argsIf this doesn't work, visit the block explorer web interface for each of the deployed contract and manually verify through the interface.
Choose "standard JSON input" as the verification method and use the files from dev/standard-json-input.
After successfully deploying the contracts, a deployment file is automatically generated in the broadcast/Deploy.s.sol/ directory under the relevant chain subdirectory. Make sure to commit this file to the repository.
The file networks.json lists all official deployments of the contracts in this repository by chain id.
This file is generated automatically using the broadcast files in the broadcast/ directory.
Most of the deployments are done using the forge script as described in this README, however, some networks might be deployed in some other way (like replaying the creation code and constructor arguments). For these, we will need to manually update the file broadcast/networks-manual.json.
To regenerate the file after a new deployment, run the following command:
bash dev/generate-networks-file.sh > networks.jsonThis is normally not necessary if deploying a contract to the same deterministic address of a previous deployment but it may be necessary if part of the contract code changed.
The standard JSON input files can be updated with the following command:
bash dev/generate-solc-standard-input.sh