Error: gas required exceeds allowance (8000000) or always failing transaction

I am trying to invoke a function using oz send-tx but it fails with Error: gas required exceeds allowance (8000000) or always failing transaction

:computer: Environment

I am using OZ v2.6

:memo:Details

:1234: Code to reproduce

Here is my contract code. It compiles and deploys without any issue. Please deploy to Ropsten testnet to reproduce

pragma solidity ^0.5.0;
import "@ensdomains/ens/contracts/ENS.sol";
import "@ensdomains/ethregistrar/contracts/ETHRegistrarController.sol";

contract ReverseResolver {
  function setName(bytes32 node, string memory name) public;
}

contract NameStack {
  bool private initialized;
  ENS ens;
  ETHRegistrarController controller;
  ReverseResolver reverseResolver;
  
  function initialize(address ensAddress, address controllerAddress, address reverseResolverAddress) public {
    require(!initialized);
    initialized = true;
    ens = ENS(ensAddress);
    controller = ETHRegistrarController(controllerAddress);
    reverseResolver = ReverseResolver(reverseResolverAddress);
  }

  function registerWithConfig(string memory name, address acc, uint256 duration, bytes32 salt, address publicResolver) public payable {
    controller.registerWithConfig.value(msg.value)(name, acc, duration, salt, publicResolver, acc);
  }

  function register(string memory name, address acc, uint256 duration, bytes32 salt) public payable {
    controller.register.value(msg.value)(name, acc, duration, salt);
  }

  function makeCommitmentWithConfig(string memory name, bytes32 salt, address publicResolver, address owner) view public returns(bytes32) {
    return controller.makeCommitmentWithConfig(name, owner, salt, publicResolver, owner);
  }

  function makeCommitment(string memory name, bytes32 salt, address owner) view public returns(bytes32) {
    return controller.makeCommitment(name, owner, salt);
  }

  function commit(bytes32 commitment) public {
    return controller.commit(commitment);
  }

  function() payable external { }

}

Then, call send-tx (details below):

$ oz send-tx --network ropsten --value 20000000000000000
? Pick an instance NameStack at 0x584C72faED8C7730170BF9761195BF08a2a0080A
? Select which function registerWithConfig(name: string, acc: address, duration: uint256, salt: bytes32, publicResolver: address)
? name (string): phantom
? acc (address): 0x98d79D728b0f5eDd1F0e68010e54Eaa78A011E76
? duration (uint256): 31556952
? salt (bytes32): 0x592d9b9f53c241b8ce6aa52c8a8f57f09c0ef4dd2fa6ce214f93c687b1fdda19
? publicResolver (address): 0x12299799a50340FB860D276805E78550cBaD3De3

You should see an error. The exact same code with same inputs works in a truffle project, so I know the issue is not in the code. How do I even debug this error? Thanks!

1 Like

Hi @mmurthy,

Welcome to the community :wave:, thanks for joining the forum.

What values do you use on Ropsten for initialize(address ensAddress, address controllerAddress, address reverseResolverAddress)?

Thanks for looking into this. You can use these respectively @abcoathup 0x112234455c3a32fd11230c42e7bccd4a84e02010’, ‘0x12a0083531C904fe4ac490DF231c2e4e4403dB60’, '0x67d5418a000534a8f1f5ff4229cc2f439e63bbe2

Hey @mmurthy. What is your gasLimit for Ropsten? I am pretty sure Ropsten has gas block limit smaller than 8kk. That might be an issue.

1 Like

I hadn’t set a limit, not sure what it was defaulting to. I just set it 4.7 million and now the transaction is submitted but fails with out of gas error. That exact transaction with truffle project consumes lot less gas, you can see here: https://ropsten.etherscan.io/tx/0xeba9c8e98e0af0e6f4f1eac6c3a15980fad67c173cce3d9058acb3eaed4197ba. So, I don’t know why it is throwing out of gas exception. Thoughts @ylv-io?

Here is something interesting. I tried to execute the transaction and it failed. Here is that transaction

https://ropsten.etherscan.io/tx/0x9a8839d8fbc19b2878f838b6f6d9350b8d71c194e5d649325c01c0e3bc059e58

Then, I tried in truffle console and it worked, here is that transaction:

https://ropsten.etherscan.io/tx/0xf711a365c5a0b1c5337c2455def75a0e88b2a8cb16af16af644394994d99e869

You see the input data, it is exactly the same. Same contract code has been deployed to both. Why would OZ code fail?

1 Like

Hi @mmurthy,

I deployed the contract above using Truffle console to Ropsten and then called initialize and then had the transaction revert when calling registerWithConfig

truffle(ropsten)> await ns.registerWithConfig('phantom', '0x98d79D728b0f5eDd1F0e68010e54Eaa78A011E76', 31556952, '0x592d9b9f53c241b8ce6aa52c8a8f57f09c0ef4dd2fa6ce214f93c687b1fdda19', '0x12299799a50340FB860D276805E78550cBaD3De3', {value: 200000000000000000})

https://ropsten.etherscan.io/tx/0x7f1f6f2015be05a1dda672ce76549fbb67210d58fb197e322ee23a8ceeae250c

I didn’t spot an obvious issue unfortunately.

@abcoathup, the reason it reverted is because that name has already been registered. Atleast the transaction reverted with truffle (that is the right behavior), try the same with OZ and you will get out of gas exception and not revert.

1 Like

Hi @mmurthy,

If I send a transaction via OpenZeppelin CLI it fails with error: gas required exceeds allowance (8000000) or always failing transaction

$ oz send-tx --network ropsten --value 200000000000000000
? Pick an instance NameStack at 0x7A7d28F380f02A75B71c283b6B6ba0933f29Ad34
? Select which function registerWithConfig(name: string, acc: address, duration: uint256, salt: bytes32, publicResolver:
 address)
? name (string): phantom
? acc (address): 0x98d79D728b0f5eDd1F0e68010e54Eaa78A011E76
? duration (uint256): 31556952
? salt (bytes32): 0x592d9b9f53c241b8ce6aa52c8a8f57f09c0ef4dd2fa6ce214f93c687b1fdda19
? publicResolver (address): 0x12299799a50340FB860D276805E78550cBaD3De3
✖ Calling: 'registerWithConfig' with:
- name (string): "phantom"
- acc (address): "0x98d79D728b0f5eDd1F0e68010e54Eaa78A011E76"
- duration (uint256): "31556952"
- salt (bytes32): "0x592d9b9f53c241b8ce6aa52c8a8f57f09c0ef4dd2fa6ce214f93c687b1fdda19"
- publicResolver (address): "0x12299799a50340FB860D276805E78550cBaD3De3"
Error while trying to send transaction to 0x7A7d28F380f02A75B71c283b6B6ba0933f29Ad34. Error: Error: gas required exceeds allowance (8000000) or always failing transaction

If I send a transaction via Truffle console to the same upgradeable contract the transaction fails with a revert.

Error: Transaction: 0x25f9a3dc221a1215ae642280f8e3a8b89df23ecd7a0fa253344142ffde8a48e0 exited with an error (status 0).

What parameters can I use to make a successful call?

Hi @mmurthy,

I tried deploying the non-upgradeable contract in Truffle, and then interacting using the Truffle console (first calling initialize) but the transaction reverts.

Am I missing any steps?

ns = await NameStack.deployed()
ns.address
'0x2546288Bd928dEb2Ed2d7F1Feaed79Ca2c62969f'
await ns.initialize('0x112234455c3a32fd11230c42e7bccd4a84e02010', '0x12a0083531C904fe4ac490DF231c2e4e4403dB60', '0x67d5418a000534a8f1f5ff4229cc2f439e63bbe2')
await ns.makeCommitmentWithConfig('abcoathup3', '0x592d9b9f53c241b8ce6aa52c8a8f57f09c0ef4dd2fa6ce214f93c687b1fdda19', '0x12299799a50340FB860D276805E78550cBaD3De3', '0x537f62D5f099EDd9F0FE78501D8C9D096082B573')
'0xc6b8645b5189162088c8ec80da2b17f1a1c4dd92c6355e3c1384bbe7954620ab'

Wait a minute

await ns.registerWithConfig('abcoathup3', '0x98d79D728b0f5eDd1F0e68010e54Eaa78A011E76', 31556952, '0x592d9b9f53c241b8ce6aa52c8a8f57f09c0ef4dd2fa6ce214f93c687b1fdda19', '0x12299799a50340FB860D276805E78550cBaD3De3', {value: 200000000000000000})

Reverts
https://ropsten.etherscan.io/tx/0x62c4ae6608edb1ad63697743e39192190d056835200d4ba235de5ab62c310433

After you call makeCommitmentWithConfig, the hash you get, you have to use that to call commit() function. Then wait a minute and then registerWithConfig. Hope that is clear.

1 Like

Hi @mmurthy,

I can reproduce the issue (thanks for your help). Where calling registerWithConfig fails for an upgradeable contract but succeeds with a non-upgradeable contract.

Reverts (out of gas) when calling registerWithConfig on upgradeable contract
https://ropsten.etherscan.io/tx/0xc948431fd11132654f8ca4dbbcec788735374b0dd32db838e210d8fec77a5d40

Success when calling registerWithConfig on non-upgradeable contract (from truffle console)
https://ropsten.etherscan.io/tx/0xacfb688db6fbf7e15236ba75b5776a55f2cffc8c54cb31552102d392b6e68a09

Non-upgradeable contract

Contract deployed using truffle migrate --network ropsten
Interaction using truffle console --network ropsten

ns = await NameStack.deployed()
ns.address
'0x2546288Bd928dEb2Ed2d7F1Feaed79Ca2c62969f'
await ns.initialize('0x112234455c3a32fd11230c42e7bccd4a84e02010', '0x12a0083531C904fe4ac490DF231c2e4e4403dB60', '0x67d5418a000534a8f1f5ff4229cc2f439e63bbe2')

Use unique name (and account address) and get hash with makeCommitmentWithConfig

await ns.makeCommitmentWithConfig('abcoathup5', '0x592d9b9f53c241b8ce6aa52c8a8f57f09c0ef4dd2fa6ce214f93c687b1fdda19', '0x12299799a50340FB860D276805E78550cBaD3De3', '0x77737a65C296012C67F8c7f656d1Df81827c9541')
'0xa49a54d3aee955ffa58c8f08490f1d3b7b2a51007b081442e02d00a8562b649a'

Commit hash with commit

await ns.commit('0xa49a54d3aee955ffa58c8f08490f1d3b7b2a51007b081442e02d00a8562b649a')

Wait a minute

Register with registerWithConfig

await ns.registerWithConfig('abcoathup5', '0x77737a65C296012C67F8c7f656d1Df81827c9541', 31556952, '0x592d9b9f53c241b8ce6aa52c8a8f57f09c0ef4dd2fa6ce214f93c687b1fdda19', '0x12299799a50340FB860D276805E78550cBaD3De3', {value: 200000000000000000})

Upgradeable contract

Contract deployed using oz create
Interaction using truffle console --network ropsten

ns = await NameStack.at('0x7f3fCc75464642A889B2eD529Fb18A6b5b1f4Ace')
await ns.makeCommitmentWithConfig('abcoathup7', '0x592d9b9f53c241b8ce6aa52c8a8f57f09c0ef4dd2fa6ce214f93c687b1fdda19', '0x12299799a50340FB860D276805E78550cBaD3De3', '0x77737a65C296012C67F8c7f656d1Df81827c9541')
'0xfe47a9e05d8dd209e39133422df210ce52d66db4cafdf8706aa51e15ec965e8c'
await ns.commit('0xfe47a9e05d8dd209e39133422df210ce52d66db4cafdf8706aa51e15ec965e8c')
await ns.registerWithConfig('abcoathup7', '0x77737a65C296012C67F8c7f656d1Df81827c9541', 31556952, '0x592d9b9f53c241b8ce6aa52c8a8f57f09c0ef4dd2fa6ce214f93c687b1fdda19', '0x12299799a50340FB860D276805E78550cBaD3De3', {value: 200000000000000000})

Reverts (out of gas) when calling registerWithConfig on upgradeable contract
https://ropsten.etherscan.io/tx/0xc948431fd11132654f8ca4dbbcec788735374b0dd32db838e210d8fec77a5d40

Success when calling registerWithConfig on non-upgradeable contract (from truffle console)
https://ropsten.etherscan.io/tx/0xacfb688db6fbf7e15236ba75b5776a55f2cffc8c54cb31552102d392b6e68a09

Hey @mmurthy! I think the problem may be related to the opcode repricing from the Istanbul hard fork. As @nventuro explained in this post, the repricing affects all OpenZeppelin upgradeable contracts who are to receive a transfer from another contract.

In this case, going through the transaction that @abcoathup set up (thanks Andy for the help in reproducing the issue!), it seems the very last internal transaction is an ETH transfer with 2300 gas. This succeeds when the destination contract is a regular one, but fails when it’s upgradeable.

I’ve opened an issue on ENS so they stop using Solidity’s transfer as it has been advised, but I’m not sure how easily they can push that fix, since the ENS contracts are not upgradeable.

In the meantime, you should be able to work around this problem by setting up your contract as non-upgradeable in the oz CLI, by setting the --minimal flag when running oz create. Let me know if this works! And apologies for the hassle, but the repricing from the hard fork is breaking applications in ways we could not anticipate.

1 Like

Actually @mmurthy, you may have another option around this. The ETHRegistrarController contract only calls transfer if you send more ETH than the actual cost (see here). This means that if you adjust the payment to exactly match the cost, the transfer would never be executed, and the transaction should work.

Could you try changing your registerWithConfig method to something like this, so you send exactly the registration cost? (I’m coding directly on the forum, so you may need to adjust it a bit, but I hope the idea is clear)

  function registerWithConfig(string memory name, address acc, uint256 duration, bytes32 salt, address publicResolver) public payable {
    uint256 cost = controller.rentPrice(name, duration); // gets the cost of the registration
    controller.registerWithConfig.value(cost)(name, acc, duration, salt, publicResolver, acc);
  }

Let me know if this works!

1 Like

Thanks @abcoathup and @spalladino for helping me with this. I like the option you suggest @spalladino, let me try that.

Just curious, if I use --minimal flag to make my contract non-upgradeable, what is the benefit of using OZ SDK at all instead of directly using truffle?

1 Like

Using --minimal uses a minimal proxy under the hood. This is useful if you plan on deploying multiple instances of the same contract, as it makes each deployment after the first one super cheap, though I don’t know if it’s your use case. Still, you may want to manage this specific contract as non-upgradeable, while keeping the rest of the contracts in your project upgradeable.

Also, and besides deployment itself, the OpenZeppelin CLI has a few handy commands for interacting with your contracts from the terminal (send-tx, call, transfer, etc) which AFAIK are not present in truffle. Compilation times are also faster.

2 Likes

Woot! I changed the code to send the exact amount and it now works! Thanks @spalladino and @abcoathup for all your help.

1 Like