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

USDT 代币合约分析

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

USDT 代币合约分析

一个代币合约最基本功能有增发币、销毁币、转账、批准、查询等,我们以以太坊网络上的 USDT 为例看一下代币合约的细节,合约地址:https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7。在 etherscan 浏览器上找到 Contract 可以看到合约代码,可以看到有好几个合约,需要找到主合约,点击 Outline 找到黄底加粗的就是主合约,如下图所示。

在 etherscan 浏览器有一个功能是可以显示合约之间的继承关系图,在合约代码页面点击 More Option -> Sol2Umi ,找到 TetherToken 主合约的图,如下图所示。

从图上可以看出,constructor 构造函数有 4 个参数,分别是总量、币的名称,币的符号名,币的小数精度。在 remix 上填上这 4 个参数即可布署合约

增发、销毁、更新合约

USDT合约有 4 个事件,分别是增发币、销毁币、升级合约,调整手续费,这 4 个事件分别会在 issue、redeem, deprecate、setParams 这 4 个函数中触发。

(1) 增发函数 issue,这个函数只能由 Owner 调用,只有一个参数 amount,用于指定需要增发的数量,从代码可以看出,铸币是给 Owner 的地址增发相应的币数。

(2) 销毁函数 redeem,这个函数也是只能由 Owner 调用,也是只有一个参数 amount,用于指定需要销毁的数量,Owner 的地址减少相应的币数。

(3) 更新合约函数 deprecate,这个函数的功能可以作废当前合约,转到一个新的合约,有一个参数 _upgradedAddress,这个是更新后的合约地址。可以看到代码里的全局变量 deprecate 置为 true,一旦 deprecated 为 true,这个合约的功能已经失效,会转向新的合约,这也相当于一个后门。

转账与黑名单

与转账相关的有下面这 5 个函数。transfer 用于转账,transferFrom 也是用于转账,它与前者的区别是 transfer 只能从调用者自己账户里转账到目标,而 transferFrom 可以从第三者的账户里转账到目标,当然这需要第三者事先调用 approve 函数先批准授权指定哪个地址能够有权限操纵多少币。allowance 函数是获取某个地址授权给另一个地址可操纵的币的数量。balanceOf 函数用于获取指定地址当前的余额。

之前总听说 USDT 不安全,有后门可以冻结。看一下 transfer 函数,第一句就是判断调用者的地址不能在黑名单列表里,transfer From 也类似的判断。

黑名单列表有两个函数可以操作,一个是添加 addBlackList,一个是删除 removeBlackList,参数都是提供需要操作的地址。操作黑名单的函数只有 Owner 可以调用。

看样子 USDT 的项目方真的是可以冻结任一地址,那么历史上有没有被冻结的地址呢?可以看出 addBlackList 函数会触发一个事件 AddedBlackList,那只要在区块链浏览器里过滤出这个事件,就知道有没有地址被冻结过,在 geth 以太坊的客户端控制台使用下面的命令可以得到 AddedBlackList 事件签名的 keccak256 值。

得到事件签名值之后,在 etherscan 浏览器事件的搜索框输入0x42e160154868087d6bfdc0ca23d96a1c1cfa32f1b72ba9ba27b69b98a0d819dc 即可查询到 AddedBlackList 事件的调用 ,topic0 即是过滤条件,下面的的参数是“拉黑”的地址,默认显示是 hex 格式,可以改成 Addr,看得更清楚,如下图所示。

除了可以冻结黑名单的地址,还可以销毁黑名单地址的币。destroyBlackFunds 函数用于销毁黑名单地址的币,首先会判断传入的地址是否在黑名单列表,如果不在则不会执行,然后获取该地址币的数量,将该地址的币清零,并且把总币数量减掉原来该地址的币数。

补充几个常用的函数

最后补充几个在合约审计经常会遇到的函数,获取合约地址、获取合约所有者的地址、获取发送者的地址、获取合约的余额、获取合约所有者的余额、获取发送者的余额。

(1) 获取合约的地址,即是 this 的地址。

(2) 获取合约所有者的地址,owner 地址一般定义成全局变量,在构造函数的时候获取 msg.sender 调用者的地址即是所有者。

(3) 获取发送者的地址,即是 msg.sender。

(4) 获取合约的余额,即 this 的 balance。

(5) 获取合约所有者的余额,owner 的余额,在获取时可以判断一下调用者是否是合约的 owner,不是的话不让获取。

(6) 获取发送者的余额,得到 mag.sender.balance 即可。

转载请注明:exchen's blog » USDT 代币合约分析

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

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

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