Skip to content

Payment tokens ​

The public v0.7 deployment accepts USDC, USD₮0, or USDG for reimbursement. USDC remains the default; select either additional token explicitly by symbol, alias, or address.

ts
const {quote} = await paymasterClient.quoteUserOperation({
  userOperation,
  token: "USDG",
  maxTokenCost: 100_000n,
});

The Viem adapter accepts the same selection through paymasterContext:

ts
paymasterContext: {
  token: "USDT0", // alias for the token's onchain USD₮0 symbol
  maxTokenCost: 100_000n,
}

maxTokenCost and allowances are denominated in the selected token's smallest unit. All three currently known Ink tokens use six decimals, but integrations should read decimals from deployment metadata instead of assuming that for future tokens.

The same helper works for all three reimbursement tokens. Each operation transfers the selected ERC-20 while the paymaster supplies native gas through EntryPoint and separately charges that same token for reimbursement:

ts
import {transferPaymentToken} from "../examples/payment-token-transfer.js";

await transferPaymentToken({
  account,
  token: "USDC",
  recipient,
  amount: "1.00",
  idempotencyKey: "transfer-usdc-order-101",
});

await transferPaymentToken({
  account,
  token: "USDT0",
  recipient,
  amount: "1.00",
  idempotencyKey: "transfer-usdt0-order-102",
});

await transferPaymentToken({
  account,
  token: "USDG",
  recipient,
  amount: "1.00",
  idempotencyKey: "transfer-usdg-order-103",
});

These are three separate UserOperations. The smart account needs a finite, owner-paid allowance for each token before using it for reimbursement.

Approval remains owner-paid ​

Each token has a separate ERC-20 allowance. Before requesting a quote, the smart account must execute approve(paymaster, finiteAllowance) on the token it plans to use. The public endpoint does not sponsor that approval or spot the account its first reimbursement.

ts
import {
  encodePublicPaymasterApproval,
  getPublicPaymasterAccountState,
  INK_PAYMENT_TOKENS,
} from "@hellomoon/ink-paymaster";

const state = await getPublicPaymasterAccountState(
  publicClient,
  smartAccount.address,
  deployment,
  "USDG",
);

const approvalCall = {
  to: INK_PAYMENT_TOKENS.USDG.address,
  value: 0n,
  data: encodePublicPaymasterApproval(10_000_000n, deployment),
};

Canonical Ink addresses ​

SymbolAddress
USDC0x2D270e6886d130D724215A266106e6832161EAEd
USD₮00x0200C29006150606B650577BBE7B6248F58470c1
USDG0xe343167631d89B6Ffc58B88d6b7fB0228795491D

Token presence in INK_PAYMENT_TOKENS identifies its canonical address; it does not by itself mean the live deployment has enabled it. Use the deployment's tokens list as the authority.

ERC-4337 paymaster clients for Ink Mainnet