question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Factory contract unable to call deployed contract with --fork flag

See original GitHub issue

This discussion on the OpenZeppelin forum contains a full description of the issue and an example that can be reproduced. Below I’ve included the core parts from that discussion.

The factory contract below should deploy a new Forwarder instance then call its initialize() function. The call to this function should emit the Initialized event and set version to 1.

This fails when testing against a forked version of the mainnnet, but succeeds otherwise.

The error messages when testing against a forked version of the mainnet are below. From the stack trace shown, generated by testing against ganache-cli -d -f https://mainnet.infura.io/v3/$INFURA_ID, you can see from the “after each” section that the cause is a fork failure.

However, in my original project—before creating a trimmed down version to help diagnose this bug—this “after each” error did not show up in the stack trace, and I have not figured out why.

Any ideas on the cause of this issue and how to fix it are greatly appreciated! Until it’s resolved I don’t really have a way to run some tests, since the full version of the initialize() function calls some functions on mainnet contracts. (There’s always the option deploying and setting up local instances of all the dependent contracts, but I’m hoping to avoid that).

Thanks!

Stack Trace

1) Contract: ForwarderFactory
       creates proxy:

      AssertionError: expected '0' to equal '1'
      + expected - actual

      -0
      +1
      
      at Context.it (test/forwarderFactory.test.js:30:55)
      at process._tickCallback (internal/process/next_tick.js:68:7)

  2) Contract: ForwarderFactory
       "after each" hook: after test for "creates proxy":
     Error: Returned error: Returned error: invalid argument 0: empty hex string
      at Object.ErrorResponse (node_modules/truffle/build/webpack:/node_modules/web3-core-helpers/src/errors.js:29:1)
      at /Users/mds/Documents/Documents-MBP/floatify/ganache-fork-failure/node_modules/truffle/build/webpack:/node_modules/web3-core-requestmanager/src/index.js:140:1
      at /Users/mds/Documents/Documents-MBP/floatify/ganache-fork-failure/node_modules/truffle/build/webpack:/packages/provider/wrapper.js:112:1
      at XMLHttpRequest.request.onreadystatechange (node_modules/truffle/build/webpack:/node_modules/web3-providers-http/src/index.js:96:1)
      at XMLHttpRequestEventTarget.dispatchEvent (node_modules/truffle/build/webpack:/node_modules/xhr2-cookies/dist/xml-http-request-event-target.js:34:1)
      at XMLHttpRequest._setReadyState (node_modules/truffle/build/webpack:/node_modules/xhr2-cookies/dist/xml-http-request.js:208:1)
      at XMLHttpRequest._onHttpResponseEnd (node_modules/truffle/build/webpack:/node_modules/xhr2-cookies/dist/xml-http-request.js:318:1)
      at IncomingMessage.<anonymous> (node_modules/truffle/build/webpack:/node_modules/xhr2-cookies/dist/xml-http-request.js:289:47)
      at endReadableNT (_stream_readable.js:1129:12)
      at process._tickCallback (internal/process/next_tick.js:63:19)

And here are the relevant files:

FowarderFactory.sol

pragma solidity ^0.5.0;

// Proxy factory contains the deployMinimal() function used below
// https://github.com/OpenZeppelin/openzeppelin-sdk/blob/v2.6.0/packages/lib/contracts/upgradeability/ProxyFactory.sol#L18
import "@openzeppelin/upgrades/contracts/upgradeability/ProxyFactory.sol";

import "./Forwarder.sol";

contract ForwarderFactory is ProxyFactory {

  address[] public forwarders;
  address[] public users;
  mapping (address => address) public getForwarder; // maps user => forwarder

  event ForwarderCreated(address indexed _address);

  function createForwarder(address _target, address _user) external {

    address _admin = msg.sender;
    bytes memory _payload = abi.encodeWithSignature("initialize(address,address)", _user, _admin);

    // Deploy proxy
    address _forwarder = deployMinimal(_target, _payload);
    emit ForwarderCreated(_forwarder);

    // Update state
    forwarders.push(_forwarder);
    users.push(_user);
    getForwarder[_user] = _forwarder;
  }
}

Forwarder.sol

pragma solidity ^0.5.0;

import "@openzeppelin/contracts-ethereum-package/contracts/ownership/Ownable.sol";
import "@openzeppelin/upgrades/contracts/Initializable.sol";

contract Forwarder is Initializable, Ownable {

  address public admin;
  uint256 public version;

  event Initialized(address indexed thisAddress);

  function initialize(address _recipient, address _admin) public initializer {
    emit Initialized(address(this));
    Ownable.initialize(_recipient);
    admin = _admin;
    version = 1;
  }
}

forwarderFactory.test.js

const {
  BN, // Big Number support
  constants, // Common constants, like the zero address and largest integers
  expectEvent, // Assertions for emitted events
  expectRevert, // Assertions for transactions that should fail
} = require('@openzeppelin/test-helpers');

const { expect } = require('chai');

const Forwarder = artifacts.require('Forwarder');
const ForwarderFactory = artifacts.require('ForwarderFactory');

contract('ForwarderFactory', ([admin, user]) => {
  it('creates proxy', async () => {
    const factory = await ForwarderFactory.new();
    const logic = await Forwarder.new();

    await factory.createForwarder(logic.address, user);

    const forwarderAddress = await factory.forwarders(0);
    const forwarder = await Forwarder.at(forwarderAddress);
    expect(await forwarder.version()).to.be.bignumber.equal('1');
  });
});

Your Environment

  • Version used:
  • Environment name and version (e.g. PHP 5.4 on nginx 1.9.1):
  • Server type and version:
  • Operating System and version:
  • Link to your project:

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:4
  • Comments:26 (14 by maintainers)

github_iconTop GitHub Comments

3reactions
AcelisWeavencommented, Feb 27, 2020

@mds1 Sorry for the double post, just wanted to let you know that I successfully emulated the same feature. The process is not as simple as ganache-cli sadly, but it allows contracts to be tested on mainnet, and they can even be debugged on Remix.

  1. Setup a geth full node
  2. Optional, but recommended: Copy the datadir to another place. I’ll refer to the new directory as <new-data-dir> below.
  3. Recompile geth to have no difficulty to mine blocks. -> https://hackernoon.com/how-to-reduce-block-difficulty-in-ethereum-private-testnet-2ad505609e82
  4. Run your modified geth. Here’s my command:
my-geth --rpc --rpcapi=eth,web3,net,personal,debug --rpccorsdomain "*" --datadir <new-data-dir> --maxpeers 0 --nat none --nodiscover --v5disc=false --port 0 --allow-insecure-unlock --unlock <your-node-address> --mine --miner.threads=1 --networkid=2020

Since the miner is running, you’ll have more more that enough ETH for your tests.

Everything seems to work fine! Sadly, you’ll miss out on truffle features, but it’s a temporary solution.

Edit

I may have stumbled upon something strange. I tried to use truffle on my forked network but had issues with lost blocks after some time. So I decided to give ganache-cli another try on both mainnet and ‘forked-mainnet’.

mainnet - Command used for launching geth - without --datadir option :

geth.exe --rpc --rpcport=8547 --rpcapi=eth,web3,net,personal,debug --rpccorsdomain "*" --ws --wsorigins "*" --maxpeers 0 --nat none --nodiscover --v5disc=false --port 0 --networkid=2020

Result with ganache-cli: VM Exception while processing transaction: revert

‘forked-mainnet’ - Command used for launching geth - with --datadir option :

geth.exe --rpc --rpcport=8547 --rpcapi=eth,web3,net,personal,debug --rpccorsdomain "*" --ws --wsorigins "*" --datadir <new-data-dir> --maxpeers 0 --nat none --nodiscover --v5disc=false --port 0 --networkid=2020

Result with ganache-cli: Everything works like a charm! And I don’t know why.

The main difference between the forked network and mainnet is that the difficulty is at 1 and more blocks have been mined.

@nicholasjpaterno Maybe this could give you a clue?

1reaction
mds1commented, Oct 4, 2020

Also, do you know why bancorConverter.convert2 reverts (since you say it’s a valid revert)? This may help me debug

Unfortunately I don’t. I did some digging and can’t remember what the bug was here, but it seems I resolved this demo by just switching to an ETH-token conversion instead of a token-token conversion. So perhaps the bug was related to ERC20 approvals, but I’m not certain of that.

However, I can confirm that upgrading truffle to ^5.1.47 resolves the issue!

Read more comments on GitHub >

github_iconTop Results From Across the Web

SushiSwap Fork reverting at createPair()
I've deployed the contract to both ropsten and mainnetusing this flag (note: this is default on mainnet). Share. Share a link to this...
Read more >
How to create and deploy a smart contract with Hardhat
1. Ethereum development environments like Truffle and Hardhat make it easier to work with smart contract... 2. Hardhat is a development environment that...
Read more >
Remix Documentation
Remix IDE is used for the entire journey of smart contract development by users at every knowledge level. It requires.
Read more >
Hello World Smart Contract
HelloWorld here is a factory for instances of our hello world contract. ... for our contract address we should be able to see...
Read more >
Command line options
--stacktrace : Allows for mixed Javascript-and-Solidity stacktraces when a Truffle Contract transaction or deployment reverts. Does not apply to calls or ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found