Web3 セキュリティシリーズ: 誤って他のブロックチェーンに転送された資金は回復できますか?
暗号資産の世界では、たった一度のミスが「デジタル災害」を引き起こす可能性があります。最もよくある悪夢の一つは、資産を間違ったブロックチェーンに送金してしまうことです。例えば、Ethereum Sepoliaテストネット上のアドレスにETHを送金するつもりが、誤ってEthereumメインネット上のアドレスに送金してしまったとします。このような状況で、誤って送金された資金をEthereumメインネットから回収することは可能でしょうか?資産を回収できるかどうかは、受信アドレスの種類によって異なります。この記事では、様々なシナリオを分析します。
1. シナリオ1: 受信アドレスがEOAの場合
EOA (外部所有アカウント) とは、一般的に、秘密鍵またはニーモニック フレーズによって直接制御される通常のウォレット アドレスのことです。
資産回復の前提条件:
- 資産を EOA アドレスに移転しました。
- このターゲットEOAアドレスの秘密鍵またはニーモニックフレーズを所有していること。(これは通常、あなた自身の別のウォレットアドレス、または協力してくれる友人のアドレスです)。
- 対象チェーンは EVM 互換チェーンです。
資産を回復する方法:
受信側の EOA アドレスの秘密鍵の所有者は、対象のブロックチェーン上で直接資金を引き出すことができます。
2. シナリオ 2: 受信アドレスは契約です。
これは最も深刻なシナリオの一つです。スマートコントラクトのアドレスは秘密鍵によって生成されないため、誰もスマートコントラクトの秘密鍵を所有できず、EOAと同じようにコントラクトを制御できません。さらに、コントラクトに「誤って移転された資産」を処理するための救済機能が事前に用意されていない場合、誤って移転された資金はコントラクト内に永久にロックされ、誰も回収できなくなる可能性があります。
しかし、場合によっては一筋の希望の光が見えてきます。次に、ETHがイーサリアムメインネット上でロックされているシナリオを想定し、その資金を救済する方法を説明します。
2.1. シーン紹介
要約すると、このシナリオでは、ユーザーがSepoliaテストネット上のコントラクトを呼び出して、トークン発行用のコントラクトにETHを送金しようとします。しかし、トランザクションの開始時にメインネットへの誤った接続が行われ、その結果、ETHがメインネットのコントラクトにロックされてしまいます。具体的なシナリオ構築プロセスは以下のとおりです。

1. Ethereum Sepolia テストネットにおいて、プロジェクトチーム(EOA)は実装コントラクトをデプロイしました。このコントラクトの主な機能は、ユーザーがETHを預け入れ、対応するATokenを発行することです。このコードは「mintTokens」関数に類似しています。デプロイアドレスはAと仮定します。AにはETHを直接引き出す機能は含まれていないことに注意してください。

2. Ethereum Sepolia テストネットにおいて、プロジェクトチーム (EOA) はファクトリーコントラクトをデプロイしました。このコントラクトの機能は、提供された実装コントラクトのアドレスとソルトに基づいて、最小限のプロキシコントラクト (クローン) を使用し、実装コントラクトを指すプロキシコントラクト (関数「deployProxyByImplementation」で示されているように) をデプロイすることです。デプロイアドレスを B と仮定します。ここで、「deployProxyByImplementation」関数を呼び出し、実装コントラクト A のアドレスを `_implementation` として渡し、アドレス C に A を指すプロキシコントラクトをデプロイします。

3. ユーザーは、Sepoliaテストネット上でETHを送金することでATokenをミントしたいと考えています。ユーザーはプロキシコントラクトCへの呼び出しを開始します。通常、プロキシコントラクトCはさらにコントラクトAを実装する「mintTokens」関数を呼び出し、ユーザーの操作を完了します。しかし、呼び出し中にユーザーが誤ってEthereumメインネットに接続してしまいました。その結果、ユーザーはETHをEthereumメインネット上のアドレスCに直接送金します。この時点では、Ethereumメインネット上のアドレスCにはコントラクトがデプロイされておらず、アドレスCの秘密鍵を所有する人もいません。そのため、ユーザーの資金はメインネット上のアドレスCに一時的にロックされます。
2.2. 重要な知識ポイント
具体的な救助プランを紹介する前に、まずは救助に必要な基礎知識をいくつか紹介しましょう。
2.2.1. 作成と作成2
`create` と `create2` は、Solidity でコントラクトをデプロイする一般的な 2 つの方法です。
- `create` 関数を使用してコントラクトをデプロイする場合、コントラクト アドレスはトランザクション イニシエーターのアドレスとアカウントのトランザクション数 (nonce) によって決定され、コントラクトの内容とは無関係です。
- create2 を使用してコントラクトをデプロイする場合、コントラクト アドレスの計算はトランザクション イニシエーターの nonce に依存せず、次の 4 つのパラメータに関連します。
- 0xff
- 新しいコントラクトを作成するためのコントラクト アドレス。
- パラメータとして使用される難読化値(ソルト)
- 作成するコントラクトの作成バイトコード (init_code)。
2.2.2. 最小限のエージェント契約(クローン)
https://docs.openzeppelin.com/contracts/4.x/api/proxy#clones
最小プロキシコントラクト(クローンコントラクトとも呼ばれる)は、特定の実装コントラクトを指すプロキシコントラクトを、極めて低いコスト(ガス)でデプロイするという考え方に基づいています。クローンコントラクトでは、プロキシコントラクトは「create」または「create2」メソッドのいずれかを使用してデプロイできます。例えば、「cloneDeterministic」関数を使用してプロキシコントラクトをデプロイする場合は、「create2」メソッドを使用します。
「cloneDeterministic」関数では、作成されたプロキシコントラクトのバイトコードは非常に短く、「0x363d3d373d3d3d363d73<実装コントラクトアドレス>5af43d82803e903d91602b57fd5bf3」という形式になっています。実装コントラクトのアドレスはバイトコードに直接ハードコードされており、プロキシコントラクトへのすべての呼び出しは実装コントラクトに委任されます。
「cloneDeterministic」関数からわかるように、create2メソッドを用いてプロキシコントラクトを作成します。作成されたプロキシコントラクトのアドレスは、コントラクト作成者のアドレス、ソルト、実装コントラクトのアドレス、そして固定バイトコード文字列と関連していますが、実装コントラクトのバイトコードとは関連していません。

2.3. 救助計画
次に、メインネットCアドレスに保有されているユーザーのETHを救済する方法を説明します。基本的な考え方は、イーサリアムメインネットCアドレスにコントラクトコードをデプロイし、アドレスを乗っ取ってETHを抽出します。具体的な手順は以下のとおりです。

1. テストネットと同じアドレスBを持つファクトリーコントラクトをメインネットにデプロイします。ファクトリーコントラクトのアドレスを同じにする必要があるのは、その後「cloneDeterministic」を呼び出してプロキシコントラクトをデプロイする際に、プロキシコントラクトのアドレス計算がファクトリーコントラクトのアドレスと関連しているためです。Sepoliaテストネットでファクトリーコントラクトをデプロイするトランザクションを調べ、このトランザクションに含まれるデプロイヤー(プロジェクトアドレス)のノンスを取得します。メインネットでは、ファクトリーコントラクトをデプロイする前に、プロジェクトオーナー(EOA)のアドレスのノンスをノンスに進めます。その後、メインネットにファクトリーコントラクトをデプロイします。デプロイヤーのアドレスとノンスはテストネットのデプロイトランザクションと同じなので、メインネットにデプロイされるファクトリーコントラクトのアドレスもBになります。
2. テストネットと同じアドレスAに、メインネット上の実装コントラクトをデプロイします。 「#最小プロキシコントラクト(クローン)」セクションで述べたように、クローンコントラクトの「cloneDeterministic」関数を用いてプロキシコントラクトをデプロイすると、プロキシコントラクトアドレスが計算されます。計算されるプロキシコントラクトアドレスは、入力パラメータ「salt」と実装コントラクトアドレスに依存しますが、実装コントラクトのバイトコードとは独立しています。したがって、アドレスAには1つのコントラクトをデプロイするだけで済みます。コントラクトの具体的な内容は、プロキシコントラクトアドレスの計算に影響を与えません。その後、以下のコードに示すように、ETH抽出機能を備えたコントラクトをアドレスAに直接デプロイできます。
テストネットでは、実装コントラクトAはプロジェクトオーナーのアドレス(EOA)によってデプロイされます。したがって、実装コントラクトAのアドレスは、トランザクションイニシエーターとそのノンスにのみ関連しています。したがって、テストネット上で実装コントラクトAをデプロイするトランザクションを監視し、関連するノンスを見つけ、メインネット上のプロジェクトオーナーのアドレス(EOA)を指定されたノンスにプッシュし、実装コントラクトAをデプロイすることで、処理を進めることができます。

3. メインネット上のテストネットと同じアドレスCにプロキシコントラクトをデプロイします。テストネットにデプロイされたプロキシコントラクトCのトランザクションを監視し、ソルト情報を取得します。そして、ファクトリーコントラクトBの「deployProxyByImplementation」関数を呼び出し、実装コントラクトAのアドレスとソルトをパラメータとして渡します。これにより、メインネット上のアドレスCにプロキシコントラクトがデプロイされます。
4. メインネットプロキシコントラクトCが資金引き出しのために呼び出されます。プロジェクトアドレス(EOA)はプロキシコントラクトCのwithdrawal関数を呼び出し、資金の受取人を指定して、プロキシコントラクトCから凍結されたETHを正常に引き出し、該当するユーザーに返却します。
2.4. まとめ
上記の救済計画からわかるように、対象チェーン上のコントラクトデプロイヤーの関連 nonce が使用されていないこと、資金をトラップしているコントラクトに出金機能があること、またはさまざまな方法で出金機能を展開できること(コントラクトをアップグレードしたり、Clone などのプロキシを使用できるなど)など、多くの条件が同時に満たされた場合にのみ資金を回復できます。
したがって、取引を行う際は細心の注意を払い、契約に携わる前に各取引を綿密に検証する必要があります。契約に携わる前に、ZANのAI SCAN脆弱性スキャンツールを使ってセキュリティを確認できます。資金が誤ってロックされた場合でも、慌てる必要はありません。ZANの契約セキュリティ監査チームに連絡して、資金の回復を支援してもらえます。
この記事は、ZAN チーム (X アカウント@zan_team ) と AntChain OpenLabs (X アカウント@AntChainOpenLab ) の Cara ( @Cara6289 ) によって書かれました。
- 核心观点:误转资产能否找回取决于地址类型。
- 关键要素:
- EOA地址需持有私钥可找回。
- 合约地址无救援函数则永久锁定。
- 特定条件下可通过部署合约救援。
- 市场影响:提升用户操作谨慎性与安全工具需求。
- 时效性标注:长期影响


