# 记录一次合约分析过程

By [plsdm7](https://paragraph.com/@dogsuisui) · 2022-11-11

---

本人移动端出身，js不太懂，sol也很菜有说讲的不对的地方欢迎来喷。

前两天有个项目freemint

[https://piratenation.game/](https://piratenation.game/)

mint分三个阶段：

1、白名单保证分配，每个地址2个

2、注册名单，有超发，不保证分配，同时白名单用户也能mint(这个我不完全确定)，相当于一个白名单的超集，每个地址3个

3、公开注册，这个可以忽略

进入2阶段，我发现mint的速度不快，但看得出来还是基本都是机器人。但是部分打的gas已经超过了os的floor。合约链接：

[https://etherscan.io/address/0x55a44e7ed23409241e1c4b9c5cbe80a066993bdd](https://etherscan.io/address/0x55a44e7ed23409241e1c4b9c5cbe80a066993bdd)

但是往前找还是会发现有小部分在block0和block1上mint成功的，这部分gas就比较划算了。

所以我想分析下mint流程。

合约不开源，decompile后地址

[https://etherscan.io/bytecode-decompiler?a=0x55a44e7ed23409241e1c4b9c5cbe80a066993bdd&userConsentRedirect=true](https://etherscan.io/bytecode-decompiler?a=0x55a44e7ed23409241e1c4b9c5cbe80a066993bdd&userConsentRedirect=true)

简单分析可以发现合约有一个开关控制mint阶段，代码中为unknownf150a049

并且1是wl，2是注册，3是public。因此可以知道，项目方在2阶段开始前需要修改这个值，txn找到这一条：

[https://etherscan.io/tx/0xc4c44f9f8b1e0e55c672974061b091683d05e38725b66a8255e59adc2d7f7a2f](https://etherscan.io/tx/0xc4c44f9f8b1e0e55c672974061b091683d05e38725b66a8255e59adc2d7f7a2f)

这里说一下，因为大部分项目都是抄来抄去的，etherscan很贴心的通过签名hash匹配把一些方法名都给标出来了，像这次的setMintStage，说实话挺难绷的。。我开始想了挺久他是怎么知道方法名的的，估计也只有这一种可能的。

其实这也不算事后诸葛亮，一直往前翻到最前面可以看到项目方开始设置过stage=1也就是开始1阶段mint。

现在要做的就是监听event然后mint了对吧，然后问题就来了：看一下mint成功的记录，就拿这个block0的大哥：

[https://etherscan.io/tx/0x164fecf2b5c7a5dd6d1d718304f82cac15e53c9dbab3642986a581b461a017af](https://etherscan.io/tx/0x164fecf2b5c7a5dd6d1d718304f82cac15e53c9dbab3642986a581b461a017af)

可以看到这个方法的参数不知道传了一堆什么鬼东西

勉强可以看出来第一个是个uint256的3，代表mint的个数，后面是一坨神马呢。可以大佬会笑我，我是真的事先不知道**merkle tree**这东西，所以对着decompile的代码看了好久，最后没办法去看js才发现这么个东西。这里具体就不解释了，总体而言他是一种比较省性能的验证方式，适合用在sol这种性能重要的场合做白名单娇艳，可以参考这个链接：

[https://mirror.xyz/yidakoumi.eth/0Lnbf4ZhFJHM3zlO--JFQr3HTktqKeHsIJlz6ln0\_H8](https://mirror.xyz/yidakoumi.eth/0Lnbf4ZhFJHM3zlO--JFQr3HTktqKeHsIJlz6ln0_H8)

了解了这个之后，我们知道要想模拟出bot钱包的校验结果，需要root值和白名单列表

我们继续看txn

[https://etherscan.io/tx/0x398abc6fd23c6a5ba668577c30d60f182ff1d4fdaecb99940685a148ea461c3f](https://etherscan.io/tx/0x398abc6fd23c6a5ba668577c30d60f182ff1d4fdaecb99940685a148ea461c3f)

这条记录项目方在2阶段开始前更新了root值，当然1阶段也设置过，这也说明1和2阶段的白名单地址是不一样的（废话。。。）

所以说root找到了，下面就是要找到白名单列表，但这一步我犯难了，因为白名单量很大，不会写在合约里，它需要前端计算后，把结果传给合约然后做校验。所以只能从js入手，进入项目mint网址：

[https://piratenation.game/mint](https://piratenation.game/mint)

容易发现具体mint逻辑在Mint.07cae2b9.js里，代码做过名次混淆看起来比较累，最后找到处理函数在enterPremint中，这里有两处调用，分别对应1 2阶段，public阶段因为不需要校验，直接调的是合约的mint函数。

![](https://storage.googleapis.com/papyrus_images/82658c2a43f5e59e5235025f42de1ff075f06bc13d6860f2257d47c6d9d17d07.png)

解释下前两行，Wn白名单列表，先把他映射成keccak256，然后交给默克尔树生成校验结果，也可以看到合约有三个参数，分别是mint数量，校验结果和mint费用。

所以问题就来到了如何获取Wn，因为我调试的时候活动已经结束了，只能想办法改一下js让流程回到mint阶段。这里控制位置在：

        return ((v = u == null ? void 0 : u.remainingSupply) == null ? void 0 : v.lte(0)) === !1 ? u.mintStage === Z0.PREMINT ? l = H(qn, {
    

大概就是先判断余量，然后判断阶段，这里简单粗暴，把u.mintStage改成Z0.PREMINT，然后把前面判断删了，变成

    u.mintStage = Z0.PREMINT;
    return 0 === 0 ? u.mintStage === Z0.PREMINT ? l = H(qn, {
    

override后刷新页面，发现成功出现了mint按钮，把按钮disable打开，点击发现断点也成功地走到了上面写的计算函数，但是这时候我发现Wn居然没有值！！！WTF，等于全白干呢，我又搜索了一下请求也没有看到白名单相关的东西，然后找了一下代码里有没有给wn赋值的地方也没找到，所以探索就到此卡住了。

我猜测可能是mint结束了不再返回白名单了，因为我只改了一个地方的判断。当然更可能是我菜没改对地方，估计在活动期间是能获取到白名单并且得出计算结果的。

所以这些bot大哥能在这么短时间分析出来白名单获取逻辑然后改好代码并且一次成功，不得不佩服了～～我前后看了四五个小时当然我还是太菜了。。

---

*Originally published on [plsdm7](https://paragraph.com/@dogsuisui/EBBVRJOcd2Z2rdOz3RRP)*
