Ownership of ERC777 tokens

I’ve been having ‘fun’ developing an ERC777 contract setup. I may have it working, but I have a whole bunch of questions about _mint_, erc1820.setManager, erc1820.setInterfaceImplementer and the hook tokensToSend.

To keep this as brief as possible, I’m going to gloss over much of the pain I’ve been through :wink:

First, most of my issues seem to be with who receives newly minted tokens. When minting with msg.sender (i.e. the contract owner): _mint( msg.sender, msg.sender, _initialSupply, "", "" );, I’ve been unable to set any of my defaultOperators as a manager of the msg.sender address, and consequently, I’ve been unable to hook into tokensToSend (amongst other issues).

Instead, my token constructor gives the minted tokens to itself, i.e. _mint( address(this), address(this), _initialSupply, "", "" );. Afterwards, I do this: erc1820.setManager( address(this), _defaultOperators[0] );.

Then my token manager (_defaultOperators[0]), is passed the token, and calls erc1820.setInterfaceImplementer( address(token), TOKENS_SENDER_INTERFACE_HASH, address(this) );. That means it can send tokens, token.operatorSend( address(token), _recipient, _amount, "", _buyData );, which successfully hooks into tokensToSend (since my token manager is a IERC777Sender, and all seems to behave properly. Huzzah!

Is that correct? Can the ERC777 token contract give itself the tokens? Have I called erc1820.setManager and erc1820.setInterfaceImplementer correctly?

As I said, it all seems to behave correctly. However, when I deploy my token contracts to Ganache, I send an address some of my tokens via my contracts. Unfortunately, after adding the token to an address under MetaMask, the account shows 0 tokens, instead of the amount sent. Eek!

Apologies for the (probably) nonsensical posting, but any help/guidance/hugs are much appreciated :smiley:

1 Like

Hi @glowkeeper,

Sorry to hear that you have been suffering. :hugs: I hope I can help.

I created a Simple ERC777 token example including a recipient smart contract that may answer some of your questions. (Though I will need to update to import @openzeppelin/contracts, I will do this next week)

I haven't played with operators yet, the OpenZeppelin Contracts tests are a good place to look to see how they can be used. https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/test/token/ERC777/ERC777.test.js

Feel free to ask all the questions that you need and I can update the ERC777 token example to attempt to answer them :smile:

Hi @abcoathup,

Thanks for the response! My token is a little more complex than your example because it has an operator for managing both the coin and a database for recording buy and sells (the code is on GitHub, here: https://github.com/glowkeeper/Enervator). I think most of my problems have revolved around permissioning that operator. So I suppose my questions boils down to this:

Who should own newly minted tokens? I give them to the derived ERC777 contract itself - is that correct?

Your example gives them to the token contract creator, but I’m not certain that works for operators.

Anyway, thanks for pointing out ERC777Test - I hadn’t seen that! At first glance, it looks like it has some answers for me, so I shall go through it when I get home, later.

As an aside - MetaMask - I can import my new token into a wallet there, but the account holding some tokens I’ve sent is showing a balance of zero. Has anyone got MetaMask working with ERC777 openzeppelin tokens? If so, what am I missing?

Massive thanks for your help.

Steve Huckle

1 Like

I’ve just edited the reply above as I realised that my code gives minted tokens to the dervied ERC777 contract and not an operator.

1 Like

Hi @glowkeeper,

What ever account you want to own those minted tokens.
In my simple example I have the deployer of the contract as the holder of the tokens.
I assume you minted the tokens to be owned by the token itself as you are then using a default operator to transfer them.

defaultOperators : special accounts (usually other smart contracts) that will be able to transfer tokens on behalf of their holders.

I added a custom token in MetaMask (0xb7DB1fF4bB6fEddEc0B7F13EdCB35d877e8E8a04 on Ropsten) using the address of my deployed token, MetaMask picks up the symbol and precision. That account had a balance of zero, which is what MetaMask showed until I transferred some tokens to that account and then MetaMask displayed it correctly.

Did the account in MetaMask actually have a balance?
Suggest checking the holders (e.g. use Etherscan: https://ropsten.etherscan.io/token/0xb7db1ff4bb6feddec0b7f13edcb35d877e8e8a04#balances)

Uhmmm - I added a custom token I deployed to Rinkeby (0x4E302158Ee8FC54f4959Bc071cb050AfD723cC73) and MetaMask picks up the symbol and precision. I used a test script to transfer some Enervator tokens to my MetaMask address, but they have not appeared in MetaMask’s balance. Eek! I must be doing something wrong…

1 Like

Ah - this may be a bignumber maths issue as etherscan is showing some tokens transferred, but only tiny amounts. Progress, I think! Thanks @abcoathup!

1 Like

Yup - maths issues due to problems with decimals and bignumbers and all that nonsense - I’ll work that out, meanwhile, I’ve got tokens in my account on Rinkeby now! Boom!

1 Like

Hi @glowkeeper,

Having a look at Etherscan, it appears that you were able to transfer whole tokens:
I assume you have resolved.

If you haven’t read it previously, suggest reading the documentation section on decimals: https://docs.openzeppelin.com/contracts/2.x/tokens#a-note-on-decimals

Having a look at Etherscan, it appears that you were able to transfer whole tokens:


If you haven’t read it previously, suggest reading the documentation section on decimals

Thanks - I wish it were that simple! I'm well aware of the need for decimalisation! My problem was a combination of that decimal requirement (so I need to buy tokens * 10**18, and not just tokens) and needing to do fixed-point maths because I'm 'buying' tokens at a token-to-FIAT exchange rate. Hence, getting the arithmetic right in Solidity is tricky and you have noticed that I haven't been getting that quite right :wink:

Thanks for providing your 'simple' example - it's been an incredibly useful starting point. It kinda hides some important details (such as ownership of minted tokens concerning operators), but I'm sure more examples will come along soon, and I'm looking forward to seeing them...

1 Like

Good luck with the exchange rate mechanism. Ether to token rates are simpler (but can still be tricky)

I need to add operators to my example then :smile:

1 Like

Good luck with the exchange rate mechanism.


I'm currently storing exchange rates and FIAT amounts as 64.64 fixed point int128s and using abdk libraries to get the 64.64 fixed point amount of tokens by dividing the FIAT amount by the rate. Currently, I then find the decimal representation of the tokens required through uint256( fixedAmountEOR * 10**18 ) >> 64; . That appears close to correct when the exchange rate is >=1, but it breaks for decimal amounts (when the exchange rate is <1). So I still have some work to do, but for demo' purposes, It'll do for now :wink: Meanwhile, I'll have a read of that crowdsale link (thanks!), since it may have some solutions for me :slight_smile:

1 Like

This is the Rinkeby address of the token, after I deployed it with a proper supply: https://rinkeby.etherscan.io/token/0x0e57aa96b255e182896abd98c8015ffa6db9fe42. More details about the token here: https://github.com/glowkeeper/Enervator.

Meanwhile, I’ll be writing a quick front end to the token in the next week or so - the aim of that will be to simulate depositing FIAT currencies and buying Enervator tokens. Watch this space!

Thanks again for your help, @abcoathup!