Test transactions in ICP

To confirm, you are trying to tie a transaction specific to a product. Let’s say Customer A buys Product A from Customer B using ICP. You would like to tie this transaction?

You can do the following:

  1. When a user calls a transfer function, it should return the block number specific to the transaction such as:

(variant { Ok = 2 : nat })

  1. You can create a Hashmap (if using Motoko) to store the block number with the product ID. For example:
import HashMap "mo:base/HashMap";
import Text "mo:base/Text";

let map = HashMap.HashMap<Text, Nat>(5, Text.equal, Text.hash);
map.put("productA", blockNumber);
  1. Putting this together, I imagine you can something like this (Please test this):
import Icrc1Ledger "canister:icrc1_ledger_canister";
import Debug "mo:base/Debug";
import Result "mo:base/Result";
import Error "mo:base/Error";
import HashMap "mo:base/HashMap";

actor {

  // Define the ProductName type
  type ProductName = Text;

  type TransferArgs = {
    amount : Nat;
    toAccount : Icrc1Ledger.Account;
    productName : ProductName;
  };

   let map = HashMap.HashMap<Text, Nat>(5, Text.equal, Text.hash);

  public shared func transfer(args : TransferArgs) : async Result.Result<Icrc1Ledger.BlockIndex, Text> {
    Debug.print(
      "Transferring "
      # debug_show (args.amount)
      # " tokens to account "
      # debug_show (args.toAccount)
      # " for product "
      # debug_show (args.productName)
    );

    let transferArgs : Icrc1Ledger.TransferArg = {
      // can be used to distinguish between transactions
      memo = null;
      // the amount we want to transfer
      amount = args.amount;
      // we want to transfer tokens from the default subaccount of the canister
      from_subaccount = null;
      // if not specified, the default fee for the canister is used
      fee = null;
      // the account we want to transfer tokens to
      to = args.toAccount;
      // a timestamp indicating when the transaction was created by the caller; if it is not specified by the caller then this is set to the current ICP time
      created_at_time = null;
    };

    try {
      // initiate the transfer
      let transferResult = await Icrc1Ledger.icrc1_transfer(transferArgs);

      // check if the transfer was successful
      switch (transferResult) {
        case (#Err(transferError)) {
          return #err("Couldn't transfer funds:\n" # debug_show (transferError));
        };
        case (#Ok(blockIndex)) {
          map.put(args.productName, blockIndex); // Use args.productName
          return #ok blockIndex;
        };
      };
    } catch (error : Error) {
      // catch any errors that might occur during the transfer
      return #err("Reject message: " # Error.message(error));
    };
  };
};
1 Like