Local ledger canister failed to call send_dfx command

i have setup ledger canister using dfinity’s official guide, followed instructions from here

after setup i tried this command:

dfx canister call custom-ledger account_balance_dfx '(record { account = "'$LEDGER_ACC'" })'

got response:

(record { e8s = 100_000_000_000 : nat64 })

so i’m assuming custom ledger canister was setup properly.

i got stuck at dfx_transfer command, i’m using this command:

dfx canister call custom-ledger send_dfx '(record {memo = 1234; amount = record { e8s=10_000_000 }; fee = record { e8s=10_000 }; to = "'$USER_ACC'"; created_at_time = null })'

& getting response:

Error: Failed update call. Caused by: Failed update call. The Replica returned an error: code 5, message: "canister trapped: EvalTrapError region:0x51693-0x51695 "canister trapped explicitly: Panicked at 'Deserialization Failed: \"Fail to decode argument 0 from table0 to record {\\n to : text;\\n fee : record { e8s : nat64 };\\n memo : nat64;\\n from_subaccount : opt vec nat8;\\n created_at_time : opt record { timestamp_nanos : nat64 };\\n amount : record { e8s : nat64 };\\n}\"', /ic/rs/rust_canisters/dfn_core/src/endpoint.rs:123:41""

USER_ACC here is just principal of another identity, this is the exact value:

fuddf-sqzfl-yvosv-7gw22-77y5x-nzj3y-fve3j-mvcr7-wa7x2-e3tnp-nae

what am i doing wrong here? & is there any other documentation for ref. of cli commands & their formats?!
thanks for help in advance.

I think you’re missing the field from_subaccount in your call arguments

Screenshot from 2022-11-23 23-14-45

in IDL it is marked as optional, is it required argument here?

I think it’s optional to have a value, but it’s required to write it. I.e. the same way you included created_at_time = null

thanks for the response @Severin
i tried using null with it, still getting error:

The Replica returned an error: code 5, message: "canister trapped: EvalTrapError region:0x51693-0x51695 “canister trapped explicitly: Panicked at ‘Deserialization Failed: "Fail to decode argument 0 from table0 to record {\n to : text;\n fee : record { e8s : nat64 };\n memo : nat64;\n from_subaccount : opt vec nat8;\n created_at_time : opt record { timestamp_nanos : nat64 };\n amount : record { e8s : nat64 };\n}"’, /ic/rs/rust_canisters/dfn_core/src/endpoint.rs:123:41"”

not able to figure out what am i missing on this. is format of all argument correct? i’m using this command:

dfx canister call custom-ledger send_dfx ‘(record {memo = 1234; amount = record { e8s=10_000_000 }; fee = record { e8s=10_000 }; to = "’$USER_ACC’"; from_subaccount = null; created_at_time = null })’

and these are the exact values which are getting passed:

(record {memo = 1234; amount = record { e8s=10_000_000 }; fee = record { e8s=10_000 }; to = “xpfaj-evqin-hf3bt-dxnj6-mb6t6-e6deg-3nigb-ekb6q-f5pjy-7oq3y-bae”; from_subaccount = null; created_at_time = null })

I think I got it: Your numerical values get encoded as int, but they have to be nat64. Your argument has to look like this:

(record {memo = 1234 : nat64; amount = record { e8s=10_000_000 : nat64}; fee = record { e8s=10_000 : nat64 }; to = "xpfaj-evqin-hf3bt-dxnj6-mb6t6-e6deg-3nigb-ekb6q-f5pjy-7oq3y-bae"; from_subaccount = null; created_at_time = null })

Notice the : nat64 after the numerical values.

To see how it works under the hood:

  • get didc from the candid repo
  • didc encode <your argument string> shows the value that gets sent over the wire
  • didc decode <output from previous command> shows how it gets deserialised at the other end
  • compare the types you need and the types that you get

Using your actual data:

❯ didc encode '(record {memo = 1234; amount = record { e8s=10_000_000 }; fee = record { e8s=10_000 }; to = "xpfaj-evqin-hf3bt-dxnj6-mb6t6-e6deg-3nigb-ekb6q-f5pjy-7oq3y-bae"; from_subaccount = null; created_at_time = null })'
4449444c026c06fbca0171c6fcb60201ba89e5c2047ca2de94eb067f82f3f3910c7fd8a38ca80d016c01e0a9b3027c01003f787066616a2d657671696e2d68663362742d64786e6a362d6d623674362d65366465672d336e6967622d656b6236712d6635706a792d376f7133792d62616590ce00d20980ade204

didc decode 4449444c026c06fbca0171c6fcb60201ba89e5c2047ca2de94eb067f82f3f3910c7fd8a38ca80d016c01e0a9b3027c01003f787066616a2d657671696e2d68663362742d64786e6a362d6d623674362d65366465672d336e6967622d656b6236712d6635706a792d376f7133792d62616590ce00d20980ade204
(
  record {
    25_979 = "xpfaj-evqin-hf3bt-dxnj6-mb6t6-e6deg-3nigb-ekb6q-f5pjy-7oq3y-bae";
    5_094_982 = record { 5_035_232 = 10_000 : int };
    1_213_809_850 = 1_234 : int;
    1_835_347_746 = null : null;
    3_258_775_938 = null : null;
    3_573_748_184 = record { 5_035_232 = 10_000_000 : int };
  },
)

This is missing the field names (since we didn’t supply the .did file), but we’re only interested in the data types. You can see that it gets decoded as an int, but the error message calls for nat64. Using the nat64 annotations:

❯ didc encode '(record {memo = 1234 : nat64; amount = record { e8s=10_000_000 : nat64}; fee = record { e8s=10_000 : nat64 }; to = "xpfaj-evqin-hf3bt-dxnj6-mb6t6-e6deg-3nigb-ekb6q-f5pjy-7oq3y-bae"; from_subaccount = null; created_at_time = null })'
4449444c026c06fbca0171c6fcb60201ba89e5c20478a2de94eb067f82f3f3910c7fd8a38ca80d016c01e0a9b3027801003f787066616a2d657671696e2d68663362742d64786e6a362d6d623674362d65366465672d336e6967622d656b6236712d6635706a792d376f7133792d6261651027000000000000d2040000000000008096980000000000

❯ didc decode 4449444c026c06fbca0171c6fcb60201ba89e5c20478a2de94eb067f82f3f3910c7fd8a38ca80d016c01e0a9b3027801003f787066616a2d657671696e2d68663362742d64786e6a362d6d623674362d65366465672d336e6967622d656b6236712d6635706a792d376f7133792d6261651027000000000000d2040000000000008096980000000000
(
  record {
    25_979 = "xpfaj-evqin-hf3bt-dxnj6-mb6t6-e6deg-3nigb-ekb6q-f5pjy-7oq3y-bae";
    5_094_982 = record { 5_035_232 = 10_000 : nat64 };
    1_213_809_850 = 1_234 : nat64;
    1_835_347_746 = null : null;
    3_258_775_938 = null : null;
    3_573_748_184 = record { 5_035_232 = 10_000_000 : nat64 };
  },
)

now the types match :partying_face:

1 Like

@Severin does not seem to work in my case. still getting Deserialization error.
tried encoding my input with didc, i’m getting this when decoded again:

(
  record {
    25_979 = "xpfaj-evqin-hf3bt-dxnj6-mb6t6-e6deg-3nigb-ekb6q-f5pjy-7oq3y-bae";
    5_094_982 = record { 5_035_232 = 10_000 : nat64 };
    1_213_809_850 = 1_234 : nat64;
    1_835_347_746 = null : null;
    3_258_775_938 = null : null;
    3_573_748_184 = record { 5_035_232 = 10_000_000 : nat64 };
  },
)

i tried same input what you have posted hard-coded as argument, still getting same error.

dfx canister call custom-ledger send_dfx '(record { memo = 1234 : nat64; amount = record { e8s=10_000_000 : nat64; }; fee = record { e8s=10_000 : nat64; }; to = "xpfaj-evqin-hf3bt-dxnj6-mb6t6-e6deg-3nigb-ekb6q-f5pjy-7oq3y-bae"; from_subaccount = null; created_at_time = null })'

got this error:

The Replica returned an error: code 5, message: "canister trapped: EvalTrapError region:0x51693-0x51695 "canister trapped explicitly: Panicked at 'Deserialization Failed: \"Fail to decode argument 0 from table0 to record {\\n  to : text;\\n  fee : record { e8s : nat64 };\\n  memo : nat64;\\n  from_subaccount : opt vec nat8;\\n  created_at_time : opt record { timestamp_nanos : nat64 };\\n  amount : record { e8s : nat64 };\\n}\"', /ic/rs/rust_canisters/dfn_core/src/endpoint.rs:123:41""

not sure but could it be possible the "to" address is causing this error.
current "to" address i’m using here is: dfx identity get-principal
is this supposed to be any account address or something?

Ah, right, sorry for not noticing this earlier. Ledger accounts are not principals. dfx ledger account-id and its many options can help you construct some valid ledger accounts.

If you need more info on generating account identifiers I can recommend this topic: Error exchanging ICP for cycles

1 Like