Integrating with the Internet Computer ledger

I did a bit more researching. I think i may know the answer to my first question. Still clueless about the second question though.

Initially, i was wondering if that specific byte (0x0A) had some sort of significance in particular, but, now I’m guessing the answer to why you hashed the first array with the single entry of 0x0A was just to add an extra layer of hashing to minimize the probability of someone being able to decrypt the real data you intend to hash which are the text (‘account-id’), the principal and the subaccount. 0x0A is just an arbitrary byte that was chosen, it could have been any byte. is that correct?

1 Like

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

0x0A is 10, which is the length of the string “account-id” that follows. This technique of prefixing values being hashed with an identifier is called domain separators. The IC uses domain separators almost every time when something needs to be hashed (search for “domain separator” in Smart Contracts on the Internet Computer for more examples).

why’d you have to run the checksum through the beBytes function and append the result to the hashsum array?

We prepend the CRC32 sum of the hash to form an account identifier as an additional safety measure. It’s a bit like the Luhn check for credit card numbers. The price of a mistake is high: someone might select a wrong hex string that happens to have the right length and lose ICP by transferring to that “account”. That actually happened before with the Protobuf interface that accepts 28-byte identifiers (these don’t have the checksum).
The beBytes function converts the checksum, which is a 32-bit unsigned integer, into a byte array. There is more than one way to do that, and beBytes stands for “big-endian bytes” (see Endianness - Wikipedia for more information on this).

The Ledger Canister Specification also has a section describing the formation of account identifiers.

4 Likes

Thanks a ton! this was enlightening.

The issue is that on Ethereum a transferAndCall method would be atomic… Imagine a user is trying to pay a dapp canister tokens for some service. Then, the user would call the transferAndCall method on the token ledger canister, which would then call some tokenFallback method on the dapp canister. If any part of this fails, the entire transaction is reverted.

But on the IC, inter-canister calls are not atomic… so porting transferAndCall over to the IC as is doesn’t really make sense since it can’t be treated as atomic anyways. But then, why create a new notify method on the ICP ledger canister? It still makes an inter-canister call to the destination canister…

In general, one thing that bothers me is that we jump through all these hoops to avoid making inter-canister calls due to safety concerns with upgrades, atomicity, etc… But inter-canister calls are an essential ingredient in the IC’s vision of composability. I hope they can be made safer and more ergonomic so that developers can be encouraged to use them.

3 Likes

I can’t use this ledger canister id “ryjl3-tyaaa-aaaaa-aaaba-cai” in motoko playground with the following error when I import it. is there any ledger canister that can be used in motoko playground?

file idl/ryjl3-tyaaa-aaaaa-aaaba-cai.did uses Candid types without corresponding Motoko type

I think it’s fixed now. Can you try again in the playground?

2 Likes

Thank you! The error is done. I can use it!

1 Like