Tokens are digital assets native to their blockchain, to provide interactivity, usability, and uniformity, token standards have been introduced, the most widely used standard for creating tokens in the (Ethereum Request for Comments 20) ERC20, ERC-20, and ERC-777 are some standards for fungible tokens that exist on the Ethereum blockchain. There are many token standards for smart contract development; however, the ERC 20 is the base standard or default standard, immutable and widely used in the development of smart contracts.
As a result, adopting a new standard for tokens when existing standards work perfectly fine is a no-brainer and often not considered. However, with the increased use and adoption of decentralized finance, and the huge locked up liquidity with almost non-existence regulation, there is an increased risk for dishonest participants to exploit the ecosystem and profit.
Choosing A Token Standard: ERC20 VS ERC777
ERC20 and ERC777 are the two tokens of choice for fungible token development. The choice of a token mostly depends on usage, adoption, features, and security.
ERC20 has wide usage, adoption, and security, while ERC777 has improved features and backward compatibility.
Purpose of ERC 777
The EIP (Ethereum Improvement Proposal) ERC777 introduces enhanced features to make interaction with tokens more responsive and enhanced.
Features such as hooks enable smart contracts to react or perform specific actions when an event occurs, giving token holders more control. This has the advantage of avoiding lost token scenarios where tokens are sent to the wrong destination addresses.
Also using operators, smart contracts are granted permissions to perform tasks and can send tokens on behalf of another contract or regular address.
The ERC777 standard is backward compatible with ERC20, this allows for seamless interacting with these tokens as if they were ERC20, using the standard functions and still benefiting from enhanced features.
What are smart contracts?
A smart contract is a self-executing code written by a developer to enforce the terms of the buyer-seller agreement. The code and its agreements are distributed and decentralized across a secure and immutable blockchain network.
Smart contracts require no third party, central authority or intermediary to enforce the terms of the code, the code in itself becomes the law. It can enable trusted transactions and agreements to be conducted among unknown parties and trust the safe performance of each person’s obligations.
Why are ERC777 tokens being used in exploits?
Smart contracts do encounter exploits, these exploits are mostly a result of a bug in a code, be it ERC20 or ERC777 smart contract codes are written by humans mostly in the solidity programming language, and all humans are fallible to mistakes and errors and sometimes unforeseeable events at one point in time can render existing infrastructures vulnerable if not expected for inclusion. The ERC777 has only made it easy to target poorly designed protocols.
Uniswap (A decentralized exchange) V1 pool for imBTC and Dforce were exploited using the re-entrancy vector attack. Re-entrancy attacks have become a well-known vulnerability, it came to light during famous DAO (Decentralized Autonomous Organization) hack in 2016, when the ERC777 standard was non-existent.
It is very convenient to blame a token standard for an exploit, where developers and project teams to not thoroughly subject smart contracts to audit and upgrades and are solely driven by profit.
Use cases of ERC777
- It can be used to blacklist or reject tokens from certain addresses
- Using operators, It can be used to automatically process subscriptions or payments on your behalf.
- The send function allows user transaction data and operator transaction data to be added for faster reconciliations.
- It can allow to automatically redirect specific tokens to another contract.
Using ERC777 tokensReceived Hook
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.1/contracts/token/ERC777/ERC777.sol";
contract my777Receiver is IERC777Recipient {
mapping (address=>uint) public balances;
ERC777 my_erc777;
IERC1820Registry private registry1820= IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
constructor (address my_erc777_address){
registry1820.setInterfaceImplementer(address(this),keccak256("ERC777TokensRecipient"),address(this));
my_erc777 = ERC777(my_erc777_address);
}
//ERC777 Recipient Hook
function tokensReceived(address operator, address from, address to,uint256 amount, bytes calldata data,
bytes calldata operatorData) external {
//revert or require
}
function () external payable {}
}
Using ERC777 tokensToSend Hook
// SPDX-License-Identifier: MIT
//Using https://remix.ethereum.org
pragma solidity >=0.8.4;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.1/contracts/token/ERC777/ERC777.sol";
contract ERC777 is IERC777Recipient {
//calling the setInterfaceImplementer function on the ERC-1820 registry with the holder address as the address
IERC1820Registry private registry1820= IERC1820Registry (0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
registry1820.setInterfaceImplementer(address(this), keccak256("ERC777TokensSender"), address(this));
mapping (address=>uint) public balances;
//ERC777 Sender Hook
function tokensToSend(address operator, address from,address to,uint256 amount,bytes calldata userData,
bytes calldata operatorData) external{
}
function () external payable {}
}
Using ERC777 Operators
// SPDX-License-Identifier: MIT
//Using https://remix.ethereum.org
pragma solidity >=0.8.4;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.1/contracts/token/ERC777/ERC777.sol";
contract my777Receiver is IERC777Recipient {
mapping (address=>uint) public balances;
ERC777 my_erc777;
IERC1820Registry private registry1820= IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
constructor (address my_erc777_address){
registry1820.setInterfaceImplementer(address(this),keccak256("ERC777TokensRecipient"),address(this));
my_erc777 = ERC777(my_erc777_address);
}
//ERC 777 HOOK
function tokensReceived(address operator,address from,address to,uint256 amount,
bytes calldata userData,bytes calldata operatorData) override external{
// revert();
}
//Authorised Operator deposit
function deposit(uint amount) public{
my_erc777.operatorSend(address(msg.sender), address(this), amount, "", "");
balances[msg.sender] += amount;
}
//authorised Operator withdrawal
function withdrawTokens() public{
my_erc777.operatorSend(address(this), address(msg.sender), balances[msg.sender], "", "");
balances[msg.sender] = 0;
}
}
ERC777 sending process
-
A sender, being the owner of a token who would like to transfer tokens to the ERC777 contract will call the send function of ERC777.
-
The contract will then find out from the registry contract, thus the deployed ERC1820 (trusted registry already deployed on the blockchain) whether the recipient address has registered with it to receive tokens.
-
If there is a record in the registry, then the function tokensReceived in the recipient contract is going to be called to receive tokens.
-
The recipient contract can also decide to reject the tokens within the tokensReceived function.
ERC777 recipient contract can register ERC20 tokens in the ERC1820 registry to also enjoy the benefits of hooks.
Preventing smart contract risks
Risk is constantly present and smart contract risk is no exception. It is, therefore, of essence to adopt risk management practices to safeguard entities who use decentralized finance, considering the huge amount of funds being moved into the space. The following are worth considering though not exhaustive to reduce the risks.
Audit
With the increased value locked up in Decentralized Finance (DeFi), there is an increased need for security audits. Smart contract vulnerabilities, rug pulls, and other code bugs. Smart contract audits can be done manually or automated. smart-contract auditors look into smart contract codes to detect vulnerabilities and security issues, thereby giving a level of assurance that a project code can be safely deployed.
Certik, Chainsulting, Openzeppellen, Perkshield are some notable block chain security firms that audit smart contracts.
Buying insurance coverage
DeFi insurance refers to insuring yourself, or ‘buying coverage’, against losses and risks arising from events in the DeFi space.
Decentralized finance (DeFi) insurance is a coverage that protects users from loss in exchange for a fee. Insurance coverage providers may be centralized or a decentralized pool of insurance coverage providers. By buying insurance coverage, the effect of losses can be minimized.
Opium insurance, insurAce, nexus Mutual, Bridge mutual, Insure Defi and Unslashed are some decentralized finance insurance coverage providers.
Using Experienced developers: The use of experienced developers can help reduce some risks that face smart contracts. Season smart contract developers are more opportune to know some risks that face the industry and best practices to adopt in smart contract deployments.
Avoid copying other codes: Copying or forking code from other protocols is a speedy way to develop but may lead to easy exploits because of familiarity and possible incompatibility issues.
Limit user access: Hardware or software devices may be used to store your private keys offline, user access should be restricted to only a few users who require access, a multi-signature contract may also be used to strengthen the security.
Wrap up
ERC777 introduces amazing features for smart contract usage; however, due to it
Developers are therefore encouraged to write software codes with risk reduction in mind, they can do this by protecting against known vulnerabilities, subjecting smart contract codes to audit, buying insurance coverage and providing functionalities to halt, pause and upgrade smart contracts.
Risk mitigation strategies can not eliminate losses, but it can reduce the impact of losses.