Deploy CCA (Continuous Clearing Auction) smart contracts using the Factory pattern. Use when user says "deploy auction", "deploy cca", "factory deployment", or wants to deploy a configured auction.
Deploy Continuous Clearing Auction (CCA) smart contracts using the ContinuousClearingAuctionFactory with CREATE2 for consistent addresses across chains.
Runtime Compatibility: This skill uses
AskUserQuestionfor interactive prompts. IfAskUserQuestionis not available in your runtime, collect the same parameters through natural language conversation instead.
When the user invokes this skill, guide them through the CCA deployment process with appropriate safety warnings and validation.
forge and cast available)forge script commands with security guidanceonTokensReceived() to activateAlways display this before any deployment steps:
This skill provides educational guidance for deploying CCA smart contracts. Smart contract deployment involves real financial risk. Always:
- Test on testnet first (Sepolia or Base Sepolia)
- Audit your configuration before mainnet deployment
- Never share or expose your private key
- Understand that deployed contracts may be immutable
Ask the user to acknowledge before proceeding.
# NEVER — exposes key in shell history
forge script ... --private-key 0xYOUR_PRIVATE_KEY
# NEVER — key visible in process list
PRIVATE_KEY=0x... forge script ...
Option 1: Hardware wallet (Ledger) — Most Secure
forge script script/Deploy.s.sol \
--rpc-url $RPC_URL \
--ledger \
--broadcast
Option 2: Encrypted keystore
# Import key once
cast wallet import deployer --interactive
# Use in scripts
forge script script/Deploy.s.sol \
--rpc-url $RPC_URL \
--account deployer \
--broadcast
Option 3: Environment variable (testing only)
# In .env file (never commit to git)
PRIVATE_KEY=0x...
# Load and use
source .env
forge script script/Deploy.s.sol \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY \
--broadcast
Always deploy to testnet before mainnet:
| Mainnet | Testnet |
|---|---|
| Ethereum | Sepolia |
| Base | Base Sepolia |
| Arbitrum | Arbitrum Sepolia |
| Unichain | Unichain Sepolia |
The CCA Factory is already deployed at a canonical address. You do not need to deploy the factory.
| Property | Value |
|---|---|
| Factory Version | v1.1.0 |
| Factory Address | 0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5 |
| Deployment Method | CREATE2 (deterministic addresses) |
The factory is deployed on: Ethereum, Base, Arbitrum, Unichain, Sepolia, Unichain Sepolia.
Step 1: Clone the CCA repository
git clone https://github.com/Uniswap/continuous-clearing-auction
cd continuous-clearing-auction
forge install
Step 2: Set environment variables
# .env
RPC_URL=https://mainnet.base.org
FACTORY_ADDRESS=0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5
TOKEN_ADDRESS=0x...
CURRENCY_ADDRESS=0x0000000000000000000000000000000000000000
TOTAL_SUPPLY=100000000000000000000000000
START_BLOCK=24321000
END_BLOCK=24327001
FLOOR_PRICE=7922816251426433759354395000
TICK_SPACING=79228162514264337593543950
Step 3: Deploy via forge script
forge script script/DeployAuction.s.sol \
--rpc-url $RPC_URL \
--account deployer \
--broadcast \
--verify
Step 4: Verify deployment
# Check auction was created
cast call $FACTORY_ADDRESS \
"getAuction(address)(address)" \
$TOKEN_ADDRESS \
--rpc-url $RPC_URL
For direct deployment without the factory:
ContinuousClearingAuction auction = new ContinuousClearingAuction(
token,
totalSupply,
currency,
startBlock,
endBlock,
floorPrice,
tickSpacing,
supplySchedule,
recipients
);
# Verify on Etherscan/Basescan
forge verify-contract \
$AUCTION_ADDRESS \
src/ContinuousClearingAuction.sol:ContinuousClearingAuction \
--chain-id CHAIN_ID \
--etherscan-api-key $ETHERSCAN_API_KEY
After deployment, the token issuer must transfer tokens to the auction contract:
# Transfer tokens to auction contract
cast send $TOKEN_ADDRESS \
"transfer(address,uint256)" \
$AUCTION_ADDRESS \
$TOTAL_SUPPLY \
--rpc-url $RPC_URL \
--account deployer
The auction activates automatically when tokens are received (via onTokensReceived() callback).
Run this checklist before deployment:
startBlock > current block numberendBlock > startBlockendBlock - startBlock == supplySchedule.lengthfloorPrice > 0floorPrice is a multiple of tickSpacingtickSpacing > 0 and < floorPricetotalSupply > 0 (in wei)token is a valid ERC-20 contractcurrency is zero address (ETH) or valid ERC-20All prices use Q96 format: value = human_price * 2^96
Q96 = 2 ** 96 # = 79228162514264337593543950336
# Convert human price to Q96
q96_price = int(human_price * Q96)
# Convert Q96 back to human price
human_price = q96_price / Q96
Each block in [startBlock, endBlock) is one auction step. The supply schedule determines what fraction of totalSupply is available at each step.
| Function | Description |
|---|---|
initializeDistribution(token, amount, params, salt) | Factory: deploy new auction |
onTokensReceived(operator, from, amount, data) | Activate auction after token transfer |
bid(amount) | Place a bid in the auction |
claim() | Claim tokens after auction ends |
withdraw() | Withdraw unsold tokens (issuer only) |
| Network | Chain ID | Factory Address |
|---|---|---|
| Ethereum | 1 | 0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5 |
| Base | 8453 | 0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5 |
| Arbitrum | 42161 | 0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5 |
| Unichain | 130 | 0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5 |
| Sepolia | 11155111 | 0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5 |
| Unichain Sepolia | 1301 | 0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5 |
| Error | Cause | Fix |
|---|---|---|
InvalidBlockRange | endBlock <= startBlock | Recalculate blocks |
InvalidFloorPrice | Floor not multiple of tick | Round floor to tick |
InvalidSupplySchedule | Sum != 1,000,000 | Regenerate schedule |
InsufficientGas | Not enough ETH | Add more ETH to deployer |
TokenTransferFailed | Token not approved | Approve factory first |
Before broadcasting, always simulate first:
forge script script/DeployAuction.s.sol \
--rpc-url $RPC_URL \
--account deployer
# No --broadcast flag = simulation only