Invalid certificate: Signature verification failed when using @dfinity/ledger-icrc

So I’m trying to use the @dfinity/ledger-icrc to send a payment from a users account to my apps backend account but I get the following error:

image

Uncaught (in promise) Error: Invalid certificate: Signature verification failed
at _Certificate.verify (chunk-DG3IE5T5.js?v=e95fdae5:11396:13)
at async _Certificate.create (chunk-DG3IE5T5.js?v=e95fdae5:11352:5)
at async pollForResponse (chunk-MOKRRM53.js?v=e95fdae5:4581:16)
at async caller (chunk-MOKRRM53.js?v=e95fdae5:5112:29)
at async e2.transfer (@dfinity_ledger-icrc.js?v=e95fdae5:124:15)
at async Array. (user.store.ts?t=1716674233096:124:31)

To send the payment I have the following code:

async function saveEuro2024Predictions(
dto: Euro2024PredictionDTO,
): Promise {
try {
const identityActor = await ActorFactory.createIdentityActor(
authStore,
process.env.FOOTBALL_GOD_BACKEND_CANISTER_ID ?? “”,
);

  if (dto.alreadyEntered) {
    const result = await identityActor.submitEuro2024Prediction(dto);
    console.log(result);
    if (isError(result)) {
      console.error("Error saving Euro2024 prediction.");
      return;
    }
    return result;
  }

  const ledger = IcrcLedgerCanister.create({
    agent: ActorFactory.getAgent(),
    canisterId: Principal.fromText("avqkn-guaaa-aaaaa-qaaea-cai"),
  });

  authStore.subscribe(async (auth) => {
    let transfer_result = await ledger.transfer({
      to: {
        owner: Principal.fromText(
          process.env.FOOTBALL_GOD_BACKEND_CANISTER_ID ?? "",
        ),
        subaccount: [auth.identity?.getPrincipal().toUint8Array() ?? []],
      },
      fee: 100_000n,
      memo: undefined,
      from_subaccount: undefined,
      created_at_time: BigInt(Date.now()),
      amount: 100_000_000_000n,
    });
    console.log(transfer_result);
  });
} catch (error) {
  console.error("Error saving Euro2024 prediction.", error);
  throw error;
}

}

The user starts in the NNS, sending FPL to their FootballGod principal ID. This is the account I am trying to send from within footballgod. The transfer goes from their FPL ledger account, using the sub account for their caller ID into the FootballGod backend account, using their caller id as the sub account for me to use for the prize pool.

Ok so I changed my setup to better match the docs and not reuse my existing actor and it makes the request without the signature verification error:

image

However as @v1ctor mentioned earlier, I need to pad the 29 byte principal to 32 bytes. Please could you provide me with the way to do this? Is there a frontend Sha256 conversion utility?

Try principalToSubAccount: https://github.com/dfinity/ic-js/tree/main/packages/utils#gear-principaltosubaccount

1 Like

Thank you David, this worked.

1 Like

Hey, can I ask what you meant by that? I’m running into the same situation (Invalid certificate: Signature verification failed error) and I’m not sure how to fix it.

I went through the error now, i changed my code from this

const agent = await createAgent({
    identity: client.getIdentity(),
    host: `http://${MY_LEDGER_CANISTER_ID}.localhost:4943`,
  });

to this

const agent = await createAgent({
    identity: client.getIdentity(),
    host: `http://${MY_LEDGER_CANISTER_ID}.localhost:4943`,
    fetchRootKey: true,
  });

fetchRootKey = Fetch root key for certificate validation during local development or on testnet

1 Like