最新消息:本站技术交流 QQ 群:28124927

USDT 多签钱包合约分析

区块链/比特币 exchen 2486浏览 0评论

USDT 多签钱包合约分析

之前看过 USDT 的合约,了解到它有一个 issue 函数用于增发,只有 owner 调用 issue 才可以增发,但仔细分析并没有那么简单,它的 owner 不是普通地址,是一个合约地址 ,这个合约是一个多签钱包。多签钱包主要特点是有多个 owner,执行增发操作时,并不需要满足所有 owner 的批准,在合约里指定 required 的数量,只要获得批准的 owner 数量满足 required 数量即可执行操作。

USDT 的多签钱包地址是 https://etherscan.io/address/0xc6cde7c39eb2f0f0095f41570af89efc2c1ea828#readContract, 目前是有 6 个 owner,增发币只要满足 3 个 owner 的批准即可。下面我们来具体分析。

具体代码

比如要执行一个增发币,主要会有三个事件,一开始是 Submission 提交一个交易,提交后不会马上执行,要等待 owner 们批准,批准事件是 Confirmation ,最终执行事件是 Execution。

提交交易需要构造 Transaction 结构体,由 4 个参数组成。

接下来我们看一下构造函数,和合约名称相同的函数是构造函数,里面有两个参数,owners 是一个数组,_required 是多签的最低确认数,不管 owner 有多少个,只要满足 _required 的确认数量即可执行交易操作,比如 owner 有 6 个,required 是 3,那么只要有 3 个 owner 确认,交易即可发送。

要执行一个操作,先调用 submitTransaction 函数,提供三个参数,destination 是 USDT 合约地址,value 是主币 ETH,data 是 USDT 合约里的函数和参数。addTransaction 函数构造 Transaction 结构。

confirmTransaction 函数是用于批准操作,如果需要 3 个 owner 批准,那 3 个 owner 都调用该函数,提供需要操作的 transactionId 即可,将 transactionId 的状态置为 true。 revokeConfirmation 函数是拒绝操作,将 transactionId 的状态置为 false。

executeTransaction 是用于最终执行交易操作,使用的是 call 指令调用 USDT 合约。不过其实在 confirmTransaction 函数中,如果是 owner 批准的数量足够,会调用 executeTransaction。

分析 USDT 增发的过程

接下来我们来分析 USDT 的增发过程,加深对多签钱包合约的理解。2021年11月8日 Tether 在以太坊链上增发 10 亿USDT,交易哈希为:0xb313f71038cbb873919707eb81618bed35678cbb578bd214f630204cde00dfe1。我们来分析下这个增发的过程,通过 etherscan 浏览器查到这笔交易的详情,可以看到调用了 confirmTransaction 函数,参数十六进制 619,转为十进制是 1561,MethodID 为 0xc01a8c84 是函数的签名,如下图所示:

点击 Logs 标签栏,可以看到有 3 个事件,Conformation 事件是 owner 批准操作,批准的交易 ID 是 1561,Issue 事件从地址上可以看出是 USDT 合约的增发函数 issue 发出的事件,从参数上可以看出增发数量是 1000000000000000,USDT 的最小精度是 6,相当于 10 亿个 USDT,Execution 是执行交易操作,如下图所示:

回到多签钱包合约代码上,在 transctions 输入交易 ID 1561,可以看到交易结构体里的 4 个参数,参数的含义上面的代码有讲过,其中 data 是用于调用 USDT 合约参数,前面 0xcc872b66 是 USDT 合约里的增发函数 issue 的签名值,后面是 038d7ea4c68000 是增发的数据,转换为十进制是 1000000000000000,即 10 亿个,如下图所示。

增发函数的调用可以转为以下伪代码:

关于函数签名

函数签名也称为选择器,将函数的名称和函数的参数打包在一起计算出哈希,然后取哈希前 4 个字节,下面我们编写两个合约,一个合约是 FunctionSelector 用于获取函数的签名,一个是 FunctionTest 用于打印日志,将 data 数据打印出来,和函数签名做对比,具体代码如下:

布署 FunctionTest 合约,输入参数 100000000000000,执行后会在控制台打印日志,找到 data 数据,如下图所示:

再布署 FunctionSelector 合约,输入 issue(uint256),得出的签名值是 0xcc872b66,与 USDT 增发函数的签名值是一样的,如下图所示。由于 EVM 是通过函数签名去寻找函数的,所以一个合约里可以存在同名的函数,只要参数不一样签名就不同。

转载请注明:exchen's blog » USDT 多签钱包合约分析

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址