Integrating with the Internet Computer ledger

Airgapped approach is not available for the option?

a. Standard messages via canister’s interface : Despite its big-sounding name, the Ledger Canister is just another canister so any one person or canister can interact with it by sending it messages using the canister’s interface. This is how we expect most people will interact with it as it is very lightweight. This interface is NOT in the docs (yet) — we are updating it soon.

So, it looks like I’ve figured it out myself. There are two main advantages of Dfinity’s approach over ERCs. And I think one could find more.

  1. Onchain ledger frees us from writing other offchain tools to analyze this ledger. With ERCs it is not possible to access transaction history onchain.

  2. Separate method to reference some transaction lets you split send and call parts in time. It’s easy to imagine some “airdrop based on previous activity” usecase with this approach.


I would be interested on how to call ledger methods inside a canister.
The thing I would like to do is to create a wallet(private key) inside a canister and afterwards send some coins to another wallet via the ledger.


Just wanted to say I really appreciate your explanation style… so helpful and conscientious. A rarity in technical spaces. Thanks so much. Onward and Upward.

1 Like

Thank you so very much!

Hi, were you able to fix this?

has the documentation for interacting with the ledger canister via a standard message from another canister been updated and released yet?

Good question, let me ping the team and find out.

Hi Jesse, not yet – we’re in the process of doing this

1 Like

ok. do you have an approximate date when the documentation might be released?

We develop the documentation in conjunction with the new Candid interface, which in turn is somewhat aligned with the “Canisters can transfer ICP” feature. This makes it a bit hard to estimate, but I would say 2 - 3 weeks.


Is the create-canister functions of the ledger going to be a part of the new public candid interface? is it going to change, and if it will change, will there be the documentation for it?

The ledger itself does not have a create-canister function, per se. Perhaps you may be referring to the method notify() which can be used to create canisters. Our plans are to modify/replace that method so I think that this replacement will not be immediately (if at all) available as part of the candid interface.

Got it, thanks. Yes I meant the functionality. Can it be public what the plans are for the change?

just following up on this. I was looking for the documentation of interacting with the ledger canister via canister calls, and wasn’t quite able to find anything.

Hi @Jesse!

Here is the current public interface of the Ledger canister: ic/ledger.did at 09af55f2e9975aa19ea8fb5136d8b245d6d0e003 · dfinity/ic · GitHub

Ledger canister id: ryjl3-tyaaa-aaaaa-aaaba-cai

Instructions how to setup ledger locally for testing: ic/rs/rosetta-api/ledger_canister at master · dfinity/ic · GitHub

If you use Rust, you might find this library helpful: ic_ledger_types - Rust

Examples of canisters in Rust and Motoko talking to the Ledger:

Community conversation talk explaining how you could implement payments on top of transfers:

Please let me know if you have questions that aren’t answered by this documentation!


Thank you! I’ve taken some time to look over the examples you gave me. I have one question so far, how do i get a canister to be able to receive ICP? is it as simple as going into my wallet and sending ICP to the canister’s wallet address? if so, how do i get the canister’s wallet address?

I’m learning this now! It’s a little non-trivial, although it is covered in the examples Roman provided.

You can get an account-identifier by hashing the principal of the canister together with a “subaccount” which can be pretty much any other value converted into a blob. Any account-identifier that starts with your canister’s principal can be controlled by your canister.

You’ll need to convert it into a string, for people to send money to it, though.

Because this isn’t very easy to drop into an existing app, I’m building an invoice canister that will simplify the experience for a lot of use cases. Payments - Invoice Canister Design Review. With the invoice, you’ll be able to run a simple query to find out your default account-identifier to transfer into, and you’ll be able to make an invoice for an amount to be paid, and easily check whether the payment has been satisfied


Yep, transfer to a canister is regular ledger transfer.

I’d say the easiest way to figure out the canister account identifier is to add a query endpoint that returns it: examples/ at 85e31a49a8f9ac095ac8eda4a1dc3613d4a4e77d · dfinity/examples · GitHub

You convert the binary AccountIdentifier to hex, this will be the ledger account id that you can use on the mainnet with the tool of your choice (dfx ledger transfer, NNS Dapp, Coinbase, etc.).

Unfortunately, the workflow for local ledger deployments is a bit more complicated and needs a direct call to the local ledger canister, something like

dfx canister call ledger transfer '(record { to = blob "\08.\cf.?dz\c6\00\f4?8\a6\83B\fb\a5\b8\e6\8b\08_\02Y+w\f3\98\08\a8\d2\b5"; memo = 1; amount = record { e8s = 2_00_000_000 }; fee = record { e8s = 10_000 }; })'

Where to is the binary account id that your canister reports.

It seems that we need the following:

  1. Extend dfx to include tools that allow you to compute canister ledger account identifier without writing any code (Extend `dfx ledger account-id` to support canister accounts · Issue #1981 · dfinity/sdk · GitHub)
  2. Document how to do transfer ICP to a canister given canister id (As a developer, I want to know how to transfer ICP to my canister so that I can top up my canister · Issue #655 · dfinity/docs · GitHub)
  3. (Long term) extend dfx to allow everyone to easily install ledger in a way that integrates well with dfx ledger commands (Make installing ledger locally simple · Issue #1982 · dfinity/sdk · GitHub).

The first two points are simple, I’ll try to implement them in the next couple of weeks. The third point is a bit more involved and will take longer.


in the accountIdentifier function within the file of the example you gave, as I understand it, you perform the following:
1.) first, you hash an array consisting of a single entry. that entry is 0x0A.
2.) next, you hash the text “account-id”.
3.) next, you hash the user’s principal.
4.) next, you hash the user’s subaccount.
5.) then you concatenate those hashes together to get the hashsum.
6.) then you get the CRC32 checksum of the hashsum.
7.) then you run the checksum though the beBytes function.
8.)finally, you append the array returned from running the checksum through the beBytes function with the hashsum array.

My first question is, why’d you have to hash that first array with the 0x0A entry? whats the significance of that?

my second question is, why’d you have to run the checksum through the beBytes function and append the result to the hashsum array?

1 Like