# Metroverse公发是怎么了 **Published by:** [01dcat](https://paragraph.com/@01dcat/) **Published on:** 2022-01-20 **URL:** https://paragraph.com/@01dcat/metroverse ## Content 发生了什么?1/19/2022也就是今天,Metroverse的publicsale。我刚好这个时候没有会议,所以打算看看是不是热的一塌糊涂。但是很奇怪Metroverse的合约啥都没有发生,就卖完了。唯一一个成功的mint是第10000个block,也就是最后一个。https://etherscan.io/tx/0x5f25e7202691ed0b5ccabf3e0640782077f9e29643b58755e6591b5c3ef6415c 其他都去哪里了??大神出现了让我们看看其他都去哪儿了!https://etherscan.io/tx/0x54993818335b0cf3e083bfddb304d1d33761e095cb92e6fcab6a41d6cdf9c612出了什么事情?我也不知道,这个 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,我也就是大概说说想法,注意我高亮的地方:checkWhietlistsaleActive计算要多少个钱包,每个钱包mint两个创建contract去call 这段mem[mem[64] len 892] 代码,如果没有猜错就是创建钱包和mintnft了剩下的问题是为什么这个contract可以改官方contract里面的数据? 我们再来看看官方如何开始公售的 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. ## Publication Information - [01dcat](https://paragraph.com/@01dcat/): Publication homepage - [All Posts](https://paragraph.com/@01dcat/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@01dcat): Subscribe to updates - [Twitter](https://twitter.com/levixie): Follow on Twitter