Convert ICP Memo to ICRC

In today’s Juno live stream, I was implementing the CMC notify_top_up. My first attempt failed because I forgot to specify the memo in the transfer. At that point, I tried converting the ICP memo — which I knew worked — into an ICRC memo, but I couldn’t get it to work. Ultimately, I abandoned the ICRC transfer and reverted the entire solution back to an ICP transfer.

Long story short, I’m wondering: is it possible to convert an ICP memo to an ICRC memo?

I tried the following, but it failed at runtime.

use icrc_ledger_types::icrc1::transfer::{Memo as IcrcMemo};
use ic_ledger_types::{Memo};

const MEMO_CANISTER_TOP_UP: Memo = Memo(0x50555054); // == 'TPUP'

let icrc_memo = IcrcMemo::from(MEMO_CANISTER_TOP_UP.0);

// Proceed with an icrc1_transfer using icrc_memo
// Then CMC notify_top_up

maybe this helps

2 Likes

Interesting, thanks. So you can’t really just convert an ICP memo to an ICRC memo for the CMC because it needs to be padded with four 0s — that’s why my above snippet failed?

Yes, this is confusing. Sorry about that.

To convert, do this:

MEMO_CANISTER_TOP_UP.0.to_le_bytes().to_vec()

IMHO, IcrcMemo::from(u64) should not exist. This is because ICRC memo is an opaque blob. This means that ledger has no idea what the bytes in the memo field signify.

The significance of a memo blob is something that sender and receiver need to agree on. In this case, the receiver is the CMC, and CMC says that legacy (u64) memo and ICRC (blob) memo are equivalent up to little endian 64-bit integer encoding.

2 Likes

Gotcha! Thanks a lot for providing both solution and explanation! :+1: