Open derekpierre opened 1 week ago
This article claimed that you can do a reverse search for 0033 and then use the bytecode after that for the constructor args
This doesn't seem safe, what if there's 0033
somewhere in the constructor args? In general it seems that, with the way deployment code is organized in Ethereum, determining the position of the constructor arguments is akin to the halting problem: you have to run the whole thing to find out what it returns and what it uses as inputs.
I guess it is possible to get the constructor args if you know the constructor signature and can thus derive the full encoded size of the arguments, so you can take that substring from the end of the deployment bytecode and decode it. And if there are dynamic size arguments, you're out of luck.
It may be possible to find the end of the constructor code by tokenizing the bytecode and searching for RETURN INVALID
, then working back to find the runtime code offset, but I'm not sure if the compiler always transforms the constructor to have a single return, or not.
Environment information
What went wrong?
After resolving https://github.com/ApeWorX/ape-solidity/issues/153 with my local fix, I was still trying to do verification of our Coordinator contract (https://github.com/nucypher/nucypher-contracts/blob/main/contracts/contracts/coordination/Coordinator.sol) on polygon amoy (https://amoy.polygonscan.com/address/0x7d5f9a339e0b22f1e7d44f1b21e01f5c2207cdb3), after having already deployed it, and ran into issues determining the constructor arguments i.e. the contract was successfully deployed and separately, I'm not trying to verify it.
Code used from the ape console:
and got the following exception:
Looking at the runtime and deployment bytecode I can notice the following difference:
rutime_bytecode
vs
deployment_bytecode
where:
[some other code]
is just byte code at the beginning of thedeployment_bytecode
[common bytecode]
is the equivalent bytecode in both theruntime_bytecode
and thedeployment_bytecode
As you can see the entire
runtime_bytecode
is not contained within thedeployment_bytecode
but instead only a substring.I can see the constructor arguments at the end of the
deployment_code
, i.e.000000000000000000000000489287ed5bdf7a35fee411fbdcc47331093d0769
but it is not properly being extracted.Looking at the
extract_constructor_arguments
method, I can see that the error is raised because of the following:The reason for the difference between the bytecode is unclear to me. If I'm doing something wrong, let me know. If not, it makes me wonder whether the algorithm used is not covering all cases/solidity versions?
I tried researching what etherscan does when they provide constructor arguments during manual verification, but couldn't really find anything.
How can it be fixed?
This could filter down into the
SourceVerifier
object.That way, the caller can manually override the algorithm to determine constructor args. Similar to what etherscan allows for in case they got the constructor arguments incorrect.
I think this option is worthwhile irrespective of any alternative solutions you use.
This article claimed that you can do a reverse search for
0033
and then use the bytecode after that for the constructor args:So instead:
I did use this to work around my issue, and for this one contract. That being said, this seems extremely flimsy.
Something that could make it less flimsy is noted here, https://github.com/gnosis/verify-on-etherscan/blob/master/src/get_constructor_arguments.js#L14C1-L16C62 i.e.
So you can validate the length of the determined constructor arguments and ensure it is a multiple of 64. Kind of what they do here to verify constructor arguments - https://github.com/gnosis/verify-on-etherscan/blob/master/src/get_constructor_arguments.js#L17. If not a multiple of 64, then likely you need to reverse find the next instance of
0033
. Repeat until the corresponding arguments length is a multiple of 64.