Skip to main content
ComposableCoW contracts can be deployed using Forge scripts or deterministic CREATE2 deployment for consistent addresses across networks.

Deployment Methods

There are two primary deployment approaches:
  1. Script-based deployment: Fast and flexible for testing or new contract types
  2. Deterministic CREATE2 deployment: Ensures identical addresses across all networks (production method)
Script-based deployment will NOT deploy contracts to the official addresses. Use CREATE2 deployment for production.

Prerequisites

Environment Setup

Copy the example environment file and configure variables:
cp .env.example .env
Required variables:
.env
# RPC endpoint for target network
ETH_RPC_URL=http://your-rpc-endpoint:8545

# Deployer private key
PRIVATE_KEY=your_private_key_here

# GPv2Settlement contract address for the target network
SETTLEMENT=0x9008D19f58AAbD9eD0D60971565AA8510560ab41

# Optional: Etherscan API key for contract verification
ETHERSCAN_API_KEY=your_etherscan_api_key

# Optional: For single order testing
SAFE=your_safe_address
TWAP=0x6cF1e9cA41f7611dEf408122793c358a3d11E5a5
COMPOSABLE_COW=0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74
The SETTLEMENT address varies by network. For Ethereum Mainnet, use 0x9008D19f58AAbD9eD0D60971565AA8510560ab41.

Install Dependencies

Ensure Foundry is installed:
curl -L https://foundry.paradigm.xyz | bash
foundryup

Script-Based Deployment

Deploy Full Production Stack

Deploy all contracts in a single transaction:
source .env
forge script script/deploy_ProdStack.s.sol:DeployProdStack \
  --rpc-url $ETH_RPC_URL \
  --broadcast \
  -vvvv \
  --verify
This deploys:
  • ExtensibleFallbackHandler
  • ComposableCoW
  • Order types: TWAP, GoodAfterTime, PerpetualStableSwap, TradeAboveThreshold, StopLoss
  • Utilities: CurrentBlockTimestampFactory

Deploy Individual Contracts

Deploy ComposableCoW Only

forge script script/deploy_ComposableCoW.s.sol:DeployComposableCoW \
  --rpc-url $ETH_RPC_URL \
  --broadcast \
  -vvvv \
  --verify

Deploy Order Types Only

forge script script/deploy_OrderTypes.s.sol:DeployOrderTypes \
  --rpc-url $ETH_RPC_URL \
  --broadcast \
  -vvvv \
  --verify
For order types deployment, ensure COMPOSABLE_COW is set in your .env file.

Script Details

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import {Script} from "forge-std/Script.sol";
import {ComposableCoW} from "../src/ComposableCoW.sol";
import {TWAP} from "../src/types/twap/TWAP.sol";
import {GoodAfterTime} from "../src/types/GoodAfterTime.sol";
import {PerpetualStableSwap} from "../src/types/PerpetualStableSwap.sol";
import {TradeAboveThreshold} from "../src/types/TradeAboveThreshold.sol";
import {StopLoss} from "../src/types/StopLoss.sol";

contract DeployProdStack is Script {
    function run() external {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        address settlement = vm.envAddress("SETTLEMENT");

        vm.startBroadcast(deployerPrivateKey);

        // Deploy contracts with deterministic salt
        new ExtensibleFallbackHandler{salt: "v1.0.0"}();
        ComposableCoW composableCow = new ComposableCoW{salt: "v1.0.0"}(settlement);
        new TWAP{salt: "v1.0.0"}(composableCow);
        new GoodAfterTime{salt: "v1.0.0"}();
        new PerpetualStableSwap{salt: "v1.0.0"}();
        new TradeAboveThreshold{salt: "v1.0.0"}();
        new StopLoss{salt: "v1.0.0"}();
        new CurrentBlockTimestampFactory{salt: "v1.0.0"}();
    }
}

Deterministic CREATE2 Deployment

For production deployments with consistent addresses across networks:

Process

  1. Find an existing deployment transaction on another network (e.g., ExtensibleFallbackHandler on Mainnet)
  2. Navigate to the transaction and click “Click to show more”
  3. Copy the “Input Data” in Original format
  4. Copy the “to” address
  5. Use a transaction tool (e.g., swiss-knife) to submit the transaction
  6. The contract will be deployed to the same deterministic address
This method ensures all contracts are deployed at the same addresses across networks, as shown in the networks page.

Why Deterministic Deployment?

Benefits of CREATE2 deployment:
  • Consistent addresses across all networks
  • Simplified integration and documentation
  • Predictable contract locations
  • Enhanced user trust through verifiable deployment patterns

Contract Verification

Automatic Verification

Verify all contracts automatically after deployment:
export ETHERSCAN_API_KEY="your_api_key_here"
chain_id=1  # Ethereum Mainnet
dev/verify-contracts.sh "$chain_id"

Manual Verification

If automatic verification fails, use Standard JSON Input:
  1. Locate the verification file in broadcast/StandardJsonInput/
  2. Follow instructions in broadcast/StandardJsonInput/README.md

Verification Requirements

ETHERSCAN_API_KEY=your_key_here

Local Deployment

Deploy to Anvil

For local integration testing with Watch Tower:

1. Start Anvil

anvil --code-size-limit 50000 --block-time 5
The --code-size-limit flag is required when deploying the full stack due to the Balancer Vault contract size.

2. Deploy Stack

source .env
forge script script/deploy_AnvilStack.s.sol:DeployAnvilStack \
  --rpc-url http://127.0.0.1:8545 \
  --broadcast \
  -vvvv
This deploys:
  • CoW Protocol stack (Settlement, Vault, Authentication)
  • Safe contract infrastructure
  • ComposableCoW and order types
  • A test Safe contract
The Safe address will be printed in the deployment output. Save this for testing.

3. Submit Test Order

Create a single test order:
source .env
SAFE="address_from_step_2" forge script script/submit_SingleOrder.s.sol:SubmitSingleOrder \
  --rpc-url http://127.0.0.1:8545 \
  --broadcast

Post-Deployment

Verify Deployment

Check deployed contract code:
cast code 0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74 --rpc-url $ETH_RPC_URL

Update Network Registry

Add deployment addresses to networks.json:
{
  "ComposableCoW": {
    "1": {
      "address": "0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74",
      "transactionHash": "0x..."
    }
  }
}

Broadcast Directory

Deployment artifacts are stored in the broadcast/ directory:
broadcast/
└── deploy_OrderTypes.s.sol/
    └── 1/
        └── run-latest.json
These files contain deployment addresses, transaction hashes, and contract ABIs.

Network-Specific Considerations

Gnosis Chain

Gnosis Chain has a different gas model. Adjust gas parameters if needed:
forge script script/deploy_ProdStack.s.sol:DeployProdStack \
  --rpc-url $GNOSIS_RPC_URL \
  --broadcast \
  --gas-price 2000000000

Layer 2 Networks

For L2s (Arbitrum, Optimism, Base), ensure you’re using the correct RPC endpoint and have sufficient ETH for gas:
# Example for Arbitrum One
ETH_RPC_URL=https://arb1.arbitrum.io/rpc
SETTLEMENT=0x9008D19f58AAbD9eD0D60971565AA8510560ab41

Troubleshooting

Transaction Underpriced

Increase gas price:
forge script <script> --broadcast --gas-price 20000000000

Nonce Too Low

Reset your nonce:
cast nonce $YOUR_ADDRESS --rpc-url $ETH_RPC_URL

Contract Size Exceeded

Enable optimizer in foundry.toml:
optimizer = true
optimizer_runs = 20000

Next Steps

Build docs developers (and LLMs) love