I will share the code I have it so far.
1. XToken777Recipient Contract
You can see that the code is the same as in this Simple ERC777 token example
I just added revert function into tokenReceived function
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC777/IERC777.sol";
import "@openzeppelin/contracts/introspection/IERC1820Registry.sol";
import "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol";
contract XToken777Recipient is IERC777Recipient {
IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient");
IERC777 private _token;
event DoneStuff(address operator, address from, address to, uint256 amount, bytes userData, bytes operatorData);
constructor (address token) {
_token = IERC777(token);
_erc1820.setInterfaceImplementer(address(this), TOKENS_RECIPIENT_INTERFACE_HASH, address(this));
}
function tokensReceived(
address operator,
address from,
address to,
uint256 amount,
bytes calldata userData,
bytes calldata operatorData
) external override {
revert();
require(msg.sender == address(_token), "XToken777Recipient: Invalid token");
// do stuff
emit DoneStuff(operator, from, to, amount, userData, operatorData);
}
}
2. Truffle migration: 2_deploy.js
const XToken777Recipient = artifacts.require('XToken777Recipient');
require('@openzeppelin/test-helpers/configure')({ provider: web3.currentProvider, environment: 'truffle' });
const { singletons } = require('@openzeppelin/test-helpers');
module.exports = async (deployer, network, accounts) => {
if (network === 'development') {
// In a test environment an ERC777 token requires deploying an ERC1820 registry
await singletons.ERC1820Registry(accounts[0]);
}
await deployer.deploy(XToken777Recipient, "0x8D8ab567C57De121C515c85c24f9B3d796c0872A"); // Contract address of XToken Testnet link: https://rinkeby.etherscan.io/token/0x8D8ab567C57De121C515c85c24f9B3d796c0872A
};
3. Truffle config: truffle-config.js
const HDWalletProvider = require('@truffle/hdwallet-provider');
module.exports = {
networks: {
development: {
protocol: 'http',
host: 'localhost',
port: 8545,
gas: 5000000,
gasPrice: 5e9,
networkId: '*',
},
rinkeby: {
network_id: '4',
provider: () => new HDWalletProvider(
['<privateKey>'],
'https://rinkeby.infura.io/v3/<apiKey>'>,
0,
1,
),
gasPrice: 10000000000, // 10 gwei
gas: 6900000,
from: '<ownerAddress>',
timeoutBlocks: 500,
}
},
mocha: {
// timeout: 100000
},
compilers: {
solc: {
version: '0.8.0',
docker: false,
parser: 'solcjs',
settings: {
optimizer: {
enabled: true,
runs: 50000
},
evmVersion: 'istanbul',
}
}
},
db: {
enabled: false
}
};
Now i will explain the whole process step by step:
- Created an ERC20 token named: XToken Testnet (XTT)
- Created new user address and sent 5000 XTT to it
- Ran command: migrate --network rinkeby
2_deploy.js
===========
Deploying 'XToken777Recipient'
------------------------------
> transaction hash: 0x9c4feebdff10a771a31b5bf32d7db82de2e295c3e7f153e288c5b08044c63e09
> Blocks: 0 Seconds: 8
> contract address: 0x96aBa35C73Ff3d86f4d904B26C94CF373B214Cc6
> block number: 8779769
> block timestamp: 1623932892
> account: 0x58C7716959efb3E6495793956F639Efc2a3412Aa
> balance: 1.99554411
> gas used: 220137 (0x35be9)
> gas price: 10 gwei
> value sent: 0 ETH
> total cost: 0.00220137 ETH
- From XToken User I sent 10 XTT tokens to XToken777Recipient contract
So you can see that the transaction has been confirmed and should be reverted. You can see revert function in XToken777Recipient tokenReceived function.