deployer について
ContinuousClearingAuctionFactory を使った CCA オークションコントラクトのデプロイ向け Claude Code スキルです。CREATE2 によるチェーン間で一貫したアドレスを扱い、設定検証、確認、コマンド準備、鍵の安全な取り扱いを案内します。
主な機能
- 01ファクトリー経由でオークションをデプロイ
- 02CREATE2 による決定的なアドレス生成
- 03設定と入力値の検証
- 04Foundry デプロイコマンドの準備
- 05デプロイ後の手順とエクスプローラー検証
- 06デプロイの安全対策と鍵管理の案内
活用シーン
- 01設定から CCA オークションをデプロイ
- 02デプロイ前にアドレス、数値、オークション設定を検証
- 03テストネットへのデプロイとコントラクト検証のコマンドを準備
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ uniswap/ uniswap-ai --skill deployerインストール後、Claude Code で/deployerを入力して読み込まれたか確認します。
詳細
CCA のデプロイ
ContinuousClearingAuctionFactory を CREATE2 とともに使用して、チェーン間でアドレスを統一しながら Continuous Clearing Auction(CCA)スマートコントラクトをデプロイします。
ランタイムの互換性: このスキルでは、対話形式のプロンプトに
AskUserQuestionを使用します。実行環境でAskUserQuestionを利用できない場合は、自然言語での会話を通じて同じパラメーターを収集してください。
Claude Code の使用手順
ユーザーがこのスキルを呼び出したら、適切な安全上の警告と検証を行いながら、CCA のデプロイ手順を案内してください。
デプロイ前の要件
デプロイに進む前に、必ず以下を行ってください。
- 教育目的の免責事項を表示し、ユーザーの了承を得る
- 提供された場合は設定ファイルを検証する
- 対象ネットワークのファクトリーアドレスを確認する
- デプロイパラメーターをユーザーに確認する
デプロイのワークフロー
- 教育目的の免責事項を表示(必須)
- 設定を読み込む、または入力を求める
- 設定を検証する
- デプロイ計画を表示する
- ユーザーの確認を得る
- デプロイコマンドを提示する
- デプロイ後の手順
⚠️ 教育目的での使用に関する免責事項
重要:デプロイに進む前に、以下を了承する必要があります。
このツールとすべてのデプロイ手順は、教育目的のみで提供されています。AI が生成したデプロイコマンドには、エラーやセキュリティ上の脆弱性が含まれる可能性があります。
必ず以下を行ってください。
- ✅ デプロイ前に、すべての設定を慎重に確認する
- ✅ すべてのパラメーター(アドレス、価格、スケジュール)が正しいことを確認する
- ✅ メインネットにデプロイする前に、まずテストネットでテストする
- ✅ 実資金を使用してデプロイする前に、コントラクトを監査する
デプロイ手順に進む前に、AskUserQuestion を使用して、ユーザーがこれらの警告を了承したことを確認してください。
入力検証ルール
ユーザーが指定した値を forge/cast コマンドまたはデプロイスクリプトに補間する前に、必ず以下を確認してください。
- Ethereum アドレス:
^0x[a-fA-F0-9]{40}$に一致する必要があります。一致しない場合は拒否してください - チェーン ID:サポート対象チェーンのリスト(1, 130, 1301, 8453, 42161, 11155111)に含まれている必要があります
- 数値(供給量、価格、ブロック数、チェーン ID):0 以上で、
^[0-9]+\.?[0-9]*$に一致する必要があります - RPC エンドポイント URL(
$RPC_URL):https://スキームである必要があり、以下のルールに記載されたメタ文字や空白を含んではなりません。この値は設定ファイルから取得するものではなく、手順の実行中にユーザーが指定し、以下のすべてのforge script、cast send、forge verify-contractコマンドの--rpc-urlに渡されます。「設定ではなくユーザーから取得した値」であることは免除の理由になりません。最初に入力された時点で検証し、$RPC_URLに割り当ててください。その後はこの変数のみを参照し、後続のコマンドで生の URL を再読み込みしないでください。プロバイダーの API キーなど、クエリー文字列を必要とするエンドポイントは、環境に別途エクスポートして$RPC_URLで参照してください。コマンドテキストに直接貼り付けてはいけません。 - シェルのメタ文字または空白(
;、|、&、$、`、(、)、>、<、\、'、"、スペース、タブ、改行)を含む入力は拒否してください。$(...)とバッククォートは二重引用符の内側でもコマンドを実行し、スペースは値を分割して forge/cast の追加フラグにするため、どちらも補間に使用してはいけません。問題の文字を削除して続行するのではなく、処理を中止し、検証に失敗した値と文字を報告してください。 - 検証せずにユーザーの生の入力をシェルコマンドに渡してはいけません。
- 生成するコマンドでは、すべての補間を必ず二重引用符で囲んでください(引用符のない形式ではなく、
--rpc-url "$RPC_URL"と記述してください)。引用符は第二の防御層であり、最初の防御層ではありません。コマンドに渡す前に値を検証し、そのうえで引用符で囲んでください。
⚠️ 権限の安全性
Claude Code の設定で Bash(forge:*) や Bash(cast:*) を自動承認しないでください。 ガスを消費するコマンドやトランザクションをブロードキャストするコマンドは、必ず実行ごとに承認を求めてください。.claude/hooks/ の PreToolUse フックは安全策としてプログラムによる検証を行いますが、コマンドごとのユーザー承認が主要な制御手段です。
🔐 秘密鍵のセキュリティ
重要:安全なデプロイには、秘密鍵を安全に取り扱うことが不可欠です。
⚠️ 絶対にしてはいけないこと
- ❌ 絶対に秘密鍵を git リポジトリや設定ファイルに保存しないでください
- ❌ 絶対に秘密鍵をコマンドラインに直接貼り付けないでください(シェルの履歴に表示されます)
- ❌ 絶対に秘密鍵を共有したり、共有環境に保存したりしないでください
- ❌ 絶対に信頼できないコンピューターでメインネットの秘密鍵を使用しないでください
- ❌ 絶対に
--private-keyフラグを使用しないでください(PreToolUse フックによってブロックされます)
✅ 推奨される方法
オプション 1:ハードウェアウォレット(最も安全)
Ledger または Trezor のハードウェアウォレットを --ledger フラグと併用します。
forge script script/Example.s.sol:ExampleScript \
--rpc-url "$RPC_URL" \
--broadcast \
--ledger
オプション 2:暗号化されたキーストア
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"
オプション 3:環境変数(テスト専用)
環境変数を使用する場合は、次の点を確認してください。
- 安全な
.envファイルに設定する(git にコミットしない) source .envまたはdotenvで読み込む- 信頼できる安全なコンピューターでのみ使用する
- 開発にはテストネットの鍵を使用する
例:
# .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"
まずテストネットで
メインネットの前に、必ずテストネットでテストしてください。
- Sepolia(テストネット):フォーセットから無料の ETH を入手できます
- Base Sepolia:Base でのテストに使える無料の ETH
- テストネットでワークフロー全体をデプロイして検証する
- 十分にテストした後でのみ、メインネットにデプロイする
デプロイガイド
ファクトリーのデプロイ
CCA インスタンスは ContinuousClearingAuctionFactory コントラクトを介してデプロイされます。このコントラクトは CREATE2 を使用し、チェーン間で一貫したアドレスを実現します。
ファクトリーのアドレス
| バージョン | アドレス | ステータス |
|---|---|---|
| v1.1.0 | 0xCCccCcCAE7503Cac057829BF2811De42E16e0bD5 | 推奨 |
オークションインスタンスのデプロイ
ステップ 0:CCA リポジトリをクローンする
CCA コントラクトがまだローカルにない場合は、リポジトリをクローンして依存関係をインストールします。
git clone https://github.com/Uniswap/continuous-clearing-auction.git
cd continuous-clearing-auction
forge install
これにより、以降の手順で使用するデプロイスクリプト、コントラクト ABI、テストヘルパーを利用できるようになります。
ステップ 1:設定を準備する
有効な設定ファイルがあることを確認します(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 }
]
}
}
ステップ 2:設定を検証する
デプロイ前に、設定がすべての検証ルールに合格することを確認します(「検証ルール」セクションを参照)。
ステップ 3:ファクトリーを介してデプロイする
ファクトリーのインターフェースはシンプルです。
function initializeDistribution(
address token,
uint256 amount,
bytes calldata configData,
bytes32 salt
) external returns (IDistributionContract);
各項目の説明:
token:販売するトークンのアドレスamount:オークションで販売するトークンの数量configData:ABI エンコードされたAuctionParameters構造体salt:バニティアドレスのマイニングに使う任意の bytes32 値
ステップ 3.5:設定を configData にエンコードする
ファクトリーの initializeDistribution は、ABI エンコードされた AuctionParameters として configData を受け取ります。JSON 設定をエンコード済みのバイト列に変換します。
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"
Foundry スクリプトを使用する場合:
// script/DeployAuction.s.sol
pragma solidity ^0.8.24;
import "forge-std/Script.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.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);
}
}
重要: initializeDistribution を呼び出す前に、ファクトリーへのトークン転送を承認する必要があります。ファクトリーは、あなたのアドレスから新しく作成されたオークションコントラクトへ amount 分のトークンを転送します。
ステップ 4:Foundry スクリプトを使用する
# 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"
ステップ 5:デプロイ後
デプロイ後、トークンが転送されたことをオークションに通知するため、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 - 有効なアドレス:すべてのアドレスが有効な Ethereum アドレス(0x + 40 桁の 16 進数)であること
- 負でない値:すべての数値が 0 以上であること
- 最低価格の整合性:最低価格がティックスペーシングの倍数であること
- ティックスペーシング:最低価格の 1 ベーシスポイント以上(1%、10% を推奨)
- 供給スケジュール:最後のブロックで相当量のトークン(約 30% 以上)が売却されること
- 総供給量の上限:最大 1e30 wei(18 桁の小数を持つ 1 兆トークン)
- FoT トークンは不可:送金手数料のあるトークンはサポートされません
- 最小小数桁数:小数桁数が 6 未満のトークンは使用しないでください
技術概要
Q96 固定小数点演算
オークションでは Q96 固定小数点演算を使用します。
library FixedPoint96 {
uint8 internal constant RESOLUTION = 96;
uint256 internal constant Q96 = 0x1000000000000000000000000; // 2^96
}
- 価格:小数を含む価格比率を表す Q96 固定小数点数
- 需要:Q96 でスケーリングされた通貨額
オークションのステップ(供給量の発行)
ステップはバイトにパックされ、各ステップは uint64 です。
- 最初の 24 ビット:
mps(MPS 単位のブロックごとの発行率) - 最後の 40 ビット:
blockDelta(ブロック数)
function parse(bytes8 data) internal pure returns (uint24 mps, uint40 blockDelta) {
mps = uint24(bytes3(data));
blockDelta = uint40(uint64(data));
}
データは、読み取りコストを抑えるため、外部の SSTORE2 コントラクトにデプロイされます。
主なコントラクト関数
submitBid()
ユーザーは次の値を指定して入札します。
maxPrice:支払いを許容する最高価格(Q96)amount:入札する通貨額owner:トークン/返金を受け取るアドレスprevTickPrice:ガス最適化のためのヒントhookData:検証フック用の任意データ
checkpoint()
新しい入札があるたびに、オークションはブロックごとにチェックポイントされます。チェックポイントによってトークンの割り当てが決まります。
exitBid() / exitPartiallyFilledBid()
入札は、より高い入札に上回られた場合、またはオークション終了後(グラデュエーション後のみ)に退出できます。
isGraduated()
currencyRaised >= requiredCurrencyRaised の場合に true を返します。グラデュエーション前は入札から退出できません。
claimTokens()
ユーザーは claimBlock 以降に購入したトークンを請求できます(グラデュエーションしたオークションのみ)。
sweepCurrency() / sweepUnsoldTokens()
オークション終了後:
sweepCurrency():調達した通貨を引き出します(グラデュエーションした場合のみ)sweepUnsoldTokens():売れ残ったトークンを引き出します
対応チェーン
CCA は、選定された EVM チェーン上の正規アドレスにデプロイされています。
| チェーン ID | ネットワーク | ブロック時間 |
|---|---|---|
| 1 | メインネット | 12s |
| 130 | Unichain | 1s |
| 1301 | Unichain Sepolia | 2s |
| 8453 | Base | 2s |
| 42161 | Arbitrum | 2s |
| 11155111 | Sepolia | 12s |
トラブルシューティング
よくある問題
| 問題 | 解決策 |
|---|---|
| "Invalid block sequence" | startBlock < endBlock <= claimBlock であることを確認します |
| "Floor price not aligned" | 最低価格をティックスペーシングの倍数に丸めます |
| "Tick spacing too small" | 最低価格の 1% 以上に設定します |
| "Total supply too large" | 最大 1e30 wei(18 桁の小数を持つ 1 兆トークン) |
| "Gas inefficiency" | ティックスペーシングを大きくします |
| "Invalid address" | アドレスが 0x で始まる 42 文字であることを確認します |
検証チェックリスト
デプロイ前に確認してください。
- ブロックの順序が有効である(start < end <= claim)
- 最低価格がティック幅の倍数である
- ティック幅が最低価格の 1% 以上である
- すべてのアドレスが有効な Ethereum アドレスである
- 総供給量が 1e30 wei 以下である
- 通貨の価値がトークンより高い
- ブロック時間がネットワークに合っている(メインネットは 12s、L2 は 2s)
- 受取人のアドレスが設定されている(プレースホルダーではない)
- 通貨アドレスがネットワークに対して正しい
- 最後の供給ステップでトークンの約 30% 以上が売却される
- 送金時に手数料が発生するトークンを使用していない
- トークンの小数桁数が 6 以上である
- デプロイ後に
onTokensReceived()が呼び出される
追加リソース
- 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