github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/examples/precompile_example/HederaTokenService.sol (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  pragma solidity >=0.5.0 <0.9.0;
     3  pragma experimental ABIEncoderV2;
     4  
     5  // This file was copied from github.com/hashgraph/hedera-smart-contracts on Sep 27 2023
     6  
     7  import "./HederaResponseCodes.sol";
     8  import "./IHederaTokenService.sol";
     9  
    10  abstract contract HederaTokenService {
    11      address constant precompileAddress = address(0x167);
    12      // 90 days in seconds
    13      int32 constant defaultAutoRenewPeriod = 7776000;
    14  
    15      modifier nonEmptyExpiry(IHederaTokenService.HederaToken memory token)
    16      {
    17          if (token.expiry.second == 0 && token.expiry.autoRenewPeriod == 0) {
    18              token.expiry.autoRenewPeriod = defaultAutoRenewPeriod;
    19          }
    20          _;
    21      }
    22  
    23      /// Generic event
    24      event CallResponseEvent(bool, bytes);
    25  
    26      /// Performs transfers among combinations of tokens and hbars
    27      /// @param transferList the list of hbar transfers to do
    28      /// @param tokenTransfers the list of transfers to do
    29      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
    30      /// @custom:version 0.3.0 the signature of the previous version was cryptoTransfer(TokenTransferList[] memory tokenTransfers)
    31      function cryptoTransfer(IHederaTokenService.TransferList memory transferList, IHederaTokenService.TokenTransferList[] memory tokenTransfers) internal
    32      returns (int responseCode)
    33      {
    34          (bool success, bytes memory result) = precompileAddress.call(
    35              abi.encodeWithSelector(IHederaTokenService.cryptoTransfer.selector, transferList, tokenTransfers));
    36          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
    37      }
    38  
    39      /// Mints an amount of the token to the defined treasury account
    40      /// @param token The token for which to mint tokens. If token does not exist, transaction results in
    41      ///              INVALID_TOKEN_ID
    42      /// @param amount Applicable to tokens of type FUNGIBLE_COMMON. The amount to mint to the Treasury Account.
    43      ///               Amount must be a positive non-zero number represented in the lowest denomination of the
    44      ///               token. The new supply must be lower than 2^63.
    45      /// @param metadata Applicable to tokens of type NON_FUNGIBLE_UNIQUE. A list of metadata that are being created.
    46      ///                 Maximum allowed size of each metadata is 100 bytes
    47      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
    48      /// @return newTotalSupply The new supply of tokens. For NFTs it is the total count of NFTs
    49      /// @return serialNumbers If the token is an NFT the newly generate serial numbers, otherwise empty.
    50      function mintToken(address token, int64 amount, bytes[] memory metadata) internal
    51      returns (int responseCode, int64 newTotalSupply, int64[] memory serialNumbers)
    52      {
    53          (bool success, bytes memory result) = precompileAddress.call(
    54              abi.encodeWithSelector(IHederaTokenService.mintToken.selector,
    55              token, amount, metadata));
    56          (responseCode, newTotalSupply, serialNumbers) =
    57          success
    58          ? abi.decode(result, (int32, int64, int64[]))
    59          : (HederaResponseCodes.UNKNOWN, int64(0), new int64[](0));
    60      }
    61  
    62      /// Burns an amount of the token from the defined treasury account
    63      /// @param token The token for which to burn tokens. If token does not exist, transaction results in
    64      ///              INVALID_TOKEN_ID
    65      /// @param amount  Applicable to tokens of type FUNGIBLE_COMMON. The amount to burn from the Treasury Account.
    66      ///                Amount must be a positive non-zero number, not bigger than the token balance of the treasury
    67      ///                account (0; balance], represented in the lowest denomination.
    68      /// @param serialNumbers Applicable to tokens of type NON_FUNGIBLE_UNIQUE. The list of serial numbers to be burned.
    69      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
    70      /// @return newTotalSupply The new supply of tokens. For NFTs it is the total count of NFTs
    71      function burnToken(address token, int64 amount, int64[] memory serialNumbers) internal
    72      returns (int responseCode, int64 newTotalSupply)
    73      {
    74          (bool success, bytes memory result) = precompileAddress.call(
    75              abi.encodeWithSelector(IHederaTokenService.burnToken.selector,
    76              token, amount, serialNumbers));
    77          (responseCode, newTotalSupply) =
    78          success
    79          ? abi.decode(result, (int32, int64))
    80          : (HederaResponseCodes.UNKNOWN, int64(0));
    81      }
    82  
    83      ///  Associates the provided account with the provided tokens. Must be signed by the provided
    84      ///  Account's key or called from the accounts contract key
    85      ///  If the provided account is not found, the transaction will resolve to INVALID_ACCOUNT_ID.
    86      ///  If the provided account has been deleted, the transaction will resolve to ACCOUNT_DELETED.
    87      ///  If any of the provided tokens is not found, the transaction will resolve to INVALID_TOKEN_REF.
    88      ///  If any of the provided tokens has been deleted, the transaction will resolve to TOKEN_WAS_DELETED.
    89      ///  If an association between the provided account and any of the tokens already exists, the
    90      ///  transaction will resolve to TOKEN_ALREADY_ASSOCIATED_TO_ACCOUNT.
    91      ///  If the provided account's associations count exceed the constraint of maximum token associations
    92      ///    per account, the transaction will resolve to TOKENS_PER_ACCOUNT_LIMIT_EXCEEDED.
    93      ///  On success, associations between the provided account and tokens are made and the account is
    94      ///    ready to interact with the tokens.
    95      /// @param account The account to be associated with the provided tokens
    96      /// @param tokens The tokens to be associated with the provided account. In the case of NON_FUNGIBLE_UNIQUE
    97      ///               Type, once an account is associated, it can hold any number of NFTs (serial numbers) of that
    98      ///               token type
    99      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   100      function associateTokens(address account, address[] memory tokens) internal returns (int responseCode) {
   101          (bool success, bytes memory result) = precompileAddress.call(
   102              abi.encodeWithSelector(IHederaTokenService.associateTokens.selector,
   103              account, tokens));
   104          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   105      }
   106  
   107      function associateToken(address account, address token) internal returns (int responseCode) {
   108          (bool success, bytes memory result) = precompileAddress.call(
   109              abi.encodeWithSelector(IHederaTokenService.associateToken.selector,
   110              account, token));
   111          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   112      }
   113  
   114      /// Dissociates the provided account with the provided tokens. Must be signed by the provided
   115      /// Account's key.
   116      /// If the provided account is not found, the transaction will resolve to INVALID_ACCOUNT_ID.
   117      /// If the provided account has been deleted, the transaction will resolve to ACCOUNT_DELETED.
   118      /// If any of the provided tokens is not found, the transaction will resolve to INVALID_TOKEN_REF.
   119      /// If any of the provided tokens has been deleted, the transaction will resolve to TOKEN_WAS_DELETED.
   120      /// If an association between the provided account and any of the tokens does not exist, the
   121      /// transaction will resolve to TOKEN_NOT_ASSOCIATED_TO_ACCOUNT.
   122      /// If a token has not been deleted and has not expired, and the user has a nonzero balance, the
   123      /// transaction will resolve to TRANSACTION_REQUIRES_ZERO_TOKEN_BALANCES.
   124      /// If a <b>fungible token</b> has expired, the user can disassociate even if their token balance is
   125      /// not zero.
   126      /// If a <b>non fungible token</b> has expired, the user can <b>not</b> disassociate if their token
   127      /// balance is not zero. The transaction will resolve to TRANSACTION_REQUIRED_ZERO_TOKEN_BALANCES.
   128      /// On success, associations between the provided account and tokens are removed.
   129      /// @param account The account to be dissociated from the provided tokens
   130      /// @param tokens The tokens to be dissociated from the provided account.
   131      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   132      function dissociateTokens(address account, address[] memory tokens) internal returns (int responseCode) {
   133          (bool success, bytes memory result) = precompileAddress.call(
   134              abi.encodeWithSelector(IHederaTokenService.dissociateTokens.selector,
   135              account, tokens));
   136          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   137      }
   138  
   139      function dissociateToken(address account, address token) internal returns (int responseCode) {
   140          (bool success, bytes memory result) = precompileAddress.call(
   141              abi.encodeWithSelector(IHederaTokenService.dissociateToken.selector,
   142              account, token));
   143          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   144      }
   145  
   146      /// Creates a Fungible Token with the specified properties
   147      /// @param token the basic properties of the token being created
   148      /// @param initialTotalSupply Specifies the initial supply of tokens to be put in circulation. The
   149      /// initial supply is sent to the Treasury Account. The supply is in the lowest denomination possible.
   150      /// @param decimals the number of decimal places a token is divisible by
   151      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   152      /// @return tokenAddress the created token's address
   153      function createFungibleToken(
   154          IHederaTokenService.HederaToken memory token,
   155          int64 initialTotalSupply,
   156          int32 decimals) nonEmptyExpiry(token)
   157      internal returns (int responseCode, address tokenAddress) {
   158          (bool success, bytes memory result) = precompileAddress.call{value : msg.value}(
   159              abi.encodeWithSelector(IHederaTokenService.createFungibleToken.selector,
   160              token, initialTotalSupply, decimals));
   161  
   162  
   163          (responseCode, tokenAddress) = success ? abi.decode(result, (int32, address)) : (HederaResponseCodes.UNKNOWN, address(0));
   164      }
   165  
   166      /// Creates a Fungible Token with the specified properties
   167      /// @param token the basic properties of the token being created
   168      /// @param initialTotalSupply Specifies the initial supply of tokens to be put in circulation. The
   169      /// initial supply is sent to the Treasury Account. The supply is in the lowest denomination possible.
   170      /// @param decimals the number of decimal places a token is divisible by
   171      /// @param fixedFees list of fixed fees to apply to the token
   172      /// @param fractionalFees list of fractional fees to apply to the token
   173      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   174      /// @return tokenAddress the created token's address
   175      function createFungibleTokenWithCustomFees(
   176          IHederaTokenService.HederaToken memory token,
   177          int64 initialTotalSupply,
   178          int32 decimals,
   179          IHederaTokenService.FixedFee[] memory fixedFees,
   180          IHederaTokenService.FractionalFee[] memory fractionalFees) nonEmptyExpiry(token)
   181      internal returns (int responseCode, address tokenAddress) {
   182          (bool success, bytes memory result) = precompileAddress.call{value : msg.value}(
   183              abi.encodeWithSelector(IHederaTokenService.createFungibleTokenWithCustomFees.selector,
   184              token, initialTotalSupply, decimals, fixedFees, fractionalFees));
   185          (responseCode, tokenAddress) = success ? abi.decode(result, (int32, address)) : (HederaResponseCodes.UNKNOWN, address(0));
   186      }
   187  
   188      /// Creates an Non Fungible Unique Token with the specified properties
   189      /// @param token the basic properties of the token being created
   190      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   191      /// @return tokenAddress the created token's address
   192      function createNonFungibleToken(IHederaTokenService.HederaToken memory token) nonEmptyExpiry(token)
   193      internal returns (int responseCode, address tokenAddress) {
   194          (bool success, bytes memory result) = precompileAddress.call{value : msg.value}(
   195              abi.encodeWithSelector(IHederaTokenService.createNonFungibleToken.selector, token));
   196          (responseCode, tokenAddress) = success ? abi.decode(result, (int32, address)) : (HederaResponseCodes.UNKNOWN, address(0));
   197      }
   198  
   199      /// Creates an Non Fungible Unique Token with the specified properties
   200      /// @param token the basic properties of the token being created
   201      /// @param fixedFees list of fixed fees to apply to the token
   202      /// @param royaltyFees list of royalty fees to apply to the token
   203      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   204      /// @return tokenAddress the created token's address
   205      function createNonFungibleTokenWithCustomFees(
   206          IHederaTokenService.HederaToken memory token,
   207          IHederaTokenService.FixedFee[] memory fixedFees,
   208          IHederaTokenService.RoyaltyFee[] memory royaltyFees) nonEmptyExpiry(token)
   209      internal returns (int responseCode, address tokenAddress) {
   210          (bool success, bytes memory result) = precompileAddress.call{value : msg.value}(
   211              abi.encodeWithSelector(IHederaTokenService.createNonFungibleTokenWithCustomFees.selector,
   212              token, fixedFees, royaltyFees));
   213          (responseCode, tokenAddress) = success ? abi.decode(result, (int32, address)) : (HederaResponseCodes.UNKNOWN, address(0));
   214      }
   215  
   216      /// Retrieves fungible specific token info for a fungible token
   217      /// @param token The ID of the token as a solidity address
   218      function getFungibleTokenInfo(address token) internal returns (int responseCode, IHederaTokenService.FungibleTokenInfo memory tokenInfo) {
   219          (bool success, bytes memory result) = precompileAddress.call(
   220              abi.encodeWithSelector(IHederaTokenService.getFungibleTokenInfo.selector, token));
   221          IHederaTokenService.FungibleTokenInfo memory defaultTokenInfo;
   222          (responseCode, tokenInfo) = success ? abi.decode(result, (int32, IHederaTokenService.FungibleTokenInfo)) : (HederaResponseCodes.UNKNOWN, defaultTokenInfo);
   223      }
   224  
   225      /// Retrieves general token info for a given token
   226      /// @param token The ID of the token as a solidity address
   227      function getTokenInfo(address token) internal returns (int responseCode, IHederaTokenService.TokenInfo memory tokenInfo) {
   228          (bool success, bytes memory result) = precompileAddress.call(
   229              abi.encodeWithSelector(IHederaTokenService.getTokenInfo.selector, token));
   230          IHederaTokenService.TokenInfo memory defaultTokenInfo;
   231          (responseCode, tokenInfo) = success ? abi.decode(result, (int32, IHederaTokenService.TokenInfo)) : (HederaResponseCodes.UNKNOWN, defaultTokenInfo);
   232      }
   233  
   234      /// Retrieves non-fungible specific token info for a given NFT
   235      /// @param token The ID of the token as a solidity address
   236      function getNonFungibleTokenInfo(address token, int64 serialNumber) internal returns (int responseCode, IHederaTokenService.NonFungibleTokenInfo memory tokenInfo) {
   237          (bool success, bytes memory result) = precompileAddress.call(
   238              abi.encodeWithSelector(IHederaTokenService.getNonFungibleTokenInfo.selector, token, serialNumber));
   239          IHederaTokenService.NonFungibleTokenInfo memory defaultTokenInfo;
   240          (responseCode, tokenInfo) = success ? abi.decode(result, (int32, IHederaTokenService.NonFungibleTokenInfo)) : (HederaResponseCodes.UNKNOWN, defaultTokenInfo);
   241      }
   242  
   243      /// Query token custom fees
   244      /// @param token The token address to check
   245      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   246      /// @return fixedFees Set of fixed fees for `token`
   247      /// @return fractionalFees Set of fractional fees for `token`
   248      /// @return royaltyFees Set of royalty fees for `token`
   249      function getTokenCustomFees(address token) internal returns (int64 responseCode,
   250          IHederaTokenService.FixedFee[] memory fixedFees,
   251          IHederaTokenService.FractionalFee[] memory fractionalFees,
   252          IHederaTokenService.RoyaltyFee[] memory royaltyFees) {
   253          (bool success, bytes memory result) = precompileAddress.call(
   254              abi.encodeWithSelector(IHederaTokenService.getTokenCustomFees.selector, token));
   255          IHederaTokenService.FixedFee[] memory defaultFixedFees;
   256          IHederaTokenService.FractionalFee[] memory defaultFractionalFees;
   257          IHederaTokenService.RoyaltyFee[] memory defaultRoyaltyFees;
   258          (responseCode, fixedFees, fractionalFees, royaltyFees) =
   259          success ? abi.decode
   260          (result, (int32, IHederaTokenService.FixedFee[], IHederaTokenService.FractionalFee[], IHederaTokenService.RoyaltyFee[]))
   261          : (HederaResponseCodes.UNKNOWN, defaultFixedFees, defaultFractionalFees, defaultRoyaltyFees);
   262      }
   263  
   264      /// Allows spender to withdraw from your account multiple times, up to the value amount. If this function is called
   265      /// again it overwrites the current allowance with value.
   266      /// Only Applicable to Fungible Tokens
   267      /// @param token The hedera token address to approve
   268      /// @param spender the account authorized to spend
   269      /// @param amount the amount of tokens authorized to spend.
   270      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   271      function approve(address token, address spender, uint256 amount) internal returns (int responseCode)
   272      {
   273          (bool success, bytes memory result) = precompileAddress.call(
   274              abi.encodeWithSelector(IHederaTokenService.approve.selector,
   275              token, spender, amount));
   276          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   277      }
   278  
   279      /// Transfers `amount` tokens from `from` to `to` using the
   280      //  allowance mechanism. `amount` is then deducted from the caller's allowance.
   281      /// Only applicable to fungible tokens
   282      /// @param token The address of the fungible Hedera token to transfer
   283      /// @param from The account address of the owner of the token, on the behalf of which to transfer `amount` tokens
   284      /// @param to The account address of the receiver of the `amount` tokens
   285      /// @param amount The amount of tokens to transfer from `from` to `to`
   286      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   287      function transferFrom(address token, address from, address to, uint256 amount) external returns (int64 responseCode)
   288      {
   289          (bool success, bytes memory result) = precompileAddress.call(
   290              abi.encodeWithSelector(IHederaTokenService.transferFrom.selector,
   291              token, from, to, amount));
   292          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   293      }
   294  
   295      /// Transfers `serialNumber` of `token` from `from` to `to` using the allowance mechanism.
   296      /// Only applicable to NFT tokens
   297      /// @param token The address of the non-fungible Hedera token to transfer
   298      /// @param from The account address of the owner of `serialNumber` of `token`
   299      /// @param to The account address of the receiver of `serialNumber`
   300      /// @param serialNumber The NFT serial number to transfer
   301      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   302      function transferFromNFT(address token, address from, address to, uint256 serialNumber) external returns (int64 responseCode)
   303      {
   304          (bool success, bytes memory result) = precompileAddress.call(
   305              abi.encodeWithSelector(IHederaTokenService.transferFromNFT.selector,
   306              token, from, to, serialNumber));
   307          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   308      }
   309  
   310      /// Returns the amount which spender is still allowed to withdraw from owner.
   311      /// Only Applicable to Fungible Tokens
   312      /// @param token The Hedera token address to check the allowance of
   313      /// @param owner the owner of the tokens to be spent
   314      /// @param spender the spender of the tokens
   315      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   316      function allowance(address token, address owner, address spender) internal returns (int responseCode, uint256 amount)
   317      {
   318          (bool success, bytes memory result) = precompileAddress.call(
   319              abi.encodeWithSelector(IHederaTokenService.allowance.selector,
   320              token, owner, spender));
   321          (responseCode, amount) = success ? abi.decode(result, (int32, uint256)) : (HederaResponseCodes.UNKNOWN, 0);
   322      }
   323  
   324      /// Allow or reaffirm the approved address to transfer an NFT the approved address does not own.
   325      /// Only Applicable to NFT Tokens
   326      /// @param token The Hedera NFT token address to approve
   327      /// @param approved The new approved NFT controller.  To revoke approvals pass in the zero address.
   328      /// @param serialNumber The NFT serial number  to approve
   329      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   330      function approveNFT(address token, address approved, uint256 serialNumber) internal returns (int responseCode)
   331      {
   332          (bool success, bytes memory result) = precompileAddress.call(
   333              abi.encodeWithSelector(IHederaTokenService.approveNFT.selector,
   334              token, approved, serialNumber));
   335          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   336      }
   337  
   338      /// Get the approved address for a single NFT
   339      /// Only Applicable to NFT Tokens
   340      /// @param token The Hedera NFT token address to check approval
   341      /// @param serialNumber The NFT to find the approved address for
   342      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   343      /// @return approved The approved address for this NFT, or the zero address if there is none
   344      function getApproved(address token, uint256 serialNumber) internal returns (int responseCode, address approved)
   345      {
   346          (bool success, bytes memory result) = precompileAddress.call(
   347              abi.encodeWithSelector(IHederaTokenService.getApproved.selector,
   348              token, serialNumber));
   349          (responseCode, approved) =
   350          success
   351          ? abi.decode(result, (int32, address))
   352          : (HederaResponseCodes.UNKNOWN, address(0));
   353      }
   354  
   355      /// Query if token account is frozen
   356      /// @param token The token address to check
   357      /// @param account The account address associated with the token
   358      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   359      /// @return frozen True if `account` is frozen for `token`
   360      function isFrozen(address token, address account) internal returns (int64 responseCode, bool frozen){
   361          (bool success, bytes memory result) = precompileAddress.call(
   362              abi.encodeWithSelector(IHederaTokenService.isFrozen.selector, token, account));
   363          (responseCode, frozen) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false);
   364      }
   365  
   366      /// Query if token account has kyc granted
   367      /// @param token The token address to check
   368      /// @param account The account address associated with the token
   369      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   370      /// @return kycGranted True if `account` has kyc granted for `token`
   371      function isKyc(address token, address account) internal returns (int64 responseCode, bool kycGranted){
   372          (bool success, bytes memory result) = precompileAddress.call(
   373              abi.encodeWithSelector(IHederaTokenService.isKyc.selector, token, account));
   374          (responseCode, kycGranted) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false);
   375      }
   376  
   377      /// Operation to freeze token account
   378      /// @param token The token address
   379      /// @param account The account address to be frozen
   380      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   381      function freezeToken(address token, address account) internal returns (int64 responseCode){
   382          (bool success, bytes memory result) = precompileAddress.call(
   383              abi.encodeWithSelector(IHederaTokenService.freezeToken.selector, token, account));
   384          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   385      }
   386  
   387      /// Operation to unfreeze token account
   388      /// @param token The token address
   389      /// @param account The account address to be unfrozen
   390      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   391      function unfreezeToken(address token, address account) internal returns (int64 responseCode){
   392          (bool success, bytes memory result) = precompileAddress.call(
   393              abi.encodeWithSelector(IHederaTokenService.unfreezeToken.selector, token, account));
   394          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   395      }
   396  
   397      /// Operation to grant kyc to token account
   398      /// @param token The token address
   399      /// @param account The account address to grant kyc
   400      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   401      function grantTokenKyc(address token, address account) internal returns (int64 responseCode){
   402          (bool success, bytes memory result) = precompileAddress.call(
   403              abi.encodeWithSelector(IHederaTokenService.grantTokenKyc.selector, token, account));
   404          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   405      }
   406  
   407      /// Operation to revoke kyc to token account
   408      /// @param token The token address
   409      /// @param account The account address to revoke kyc
   410      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   411      function revokeTokenKyc(address token, address account) internal returns (int64 responseCode){
   412          (bool success, bytes memory result) = precompileAddress.call(
   413              abi.encodeWithSelector(IHederaTokenService.revokeTokenKyc.selector, token, account));
   414          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   415      }
   416  
   417      /// Enable or disable approval for a third party ("operator") to manage
   418      ///  all of `msg.sender`'s assets
   419      /// @param token The Hedera NFT token address to approve
   420      /// @param operator Address to add to the set of authorized operators
   421      /// @param approved True if the operator is approved, false to revoke approval
   422      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   423      function setApprovalForAll(address token, address operator, bool approved) internal returns (int responseCode)
   424      {
   425          (bool success, bytes memory result) = precompileAddress.call(
   426              abi.encodeWithSelector(IHederaTokenService.setApprovalForAll.selector,
   427              token, operator, approved));
   428          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   429      }
   430  
   431      /// Query if an address is an authorized operator for another address
   432      /// Only Applicable to NFT Tokens
   433      /// @param token The Hedera NFT token address to approve
   434      /// @param owner The address that owns the NFTs
   435      /// @param operator The address that acts on behalf of the owner
   436      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   437      /// @return approved True if `operator` is an approved operator for `owner`, false otherwise
   438      function isApprovedForAll(address token, address owner, address operator) internal returns (int responseCode, bool approved)
   439      {
   440          (bool success, bytes memory result) = precompileAddress.call(
   441              abi.encodeWithSelector(IHederaTokenService.isApprovedForAll.selector,
   442              token, owner, operator));
   443          (responseCode, approved) =
   444          success
   445          ? abi.decode(result, (int32, bool))
   446          : (HederaResponseCodes.UNKNOWN, false);
   447      }
   448  
   449      /// Query token default freeze status
   450      /// @param token The token address to check
   451      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   452      /// @return defaultFreezeStatus True if `token` default freeze status is frozen.
   453      function getTokenDefaultFreezeStatus(address token) internal returns (int responseCode, bool defaultFreezeStatus) {
   454          (bool success, bytes memory result) = precompileAddress.call(
   455              abi.encodeWithSelector(IHederaTokenService.getTokenDefaultFreezeStatus.selector, token));
   456          (responseCode, defaultFreezeStatus) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false);
   457      }
   458  
   459      /// Query token default kyc status
   460      /// @param token The token address to check
   461      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   462      /// @return defaultKycStatus True if `token` default kyc status is KycNotApplicable and false if Revoked.
   463      function getTokenDefaultKycStatus(address token) internal returns (int responseCode, bool defaultKycStatus) {
   464          (bool success, bytes memory result) = precompileAddress.call(
   465              abi.encodeWithSelector(IHederaTokenService.getTokenDefaultKycStatus.selector, token));
   466          (responseCode, defaultKycStatus) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false);
   467      }
   468  
   469      /**********************
   470       * ABI v1 calls       *
   471       **********************/
   472  
   473      /// Initiates a Fungible Token Transfer
   474      /// @param token The ID of the token as a solidity address
   475      /// @param accountIds account to do a transfer to/from
   476      /// @param amounts The amount from the accountId at the same index
   477      function transferTokens(address token, address[] memory accountIds, int64[] memory amounts) internal
   478      returns (int responseCode)
   479      {
   480          (bool success, bytes memory result) = precompileAddress.call(
   481              abi.encodeWithSelector(IHederaTokenService.transferTokens.selector,
   482              token, accountIds, amounts));
   483          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   484      }
   485  
   486      /// Initiates a Non-Fungable Token Transfer
   487      /// @param token The ID of the token as a solidity address
   488      /// @param sender the sender of an nft
   489      /// @param receiver the receiver of the nft sent by the same index at sender
   490      /// @param serialNumber the serial number of the nft sent by the same index at sender
   491      function transferNFTs(address token, address[] memory sender, address[] memory receiver, int64[] memory serialNumber)
   492      internal returns (int responseCode)
   493      {
   494          (bool success, bytes memory result) = precompileAddress.call(
   495              abi.encodeWithSelector(IHederaTokenService.transferNFTs.selector,
   496              token, sender, receiver, serialNumber));
   497          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   498      }
   499  
   500      /// Transfers tokens where the calling account/contract is implicitly the first entry in the token transfer list,
   501      /// where the amount is the value needed to zero balance the transfers. Regular signing rules apply for sending
   502      /// (positive amount) or receiving (negative amount)
   503      /// @param token The token to transfer to/from
   504      /// @param sender The sender for the transaction
   505      /// @param receiver The receiver of the transaction
   506      /// @param amount Non-negative value to send. a negative value will result in a failure.
   507      function transferToken(address token, address sender, address receiver, int64 amount) internal
   508      returns (int responseCode)
   509      {
   510          (bool success, bytes memory result) = precompileAddress.call(
   511              abi.encodeWithSelector(IHederaTokenService.transferToken.selector,
   512              token, sender, receiver, amount));
   513          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   514      }
   515  
   516      /// Transfers tokens where the calling account/contract is implicitly the first entry in the token transfer list,
   517      /// where the amount is the value needed to zero balance the transfers. Regular signing rules apply for sending
   518      /// (positive amount) or receiving (negative amount)
   519      /// @param token The token to transfer to/from
   520      /// @param sender The sender for the transaction
   521      /// @param receiver The receiver of the transaction
   522      /// @param serialNumber The serial number of the NFT to transfer.
   523      function transferNFT(address token, address sender, address receiver, int64 serialNumber) internal
   524      returns (int responseCode)
   525      {
   526          (bool success, bytes memory result) = precompileAddress.call(
   527              abi.encodeWithSelector(IHederaTokenService.transferNFT.selector,
   528              token, sender, receiver, serialNumber));
   529          responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   530      }
   531  
   532      /// Operation to pause token
   533      /// @param token The token address to be paused
   534      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   535      function pauseToken(address token) internal returns (int responseCode)
   536      {
   537          (bool success, bytes memory result) = precompileAddress.call(
   538              abi.encodeWithSelector(IHederaTokenService.pauseToken.selector, token));
   539          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   540      }
   541  
   542      /// Operation to unpause token
   543      /// @param token The token address to be unpaused
   544      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   545      function unpauseToken(address token) internal returns (int responseCode)
   546      {
   547          (bool success, bytes memory result) = precompileAddress.call(
   548              abi.encodeWithSelector(IHederaTokenService.unpauseToken.selector, token));
   549          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   550      }
   551  
   552      /// Operation to wipe fungible tokens from account
   553      /// @param token The token address
   554      /// @param account The account address to revoke kyc
   555      /// @param amount The number of tokens to wipe
   556      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   557      function wipeTokenAccount(address token, address account, int64 amount) internal returns (int responseCode)
   558      {
   559          (bool success, bytes memory result) = precompileAddress.call(
   560              abi.encodeWithSelector(IHederaTokenService.wipeTokenAccount.selector, token, account, amount));
   561          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   562      }
   563  
   564      /// Operation to wipe non fungible tokens from account
   565      /// @param token The token address
   566      /// @param account The account address to revoke kyc
   567      /// @param  serialNumbers The serial numbers of token to wipe
   568      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   569      function wipeTokenAccountNFT(address token, address account, int64[] memory serialNumbers) internal
   570      returns (int responseCode)
   571      {
   572          (bool success, bytes memory result) = precompileAddress.call(
   573              abi.encodeWithSelector(IHederaTokenService.wipeTokenAccountNFT.selector, token, account, serialNumbers));
   574          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   575      }
   576  
   577      /// Operation to delete token
   578      /// @param token The token address
   579      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   580      function deleteToken(address token) internal returns (int responseCode)
   581      {
   582          (bool success, bytes memory result) = precompileAddress.call(
   583              abi.encodeWithSelector(IHederaTokenService.deleteToken.selector, token));
   584          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   585      }
   586  
   587      /// Operation to update token keys
   588      /// @param token The token address
   589      /// @param keys The token keys
   590      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   591      function updateTokenKeys(address token, IHederaTokenService.TokenKey[] memory keys)
   592      internal returns (int64 responseCode){
   593          (bool success, bytes memory result) = precompileAddress.call(
   594              abi.encodeWithSelector(IHederaTokenService.updateTokenKeys.selector, token, keys));
   595          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   596      }
   597  
   598      /// Query token KeyValue
   599      /// @param token The token address to check
   600      /// @param keyType The keyType of the desired KeyValue
   601      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   602      /// @return key KeyValue info for key of type `keyType`
   603      function getTokenKey(address token, uint keyType)
   604      internal returns (int64 responseCode, IHederaTokenService.KeyValue memory key){
   605          (bool success, bytes memory result) = precompileAddress.call(
   606              abi.encodeWithSelector(IHederaTokenService.getTokenKey.selector, token, keyType));
   607          IHederaTokenService.KeyValue memory defaultKeyValueInfo;
   608          (responseCode, key) = success ? abi.decode(result, (int32,IHederaTokenService.KeyValue) ) : (HederaResponseCodes.UNKNOWN, defaultKeyValueInfo);
   609      }
   610  
   611  
   612      /// Query if valid token found for the given address
   613      /// @param token The token address
   614      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   615      /// @return isTokenFlag True if valid token found for the given address
   616      function isToken(address token) internal returns (int64 responseCode, bool isTokenFlag) {
   617          (bool success, bytes memory result) = precompileAddress.call(
   618              abi.encodeWithSelector(IHederaTokenService.isToken.selector, token));
   619          (responseCode, isTokenFlag) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false);
   620      }
   621  
   622      /// Query to return the token type for a given address
   623      /// @param token The token address
   624      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   625      /// @return tokenType the token type. 0 is FUNGIBLE_COMMON, 1 is NON_FUNGIBLE_UNIQUE, -1 is UNRECOGNIZED
   626      function getTokenType(address token) internal returns (int64 responseCode, int32 tokenType) {
   627          (bool success, bytes memory result) = precompileAddress.call(
   628              abi.encodeWithSelector(IHederaTokenService.getTokenType.selector, token));
   629          (responseCode, tokenType) = success ? abi.decode(result, (int32, int32)) : (HederaResponseCodes.UNKNOWN, - 1);
   630      }
   631  
   632      /// Operation to get token expiry info
   633      /// @param token The token address
   634      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   635      /// @return expiryInfo The expiry info of the token
   636      function getTokenExpiryInfo(address token) internal returns (int responseCode, IHederaTokenService.Expiry memory expiryInfo){
   637          (bool success, bytes memory result) = precompileAddress.call(
   638              abi.encodeWithSelector(IHederaTokenService.getTokenExpiryInfo.selector, token));
   639          IHederaTokenService.Expiry memory defaultExpiryInfo;
   640          (responseCode, expiryInfo) = success ? abi.decode(result, (int32, IHederaTokenService.Expiry)) : (HederaResponseCodes.UNKNOWN, defaultExpiryInfo);
   641      }
   642  
   643      /// Operation to update token expiry info
   644      /// @param token The token address
   645      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   646      function updateTokenExpiryInfo(address token, IHederaTokenService.Expiry memory expiryInfo) internal returns (int responseCode){
   647          (bool success, bytes memory result) = precompileAddress.call(
   648              abi.encodeWithSelector(IHederaTokenService.updateTokenExpiryInfo.selector, token, expiryInfo));
   649          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   650      }
   651  
   652      /// Operation to update token info
   653      /// @param token The token address
   654      /// @param tokenInfo The hedera token info to update token with
   655      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   656      function updateTokenInfo(address token, IHederaTokenService.HederaToken memory tokenInfo) internal returns (int responseCode) {
   657          (bool success, bytes memory result) = precompileAddress.call(
   658              abi.encodeWithSelector(IHederaTokenService.updateTokenInfo.selector, token, tokenInfo));
   659          (responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
   660      }
   661  
   662      /// Redirect for token
   663      /// @param token The token address
   664      /// @param encodedFunctionSelector The function selector from the ERC20 interface + the bytes input for the function called
   665      /// @return responseCode The response code for the status of the request. SUCCESS is 22.
   666      /// @return response The result of the call that had been encoded and sent for execution.
   667      function redirectForToken(address token, bytes memory encodedFunctionSelector) external returns (int responseCode, bytes memory response) {
   668          (bool success, bytes memory result) = precompileAddress.call(
   669              abi.encodeWithSelector(IHederaTokenService.redirectForToken.selector, token, encodedFunctionSelector)
   670          );
   671  
   672          emit CallResponseEvent(success, result);
   673          (responseCode, response) = success ? abi.decode(result, (int32, bytes)) : (HederaResponseCodes.UNKNOWN, bytes(""));
   674      }
   675  }