// 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; amount : Tokens; }; Transfer : record { from : AccountIdentifier; to : AccountIdentifier; amount : Tokens; fee : Tokens; }; Approve : record { from : AccountIdentifier; spender : AccountIdentifier; allowance_e8s : int; fee : Tokens; expires_at : opt TimeStamp; }; TransferFrom : record { from : AccountIdentifier; to : AccountIdentifier; spender : AccountIdentifier; amount : Tokens; fee : 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 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 Archive = record { canister_id: principal; }; type Archives = record { archives: vec Archive; }; service : { // 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 current transfer_fee. transfer_fee : (TransferFeeArg) -> (TransferFee) query; // Queries blocks in the specified range. query_blocks : (GetBlocksArgs) -> (QueryBlocksResponse) 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; }