configurator by uniswap/uniswap-ai
npx skills add https://github.com/uniswap/uniswap-ai --skill configurator配置连续清算拍卖(CCA)智能合约参数,以实现公平透明的代币分发。
运行时兼容性: 此技能使用
AskUserQuestion进行交互式提示。如果您的运行时环境中没有AskUserQuestion,请通过自然语言对话收集相同的参数。
当用户调用此技能时,使用 AskUserQuestion 引导他们完成批量交互式表单配置流程。分批收集参数以尽量减少用户交互轮次。
按以下批次收集参数:
问题 1:任务类型
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
收集后: 如果不是“配置拍卖参数”,则跳转到相应部分。
问题 1:网络
chainId、blockTime、rpcUrl、currencyDecimals(针对所选货币)问题 2:代币地址
token问题 3:总供应量
totalSupply问题 4:货币
currency收集后: 验证所有输入,显示基本配置摘要。
问题 1:拍卖时长
auctionBlocks问题 2:预出价期
prebidBlocks问题 3:底价
Q96 * 比率 / 10^(tokenDecimals - currencyDecimals)Q96 * 比率 / 10^12Q96 * 比率 / 10^0 = Q96 * 比率floorPriceRatio、floorPrice (Q96)、tokenDecimals、currencyDecimals问题 4:价格间隔
tickSpacing = int(floorPrice * 百分比)roundedFloorPrice = (floorPrice // tickSpacing) * tickSpacingroundedFloorPrice % tickSpacing == 0 必须为真tickSpacingPercentage、tickSpacing (Q96)、roundedFloorPrice收集后: 验证输入,验证底价可整除性,计算并显示 Q96 值,显示时间摘要。
问题 1:代币接收方
tokensRecipient问题 2:资金接收方
fundsRecipient问题 3:开始时间
startBlockendBlock = startBlock + prebidBlocks + auctionBlocks、claimBlock = endBlock问题 4:最低所需资金
requiredCurrencyRaised收集后: 验证地址,从 RPC 获取当前区块,计算完整的区块时间线。
问题 1:验证钩子
validationHook收集后: 如果提供了钩子地址,则验证它。
如果 MCP 服务器未运行,请提供启动说明:
# 导航到 MCP 服务器目录
cd packages/plugins/uniswap-cca/mcp-server/supply-schedule
# 运行设置脚本(仅首次)
chmod +x setup.sh
./setup.sh
# 启动 MCP 服务器
python3 server.py
一旦 MCP 服务器运行,使用收集到的参数调用 cca-supply-schedule__generate_supply_schedule MCP 工具。该工具期望一个 JSON 对象:
{
"auction_blocks": 86400,
"prebid_blocks": 0
}
将值替换为用户收集的实际 auctionBlocks 和 prebidBlocks。
如果 MCP 工具不可用,直接使用备用 Python 算法(参见供应计划配置部分)。
存储:supplySchedule
收集所有参数并生成供应计划后,在 CLI 输出中显示完整的 JSON 配置:
{
"[chainId]": {
"token": "...",
"totalSupply": ...,
"currency": "...",
"tokensRecipient": "...",
"fundsRecipient": "...",
"startBlock": ...,
"endBlock": ...,
"claimBlock": ...,
"tickSpacing": ...,
"validationHook": "...",
"floorPrice": ...,
"requiredCurrencyRaised": ...,
"supplySchedule": [...]
}
}
请勿自动创建文件。让用户复制 JSON 或指定文件路径来保存它。
向用户显示一个全面的格式化摘要,包括:
询问用户想要做什么:
script/auction-config.json)Q96 * 比率 / 10^(tokenDecimals - currencyDecimals)roundedFloorPrice = (floorPrice // tickSpacing) * tickSpacingroundedFloorPrice % tickSpacing == 0存储这些常量以便快速参考:
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 表示法)
const Q96 = 79228162514264337593543950336n;
Python 等效:
# Q96 = 2**96
Q96 = 79228162514264337593543950336
CCA(连续清算拍卖)是一种新颖的拍卖机制,将统一价格拍卖推广到连续时间。它为引导初始流动性提供了公平的价格发现,同时消除了时机博弈并鼓励早期参与。
主要特点:
| 任务... | 使用此部分 |
|---|---|
| 配置拍卖参数 | 配置指南 |
| 生成供应计划 | 供应计划配置 |
| 了解拍卖机制 | 技术概述 |
CCA 拍卖通过 AuctionParameters 结构体配置:
struct AuctionParameters {
address currency; // 筹集资金的代币(ETH 为 address(0))
address tokensRecipient; // 接收剩余代币的地址
address fundsRecipient; // 接收所有筹集资金的地址
uint64 startBlock; // 拍卖开始的区块
uint64 endBlock; // 拍卖结束的区块
uint64 claimBlock; // 可领取代币的区块
uint256 tickSpacing; // 价格的固定粒度(Q96)
address validationHook; // 可选钩子(如果没有,使用 0x0)
uint256 floorPrice; // 起始底价(Q96)
uint128 requiredCurrencyRaised; // 完成拍卖所需的最低资金
bytes auctionStepsData; // 打包的供应发行计划
}
创建 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 |
各网络出块时间:
| 参数 | 类型 | 描述 |
|---|---|---|
floorPrice | number | 最低价格(Q96 格式) |
tickSpacing | number | 价格刻度增量(Q96 格式) |
validationHook | address | 可选验证合约(如果没有,使用 0x0) |
requiredCurrencyRaised | number | 所需最低资金(0 表示无最低要求) |
| 参数 | 类型 | 描述 |
|---|---|---|
supplySchedule | array | {mps, blockDelta} 对象数组 |
CCA 使用 Q96 定点格式进行精确定价。基准值 2^96 (79228162514264337593543950336) 表示 1:1 的价格比率。
关键:考虑代币和货币之间的小数位数差异。
# 1:1 比率的基准值
Q96 = 79228162514264337593543950336
# 公式:Q96 * (人类价格比率) / 10^(token_decimals - currency_decimals)
# 示例 1:USDC(6 位小数)每 18 位小数代币,比率为 $0.10
token_decimals = 18
currency_decimals = 6 # USDC 有 6 位小数
decimal_adjustment = 10 ** (token_decimals - currency_decimals) # 10^12
floorPrice = Q96 * 0.1 / decimal_adjustment
# 结果:7922816251426433759354395(约)
# 示例 2:原生 ETH(18 位小数)每 18 位小数代币,比率为 0.1
token_decimals = 18
currency_decimals = 18 # 原生 ETH 有 18 位小数
decimal_adjustment = 10 ** (18 - 18) # 10^0 = 1
floorPrice = Q96 * 0.1 / 1
# 结果:7922816251426433759354395034
关键点: USDC 在所有网络上都是 6 位小数,因此当使用 USDC 与 18 位小数代币时,必须除以 10^12。
价格间隔决定了出价可以放置的位置。选择至少为底价的 1 个基点。1% 或 10% 也是合理的。
# 示例:底价的 1%
tickSpacing = int(floorPrice * 0.01)
# 对于 floorPrice = 7922816251426433759354395000
# 结果:79228162514264337593543950
底价必须能被价格间隔整除。 向下舍入以确保精确整除:
# 首先计算价格间隔
tickSpacing = int(floorPrice * 0.01) # 底价的 1%
# 将底价向下舍入以使其能被整除
roundedFloorPrice = (floorPrice // tickSpacing) * tickSpacing
# 验证可整除性(必须为 True)
assert roundedFloorPrice % tickSpacing == 0, "底价必须能被价格间隔整除!"
示例:
Q96 = 79228162514264337593543950336
raw_floor_price = int(Q96 * 0.0001) # 每代币 0.0001 ETH
# 结果:7922816251426434139029504
tick_spacing = int(raw_floor_price * 0.01) # 1%
# 结果:79228162514264350785536
rounded_floor_price = (raw_floor_price // tick_spacing) * tick_spacing
# 结果:7843588088912170727768064
# 验证:7843588088912170727768064 / 79228162514264350785536 = 99(精确)
# 余数:0 ✓
警告: 设置过小的价格间隔将使拍卖极其消耗 Gas 且效率低下,并可能导致 DoS 攻击。
供应计划使用 MPS = 1e7(1000 万),其中每个单位代表一个基点的千分之一。
供应计划定义了代币随时间的发行速率。每个步骤包含:
mps:每区块释放的代币(以 mps 单位计)blockDelta:此速率适用的区块数该插件包含一个 MCP 服务器,使用归一化凸曲线生成供应计划,具有以下属性:
使用 MCP 工具 generate_supply_schedule 生成此标准分布:
MCP 工具调用:
{
"auction_blocks": 86400,
"prebid_blocks": 0
}
算法自动计算:
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
}
}
注意:
添加一个不释放代币(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 中。
对于供应计划中的每个元素:
mps 值(左填充)blockDelta 值(左填充)encodePacked 打包所有 uint64(连接字节)0x 前缀的十六进制字节字符串// Solidity 等效
uint64 packed = (uint64(mps) << 40) | uint64(blockDelta);
bytes memory auctionStepsData = abi.encodePacked(packed1, packed2, ...);
使用 encode_supply_schedule MCP 工具编码供应计划:
输入:
{
"schedule": [
{ "mps": 0, "blockDelta": 43200 },
{ "mps": 54, "blockDelta": 10894 },
{ "mps": 68, "blockDelta": 8517 }
]
}
输出:
{
"encoded": "0x0000000000a8c00000003600002aa60000004400002145...",
"length_bytes": 112,
"num_elements": 14
}
def encode_supply_schedule(schedule):
"""将供应计划编码为字节。"""
encoded_bytes = b''
for item in schedule:
mps = item['mps']
block_delta = item['blockDelta']
# 验证边界
assert mps < 2**24, f"mps {mps} 超过 24 位最大值"
assert block_delta < 2**40, f"blockDelta {block_delta} 超过 40 位最大值"
# 打包到 uint64:mps (24 位) << 40 | blockDelta (40 位)
packed = (mps << 40) | block_delta
# 转换为 8 字节(大端序)
encoded_bytes += packed.to_bytes(8, byteorder='big')
return '0x' + encoded_bytes.hex()
# 示例
schedule = [
{"mps": 0, "blockDelta": 43200},
{"mps": 54, "blockDelta": 10894}
]
encoded = encode_supply_schedule(schedule)
print(encoded) # 0x0000000000a8c00000003600002aa6
使用配置器技能时:
generate_supply_schedule MCP 工具生成计划encode_supply_schedule MCP 工具编码计划auctionStepsData 参数传递给部署脚本编码后的字节字符串是作为 configData 参数的一部分传递给 Factory 的 initializeDistribution 函数的内容。
使用公共 RPC 获取当前区块以配置 startBlock:
| 网络 | RPC URL |
|---|---|
| Mainnet | https://ethereum-rpc.publicnode.com |
| Unichain | https://unichain-rpc.publicnode.com |
| Base | https://mainnet.base.org |
| Arbitrum | https://arb1.arbitrum.io/rpc |
| Sepolia | https://ethereum-sepolia-rpc.publicnode.com |
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 <= claimBlockdocs/TechnicalDocumentation.mddocs/DeploymentGuide.mddocs/assets/whitepaper.pdfdocs/audits/README.md每周安装次数
273
仓库
GitHub 星标数
185
首次出现
2026年2月12日
安全审计
安装于
codex259
opencode259
gemini-cli255
github-copilot253
cursor253
kimi-cli250
Configure Continuous Clearing Auction (CCA) smart contract parameters for fair and transparent token distribution.
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 a bulk interactive form configuration flow using AskUserQuestion. Collect parameters in batches to minimize user interaction rounds.
Collect parameters in these batches:
Question 1: Task Type
After collection: If not "Configure auction parameters", skip to appropriate section.
Question 1: Network
chainId, blockTime, rpcUrl, currencyDecimals (for selected currency)Question 2: Token Address
tokenQuestion 3: Total Supply
totalSupplyQuestion 4: Currency
currencyAfter collection: Validate all inputs, show summary of basic configuration.
Question 1: Auction Duration
auctionBlocksQuestion 2: Prebid Period
prebidBlocksQuestion 3: Floor Price
Q96 * ratio / 10^(tokenDecimals - currencyDecimals)Q96 * ratio / 10^12Q96 * ratio / 10^0 = Q96 * ratiofloorPriceRatio, floorPrice (Q96), tokenDecimals, currencyDecimalsQuestion 4: Tick Spacing
tickSpacing = int(floorPrice * percentage)roundedFloorPrice = (floorPrice // tickSpacing) * tickSpacingroundedFloorPrice % tickSpacing == 0 must be truetickSpacingPercentage, tickSpacing (Q96), roundedFloorPriceAfter collection: Validate inputs, verify floor price divisibility, calculate and display Q96 values, show timing summary.
Question 1: Tokens Recipient
tokensRecipientQuestion 2: Funds Recipient
fundsRecipientQuestion 3: Start Time
startBlockendBlock = startBlock + prebidBlocks + auctionBlocks, claimBlock = endBlockQuestion 4: Minimum Funds Required
requiredCurrencyRaisedAfter collection: Validate addresses, fetch current block from RPC, calculate full block timeline.
Question 1: Validation Hook
validationHookAfter collection: Validate hook address if provided.
If MCP server is not running , provide instructions to start it:
# 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
Once the MCP server is running, call the cca-supply-schedule__generate_supply_schedule MCP tool with the collected parameters. The tool expects a JSON object:
{
"auction_blocks": 86400,
"prebid_blocks": 0
}
Replace the values with the actual auctionBlocks and prebidBlocks collected from the user.
If the MCP tool is unavailable, use the fallback Python algorithm directly (see Supply Schedule Configuration section).
Store: supplySchedule
After collecting all parameters and generating the supply schedule, display the complete JSON configuration in the CLI output:
{
"[chainId]": {
"token": "...",
"totalSupply": ...,
"currency": "...",
"tokensRecipient": "...",
"fundsRecipient": "...",
"startBlock": ...,
"endBlock": ...,
"claimBlock": ...,
"tickSpacing": ...,
"validationHook": "...",
"floorPrice": ...,
"requiredCurrencyRaised": ...,
"supplySchedule": [...]
}
}
Do NOT automatically create a file. Let the user copy the JSON or specify a filepath to save it.
Show the user a comprehensive formatted summary including:
Ask the user what they want to do:
script/auction-config.json)Q96 * ratio / 10^(tokenDecimals - currencyDecimals)roundedFloorPrice = (floorPrice // tickSpacing) * tickSpacingroundedFloorPrice % tickSpacing == 0Store these for quick reference:
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 equivalent:
# Q96 = 2**96
Q96 = 79228162514264337593543950336
CCA (Continuous Clearing Auction) is a novel auction mechanism that generalizes the uniform-price auction into continuous time. It provides fair price discovery for bootstrapping initial liquidity while eliminating timing games and encouraging early participation.
Key features:
| Task... | Use This Section |
|---|---|
| Configure auction parameters | Configuration Guide |
| Generate supply schedule | Supply Schedule Configuration |
| Understand auction mechanics | Technical Overview |
CCA auctions are configured through the AuctionParameters struct:
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
}
Create a JSON configuration file (e.g., 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 }
]
}
}
| Parameter | Type | Description |
|---|---|---|
token | address | Token being auctioned |
totalSupply | number | Total tokens to auction (wei/smallest unit) |
currency | address | Purchase token (USDC, etc.) or address(0) for ETH |
tokensRecipient | address | Where unsold tokens go |
fundsRecipient | address |
| Parameter | Type | Description | Constraint |
|---|---|---|---|
startBlock | number | When auction starts | startBlock < endBlock |
endBlock | number | When auction ends | endBlock <= claimBlock |
claimBlock | number | When tokens can be claimed | claimBlock >= endBlock |
Block times by network:
| Parameter | Type | Description |
|---|---|---|
floorPrice | number | Minimum price (Q96 format) |
tickSpacing | number | Price tick increment (Q96 format) |
validationHook | address | Optional validation contract (use 0x0 if none) |
requiredCurrencyRaised | number | Minimum funds needed (0 if no minimum) |
| Parameter | Type | Description |
|---|---|---|
supplySchedule | array | Array of {mps, blockDelta} objects |
CCA uses Q96 fixed-point format for precise pricing. The base value 2^96 (79228162514264337593543950336) represents a 1:1 price ratio.
CRITICAL: Account for decimal differences between token and currency.
# 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
Key Point: USDC has 6 decimals on all networks, so you must divide by 10^12 when using USDC with 18-decimal tokens.
Tick spacing governs where bids can be placed. Choose AT LEAST 1 basis point of the floor price. 1% or 10% is also reasonable.
# Example: 1% of floor price
tickSpacing = int(floorPrice * 0.01)
# For floorPrice = 7922816251426433759354395000
# Result: 79228162514264337593543950
Floor price MUST be evenly divisible by tick spacing. Round DOWN to ensure exact divisibility:
# 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!"
Example:
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 ✓
Warning : Setting too small of a tick spacing will make the auction extremely gas inefficient and can result in DoS attacks.
Supply schedules use MPS = 1e7 (10 million), where each unit represents one thousandth of a basis point.
The supply schedule defines the token issuance rate over time. Each step contains:
mps: Tokens released per block (in mps units)blockDelta: Number of blocks this rate appliesThe plugin includes an MCP server that generates supply schedules using a normalized convex curve with the following properties:
Use the MCP tool generate_supply_schedule to generate this standard distribution:
MCP Tool Call:
{
"auction_blocks": 86400,
"prebid_blocks": 0
}
The algorithm automatically calculates:
Base uses 2s blocks, so 2 days = 86400 blocks.
Call generate_supply_schedule with:
{
"auction_blocks": 86400,
"prebid_blocks": 0
}
Output (normalized convex distribution):
{
"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
}
}
Notice:
Add a prebid period where no tokens are released (mps=0). The prebid is prepended to the schedule.
Call generate_supply_schedule with:
{
"auction_blocks": 86400,
"prebid_blocks": 43200
}
Output:
{
"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
}
}
Notice: The prebid phase is simply prepended with mps: 0. The auction portion still uses the same normalized convex distribution.
For custom distribution, manually define the schedule:
{
"supplySchedule": [
{ "mps": 100, "blockDelta": 5000 },
{ "mps": 200, "blockDelta": 5000 },
{ "mps": 500, "blockDelta": 4400 }
]
}
Important : The last block should sell a significant amount of tokens (typically 30%+) to prevent price manipulation.
After generating a supply schedule, it must be encoded into a bytes format for the onchain AuctionParameters struct. The encoding packs each {mps, blockDelta} element into a uint64.
For each element in the supply schedule:
mps value (left padded)blockDelta value (left padded)encodePacked (concatenate bytes)0x prefix// Solidity equivalent
uint64 packed = (uint64(mps) << 40) | uint64(blockDelta);
bytes memory auctionStepsData = abi.encodePacked(packed1, packed2, ...);
Use the encode_supply_schedule MCP tool to encode a supply schedule:
Input:
{
"schedule": [
{ "mps": 0, "blockDelta": 43200 },
{ "mps": 54, "blockDelta": 10894 },
{ "mps": 68, "blockDelta": 8517 }
]
}
Output:
{
"encoded": "0x0000000000a8c00000003600002aa60000004400002145...",
"length_bytes": 112,
"num_elements": 14
}
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
When using the configurator skill:
generate_supply_schedule MCP toolencode_supply_schedule MCP toolauctionStepsData parameterThe encoded bytes string is what gets passed to the Factory's initializeDistribution function as part of the configData parameter.
Use public RPCs to fetch current block for startBlock configuration:
| Network | RPC URL |
|---|---|
| Mainnet | https://ethereum-rpc.publicnode.com |
| Unichain | https://unichain-rpc.publicnode.com |
| Base | https://mainnet.base.org |
| Arbitrum | https://arb1.arbitrum.io/rpc |
| Sepolia | https://ethereum-sepolia-rpc.publicnode.com |
curl -X POST "https://mainnet.base.org" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_blockNumber",
"params": [],
"id": 1
}'
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x123abc"
}
Convert hex to decimal for block number.
Before generating configuration, ensure:
startBlock < endBlock <= claimBlockdocs/TechnicalDocumentation.md in repodocs/DeploymentGuide.md in repodocs/assets/whitepaper.pdf in repodocs/audits/README.md in repoWeekly Installs
273
Repository
GitHub Stars
185
First Seen
Feb 12, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex259
opencode259
gemini-cli255
github-copilot253
cursor253
kimi-cli250
agent-browser 浏览器自动化工具 - Vercel Labs 命令行网页操作与测试
140,500 周安装
| Where raised funds go |