VM Error deploying ERC777 with Remix

Using remix, compiler on 0.6.12 and I keep getting this error when trying to deploy basic erc777 from open zeppelin tutorials. Constructor params are “1000”,[“0x5B38Da6a701c568545dCfcB03FcB875f56beddC4”]

creation of GLDToken errored: VM error: revert. revert The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.

pragma solidity ^0.6.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC777/ERC777.sol";

contract GLDToken is ERC777 {
    constructor(uint256 initialSupply, address[] memory defaultOperators)
        ERC777("Gold", "GLR", defaultOperators)
        _mint(msg.sender, initialSupply, "", "");

Hi @adriadrop,

Welcome to the community :wave:

A key point to note is that in a testing environment an ERC777 token requires deploying an ERC1820 registry

From: Simple ERC777 token example

The issue is that the JavaScript VM doesn’t have the ERC1820 registry deployed.

You would need to deploy the ERC1820 registry first if deploying to a JavaScript VM (I don’t know how to do this in Remix without looking into it).

You could deploy locally to ganache-cli and deploy the ERC1820 registry using a script.
See the following example of a script to deploy ERC1820: How to deploy ERC777 using OpenZeppelin CLI?

Alternatively, you can deploy using Remix to a public testnet. I reproduced the error that you saw with a JavaScript VM and then deployed GLDToken to a public testnet. (Kovan)


Ohh so it must be then this part

contract ERC777 is Context, IERC777, IERC20 {
    using SafeMath for uint256;
    using Address for address;

    IERC1820Registry constant internal _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);

few questions if I may:

  1. How come this contract has same address on mainnet and kovan, how can it be achieved to have same hex on both?
  2. I am still new to solidity so I am trying to get when is something imported and when you can use already deployed contracts. This above uses deployed contract, but couldn’t we also just import this like usually we import .sol contracts? And also could we for example use some deployed SafeMath.sol contract instead of importing it? Maybe I am missing some important info here and experience, but this something I have doubts about.
1 Like

Hi @adriadrop,

EIP-1820 Registry Contract Address 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 is the same on every chain on which it is deployed as the same transaction is used to deploy.

It is achieved by using the keyless deployment method—also known as Nick’s method—which relies on a single-use address. (See Nick’s article for more details).

From: Deployment Method section of EIP 1820: https://eips.ethereum.org/EIPS/eip-1820

It is an interesting technique and worth digging into.

ERC 1820 is a universal registry smart contract, so we want all contracts to interact with the one registry.

We import the ERC1820 interface so that we can interact with the functions of the contract

We also import to inherit and extend a contract e.g. you could extend ERC777 implementation to creation your own token.

SafeMath functions are internal functions that:

at compile time be included in the calling contract, and a regular JUMP call will be used instead of a DELEGATECALL.

Thanx on answer, very helpful. Seems I am baffled a bit about when to use library and when to use already deployed contract on blockchain. For example I am thinking wouldn’t it also be possible to have
"EIP-1820 Registry Contract " as library and implemented with import? What would be downside if this was done like that or it wouldnt be even possible and why so?

1 Like

Hi @adriadrop,

If each contract used an ERC1820 registry library then the storage would be in each contract, so instead of a single universal registry there would be one for every contract. Does that make sense?

Yes it makes sense.

I see that this data is stored here

    mapping(address => mapping(bytes32 => address)) internal interfaces;

At this point I got it that it is useful that each contract saves data on which interfaces it supports so I guess other contracts using that contract can get info on what functions they can call. I dont get practical part, wouldnt you check manually which functions you can call from other contract before using them in your own? What is the use case here, trying still to fully wrap my mind around that and how does it give benefit?

1 Like

Hi @adriadrop,

I suggest reading the EIP (I will probably need to as well so that I can try to provide an explanation if needed).