HIP-218: Smart Contract interactions with Hedera Token Accounts
Author | Danno Ferrin |
---|---|
Discussions-To | https://github.com/hashgraph/hedera-improvement-proposal/discussions/220 |
Status | Final ⓘ |
Needs Council Approval | Yes ⓘ |
Review period ends ⓘ | Fri, 03 Dec 2021 07:00:00 +0000 |
Type | Standards Track ⓘ |
Category | Service ⓘ |
Created | 2021-11-12 |
Updated | 2022-04-26 |
Requires | 206 |
Release | v0.24.0 |
Table of Contents
Abstract
Describe the interfaces and mechanisms that allow the Hedera Smart Contract Service (HSCS) to interact with Hedera Token Service (HTS) accounts as though they were ERC-20 and ERC-721 accounts.
Motivation
The goal of this HIP is to enable users of the HSCS to interact with Hedera native tokens in a manner that is similar to how they would in other EVM based systems. This mechanism is to send function calls to the account representing the token rather than to a centralized precompile with the token as an argument. However, we will still want to maintain the existing HTS precompile from HIP-206.
Rationale
The standard model of ERC-20 and ERC-721 interactions involves directly calling the account address. Solidity, however, does a code size check before calling a smart contract and reverts if it finds no code. To address this a simple proxy redirect is proposed to be added to each token contract accessed that will redirect the call (including information about what address was called). HSCS will report all token address have this precompile, permitting solidity to interact with the token addresses as though it was an account with code.
User stories
As a hedera smart contract services user, I want to be able to access my HTS fungible tokens like an Ethereum ERC-20 token.
As a hedera smart contract services user, I want to be able to access my HTS non-fungible tokens like an Ethereum ERC-721 token.
As a hedera smart contract services user, I want to be able to access metadata provided by the getTokenInfo in a smart contract.
Specification
EVM Precompile
The HTS precompile described in HIP-206, at address 0x167
,will be extended to
recognize one more function call: redirectForToken(address,bytes)
.
ERC-20 calls directly to Token Accounts
To enable HTS tokens to be more broadly used in DeFi applications the interactions with HSCS and Token accounts will be enhanced to allow HTS accounts to receive smart contract calls that will be immediately delegated to the HTS precompile for evaluation.
Redirect contract
Each HTS account will expose a standard redirection EVM bytestream. This
bytestream will be available to EXTCODEHASH
, EXTCODESIZE
and EXTCODECOPY
operations as though the smart contract were deployed itself. The EVM will
execute the bytecode, which will wrap the call data with the address of the HTS
Token, to a call to the HTS precompile. The HTS precompile will then either
execute or reject the call based on IERC20
mappings described in the next
section.
(The following pseudocode will be replaced with real EVM opcodes prior to review)
// Put CALLER in memory // Put the remaining CALLDATA into memory // DELEGATECALL 0x127 with all remaining gas // if the DELEGATECALL failed REVERT() // RETURN the exact same results as the DELEGATECALL
Gas Schedule
For function calls that cause HTS token transfers the appropriate gas charges will be applied. Calls that emit events will be charged the event fees too.
For other functions that return data the cost will be 10 gas per 32 bytes returned or fraction fo 32 bytes returned. For functions that return integers or an address this will be a flat 10 gas. For string values (name, symbol, etc.) this will be a variable fee.
Supported ERC-20 operations
Tokens of type FUNGIBLE_COMMON will support standard ERC-20 calls.
The following ERC-20 operations will be supported. Standard ERC-20 Events will be emitted as appropriate.
function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() external view returns (uint256)
function balanceOf(address account) external view returns (uint256)
function transfer(address recipient, uint256 amount) external returns (bool)
Support for these functions is described in HIP-376
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
Supported ERC-721 operations
Tokens of type NON_FUNGIBLE_UNIQUE will support standard ERC-721 calls.
The following ERC-721 operations will be supported. Standard ERC-721 Events will be emitted as appropriate.
- From interface ERC721
function balanceOf(address _owner) external view returns (uint256)
function ownerOf(uint256 _tokenId) external view returns (address)
- From interface ERC721Metadata
function name() external view returns (string _name)
function symbol() external view returns (string _symbol)
function tokenURI(uint256 _tokenId) external view returns (string)
- From interface ERC721Enumerable
function totalSupply() external view returns (uint256)
The following ERC-721 operations will not be directly supported and will return a failure if called.
- From interface ERC721
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable
- All semantics of interface ERC721TokenReceiver.
- Existing Hedera token association rules will take the place of such checks.
- From interface ERC721Enumerable
function tokenByIndex(uint256 _index) external view returns (uint256)
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256)
Support for these functions is described in HIP-376
- From interface ERC721
function approve(address _approved, uint256 _tokenId) external payable
function setApprovalForAll(address _operator, bool _approved) external
function getApproved(uint256 _tokenId) external view returns (address)
function isApprovedForAll(address _owner, address _operator) external view returns (bool)
function transferFrom(address _from, address _to, uint256 _tokenId) external payable
Backwards Compatibility
The existing functions in the HTS precompile will remain in place, all prior usages of the precompile will function as they did before.
Security Implications
The same implications relating to contract keys and delegate calls outlined in HIP-206 also apply to the direct support of ERC-20 and ERC-721 contracts.
How to Teach This
Tutorials and SDK examples should be written showing how solidity can access the token accounts directly as ERC-20 and ERC-721 contracts.
HSCS documentation should be updated to explicitly enumerate the supported and non-supported contract functions.
Reference Implementation
// TODO
Rejected Ideas
Directly supporting getTokenInfo
Some redirected ERC functions will result in a call to the getTokenInfo
gRPC method. Directly supporting that call outside of gRPC and protobufs is
problematic for a number of reasons. First, the Key
type is a complex and
nested struct, not well suited to flat representation. The CustomFee
type is
similarly dependent on a ‘oneof’ field. Second, the amount of data returned is
comparatively large to the amount of data expected to be used.
For those reasons the token info fields needed in a smart contract will be supported via ERC-20 methods and extra methods added to the ERC-20 interface as needed.
Support ERC-20 allowances and ERC-721 transfer approval
These two functions facilitate methods for “pull” payments and consignment of NFTs. Proper support would need to be plumbed through the HTS system and not layered on top by the HSCS. Future HIPs may provide the needed support for these operations. At that time enabling these methods can be reconsidered.
Open Issues
None at this time.
References
Copyright/license
This document is licensed under the Apache License, Version 2.0 – see LICENSE or (https://www.apache.org/licenses/LICENSE-2.0)
Citation
Please cite this document as: