npx skills add https://github.com/uniswap/uniswap-ai --skill deployer使用 ContinuousClearingAuctionFactory 部署连续清算拍卖(CCA)智能合约,利用 CREATE2 实现在不同链上地址一致。
运行时兼容性说明: 此技能使用
AskUserQuestion进行交互式提示。如果您的运行时环境中AskUserQuestion不可用,请通过自然语言对话收集相同的参数。
当用户调用此技能时,引导他们完成 CCA 部署流程,并提供适当的安全警告和验证。
在继续部署之前,您必须:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
重要提示:在继续部署之前,您必须确认:
此工具及所有部署说明仅用于教育目的。AI 生成的部署命令可能包含错误或安全漏洞。
您必须:
在继续执行部署步骤之前,使用 AskUserQuestion 来确认用户已了解这些警告。
在将任何用户提供的值插入到 forge/cast 命令或部署脚本之前:
^0x[a-fA-F0-9]{40}$ — 否则拒绝^[0-9]+\.?[0-9]*$;, |, &, $, ```, (, ), >, <, \, ', ", 换行符请勿在您的 Claude Code 设置中自动批准 Bash(forge:*) 或 Bash(cast:*)。 对于消耗 Gas 或广播交易的命令,始终要求每次调用都需批准。.claude/hooks/ 中的 PreToolUse 钩子提供了程序化验证作为安全网,但每次命令的用户批准是主要控制手段。
关键提示:安全处理私钥对于安全部署至关重要。
--private-key 标志(已被 PreToolUse 钩子阻止)使用 Ledger 或 Trezor 硬件钱包配合 --ledger 标志:
forge script script/Example.s.sol:ExampleScript \
--rpc-url $RPC_URL \
--broadcast \
--ledger
使用 cast wallet import 创建加密密钥库:
# 将私钥导入到加密密钥库(一次性设置)
cast wallet import deployer --interactive
# 使用密钥库进行部署
forge script script/Example.s.sol:ExampleScript \
--rpc-url $RPC_URL \
--broadcast \
--account deployer \
--sender $DEPLOYER_ADDRESS
如果使用环境变量,请确保它们:
.env 文件中(切勿提交到 git)source .env 或 dotenv 加载示例:
# .env 文件(添加到 .gitignore)
PRIVATE_KEY=0x...
RPC_URL=https://...
# 加载环境变量
source .env
# 部署(使用加密密钥库而非 --private-key)
cast wallet import deployer --interactive
forge script ... --account deployer --sender $DEPLOYER_ADDRESS
在部署到主网之前,务必先在测试网上测试:
CCA 实例通过 ContinuousClearingAuctionFactory 合约部署,该合约使用 CREATE2 实现跨链地址一致性。
| 版本 | 地址 | 状态 |
|---|---|---|
| v1.1.0 | 0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5 | 推荐 |
如果您本地还没有 CCA 合约,请克隆仓库并安装依赖:
git clone https://github.com/Uniswap/continuous-clearing-auction.git
cd continuous-clearing-auction
forge install
这将使您可以访问后续步骤中引用的部署脚本、合约 ABI 和测试辅助工具。
确保您有一个有效的配置文件(通过 configurator 技能生成或手动创建)。
配置文件结构示例:
{
"1": {
"token": "0x...",
"totalSupply": 1e29,
"currency": "0x0000000000000000000000000000000000000000",
"tokensRecipient": "0x...",
"fundsRecipient": "0x...",
"startBlock": 24321000,
"endBlock": 24327001,
"claimBlock": 24327001,
"tickSpacing": 79228162514264337593543950,
"validationHook": "0x0000000000000000000000000000000000000000",
"floorPrice": 7922816251426433759354395000,
"requiredCurrencyRaised": 0,
"supplySchedule": [
{ "mps": 1000, "blockDelta": 6000 },
{ "mps": 4000000, "blockDelta": 1 }
]
}
}
在部署之前,验证配置是否通过所有验证规则(参见验证规则部分)。
工厂有一个简单的接口:
function initializeDistribution(
address token,
uint256 amount,
bytes calldata configData,
bytes32 salt
) external returns (IDistributionContract);
其中:
token:要出售的代币地址amount:拍卖中要出售的代币数量configData:ABI 编码的 AuctionParameters 结构体salt:用于自定义地址挖掘的可选 bytes32 值工厂的 initializeDistribution 期望 configData 是 ABI 编码的 AuctionParameters。将您的 JSON 配置转换为编码字节:
使用 cast(Foundry CLI):
# 编码 AuctionParameters 结构体
cast abi-encode "initializeDistribution(address,uint256,bytes,bytes32)" \
"$TOKEN_ADDRESS" \
"$TOTAL_SUPPLY" \
"$(cast abi-encode "(address,address,address,uint64,uint64,uint64,uint256,address,uint256,uint128,bytes)" \
"$CURRENCY" \
"$TOKENS_RECIPIENT" \
"$FUNDS_RECIPIENT" \
"$START_BLOCK" \
"$END_BLOCK" \
"$CLAIM_BLOCK" \
"$TICK_SPACING" \
"$VALIDATION_HOOK" \
"$FLOOR_PRICE" \
"$REQUIRED_CURRENCY_RAISED" \
"$ENCODED_SUPPLY_SCHEDULE")" \
"0x0000000000000000000000000000000000000000000000000000000000000000"
使用 Foundry 脚本:
// script/DeployAuction.s.sol
pragma solidity ^0.8.24;
import "forge-std/Script.sol";
interface ICCAFactory {
function initializeDistribution(
address token,
uint256 amount,
bytes calldata configData,
bytes32 salt
) external returns (address);
}
contract DeployAuction is Script {
function run() external {
// 加载配置值
address token = vm.envAddress("TOKEN");
uint256 amount = vm.envUint("TOTAL_SUPPLY");
// 编码 AuctionParameters
bytes memory configData = abi.encode(
vm.envAddress("CURRENCY"),
vm.envAddress("TOKENS_RECIPIENT"),
vm.envAddress("FUNDS_RECIPIENT"),
uint64(vm.envUint("START_BLOCK")),
uint64(vm.envUint("END_BLOCK")),
uint64(vm.envUint("CLAIM_BLOCK")),
vm.envUint("TICK_SPACING"),
vm.envAddress("VALIDATION_HOOK"),
vm.envUint("FLOOR_PRICE"),
uint128(vm.envUint("REQUIRED_CURRENCY_RAISED")),
vm.envBytes("ENCODED_SUPPLY_SCHEDULE")
);
vm.startBroadcast();
// 批准代币转移到工厂
IERC20(token).approve(
0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5,
amount
);
// 部署拍卖
address auction = ICCAFactory(
0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5
).initializeDistribution(
token,
amount,
configData,
bytes32(0) // salt
);
vm.stopBroadcast();
console.log("Auction deployed at:", auction);
}
}
重要提示: 在调用 initializeDistribution 之前,您必须批准代币转移到工厂。工厂会将 amount 数量的代币从您的地址转移到新创建的拍卖合约。
# 部署工厂(如果在新网络上需要)
forge script script/deploy/DeployContinuousAuctionFactory.s.sol:DeployContinuousAuctionFactoryScript \
--rpc-url $RPC_URL \
--broadcast \
--account deployer --sender $DEPLOYER_ADDRESS
# 部署拍卖实例
forge script script/Example.s.sol:ExampleScript \
--rpc-url $RPC_URL \
--broadcast \
--account deployer --sender $DEPLOYER_ADDRESS
部署后,您必须调用 onTokensReceived() 来通知拍卖代币已转移:
cast send $AUCTION_ADDRESS "onTokensReceived()" --rpc-url $RPC_URL --account deployer --sender $DEPLOYER_ADDRESS
这是拍卖能够接受出价的必要前提条件。
您也可以通过构造函数直接部署:
constructor(
address token,
uint128 amount,
AuctionParameters memory parameters
) {}
这种方法不需要 salt 参数,但无法受益于 CREATE2 的确定性寻址。
生成用于验证的标准 JSON 输入:
forge verify-contract $AUCTION_ADDRESS \
src/ContinuousClearingAuction.sol:ContinuousClearingAuction \
--rpc-url $RPC_URL \
--show-standard-json-input > standard-json-input.json
将此文件上传到区块浏览器进行验证。
部署前,请确保:
startBlock < endBlock <= claimBlock拍卖使用 Q96 定点算术:
library FixedPoint96 {
uint8 internal constant RESOLUTION = 96;
uint256 internal constant Q96 = 0x1000000000000000000000000; // 2^96
}
步骤被打包成字节,每个步骤是一个 uint64:
mps(每区块发行率,以 MPS 为单位)blockDelta(区块数量)function parse(bytes8 data) internal pure returns (uint24 mps, uint40 blockDelta) {
mps = uint24(bytes3(data));
blockDelta = uint40(uint64(data));
}
数据被部署到一个外部的 SSTORE2 合约中以实现更便宜的读取。
用户提交出价,参数包括:
maxPrice:愿意支付的最高价格(Q96)amount:出价的货币数量owner:接收代币/退款的地址prevTickPrice:用于 Gas 优化的提示hookData:验证钩子的可选数据每次有新出价时,拍卖会进行一次区块检查点。检查点决定代币分配。
当出价被超越或拍卖结束时(仅在毕业后),可以退出出价。
如果 currencyRaised >= requiredCurrencyRaised 则返回 true。毕业前不能退出任何出价。
在 claimBlock 之后(仅适用于已毕业的拍卖),用户领取购买到的代币。
拍卖结束后:
sweepCurrency():提取筹集的货币(仅限已毕业)sweepUnsoldTokens():提取未售出的代币CCA 已部署到选定 EVM 链的规范地址:
| 链 ID | 网络 | 出块时间 |
|---|---|---|
| 1 | Mainnet | 12s |
| 130 | Unichain | 1s |
| 1301 | Unichain Sepolia | 2s |
| 8453 | Base | 2s |
| 42161 | Arbitrum | 2s |
| 11155111 | Sepolia | 12s |
| 问题 | 解决方案 |
|---|---|
| "无效的区块序列" | 确保 startBlock < endBlock <= claimBlock |
| "底价未对齐" | 将底价四舍五入为 tick spacing 的倍数 |
| "Tick spacing 太小" | 使用至少为底价 1% 的值 |
| "总供应量太大" | 最大 1e30 wei(1 万亿 18 位小数代币) |
| "Gas 效率低" | 增加 tick spacing |
| "无效地址" | 验证地址是否为以 0x 开头的 42 个字符 |
部署前:
onTokensReceived()docs/TechnicalDocumentation.mddocs/DeploymentGuide.mddocs/assets/whitepaper.pdfdocs/audits/README.md每周安装次数
279
仓库
GitHub 星标数
185
首次出现
2026年2月12日
安全审计
安装于
codex265
opencode265
gemini-cli261
github-copilot259
cursor259
kimi-cli256
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.
Before proceeding with deployment, you MUST:
IMPORTANT: Before proceeding with deployment, you must acknowledge:
This tool and all deployment instructions are provided for educational purposes only. AI-generated deployment commands may contain errors or security vulnerabilities.
You must:
Use AskUserQuestion to confirm the user acknowledges these warnings before proceeding with deployment steps.
Before interpolating ANY user-provided value into forge/cast commands or deployment scripts:
^0x[a-fA-F0-9]{40}$ — reject otherwise^[0-9]+\.?[0-9]*$;, |, &, $, ```, (, ), >, <, , , , newlinesDo NOT auto-approveBash(forge:*) or Bash(cast:*) in your Claude Code settings. Always require per-invocation approval for commands that spend gas or broadcast transactions. The PreToolUse hooks in .claude/hooks/ provide programmatic validation as a safety net, but user approval per command is the primary control.
CRITICAL: Handling private keys safely is essential for secure deployments.
--private-key flag (blocked by PreToolUse hook)Use Ledger or Trezor hardware wallets with the --ledger flag:
forge script script/Example.s.sol:ExampleScript \
--rpc-url $RPC_URL \
--broadcast \
--ledger
Create an encrypted keystore with cast wallet import:
# Import private key to encrypted keystore (one-time setup)
cast wallet import deployer --interactive
# Use keystore for deployment
forge script script/Example.s.sol:ExampleScript \
--rpc-url $RPC_URL \
--broadcast \
--account deployer \
--sender $DEPLOYER_ADDRESS
If using environment variables, ensure they are:
.env file (never committed to git)source .env or dotenvExample:
# .env file (add to .gitignore)
PRIVATE_KEY=0x...
RPC_URL=https://...
# Load environment
source .env
# Deploy (use encrypted keystore instead of --private-key)
cast wallet import deployer --interactive
forge script ... --account deployer --sender $DEPLOYER_ADDRESS
Always test on testnets before mainnet:
CCA instances are deployed via the ContinuousClearingAuctionFactory contract, which uses CREATE2 for consistent addresses across chains.
| Version | Address | Status |
|---|---|---|
| v1.1.0 | 0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5 | Recommended |
If you don't already have the CCA contracts locally, clone the repository and install dependencies:
git clone https://github.com/Uniswap/continuous-clearing-auction.git
cd continuous-clearing-auction
forge install
This gives you access to the deployment scripts, contract ABIs, and test helpers referenced in later steps.
Ensure you have a valid configuration file (generated via the configurator skill or manually created).
Example configuration file structure:
{
"1": {
"token": "0x...",
"totalSupply": 1e29,
"currency": "0x0000000000000000000000000000000000000000",
"tokensRecipient": "0x...",
"fundsRecipient": "0x...",
"startBlock": 24321000,
"endBlock": 24327001,
"claimBlock": 24327001,
"tickSpacing": 79228162514264337593543950,
"validationHook": "0x0000000000000000000000000000000000000000",
"floorPrice": 7922816251426433759354395000,
"requiredCurrencyRaised": 0,
"supplySchedule": [
{ "mps": 1000, "blockDelta": 6000 },
{ "mps": 4000000, "blockDelta": 1 }
]
}
}
Before deployment, verify the configuration passes all validation rules (see Validation Rules section).
The factory has a simple interface:
function initializeDistribution(
address token,
uint256 amount,
bytes calldata configData,
bytes32 salt
) external returns (IDistributionContract);
Where:
token: Address of the token to be soldamount: Amount of tokens to sell in the auctionconfigData: ABI-encoded AuctionParameters structsalt: Optional bytes32 value for vanity address miningThe factory's initializeDistribution expects configData as ABI-encoded AuctionParameters. Convert your JSON config to encoded bytes:
Using cast (Foundry CLI):
# Encode the AuctionParameters struct
cast abi-encode "initializeDistribution(address,uint256,bytes,bytes32)" \
"$TOKEN_ADDRESS" \
"$TOTAL_SUPPLY" \
"$(cast abi-encode "(address,address,address,uint64,uint64,uint64,uint256,address,uint256,uint128,bytes)" \
"$CURRENCY" \
"$TOKENS_RECIPIENT" \
"$FUNDS_RECIPIENT" \
"$START_BLOCK" \
"$END_BLOCK" \
"$CLAIM_BLOCK" \
"$TICK_SPACING" \
"$VALIDATION_HOOK" \
"$FLOOR_PRICE" \
"$REQUIRED_CURRENCY_RAISED" \
"$ENCODED_SUPPLY_SCHEDULE")" \
"0x0000000000000000000000000000000000000000000000000000000000000000"
Using a Foundry Script:
// script/DeployAuction.s.sol
pragma solidity ^0.8.24;
import "forge-std/Script.sol";
interface ICCAFactory {
function initializeDistribution(
address token,
uint256 amount,
bytes calldata configData,
bytes32 salt
) external returns (address);
}
contract DeployAuction is Script {
function run() external {
// Load config values
address token = vm.envAddress("TOKEN");
uint256 amount = vm.envUint("TOTAL_SUPPLY");
// Encode AuctionParameters
bytes memory configData = abi.encode(
vm.envAddress("CURRENCY"),
vm.envAddress("TOKENS_RECIPIENT"),
vm.envAddress("FUNDS_RECIPIENT"),
uint64(vm.envUint("START_BLOCK")),
uint64(vm.envUint("END_BLOCK")),
uint64(vm.envUint("CLAIM_BLOCK")),
vm.envUint("TICK_SPACING"),
vm.envAddress("VALIDATION_HOOK"),
vm.envUint("FLOOR_PRICE"),
uint128(vm.envUint("REQUIRED_CURRENCY_RAISED")),
vm.envBytes("ENCODED_SUPPLY_SCHEDULE")
);
vm.startBroadcast();
// Approve token transfer to factory
IERC20(token).approve(
0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5,
amount
);
// Deploy auction
address auction = ICCAFactory(
0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5
).initializeDistribution(
token,
amount,
configData,
bytes32(0) // salt
);
vm.stopBroadcast();
console.log("Auction deployed at:", auction);
}
}
Important: You must approve the token transfer to the factory before calling initializeDistribution. The factory will transfer amount tokens from your address to the newly created auction contract.
# Deploy factory (if needed on new network)
forge script script/deploy/DeployContinuousAuctionFactory.s.sol:DeployContinuousAuctionFactoryScript \
--rpc-url $RPC_URL \
--broadcast \
--account deployer --sender $DEPLOYER_ADDRESS
# Deploy auction instance
forge script script/Example.s.sol:ExampleScript \
--rpc-url $RPC_URL \
--broadcast \
--account deployer --sender $DEPLOYER_ADDRESS
After deployment, you must call onTokensReceived() to notify the auction that tokens have been transferred:
cast send $AUCTION_ADDRESS "onTokensReceived()" --rpc-url $RPC_URL --account deployer --sender $DEPLOYER_ADDRESS
This is a required prerequisite before the auction can accept bids.
You can also deploy directly via the constructor:
constructor(
address token,
uint128 amount,
AuctionParameters memory parameters
) {}
This approach doesn't require a salt parameter but won't benefit from CREATE2's deterministic addressing.
Generate standard JSON input for verification:
forge verify-contract $AUCTION_ADDRESS \
src/ContinuousClearingAuction.sol:ContinuousClearingAuction \
--rpc-url $RPC_URL \
--show-standard-json-input > standard-json-input.json
Upload this file to block explorers for verification.
Before deployment, ensure:
startBlock < endBlock <= claimBlockThe auction uses Q96 fixed-point arithmetic:
library FixedPoint96 {
uint8 internal constant RESOLUTION = 96;
uint256 internal constant Q96 = 0x1000000000000000000000000; // 2^96
}
Steps are packed into bytes, where each step is a uint64:
First 24 bits: mps (per-block issuance rate in MPS)
Last 40 bits: blockDelta (number of blocks)
function parse(bytes8 data) internal pure returns (uint24 mps, uint40 blockDelta) { mps = uint24(bytes3(data)); blockDelta = uint40(uint64(data)); }
The data is deployed to an external SSTORE2 contract for cheaper reads.
Users submit bids with:
maxPrice: Maximum price willing to pay (Q96)amount: Currency amount to bidowner: Address to receive tokens/refundsprevTickPrice: Hint for gas optimizationhookData: Optional data for validation hooksAuction is checkpointed once per block with a new bid. Checkpoints determine token allocations.
Bids can be exited when outbid or when auction ends (only after graduation).
Returns true if currencyRaised >= requiredCurrencyRaised. No bids can exit before graduation.
Users claim purchased tokens after claimBlock (only for graduated auctions).
After auction ends:
sweepCurrency(): Withdraw raised currency (graduated only)sweepUnsoldTokens(): Withdraw unsold tokensCCA is deployed to canonical addresses across select EVM chains:
| Chain ID | Network | Block Time |
|---|---|---|
| 1 | Mainnet | 12s |
| 130 | Unichain | 1s |
| 1301 | Unichain Sepolia | 2s |
| 8453 | Base | 2s |
| 42161 | Arbitrum | 2s |
| 11155111 | Sepolia | 12s |
| Issue | Solution |
|---|---|
| "Invalid block sequence" | Ensure startBlock < endBlock <= claimBlock |
| "Floor price not aligned" | Round floor price to multiple of tick spacing |
| "Tick spacing too small" | Use at least 1% of floor price |
| "Total supply too large" | Max 1e30 wei (1 trillion 18-decimal tokens) |
| "Gas inefficiency" | Increase tick spacing |
| "Invalid address" | Verify addresses are 42 characters starting with 0x |
Before deployment:
onTokensReceived() called post-deploymentdocs/TechnicalDocumentation.md in repodocs/DeploymentGuide.md in repodocs/assets/whitepaper.pdf in repodocs/audits/README.md in repoWeekly Installs
279
Repository
GitHub Stars
185
First Seen
Feb 12, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
codex265
opencode265
gemini-cli261
github-copilot259
cursor259
kimi-cli256
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
106,200 周安装
批量文档转换工具 - 支持PDF、Word、Markdown等多格式互转,高效处理数百文件
274 周安装
免费在线发票生成器 - 支持多国税费计算与多格式导出
274 周安装
Gmail自动化工作流:附件管理、邮件整理与Google Drive集成 | 7800+ n8n模板
274 周安装
Vibe代码审查工具:AI驱动自动化代码质量与安全审计 | 开发与测试
274 周安装
Open-AutoGLM Phone Agent:开源AI手机智能体,用自然语言控制安卓/iOS/HarmonyOS设备
274 周安装
Inngest Steps 教程:构建健壮工作流的步骤方法详解与最佳实践
274 周安装
\'"