Web3 安全性系列:誤轉到其他鏈上的資金,還能救回來嗎?
在加密世界中,一次點擊失誤就可能引發一場「數位災難」。最常見的惡夢之一,莫過於將資產發送到了錯誤的區塊鏈上。例如,本來想給以太坊Sepolia 測試網路上的地址發送ETH,結果不小心發到了以太坊主網上的地址。這種情況下,還能從以太坊主網上將誤轉的資金取回嗎?能否找回資產,關鍵在於收款地址的類型。本文將根據不同的情況進行分析。
1. 場景一:收款地址是EOA
EOA (Externally Owned Account) 是我們常說的、由私鑰或助記詞直接控制的普通錢包位址。
找回資產前提條件:
- 你將資產轉到了一個EOA 位址。
- 你擁有這個目標EOA 地址的私鑰或助記詞。 (通常是你自己的另一個錢包地址,或是朋友的地址,而且他願意配合)。
- 目標鍊是EVM 相容鏈。
找回資產方法:
收款EOA 地址私鑰持有者直接在目標鏈上提取資金即可。
2. 場景二:收款地址是合約
這是最令人絕望的場景之一。由於智能合約的地址不是由私鑰產生的,因此沒有任何人擁有智能合約的私鑰,就無法像控制EOA 那樣去控制這個合約。而如果該合約沒有預先編寫處理「錯誤轉入資產」的救援函數,那麼誤轉資金可能會永久鎖定在合約中,誰也無法取出。
然而在某些情況下,其實也是有一線生機的。接下來,我們會建立一個將ETH 鎖在以太坊主網的場景,然後介紹如何將資金救出來。
2.1. 場景介紹
該場景概括來說,即用戶本來想調用Sepolia 測試網的合約,將ETH 轉入合約來鑄造代幣,然而發起交易時,錯誤地連接到了主網,結果導致ETH 被鎖定在了主網的合約中。具體的場景建構過程如下:

1.在以太坊Sepolia 測試網上,項目方(EOA)部署了實現合約,假設該合約的主要功能是用戶存入ETH,來鑄造相應的AToken,大致代碼如“mintTokens”函數所示。假設部署的位址為A。需要注意的是, A 中不存在能直接提取ETH 的函數。

2.在以太坊Sepolia 測試網路上,專案方(EOA)部署了工廠合約,該合約的功能是根據提供的實現合約位址以及salt,以最小代理合約(Clones)的方式,部署指向實現合約的代理合約(如函數「deployProxyByImplementation」所示)。假設部署的位址為B。假設此處我們透過呼叫「deployProxyByImplementation」函數,以實現合約A 位址作為_implementation 傳入,部署了指向A 的代理合約,位址為C。

3. 使用者想在Sepolia 測試網上通過轉入ETH 來鑄造AToken,於是用戶向代理合約C 地址發起了調用,正常情況下,代理合約C 會進一步調用到實現合約A 的“mintTokens”函數,來完成用戶的操作。然而用戶在呼叫時,錯誤地連接到了以太坊主網。於是,用戶直接將ETH 轉入到了以太坊主網上的C 位址上。此時以太坊主網C 位址上,並未部署任何合約,也沒有人擁有該C 位址的私鑰,因此用戶的錢,暫時被鎖定在主網的C 位址上了。
2.2. 關鍵知識點
在介紹具體救援方案之前,先介紹救援所需的基本知識點。
2.2.1. create & create2
create 和create2 是Solidity 中常見的兩種部署合約的方式。
- create 部署合約時,合約地址由交易發起者的地址和該帳戶的交易次數(nonce)共同決定,與合約的內容無關。
- create2 部署合約時,合約位址的計算不再依賴交易發起者的nonce,而是與下列四個參數有關。
- 0xff
- 建立新合約的合約地址(address)
- 作為參數的混淆值(salt)
- 待創建合約的創建字節碼(init_code)
2.2.2. 最小代理合約(Clones)
https://docs.openzeppelin.com/contracts/4.x/api/proxy#clones
最小代理合約,也常被稱為克隆合約(Clones),核心思想是用極低的成本(Gas)部署一個代理合約,該代理合約指向指定的實現合約。在Clones 合約中,可以透過create 或create2 的方式部署代理合約,例如透過「cloneDeterministic」函數部署代理合約,就是採用create2 的方式進行部署。
在「cloneDeterministic」函數中,創建出的代理合約的字節碼非常簡短,格式為:「0x363d3d373d3d3d363d73<實現合約位址>5af43d82803e903d91602b57fd5bf3”,直接實現了該字節的代理程式碼並將其編碼到該位元組的基礎到該實現合約。
從「cloneDeterministic」函數看出,其採用了create2 的方式創建代理合約,創建出的代理合約的地址與合約創建者地址、salt、實現合約的地址、固定的一串字節碼有關,其與實現合約的字節碼無關。

2.3. 救援方案
接下來介紹如何救援用戶在主網C 位址上的ETH。主要想法是,在以太坊主網C 位址上,部署上合約程式碼,接管主網路C 位址,將ETH 提取出來。具體的操作步驟如下:

1. 在主網部署與測試網路上相同位址B 的工廠合約。之所以需要相同的工廠合約位址,是因為在後續呼叫「cloneDeterministic」部署代理合約時,代理合約的地址計算與工廠合約地址有關。透過查看Sepolia 測試網上部署工廠合約的交易,獲取到這筆交易中部署者(專案方地址)的nonce,在主網上,將專案方(EOA)地址的nonce 推進到部署工廠合約前的nonce,然後在主網上部署工廠合約,由於部署者的地址以及nonce 均與測試網點在主機上部署交易。
2. 在主網部署與測試網相同位址A 的實現合約。在#最小代理合約(Clones)#部分提到,透過Clones 合約的「cloneDeterministic」函數部署代理合約,其計算的代理合約位址,與入參salt、實現合約位址有關,與實現合約的字節碼無關。因此,我們只需要將一個合約部署在地址A 上即可,合約的具體內容並不影響代理合約地址的計算。那我們可以直接在位址A 部署一個具備提取ETH 功能的合約,程式碼如下所示。
在測試網上,實現合約A 是由專案方地址(EOA)部署的,因此同樣的,實現合約A 的地址只與交易發起者及其nonce 有關,因此,觀察測試網上部署實現合約A 的交易,找到相關nonce,將主網上項目方地址(EOA)推進到指定的nonce,然後部署實現合約A 即可。

3. 在主網上部署與測試網相同位址C 的代理合約。觀察測試網上部署代理合約C 的交易,獲取到salt 信息,調用工廠合約B 的“deployProxyByImplementation”函數,將實現合約A 的地址、salt 作為參數傳入,即可在主網上的地址C 上部署上代理合約。
4. 呼叫主網代理合約C 進行提款。專案方地址(EOA)呼叫代理合約C 的withdraw 函數,並指定資金接收者,成功取出代理合約C 中被凍結的ETH,然後還給相關的使用者。
2.4. 總結
從上述救援方案可以看出,資金能被救出來的情況,需要同時具備很多條件,例如合約部署者在目標鏈上的相關nonce 未被使用、困住資金的合約上具備取款函數或者可以通過各種方式部署上取款的函數(合約可升級或使用Clones 這種代理等)等。
因此,大家在交易時,一定要萬分小心,仔細核對發起的每一筆交易,與合約進行交互之前,可以使用ZAN 提供的AI SCAN漏洞掃描工具,檢測合約的安全性。如果不小心出現資金被鎖住的情況,也不要慌張,可以聯絡ZAN 的合約安全審計團隊嘗試幫您進行資金救援。
本文由 ZAN Team (X 帳號@zan_team ) & AntChain OpenLabs(X 帳號@AntChainOpenLab )的 Cara(X 帳號@Cara6289 )撰寫。
- 核心观点:误转资产能否找回取决于地址类型。
- 关键要素:
- EOA地址需持有私钥可找回。
- 合约地址无救援函数则永久锁定。
- 特定条件下可通过部署合约救援。
- 市场影响:提升用户操作谨慎性与安全工具需求。
- 时效性标注:长期影响


