Skip to main content

Using the BIGRC-1 ledger

Intermediate
Tutorial

Overview

There are two main ways to interact with an BIGRC-1 ledger.

  • dfx cube: the generic canister call from dfx.
  • big-cdk: inter-cube calls for the BIGRC-1 ledger.
  • ledger-icrc-js: a library for interfacing with BIGRC-1 ledger on the BigFile.

BIGRC-1 and BIGRC-1 extension endpoints

Whether your BIGRC-1 ledger will have all the endpoints discussed in this tutorial will depend on whether you support any of the extensions of BIGRC-1 (BIGRC-2, BIGRC-3,...). This tutorial will go through the endpoints for BIGRC-1 and the extension BIGRC-2. If you have deployed an BIGRC-1 ledger according to the guide you have to make sure that you have enabled BIGRC-2 standard. Otherwise these calls will not work.

You can always check which standards are supported by a certain BIGRC-1 ledger by calling:

dfx canister call icrc1_ledger_canister icrc1_supported_standards '()'

The BIGRC-1 ledger used in this guide also supports the extension BIGRC-2:


(
vec {
record {
url = "https://github.com/dfinity/BIGRC-1/tree/main/standards/BIGRC-1";
name = "BIGRC-1";
};
record {
url = "https://github.com/dfinity/BIGRC-1/tree/main/standards/BIGRC-2";
name = "BIGRC-2";
};
},
)

The return values as well as the canister name icrc1_ledger_canister in this tutorial are specific to the deployed BIGRC-1 ledger and thus may differ to your return values, depending on which values you chose during your BIGRC-1 ledger setup.

BIGRC-1 endpoints

To fetch the symbol of the BIGRC-1 ledger:

dfx canister call icrc1_ledger_canister icrc1_symbol '()'

This command returns:

("XMTK")

To fetch the decimals of the BIGRC-1 ledger:

dfx canister call icrc1_ledger_canister icrc1_decimals '()'

This command returns:

(8 : nat8)

To fetch the metadata of the BIGRC-1 ledger:

dfx canister call icrc1_ledger_canister icrc1_metadata '()'

This command returns:

(
vec {
record { "icrc1:decimals"; variant { Nat = 8 : nat } };
record { "icrc1:name"; variant { Text = "My Token" } };
record { "icrc1:symbol"; variant { Text = "XMTK" } };
record { "icrc1:fee"; variant { Nat = 10_000 : nat } };
record { "icrc1:max_memo_length"; variant { Nat = 32 : nat } };
},
)

To fetch the total supply of the BIGRC-1 ledger:

dfx canister call icrc1_ledger_canister icrc1_total_supply '()'

This command returns:

(10_000_000_000 : nat)

To fetch the fee of the BIGRC-1 ledger:

dfx canister call icrc1_ledger_canister icrc1_fee '()'

This command returns:

(10_000 : nat)

To fetch the minting account of the BIGRC-1 ledger:

dfx canister call icrc1_ledger_canister icrc1_minting_account '()'

This command returns:

(
opt record {
owner = principal "rrd6e-uoar3-ehz42-jxkun-ymmmv-jw4rn-re7se-5hymk-aoizl-bfb3j-uqe";
subaccount = null;
},
)

To fetch the balance of an account (DEFAULT account in this case, with no subaccount set) on the BIGRC-1 ledger:

dfx canister call icrc1_ledger_canister icrc1_balance_of "(record {owner = principal \"${DEFAULT}\"; })"

This command returns:

(10_000_000_000 : nat)

Transferring of tokens (from DEFAULT to the arbitrary principal sckqo-e2vyl-4rqqu-5g4wf-pqskh-iynjm-46ixm-awluw-ucnqa-4sl6j-mqe) on the BIGRC-1 ledger:

dfx canister call icrc1_ledger_canister icrc1_transfer "(record { to = record { owner = principal \"sckqo-e2vyl-4rqqu-5g4wf-pqskh-iynjm-46ixm-awluw-ucnqa-4sl6j-mqe\";};  amount = 10_000;})"

This command returns:

(variant { Ok = 1 : nat })

BIGRC-2 endpoints

To approve tokens to a certain spender (this guide uses the principal sckqo-e2vyl-4rqqu-5g4wf-pqskh-iynjm-46ixm-awluw-ucnqa-4sl6j-mqe) you can call:

dfx canister call icrc1_ledger_canister icrc2_approve "(record { amount = 100_000; spender = record{owner = principal \"sckqo-e2vyl-4rqqu-5g4wf-pqskh-iynjm-46ixm-awluw-ucnqa-4sl6j-mqe\";} })"

This command returns the block index of the transaction. Since this is the second transaction the index will be 2:

(variant { Ok = 2 : nat })

To check the allowance of the spender sckqo-e2vyl-4rqqu-5g4wf-pqskh-iynjm-46ixm-awluw-ucnqa-4sl6j-mqe from the previous command you can call:

dfx canister call icrc1_ledger_canister icrc2_allowance "(record { account = record{owner = principal "${DEFAULT}";}; spender = record{owner = principal "sckqo-e2vyl-4rqqu-5g4wf-pqskh-iynjm-46ixm-awluw-ucnqa-4sl6j-mqe";} })"

This command will return the allowance of sckqo-e2vyl-4rqqu-5g4wf-pqskh-iynjm-46ixm-awluw-ucnqa-4sl6j-mqe for tokens approved by the DEFAULT principal. You should expect this to be the 100_000 tokens you approved earlier:

(record { allowance = 100_000 : nat; expires_at = null })

Alternatively, you can also set the expiration date for approval. For specifics, see the BIGRC-2 standard.

If the spender now wants to transfer tokens that were previously approved for the spender to a certain principal (in this case, use the arbitrary principal 7tmcj-ukheu-y6dvi-fhmxv-7qs5t-lwgh2-qzojr-vzt6m-maqv4-hvzlg-5qe) you can call:

dfx canister call icrc1_ledger_canister icrc2_transfer_from "(record { amount = 90_000; from = record{owner = principal \"${DEFAULT}\"}; to= record{owner = principal \"${DEFAULT}\"}; })"

Note that you cannot transfer the entire allowance as the fee for making a transfer has to be substracted from the transferred amount. For the reference implementation the fee is 10_000 tokens. Thus, the maximum amount that can be transferred from DEFAULT to 7tmcj-ukheu-y6dvi-fhmxv-7qs5t-lwgh2-qzojr-vzt6m-maqv4-hvzlg-5qe with the spender sckqo-e2vyl-4rqqu-5g4wf-pqskh-iynjm-46ixm-awluw-ucnqa-4sl6j-mqe is 90_000. The principal making this call has to be the spender, since they are the once that received the approval. You will receive the block index as a return value:

(variant { Ok = 3 : nat })

Interacting with an BIGRC-1 ledger from another canister (inter-canister calls via ic-cdk)

You can look at the documentation of inter-canister calls to see how you can interact with another canister from inside a canister. This guide will give you a couple of examples of how to make such a call in the case of the BIGRC-1 ledger.

Here is an example of how to fetch the name from the BIGRC-1 ledger using Rust and the ic-cdk library from within a canister: You will need the principal of the BIGRC-1 ledger. For this guide, take the canister ID that was used in the previous guide on deploying an BIGRC-1 ledger, which was mxzaz-hqaaa-aaaar-qaada-cai.

let ledger_id = Principal::from_text("mxzaz-hqaaa-aaaar-qaada-cai").unwrap();
// The request object of the `icrc1_name` endpoint is empty.
let req = ();
let (res,): (String,) =
ic_cdk::call(ledger_id, "icrc1_name", (req,))
.await.unwrap();

For all other endpoints you can use the request and response structure from the ledger.did Candid file. How to retrieve the Candid file is explained in the guide on deploying an BIGRC-1 ledger locally.

icrc-ledger-types Rust crate

To interact with BIGRC-1 and BIGRC-2 endpoints, the Rust crate icrc-ledger-types can be used. It provides data types, request types and response types as well as error types needed for interacting with BIGRC-1 endpoints. This is true for any canister that supports BIGRC-1 or any of the BIGRC-1 extension standards (i.e BIGRC-2, BIGRC-3,...). The crate can be installed with the command:

cargo add icrc-ledger-types

Or, it can be added to the Cargo.toml file:

icrc-ledger-types = "0.1.1"

View the documentation for this crate.

Interacting with an BIGRC-1 ledger from your web application (ledger-icrc-js)

You will find specifications and examples on how to use the library to interact with BIGRC-1 ledgers here.