自选
我的自选
查看全部
市值 价格 24h%

免责声明:内容不构成买卖依据,投资有风险,入市需谨慎!

Web3安全系列:误转到其他链上的资金,还能救回来吗?

2025-12-16 13:52:54
收藏

在链上操作越来越频繁的当下,“一秒点错链”正在成为不少用户的真实噩梦。链上数据平台显示,误转资产依然是新手乃至老用户最常见的损失来源之一,尤其集中在主网与测试网、跨链地址混用的场景。看似只是选错网络,背后却可能牵涉到私钥控制权、合约逻辑和链间不可逆的结算规则。好消息是,并非所有误转都等于永久消失,资金能否追回,关键取决于你把币打进了什么类型的地址。

场景一:收款地址是EOA

EOA(Externally Owned Account)就是我们常说的、由私钥或助记词直接控制的普通钱包地址。

找回资产前提条件:

● 你将资产转到了一个EOA地址。

● 你拥有这个目标EOA地址的私钥或助记词。(通常是你自己的另一个钱包地址,或者是朋友的地址,且他愿意配合)。

● 目标链是EVM兼容链。

找回资产方法:

● 收款EOA地址私钥持有者直接在目标链上提取资金即可。

场景二:收款地址是合约

这是最令人绝望的场景之一。由于智能合约的地址不是由私钥生成的,因此没有任何人拥有智能合约的私钥,就无法像控制EOA那样去控制这个合约。并且如果该合约没有预先编写处理“错误转入资产”的救援函数,那么误转资金可能被永久锁定在合约中,谁也无法取出。

然而在某些情况下,其实也是有一线生机的。接下来,我们会构建一个将ETH锁在以太坊主网的场景,然后介绍如何将资金救出来。

1、场景介绍

该场景概括来说,即用户本来想调用Sepolia测试网的合约,将ETH转入合约来铸造代币,然而发起交易时,错误地连接到了主网,结果导致ETH被锁定在了主网的合约中。具体的场景构建过程如下:

● 在以太坊Sepolia测试网上,项目方(EOA)部署了实现合约,假设该合约的主要功能是用户存入ETH,来铸造相应的AToken,大致代码如mintTokens函数所示。假设部署的地址为A。需要注意的是,A中不存在能直接提取ETH的函数。

● 在以太坊Sepolia测试网上,项目方(EOA)部署了工厂合约,该合约的功能是根据提供的实现合约地址以及salt,以最小代理合约(Clones)的方式,部署指向实现合约的代理合约(如函数deployProxyByImplementation所示)。假设部署的地址为B。假设此处我们通过调用deployProxyByImplementation函数,以实现合约A地址作为_implementation传入,部署了指向A的代理合约,地址为C。

● 用户想在Sepolia测试网上通过转入ETH来铸造AToken,于是用户向代理合约C地址发起了调用,正常情况下,代理合约C会进一步调用到实现合约A的mintTokens函数,来完成用户的操作。然而用户在调用时,错误地连接到了以太坊主网。于是,用户直接将ETH转入到了以太坊主网上的C地址上。此时以太坊主网C地址上,并未部署任何合约,也没有人拥有该C地址的私钥,因此用户的钱,暂时被锁定在主网的C地址上了。

2、关键知识点

在介绍具体救援方案之前,先介绍一下救援需要的基本知识点。

● create&create2

create和create2是Solidity中常见的两种部署合约的方式。

create部署合约时,合约地址由交易发起者的地址和该账户的交易次数(nonce)共同决定,与合约的内容无关。

create2部署合约时,合约地址的计算不再依赖于交易发起者的nonce,而是与以下四个参数有关。

0xff

创建新合约的合约地址(address)

作为参数的混淆值(salt)

待创建合约的创建字节码(init_code)

● 最小代理合约(Clones)

https://docs.openzeppelin.com/contracts/4.x/api/proxy#clones

最小代理合约,也常被称为克隆合约(Clones),核心思想是用极低的成本(Gas)部署一个代理合约,该代理合约指向指定的实现合约。在Clones合约中,可以通过create或者create2的方式部署代理合约,比如通过cloneDeterministic函数部署代理合约,就是采用create2的方式进行部署。

在cloneDeterministic函数中,创建出的代理合约的字节码非常简短,格式为:0x363d3d373d3d3d363d73<实现合约地址>5af43d82803e903d91602b57fd5bf3,直接将实现合约的地址硬编码到了字节码中,并将调用到该代理合约的调用都delegatecall到该实现合约。

从cloneDeterministic函数看出,其采用了create2的方式创建代理合约,创建出的代理合约的地址与合约创建者地址、salt、实现合约的地址、固定的一串字节码有关,其与实现合约的字节码无关。

3、救援方案

接下来介绍如何救援用户在主网C地址上的ETH。主要思路是,在以太坊主网C地址上,部署上合约代码,接管主网C地址,将ETH提取出来。具体的操作步骤如下:

● 在主网部署与测试网上相同地址B的工厂合约。之所以需要相同的工厂合约地址,是因为在后续调用cloneDeterministic部署代理合约时,代理合约的地址计算与工厂合约地址有关。通过查看Sepolia测试网上部署工厂合约的交易,获取到这笔交易中部署者(项目方地址)的nonce,在主网上,将项目方(EOA)地址的nonce推进到部署工厂合约前的nonce,然后在主网上部署工厂合约,由于部署者的地址以及nonce均与测试网上部署交易相同,因此在主网上部署的工厂合约地址也为B。

● 在主网部署与测试网相同地址A的实现合约。在#最小代理合约(Clones)#部分提到,通过Clones合约的cloneDeterministic函数部署代理合约,其计算出的代理合约地址,与入参salt、实现合约地址有关,与实现合约的字节码无关。因此,我们只需要将一个合约部署在地址A上即可,合约的具体内容并不影响代理合约地址的计算。那么我们可以直接在地址A上部署一个具备提取ETH功能的合约,代码如下所示。

在测试网上,实现合约A是由项目方地址(EOA)部署的,因此同样的,实现合约A的地址只与交易发起者及其nonce有关,因此,观察测试网上部署实现合约A的交易,找到相关nonce,将主网上项目方地址(EOA)推进到指定的nonce,然后部署实现合约A即可。

● 在主网上部署与测试网相同地址C的代理合约。观察测试网上部署代理合约C的交易,获取到salt信息,调用工厂合约B的deployProxyByImplementation函数,将实现合约A的地址、salt作为参数传入,即可在主网上的地址C上部署上代理合约。

● 调用主网代理合约C进行取款。项目方地址(EOA)调用代理合约C的withdraw函数,并指定资金接收者,成功取出代理合约C中被冻结的ETH,然后还给相关的用户。

4、总结

从上述救援方案可以看出,资金能被救出来的情况,需要同时具备很多条件,比如合约部署者在目标链上的相关nonce未被使用、困住资金的合约上具备取款函数或者可以通过各种方式部署上取款的函数(合约可升级或使用Clones这种代理等)等。

因此,大家在交易时,一定要万分小心,仔细核对发起的每一笔交易,与合约进行交互之前,可以使用ZAN提供的AI SCAN漏洞扫描工具,检测合约的安全性。如果不小心出现资金被锁住的情况,也不要慌张,可以联系ZAN的合约安全审计团队尝试帮您进行资金救援。

免责声明:

本网站、超链接、相关应用程序、论坛、博客等媒体账户以及其他平台和用户发布的所有内容均来源于第三方平台及平台用户。百亿财经对于网站及其内容不作任何类型的保证,网站所有区块链相关数据以及其他内容资料仅供用户学习及研究之用,不构成任何投资、法律等其他领域的建议和依据。百亿财经用户以及其他第三方平台在本网站发布的任何内容均由其个人负责,与百亿财经无关。百亿财经不对任何因使用本网站信息而导致的任何损失负责。您需谨慎使用相关数据及内容,并自行承担所带来的一切风险。强烈建议您独自对内容进行研究、审查、分析和验证。

展开阅读全文
最新文章