Issue with ICRC2 Token Approval Logic in Canister Development

Hello everyone,

I’m working on a canister that transfers some tokens using the ICRC2 standard. I’ve encountered an issue with the approve function, which is supposed to allow a spender to transfer tokens on behalf of an owner.

However, the approval seems incorrectly set up with the canister’s principal as the owner instead of the intended account owner.

Here’s a brief overview of the setup:

  1. Functionality: The ifarm_approve function should approve a spender to use tokens from a specific owner’s account.
  2. Issue: When calling the ifarm_approve function, the approval seems to be associated with the canister’s principal rather than the specified owner’s principal.
  3. Expected Behavior: The approval should be set up such that the spender can use tokens from the specified owner’s account, not the canister’s account.

Here’s the code:

// Approve ifarm token
#[ic_cdk::update]
async fn ifarm_approve(owner: Principal, spender: Principal, amount: Nat) -> Result<ICRC2ApproveResult, String> {
    if owner == spender {
        return Err("Owner and spender cannot be the same".to_string());
    }

    let spender_account = ICRCAccount::new(spender, None);

    let approve_args = ICRC2ApproveArgs {
        spender: spender_account,
        amount,
        from_subaccount: None,
        expected_allowance: None,
        expires_at: None,
        fee: None,
        memo: None,
        created_at_time: None,
    };

    ICRC2::from(IFARM_TOKEN).approve(approve_args).await.map_err(|e| format!("Approval failed: {:?}", e))
}

Link to code on github

My concern is, how can I ensure that the approval is correctly associated with the intended owner’s tokens?

Assuming we have:

  1. Person A of principal ID xxx
  2. Person B of principal ID yyy
  3. Canister of ID zzz

When I call the approve function to approve xxx to spend yyy’s tokens, The issue seems to be that the function is approving the spender xxx to use tokens from the canister’s account zzz instead of the intended account owner yyy

It is only possible to approve other principals to spend your tokens. Otherwise everyone could transfer everyone’s tokens at will. On ICP, unlike ETH, when a user makes a call and the called canister makes a call itself (e.g. your canister to the token ledger’s icrc2_approve function) then the canister becomes the caller and it is no longer possible to see that the user triggered that transaction.

In other words: the user must make the call to icrc2_approve. You can’t call it for one of your users.

Oh great!

Than you for the clarification