Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Override transaction options (from, gas, gasPrice) in create and upgrade proxy #85

Closed
spalladino opened this issue Jul 31, 2020 · 32 comments · Fixed by #852
Closed

Override transaction options (from, gas, gasPrice) in create and upgrade proxy #85

spalladino opened this issue Jul 31, 2020 · 32 comments · Fixed by #852

Comments

@spalladino
Copy link
Contributor

Add from, gas, and gasPrice as optional values to the options parameter of createProxy and upgradeProxy, so the user can change the defaults for a specific transaction. For example:

await upgradeProxy(existing.address, BoxV2, { deployer, from: '0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0', gasPrice: 10e9, gas: 1e6 });

(found in truffle plugin, unsure if applies to builder as well)

@frangio
Copy link
Contributor

frangio commented Aug 19, 2020

We potentially want these settings to be granular since each function can correspond to multiple transactions.

@pedrobranco
Copy link

We potentially want these settings to be granular since each function can correspond to multiple transactions.

@frangio Agree, but at least the from option would be great to support.

@frangio
Copy link
Contributor

frangio commented Dec 3, 2021

Note that the plugin will use the signer that comes attached to the ImplFactory in the Hardhat plugin, and I believe it also uses the same from default that was set for the contract class passed in the Truffle plugin.

This means that you can customize from by setting it in the contract abstraction you give the plugin (e.g. a MyContractV2 class).

@blabno
Copy link

blabno commented Dec 28, 2021

I had a nightmare deploying to mainnet using deployProxy. I was unable to set maxPriorityFeePerGas which made me wait 36 hours to get the implementation deployed. After that I resumed the process, got the Admin contract deployed quickly, but then got stuck on Proxy deployment for another 2 days.
Overriding maxPriorityFeePerGas and maxFeePerGas is a must.
Ideally we should be able to resume the process and bump the fees.

@ItsShadowl
Copy link

Its totally a bad idea to not allow configuring the max base fee when deploying....
Not sure if i've seen any workaround for now, is there any to achieve cheap deployment of many contracts?

@frangio
Copy link
Contributor

frangio commented Feb 2, 2022

Here is a possible workaround for ethers.js:

const FEE_DATA = {
    maxFeePerGas:         ethers.utils.parseUnits('100', 'gwei'),
    maxPriorityFeePerGas: ethers.utils.parseUnits('5',   'gwei'),
};

// Wrap the provider so we can override fee data.
const provider = new ethers.providers.FallbackProvider([ethers.provider], 1);
provider.getFeeData = async () => FEE_DATA;

// Create the signer for the mnemonic, connected to the provider with hardcoded fee data
const signer = ethers.Wallet.fromMnemonic(/* mnemonic */).connect(provider);

// Get the contract factory connected to signer so it uses hardcoded fee data
const MyContract = await ethers.getContractFactory('MyContract', signer);

// Should now use hardcoded fee data for deployments
await upgrades.deployProxy(MyContract);

@gitbaq
Copy link

gitbaq commented Feb 9, 2022

I'm trying the above @frangio still the same result. everything works fine on the mainnet (even without the workaround above), but the same configuration fails on testnet (harmony)

@frangio
Copy link
Contributor

frangio commented Feb 9, 2022

@gitbaq Please share more information about the error.

@ItsShadowl
Copy link

ItsShadowl commented Feb 14, 2022

When the gas price is set to >15 mins slow, it times out with : timed out waiting for transaction "txHash" error, any solution to that or should just revert to suggested ethers.js gas price?
Not sure if the transaction can continue without manual intervention

@ericglau
Copy link
Member

@noobshow Note that if it times out, you can just run the deployProxy function again and it will continue waiting for the transaction to be confirmed (you can also use the timeout and pollingInterval options to change how long it waits). Does that help, or are you more looking for a way to replace the transaction with a different gas price?

@ItsShadowl
Copy link

There are lots of deployments set up to go after each other.
I was hoping it was possible for the deployment of implementation and the proxy to happen without waiting for the other or maybe a replacement transaction with a higher gas fee, since the script I use updates according to some gas prices recommendations

@frangio
Copy link
Contributor

frangio commented Feb 17, 2022

the deployment of implementation and the proxy to happen without waiting for the other

We don't do this because if the implementation deployment fails, then the proxy deployment will fail as well and it will cost a lot of gas for no reason.

@sullof
Copy link

sullof commented Apr 10, 2022

@frangio
I am trying to deploy the contract at
https://github.com/superpowerlabs/synr-seed/blob/main/contracts/SeedFarm.sol
All tests pass and I can deploy it without issues on localhost. I can also deploy the other upgradeable contracts without issues on all chains. Still, I cannot deploy SeedFarm because hardhat returns a gas estimation issue.
The problem is that it seems that there is no way to set up a limit manually.
Any suggestion for a work-around? I have a deadline coming soon and if I do not find a solution, I have to rewrite it and use a different approach to upgradeability. Thanks!

@sullof
Copy link

sullof commented Apr 10, 2022

BTW, I didn't try on main net, yet. It fails on Ropsten, Mumbai and BSC Testnet.

@frangio
Copy link
Contributor

frangio commented Apr 11, 2022

There is a workaround above: #85 (comment)

@migbash
Copy link

migbash commented May 21, 2022

Still no solution ?

I am trying to simply do a npx hardhat test of my proxy - upgradable contract, but not working:

image

image

@SalvatoreCataniaVS
Copy link

Hello everyone, I am having problem with deployProxy function, the script worked as well for goerli and rinkeby (without using the workaround above) but on mumbai I am not able to deploy the contract.

These are the library used:

"@nomiclabs/hardhat-ethers": "^2.0.6"
 "@openzeppelin/hardhat-upgrades": "^1.18.1"

This is the script:

const FEE_DATA = {
   maxFeePerGas:         ethers.utils.parseUnits('100', 'gwei'),
   maxPriorityFeePerGas: ethers.utils.parseUnits('5',   'gwei'),
 };

 // Wrap the provider so we can override fee data.
 const provider = new ethers.providers.FallbackProvider([ethers.provider], 1);
 provider.getFeeData = async () => FEE_DATA;

 // Create the signer for the mnemonic, connected to the provider with hardcoded fee data
 const signer = new ethers.Wallet(config.privateKey).connect(provider)
 // const [signer] = await ethers.getSigners();

 console.log("Deploying contracts with the account:", signer.address);

 console.log("#################################")
 console.log("STARTING DEPLOY ACCESS TOKEN CONTRACTS")
 const AccessTokenManager = await ethers.getContractFactory("AccessTokenManager", signer)
 const accessTokenManager = await upgrades.deployProxy(AccessTokenManager,{ initializer: 'initialize', kind: 'uups'})

Can someone please tell me was is wrong here?

Thanks in advance.

@frangio
Copy link
Contributor

frangio commented Jun 15, 2022

@SalvatoreCataniaVS Please post this question in the OpenZeppelin Forum and include the error message you are seeing.

@sebastiantf
Copy link

Is from supported yet for deployProxy() in hardhat-upgrades?

@albatros-github
Copy link

Here is a possible workaround for ethers.js:

const FEE_DATA = {
    maxFeePerGas:         ethers.utils.parseUnits('100', 'gwei'),
    maxPriorityFeePerGas: ethers.utils.parseUnits('5',   'gwei'),
};

// Wrap the provider so we can override fee data.
const provider = new ethers.providers.FallbackProvider([ethers.provider], 1);
provider.getFeeData = async () => FEE_DATA;

// Create the signer for the mnemonic, connected to the provider with hardcoded fee data
const signer = ethers.Wallet.fromMnemonic(/* mnemonic */).connect(provider);

// Get the contract factory connected to signer so it uses hardcoded fee data
const MyContract = await ethers.getContractFactory('MyContract', signer);

// Should now use hardcoded fee data for deployments
await upgrades.deployProxy(MyContract);

Maybe extending the Hardhat HRE following this example of the docs with the modifications indicated by @frangio :

  • In hardhat.config.js:

extendEnvironment((hre) => {
const Web3 = require("web3");
hre.Web3 = Web3;

// hre.network.provider is an EIP1193-compatible provider.
hre.web3 = new Web3(hre.network.provider);
});

@qruz-hq
Copy link

qruz-hq commented Jan 22, 2023

This is still an issue, no way to properly override gas values.

@stevenkeith85
Copy link

The workaround doesn't appear to work if you use call with upgradeProxy .

Any suggestions, or should I just do two transactions?

Thanks

@ericglau
Copy link
Member

@stevenkeith85 upgradeProxy uses the same signer as the contract factory that is passed in, and the call option is included in the same transaction so the workaround should work.

I was able to get the following example working (using a private key in this example instead of mnemonic):

const FEE_DATA = {
  maxFeePerGas:         ethers.utils.parseUnits('100', 'gwei'),
  maxPriorityFeePerGas: ethers.utils.parseUnits('5',   'gwei'),
};

// Wrap the provider so we can override fee data.
const provider = new ethers.providers.FallbackProvider([ethers.provider], 1);
provider.getFeeData = async () => FEE_DATA;

// Create the signer for the private key, connected to the provider with hardcoded fee data
const signer = (new ethers.Wallet('<MY PRIVATE KEY>')).connect(provider);

const MyContractV2Factory = await hre.ethers.getContractFactory("MyContractV2", signer);
await upgrades.upgradeProxy(proxyAddress, MyContractV2Factory, { call: {fn: 'myFunction'} } );

@stevenkeith85
Copy link

stevenkeith85 commented Jan 26, 2023

@stevenkeith85 upgradeProxy uses the same signer as the contract factory that is passed in, and the call option is included in the same transaction so the workaround should work.

I was able to get the following example working (using a private key in this example instead of mnemonic):

const FEE_DATA = {
  maxFeePerGas:         ethers.utils.parseUnits('100', 'gwei'),
  maxPriorityFeePerGas: ethers.utils.parseUnits('5',   'gwei'),
};

// Wrap the provider so we can override fee data.
const provider = new ethers.providers.FallbackProvider([ethers.provider], 1);
provider.getFeeData = async () => FEE_DATA;

// Create the signer for the private key, connected to the provider with hardcoded fee data
const signer = (new ethers.Wallet('<MY PRIVATE KEY>')).connect(provider);

const MyContractV2Factory = await hre.ethers.getContractFactory("MyContractV2", signer);
await upgrades.upgradeProxy(proxyAddress, MyContractV2Factory, { call: {fn: 'myFunction'} } );

Thanks for helping out!

I've got exactly the same code as you now, (except for the contract that I'm updating) and I'm still getting the same behaviour - UNPREDICTABLE_GAS_LIMIT if I have a call fn.

Removing the call from upgradeProxy makes it look like its happy, but I suspect it isn't as trying to call a new method (added in V2) doesn't work.

I'm wondering if the contract size matters at all? I tried allowUnlimitedContractSize: true, in the config under hardhat but it made no difference.

What's very strange is that the unit tests work. They deploy a proxy and then upgrade it to V2 so that I can run the new initializer function

function initializeV2() public reinitializer(2) {
//...
}

which just updates the value of a new state variable in the V2 updates.

What's also strange is that I've had the upgradeProxy working on the local hardhat network before, when the contract was much simpler.

EDIT: If I remove the reinitializer from the contract and then try to upgrade it sort of works. I'm still getting UNPREDICTABLE_GAS_LIMIT, but at least that seems to be related to a revert. (caller is not the owner) (I just tried calling a setter to see if the upgrade worked and stumbled on the owner issue)

Now to figure out why I'm not the owner 😢

@ericglau
Copy link
Member

ericglau commented Jan 26, 2023

@stevenkeith85 To avoid UNPREDICTABLE_GAS_LIMIT, can you try setting your own estimate for the gas limit? e.g.

signer.estimateGas = async(transaction) => {
  return 200000;
}

@stevenkeith85
Copy link

stevenkeith85 commented Jan 26, 2023

@stevenkeith85 To avoid UNPREDICTABLE_GAS_LIMIT, can you try setting your own estimate for the gas limit? e.g.

signer.estimateGas = async(transaction) => {
  return 200000;
}

I just stumbled onto the issue.

Seems I forgot to call one of the _XXXinit(); functions in initializeV2 when I subclassed a new upgradeable contract.

Pity the tests didn't complain about that, but at least I'm further along.

No idea what the ownership weirdness is all about now, but I guess that's another issue.

TLDR; If you get UNPREDICTABLE_GAS_LIMIT when you use call to an initializer, make sure you remember to call the requiredXXX_init function(s).

@0xmichalis
Copy link
Contributor

0xmichalis commented Feb 15, 2023

@frangio @ericglau just checking in here before getting too deep into the rabbithole. Is the FallbackProvider workaround to provide our own gas params also working with prepareUpgrade? I see both functions are using the same underlying helper (deployProxyImpl) so I guess it's meant to work for both.

EDIT

In Polygon given the code above I am getting an estimateGas issue and need to override the original provider's estimateGas in order to work around this issue:

cannot estimate gas; transaction may fail or may require manual gas limit
const provider = new ethers.providers.FallbackProvider([ethers.provider], 1);
provider.getFeeData = async () => FEE_DATA;
provider.estimateGas = async() => BigNumber.from('<GAS_LIMIT>');

@ericglau
Copy link
Member

Is the FallbackProvider workaround to provide our own gas params also working with prepareUpgrade? I see both functions are using the same underlying helper (deployProxyImpl) so I guess it's meant to work for both.

@0xmichalis Yes, it would be the same for prepareUpgrade.

@tetris-dev-web
Copy link

tetris-dev-web commented Feb 17, 2023

@frangio @ericglau

Here is a possible workaround for ethers.js:

const FEE_DATA = {
    maxFeePerGas:         ethers.utils.parseUnits('100', 'gwei'),
    maxPriorityFeePerGas: ethers.utils.parseUnits('5',   'gwei'),
};

// Wrap the provider so we can override fee data.
const provider = new ethers.providers.FallbackProvider([ethers.provider], 1);
provider.getFeeData = async () => FEE_DATA;

// Create the signer for the mnemonic, connected to the provider with hardcoded fee data
const signer = ethers.Wallet.fromMnemonic(/* mnemonic */).connect(provider);

// Get the contract factory connected to signer so it uses hardcoded fee data
const MyContract = await ethers.getContractFactory('MyContract', signer);

// Should now use hardcoded fee data for deployments
await upgrades.deployProxy(MyContract);

This solution doesn't work to me. deployProxy or UpgradeProxy shows timeout error still
This is my codebase. Anybody help ?

```
const FEE_DATA = {
  maxFeePerGas: ethers.utils.parseUnits("600", "gwei"),
  maxPriorityFeePerGas: ethers.utils.parseUnits("500", "gwei"),
};

// Wrap the provider so we can override fee data.
const provider = new ethers.providers.FallbackProvider(
  [ethers.provider],
  1
);
provider.getFeeData = async () => FEE_DATA;

// Create the signer for the private key, connected to the provider with hardcoded fee data
const signer = new ethers.Wallet(process.env.PRIVATE_KEY!).connect(
  provider
);

const ContractNew = await hre.ethers.getContractFactory(
  "upgradeContractNew",
  signer
);
const contract = await upgrades.upgradeProxy(proxyAddress, ContractNew, {
  timeout: 0,
});
await contract.deployed();

@nvdtf
Copy link

nvdtf commented Mar 1, 2023

Reading this block:

// Get the contract factory connected to signer so it uses hardcoded fee data
const MyContract = await ethers.getContractFactory('MyContract', signer);

// Should now use hardcoded fee data for deployments
await upgrades.deployProxy(MyContract);

For some reason this worked for me instead of above:

// Get the contract factory
let MyContract = await ethers.getContractFactory('MyContract');

// Connect to signer
MyContract = await MyContract.connect(signer);

// Should now use hardcoded fee data for deployments
await upgrades.deployProxy(MyContract);

I was trying to deploy with GCP KMS key as signer (https://www.npmjs.com/package/ethers-gcp-kms-signer)

@pagameba
Copy link

Has there been any movement on this issue? It is really awkward for me to deploy to the production polygon chain. I've forked the upgrades repo and hacked gas into a couple of places just to be able to deploy and upgrade, but there really needs to be first class support for this in the library - it is essentially unusable for production polygon deploys at the moment.

@ericglau
Copy link
Member

ericglau commented Aug 3, 2023

This is available in the latest releases of the Hardhat and Truffle Upgrades plugins by using the txOverrides option, where you can provide an ether.js Overrides or Truffle options object, respectively, containing the transaction parameters to override.

See documentation for the txOverrides option in the Hardhat and Truffle Upgrades API reference.

For example, to set maxFeePerGas to 10 gwei:

await upgrades.deployProxy(Greeter, ['Hello'], {
    txOverrides: { maxFeePerGas: 10e9 },
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.