ICRC-2 Batch operations library

Often times, you might want to make multiple transaction calls to a ledger canister. Doing this sequentially takes a long time.

So, on behalf of a new stealth project :grin:, and while we wait for ICRC-4, I built icrc2-batch, a Motoko ICRC-2 library specifically tailored for parallel execution of allowance, approve, and transfer_from operations.

Using it is as easy as

import ICRC2Batch "mo:icrc2-batch";
import ICRC2Interface "mo:icrc2-batch/IRCR2Interface"

// example (inside an API)...
let icpLedgerCanisterId = "ryjl3-tyaaa-aaaaa-aaaba-cai"; 

let icrc2Actor = ICRC2Batch.ICRC2BatchActor({
  icrc2LedgerCanisterId = icpLedgerCanisterId;
  batchSize = 100;

let allowanceArgs : [ICRC2Interface.AllowanceArgs] = [
    account = { owner = <ownerPrincipal>; subaccount = null };
    spender = { owner = <spenderPrincipal>; subaccount = null };
let allowanceResponses = await* icrc2Actor.icrc2_allowance_batch(allowanceArgs);

(Similarly comes icrc2_approve_batch and icrc2_transfer_from_batch APIs)

The library supports up to 100 parallel async icrc2 operations at a time. Why 100? It’s a “conservative” approach to make sure developers don’t overflow their canister output queues.


This was my first time really using PicJS and getting it set up in CI. Ran into a few issues along the way, but man is it so much faster than dfx. Thanks so much @NathanosDev!

Also, I’d like to give a shout out to @quint and his testing.mo library.

It uses the interpreter and essentially allows you to run async* tests as unit tests, as long as you provide mock arguments for the async*.

This test is an example of observing a mocked async* function and testing that the arguments passed to it each time are correct.