// This is the official Ledger interface that is guaranteed to be backward compatible. // Amount of tokens, measured in 10^-8 of a token. type Tokens = record { e8s : nat64 }; // Number of nanoseconds from the UNIX epoch in UTC timezone. type TimeStamp = record { timestamp_nanos : nat64 }; // AccountIdentifier is a 32-byte array. // The first 4 bytes is big-endian encoding of a CRC32 checksum of the last 28 bytes. type AccountIdentifier = blob; // Subaccount is an arbitrary 32-byte byte array. // Ledger uses subaccounts to compute the source address, which enables one // principal to control multiple ledger accounts. type SubAccount = blob; // Sequence number of a block produced by the ledger. type BlockIndex = nat64; type Transaction = record { memo : Memo; icrc1_memo : opt blob; operation : opt Operation; created_at_time : TimeStamp }; // An arbitrary number associated with a transaction. // The caller can set it in a `transfer` call as a correlation identifier. type Memo = nat64; // Arguments for the `transfer` call. type TransferArgs = record { // Transaction memo. // See comments for the `Memo` type. memo : Memo; // The amount that the caller wants to transfer to the destination address. amount : Tokens; // The amount that the caller pays for the transaction. // Must be 10000 e8s. fee : Tokens; // The subaccount from which the caller wants to transfer funds. // If null, the ledger uses the default (all zeros) subaccount to compute the source address. // See comments for the `SubAccount` type. from_subaccount : opt SubAccount; // The destination account. // If the transfer is successful, the balance of this address increases by `amount`. to : AccountIdentifier; // The point in time when the caller created this request. // If null, the ledger uses current IC time as the timestamp. created_at_time : opt TimeStamp }; type TransferError = variant { // The fee that the caller specified in the transfer request was not the one that ledger expects. // The caller can change the transfer fee to the `expected_fee` and retry the request. BadFee : record { expected_fee : Tokens }; // The account specified by the caller doesn't have enough funds. InsufficientFunds : record { balance : Tokens }; // The request is too old. // The ledger only accepts requests created within 24 hours window. // This is a non-recoverable error. TxTooOld : record { allowed_window_nanos : nat64 }; // The caller specified `created_at_time` that is too far in future. // The caller can retry the request later. TxCreatedInFuture : null; // The ledger has already executed the request. // `duplicate_of` field is equal to the index of the block containing the original transaction. TxDuplicate : record { duplicate_of : BlockIndex } }; type TransferResult = variant { Ok : BlockIndex; Err : TransferError }; // Arguments for the `account_balance` call. type AccountBalanceArgs = record { account : AccountIdentifier }; type TransferFeeArg = record {}; type TransferFee = record { // The fee to pay to perform a transfer transfer_fee : Tokens }; type GetBlocksArgs = record { // The index of the first block to fetch. start : BlockIndex; // Max number of blocks to fetch. length : nat64 }; type Operation = variant { Mint : record { to : AccountIdentifier; amount : Tokens }; Burn : record { from : AccountIdentifier; spender : opt AccountIdentifier; amount : Tokens }; Transfer : record { from : AccountIdentifier; to : AccountIdentifier; amount : Tokens; fee : Tokens; spender : opt vec nat8 }; Approve : record { from : AccountIdentifier; spender : AccountIdentifier; // This field is deprecated and should not be used. allowance_e8s : int; allowance : Tokens; fee : Tokens; expires_at : opt TimeStamp; expected_allowance : opt Tokens } }; type Block = record { parent_hash : opt blob; transaction : Transaction; timestamp : TimeStamp }; // A prefix of the block range specified in the [GetBlocksArgs] request. type BlockRange = record { // A prefix of the requested block range. // The index of the first block is equal to [GetBlocksArgs.from]. // // Note that the number of blocks might be less than the requested // [GetBlocksArgs.len] for various reasons, for example: // // 1. The query might have hit the replica with an outdated state // that doesn't have the full block range yet. // 2. The requested range is too large to fit into a single reply. // // NOTE: the list of blocks can be empty if: // 1. [GetBlocksArgs.len] was zero. // 2. [GetBlocksArgs.from] was larger than the last block known to the canister. blocks : vec Block }; // An error indicating that the arguments passed to [QueryArchiveFn] were invalid. type QueryArchiveError = variant { // [GetBlocksArgs.from] argument was smaller than the first block // served by the canister that received the request. BadFirstBlockIndex : record { requested_index : BlockIndex; first_valid_index : BlockIndex }; // Reserved for future use. Other : record { error_code : nat64; error_message : text } }; type QueryArchiveResult = variant { // Successfully fetched zero or more blocks. Ok : BlockRange; // The [GetBlocksArgs] request was invalid. Err : QueryArchiveError }; // A function that is used for fetching archived ledger blocks. type QueryArchiveFn = func(GetBlocksArgs) -> (QueryArchiveResult) query; // The result of a "query_blocks" call. // // The structure of the result is somewhat complicated because the main ledger canister might // not have all the blocks that the caller requested: One or more "archive" canisters might // store some of the requested blocks. // // Note: as of Q4 2021 when this interface is authored, the IC doesn't support making nested // query calls within a query call. type QueryBlocksResponse = record { // The total number of blocks in the chain. // If the chain length is positive, the index of the last block is `chain_len - 1`. chain_length : nat64; // System certificate for the hash of the latest block in the chain. // Only present if `query_blocks` is called in a non-replicated query context. certificate : opt blob; // List of blocks that were available in the ledger when it processed the call. // // The blocks form a contiguous range, with the first block having index // [first_block_index] (see below), and the last block having index // [first_block_index] + len(blocks) - 1. // // The block range can be an arbitrary sub-range of the originally requested range. blocks : vec Block; // The index of the first block in "blocks". // If the blocks vector is empty, the exact value of this field is not specified. first_block_index : BlockIndex; // Encoding of instructions for fetching archived blocks whose indices fall into the // requested range. // // For each entry `e` in [archived_blocks], `[e.from, e.from + len)` is a sub-range // of the originally requested block range. archived_blocks : vec ArchivedBlocksRange }; type ArchivedBlocksRange = record { // The index of the first archived block that can be fetched using the callback. start : BlockIndex; // The number of blocks that can be fetch using the callback. length : nat64; // The function that should be called to fetch the archived blocks. // The range of the blocks accessible using this function is given by [from] // and [len] fields above. callback : QueryArchiveFn }; type ArchivedEncodedBlocksRange = record { callback : func(GetBlocksArgs) -> ( variant { Ok : vec blob; Err : QueryArchiveError } ) query; start : nat64; length : nat64 }; type QueryEncodedBlocksResponse = record { certificate : opt blob; blocks : vec blob; chain_length : nat64; first_block_index : nat64; archived_blocks : vec ArchivedEncodedBlocksRange }; type Archive = record { canister_id : principal }; type Archives = record { archives : vec Archive }; type Duration = record { secs : nat64; nanos : nat32 }; type ArchiveOptions = record { trigger_threshold : nat64; num_blocks_to_archive : nat64; node_max_memory_size_bytes : opt nat64; max_message_size_bytes : opt nat64; controller_id : principal; more_controller_ids : opt vec principal; cycles_for_archive_creation : opt nat64; max_transactions_per_response : opt nat64 }; // Account identifier encoded as a 64-byte ASCII hex string. type TextAccountIdentifier = text; // Arguments for the `send_dfx` call. type SendArgs = record { memo : Memo; amount : Tokens; fee : Tokens; from_subaccount : opt SubAccount; to : TextAccountIdentifier; created_at_time : opt TimeStamp }; type AccountBalanceArgsDfx = record { account : TextAccountIdentifier }; type FeatureFlags = record { icrc2 : bool }; type InitArgs = record { minting_account : TextAccountIdentifier; icrc1_minting_account : opt Account; initial_values : vec record { TextAccountIdentifier; Tokens }; max_message_size_bytes : opt nat64; transaction_window : opt Duration; archive_options : opt ArchiveOptions; send_whitelist : vec principal; transfer_fee : opt Tokens; token_symbol : opt text; token_name : opt text; feature_flags : opt FeatureFlags }; type Icrc1BlockIndex = nat; // Number of nanoseconds since the UNIX epoch in UTC timezone. type Icrc1Timestamp = nat64; type Icrc1Tokens = nat; type Account = record { owner : principal; subaccount : opt SubAccount }; type TransferArg = record { from_subaccount : opt SubAccount; to : Account; amount : Icrc1Tokens; fee : opt Icrc1Tokens; memo : opt blob; created_at_time : opt Icrc1Timestamp }; type Icrc1TransferError = variant { BadFee : record { expected_fee : Icrc1Tokens }; BadBurn : record { min_burn_amount : Icrc1Tokens }; InsufficientFunds : record { balance : Icrc1Tokens }; TooOld; CreatedInFuture : record { ledger_time : nat64 }; TemporarilyUnavailable; Duplicate : record { duplicate_of : Icrc1BlockIndex }; GenericError : record { error_code : nat; message : text } }; type Icrc1TransferResult = variant { Ok : Icrc1BlockIndex; Err : Icrc1TransferError }; // The value returned from the [icrc1_metadata] endpoint. type Value = variant { Nat : nat; Int : int; Text : text; Blob : blob }; type ChangeArchiveOptions = record { trigger_threshold : opt nat64; num_blocks_to_archive : opt nat64; node_max_memory_size_bytes : opt nat64; max_message_size_bytes : opt nat64; controller_id : opt principal; more_controller_ids : opt vec principal; cycles_for_archive_creation : opt nat64; max_transactions_per_response : opt nat64 }; type UpgradeArgs = record { icrc1_minting_account : opt Account; feature_flags : opt FeatureFlags; change_archive_options : opt ChangeArchiveOptions }; type LedgerCanisterPayload = variant { Init : InitArgs; Upgrade : opt UpgradeArgs }; type ApproveArgs = record { from_subaccount : opt SubAccount; spender : Account; amount : Icrc1Tokens; expected_allowance : opt Icrc1Tokens; expires_at : opt Icrc1Timestamp; fee : opt Icrc1Tokens; memo : opt blob; created_at_time : opt Icrc1Timestamp }; type ApproveError = variant { BadFee : record { expected_fee : Icrc1Tokens }; InsufficientFunds : record { balance : Icrc1Tokens }; AllowanceChanged : record { current_allowance : Icrc1Tokens }; Expired : record { ledger_time : nat64 }; TooOld; CreatedInFuture : record { ledger_time : nat64 }; Duplicate : record { duplicate_of : Icrc1BlockIndex }; TemporarilyUnavailable; GenericError : record { error_code : nat; message : text } }; type ApproveResult = variant { Ok : Icrc1BlockIndex; Err : ApproveError }; type AllowanceArgs = record { account : Account; spender : Account }; type Allowance = record { allowance : Icrc1Tokens; expires_at : opt Icrc1Timestamp }; type TransferFromArgs = record { spender_subaccount : opt SubAccount; from : Account; to : Account; amount : Icrc1Tokens; fee : opt Icrc1Tokens; memo : opt blob; created_at_time : opt Icrc1Timestamp }; type TransferFromResult = variant { Ok : Icrc1BlockIndex; Err : TransferFromError }; type TransferFromError = variant { BadFee : record { expected_fee : Icrc1Tokens }; BadBurn : record { min_burn_amount : Icrc1Tokens }; InsufficientFunds : record { balance : Icrc1Tokens }; InsufficientAllowance : record { allowance : Icrc1Tokens }; TooOld; CreatedInFuture : record { ledger_time : Icrc1Timestamp }; Duplicate : record { duplicate_of : Icrc1BlockIndex }; TemporarilyUnavailable; GenericError : record { error_code : nat; message : text } }; type icrc21_consent_message_metadata = record { language : text; utc_offset_minutes : opt int16 }; type icrc21_consent_message_spec = record { metadata : icrc21_consent_message_metadata; device_spec : opt variant { GenericDisplay; FieldsDisplay } }; type icrc21_consent_message_request = record { method : text; arg : blob; user_preferences : icrc21_consent_message_spec }; type Icrc21Value = variant { TokenAmount : record { decimals : nat8; amount : nat64; symbol : text }; TimestampSeconds : record { amount : nat64 }; DurationSeconds : record { amount : nat64 }; Text : record { content : text } }; type FieldsDisplay = record { intent : text; fields : vec record { text; Icrc21Value } }; type icrc21_consent_message = variant { GenericDisplayMessage : text; FieldsDisplayMessage : FieldsDisplay }; type icrc21_consent_info = record { consent_message : icrc21_consent_message; metadata : icrc21_consent_message_metadata }; type icrc21_error_info = record { description : text }; type icrc21_error = variant { UnsupportedCanisterCall : icrc21_error_info; ConsentMessageUnavailable : icrc21_error_info; InsufficientPayment : icrc21_error_info; // Any error not covered by the above variants. GenericError : record { error_code : nat; description : text } }; type icrc21_consent_message_response = variant { Ok : icrc21_consent_info; Err : icrc21_error }; // The arguments for the `get_allowances` endpoint. // The `prev_spender_id` argument can be used for pagination. If specified // the endpoint returns allowances that are lexicographically greater than // (`from_account_id`, `prev_spender_id`) - start with spender after `prev_spender_id`. type GetAllowancesArgs = record { from_account_id : TextAccountIdentifier; prev_spender_id : opt TextAccountIdentifier; take : opt nat64 }; // The allowances returned by the `get_allowances` endpoint. type Allowances = vec record { from_account_id : TextAccountIdentifier; to_spender_id : TextAccountIdentifier; allowance : Tokens; expires_at : opt nat64 }; type TipOfChainRes = record { certification : opt blob; tip_index : BlockIndex }; type RemoveApprovalArgs = record { from_subaccount : opt SubAccount; spender : AccountIdentifier; fee : opt Icrc1Tokens }; service : (LedgerCanisterPayload) -> { // Transfers tokens from a subaccount of the caller to the destination address. // The source address is computed from the principal of the caller and the specified subaccount. // When successful, returns the index of the block containing the transaction. transfer : (TransferArgs) -> (TransferResult); // Returns the amount of Tokens on the specified account. account_balance : (AccountBalanceArgs) -> (Tokens) query; // Returns the account identifier for the given Principal and subaccount. account_identifier : (Account) -> (AccountIdentifier) query; // Returns the current transfer_fee. transfer_fee : (TransferFeeArg) -> (TransferFee) query; // Queries blocks in the specified range. query_blocks : (GetBlocksArgs) -> (QueryBlocksResponse) query; // Queries encoded blocks in the specified range query_encoded_blocks : (GetBlocksArgs) -> (QueryEncodedBlocksResponse) query; // Returns token symbol. symbol : () -> (record { symbol : text }) query; // Returns token name. name : () -> (record { name : text }) query; // Returns token decimals. decimals : () -> (record { decimals : nat32 }) query; // Returns the existing archive canisters information. archives : () -> (Archives) query; send_dfx : (SendArgs) -> (BlockIndex); account_balance_dfx : (AccountBalanceArgsDfx) -> (Tokens) query; // The following methods implement the ICRC-1 Token Standard. // https://github.com/dfinity/ICRC-1/tree/main/standards/ICRC-1 icrc1_name : () -> (text) query; icrc1_symbol : () -> (text) query; icrc1_decimals : () -> (nat8) query; icrc1_metadata : () -> (vec record { text; Value }) query; icrc1_total_supply : () -> (Icrc1Tokens) query; icrc1_fee : () -> (Icrc1Tokens) query; icrc1_minting_account : () -> (opt Account) query; icrc1_balance_of : (Account) -> (Icrc1Tokens) query; icrc1_transfer : (TransferArg) -> (Icrc1TransferResult); icrc1_supported_standards : () -> (vec record { name : text; url : text }) query; icrc2_approve : (ApproveArgs) -> (ApproveResult); icrc2_allowance : (AllowanceArgs) -> (Allowance) query; icrc2_transfer_from : (TransferFromArgs) -> (TransferFromResult); remove_approval : (RemoveApprovalArgs) -> (ApproveResult); icrc21_canister_call_consent_message : (icrc21_consent_message_request) -> (icrc21_consent_message_response); icrc10_supported_standards : () -> (vec record { name : text; url : text }) query; get_allowances : (GetAllowancesArgs) -> (Allowances) query; tip_of_chain : () -> (TipOfChainRes) query; is_ledger_ready : () -> (bool) query }