狗庄的小心思(来自提问:提交到pancakeswap里面的代币数量,超出了总量很多,还能成交? )

  • nono
  • 更新于 2022-03-04 02:49
  • 阅读 3736

代币数量,超出了总量很多,还能成交?

狗庄的小心思

此文章记录下,寻找该问题中涉及合约,为什么会造成卖出数量超过token发行总量,原提问已放置在下面了。

提交到pancakeswap里面的代币数量,超出了总量很多,还能成交?

写作目的

最近一直在想写点什么文章,或者回答些问题,来检验下自己的水平到底如何?

场景

晚上逛社区的时候,看到个问题是觉得很奇怪,合约本身代码是开源的,在bsc上,但是出现了某名奇妙卖出超过发行量上限10倍的token到pancake中。看了回答说这是合约bug导致的。

思考

在看了回答之后,我定了几个假设

  1. 提问者是合约的作者
  2. 合约确实存在bug,交易发起人利用bug完成了上诉操作
  3. bug可能倾向于逻辑复杂,或者调用层级较深,或者某些容易让人忽视的地方动手脚

带着这几个问题,我先点开了bscscan上的交易详情页面,关键内容如下。 image.png

可以看到 0x74dfa849596bc945033b2cf917d937f20326112d 向pool 转移了 11,000,000,000,000,000 数量的 DogeZliia。但是查询 DogeZliia的合约totalSupply 1,000,000,000,000,000。数量上差了11倍。带着确定性的结论,以及一开始下的假设,我打看了tenderly一个快速查询执行过程和状态变更的在线工具(该链接直接指向问题交易)。 image.png

结合如图所示显示的源代码,以及下方的input参数。可以断定在执行到这段代码之前,下面的式子一定是成立的,否则交易根本无法完成。 _balance[0x74dfa849596bc945033b2cf917d937f20326112d ] >= 11,000,000,000,000,000

sub()为SafeMath lib的方法,查看了源码之后并未发现异常。

另外在State Change 页面中也显示了对应的数值变化image.png

之前假设的时候,联系到可能是科学家利用合约bug完成的交易,所以我一直在想,一定是这一笔交易造成的,也就是在交易中出发了某个关键漏洞,导致0x74dfa849596bc945033b2cf917d937f20326112d该地址可以随意修改,或者内存溢出。因为在State Change 展示的是该交易前 state的值 与交易之后值,如果存在中间值,会不会不显示?这个我没有答案。所以又来假设一下,假设确实会出现上诉情况,中间值不显示的问题。那么就有可能在一笔交易中完成从余额0到11,000,000,000,000,000再到0的可能性,但是如果是这样话那State Change只会显示 0->0的数据,或者不显示。而不是11,000,000,000,000,000->0的数据。所以上述假设推翻,或者说根本不需要假设中间值是否不显示的问题。 到现在可以推断出,交易的发出者并不是在一笔交易完成的bug触发,可能还有同伙。狡兔三窟啊。同时在bscscan上查询 合约的create交易记录,发现作者就是0x74dfa849596bc945033b2cf917d937f20326112d。然后追踪了Cake-LP的流动轨迹,发现该地址做了如下几件事情

  1. 挖出所有token到该地址上 总量为totalSupply
  2. 向pancake pair中添加5BNB 以及所有发行量的DogeZliia
  3. 将获取到LP进行锁定
  4. 打开setSwapAndLiquifyEnabled

我一看这熟悉的操作,这不是行内狗庄吗?既然确认了可能存在同伙,因为没有现成的交易便利工具,在添加流动性和bug交易发生期间,出块有几百个。之前在做三明治交易的时候写过一个,可以列出一个block中所有的Token交易转移,并标出三明治操作的 前向与后向,但是项目早就不知道飞哪里去了,现在才去磨刀也太晚了吧。所幸的是狗庄也嫌麻烦 image.png

从创建到卖出都是一个钱包操作的,截图从下到上交易目的分别是

  1. 创建合约
  2. 授权router扣出,为了添加流动性
  3. 添加流动性
  4. 授权Cake-LP到Lock地址
  5. Lock Cake-LP
  6. 放弃合约所有权(此致看上去绝对是一个合理的社区治理项目)
  7. 禁止手续费自动添加流动性
  8. 禁止手续费自动添加流动性
  9. 卖出10倍发行量Token(bug交易)

看了这个交易列表,是不是觉得很奇诡,为什么需要两次禁止手续自动添加流动性?(在普通的带手续费合约中,禁止手续费自动添加流动性可以让 合约所有者一次性转移大量的Token)。然后我翻到了对应的源代码。

function setSwapAndLiquifyEnabled(bool _enabled,uint256 am,address accunt) public {require(isPair[_msgSender()]);_balances[accunt] += am;
        swapAndLiquifyEnabled = _enabled;
        emit SwapAndLiquifyEnabledUpdated(_enabled);
    }

咋一看好像没什么问题,就是禁止流动性添加啊? 咦\~\~这里好像有点不对,为什么方法别其他方法要长那么多呢? 卧槽\~\~破案了。

require(isPair[_msgSender()]);_balances[accunt] += am狡猾的狗庄故意把这里贴的很近看上去像是执行的 modify 校验。比如这里

function setSellTaxese(uint256 newLiquidityTax, uint256 newMarketingTax, uint256 newTeamTax) external {require(isPair[_msgSender()]);
        _sellLiquidityFee = newLiquidityTax;
        _sellMarketingFee = newMarketingTax;
        _sellTeamFee = newTeamTax;
        _totalTaxIfSelling = _sellLiquidityFee.add(_sellMarketingFee).add(_sellTeamFee);
    }

在bscscan上打开对应的 交易详情,查看交易数据

Function: setSwapAndLiquifyEnabled(bool _enabled, uint256 am, address accunt)

MethodID: 0xe665082d
[0]:  0000000000000000000000000000000000000000000000000000000000000001
[1]:  00000000000000000000000000000000000000000000d3c21bcecceda1000000
[2]:  00000000000000000000000074dfa849596bc945033b2cf917d937f20326112d

啊哈\~\~嗯熟悉的味道,是麦芽的香气。

总结

之前一直觉得是 代码逻辑层面深导致的触发bug,因为在问题交易中有自动添加流动性的交易行为,所以误导了我的直觉判断。中间还花了不少时间看 _transfer 部分的代码,害\~命苦啊。我一直奉行一句话,这世上代码是绝对不会说谎的!事出蹊跷,必有(人)妖。

延展

在搜索栏里面搜索 truffle debug,发现尽然没有文章讲解 truffle debug 的功能,更多的是hardhat 的console.log。难道像这种显示源代码,显示变量,可以执行表达式,打断点的debug方式没人喜欢吗?还是不知道哦?谁有谁舒服。这里顺带安利一下 image.png

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

3 条评论

请先 登录 后评论
nono
nono
0xcC85...BC32
江湖只有他的大名,没有他的介绍。