Hello Dfinity Community,
I am reaching out for assistance with a problem I’ve encountered in my Motoko code while trying to implement a token transfer function on the Internet Computer. Despite having sufficient balance, I am consistently getting an ‘Insufficient Balance’ error when trying to perform a transfer.
Here’s a brief overview of what I’m trying to achieve:
- I have a
lockToken
function, which is meant to transfer tokens from a user’s principal to a specified canister. - The function retrieves the user’s balance and compares it with the required amount for the transfer.
- Despite the user’s balance being sufficient, the
Ledger.transfer
call within thetransferICP
function returns an ‘Insufficient Balance’ error.
Below is the relevant part of my code:
lockToken method:
public shared ({ caller }) func lockToken(principal : Principal, amount : Ledger.Tokens, dealId : Nat) : async LockTokenResult {
let canisterPrincipal = Principal.fromText("example canister");
let depositAddressBlob = Account.accountIdentifier(canisterPrincipal, Principal.toBlob(caller));
let depositAddress : [Nat8] = Blob.toArray(depositAddressBlob);
Debug.print("Caller Principal: " # Principal.toText(principal));
let debitBalance = await getBalance(principal);
Debug.print("Debit Balance: " # Nat64.toText(debitBalance));
Debug.print("Required Balance: " # Nat64.toText(amount.e8s));
Debug.print("ICP Fee: " # Nat64.toText(icp_fee));
let transferResult = await transferICP(principal, depositAddress, amount.e8s);
switch (transferResult) {
case (#Ok(_)) {
let dealOpt = deals.get(dealId);
switch (dealOpt) {
case (null) {
return #DealNotFound;
};
case (?deal) {
let updatedDeal = {
id = dealId;
status = "Tokens Locked";
name = deal.name;
from = deal.from;
to = deal.to;
amount = deal.amount;
picture = deal.picture;
description = deal.description;
dealCategory = deal.dealCategory;
dealType = deal.dealType;
paymentScheduleInfo = deal.paymentScheduleInfo;
dealTimeline = deal.dealTimeline;
deliverables = deal.deliverables;
supportingDocuments = deal.supportingDocuments;
createTime = deal.createTime;
submissionTime = deal.submissionTime;
buyerCancelRequest = deal.buyerCancelRequest;
sellerCancelRequest = deal.sellerCancelRequest;
};
deals.put(dealId, updatedDeal);
let activityLog = {
dealId = dealId;
description = "Tokens locked for the deal.";
activityType = "Tokens Locked";
amount = deal.amount;
status = "Tokens Locked";
activityTime = Time.now();
user = principal;
deal = updatedDeal;
};
await createActivityLog(activityLog, principal);
return #TokenLocked;
};
};
};
case (#Err(e)) {
return #TransferError(e);
};
};
};
transferICP method:
public func transferICP(transferFrom : Principal, transferTo : [Nat8], amount : Nat64) : async Ledger.TransferResult {
let res = await Ledger.transfer({
memo = 1;
amount = { e8s = amount };
fee = { e8s = 10_000 };
from_subaccount = null;
to = transferTo;
created_at_time = null;
});
return res;
};
I’ve used Debug.print
to confirm that the user’s balance is indeed sufficient before the transfer call. Here’s what I’ve verified:
2024-01-29 11:46:28.290769 UTC: [Canister bd3sg-teaaa-aaaaa-qaaba-cai] Debit Balance: 2100000000
2024-01-29 11:46:28.290769 UTC: [Canister bd3sg-teaaa-aaaaa-qaaba-cai] Required Balance: 100000000
2024-01-29 11:46:28.290769 UTC: [Canister bd3sg-teaaa-aaaaa-qaaba-cai] ICP Fee: 10000
Despite this, the transfer fails with an ‘Insufficient Balance’ error. I am wondering if there might be a subtle issue or a common pitfall that I’m overlooking.
I would greatly appreciate any insights or suggestions you might have. Has anyone else faced a similar issue, or can anyone spot a mistake in my approach?
Thank you in advance for your time and help!