Correct account Identifier of Canister

I am trying to send some ICP to my canister and then burn them to cycles using cycles minting canister. Here are the steps I followed

STEP 1 : Fetch account id for my canister

dfx ledger account-id --of-principal gq3rs-huaaa-aaaaa-qaasa-cai


STEP 2 : Transfer some icp to my canister

dfx ledger transfer f9389bf5d1d3f16dbe2a9ec554ef540c5f843e445ed7190fd0e55edd9cd641fd --memo 12345 --icp 100

STEP 3 : Fetch account identifier(blob) for my canister

dfx canister call nns-ledger account_identifier '(record{owner=principal "gq3rs-huaaa-aaaaa-qaasa-cai"; subaccount=null;})'

blob “\f98\9b\f5\d1\d3\f1m\be*\9e\c5T\efT\0c_\84>D^\d7\19\0f\d0\e5^\dd\9c\d6A\fd”,

STEP 4 : Check Balance of my canister

dfx canister call nns-ledger account_balance '(record{account = blob "\f98\9b\f5\d1\d3\f1m\be*\9e\c5T\efT\0c_\84>D^\d7\19\0f\d0\e5^\dd\9c\d6A\fd"})'

(record { e8s = 10_000_000_000 : nat64 })

STEP 5 : Notify cmc to burn icp into cycles

dfx canister call nns-cycles-minting notify_top_up '(record{block_index=8;canister_id = principal "gq3rs-huaaa-aaaaa-qaasa-cai";})'

variant {
Err = variant {
InvalidTransaction = “Destination account in the block (f9389bf5d1d3f16dbe2a9ec554ef540c5f843e445ed7190fd0e55edd9cd641fd) different than in the notification (76c14e54d0093d9300542fee42bf8a8e6d24d0ed97193a07a516f3ad3e94f8d6)”

Why am i recieving error in the last step ? I have double checked the block height using query_blocks. But it is to be noted that the ‘to’ argument in block no 8 do not match with blob of my canister account identifier fetched from nns ledger

Any specific reason you’re not using dfx ledger top-up? It would do that for you.

You have two parts to correct in your flow. The destination account (as the error message says) and once that’s fixed the CMC will complain about having the wrong memo.

The account you need to send your ICP to is an account controlled by the CMC where the subaccount is the top up target’s principal. IDK how to convert this except for this Rust code:

let to_subaccount = Subaccount::from(&to_principal);
let to = AccountIdentifier::new(MAINNET_CYCLE_MINTER_CANISTER_ID, Some(to_subaccount)).to_address();

You also need to set the right memo when transferring ICP to the CMC. For topping up a canister, the memo is

const MEMO_TOP_UP_CANISTER: u64 = 1347768404_u64;

which IIRC is TPUP converted to a number.

I am doing this now on CLI but my eventual goal is to do this process via code either in motoko or typescript by calling the canister functions individually. Is there any other way ?

I will apply the fixes you have mentioned and will update the result in this thread.

If you want code for inspiration, have a look here where we do the whole process in dfx

Thank you for this reference @Severin. Earlier @domwoe pointed me to same code and i am using it as a reference.

I have just one more question : When passing subaccount as an argument it must be passed as opt vec {32 bytes} . Is there a way in motoko or typescript to obtain this vector from principal of the subaccount ?

Will this do it in motoko?

Blob.toArrray(Principal.toBlob(<principal of subaccount>))

I think you have to pad that array with zeroes for it to be 32 bytes long, but otherwise this should work

Where will be the zeroes added to front or back of the array ?

I just had a look at the Rust impl. Looks like the first byte is the principal length, then the principal is appended, and then the padding is added at the end