Error while deploying ERC1820Registry without truffle

Hello !
I was trying to deploy ERC1820Registry, first i did:

const { singletons } = require('openzeppelin-test-helpers');

and then i did :

    await singletons.ERC1820Registry(_address);
    let Token = await deploy('Token',{ from: _address, args: ["simpletoken", "ST", arr]});

Here i am not using truffle , the function “deploy” is a function that compiles the smart contract with solc then deploys it on ganache …
I tried deploying other smart contracts using that function and it works so far.
My problem is when it hits the line await singletons.ERC1820Registry i get this error :

I guess if im using my own deploy function , then i can’t use singletons ? maybe i should deploy the contract erc1820 on my own ?

Thank you !

2 Likes

Hi @Sarah,

OpenZeppelin Test Helpers 0.5 supports plain Web3.js workflows.

I assume based on openzeppelin-test-helpers that you have an older version.

I suggest that you update to the latest version (npm install @openzeppelin/test-helpers) and try with that.

Hi @abcoathup !
Thank you for the reply i tried with “@openzeppelin/test-helpers”: “^0.5.4” , but i still get the same error…

1 Like

Hi @Sarah,

Are you able to share your repository (if it is open source) or a cut down sample?

Otherwise I will need to create a project without truffle (I use Truffle and OpenZeppelin SDK) so I can reproduce the issue.

Hi @abcoathup , i could share the files that i think are involved , here : https://repl.it/repls/IncompatibleIdealAlgorithm i am sorry the paths are not correct let me know if you need something else !
I basically import the web3 and deploy function from the helper file and use it to deploy my smart contracts …
thank you

1 Like

Hi @Sarah,

Unfortunately I wasn’t able to reproduce the error. I cut down the sample code so it was just deploying an empty contract and the ERC1820Registry.
I am running on Windows Subsystem for Linux

$ node --version
v10.16.0
$ npm --version
6.13.0

When I ran the script (after running ganache-cli -d in a separate terminal) I can see the token deployed in ganache-cli

$ node index.js
token deployed at 0x32Cf1f3a98aeAF57b88b3740875D19912A522c1A

Output in ganache-cli:

  Transaction: 0xfefb2da535e927b85fe68eb81cb2e4a5827c905f78381a01ef2322aa9b0aee8e
  Contract created: 0x1820a4b7618bde71dce8cdc73aab6c95905fad24
  Gas usage: 711453
  Block Number: 2
  Block Time: Tue Nov 19 2019 14:29:17 GMT+1100 (Australian Eastern Daylight Time)

package.json

{
  "name": "lucky",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@openzeppelin/contracts": "^2.4.0",
    "@openzeppelin/test-helpers": "^0.5.4",
    "chai": "^4.2.0",
    "ganache-core": "^2.8.0",
    "solc": "^0.5.12",
    "web3": "^1.2.1"
  }
}

index.js

const helper =  require('./_helper');
const { singletons } = require('@openzeppelin/test-helpers');

(async () => {
    var { deploy, accounts, web3 } = await  helper.testHelper(`./contracts/`); // 
    //Deploy token contract
    let arr = [accounts[1]]
    await singletons.ERC1820Registry(accounts[1]);
    let Token = await deploy('Token',{ from: accounts[1], args: ["sahar", "sah", arr]});
    console.log('token deployed at', Token._address)
})().catch(e => {
   console.log(e)
});

_helper.js

const fs = require ('fs');
const solc= require('solc');
const linker= require('solc/linker');
const Ganache= require('ganache-core');
const Web3= require('web3');

var solcOpts = {
  language: 'Solidity',
  settings: {
    metadata: { useLiteralContent: true },
    outputSelection: {
      '*': {
        '*': ['abi', 'evm.bytecode.object']
      }
    }
  }
}

// Instantiate a web3 instance. Start a node if one is not already running.
 async function web3Helper(provider = 'ws://127.0.0.1:8545') {
  var web3 = new Web3(provider);
  var instance = await server(web3, provider)
  return { web3, server: instance }
}
module.exports.web3Helper = web3Helper;


function findImportsPath(prefix) {
  return function findImports(path) {
    try {
      return {
        contents: fs.readFileSync(prefix + path).toString()
      }
    } catch (e) {
      return { error: 'File not found' }
    }
  }
}



  async function compile(contractpath,contractName)
  {
    var web3 = new Web3("ws://"+process.env.GANACHE_HOST+":"+process.env.GANACHE_PORT);
   var sources = {
      [contractName]: {
        content: fs.readFileSync(`${contractpath}/${contractName}.sol`).toString()
      }
    }
    var compileOpts = JSON.stringify({ ...solcOpts, sources })

    // Compile the contract using solc
    var rawOutput = solc.compileStandardWrapper(
      compileOpts,
      findImportsPath(contractpath)
    )
    var output = JSON.parse(rawOutput)

    // If there were any compilation errors, throw them
    if (output.errors) {
      output.errors.forEach(err => {
        if (!err.formattedMessage.match(/Warning:/)) {
          throw new SyntaxError(err.formattedMessage)
        }
      })
    }

    var { abi, evm: { bytecode } } = output.contracts[contractName][
      contractName
    ]
     return {abi,web3};


  }

module.exports.compile = compile;


 async function testHelper(contracts, provider) {
  const { web3, server } = await web3Helper(provider)
  const accounts = await web3.eth.getAccounts()



  async function deploy(contractName, { from, args, log }) {

    var sources = {
      [contractName]: {
        content: fs.readFileSync(`${contracts}/${contractName}.sol`).toString()
      }
    }
    var compileOpts = JSON.stringify({ ...solcOpts, sources })

    // Compile the contract using solc
    var rawOutput = solc.compileStandardWrapper(
      compileOpts,
      findImportsPath(contracts)
    )
    var output = JSON.parse(rawOutput)

    // If there were any compilation errors, throw them
    if (output.errors) {
      output.errors.forEach(err => {
        if (!err.formattedMessage.match(/Warning:/)) {
          throw new SyntaxError(err.formattedMessage)
        }
      })
    }

    var { abi, evm: { bytecode } } = output.contracts[contractName][
      contractName
    ]

    // Deploy linked libraries
    for (let linkedFile in bytecode.linkReferences) {
      for (let linkedLib in bytecode.linkReferences[linkedFile]) {
        let libObj = output.contracts[linkedFile][linkedLib]
        let LibContract = new web3.eth.Contract(libObj.abi)
        var libContract = await LibContract.deploy({
          data: libObj.evm.bytecode.object
        }).send({
          from,
          gas: 900000000
        })

        let libs = { [`${linkedFile}:${linkedLib}`]: libContract._address }

        bytecode.object = linker.linkBytecode(bytecode.object, libs)
      }
    }

    if (!bytecode.object) {
      throw new Error(
        'No Bytecode. Do the method signatures match the interface?'
      )
    }

    if (process.env.BUILD) {
      fs.writeFileSync(
        __dirname + '/../src/contracts/' + contractName + '.js',
        'module.exports = ' +
          JSON.stringify(
            {
              abi,
              data: bytecode.object
            },
            null,
            4
          )
      )
    }

    // Instantiate the web3 contract using the abi and bytecode output from solc
    var Contract = new web3.eth.Contract(abi)
    var contract

    await new Promise(async resolve => {
      var chainId = web3.eth.net.getId()

      var data = await Contract.deploy({
        data: '0x' + bytecode.object,
        arguments: args
      }).encodeABI()
      web3.eth
        .sendTransaction({
          data,
          from,
          value: 0,
          gas: 4612388,
          chainId
        })
        .once('transactionHash', hash => {
          if (log) {
            console.log('Transaction Hash', hash)
          }
        })
        .once('receipt', receipt => {
          if (log) {
            console.log(
              `Deployed ${contractName} to ${receipt.contractAddress} (${
                receipt.cumulativeGasUsed
              } gas used)`
            )
          }
        })
        .catch('error', err => {
          console.log('eeeeeeeeeeeeeeeeeeeeeeeeeee', err)
          resolve()
        })
        .then(instance => {
          contract = new web3.eth.Contract(abi, instance.contractAddress)
          resolve()
        })
    })

    if (contract) {
      // Set some default options on the contract
      contract.options.gas = 1500000
      contract.options.from = from
    }

    return contract
  }

  return { web3, accounts, deploy, server}
}

// Start the server if it hasn't been already...
async function server(web3, provider) {
  try {
    // Hack to prevent "connection not open on send" error when using websockets
    web3.setProvider(provider.replace(/^ws/, 'http'))
    await web3.eth.net.getId()
    web3.setProvider(provider)
    return
  } catch (e) {
    /* Ignore */
  }

  var port = '7545'
  if (String(provider).match(/:([0-9]+)$/)) {
    port = provider.match(/:([0-9]+)$/)[1]
  }
  var server = Ganache.server()
  await server.listen(port)
  return server
}
module.exports.testHelper = testHelper;

Token.sol

pragma solidity ^0.5.0;

contract Token {
}

The issue seems to be related to the connection with the node’s RPC endpoint.

test-helpers by defaults looks for a provider in the port 8545. I see that you’re using 7545. Take a look at the Configuration section in the README and follow the steps to configure the provider and let us know how it goes!

2 Likes

Hi @sarah,

I ran ganache-cli on port 7545 and got the same JSON error as you did.

I added the following line to index.js to configure as per excellent pickup by @frangio and it now works. Sorry I didn’t spot this in the first place.

require('@openzeppelin/test-helpers/configure')({ provider: 'http://127.0.0.1:7545' });

index.js (updated)

const helper =  require('./_helper');
const { singletons } = require('@openzeppelin/test-helpers');
require('@openzeppelin/test-helpers/configure')({ provider: 'http://127.0.0.1:7545' });

(async () => {
    var { deploy, accounts, web3 } = await  helper.testHelper(`./contracts/`); // 
    //Deploy token contract
    let arr = [accounts[1]]
    await singletons.ERC1820Registry(accounts[1]);
    let Token = await deploy('Token',{ from: accounts[1], args: ["sahar", "sah", arr]});
    console.log('token deployed at', Token._address)
})().catch(e => {
   console.log(e)
});
2 Likes

@abcoathup @frangio Thank you so much ! indeed that solved my problem !
Thank youuu ! :DDDDDD

2 Likes

Awesome! :smile:

By the way, I think you will like our new project: Test Environment. I noticed that your _helper.js is doing essentially the same thing of spinning up a Ganache server. Our library will also automatically configure Test Helpers for you, and will work great if you want to parallelize your tests using other test runners like Jest or Ava.

2 Likes

Hello ,

Sorry i know this was supposed to be closed, just wanted to verify an information about the function “ERC1820Registry” in the file " openzeppelin-test-helpers/src/ singletons.js "

In this function there is this line:
await send.ether(funder, '0xa990077c3205cbDf861e17Fa532eeB069cE9fF96', ether('0.08'));
which calls the function “ether()” in the send.js file :

function ether (from, to, value) {
  return web3.eth.sendTransaction({ from, to, value, gasPrice: 0 });
}

So in the case where someone is using a local node and local private keys then he can’t use web3.eth.sendTransaction , instead he uses sendRawTransaction , meaning i guess if he can’t deploy the erc1820 contract using the openzeppelin-test-helpers because i guess he will have an error when trying to send ether to the deployer address on this line

await send.ether(funder, '0xa990077c3205cbDf861e17Fa532eeB069cE9fF96', ether('0.08'))

because that address is not known by the local node.

Please correct me if what i just said was wrong and i’m sorry again for re-opening this,

thanks a lot !

1 Like

Hello @Sarah!

There should be no issues sending funds to the deployer address (0xa999077...), regardless of the setup: it is just a regular Ethereum address.

Regarding the private key, if using web3 there should be a signing provider that knows how to sign messages and send raw transactions: this is what happens when you use mnemonic-based providers such as @truffle/hdwallet-provider.

Did you encounter a situation where you were unable to deploy the 1820Registry? If so, could you share more details about your setup? Thanks!

1 Like

hello @nventuro,
To be honest for me it worked just fine with ganache, but a friend tried it on a local parity node with local keys that he created and he had a problem in the deploy, we were looking into it and we figured out that it is on the line that sends ether to the deployer account that it fails … so that was the only explanation that came to me

1 Like

Interesting! It’d be great if you could share more information about the setup your friend uses so we can replicate it to find the issue and help you get the Registry deployed - your feedback is extremely useful to help us improve our tools and documentation.

1 Like

@nventuro Sorry for the late reply ,
So in a docker container we are running a private parity node. In our app.js file we have two arrays, first with 4 public keys and second with the corresponding private keys. He took the private keys from the KEYSTORE file. The _helper.js file looks pretty much the same as the one i shared above.
There is a send function to interact with deployed SM by creating a raw transaction and using web3.sendSignedTx.
If we comment the erc1820 part in the erc777 smart contract everything works fine.
When we try to add it with the following:

const { singletons }    = require('@openzeppelin/test-helpers');
require('@openzeppelin/test-helpers/configure')({ provider: 'ws://node:8546' });

And after before deploying token contract we do:

await singletons.ERC1820Registry(_address);

We noticed (after adding some console logs in the “singletons.js” file that it gets stuck on this call:

await send.ether(funder, '0xa990077c3205cbDf861e17Fa532eeB069cE9fF96', ether('0.08'));

Please let me know if you have an idea on why it might not be working , maybe we are doin sth wrong …

Thanks

Hm, the issue might be that send.ether sets a gasPrice of 0, which your node might reject. Test Helpers weren’t really designed to be used in this way - we might want to change that for a regular Ether transfer.

Try changing the send.ether line to the following:

await return web3.eth.sendTransaction({ funder, '0xa990077c3205cbDf861e17Fa532eeB069cE9fF96', ether('0.08') });
1 Like

Prior discussion about that here:

1 Like