# Metroverse公发是怎么了

By [01dcat](https://paragraph.com/@01dcat) · 2022-01-20

---

![](https://storage.googleapis.com/papyrus_images/4f5d9a486b75ecde23ee954e5b6d60dde7ec734e14bf40af661cced2dcc4d7d5.png)

发生了什么？
------

1/19/2022也就是今天，Metroverse的publicsale。我刚好这个时候没有会议，所以打算看看是不是热的一塌糊涂。但是很奇怪Metroverse的合约啥都没有发生，就卖完了。唯一一个成功的mint是第10000个block，也就是最后一个。

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

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

其他都去哪里了？？

大神出现了
-----

让我们看看其他都去哪儿了！

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

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

出了什么事情？
-------

我也不知道，这个 [0x1b900a675Dbdb008718E7763cc61c592FAcfA3EF](https://etherscan.io/address/0x1b900a675dbdb008718e7763cc61c592facfa3ef) 是个什么的合约，我只好去看看它的bytecode，基本上还是不明白，为什么这个可以把这些nft都拿走。

    #
    #  Panoramix v4 Oct 2019 
    #  Decompiled source of 0x1b900a675Dbdb008718E7763cc61c592FAcfA3EF
    # 
    #  Let's make the world open source 
    # 
    #
    #  I failed with these: 
    #  - unknowna893c195(?)
    #  - withdrawETH()
    #  - _fallback()
    #  All the rest is below.
    #const owner = 0x7b1af7b1ef831d1bf46314d3a579eb153f980776def storage:
      saleContractAddress is addr at storage 0
      count is uint256 at storage 1
      limit is uint256 at storage 2def count(): # not payable
      return countdef limit(): # not payable
      return limitdef saleContract(): # not payable
      return saleContractAddress#
    #  Regular functions
    #def setLimit(uint256 _tokenId): # not payable
      require calldata.size - 4 >=′ 32
      if 0x7b1af7b1ef831d1bf46314d3a579eb153f980776 != caller:
          revert with 0, 'Ownable: caller is not the owner'
      limit = _tokenIddef unknownafdce2ec() payable: 
      require calldata.size - 4 >=′ 64
      require cd <= 18446744073709551615
      require cd <′ calldata.size
      require ('cd', 4).length <= 18446744073709551615
      require cd * ('cd', 4).length) + 36 <= calldata.size
      require ext_code.size(saleContractAddress)
      static call saleContractAddress.0x6f2057a with:
              gas gas_remaining wei
      mem[96] = ext_call.return_data[0]
      if not ext_call.success:
          revert with ext_call.return_data[0 len return_data.size]
      require return_data.size >=′ 32
      require ext_call.return_data == bool(ext_call.return_data[0])
      require not ext_call.return_data[0]
      require ext_code.size(saleContractAddress)
      static call saleContractAddress.saleActive() with:
              gas gas_remaining wei
      mem[ceil32(return_data.size) + 96] = ext_call.return_data[0]
      if not ext_call.success:
          revert with ext_call.return_data[0 len return_data.size]
      require return_data.size >=′ 32
      require ext_call.return_data == bool(ext_call.return_data[0])
      require ext_call.return_data[0]
      if cd > 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:
          revert with 0, 17
      require ext_code.size(saleContractAddress)
      static call saleContractAddress.totalSupply() with:
              gas gas_remaining wei
      mem[(2 * ceil32(return_data.size)) + 96] = ext_call.return_data[0]
      if not ext_call.success:
          revert with ext_call.return_data[0 len return_data.size]
      mem[64] = (4 * ceil32(return_data.size)) + 96
      require return_data.size >=′ 32
      if ext_call.return_data > !(2 * cd[36]):
          revert with 0, 17
      if ext_call.return_data * cd > 10000:
          revert with 0, 'Exceeds Max Supply'
      require count < limit
      idx = 0
      while idx < cd:
          _17 = mem[64]
          mem[mem[64] len 892] = 0xfe608060405260405161037c38038061037c833981016040819052610022916101ca565b600080826001600160a01b0316348560008151811061005157634e487b7160e01b600052603260045260246000fd5b6020026020010151604051610066919061029d565b60006040518083038185875af1925050503d80600081146100a3576040519150601f19603f3d011682016040523d82523d6000602084013e6100a8565b606091505b5091509150816100b757600080fd5b826001600160a01b0316846001815181106100e257634e487b7160e01b600052603260045260246000fd5b60200260200101516040516100f7919061029d565b6000604051808303816000865af19150503d8060008114610134576040519150601f19603f3d011682016040523d82523d6000602084013e610139565b606091505b5050505050505061032f565b80516001600160a01b038116811461015c57600080fd5b919050565b600082601f830112610171578081fd5b81516001600160401b0381111561018a5761018a610319565b61019d601f8201601f19166020016102b9565b8181528460208386010111156101b1578283fd5b6101c28260208301602087016102e9565b949350505050565b600080604083850312156101dc578182fd5b82516001600160401b03808211156101f2578384fd5b818501915085601f830112610205578384fd5b815160208282111561021957610219610319565b8160051b6102288282016102b9565b8381528281019086840183880185018c101561024257898afd5b8993505b8584101561027f5780518781111561025c578a8bfd5b61026a8d87838c0101610161565b84525060019390930192918401918401610246565b509750610290915050878201610145565b9450505050509250929050565b600082516102af8184602087016102e9565b9190910192915050565b604051601f8201601f191681016001600160401b03811182821017156102e1576102e1610319565b604052919050565b60005b838110156103045781810151838201526020016102ec565b83811115610313576000848401525b50505050565b634e487b7160e01b600052604160045260246000fd5b603f8061033d6000396000f3fe6080604052600080fdfea264697066735822122053f6501ff55f957ac07c643b9763b0d556c11ce1ec1de13a2bb98828df801aae64736f6c634300080400
          mem[mem[64] + 892] = 64
          mem[mem[64] + 956] = ('cd', 4).length
          s = 0
          t = cd[4] + 36
          u = mem[64] + 988
          v = mem[64] + (32 * ('cd', 4).length) + 988
          while s < ('cd', 4).length:
              mem[u] = v + -_17 - 988
              require cd[t] <′ calldata.size + -cd[4] - 67
              require cd[(cdt] + 36)] <= 18446744073709551615
              require cd <=′ calldata.size - cd[(cdt] + 36)]
              mem[v] = cd[(cdt] + 36)]
              mem[v + 32 len cd[(cdt] + 36)]] = call.data[cdt] + 68 len cd[(cdt] + 36)]]
              mem[cd[(cdt] + 36)] + v + 32] = 0
              s = s + 1
              t = t + 32
              u = u + 32
              v = v + ceil32(cd[(cdt] + 36)]) + 32
              continue 
          mem[_17 + 924] = saleContractAddress
          create contract with 200000000000000000 wei
                          code: mem[memem[64] + 988]
          if not create.new_address:
              revert with ext_call.return_data[0 len return_data.size]
          if idx == -1:
              revert with 0, 17
          idx = idx + 1
          continue 
      if cd > 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:
          revert with 0, 17
      if count > !(2 * cd[36]):
          revert with 0, 17
      count += 2 * cd[36]def unknown888fdd2e(): # not payable
      require calldata.size - 4 >=′ 128
      require cd <= 18446744073709551615
      require cd <′ calldata.size
      require ('cd', 4).length <= 18446744073709551615
      require cd * ('cd', 4).length) + 36 <= calldata.size
      require cd == addr(cd)
      require cd <= 18446744073709551615
      require cd <′ calldata.size
      require ('cd', 100).length <= 18446744073709551615
      require cd('cd', 100).length + 36 <= calldata.size
      mem[96 len ('cd', 100).length] = call.data[cd('cd', 100).length]
      mem[('cd', 100).length + 96] = 0
      call addr(cd) with:
           gas gas_remaining wei
          args call.data[cd('cd', 100).length]
      if not return_data.size:
          require ext_call.success
          require ext_code.size(saleContractAddress)
          static call saleContractAddress.0x6f2057a with:
                  gas gas_remaining wei
          mem[96] = ext_call.return_data[0]
          if not ext_call.success:
              revert with ext_call.return_data[0 len return_data.size]
          require return_data.size >=′ 32
          require ext_call.return_data == bool(ext_call.return_data[0])
          require not ext_call.return_data[0]
          require ext_code.size(saleContractAddress)
          static call saleContractAddress.saleActive() with:
                  gas gas_remaining wei
          mem[ceil32(return_data.size) + 96] = ext_call.return_data[0]
          if not ext_call.success:
              revert with ext_call.return_data[0 len return_data.size]
          require return_data.size >=′ 32
          require ext_call.return_data == bool(ext_call.return_data[0])
          require ext_call.return_data[0]
          if cd > 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:
              revert with 0, 17
          require ext_code.size(saleContractAddress)
          static call saleContractAddress.totalSupply() with:
                  gas gas_remaining wei
          mem[(2 * ceil32(return_data.size)) + 96] = ext_call.return_data[0]
          if not ext_call.success:
              revert with ext_call.return_data[0 len return_data.size]
          mem[64] = (4 * ceil32(return_data.size)) + 96
          require return_data.size >=′ 32
          if ext_call.return_data > !(2 * cd[36]):
              revert with 0, 17
          if ext_call.return_data * cd > 10000:
              revert with 0, 'Exceeds Max Supply'
          require count < limit
          idx = 0
          while idx < cd:
              _36 = mem[64]
              mem[mem[64] len 892] = 0xfe608060405260405161037c38038061037c833981016040819052610022916101ca565b600080826001600160a01b0316348560008151811061005157634e487b7160e01b600052603260045260246000fd5b6020026020010151604051610066919061029d565b60006040518083038185875af1925050503d80600081146100a3576040519150601f19603f3d011682016040523d82523d6000602084013e6100a8565b606091505b5091509150816100b757600080fd5b826001600160a01b0316846001815181106100e257634e487b7160e01b600052603260045260246000fd5b60200260200101516040516100f7919061029d565b6000604051808303816000865af19150503d8060008114610134576040519150601f19603f3d011682016040523d82523d6000602084013e610139565b606091505b5050505050505061032f565b80516001600160a01b038116811461015c57600080fd5b919050565b600082601f830112610171578081fd5b81516001600160401b0381111561018a5761018a610319565b61019d601f8201601f19166020016102b9565b8181528460208386010111156101b1578283fd5b6101c28260208301602087016102e9565b949350505050565b600080604083850312156101dc578182fd5b82516001600160401b03808211156101f2578384fd5b818501915085601f830112610205578384fd5b815160208282111561021957610219610319565b8160051b6102288282016102b9565b8381528281019086840183880185018c101561024257898afd5b8993505b8584101561027f5780518781111561025c578a8bfd5b61026a8d87838c0101610161565b84525060019390930192918401918401610246565b509750610290915050878201610145565b9450505050509250929050565b600082516102af8184602087016102e9565b9190910192915050565b604051601f8201601f191681016001600160401b03811182821017156102e1576102e1610319565b604052919050565b60005b838110156103045781810151838201526020016102ec565b83811115610313576000848401525b50505050565b634e487b7160e01b600052604160045260246000fd5b603f8061033d6000396000f3fe6080604052600080fdfea264697066735822122053f6501ff55f957ac07c643b9763b0d556c11ce1ec1de13a2bb98828df801aae64736f6c634300080400
              mem[mem[64] + 892] = 64
              mem[mem[64] + 956] = ('cd', 4).length
              s = 0
              t = cd[4] + 36
              u = mem[64] + 988
              v = mem[64] + (32 * ('cd', 4).length) + 988
              while s < ('cd', 4).length:
                  mem[u] = v + -_36 - 988
                  require cd[t] <′ calldata.size + -cd[4] - 67
                  require cd[(cdt] + 36)] <= 18446744073709551615
                  require cd <=′ calldata.size - cd[(cdt] + 36)]
                  mem[v] = cd[(cdt] + 36)]
                  mem[v + 32 len cd[(cdt] + 36)]] = call.data[cdt] + 68 len cd[(cdt] + 36)]]
                  mem[cd[(cdt] + 36)] + v + 32] = 0
                  s = s + 1
                  t = t + 32
                  u = u + 32
                  v = v + ceil32(cd[(cdt] + 36)]) + 32
                  continue 
              mem[_36 + 924] = saleContractAddress
              create contract with 200000000000000000 wei
                              code: mem[memem[64] + 988]
              if not create.new_address:
                  revert with ext_call.return_data[0 len return_data.size]
              if idx == -1:
                  revert with 0, 17
              idx = idx + 1
              continue 
      else:
          mem[96] = return_data.size
          mem[128 len return_data.size] = ext_call.return_data[0 len return_data.size]
          require ext_call.success
          require ext_code.size(saleContractAddress)
          static call saleContractAddress.0x6f2057a with:
                  gas gas_remaining wei
          mem[ceil32(return_data.size) + 97] = ext_call.return_data[0]
          if not ext_call.success:
              revert with ext_call.return_data[0 len return_data.size]
          require return_data.size >=′ 32
          require ext_call.return_data == bool(ext_call.return_data[0])
          require not ext_call.return_data[0]
          require ext_code.size(saleContractAddress)
          static call saleContractAddress.saleActive() with:
                  gas gas_remaining wei
          mem[ceil32(return_data.size) + ceil32(return_data.size) + 97] = ext_call.return_data[0]
          if not ext_call.success:
              revert with ext_call.return_data[0 len return_data.size]
          require return_data.size >=′ 32
          require ext_call.return_data == bool(ext_call.return_data[0])
          require ext_call.return_data[0]
          if cd > 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:
              revert with 0, 17
          require ext_code.size(saleContractAddress)
          static call saleContractAddress.totalSupply() with:
                  gas gas_remaining wei
          mem[ceil32(return_data.size) + (2 * ceil32(return_data.size)) + 97] = ext_call.return_data[0]
          if not ext_call.success:
              revert with ext_call.return_data[0 len return_data.size]
          mem[64] = ceil32(return_data.size) + (4 * ceil32(return_data.size)) + 97
          require return_data.size >=′ 32
          if ext_call.return_data > !(2 * cd[36]):
              revert with 0, 17
          if ext_call.return_data * cd > 10000:
              revert with 0, 'Exceeds Max Supply'
          require count < limit
          idx = 0
          while idx < cd:
              _37 = mem[64]
              mem[mem[64] len 892] = 0xfe608060405260405161037c38038061037c833981016040819052610022916101ca565b600080826001600160a01b0316348560008151811061005157634e487b7160e01b600052603260045260246000fd5b6020026020010151604051610066919061029d565b60006040518083038185875af1925050503d80600081146100a3576040519150601f19603f3d011682016040523d82523d6000602084013e6100a8565b606091505b5091509150816100b757600080fd5b826001600160a01b0316846001815181106100e257634e487b7160e01b600052603260045260246000fd5b60200260200101516040516100f7919061029d565b6000604051808303816000865af19150503d8060008114610134576040519150601f19603f3d011682016040523d82523d6000602084013e610139565b606091505b5050505050505061032f565b80516001600160a01b038116811461015c57600080fd5b919050565b600082601f830112610171578081fd5b81516001600160401b0381111561018a5761018a610319565b61019d601f8201601f19166020016102b9565b8181528460208386010111156101b1578283fd5b6101c28260208301602087016102e9565b949350505050565b600080604083850312156101dc578182fd5b82516001600160401b03808211156101f2578384fd5b818501915085601f830112610205578384fd5b815160208282111561021957610219610319565b8160051b6102288282016102b9565b8381528281019086840183880185018c101561024257898afd5b8993505b8584101561027f5780518781111561025c578a8bfd5b61026a8d87838c0101610161565b84525060019390930192918401918401610246565b509750610290915050878201610145565b9450505050509250929050565b600082516102af8184602087016102e9565b9190910192915050565b604051601f8201601f191681016001600160401b03811182821017156102e1576102e1610319565b604052919050565b60005b838110156103045781810151838201526020016102ec565b83811115610313576000848401525b50505050565b634e487b7160e01b600052604160045260246000fd5b603f8061033d6000396000f3fe6080604052600080fdfea264697066735822122053f6501ff55f957ac07c643b9763b0d556c11ce1ec1de13a2bb98828df801aae64736f6c634300080400
              mem[mem[64] + 892] = 64
              mem[mem[64] + 956] = ('cd', 4).length
              s = 0
              t = cd[4] + 36
              u = mem[64] + 988
              v = mem[64] + (32 * ('cd', 4).length) + 988
              while s < ('cd', 4).length:
                  mem[u] = v + -_37 - 988
                  require cd[t] <′ calldata.size + -cd[4] - 67
                  require cd[(cdt] + 36)] <= 18446744073709551615
                  require cd <=′ calldata.size - cd[(cdt] + 36)]
                  mem[v] = cd[(cdt] + 36)]
                  mem[v + 32 len cd[(cdt] + 36)]] = call.data[cdt] + 68 len cd[(cdt] + 36)]]
                  mem[cd[(cdt] + 36)] + v + 32] = 0
                  s = s + 1
                  t = t + 32
                  u = u + 32
                  v = v + ceil32(cd[(cdt] + 36)]) + 32
                  continue 
              mem[_37 + 924] = saleContractAddress
              create contract with 200000000000000000 wei
                              code: mem[memem[64] + 988]
              if not create.new_address:
                  revert with ext_call.return_data[0 len return_data.size]
              if idx == -1:
                  revert with 0, 17
              idx = idx + 1
              continue 
      if cd > 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:
          revert with 0, 17
      if count > !(2 * cd[36]):
          revert with 0, 17
      count += 2 * cd[36]
    

你都到这了，我们还是往下看看吧
---------------

我们只看这个unknown888fdd2e，这个就是这位大神的思路，当然我不是smartcontract的expert，我也就是大概说说想法，注意我高亮的地方：

1.  checkWhietlist
    
2.  saleActive
    
3.  计算要多少个钱包，每个钱包mint两个
    
4.  创建contract去call 这段**_mem\[mem\[64\] len 892\]_** 代码，如果没有猜错就是创建钱包和mintnft了
    

剩下的问题是为什么这个contract可以改官方contract里面的数据？

我们再来看看官方如何开始公售的

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

这个就是官方的call，这个时候科学家把里面的签名拿了，完全一样的call了自己的contract，如果没有猜错，科学家把官方的tx拿到了，然后加大gas，运气好了就赢了。

bonus point: 这儿必须要check owner亚

    function mintNFT(uint256 amount, bool stake) public payable {         require(!checkWhitelist, "Not public mode");          _mintNFT(amount, "", "", stake);     
    }
    

但是也有可能他有别的方式保证自己的成功率，但是我们还没有看出来。

结论
--

在mint的时候还是要检查owner亚。。。

本来了项目方使用Gnosis来做多重签名是好的，但是这个没有办法避免tx跟监听，然后先做了。应用的场景完全不对了。

_Originally published at_ [_https://01dcat.notion.site_](https://01dcat.notion.site/Metroverse-c9bfdf572d8c4be1a2c8514b8867d7fc).

---

*Originally published on [01dcat](https://paragraph.com/@01dcat/metroverse)*
