Documentation Index
Fetch the complete documentation index at: https://docs.mls.onchainden.com/llms.txt
Use this file to discover all available pages before exploring further.
What is a token transfer transaction?
A token transfer transaction moves ERC-20 tokens from one account to another.
This guide uses an ERC-20 transfer (USDC) as a reference example. Replace the
token, decimals, and amount for your asset.
1) Set up the client and signer
Create the SDK client and signer used for approvals.
import { DenClient } from "@onchainden/mls-sdk-ts";
import { privateKeyToAccount } from "viem/accounts";
import { encodeFunctionData } from "viem";
const signer = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const client = new DenClient({
apiKey: process.env.DEN_API_KEY!,
baseUrl: process.env.DEN_API_BASE_URL!,
});
2) Build the transfer data
Encode the ERC-20 transfer call data for the token transfer.
const erc20TransferAbi = [
{
name: "transfer",
type: "function",
stateMutability: "nonpayable",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ name: "success", type: "bool" }],
},
];
const callData = encodeFunctionData({
abi: erc20TransferAbi,
functionName: "transfer",
args: ["0xRecipient...", 250_000_000n],
});
3) Create the transaction
Create a transaction proposal using the encoded transfer data.
const { data: queued } = await client.createTransaction({
accountId: "acc_123",
initiatorWalletAddress: signer.address,
networkId: 1,
policyId: "pol_123",
description: "USDC payout",
to: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
value: "0",
data: callData,
});
4) Sign and execute
Sign as the initiator, then execute once approvals are ready.
const initiatorSig = await signer.signMessage({
message: queued.signatureData.initiatorPayload,
});
const { data: afterInitiator } = await client.signTransaction(queued.id, {
type: "initiator",
signature: initiatorSig,
});
if (afterInitiator.signatureData.status === "approvalReady") {
await client.executeTransaction(queued.id, { type: "approve" });
}
Full example
import { DenClient } from "@onchainden/mls-sdk-ts";
import { privateKeyToAccount } from "viem/accounts";
import { encodeFunctionData } from "viem";
// 1) Set up the client and signer.
const signer = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const client = new DenClient({
apiKey: process.env.DEN_API_KEY!,
baseUrl: process.env.DEN_API_BASE_URL!,
});
// 2) Build the transfer data.
const erc20TransferAbi = [
{
name: "transfer",
type: "function",
stateMutability: "nonpayable",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ name: "success", type: "bool" }],
},
];
const callData = encodeFunctionData({
abi: erc20TransferAbi,
functionName: "transfer",
args: ["0xRecipient...", 250_000_000n],
});
// 3) Create the transaction.
const { data: queued } = await client.createTransaction({
accountId: "acc_123",
initiatorWalletAddress: signer.address,
networkId: 1,
policyId: "pol_123",
description: "USDC payout",
to: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
value: "0",
data: callData,
});
// 4) Sign and execute.
const initiatorSig = await signer.signMessage({
message: queued.signatureData.initiatorPayload,
});
const { data: afterInitiator } = await client.signTransaction(queued.id, {
type: "initiator",
signature: initiatorSig,
});
if (afterInitiator.signatureData.status === "approvalReady") {
await client.executeTransaction(queued.id, { type: "approve" });
}