|  | 
|  | 1 | +// SPDX-License-Identifier: Apache-2.0 | 
|  | 2 | +pragma solidity >=0.5.0 <0.9.0; | 
|  | 3 | +pragma experimental ABIEncoderV2; | 
|  | 4 | + | 
|  | 5 | +import "./IHederaTokenService.sol"; | 
|  | 6 | + | 
|  | 7 | +abstract contract HederaTokenService { | 
|  | 8 | +    // all response codes are defined here https://github.com/hashgraph/hedera-smart-contracts/blob/main/contracts/system-contracts/HederaResponseCodes.sol | 
|  | 9 | +    int32 constant UNKNOWN_CODE = 21; | 
|  | 10 | +    int32 constant SUCCESS_CODE = 22; | 
|  | 11 | + | 
|  | 12 | +    address constant precompileAddress = address(0x167); | 
|  | 13 | +    // 90 days in seconds | 
|  | 14 | +    int32 constant defaultAutoRenewPeriod = 7776000; | 
|  | 15 | + | 
|  | 16 | +    modifier nonEmptyExpiry(IHederaTokenService.HederaToken memory token) { | 
|  | 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 | +    /// Mints an amount of the token to the defined treasury account | 
|  | 27 | +    /// @param token The token for which to mint tokens. If token does not exist, transaction results in | 
|  | 28 | +    ///              INVALID_TOKEN_ID | 
|  | 29 | +    /// @param amount Applicable to tokens of type FUNGIBLE_COMMON. The amount to mint to the Treasury Account. | 
|  | 30 | +    ///               Amount must be a positive non-zero number represented in the lowest denomination of the | 
|  | 31 | +    ///               token. The new supply must be lower than 2^63. | 
|  | 32 | +    /// @param metadata Applicable to tokens of type NON_FUNGIBLE_UNIQUE. A list of metadata that are being created. | 
|  | 33 | +    ///                 Maximum allowed size of each metadata is 100 bytes | 
|  | 34 | +    /// @return responseCode The response code for the status of the request. SUCCESS is 22. | 
|  | 35 | +    /// @return newTotalSupply The new supply of tokens. For NFTs it is the total count of NFTs | 
|  | 36 | +    /// @return serialNumbers If the token is an NFT the newly generate serial numbers, otherwise empty. | 
|  | 37 | +    function mintToken( | 
|  | 38 | +        address token, | 
|  | 39 | +        int64 amount, | 
|  | 40 | +        bytes[] memory metadata | 
|  | 41 | +    ) | 
|  | 42 | +        internal | 
|  | 43 | +        returns ( | 
|  | 44 | +            int responseCode, | 
|  | 45 | +            int64 newTotalSupply, | 
|  | 46 | +            int64[] memory serialNumbers | 
|  | 47 | +        ) | 
|  | 48 | +    { | 
|  | 49 | +        (bool success, bytes memory result) = precompileAddress.call( | 
|  | 50 | +            abi.encodeWithSelector( | 
|  | 51 | +                IHederaTokenService.mintToken.selector, | 
|  | 52 | +                token, | 
|  | 53 | +                amount, | 
|  | 54 | +                metadata | 
|  | 55 | +            ) | 
|  | 56 | +        ); | 
|  | 57 | +        (responseCode, newTotalSupply, serialNumbers) = success | 
|  | 58 | +            ? abi.decode(result, (int32, int64, int64[])) | 
|  | 59 | +            : (HederaTokenService.UNKNOWN_CODE, 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( | 
|  | 72 | +        address token, | 
|  | 73 | +        int64 amount, | 
|  | 74 | +        int64[] memory serialNumbers | 
|  | 75 | +    ) internal returns (int responseCode, int64 newTotalSupply) { | 
|  | 76 | +        (bool success, bytes memory result) = precompileAddress.call( | 
|  | 77 | +            abi.encodeWithSelector( | 
|  | 78 | +                IHederaTokenService.burnToken.selector, | 
|  | 79 | +                token, | 
|  | 80 | +                amount, | 
|  | 81 | +                serialNumbers | 
|  | 82 | +            ) | 
|  | 83 | +        ); | 
|  | 84 | +        (responseCode, newTotalSupply) = success | 
|  | 85 | +            ? abi.decode(result, (int32, int64)) | 
|  | 86 | +            : (HederaTokenService.UNKNOWN_CODE, int64(0)); | 
|  | 87 | +    } | 
|  | 88 | + | 
|  | 89 | +    /// Creates a Fungible Token with the specified properties | 
|  | 90 | +    /// @param token the basic properties of the token being created | 
|  | 91 | +    /// @param initialTotalSupply Specifies the initial supply of tokens to be put in circulation. The | 
|  | 92 | +    /// initial supply is sent to the Treasury Account. The supply is in the lowest denomination possible. | 
|  | 93 | +    /// @param decimals the number of decimal places a token is divisible by | 
|  | 94 | +    /// @return responseCode The response code for the status of the request. SUCCESS is 22. | 
|  | 95 | +    /// @return tokenAddress the created token's address | 
|  | 96 | +    function createFungibleToken( | 
|  | 97 | +        IHederaTokenService.HederaToken memory token, | 
|  | 98 | +        int64 initialTotalSupply, | 
|  | 99 | +        int32 decimals | 
|  | 100 | +    ) | 
|  | 101 | +        internal | 
|  | 102 | +        nonEmptyExpiry(token) | 
|  | 103 | +        returns (int responseCode, address tokenAddress) | 
|  | 104 | +    { | 
|  | 105 | +        (bool success, bytes memory result) = precompileAddress.call{ | 
|  | 106 | +            value: msg.value | 
|  | 107 | +        }( | 
|  | 108 | +            abi.encodeWithSelector( | 
|  | 109 | +                IHederaTokenService.createFungibleToken.selector, | 
|  | 110 | +                token, | 
|  | 111 | +                initialTotalSupply, | 
|  | 112 | +                decimals | 
|  | 113 | +            ) | 
|  | 114 | +        ); | 
|  | 115 | + | 
|  | 116 | +        (responseCode, tokenAddress) = success | 
|  | 117 | +            ? abi.decode(result, (int32, address)) | 
|  | 118 | +            : (HederaTokenService.UNKNOWN_CODE, address(0)); | 
|  | 119 | +    } | 
|  | 120 | + | 
|  | 121 | +    /// Transfers tokens where the calling account/contract is implicitly the first entry in the token transfer list, | 
|  | 122 | +    /// where the amount is the value needed to zero balance the transfers. Regular signing rules apply for sending | 
|  | 123 | +    /// (positive amount) or receiving (negative amount) | 
|  | 124 | +    /// @param token The token to transfer to/from | 
|  | 125 | +    /// @param sender The sender for the transaction | 
|  | 126 | +    /// @param receiver The receiver of the transaction | 
|  | 127 | +    /// @param amount Non-negative value to send. a negative value will result in a failure. | 
|  | 128 | +    function transferToken( | 
|  | 129 | +        address token, | 
|  | 130 | +        address sender, | 
|  | 131 | +        address receiver, | 
|  | 132 | +        int64 amount | 
|  | 133 | +    ) internal returns (int responseCode) { | 
|  | 134 | +        (bool success, bytes memory result) = precompileAddress.call( | 
|  | 135 | +            abi.encodeWithSelector( | 
|  | 136 | +                IHederaTokenService.transferToken.selector, | 
|  | 137 | +                token, | 
|  | 138 | +                sender, | 
|  | 139 | +                receiver, | 
|  | 140 | +                amount | 
|  | 141 | +            ) | 
|  | 142 | +        ); | 
|  | 143 | +        responseCode = success | 
|  | 144 | +            ? abi.decode(result, (int32)) | 
|  | 145 | +            : HederaTokenService.UNKNOWN_CODE; | 
|  | 146 | +    } | 
|  | 147 | + | 
|  | 148 | +    /// Operation to update token keys | 
|  | 149 | +    /// @param token The token address | 
|  | 150 | +    /// @param keys The token keys | 
|  | 151 | +    /// @return responseCode The response code for the status of the request. SUCCESS is 22. | 
|  | 152 | +    function updateTokenKeys(address token, IHederaTokenService.TokenKey[] memory keys) | 
|  | 153 | +    internal returns (int64 responseCode){ | 
|  | 154 | +        (bool success, bytes memory result) = precompileAddress.call( | 
|  | 155 | +            abi.encodeWithSelector(IHederaTokenService.updateTokenKeys.selector, token, keys)); | 
|  | 156 | +        (responseCode) = success ? abi.decode(result, (int32)) : HederaTokenService.UNKNOWN_CODE; | 
|  | 157 | +    } | 
|  | 158 | + | 
|  | 159 | +} | 
0 commit comments