GitHub Logo 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

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: