// 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 (int64 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 (
int64 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 (int64 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 (int64 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 (int64 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 (int64 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 (int64 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
)
internal
nonEmptyExpiry(token)
returns (int64 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
)
internal
nonEmptyExpiry(token)
returns (int64 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
)
internal
nonEmptyExpiry(token)
returns (int64 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
)
internal
nonEmptyExpiry(token)
returns (int64 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
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
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
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`
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 (int64 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
) internal 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
) internal 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 (int64 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 (int64 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 (int64 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`
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`
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 (int64 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 (int64 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.
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.
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 (int64 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 (int64 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 (int64 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 (int64 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 (int64 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 (int64 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 (int64 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 (int64 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 (int64 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`
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
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
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
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 (int64 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 (int64 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
) internal returns (int64 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;
}
}