本文作者:bixia1994[1]
DappTools
DappTools是Samczsun推荐使用的一个调试EVM[2]的神器,故下载到服务器上进行初步的学习使用。
安装
官网的安装脚本异常简单,但我实际上安装到服务器上时还是踩了不少的坑,花费了很多的时间。
首先是安装条件:它仅支持linux和Mac环境,并不支持windows环境,所以在windows上就不要想了
其次是安装脚本的预置条件:
需要首先为centos添加一个alice的普通用户
代码语言:javascript复制useradd alice
然后再给alice赋值一定的权限:
代码语言:javascript复制chown alice /nix //安装时会把一些二进制文件拷贝到这个地方
chown alice /run/user/0 //也是安装时存放用户数据的地方
然后运行官网提供的脚本,记住此时是以alice为用户的:
代码语言:javascript复制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文件等
代码语言:javascript复制export ETH_RPC_URL="https://eth-mainnet.alchemyapi.io/v2/XXXXX"
export ETHERSCAN_API_KEY="XXXX"
使用
在使用之前,需要先进行一下初始化:
代码语言:javascript复制su alice
cd /run/user/0/samczsun
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
source .env
dapptools最牛逼的一点在于它可以把主网上的合约代码和合约的ABI拉取到本地,然后再本地通过形式化的执行来跑一遍整个流程
代码语言:javascript复制//第一步:拉取主网上的合约代码和合约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[3]的COMPtoken分发错误的帖子,可以使用dapptools来进行分析。这个例子也体现出了dapptools的优势所在,即它可以实时的debug一笔交易,而不像hardhat[4]或者remix需要手动部署合约。实际上即使使用了hardhat去fork了特定的blocknumber,也无法去debug它的OPCODE,对于事实上的交易顺序也是没办法重现的。
简单来讲就是COMP的一个提案62错误的给某些用户分发了错误数量的COMP Token。
这笔交易中,一个用户Claim了91170个COMP Token。https://etherscan.io/tx/0xf4bfef1655f2092cf062c008153a5be66069b2b1fedcacbf4037c1f3cc8a9f45
第一步:检查用户是否提交了可疑的数据
从etherscan我们可以看到用户调用了函数claimComp,holder为0x09d413391e975b553b7b8d19bc11f8a6c2eb889
代码语言:javascript复制Function: claimComp(address holder, address[] cTokens) ***
MethodID: 0x1c3db2e0
//holder
// offset
//len
//addr[0]
//addr[1]
//addr[2]
//addr[3]
//addr[4]
//addr[5]
//addr[6]
//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
得到的结果如下:
代码语言:javascript复制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合约
代码语言:javascript复制已知comptroller合约地址为:0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B
对应的实现合约地址为:0x374ABb8cE19A73f2c4EFAd642bda76c797f19233, 该实现合约也是62号提案更新过的合约地址
然后从etherscan上拿到对应的实现合约的源码,以方便我们进一步调试,即:
代码语言:javascript复制seth bundle-source 0x374ABb8cE19A73f2c4EFAd642bda76c797f19233 > impl.json
当运行上面的命令时会出现:报错:Argument list too long
代码语言:javascript复制[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,即该用户的交易哈希
代码语言:javascript复制txHash=0xf4bfef1655f2092cf062c008153a5be66069b2b1fedcacbf4037c1f3cc8a9f45
第四步:debug这个tx
当拿到txHash和对应的合约json文件后,我们可调用seth的方法来展示这个交易的整个流程
代码语言:javascript复制seth run-tx $txHash --trace --source implementation.json
这行命令会显示出这笔交易中的所有内部交易,其效果与在ethtx.info网站上查询的交易信息一样
然后再执行如下命令,来逐行执行这笔交易中的代码:
代码语言:javascript复制seth run-tx $txHash --source implementation.json --debug
这里使用的是Dai中的一笔普通的transfer交易来做示范,不过dapptools真的太牛了!可以debug主网上的交易,并且不需要过多的配置,比用hardhat要方便好多。hardhat压根没办法按照OPCODE的方式来进行debug,一个字 牛逼!
参考资料
[1]
bixia1994: https://learnblockchain.cn/people/3295
[2]
EVM: https://learnblockchain.cn/2019/10/05/evm-data
[3]
compound: https://learnblockchain.cn/article/1015
[4]
hardhat: https://learnblockchain.cn/docs/hardhat/getting-started/