Factory contract unable to call deployed contract with --fork flag
See original GitHub issueThis 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:
- Created 4 years ago
- Reactions:4
- Comments:26 (14 by maintainers)
Top GitHub Comments
@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.geth
full node<new-data-dir>
below.geth
to have no difficulty to mine blocks. -> https://hackernoon.com/how-to-reduce-block-difficulty-in-ethereum-private-testnet-2ad505609e82geth
. Here’s my command: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 giveganache-cli
another try on both mainnet and ‘forked-mainnet’.mainnet - Command used for launching
geth
- without --datadir option :Result with
ganache-cli
:VM Exception while processing transaction: revert
‘forked-mainnet’ - Command used for launching
geth
- with --datadir option :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?
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!