Hi!
After all, not all issues have been resolved by me.
Error exchanging ICP for cycles. The transaction is stuck. I must say right away I tried to solve the problem myself for a long time.Below in details.
Coinage code:
(
variant { Ok = 4_878_415 : nat64 },
variant {
Err = variant {
InvalidTransaction = "Destination account in the block (c46e6da5d5aab2239fe94051c759104885d80243c1f685f61e4089bf48b94a2b) different than in the notification (b00c86416e82dd18993ed926eaeee00a94de9aceb02d37ca9c4823076a7aef83)"
}
},
)
That is, the transaction with ICP passes, but they get stuck and do not return the exchanged cycles.
-Maybe it is necessary to create a canister using an actor (rkp4c-7iaaa-aaaaa-aaaca-com) .notify_create_canister and only then will the coinage cycles work for the created canister?
First, the subaccount the ICP transfer goes to needs to be an encoding of the canister id where the cycles will go to. The encoding is what Roman shared above. I think principalToAccount returns the default account of the principal.
The second issue is that transfers that are intended for topping up canisters need to have a specific memo field, namely 0x50555054 (there’s also a specific memo if you want to use the converted cycles to create a canister). You can see the definitions of the memos used here.
The error you are hitting is not because you don’t use the correct memo, but because the transfer does not go to the correct subaccount. Basically, you need a function which takes a canister_id and returns a subaccount; this is the function that Roman in his answer.
The two functions you provided take a canister_id and a subaccount and return an account (which is not what you want).
This is excellent. Your help has yielded results! I’ll give you the code, maybe it will help someone else. Function for subaccount:
public func principalToSubAccount(id: Principal) : [Nat8] {
let p = Blob.toArray(Principal.toBlob(id));
Array.tabulate(32, func(i : Nat) : Nat8 {
if (i >= p.size() + 1) 0
else if (i == 0) (Nat8.fromNat(p.size()))
else (p[i - 1])
})
};
but then there was a mistake
variant { Ok = 4_880_838 : nat64 },
variant {
Err = variant {
InvalidTransaction = "Intent in the block (0 == unrecognized) different than in the notification (1347768404 == TopUp)"
}
},
And a clear indication
let coinage_cycles_memo = 0x50555054 : Nat64;
@bogwar We passed the correct memo with the wrong endianness i.e. passed “\54\50\55\50” to use instead of “\50\55\50\54” as shown in the attached code fragment. We received the error message as #InvalidTransaction("Destination account in the block (3d9f6eb216b2dc34d458346a4fac426fe7547c714133aa7b076febedf51c3c8e) different than in the notification (6cbd57ae110d3ee0505ae32b516d4e1514ee6e244444f37e4c8575a63db233c6)")
We lost a significant amount of ICPs in this exercise. Is there a way to recover our lost ICPs?
the CMC checks that the transaction has a specific format, in particular it checks that the memo field is what it expects, before proceeding with the conversion. I think that at the moment it doesn’t do refunds if this check fails so as it stands there’s not much you can do.
Let me bring this up to the team in charge of the CMC.
One possibility would be to add an endpoint for reclaiming transfers for which the conversion fails (for whatever reason). It may be tricky to implement though.
@bogwar Also wanted you to review the code of icrc1_transfer as shown in the snapshot above. I wanted to make sure we’re passing the memo & others correctly format-wise, value-wise, etc