DappTools - 安装与使用

  • bixia1994
  • 更新于 2021-10-17 19:42
  • 阅读 4022

Dapptools的安装与调试,一个samczsun推荐的审计合约使用的工具,非常的强大。但是需要写bash脚本 :(. 又要学习怎么写bash脚本

DappTools

DappTools是Samczsun推荐使用的一个调试EVM的神器,故下载到服务器上进行初步的学习使用。

安装

官网的安装脚本异常简单,但我实际上安装到服务器上时还是踩了不少的坑,花费了很多的时间。

首先是安装条件:它仅支持linux和Mac环境,并不支持windows环境,所以在windows上就不要想了

其次是安装脚本的预置条件:

需要首先为centos添加一个alice的普通用户

useradd alice

然后再给alice赋值一定的权限:

chown alice /nix //安装时会把一些二进制文件拷贝到这个地方
chown alice /run/user/0 //也是安装时存放用户数据的地方

然后运行官网提供的脚本,记住此时是以alice为用户的:

su alice
curl -L https://nixos.org/nix/install | sh
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
curl https://dapp.tools/install | sh

如果出现任何的permission denied,则使用root用户给alice进行赋权即可。

环境变量

再安装完成dapptools后,需要先配置一定的环境变量,这样才好继续使用。这里需要用到的有两个环境变量:ETH_RPC_URL 和 ETHERSCAN_API_KEY。前者用来访问链,后者用来从etherscan上拉取对应地址的ABI文件等

export ETH_RPC_URL="https://eth-mainnet.alchemyapi.io/v2/XXXXX"
export ETHERSCAN_API_KEY="XXXX"

使用

在使用之前,需要先进行一下初始化:

su alice
cd /run/user/0/samczsun
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
source .env

dapptools最牛逼的一点在于它可以把主网上的合约代码和合约的ABI拉取到本地,然后再本地通过形式化的执行来跑一遍整个流程

//第一步:拉取主网上的合约代码和合约ABI
seth bundle-source 0x6b175474e89094c44da98b954eedeac495271d0f > daisrc.json
//第二步:利用hevm进行形式化的执行
hevm symbolic --address 0x6b175474e89094c44da98b954eedeac495271d0f --rpc $ETH_RPC_URL  --debug --sig "transfer(address,uint256)" --json-file daisrc.json

Hack Replay - COMP

https://twitter.com/msolomon44/status/1443581033220227073

这里有一个dapptools分析compound的COMPtoken分发错误的帖子,可以使用dapptools来进行分析。这个例子也体现出了dapptools的优势所在,即它可以实时的debug一笔交易,而不像hardhat或者remix需要手动部署合约。实际上即使使用了hardhat去fork了特定的blocknumber,也无法去debug它的OPCODE,对于事实上的交易顺序也是没办法重现的。

简单来讲就是COMP的一个提案62错误的给某些用户分发了错误数量的COMP Token。

这笔交易中,一个用户Claim了91170个COMP Token。https://etherscan.io/tx/0xf4bfef1655f2092cf062c008153a5be66069b2b1fedcacbf4037c1f3cc8a9f45

第一步:检查用户是否提交了可疑的数据

从etherscan我们可以看到用户调用了函数claimComp,holder为0x09d413391e975b553b7b8d19bc11f8a6c2eb889

Function: claimComp(address holder, address[] cTokens) ***

MethodID: 0x1c3db2e0
[0]:  000000000000000000000000309d413391e975b553b7b8d19bc11f8a6c2eb889 //holder
[1]:  0000000000000000000000000000000000000000000000000000000000000040 // offset
[2]:  0000000000000000000000000000000000000000000000000000000000000008 //len
[3]:  00000000000000000000000012392f67bdf24fae0af363c24ac620a2f67dad86 //addr[0]
[4]:  00000000000000000000000039aa39c021dfbae8fac545936693ac917d5e7563 //addr[1]
[5]:  0000000000000000000000004ddc2d193948926d02f9b1fe9e1daa0718270ed5 //addr[2]
[6]:  0000000000000000000000005d3a536e4d6dbd6114cc1ead35777bab948e3643 //addr[3]
[7]:  0000000000000000000000006c8c6b02e7b2be14d4fa6022dfd6d75921d90e4e //addr[4]
[8]:  00000000000000000000000070e36f6bf80a52b3b46b3af8e106cc0ed743e8e4 //addr[5]
[9]:  000000000000000000000000ccf4429db6322d5c611ee964527d42e5d685dd6a //addr[6]
[10]: 000000000000000000000000face851a4921ce59e912d19329929ce6da6eb0c7 //addr[7]

第二步:利用seth快速写一个bash脚本,找到该用户参与到的COMP池子,即调用getAssetIn函数,从而检查用户提交的8个cToken地址是否都是该用户参与的。

user=0x309d413391e975b553b7b8d19bc11f8a6c2eb889
comptroller=0x3d9819210a31b4961b30ef54be2aed79b9c9cd3b

marketsString=$(seth call $comptroller "getAssetsIn(address)(address[])" $user)
echo $marketsString
marketsArray=(${marketsString//,/ })

for market in ${marketsArray[@]}; do
    marketName=$(seth call $market "name()(string)")
    echo $market $marketName
done

得到的结果如下:

0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5 Compound Ether
0x39AA39c021dfbaE8faC545936693aC917d5E7563 Compound USD Coin
0xC11b1268C1A384e55C48c2391d8d480264A3A7F4 Compound Wrapped BTC
0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E Compound Basic Attention Token
0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643 Compound Dai
0x35A18000230DA775CAc24873d00Ff85BccdeD550 Compound Uniswap
0x70e36f6BF80a52b3B46b3aF8e106CC0ed743E8e4 Compound Collateral
0x12392F67bdf24faE0AF363c24aC620a2f67DAd86 Compound TrueUSD
0xccF4429DB6322D5C611ee964527D42E5d685DD6a Compound Wrapped BTC
0xFAce851a4921ce59e912d19329929CE6da6EB0c7 Compound ChainLink Token

从上面的结果看,该用户确实在它提出的claimComp函数中拥有以上的token,说明函数调用并没有错

第三步:我们需要进一步检查comptorller合约和对应的实现合约impl合约

已知comptroller合约地址为:0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B
对应的实现合约地址为:0x374ABb8cE19A73f2c4EFAd642bda76c797f19233, 该实现合约也是62号提案更新过的合约地址

然后从etherscan上拿到对应的实现合约的源码,以方便我们进一步调试,即:

seth bundle-source 0x374ABb8cE19A73f2c4EFAd642bda76c797f19233 > impl.json

当运行上面的命令时会出现:报错:Argument list too long

[alice@test samczsun]$ seth bundle-source 0x374ABb8cE19A73f2c4EFAd642bda76c797f19233 > impl.json
/nix/store/3fl61v0ssh5cdxqbvzvbqqx9a08j1wmg-seth-0.10.1/libexec/seth/seth-bundle-source: line 32: /nix/store/3fl61v0ssh5cdxqbvzvbqqx9a08j1wmg-seth-0.10.1/libexec/seth/seth: Argument list too long

可以参考github的issue:

https://github.com/dapphub/dapptools/issues/825

由于目前dapptools正在修复这个bug,故目前暂时无法获取到相应的数据。

然后定义一个局部变量txHash,即该用户的交易哈希

txHash=0xf4bfef1655f2092cf062c008153a5be66069b2b1fedcacbf4037c1f3cc8a9f45

第四步:debug这个tx

当拿到txHash和对应的合约json文件后,我们可调用seth的方法来展示这个交易的整个流程

seth run-tx $txHash --trace --source implementation.json

这行命令会显示出这笔交易中的所有内部交易,其效果与在ethtx.info网站上查询的交易信息一样

image20211017183043713.png

然后再执行如下命令,来逐行执行这笔交易中的代码:

seth run-tx $txHash --source implementation.json --debug

这里使用的是Dai中的一笔普通的transfer交易来做示范,不过dapptools真的太牛了!可以debug主网上的交易,并且不需要过多的配置,比用hardhat要方便好多。hardhat压根没办法按照OPCODE的方式来进行debug,一个字 牛逼!

image20211017193736598.png

点赞 4
收藏 8
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

2 条评论

请先 登录 后评论
bixia1994
bixia1994
0x92Fb...C666
learn to code