Solana 支付原理

在 Solana 上构建支付流程之前,你需要了解五个核心概念:钱包、稳定币、token account、手续费和交易。Solana 的支付模型与多币种支付系统高度契合:

传统支付模型Solana说明
客户 ID / 账号Wallet address账户持有人的唯一标识符
货币(USD、EUR)Token Mint (USDG, USDC)被转移的资产类型
按币种余额Token Account (ATA)存储某一币种/资产的余额

就像银行客户有唯一身份但为每种货币分别持有余额一样,Solana 钱包也有一个地址,但每种资产都对应一个独立的 token account。下面我们来逐一解析这些组成部分。

钱包:发送方与接收方

每笔支付都涉及两方,每一方都由一个 wallet address 标识——一个唯一的 32 字节公钥(例如,7EcDhS...)。

  • Sender:发起支付的钱包。必须拥有足够的稳定币账户余额并签署交易。
  • Receiver:接收方钱包。无需签名,也不需要已有余额。
  • Fee Payer:可选的手续费支付钱包。可用于补贴或实现仅限稳定币的用户间交易。

可以把钱包地址类比为银行账号:公开、安全、可分享,是收发资金的必要信息。

稳定币

在 Solana 上,稳定币被称为“token”。Token 代表网络上的一种资产类型。每个 token 都有一个唯一的“mint address”。在构建支付系统时,你需要引用这些 mint address 来标识你所操作的资产。以下是主网上常见的稳定币 mint:

TokenIssuerMint Address
USDCCircleEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
USDTTetherEs9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB
PYUSDPayPal2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo
USDGPaxos2u1tszSeqZ3qBWF3uNGPFc8TzMk2tdiwknnRMWGWjGWH

如需了解更多关于 Solana 上稳定币的信息,请参阅 Stablecoins 解决方案页面。

接受付款时,请务必验证 mint 地址和 Token Program。 不同的 token 可能名称相同,但发行方和底层资产不同。

Token Account

钱包并不直接持有 token。相反,每个钱包对其持有的每种 token 都拥有一个 token account 的管理权限。付款时,token 会从发送方的 token account 转账到接收方同一 mint 的 token account:

Token AccountToken Account

Associated Token Account(关联 token account)是与特定钱包和 mint 绑定的确定性 token account。给定钱包地址和 mint,ATA 地址始终唯一。

  1. 每个 mint 仅有一个 ATA。一个钱包对 USDC 有一个 ATA,对 USDT 也有一个,依此类推。
  2. 必须先存在才能接收。不能向不存在的 ATA 发送 token。
  3. 通常由发送方创建。如果接收方的 ATA 不存在,发送方可以在支付交易中创建。
import { findAssociatedTokenPda } from "@solana-program/token";
const [receiverATA] = await findAssociatedTokenPda({
mint: USDG_MINT_ADDRESS,
owner: receiverWallet.address,
tokenProgram: TOKEN_PROGRAM_ADDRESS
});

Token Program

在 Solana 上,program 是用于管理账户状态的可执行逻辑。token account 由 Token Program 管理——链上的代码会原子性地验证转账并更新余额。

Solana 有两个 Token Program:

ProgramAddress示例代币
使用此程序
Token ProgramTokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DAUSDC、USDT
Token-2022TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEbPYUSD、USDG

Token-2022(也称为 "Token Extensions")增加了如转账钩子、转账手续费和隐私转账等功能。两种程序在基础转账操作上类似,但在派生 ATA 时必须使用正确的程序。

为什么这很重要

用于创建代币的 Token Program 决定了该代币的指令和账户状态。如果你使用了错误的程序,将无法转账该代币。

ATA 由三个输入派生而来:wallet + mint + token_program。使用错误的程序会生成完全不同的地址

import {
findAssociatedTokenPda,
TOKEN_PROGRAM_ADDRESS
} from "@solana-program/token";
import { TOKEN_2022_PROGRAM_ADDRESS } from "@solana-program/token-2022";
// USDC uses Token Program
const [usdcAta] = await findAssociatedTokenPda({
mint: USDC_MINT,
owner: walletAddress,
tokenProgram: TOKEN_PROGRAM_ADDRESS // ✓ Correct
});
// ❌ This will produce a different address because it uses the wrong program
const [wrongUsdcAta] = await findAssociatedTokenPda({
mint: USDC_MINT,
owner: walletAddress,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS // ❌ Wrong program
});
// PYUSD uses Token-2022
const [pyusdAta] = await findAssociatedTokenPda({
mint: PYUSD_MINT,
owner: walletAddress,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS // ✓ Correct
});

用错误的程序派生 ATA 会生成无效地址。务必确保程序与代币的 mint 匹配。

转账指令同样适用此原则。每个 token program 都有自己的转账指令,必须调用正确的指令:

import { getTransferInstruction } from "@solana-program/token";
import { getTransferInstruction as getTransferInstruction22 } from "@solana-program/token-2022";
// For USDC (Token Program)
const usdcTransferIx = getTransferInstruction({
source: senderUsdcAta,
destination: receiverUsdcAta,
authority: senderWallet,
amount: 1_000_000n // 1 USDC (6 decimals)
});
// For PYUSD (Token-2022)
const pyusdTransferIx = getTransferInstruction22({
source: senderPyusdAta,
destination: receiverPyusdAta,
authority: senderWallet,
amount: 1_000_000n // 1 PYUSD (6 decimals)
});
// *Note*: Most token program JS Client functions include the ability
// to specify the token program address. Generally, defining it is a
// good practice to ensure you are fully aware of the program you are using
const usdcTransferIx2 = getTransferInstruction(
{
source: senderUsdcAta,
destination: receiverUsdcAta,
authority: senderWallet,
amount: 1_000_000n // 1 USDC (6 decimals)
},
{ tokenProgram: TOKEN_PROGRAM_ADDRESS }
);

将转账指令发送到错误的程序会导致失败。程序会验证其是否拥有相关 token account——由 Token Program 创建的账户无法通过 Token-2022 转账,反之亦然。

要验证某个代币或 token account 使用的是哪个程序,可获取 mint 或 token account 并检查其 owner 字段:

import { createSolanaRpc, address } from "@solana/kit";
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
const accountInfo = await rpc.getAccountInfo(address(mintAddress)).send();
// The owner field tells you which program manages this token
const tokenProgram = accountInfo.value?.owner;
// Returns: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA (Token Program)
// or: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb (Token-2022)

对于支付应用,建议为每个支持的代币存储正确的程序地址:

const SUPPORTED_TOKENS = {
USDC: {
mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
program: TOKEN_PROGRAM_ADDRESS,
decimals: 6
},
PYUSD: {
mint: "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo",
program: TOKEN_2022_PROGRAM_ADDRESS,
decimals: 6
}
};

Token Extensions

Token Extensions Program(Token 2022)通过额外的指令(称为 extensions)为 Token 提供了更多功能。Extensions 是可选功能,你可以为 token mint 或 token account 添加这些扩展功能。

如需了解更多 Token Extensions 相关信息,请参阅 Token Extensions 文档。

费用

Solana 支付包含最多三项费用组成部分:

费用类型SOL估算美元发生时机
基础交易费5,000 lamports*~$0.0007每笔交易(可将多笔支付打包以摊销费用)
优先费浮动浮动可选;网络拥堵时可加速确认
账户创建(rent)~0.0029 SOL~$0.40仅在创建新 token account 时收取

每笔支付总成本:大多数转账低于 $0.001。如需创建新 token account,总费用约为 $0.40。

Solana 采用本地费用市场——每个程序的交易只与目标相同状态的其他交易竞争。这意味着即使在网络其他部分高负载时,支付费用依然低且可预测。rent 成本也计划在近期降低 50%

你可以完全抽象费用,让用户无需直接接触 SOL。实现方式请参见 Fee Abstraction

交易与指令

在 Solana 上,交易是原子执行单元——要么全部操作成功,要么全部失败。每笔交易包含一个或多个指令,每个指令都是独立命令(如“转账 10 USDC”,“创建 token account”)。

一次典型的支付交易可能包含两个指令:如有需要,先创建收款方的 token account,然后转账 token。两步操作原子执行——不会出现部分完成的状态。正如你将在 支付处理 中看到的,你可以将多笔支付打包进一笔交易,以降低成本并提升吞吐量。

综合流程

一个典型的支付流程:

  1. 收集信息。获取发送方和接收方的钱包地址,以及所转账代币的 mint 地址。
  2. 推导 ATA。确定双方的代币账户。
  3. 构建并签名。构建包含必要转账指令的交易,并用发送方密钥签名。
  4. 发送并确认。交易将在一秒内完成结算。

下一步


* lamport 是 SOL 的最小单位,等于 0.000000001 SOL

Is this page helpful?

Table of Contents

Edit Page

管理者

©️ 2026 Solana 基金会版权所有
取得联系