// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.5.0 <0.9.0;
pragma experimental ABIEncoderV2;
import "../common/HederaResponseCodes.sol";
import "./IHederaTokenService.sol";
abstract contract HederaTokenService {
address constant precompileAddress = address(0x167);
// 90 days in seconds
int32 constant defaultAutoRenewPeriod = 7776000;
modifier nonEmptyExpiry(IHederaTokenService.HederaToken memory token)
{
if (token.expiry.second == 0 && token.expiry.autoRenewPeriod == 0) {
token.expiry.autoRenewPeriod = defaultAutoRenewPeriod;
}
_;
}
/// Generic event
event CallResponseEvent(bool, bytes);
/// Performs transfers among combinations of tokens and hbars
/// @param transferList the list of hbar transfers to do
/// @param tokenTransfers the list of transfers to do
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @custom:version 0.3.0 the signature of the previous version was cryptoTransfer(TokenTransferList[] memory tokenTransfers)
function cryptoTransfer(IHederaTokenService.TransferList memory transferList, IHederaTokenService.TokenTransferList[] memory tokenTransfers) internal
returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.cryptoTransfer.selector, transferList, tokenTransfers));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Mints an amount of the token to the defined treasury account
/// @param token The token for which to mint tokens. If token does not exist, transaction results in
/// INVALID_TOKEN_ID
/// @param amount Applicable to tokens of type FUNGIBLE_COMMON. The amount to mint to the Treasury Account.
/// Amount must be a positive non-zero number represented in the lowest denomination of the
/// token. The new supply must be lower than 2^63.
/// @param metadata Applicable to tokens of type NON_FUNGIBLE_UNIQUE. A list of metadata that are being created.
/// Maximum allowed size of each metadata is 100 bytes
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return newTotalSupply The new supply of tokens. For NFTs it is the total count of NFTs
/// @return serialNumbers If the token is an NFT the newly generate serial numbers, otherwise empty.
function mintToken(address token, int64 amount, bytes[] memory metadata) internal
returns (int responseCode, int64 newTotalSupply, int64[] memory serialNumbers)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.mintToken.selector,
token, amount, metadata));
(responseCode, newTotalSupply, serialNumbers) =
success
? abi.decode(result, (int32, int64, int64[]))
: (HederaResponseCodes.UNKNOWN, int64(0), new int64[](0));
}
/// Burns an amount of the token from the defined treasury account
/// @param token The token for which to burn tokens. If token does not exist, transaction results in
/// INVALID_TOKEN_ID
/// @param amount Applicable to tokens of type FUNGIBLE_COMMON. The amount to burn from the Treasury Account.
/// Amount must be a positive non-zero number, not bigger than the token balance of the treasury
/// account (0; balance], represented in the lowest denomination.
/// @param serialNumbers Applicable to tokens of type NON_FUNGIBLE_UNIQUE. The list of serial numbers to be burned.
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return newTotalSupply The new supply of tokens. For NFTs it is the total count of NFTs
function burnToken(address token, int64 amount, int64[] memory serialNumbers) internal
returns (int responseCode, int64 newTotalSupply)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.burnToken.selector,
token, amount, serialNumbers));
(responseCode, newTotalSupply) =
success
? abi.decode(result, (int32, int64))
: (HederaResponseCodes.UNKNOWN, int64(0));
}
/// Associates the provided account with the provided tokens. Must be signed by the provided
/// Account's key or called from the accounts contract key
/// If the provided account is not found, the transaction will resolve to INVALID_ACCOUNT_ID.
/// If the provided account has been deleted, the transaction will resolve to ACCOUNT_DELETED.
/// If any of the provided tokens is not found, the transaction will resolve to INVALID_TOKEN_REF.
/// If any of the provided tokens has been deleted, the transaction will resolve to TOKEN_WAS_DELETED.
/// If an association between the provided account and any of the tokens already exists, the
/// transaction will resolve to TOKEN_ALREADY_ASSOCIATED_TO_ACCOUNT.
/// If the provided account's associations count exceed the constraint of maximum token associations
/// per account, the transaction will resolve to TOKENS_PER_ACCOUNT_LIMIT_EXCEEDED.
/// On success, associations between the provided account and tokens are made and the account is
/// ready to interact with the tokens.
/// @param account The account to be associated with the provided tokens
/// @param tokens The tokens to be associated with the provided account. In the case of NON_FUNGIBLE_UNIQUE
/// Type, once an account is associated, it can hold any number of NFTs (serial numbers) of that
/// token type
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function associateTokens(address account, address[] memory tokens) internal returns (int responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.associateTokens.selector,
account, tokens));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
function associateToken(address account, address token) internal returns (int responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.associateToken.selector,
account, token));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Dissociates the provided account with the provided tokens. Must be signed by the provided
/// Account's key.
/// If the provided account is not found, the transaction will resolve to INVALID_ACCOUNT_ID.
/// If the provided account has been deleted, the transaction will resolve to ACCOUNT_DELETED.
/// If any of the provided tokens is not found, the transaction will resolve to INVALID_TOKEN_REF.
/// If any of the provided tokens has been deleted, the transaction will resolve to TOKEN_WAS_DELETED.
/// If an association between the provided account and any of the tokens does not exist, the
/// transaction will resolve to TOKEN_NOT_ASSOCIATED_TO_ACCOUNT.
/// If a token has not been deleted and has not expired, and the user has a nonzero balance, the
/// transaction will resolve to TRANSACTION_REQUIRES_ZERO_TOKEN_BALANCES.
/// If a fungible token has expired, the user can disassociate even if their token balance is
/// not zero.
/// If a non fungible token has expired, the user can not disassociate if their token
/// balance is not zero. The transaction will resolve to TRANSACTION_REQUIRED_ZERO_TOKEN_BALANCES.
/// On success, associations between the provided account and tokens are removed.
/// @param account The account to be dissociated from the provided tokens
/// @param tokens The tokens to be dissociated from the provided account.
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function dissociateTokens(address account, address[] memory tokens) internal returns (int responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.dissociateTokens.selector,
account, tokens));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
function dissociateToken(address account, address token) internal returns (int responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.dissociateToken.selector,
account, token));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Creates a Fungible Token with the specified properties
/// @param token the basic properties of the token being created
/// @param initialTotalSupply Specifies the initial supply of tokens to be put in circulation. The
/// initial supply is sent to the Treasury Account. The supply is in the lowest denomination possible.
/// @param decimals the number of decimal places a token is divisible by
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return tokenAddress the created token's address
function createFungibleToken(
IHederaTokenService.HederaToken memory token,
int64 initialTotalSupply,
int32 decimals) nonEmptyExpiry(token)
internal returns (int responseCode, address tokenAddress) {
(bool success, bytes memory result) = precompileAddress.call{value : msg.value}(
abi.encodeWithSelector(IHederaTokenService.createFungibleToken.selector,
token, initialTotalSupply, decimals));
(responseCode, tokenAddress) = success ? abi.decode(result, (int32, address)) : (HederaResponseCodes.UNKNOWN, address(0));
}
/// Creates a Fungible Token with the specified properties
/// @param token the basic properties of the token being created
/// @param initialTotalSupply Specifies the initial supply of tokens to be put in circulation. The
/// initial supply is sent to the Treasury Account. The supply is in the lowest denomination possible.
/// @param decimals the number of decimal places a token is divisible by
/// @param fixedFees list of fixed fees to apply to the token
/// @param fractionalFees list of fractional fees to apply to the token
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return tokenAddress the created token's address
function createFungibleTokenWithCustomFees(
IHederaTokenService.HederaToken memory token,
int64 initialTotalSupply,
int32 decimals,
IHederaTokenService.FixedFee[] memory fixedFees,
IHederaTokenService.FractionalFee[] memory fractionalFees) nonEmptyExpiry(token)
internal returns (int responseCode, address tokenAddress) {
(bool success, bytes memory result) = precompileAddress.call{value : msg.value}(
abi.encodeWithSelector(IHederaTokenService.createFungibleTokenWithCustomFees.selector,
token, initialTotalSupply, decimals, fixedFees, fractionalFees));
(responseCode, tokenAddress) = success ? abi.decode(result, (int32, address)) : (HederaResponseCodes.UNKNOWN, address(0));
}
/// Creates an Non Fungible Unique Token with the specified properties
/// @param token the basic properties of the token being created
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return tokenAddress the created token's address
function createNonFungibleToken(IHederaTokenService.HederaToken memory token) nonEmptyExpiry(token)
internal returns (int responseCode, address tokenAddress) {
(bool success, bytes memory result) = precompileAddress.call{value : msg.value}(
abi.encodeWithSelector(IHederaTokenService.createNonFungibleToken.selector, token));
(responseCode, tokenAddress) = success ? abi.decode(result, (int32, address)) : (HederaResponseCodes.UNKNOWN, address(0));
}
/// Creates an Non Fungible Unique Token with the specified properties
/// @param token the basic properties of the token being created
/// @param fixedFees list of fixed fees to apply to the token
/// @param royaltyFees list of royalty fees to apply to the token
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return tokenAddress the created token's address
function createNonFungibleTokenWithCustomFees(
IHederaTokenService.HederaToken memory token,
IHederaTokenService.FixedFee[] memory fixedFees,
IHederaTokenService.RoyaltyFee[] memory royaltyFees) nonEmptyExpiry(token)
internal returns (int responseCode, address tokenAddress) {
(bool success, bytes memory result) = precompileAddress.call{value : msg.value}(
abi.encodeWithSelector(IHederaTokenService.createNonFungibleTokenWithCustomFees.selector,
token, fixedFees, royaltyFees));
(responseCode, tokenAddress) = success ? abi.decode(result, (int32, address)) : (HederaResponseCodes.UNKNOWN, address(0));
}
/// Retrieves fungible specific token info for a fungible token
/// @param token The ID of the token as a solidity address
/// @dev This function reverts if the call is not successful
function getFungibleTokenInfo(address token) internal returns (int responseCode, IHederaTokenService.FungibleTokenInfo memory tokenInfo) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.getFungibleTokenInfo.selector, token));
IHederaTokenService.FungibleTokenInfo memory defaultTokenInfo;
(responseCode, tokenInfo) = success ? abi.decode(result, (int32, IHederaTokenService.FungibleTokenInfo)) : (HederaResponseCodes.UNKNOWN, defaultTokenInfo);
}
/// Retrieves general token info for a given token
/// @param token The ID of the token as a solidity address
/// @dev This function reverts if the call is not successful
function getTokenInfo(address token) internal returns (int responseCode, IHederaTokenService.TokenInfo memory tokenInfo) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.getTokenInfo.selector, token));
IHederaTokenService.TokenInfo memory defaultTokenInfo;
(responseCode, tokenInfo) = success ? abi.decode(result, (int32, IHederaTokenService.TokenInfo)) : (HederaResponseCodes.UNKNOWN, defaultTokenInfo);
}
/// Retrieves non-fungible specific token info for a given NFT
/// @param token The ID of the token as a solidity address
/// @dev This function reverts if the call is not successful
function getNonFungibleTokenInfo(address token, int64 serialNumber) internal returns (int responseCode, IHederaTokenService.NonFungibleTokenInfo memory tokenInfo) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.getNonFungibleTokenInfo.selector, token, serialNumber));
IHederaTokenService.NonFungibleTokenInfo memory defaultTokenInfo;
(responseCode, tokenInfo) = success ? abi.decode(result, (int32, IHederaTokenService.NonFungibleTokenInfo)) : (HederaResponseCodes.UNKNOWN, defaultTokenInfo);
}
/// Query token custom fees
/// @param token The token address to check
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return fixedFees Set of fixed fees for `token`
/// @return fractionalFees Set of fractional fees for `token`
/// @return royaltyFees Set of royalty fees for `token`
/// @dev This function reverts if the call is not successful
function getTokenCustomFees(address token) internal returns (int64 responseCode,
IHederaTokenService.FixedFee[] memory fixedFees,
IHederaTokenService.FractionalFee[] memory fractionalFees,
IHederaTokenService.RoyaltyFee[] memory royaltyFees) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.getTokenCustomFees.selector, token));
IHederaTokenService.FixedFee[] memory defaultFixedFees;
IHederaTokenService.FractionalFee[] memory defaultFractionalFees;
IHederaTokenService.RoyaltyFee[] memory defaultRoyaltyFees;
(responseCode, fixedFees, fractionalFees, royaltyFees) =
success ? abi.decode
(result, (int32, IHederaTokenService.FixedFee[], IHederaTokenService.FractionalFee[], IHederaTokenService.RoyaltyFee[]))
: (HederaResponseCodes.UNKNOWN, defaultFixedFees, defaultFractionalFees, defaultRoyaltyFees);
}
/// Allows spender to withdraw from your account multiple times, up to the value amount. If this function is called
/// again it overwrites the current allowance with value.
/// Only Applicable to Fungible Tokens
/// @param token The hedera token address to approve
/// @param spender the account authorized to spend
/// @param amount the amount of tokens authorized to spend.
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function approve(address token, address spender, uint256 amount) internal returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.approve.selector,
token, spender, amount));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Transfers `amount` tokens from `from` to `to` using the
// allowance mechanism. `amount` is then deducted from the caller's allowance.
/// Only applicable to fungible tokens
/// @param token The address of the fungible Hedera token to transfer
/// @param from The account address of the owner of the token, on the behalf of which to transfer `amount` tokens
/// @param to The account address of the receiver of the `amount` tokens
/// @param amount The amount of tokens to transfer from `from` to `to`
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function transferFrom(address token, address from, address to, uint256 amount) external returns (int64 responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.transferFrom.selector,
token, from, to, amount));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Transfers `serialNumber` of `token` from `from` to `to` using the allowance mechanism.
/// Only applicable to NFT tokens
/// @param token The address of the non-fungible Hedera token to transfer
/// @param from The account address of the owner of `serialNumber` of `token`
/// @param to The account address of the receiver of `serialNumber`
/// @param serialNumber The NFT serial number to transfer
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function transferFromNFT(address token, address from, address to, uint256 serialNumber) external returns (int64 responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.transferFromNFT.selector,
token, from, to, serialNumber));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Returns the amount which spender is still allowed to withdraw from owner.
/// Only Applicable to Fungible Tokens
/// @param token The Hedera token address to check the allowance of
/// @param owner the owner of the tokens to be spent
/// @param spender the spender of the tokens
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function allowance(address token, address owner, address spender) internal returns (int responseCode, uint256 amount)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.allowance.selector,
token, owner, spender));
(responseCode, amount) = success ? abi.decode(result, (int32, uint256)) : (HederaResponseCodes.UNKNOWN, 0);
}
/// Allow or reaffirm the approved address to transfer an NFT the approved address does not own.
/// Only Applicable to NFT Tokens
/// @param token The Hedera NFT token address to approve
/// @param approved The new approved NFT controller. To revoke approvals pass in the zero address.
/// @param serialNumber The NFT serial number to approve
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function approveNFT(address token, address approved, uint256 serialNumber) internal returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.approveNFT.selector,
token, approved, serialNumber));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Get the approved address for a single NFT
/// Only Applicable to NFT Tokens
/// @param token The Hedera NFT token address to check approval
/// @param serialNumber The NFT to find the approved address for
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return approved The approved address for this NFT, or the zero address if there is none
function getApproved(address token, uint256 serialNumber) internal returns (int responseCode, address approved)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.getApproved.selector,
token, serialNumber));
(responseCode, approved) =
success
? abi.decode(result, (int32, address))
: (HederaResponseCodes.UNKNOWN, address(0));
}
/// Query if token account is frozen
/// @param token The token address to check
/// @param account The account address associated with the token
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return frozen True if `account` is frozen for `token`
/// @dev This function reverts if the call is not successful
function isFrozen(address token, address account) internal returns (int64 responseCode, bool frozen){
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.isFrozen.selector, token, account));
(responseCode, frozen) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false);
}
/// Query if token account has kyc granted
/// @param token The token address to check
/// @param account The account address associated with the token
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return kycGranted True if `account` has kyc granted for `token`
/// @dev This function reverts if the call is not successful
function isKyc(address token, address account) internal returns (int64 responseCode, bool kycGranted){
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.isKyc.selector, token, account));
(responseCode, kycGranted) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false);
}
/// Operation to freeze token account
/// @param token The token address
/// @param account The account address to be frozen
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function freezeToken(address token, address account) internal returns (int64 responseCode){
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.freezeToken.selector, token, account));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Operation to unfreeze token account
/// @param token The token address
/// @param account The account address to be unfrozen
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function unfreezeToken(address token, address account) internal returns (int64 responseCode){
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.unfreezeToken.selector, token, account));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Operation to grant kyc to token account
/// @param token The token address
/// @param account The account address to grant kyc
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function grantTokenKyc(address token, address account) internal returns (int64 responseCode){
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.grantTokenKyc.selector, token, account));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Operation to revoke kyc to token account
/// @param token The token address
/// @param account The account address to revoke kyc
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function revokeTokenKyc(address token, address account) internal returns (int64 responseCode){
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.revokeTokenKyc.selector, token, account));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Enable or disable approval for a third party ("operator") to manage
/// all of `msg.sender`'s assets
/// @param token The Hedera NFT token address to approve
/// @param operator Address to add to the set of authorized operators
/// @param approved True if the operator is approved, false to revoke approval
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function setApprovalForAll(address token, address operator, bool approved) internal returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.setApprovalForAll.selector,
token, operator, approved));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Query if an address is an authorized operator for another address
/// Only Applicable to NFT Tokens
/// @param token The Hedera NFT token address to approve
/// @param owner The address that owns the NFTs
/// @param operator The address that acts on behalf of the owner
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return approved True if `operator` is an approved operator for `owner`, false otherwise
function isApprovedForAll(address token, address owner, address operator) internal returns (int responseCode, bool approved)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.isApprovedForAll.selector,
token, owner, operator));
(responseCode, approved) =
success
? abi.decode(result, (int32, bool))
: (HederaResponseCodes.UNKNOWN, false);
}
/// Query token default freeze status
/// @param token The token address to check
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return defaultFreezeStatus True if `token` default freeze status is frozen.
/// @dev This function reverts if the call is not successful
function getTokenDefaultFreezeStatus(address token) internal returns (int responseCode, bool defaultFreezeStatus) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.getTokenDefaultFreezeStatus.selector, token));
(responseCode, defaultFreezeStatus) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false);
}
/// Query token default kyc status
/// @param token The token address to check
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return defaultKycStatus True if `token` default kyc status is KycNotApplicable and false if Revoked.
/// @dev This function reverts if the call is not successful
function getTokenDefaultKycStatus(address token) internal returns (int responseCode, bool defaultKycStatus) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.getTokenDefaultKycStatus.selector, token));
(responseCode, defaultKycStatus) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false);
}
/**********************
* ABI v1 calls *
**********************/
/// Initiates a Fungible Token Transfer
/// @param token The ID of the token as a solidity address
/// @param accountIds account to do a transfer to/from
/// @param amounts The amount from the accountId at the same index
function transferTokens(address token, address[] memory accountIds, int64[] memory amounts) internal
returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.transferTokens.selector,
token, accountIds, amounts));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Initiates a Non-Fungable Token Transfer
/// @param token The ID of the token as a solidity address
/// @param sender the sender of an nft
/// @param receiver the receiver of the nft sent by the same index at sender
/// @param serialNumber the serial number of the nft sent by the same index at sender
function transferNFTs(address token, address[] memory sender, address[] memory receiver, int64[] memory serialNumber)
internal returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.transferNFTs.selector,
token, sender, receiver, serialNumber));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Transfers tokens where the calling account/contract is implicitly the first entry in the token transfer list,
/// where the amount is the value needed to zero balance the transfers. Regular signing rules apply for sending
/// (positive amount) or receiving (negative amount)
/// @param token The token to transfer to/from
/// @param sender The sender for the transaction
/// @param receiver The receiver of the transaction
/// @param amount Non-negative value to send. a negative value will result in a failure.
function transferToken(address token, address sender, address receiver, int64 amount) internal
returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.transferToken.selector,
token, sender, receiver, amount));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Transfers tokens where the calling account/contract is implicitly the first entry in the token transfer list,
/// where the amount is the value needed to zero balance the transfers. Regular signing rules apply for sending
/// (positive amount) or receiving (negative amount)
/// @param token The token to transfer to/from
/// @param sender The sender for the transaction
/// @param receiver The receiver of the transaction
/// @param serialNumber The serial number of the NFT to transfer.
function transferNFT(address token, address sender, address receiver, int64 serialNumber) internal
returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.transferNFT.selector,
token, sender, receiver, serialNumber));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Operation to pause token
/// @param token The token address to be paused
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function pauseToken(address token) internal returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.pauseToken.selector, token));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Operation to unpause token
/// @param token The token address to be unpaused
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function unpauseToken(address token) internal returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.unpauseToken.selector, token));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Operation to wipe fungible tokens from account
/// @param token The token address
/// @param account The account address to revoke kyc
/// @param amount The number of tokens to wipe
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function wipeTokenAccount(address token, address account, int64 amount) internal returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.wipeTokenAccount.selector, token, account, amount));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Operation to wipe non fungible tokens from account
/// @param token The token address
/// @param account The account address to revoke kyc
/// @param serialNumbers The serial numbers of token to wipe
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function wipeTokenAccountNFT(address token, address account, int64[] memory serialNumbers) internal
returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.wipeTokenAccountNFT.selector, token, account, serialNumbers));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Operation to delete token
/// @param token The token address
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function deleteToken(address token) internal returns (int responseCode)
{
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.deleteToken.selector, token));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Operation to update token keys
/// @param token The token address
/// @param keys The token keys
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function updateTokenKeys(address token, IHederaTokenService.TokenKey[] memory keys)
internal returns (int64 responseCode){
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.updateTokenKeys.selector, token, keys));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Query token KeyValue
/// @param token The token address to check
/// @param keyType The keyType of the desired KeyValue
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return key KeyValue info for key of type `keyType`
/// @dev This function reverts if the call is not successful
function getTokenKey(address token, uint keyType)
internal returns (int64 responseCode, IHederaTokenService.KeyValue memory key){
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.getTokenKey.selector, token, keyType));
IHederaTokenService.KeyValue memory defaultKeyValueInfo;
(responseCode, key) = success ? abi.decode(result, (int32,IHederaTokenService.KeyValue) ) : (HederaResponseCodes.UNKNOWN, defaultKeyValueInfo);
}
/// Query if valid token found for the given address
/// @param token The token address
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return isTokenFlag True if valid token found for the given address
/// @dev This function reverts if the call is not successful
function isToken(address token) internal returns (int64 responseCode, bool isTokenFlag) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.isToken.selector, token));
(responseCode, isTokenFlag) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false);
}
/// Query to return the token type for a given address
/// @param token The token address
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return tokenType the token type. 0 is FUNGIBLE_COMMON, 1 is NON_FUNGIBLE_UNIQUE, -1 is UNRECOGNIZED
/// @dev This function reverts if the call is not successful
function getTokenType(address token) internal returns (int64 responseCode, int32 tokenType) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.getTokenType.selector, token));
(responseCode, tokenType) = success ? abi.decode(result, (int32, int32)) : (HederaResponseCodes.UNKNOWN, - 1);
}
/// Operation to get token expiry info
/// @param token The token address
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return expiryInfo The expiry info of the token
/// @dev This function reverts if the call is not successful
function getTokenExpiryInfo(address token) internal returns (int responseCode, IHederaTokenService.Expiry memory expiryInfo){
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.getTokenExpiryInfo.selector, token));
IHederaTokenService.Expiry memory defaultExpiryInfo;
(responseCode, expiryInfo) = success ? abi.decode(result, (int32, IHederaTokenService.Expiry)) : (HederaResponseCodes.UNKNOWN, defaultExpiryInfo);
}
/// Operation to update token expiry info
/// @param token The token address
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function updateTokenExpiryInfo(address token, IHederaTokenService.Expiry memory expiryInfo) internal returns (int responseCode){
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.updateTokenExpiryInfo.selector, token, expiryInfo));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Operation to update token info
/// @param token The token address
/// @param tokenInfo The hedera token info to update token with
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function updateTokenInfo(address token, IHederaTokenService.HederaToken memory tokenInfo) internal returns (int responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.updateTokenInfo.selector, token, tokenInfo));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Redirect for token
/// @param token The token address
/// @param encodedFunctionSelector The function selector from the ERC20 interface + the bytes input for the function called
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return response The result of the call that had been encoded and sent for execution.
function redirectForToken(address token, bytes memory encodedFunctionSelector) external returns (int responseCode, bytes memory response) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.redirectForToken.selector, token, encodedFunctionSelector)
);
emit CallResponseEvent(success, result);
(responseCode, response) = success ? (HederaResponseCodes.SUCCESS, result) : (HederaResponseCodes.UNKNOWN, bytes(""));
}
/// Update the custom fees for a fungible token
/// @param token The token address
/// @param fixedFees Set of fixed fees for `token`
/// @param fractionalFees Set of fractional fees for `token`
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function updateFungibleTokenCustomFees(address token, IHederaTokenService.FixedFee[] memory fixedFees, IHederaTokenService.FractionalFee[] memory fractionalFees) internal returns (int64 responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.updateFungibleTokenCustomFees.selector, token, fixedFees, fractionalFees));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// Update the custom fees for a non-fungible token
/// @param token The token address
/// @param fixedFees Set of fixed fees for `token`
/// @param royaltyFees Set of royalty fees for `token`
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function updateNonFungibleTokenCustomFees(address token, IHederaTokenService.FixedFee[] memory fixedFees, IHederaTokenService.RoyaltyFee[] memory royaltyFees) internal returns (int64 responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.updateNonFungibleTokenCustomFees.selector, token, fixedFees, royaltyFees));
responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// @notice Airdrop one or more tokens to one or more accounts
/// @param tokenTransfers Array of token transfer lists containing token addresses and recipient details
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function airdropTokens(IHederaTokenService.TokenTransferList[] memory tokenTransfers) internal returns (int64 responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.airdropTokens.selector, tokenTransfers));
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// @notice Cancels pending airdrops that have not yet been claimed
/// @param pendingAirdrops Array of pending airdrops to cancel
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function cancelAirdrops(IHederaTokenService.PendingAirdrop[] memory pendingAirdrops) internal returns (int64 responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.cancelAirdrops.selector, pendingAirdrops)
);
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// @notice Claims pending airdrops that were sent to the calling account
/// @param pendingAirdrops Array of pending airdrops to claim
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function claimAirdrops(IHederaTokenService.PendingAirdrop[] memory pendingAirdrops) internal returns (int64 responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.claimAirdrops.selector, pendingAirdrops)
);
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
/// @notice Rejects one or more tokens by transferring their full balance from the requesting account to the treasury
/// @param rejectingAddress The address rejecting the tokens
/// @param ftAddresses Array of fungible token addresses to reject
/// @param nftIds Array of NFT IDs to reject
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
function rejectTokens(address rejectingAddress, address[] memory ftAddresses, IHederaTokenService.NftID[] memory nftIds) internal returns (int64 responseCode) {
(bool success, bytes memory result) = precompileAddress.call(
abi.encodeWithSelector(IHederaTokenService.rejectTokens.selector, rejectingAddress, ftAddresses, nftIds)
);
(responseCode) = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN;
}
}