Hi, I’m following the advice in a tutorial on inter-canister communication and can’t get it to compile. My canister is trying to call the icrc1_transfer function in a canister running the icrc1_ledger code. (I’m trying to mint and transfer some custom tokens). The icrc1_ledger canister is running and I can communicate with it on the command line ok.
I get ‘[M0038] misplaced await’ and ‘[M0037] misplaced async’ errors. The error numbers are vague (it indicates the beginning of the main actor declaration) but it seems to relate to these lines:
let ledger_canister = actor("bd3sg-teaaa-aaaaa-qaaba-cai"): actor {
icrc1_transfer : (TransferArg) -> async TransferResult;
};
The compile error messages are as follows:
/home/tom/projects/developer_journey/freeos_swap/src/freeos_swap_backend/main.mo:48.1-86.2: type error [M0038], misplaced await /home/tom/projects/developer_journey/freeos_swap/src/freeos_swap_backend/main.mo:48.1-86.2: type error [M0037], misplaced async expression; try enclosing in an async function
I’ve tried a lot of variations. My 3 AI chums (Claude, ChatGPT and Gemini) all seem to think the syntax is correct. Any hints would be much appreciated.
The whole code is as follows:
import Principal "mo:base/Principal";
import Blob "mo:base/Blob";
import Nat "mo:base/Nat";
import Text "mo:base/Text";
type Subaccount = Blob;
type Tokens = Nat;
type Timestamp = Nat64;
type Account = {
owner : Principal;
subaccount : ?Subaccount;
};
type Result<Ok, Err> = {
#ok: Ok;
#err: Err;
};
type TransferArg = {
from_subaccount : ?Subaccount;
to : Account;
amount : Tokens;
fee : ?Tokens;
memo : ?Blob;
created_at_time: ?Timestamp;
};
type BlockIndex = Nat;
type TransferError = {
BadFee : { expected_fee : Tokens };
BadBurn : { min_burn_amount : Tokens };
InsufficientFunds : { balance : Tokens };
TooOld : Nat;
CreatedInFuture : { ledger_time : Timestamp };
TemporarilyUnavailable : Nat;
Duplicate : { duplicate_of : BlockIndex };
GenericError : { error_code : Nat; message : Text };
};
type TransferResult = {
#Ok : BlockIndex;
#Err : TransferError;
};
actor {
let ledger_canister = actor("bd3sg-teaaa-aaaaa-qaaba-cai"): actor {
icrc1_transfer : (TransferArg) -> async TransferResult;
};
public func main() : async Result<Nat, Text> {
let from_principal = Principal.fromText("oi3ng-j6cnw-owsv3-4gtwq-nqfhh-ghwzh-assfr-khsv2-d37rq-2ejnj-xqe");
let to_principal = Principal.fromText("blwz3-4wsku-3otjv-yriaj-2hhdr-3gh3e-x4z7v-psn6e-ent7z-eytoo-mqe");
let memoText = "Test transfer";
let memoBlob = Text.encodeUtf8(memoText);
// Create the argument outside of the async/await context
let transferArgs = {
from = from_principal;
from_subaccount = null;
to = {
owner = to_principal;
subaccount = null;
};
amount = 50000;
fee = ?0;
memo = ?memoBlob;
created_at_time = null;
};
// Now perform the transfer with the created arguments
let transferResult = await ledger_canister.icrc1_transfer(transferArgs);
switch (transferResult) {
case (#Ok(blockIndex)) {
return #ok(blockIndex);
};
case (#Err(transferError)) {
return #err("Transfer error");
};
};
};
};
@claudio - In a previous post on this forum, you seem to suggest that the message may be caused by some sort of limitation, although you did not state what the limitation is. Can you say more about the limitation and how can I resolve it? Thank you.