关于 configurator
面向 Claude Code 的技能,用于交互式配置 Continuous Clearing Auction(CCA)智能合约参数。它会分批收集并验证输入、计算拍卖数值,并可通过 MCP 工具生成供应计划。
主要功能
- 01分批交互式收集参数
- 02验证地址、链及数值
- 03计算拍卖时间与 Q96 价格
- 04生成供应计划
- 05输出配置 JSON 和摘要
适用场景
- 01设置代币拍卖参数
- 02生成拍卖供应计划
- 03检查或部署已有配置
MCP 相关
MCP 服务运行时,技能会调用 `cca-supply-schedule__generate_supply_schedule` 工具,并传入拍卖区块数和预售区块数。工具不可用时,说明中提供 Python 备用算法。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ uniswap/ uniswap-ai --skill configurator安装后在 Claude Code 中输入/configurator确认已加载。
详细介绍
CCA 配置
配置 Continuous Clearing Auction(CCA)智能合约参数,实现公平、透明的代币分发。
运行时兼容性: 此技能使用
AskUserQuestion进行交互式提问。如果你的运行时不支持AskUserQuestion,请改用自然语言对话收集相同参数。
Claude Code 的说明
用户调用此技能时,请使用 AskUserQuestion 引导用户完成批量交互式表单配置流程。分批收集参数,尽量减少与用户的交互轮次。
批量交互式表单规则
- 批量提问 - 使用一次 AskUserQuestion 调用同时提出最多 4 个问题
- 允许直接输入 - 对于需要自定义值的字段(地址、数字):
- 提供“暂不可用”或“暂时跳过”选项
- “其他”选项(自动提供)可用于直接输入自定义值
- 绝不要单独询问“你有 X 吗?”
- 存储答案 - 将所有已收集的值保存在配置对象中
- 收集后验证 - 每批收集完成后,在继续之前验证所有输入
- 显示进度 - 每批收集完成后,显示已收集和待收集的参数
输入验证规则
上文规则 4 要求在每批收集后进行验证。以下说明了验证的含义。大多数值是通过选择预设选项获得的,但也可以通过自由文本输入:使用 AskUserQuestion 为每个问题提供的“其他”选项,或者在 AskUserQuestion 不可用且适用上述运行时兼容性回退方案时,通过普通对话输入。自定义 RPC 端点就是最明显的例子,因为 Network 问题列出了命名网络,却没有端点字段;然而,如果用户不接受公共端点,仍可通过“其他”选项或对话输入自定义端点。在将任何值写入配置文件或插入 curl 命令之前,都必须按照以下检查进行验证。不要试图寻找豁免情形:如果某个值确实是此技能提供的预设值,那么它自然会通过所有检查;而在对话回退方案下,本来也无法确定值的来源。
- Ethereum 地址(
token、currency、tokensRecipient、fundsRecipient、validationHook):必须匹配^0x[a-fA-F0-9]{40}$,否则拒绝 - Chain ID:必须属于支持的链列表(1、130、1301、8453、42161、11155111)
- 数值(供应量、价格、区块、MPS、区块差值):必须为非负数,且匹配
^[0-9]+\.?[0-9]*$ - RPC 端点 URL:优先使用 可用的公共 RPC 表中的公共端点。但无论自定义端点通过何种方式提供,在进入 获取区块编号 中的
curl命令之前,都必须使用https://协议,且不得包含下方规则列出的任何元字符或空白字符。“它是用户提供的,不是表格里的”不构成豁免理由。 - 拒绝任何包含 Shell 元字符或空白字符的输入:
;、|、&、$、`、(、)、>、<、\、'、"、空格、制表符、换行符。$(...)和反引号即使在双引号内也会执行命令,而空格会将一个值拆成多个curl标志,因此绝不能安全地将它们插入命令。中止操作,并指出哪个值中的哪个字符未通过检查;不要删除违规字符后继续。 - 绝不要未经验证就将原始用户输入传递给 Shell 命令,并且在展示给用户的任何命令中,始终使用双引号括起插入的值。
未通过任意一项检查的值也绝不会写入配置文件。deployer 技能会读取该文件,并将其中的字段插入 forge 和 cast 命令,因此在此处存储未经验证的值,会导致该值在后续命令中注入指令。
配置流程
按以下批次收集参数:
批次 1:任务选择(1 个问题)
问题 1:任务类型
- 提示:“你想用 CCA 做什么?”
- 选项:“配置拍卖参数”、“仅生成供应计划”、“审查现有配置”、“部署现有配置”
**收集后:**如果不是“配置拍卖参数”,则跳转到相应部分。
批次 2:基本配置(4 个问题)
问题 1:网络
- 提示:“要在哪个网络上部署?”
- 选项:“Ethereum Mainnet”、“Unichain (Mainnet)”、“Unichain Sepolia (Testnet)”、“Base”、“Arbitrum”、“Sepolia”
- 存储:
chainId、blockTime、rpcUrl、currencyDecimals(所选货币的小数位数)
问题 2:代币地址
- 提示:“要拍卖的代币是什么?”
- 选项:“代币尚未部署”(占位符)、自定义地址(通过“其他”)
- 验证:必须为以 0x 开头的 42 个字符
- 存储:
token
问题 3:总供应量
- 提示:“要拍卖多少代币?”
- 选项:“1 亿个代币(18 位小数)”、“10 亿个代币(18 位小数)”、“100 亿个代币(18 位小数)”、自定义(通过“其他”)
- 验证:必须 <= 1e30 wei
- 存储:
totalSupply
问题 4:货币
- 提示:“竞拍者应使用什么货币?”
- 选项:“ETH(原生)”、“[网络] 上的 USDC”、“[网络] 上的 USDT”、自定义 ERC20(通过“其他”)
- 验证:必须为以 0x 开头的 42 个字符或 address(0)
- 存储:
currency
**收集后:**验证所有输入,并显示基本配置摘要。
批次 3:时间与定价(4 个问题)
问题 1:拍卖时长
- 提示:“拍卖应持续多久?”
- 选项:“1 天”、“2 天”、“3 天”、“7 天”、自定义区块数(通过“其他”)
- 根据网络区块时间计算区块数
- 存储:
auctionBlocks
问题 2:预竞拍期
- 提示:“是否包含预竞拍期?(期间不会售出代币)”
- 选项:“无预竞拍期(0 个区块)”、“12 小时”、“1 天”、自定义区块数(通过“其他”)
- 根据网络区块时间计算区块数
- 存储:
prebidBlocks
问题 3:底价
- 提示:“起始底价是多少?(每个代币对应的货币数量比例)”
- 选项:“0.10x(1:1 比例的 10%)”、“0.01x(1:1 比例的 1%)”、“0.001x(1:1 比例的 0.1%)”、自定义比例(通过“其他”)
- 计算 Q96 值,并考虑小数位差异:
Q96 * ratio / 10^(tokenDecimals - currencyDecimals) - 对于 USDC(6 位小数)和 18 位小数的代币:
Q96 * ratio / 10^12 - 对于原生 ETH(18 位小数)和 18 位小数的代币:
Q96 * ratio / 10^0 = Q96 * ratio - 存储:
floorPriceRatio、floorPrice(Q96)、tokenDecimals、currencyDecimals
问题 4:刻度间距
- 提示:“刻度间距应占底价的百分之多少?”
- 选项:“底价的 1%(推荐)”、“底价的 10%”、“底价的 0.1%”、自定义百分比(通过“其他”)
- 计算:
tickSpacing = int(floorPrice * percentage) - **关键:**向下取整底价,使其能被刻度间距整除:
roundedFloorPrice = (floorPrice // tickSpacing) * tickSpacing- 验证:
roundedFloorPrice % tickSpacing == 0必须为 true
- 验证:刻度间距必须至少为底价的 1 个基点
- 存储:
tickSpacingPercentage、tickSpacing(Q96)、roundedFloorPrice
**收集后:**验证输入,检查底价是否可被刻度间距整除,计算并显示 Q96 值,并显示时间安排摘要。
批次 4:接收方与启动(4 个问题)
问题 1:代币接收方
- 提示词:“未售出的代币应发送到哪里?”
- 选项:“与资金接收方相同”、自定义地址(通过“其他”)
- 验证:必须是以 0x 开头的 42 个字符
- 存储:
tokensRecipient
问题 2:资金接收方
- 提示词:“筹集的资金应发送到哪里?”
- 选项:“与代币接收方相同”、自定义地址(通过“其他”)
- 验证:必须是以 0x 开头的 42 个字符
- 存储:
fundsRecipient
问题 3:开始时间
- 提示词:“拍卖应何时开始?”
- 选项:“1 小时后”、“6 小时后”、“24 小时后”、自定义区块编号(通过“其他”)
- 从 RPC 获取当前区块编号并进行计算
- 存储:
startBlock - 计算:
endBlock = startBlock + prebidBlocks + auctionBlocks,claimBlock = endBlock
问题 4:最低所需资金
- 提示词:“毕业时是否要求筹集到最低金额的货币?”
- 选项:“无最低要求(0)”、“100 ETH”、“1000 ETH”、以 wei 为单位的自定义金额(通过“其他”)
- 存储:
requiredCurrencyRaised
收集完成后: 验证地址,从 RPC 获取当前区块,并计算完整的区块时间线。
批次 5:可选钩子(1 个问题)
问题 1:验证钩子
- 提示词:“是否使用验证钩子合约?”
- 选项:“不使用验证钩子”、自定义钩子地址(通过“其他”)
- 验证:如果提供,必须是以 0x 开头的 42 个字符
- 存储:
validationHook
收集完成后: 如果提供了钩子地址,则进行验证。
步骤 6:生成供应计划
如果 MCP 服务未运行,请提供启动说明:
# Navigate to MCP server directory
cd packages/plugins/uniswap-cca/mcp-server/supply-schedule
# Run setup script (first time only)
chmod +x setup.sh
./setup.sh
# Start the MCP server
python3 server.py
MCP 服务运行后,使用收集到的参数调用 cca-supply-schedule__generate_supply_schedule MCP 工具。该工具需要一个 JSON 对象:
{
"auction_blocks": 86400,
"prebid_blocks": 0
}
将值替换为从用户处收集到的实际 auctionBlocks 和 prebidBlocks。
如果 MCP 工具不可用,请直接使用备用 Python 算法(参见“供应计划配置”部分)。
存储:supplySchedule
步骤 7:生成并显示配置
收集完所有参数并生成供应计划后,在 CLI 输出中显示完整的 JSON 配置:
{
"[chainId]": {
"token": "...",
"totalSupply": ...,
"currency": "...",
"tokensRecipient": "...",
"fundsRecipient": "...",
"startBlock": ...,
"endBlock": ...,
"claimBlock": ...,
"tickSpacing": ...,
"validationHook": "...",
"floorPrice": ...,
"requiredCurrencyRaised": ...,
"supplySchedule": [...]
}
}
不要自动创建文件。 让用户复制 JSON,或指定要保存的文件路径。
步骤 8:显示摘要
向用户显示一份全面、格式清晰的摘要,包括:
- 网络和链 ID
- 代币和货币详情
- 区块时间线(开始、结束、领取),并附带易读时间
- 以 Q96 和比率两种格式显示的定价(底价、刻度间距)
- 接收方(代币、资金)
- 供应计划摘要(阶段总数、最终区块百分比)
- 验证检查清单(所有验证规则的通过/失败情况)
步骤 9:后续步骤
询问用户接下来想做什么:
- “保存到文件”(询问文件路径,默认值:
script/auction-config.json) - “查看部署说明”(建议使用部署器技能)
- “修改配置”
- “退出”(直接结束;用户可以从 CLI 输出中复制 JSON)
重要说明
- 分批验证 —— 每批输入收集完成后验证所有输入
- 计算开始/结束区块时,从 RPC 获取当前区块编号
- 正确计算底价和刻度间距的 Q96 值:
- 关键: 考虑小数位差异:
Q96 * ratio / 10^(tokenDecimals - currencyDecimals) - 所有网络上的 USDC 都是 6 位小数——对于 18 位小数的代币,需除以 10^12
- 原生 ETH 是 18 位小数——对于 18 位小数的代币,无需调整
- 关键: 考虑小数位差异:
- 将底价四舍五入,使其可被刻度间距整除:
roundedFloorPrice = (floorPrice // tickSpacing) * tickSpacing- 必须验证:
roundedFloorPrice % tickSpacing == 0
- 使用 MCP 工具生成供应计划(如果服务未运行,则提供设置说明)
- 尽量减少交互轮次 —— 每批尽可能多地收集参数
特定网络常量
将这些内容保存起来以便快速查阅:
const NETWORKS = {
1: {
name: 'Mainnet',
blockTime: 12,
rpc: 'https://ethereum-rpc.publicnode.com',
usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
},
130: {
name: 'Unichain',
blockTime: 1,
rpc: 'https://mainnet.unichain.org',
usdc: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
},
1301: {
name: 'Unichain Sepolia (Testnet)',
blockTime: 2,
rpc: 'https://sepolia.unichain.org',
usdc: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
},
8453: {
name: 'Base',
blockTime: 2,
rpc: 'https://mainnet.base.org',
usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
},
42161: {
name: 'Arbitrum',
blockTime: 2,
rpc: 'https://arb1.arbitrum.io/rpc',
usdc: '0xaf88d065e77c8cc2239327c5edb3a432268e5831',
},
11155111: {
name: 'Sepolia',
blockTime: 12,
rpc: 'https://ethereum-sepolia-rpc.publicnode.com',
usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
},
};
// Q96 = 2^96 (JavaScript BigInt notation)
const Q96 = 79228162514264337593543950336n;
Python 等效写法:
# Q96 = 2**96
Q96 = 79228162514264337593543950336
概览
CCA(连续清算拍卖)是一种新颖的拍卖机制,可将统一价格拍卖推广到连续时间。它在启动初始流动性时实现公平的价格发现,同时消除时机博弈并鼓励早期参与。
主要特性:
- 公平的价格发现:持续清算,不存在时机博弈
- 透明的分配:按预定计划释放供应量
- 灵活的配置:可自定义拍卖参数和计划
- 多链支持:在 EVM 链上进行规范部署
- 工厂部署:通过 CREATE2 实现地址一致
快速决策指南
| 任务... | 使用此章节 |
|---|---|
| 配置拍卖参数 | 配置指南 |
| 生成供应计划 | 供应计划配置 |
| 了解拍卖机制 | 技术概览 |
配置指南
拍卖参数
CCA 拍卖通过 AuctionParameters 结构体进行配置:
struct AuctionParameters {
address currency; // Token to raise funds in (address(0) for ETH)
address tokensRecipient; // Address to receive leftover tokens
address fundsRecipient; // Address to receive all raised funds
uint64 startBlock; // Block when auction starts
uint64 endBlock; // Block when auction ends
uint64 claimBlock; // Block when tokens can be claimed
uint256 tickSpacing; // Fixed granularity for prices (Q96)
address validationHook; // Optional hook (use 0x0 if none)
uint256 floorPrice; // Starting floor price (Q96)
uint128 requiredCurrencyRaised; // Minimum funds to graduate
bytes auctionStepsData; // Packed supply issuance schedule
}
配置文件格式
创建 JSON 配置文件(例如,script/auction-config.json):
{
"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 }
]
}
}
参数详情
基本配置
| 参数 | 类型 | 说明 |
|---|---|---|
token | address | 拍卖的代币 |
totalSupply | number | 拍卖代币总量(wei/最小单位) |
currency | address | 用于购买的代币(USDC 等),或用于 ETH 的 address(0) |
tokensRecipient | address | 未售出代币的接收方 |
fundsRecipient | address | 募集资金的接收方 |
区块配置
| 参数 | 类型 | 说明 | 限制 |
|---|---|---|---|
startBlock | number | 拍卖开始时间 | startBlock < endBlock |
endBlock | number | 拍卖结束时间 | endBlock <= claimBlock |
claimBlock | number | 可领取代币的时间 | claimBlock >= endBlock |
各网络的区块时间:
- Mainnet、Sepolia:每个区块 12s
- Unichain、Base、Arbitrum:每个区块 2s
定价参数
| 参数 | 类型 | 说明 |
|---|---|---|
floorPrice | number | 最低价格(Q96 格式) |
tickSpacing | number | 价格刻度增量(Q96 格式) |
validationHook | address | 可选的验证合约(如无则使用 0x0) |
requiredCurrencyRaised | number | 所需的最低资金(无最低要求时为 0) |
供应计划
| 参数 | 类型 | 说明 |
|---|---|---|
supplySchedule | array | {mps, blockDelta} 对象数组 |
价格计算(Q96 格式)
CCA 使用 Q96 定点格式实现精确定价。基准值 2^96(79228162514264337593543950336)表示 1:1 的价格比率。
最低价格计算
重要:请考虑代币与货币之间的小数位数差异。
# Base value for 1:1 ratio
Q96 = 79228162514264337593543950336
# Formula: Q96 * (human price ratio) / 10^(token_decimals - currency_decimals)
# Example 1: USDC (6 decimals) per 18-decimal token at $0.10 ratio
token_decimals = 18
currency_decimals = 6 # USDC has 6 decimals
decimal_adjustment = 10 ** (token_decimals - currency_decimals) # 10^12
floorPrice = Q96 * 0.1 / decimal_adjustment
# Result: 7922816251426433759354395 (approximately)
# Example 2: Native ETH (18 decimals) per 18-decimal token at 0.1 ratio
token_decimals = 18
currency_decimals = 18 # Native ETH has 18 decimals
decimal_adjustment = 10 ** (18 - 18) # 10^0 = 1
floorPrice = Q96 * 0.1 / 1
# Result: 7922816251426433759354395034
**要点:**所有网络上的 USDC 都有 6 位小数,因此将 USDC 与 18 位小数的代币搭配使用时,必须除以 10^12。
刻度间距计算
刻度间距决定了可以提交出价的位置。选择不低于最低价格 1 个基点的间距。1% 或 10% 也都是合理的选择。
# Example: 1% of floor price
tickSpacing = int(floorPrice * 0.01)
# For floorPrice = 7922816251426433759354395000
# Result: 79228162514264337593543950
舍入底价(关键)
**底价 MUST 能被 tick 间距整除。**向下取整以确保可以整除:
# Calculate tick spacing first
tickSpacing = int(floorPrice * 0.01) # 1% of floor price
# Round floor price DOWN to be evenly divisible
roundedFloorPrice = (floorPrice // tickSpacing) * tickSpacing
# VERIFY divisibility (must be True)
assert roundedFloorPrice % tickSpacing == 0, "Floor price must be divisible by tick spacing!"
示例:
Q96 = 79228162514264337593543950336
raw_floor_price = int(Q96 * 0.0001) # 0.0001 ETH per token
# Result: 7922816251426434139029504
tick_spacing = int(raw_floor_price * 0.01) # 1%
# Result: 79228162514264350785536
rounded_floor_price = (raw_floor_price // tick_spacing) * tick_spacing
# Result: 7843588088912170727768064
# Verify: 7843588088912170727768064 / 79228162514264350785536 = 99 (exact)
# Remainder: 0 ✓
警告:将 tick 间距设置得过小会导致拍卖的 Gas 效率极低,并可能引发 DoS 攻击。
供应计划配置
了解 MPS(毫基点)
供应计划使用 MPS = 1e7(1,000 万),其中每个单位代表千分之一个基点。
供应计划定义了代币随时间的发行速率。每个步骤包含:
mps:每个区块释放的代币数量(以 mps 为单位)blockDelta:此速率适用的区块数
标准计划生成器
此插件包含一个 MCP 服务,可使用具有以下特性的归一化凸曲线生成供应计划:
- 12 个步骤(默认值,可配置),用于逐步释放
- 每个步骤释放相同数量的代币(逐步释放 70% 时,每步为 5.8333%)
- 区块持续时间递减(凸曲线特性)
- 较大的最后一个区块获得剩余代币(约 30%,可配置为 20%–40%)
- 总量:释放的供应量始终恰好为 10,000,000 MPS,通过对每个步骤计算
sum(mps * blockDelta)得出。mps是每个区块的释放速率,而非每个步骤的 释放量,因此单独累加mps列不会得到 10,000,000。
使用 MCP 工具 generate_supply_schedule 生成此标准分布:
MCP 工具调用:
{
"auction_blocks": 86400,
"prebid_blocks": 0
}
该算法会自动计算:
- 每个步骤释放相同数量的代币(例如,12 个步骤且逐步释放 70% 时,每步为 5.8333%)
- 根据归一化曲线 C(t) = t^α 计算时间边界(默认 α = 1.2)
- 区块持续时间随时间递减(凸曲线特性)
- 调整最后一个区块,使
sum(mps * blockDelta)恰好为 10,000,000 MPS
示例:Base 上为期 2 天的拍卖
Base 的区块时间为 2 秒,因此 2 天 = 86400 个区块。
调用 generate_supply_schedule:
{
"auction_blocks": 86400,
"prebid_blocks": 0
}
输出(归一化凸分布):
{
"schedule": [
{ "mps": 54, "blockDelta": 10894 },
{ "mps": 68, "blockDelta": 8517 },
{ "mps": 75, "blockDelta": 7803 },
{ "mps": 79, "blockDelta": 7373 },
{ "mps": 83, "blockDelta": 7068 },
{ "mps": 85, "blockDelta": 6835 },
{ "mps": 88, "blockDelta": 6647 },
{ "mps": 90, "blockDelta": 6490 },
{ "mps": 92, "blockDelta": 6356 },
{ "mps": 94, "blockDelta": 6238 },
{ "mps": 95, "blockDelta": 6136 },
{ "mps": 97, "blockDelta": 6043 },
{ "mps": 2988006, "blockDelta": 1 }
],
"auction_blocks": 86400,
"prebid_blocks": 0,
"total_phases": 13,
"summary": {
"total_mps": 10000000,
"target_mps": 10000000,
"final_block_mps": 2988006,
"final_block_percentage": 29.88,
"num_steps": 12,
"alpha": 1.2,
"main_supply_pct": 70.0,
"step_tokens_pct": 5.8333
}
}
注意:
- 区块持续时间递减:10894 → 8517 → 7803 → ... → 6043
- 每个步骤释放的代币数量近似相等(每步约为 5.8333%)
- 最后一个区块包含所有代币的 29.88%
sum(mps * blockDelta)恰好为 10,000,000 MPS(单独累加mps列会远低于该值)
示例:带预竞价阶段
添加一个不释放代币的预竞价阶段(mps=0)。该阶段会置于计划的开头。
调用 generate_supply_schedule:
{
"auction_blocks": 86400,
"prebid_blocks": 43200
}
输出:
{
"schedule": [
{ "mps": 0, "blockDelta": 43200 },
{ "mps": 54, "blockDelta": 10894 },
{ "mps": 68, "blockDelta": 8517 },
...
{ "mps": 2988006, "blockDelta": 1 }
],
"auction_blocks": 86400,
"prebid_blocks": 43200,
"total_phases": 14,
"summary": {
"total_mps": 10000000,
"target_mps": 10000000,
"final_block_mps": 2988006,
"final_block_percentage": 29.88,
"num_steps": 12,
"alpha": 1.2,
"main_supply_pct": 70.0,
"step_tokens_pct": 5.8333
}
}
**注意:**预竞价阶段只需在计划开头添加 mps: 0。拍卖部分仍使用相同的归一化凸分布。
自定义计划
如需自定义分布,请手动定义计划:
{
"supplySchedule": [
{ "mps": 100, "blockDelta": 5000 },
{ "mps": 200, "blockDelta": 5000 },
{ "mps": 500, "blockDelta": 4400 }
]
}
重要提示:最后一个区块应出售大量代币(通常为 30% 以上),以防止价格操纵。
为链上部署编码供应计划
生成供应计划后,必须将其编码为字节格式,以用于链上 AuctionParameters 结构体。编码过程会将每个 {mps, blockDelta} 元素打包为一个 uint64。
编码算法
对于供应计划中的每个元素:
- 创建 uint64(64 位 / 8 字节),其中:
- 前 24 位:
mps值(左侧填充) - 接下来的 40 位:
blockDelta值(左侧填充)
- 前 24 位:
- 通过
encodePacked将所有 uint64 打包在一起(拼接字节) - 返回带
0x前缀的十六进制字节字符串
编码公式
// Solidity equivalent
uint64 packed = (uint64(mps) << 40) | uint64(blockDelta);
bytes memory auctionStepsData = abi.encodePacked(packed1, packed2, ...);
数值限制
- mps:必须能用 24 位表示(最大值:16,777,215)
- blockDelta:必须能用 40 位表示(最大值:1,099,511,627,775)
使用 MCP 工具
使用 MCP 工具 encode_supply_schedule 对供应计划进行编码:
输入:
{
"schedule": [
{ "mps": 0, "blockDelta": 43200 },
{ "mps": 54, "blockDelta": 10894 },
{ "mps": 68, "blockDelta": 8517 }
]
}
输出:
{
"encoded": "0x0000000000a8c00000003600002aa60000004400002145...",
"length_bytes": 112,
"num_elements": 14
}
手动编码示例(Python)
def encode_supply_schedule(schedule):
"""Encode supply schedule to bytes."""
encoded_bytes = b''
for item in schedule:
mps = item['mps']
block_delta = item['blockDelta']
# Validate bounds
assert mps < 2**24, f"mps {mps} exceeds 24-bit max"
assert block_delta < 2**40, f"blockDelta {block_delta} exceeds 40-bit max"
# Pack into uint64: mps (24 bits) << 40 | blockDelta (40 bits)
packed = (mps << 40) | block_delta
# Convert to 8 bytes (big-endian)
encoded_bytes += packed.to_bytes(8, byteorder='big')
return '0x' + encoded_bytes.hex()
# Example
schedule = [
{"mps": 0, "blockDelta": 43200},
{"mps": 54, "blockDelta": 10894}
]
encoded = encode_supply_schedule(schedule)
print(encoded) # 0x0000000000a8c00000003600002aa6
与配置流程集成
使用配置器技能时:
- 生成计划:通过
generate_supply_scheduleMCP 工具 - 编码计划:通过
encode_supply_scheduleMCP 工具 - 在最终配置输出中包含编码后的字节
- 将其作为
auctionStepsData参数传递给部署脚本
编码后的字节字符串会作为 configData 参数的一部分,传递给 Factory 的 initializeDistribution 函数。
获取当前区块编号
使用公共 RPC 获取当前区块,以配置 startBlock:
可用的公共 RPC
获取区块编号
curl -X POST "https://mainnet.base.org" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_blockNumber",
"params": [],
"id": 1
}'
响应:
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x123abc"
}
将十六进制转换为十进制,即可得到区块编号。
验证规则
生成配置前,请确保:
- 区块约束:
startBlock < endBlock <= claimBlock - 有效地址:所有地址均为有效的以太坊地址(0x + 40 个十六进制字符)
- 非负值:所有数值均 >= 0
- 底价对齐:底价必须是价格刻度间距的倍数
- 价格刻度间距:至少为底价的 1 个基点(建议为 1%、10%)
- 供应计划:最后一个区块售出大量代币(约 30% 以上)
- 总供应量上限:最大为 1e30 wei(1 万亿个 18 位小数代币)
- 不支持 FoT 代币:不支持转账收费代币
- 最少小数位数:请勿使用小数位数少于 6 的代币
其他资源
- CCA 仓库:https://github.com/Uniswap/continuous-clearing-auction
- 技术文档:参阅仓库中的
docs/TechnicalDocumentation.md - 部署指南:参阅仓库中的
docs/DeploymentGuide.md - 白皮书:参阅仓库中的
docs/assets/whitepaper.pdf - 审计报告:参阅仓库中的
docs/audits/README.md - Uniswap 文档:https://docs.uniswap.org/contracts/liquidity-launchpad/CCA
- 漏洞赏金:https://cantina.xyz/code/f9df94db-c7b1-434b-bb06-d1360abdd1be/overview