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 }