copy-trade について
copy-tradeは、設定したガードレールの範囲でリーダーウォレットのスワップをフォロワーウォレットに反映する、定期実行型の戦略スキルです。オンチェーン活動を解析し、スワップ処理自体は他のインテグレーションに委任します。
主な機能
- 01リーダーの取引からスワップを検出
- 02マルチホップ経路を意図に集約
- 03資産・金額・残高の制限を適用
- 04処理済み操作の重複反映を防止
- 05インテグレーションにスワップを委任
活用シーン
- 01指定ウォレットの対象取引を反映
- 02トークンや支出制限外の取引をスキップ
- 03再実行後に安全に処理を再開
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ uniswap/ uniswap-ai --skill copy-tradeインストール後、Claude Code で/copy-tradeを入力して読み込まれたか確認します。
詳細
Copy Trade
対象チェーン上の対象ウォレット(「リーダー」)を監視し、ガードレールの範囲内で、そのスワップをフォロワーのウォレットに反映します。これは薄い戦略レイヤーです。何を反映するか、反映するかどうかを判断し、実際のスワップは swap-integration と viem-integration に委任します。このスキル自体が、見積もり、承認、スワップ、署名のロジックを構築することはありません。
ランタイムの互換性: このスキルは、実行モードと確認のプロンプトに
AskUserQuestionを使用します。ランタイムでAskUserQuestionを使用できない場合は、自然言語での会話を通じて同じパラメーターと確認を取得してください。
概要
ホストのスケジューラーは、このスキルを約5分ごとに実行します。各実行は、自己完結した決定論的な1回の処理です。
- 保存されているカーソル(最後に処理したブロック)を読み取ります。
- カーソル以降のリーダーウォレットの新しいオンチェーン操作を読み取ります。
- 新しい操作ごとにガードレールを適用します。
- 条件を満たした操作について、スワップの反映を
swap-integrationに委任します。 - カーソルを進め、反映したリーダーの操作を記録します。
これは自由形式の推論ではなく、状態機械として扱ってください。状態を読み取り、チェーンとの差分を確認し、操作ごとに判断して実行し、カーソルを進めます。オンチェーンイベントが示す内容を超えて意図を推測せず、以前の実行で記録済みの判断を再導出しないでください。
前提条件
このスキルはすべてのインフラストラクチャを委任します。見積もり、承認、署名、スワップ構築を再実装することはありません。
- swap-integration(uniswap-trading):唯一の実行経路です。反映するすべてのスワップは、Trading API のフロー(
check_approval、次にquote、次にswap、その後に署名してブロードキャスト)を通します。これらを再実装しないでください。 - viem-integration(uniswap-viem):アカウント、クライアント、署名、トランザクションのブロードキャスト、およびリーダーウォレットのアクティビティの読み取りを担います。リーダーのトランザクションとレシートをカーソルブロック以降から読み取り、スワップを検出します(ステップ2を参照)。
実行前に、これらのプラグインのリファレンスを読み、信頼できる情報として扱ってください。
- 選択した対象チェーンのテンプレート:chainId、チェーン名、コントラクトアドレス、取引可能なトークンの情報源、RPC/読み取り経路、インデックス作成の可否、資金調達の制約、テンプレート固有の注意事項。参考として Robinhood Chain テンプレートを確認するには、
../../references/robinhood-chain.mdを参照してください。 ../../references/execution-model.md:Trading API の要件、実行モード、制限事項、免責事項のルール。../../references/strategy-state.md:共有状態ファイルとスケジューラーパターン。
テンプレートの入力
選択した対象チェーンのテンプレートには、次の情報が必要です。
- chain id、チェーン名、ネイティブのガストークン、RPC/読み取り経路。
- リーダーのアクティビティをデコードするために必要な、デプロイ済みの Uniswap ルーター、Permit2、PoolManager、および v2/v3/v4 プールファクトリー/リーダーのアドレス。
- パブリックインデクサーの有無。存在しない場合、このスキルは RPC をポーリングし、上限付きのブロック範囲をスキャンします。
- トークンリストや許可リストの情報源を含む、取引可能なトークンの解決ルール。
- 資金調達の制約、送金制限に関する注意事項、市場取引時間のガイダンス。
ワークフロー(決定論的な状態機械)
ステップ1:状態カーソルを読み取る
JSON 状態ファイルを読み込みます(形式は strategy-state.md を参照)。コピー取引で関係するフィールドは、最後に処理したカーソル(ブロックまたはログ位置)と、すでに反映したリーダーのインテントの集合です。インテントは leaderTxHash をキーとしてトランザクション単位で記録し、1つのトランザクションから複数の独立したインテントが生じる場合はサブインデックスを加えます(ステップ2を参照)。状態ファイルが存在しない場合は初回実行です。カーソルを現在のヘッドブロックに初期化し、この実行では何も反映しないでください(オペレーターが明示的に選択しない限り、リーダーの全履歴を再生しないようにします)。
初回実行時にヘッドをカーソルとする動作は、このスキル固有のものであり、テンプレート固有ではありません。これにより、どの対象チェーンでも誤って履歴を再生することを防ぎます。
ステップ2:カーソル以降のリーダーの操作を読み取る
リーダーのスワップを検出するには、リーダーのアドレスでプールイベントをトピックフィルタリングするのではなく、リーダー自身のトランザクションをスキャンします。プールの Swap イベントにはリーダーの EOA は含まれません。v2 では sender/to、v3 では recipient がインデックス化されます(UniversalRouter/SwapRouter02 経由で取引をルーティングする場合、これらはいずれもリーダーではなくルーターです)。また、v4 の Swap では PoolId と sender(PoolManager の呼び出し元であり、こちらもルーターです)のみがインデックス化されます。そのため、リーダーのアドレスをキーにした getLogs フィルターでは、ルーター経由の取引は何も返されません。代わりに、次のようにします。
- 範囲
(cursor, head]のブロックを順に調べ、tx.fromがリーダーと等しいトランザクションを選びます。(viem-integrationを介して viem のブロック/トランザクション読み取り機能を使い、RPC の制限に従って範囲を限定しながらスキャンします。) - 該当するトランザクションごとにレシートを取得し、その中に含まれる
Swapログをデコードします。1 つのリーダートランザクションから、1 つ以上のSwapログが出力される場合があります(マルチホップルートでは各レッグにつき 1 つ、バッチ/マルチコールでは独立したスワップごとに 1 つのログが出力されます)。プロトコルのバージョンは、イベントを出力したコントラクトによって識別します。v4 のSwapはPoolManagerが出力し、v2/v3 のSwapログは個々のプールコントラクトが出力します。 - 方向を判定する前に、各プールからトークンペアを特定します。v2/v3 の
Swapログにはトークン名が含まれないため、イベントを出力したプールのtoken0()/token1()を読み取るか、PoolIdから v4 のPoolKeyをデコードして、ペアを特定します。トークンアドレスは、これらの読み取り結果と選択した対象チェーンのテンプレートから取得します。決して作り出してはいけません。プールのSwapログで参照されるのは常にWETH(ERC-20)であり、ネイティブETHではありません。ネイティブ ETH のレッグはルーターによるラップ/アンラップであり、ERC-20 のSwapイベントは出力されません。ここでは、WETHと判定されたレッグトークンをWETHとして正規化し、許可リストとの照合時にはexecution-model.mdの ETH/WETH 正規化ルールを適用します(ステップ 3)。 - 金額の符号から in/out を判定します。v3 と v4 では符号の規則が逆なので注意してください。v2 では
amount0In/amount1In/amount0Out/amount1Outは符号なしで報告されます。ゼロ以外の*InトークンがtokenInです。v3(int256)ではプールの残高差分が報告されるため、正の金額はプールに入るトークン(tokenIn)、負の金額はプールから出るトークン(tokenOut)です。v4(int128)ではスワッパーの差分が報告されるため、符号は逆になります。負の金額はスワッパーが支払ったトークン(tokenIn)、正の金額はスワッパーが受け取ったトークン(tokenOut)です。(v4 のSwapNatSpec では v3 のプール残高に関する表現が再利用されていますが、コントラクトが出力するのはスワッパーの符号付きBalanceDeltaであり、実際の v4 スワップでも確認済みです。スワッパー差分の規則に従ってください。)方向を割り当てた後、amountIn/amountOutには絶対値を設定します。
次に、各レッグを { tokenIn, tokenOut, amountIn, amountOut, leaderTxHash, logIndex, blockNumber } にデコードします。単一のリーダートランザクション内で 1 つのルートを構成するレッグをまとめてから、ミラーするアクションを作成します。
tokenOut→tokenInを照合してレッグを連結します。 あるレッグのtokenOutが、ログ順の次のレッグのtokenInと一致する場合(同一トランザクション内)、それらは同じルートの一部です。このような連結の最大のまとまりを 1 つの正味の意図にまとめます。tokenInは最初のレッグのtokenIn、tokenOutは最後のレッグのtokenOut、amountInは最初のレッグのamountIn、amountOutは最後のレッグのamountOutとします。中間のレッグは削除します。(例:USDG -> WETH -> AAAxは 2 つのSwapログから成り、1 つの意図USDG -> AAAxにまとめられます。両方のレッグをミラーすると、中間のWETHを誤って購入し、その後再び消費することになります。)まとめたチェーンが開始トークンに戻り、正味のtokenInとtokenOutが等しくなる場合(たとえば、USDG -> WETH -> USDGのアービトラージ往復取引)、正味の変化はありません。そのチェーンを削除し、何もミラーしません。- 独立したスワップは個別のままにします。 トランザクションは、レッグが連結しない(あるレッグの
tokenOutが別のレッグのtokenInにつながらない)バッチ/マルチコールである場合もあります。これらはルートではなく独立したスワップです。それぞれを個別の正味の意図として扱い、別々にミラーします。 結果は、最大チェーンごとに1つのミラーインテント(独立したレッグごとに1つ)になります。結果の各インテントは、トランザクションレベルでleaderTxHashをキーにします。1つの tx から複数の独立したインテントが生じる場合、そのインテントの最初のレッグのlogIndexと等しいサブインデックスを追加します。logIndexはトランザクションごとに不変であるため、キーは再スキャンやクラッシュリカバリー後も再現可能であり、マルチホップルートがミラーされるのは最大でも1回です。単一のインテントが生じる tx では、leaderTxHashのみを使用します。結果のインテントは(blockNumber, first-leg logIndex)の順に並べ、処理を決定的にします。
重要:選択したテンプレートに従ってアクティビティを読み取ってください。 テンプレートにパブリックインデクサーが用意されていない場合は、RPC をポーリングし、デプロイ済みコントラクトに対してログを直接スキャンしてください。RPC の
getLogs制限を守るため、ブロック範囲を上限付きでスキャンし、通常は連続する範囲が重複しないよう、実行ごとにカーソルを永続化してください。カーソルが進まなかった場合(クラッシュ後など)でも、ステップ 3 の冪等性ガードレール(すでにミラー済みのleaderTxHashインテントをスキップする)が重複範囲を安全に処理します。
ステップ 3:アクションごとにガードレールを適用する
新しいアクションを順番に処理します。ガードレールに違反するアクションはスキップ(ミラーしない)し、スキップ理由を記録します。ガードレール:
アクションの処理を開始する前に、設定済みのガードレールを読み取ります。ミラーごと、実行ごと、または期間ごとの支出上限が設定されていない場合は、AskUserQuestion(利用できない場合は自然言語)を使ってオペレーターに上限を確認します。比較に使用する資金供給トークンまたは単位も含めてください。いずれかの上限が未設定のままなら、autonomous モードに入らないでください。confirm モードでは、ミラーごとの確認のみを行い、自律モードは引き続き利用できないことを報告してください。
| ガードレール | ルール |
|---|---|
| チェーンフィルター | アクションは選択したターゲットチェーン上で実行される必要があります。それ以外はすべて無視します。 |
| アセットの一致 | tokenIn と tokenOut の両方が、オペレーターの許可トークンセット(デフォルト:選択したテンプレートの取引可能なトークン)に含まれている必要があります。この照合では ETH と WETH は同等です。Step 2 に従い、プールログでは常に ERC-20 が参照されるため、WETH としてデコードされたレッグは、ETH または WETH の許可リスト項目を満たします。そのため、ETH の項目に対して WETH としてデコードされたレッグが誤ってスキップされることはありません。比較の前に、execution-model.md の ETH/WETH 正規化ルールを適用してください。 |
| ポジションサイズ上限 | ミラーする金額は、1 取引あたりの上限および期間あたりの支出上限を超えてはなりません。上限を超える場合は、調整するかスキップします。 |
| フォロワーの残高 | フォロワーのウォレットには、実行に必要な量の tokenIn(およびガス)が必要です。不足している場合はスキップし、報告します。 |
| 冪等性 | このインテントの leaderTxHash(サブインデックスがある場合はそのインデックスを含む)がすでにミラー済みセットに含まれている場合はスキップし、二重にミラーしないでください。トランザクション単位でキー付けすることで、マルチホップルートは最大 1 回だけミラーされます。 |
ポジションサイズはオペレーターが選択します。ミラーする取引ごとの固定想定元本、またはリーダーの金額に対する割合のいずれかを選び、必ず上記の上限で制限します。上限を超えてミラーしてはなりません。
ステップ 4:ミラー取引を委任する
すべてのガードレールを通過したインテントについて、swap-integration に処理を引き渡します。選択したテンプレートのターゲットチェーン ID とトークンアドレスを渡します。Trading API のフロー(check_approval、続いて quote、続いて swap)が、ルーティング、承認、Permit2、署名、ブロードキャストを処理します。このスキルで指定するのは、tokenIn、tokenOut、サイズ調整済みの amount、ターゲットチェーン ID、フォロワーのウォレットのみです。見積もり、承認、スワップ、署名のロジックを再実装しないでください。ETH/WETH の取引における実行形式(ネイティブの ETH とラップ済みの WETH のどちらを使うか、およびラップ/アンラップ)は、swap-integration の Trading API パスが決定します。フォロワーのミラー取引でもリーダーと同じ形式を使う必要があると想定したり、独自にラップ/アンラップを実装したりしないでください。正規化したトークンを渡し、Trading API に形式を選択させます。
ステップ 5:カーソルを進めて記録する
リーダーの各インテントの処理が完了した直後に、状態をディスクに書き込みます。実行終了時まで書き込みをまとめてはいけません。各インテントの処理が完了するたび(ブロードキャストの確認、またはスキップの記録)、leaderTxHash キー(サブインデックスがある場合はそれも含む)を、結果とフォロワーのトランザクションハッシュとともにミラー済みセットまたはスキップ済みセットに追加してから、永続化します。永続的な cursor を進めるのは、記録がすでに確定しているインテントまでに限ります。これにより、処理が一部だけ完了した範囲が処理済みとしてマークされることを防げます。このインテントごとの書き込みが冪等性を保証します。ブロードキャストの確認後、バッチ処理の途中で実行がクラッシュしても、そのインテントの記録はすでにディスク上にあるため、次回の起動時にはステップ 3 の冪等性チェックでスキップされます。実行終了時まで書き込みをまとめると、途中でクラッシュした際に、すでにブロードキャスト済みのミラー取引が記録されないまま残り、実資金を使って再度ミラー取引されてしまいます。
実行モード
オペレーターが選択した execution-model.md の実行モードを公開します。
| モード | 動作 |
|---|---|
confirm(デフォルト) | AskUserQuestion を使って、各ミラースワップのブロードキャスト前に確認を求めます。トークン、サイズ調整済みの金額、チェーン、ミラーするリーダーのアクションを表示します。swap-integration の支出制限を再利用します。 |
autonomous | 取引ごとのプロンプトなしで、ガードレールの範囲内で厳密にミラーします。1 回の実行ごとおよび期間ごとの支出上限、ミラーごとの想定元本上限、トークンの許可リスト、事前のドライラン、キルスイッチが必要です。 |
デフォルトは confirm です。契約の全文については ../../references/execution-model.md を参照してください。
状態
状態は ../../references/strategy-state.md に準拠します。コピートレードでは、特に次の情報を保存します。
cursor:選択したターゲットチェーン上で最後に処理したブロック/ログ位置。- ミラーしたリーダーのインテントキー(
leaderTxHash。1 つのトランザクションから複数の独立したインテントが生じる場合はサブインデックスも含む)と、それぞれの結果のセット。
これにより、実行は冪等になります。再起動後やスケジューラーの起動が重複した場合でも、リーダーのインテントがミラーされるのは最大 1 回です。また、複数ホップのルート(ステップ 2 で 1 つのインテントに集約)は、各レッグにつき 1 回ではなく、最大 1 回だけミラーされます。
制限事項と免責事項
RWA のゲーティングはチェーンおよびトークンごとに異なり、トークンレベルで強制される場合があります(譲渡が制限された ERC-20)。そのため、以下に従ってください。
- リーダーの同一の取引が成功していても、ミラースワップは転送時にリバートする可能性があります(フォロワーがその資産を保有する資格を持たない場合があります)。転送制限によるリバートを適切に処理し、失敗を記録し、無条件に再試行しないでください。
- 選択したテンプレートの株式市場の取引時間に関するガイダンスを遵守してください。RWA によっては取引時間外の流動性に制限があるため、時間外の買いがスキップまたは延期される場合があります。
- 免責事項をリポジトリのルートにある
DISCLAIMER.mdに記載してください。Uniswap Labs は投資助言や推奨を提供しません。コピートレードは、運営者自身の指示に基づいて別のウォレットの取引を複製するものであり、戦略および適用法令の遵守については、運営者が単独で責任を負います。
入力の検証
運営者が指定した値をコード、API 呼び出し、またはシェルコマンドに埋め込む前に、必ず以下を検証してください。
- リーダーとフォロワーのウォレットアドレス、トークンアドレス:
^0x[a-fA-F0-9]{40}$に一致する必要があります。一致しない場合は拒否してください。 - ポジション上限と金額:
^[0-9]+\.?[0-9]*$に一致する非負の数値である必要があります。 - チェーン ID:ハードコードせず、選択したテンプレートから読み取った、運営者が設定した対象チェーン ID である必要があります。
- API キーと秘密鍵:環境変数から取得する必要があります。ハードコードしてはいけません。
- 拒否:シェルのメタ文字(
;、|、&、$、`、(、)、>、<、\、'、"、または改行)を含む入力は、すべて拒否してください。