Payment Tokens
The public v0.7 paymaster accepts USDC, USDâ‚®0, or USDG for reimbursement. USDC is the default; select another token explicitly by symbol, alias, or address.
The EIP-7702 v0.8 deployment currently accepts USDC only. Always use the
selected deployment’s tokens list as the authority for enabled tokens.
const { quote } = await paymasterClient.quoteUserOperation({
userOperation,
token: "USDG",
maxTokenCost: 100_000n,
});The Viem adapter accepts the same selection through paymasterContext:
paymasterContext: {
token: "USDT0", // Alias for the onchain USDâ‚®0 symbol
maxTokenCost: 100_000n,
}maxTokenCost and allowances are denominated in the selected token’s smallest
unit. All three current tokens use six decimals. Read decimals from deployment
metadata rather than assuming that future tokens will do the same.
Canonical Ink addresses
| Symbol | Address | Decimals |
|---|---|---|
| USDC | 0x2D270e6886d130D724215A266106e6832161EAEd | 6 |
| USDâ‚®0 | 0x0200C29006150606B650577BBE7B6248F58470c1 | 6 |
| USDG | 0xe343167631d89B6Ffc58B88d6b7fB0228795491D | 6 |
Token presence in INK_PAYMENT_TOKENS identifies its canonical address. The
active deployment’s tokens list remains the authority for what the live
paymaster has enabled.
Approvals are per token
Each token has a separate ERC-20 allowance. Before requesting a quote, the
smart account must execute approve(paymaster, finiteAllowance) on the token it
will use for reimbursement.
import {
encodePublicPaymasterApproval,
getPublicPaymasterAccountState,
INK_PAYMENT_TOKENS,
INK_PUBLIC_PAYMASTER,
} from "@hellomoon/ink-paymaster";
const state = await getPublicPaymasterAccountState(
publicClient,
smartAccount.address,
INK_PUBLIC_PAYMASTER,
"USDG",
);
const approvalCall = {
to: INK_PAYMENT_TOKENS.USDG.address,
value: 0n,
data: encodePublicPaymasterApproval(10_000_000n),
};The public paymaster does not pay for this approval. Approve from the smart account using an owner-paid UserOperation.
Charging and refunds
The paymaster precharges a bounded amount during validation. After execution, it records the final reimbursement as treasury accrual and makes unused precharge available as pull-based refund credit owned by the smart account.
Read refundCredit with getPublicPaymasterAccountState. Applications may
claim it through the smart account using encodePublicPaymasterRefundClaim.
Refunds and allowances are independent for each token.
import {
encodePublicPaymasterRefundClaim,
INK_PUBLIC_PAYMASTER,
} from "@hellomoon/ink-paymaster";
const claim = encodePublicPaymasterRefundClaim(recipient);
const encodedCall = await smartAccount.encodeCalls([
{
to: INK_PUBLIC_PAYMASTER.paymaster,
value: 0n,
data: claim,
},
]);The smart account that owns the credit must execute the claim. The recipient may be a different address.