Mismatch between frontend and backend principalToSubaccount conversion

When making a transfer within my app the user authorises a payment like so:

let principal = auth.identity?.getPrincipal();
console.log(principal)
if (principal) {
let subaccount: Uint8Array = principalToSubAccount(principal);
console.log(subaccount);
try {
let transfer_result = await transfer({
to: {
owner: Principal.fromText(
process.env.FOOTBALL_GOD_BACKEND_CANISTER_ID ?? “”,
),
subaccount: [subaccount],
},
fee: 100_000n,
memo: new Uint8Array(Text.encodeValue(“0”)),
from_subaccount: undefined,
created_at_time: BigInt(Date.now()) * BigInt(1_000_000),
amount: 10_000_000_000n,
});
console.log(transfer_result);
} catch (err: any) {
console.error(err.errorType);
}
}

I’ve checked the log of this sub account on the frontend

image

and it matches the transactions on the ledger canister

I then ran a check on the backend to see what the callers principalToSubAccount is to ensure they match:

However, they don’t:

Any idea where I’ve gone wrong?

Ah so it appears that I was using a hashing algorithm to convert principalToSubaccount on my backend and I think I just need to pad the principal using motoko.

Ok so I was able to get a balance on the account by converting the 29 byte principal to 32 by using the following function (provided by @skilesare).


  private func principalToSubaccount(principal : Principal) : Blob {
    var sub = Buffer.Buffer<Nat8>(32);
    let subaccount_blob = Principal.toBlob(principal);

    sub.add(Nat8.fromNat(subaccount_blob.size()));
    sub.append(Buffer.fromArray<Nat8>(Blob.toArray(subaccount_blob)));
    while (sub.size() < 32) {
    sub.add(0);
    };

    Blob.fromArray(Buffer.toArray(sub));
  };
1 Like

Pretty sure I borrowed this from @quint or someone else. H/t to whoever I collected it from along the way.

1 Like