Cloning a contract via abi, bytecode and contract factory? #2936
Replies: 2 comments
-
This technique will not work, in general. When you compile a contract in Solidity it produces myriad fields, the ones of interest for this discussion are The deployment bytecode includes all the code for the constructor including how to decode the constructor parameters, set up immutable sections of code to use as member fields, and possibly other low-level things. The result of the deployment bytecode is the runtime bytecode, with the contract state initialized correctly. But as such, the runtime bytecode (which is what You can look at the transaction that deployed the contract to see the data used to deploy it, which includes the deployment bytecode and parameters passed to the constructor, but this is also not a general solution, as deployment can depend on who or what deployed it, and also some opcodes have changed meaning over time, so a transaction used to deploy a contract before a given hardfork may no longer produce the same contract or initial state. You really need the use the source code to compile against solidity to be safe, and be aware of what deployment will do. Does that all make sense? The inner workings of contracts is definitely non-trivial. |
Beta Was this translation helpful? Give feedback.
-
Certainly it makes sense, its just a bit unfortunate in my use case. For my application, “clone-making” is part of the spec of the Dapp, and the other two ways I am aware of to make a true clone (not a proxy) are to use hardhat or similar to rebuild from source, link libraries etc, or to deploy a factory contract who’s only job is to make clones.
The factory contract is the relatively easy way, but if you have a 20Kb contract which costs $800 in gas to deploy, the factory contract, containing only a single “makeAnotherOne” function will another $850.00 to deploy the factory.
Having to load hardhat into a front end just to be able to call “getContractFactory(“Cloneable”, {libraries: {mylib: lib.address…}} seems like bad idea, and loading it in the cloud on GC Functions seems like a lot unnecessary and expensive overhead everytime it’s spun up. It all seems a bit unnecessary as somewhere or other the bytecode exists and it seems like you should be able to just copy it if you want a clone, but I guess that will have to wait for some future version. By the way, the JSON artificat produced by hardhat has a key called “deploymentByteCode”, but neither it, nor the “bytecode” key in the Json are deployable because it includes some kind of macro substitution thing in the EVM code indicated by a double underscore, so not actually directly useful either. I agree that this method of making clones requires care if you are not the author of the original, but that’s not the concern here.
Anyway thanks for answering this and all my other recent naive questions.
From: Richard Moore ***@***.***>
Reply-To: "ethers-io/ethers.js" ***@***.***>
Date: Wednesday, April 27, 2022 at 1:20 PM
To: "ethers-io/ethers.js" ***@***.***>
Cc: Josh Kramer ***@***.***>, Author ***@***.***>
Subject: Re: [ethers-io/ethers.js] Cloning a contract via abi, bytecode and contract factory? (Discussion #2936)
This technique will not work, in general.
When you compile a contract in Solidity it produces myriad fields, the ones of interest for this discussion are bytecode and runtimeBytecode. I really wish that bytecode was instead named deploymentBytecode, since that would resolve a lot of the confusion people (justifiably) have.
The deployment bytecode includes all the code for the constructor including how to decode the constructor parameters, set up immutable sections of code to use as member fields, and possibly other low-level things.
The result of the deployment bytecode is the runtime bytecode, with the contract state initialized correctly. But as such, the runtime bytecode (which is what provider.getCode returns) is insufficient to deploy another instance of the contract.
You can look at the transaction that deployed the contract to see the data used to deploy it, which includes the deployment bytecode and parameters passed to the constructor, but this is also not a general solution, as deployment can depend on who or what deployed it, and also some opcodes have changed meaning over time, so a transaction used to deploy a contract before a given hardfork may no longer produce the same contract or initial state.
You really need the use the source code to compile against solidity to be safe, and be aware of what deployment will do.
Does that all make sense? The inner workings of contracts is definitely non-trivial.
—
Reply to this email directly, view it on GitHub<#2936 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ACCIEBN5TVWHU4A76JGIEMTVHGOSLANCNFSM5UPU4SQQ>.
You are receiving this because you authored the thread.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I am trying to 'clone' a contract that is already deployed on the blockchain, by using its abi and bytecode, to create a duplicate contract at another address.
The mechanism I am attempting to use is to get the ABI from the JSON produced by hardhat compiler, and get the bytecode from the deployed contract using
ethers.provider.getCode([address of contract to be cloned])
and then creating a new factorylet factory = new ethers.ContractFactory(abi, bytecode, signer);?
. My question is, is this a valid approach in the first place?Can you use the bytecode fetched from a deployed contract inside a ContractFactory constructor? Otherwise, I can't figure out why this is failing, as I have confirmed the abi is properly fetched from the original json produced by hardhat, and that the constructor parameters are correct. (Same as when the original contract was deployed).
Here is the code I am using:
The script fails on call to
factory deploy
with the following error, although I have confirmed the constructor parameters are correct.It seems like the constructor is never run because a console.log at the start of the contract's constructor is not showing up in the Hardhat local node's console.
Beta Was this translation helpful? Give feedback.
All reactions