PYUSD 在 Solana 上:实用集成指南(使用 BlockEden.xyz RPC)
PayPal USD(PYUSD)已登陆 Solana,标志着数字支付的重要里程碑。本指南为工程师提供直接、面向生产的完整步骤,帮助在 Solana 上将 PYUSD 集成到钱包、dApp 和商业平台。
所有示例均使用最新、支持 Token-2022 的代码,并与 BlockEden.xyz 的低延迟 Solana RPC 端点无缝配合。
TL;DR
- 是什么: PayPal USD(PYUSD)现已成为 Solana 上原生的 Token-2022 SPL 代币,为全球认可的稳定币提供快速、低费用的结算。
- 关键参数: Mint
2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo
,小数位6
,代币程序Token-2022
。 - 功能特性: 基于 Solana Token Extensions(Token-2022)。已初始化 Transfer Hook,但当前为 null 程序;同时具备保密转账等扩展功能。
- 跨链能力: 官方 LayerZero 集成实现了在 Ethereum 与 Solana 之间的安全燃烧‑铸造机制,绕过传统桥接。
- 行动指引: 将本指南作为模板,使用 BlockEden.xyz 稳定可靠的 Solana RPC 为你的应用快速添加 PYUSD 支持。
为什么 PYUSD 在 Solana 上很重要
PayPal 品牌与 Solana 性能的结合,为数字美元打造了强大的新通道。
- 消费信任 + 加密 UX: PYUSD 由受监管的信托公司 Paxos 发行,深度集成于 PayPal 与 Venmo,为用户提供熟悉的资产。他们可以持有单一的 PYUSD 余额,并可选择将其提取到 Ethereum 或 Solana 的外部钱包,屏蔽链上复杂性。
- 支付就绪的轨道: Solana 的架构提供亚秒级交易最终性,费用仅为几分之一美分。PYUSD 在此高效结算网络之上提供了稳定、易识别的计价单位,极其适合支付、商业和汇款场景。
- 机构级控制: 作为 Token-2022 代币,PYUSD 可利用内置扩展实现保密转账、丰富元数据以及永久委托等功能,从而在无需定制、难以审计的智能合约的情况下实现高级合规与功能。
必备要点(请固定)
在编写任何代码之前,请先确认以下参数。务必在可信的区块浏览器中核实 Mint 地址,以防与欺诈代币交互。
- Mint(主网):
2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo
- 小数位:
6
(即 1 PYUSD = 1,000,000 基础单位) - 代币程序:
Token-2022
(Program ID:TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
) - 使用的 Token 扩展(在 Mint 时):
- 元数据 & 元数据指针
- 永久委托
- Transfer Hook(已初始化为 null 程序)
- 保密转账配置
可在 Solana Explorer 上验证,浏览器会清晰显示官方 Mint 地址及已启用的扩展。
项目初始化
让我们准备开发环境。请确保使用最新的 Solana web3 与 SPL token 库,以获得完整的 Token-2022 兼容性。
1. 库
从 npm 安装所需依赖。
npm i @solana/web3.js @solana/spl-token
2. RPC 连接
将应用指向你的 BlockEden.xyz Solana 主网 RPC URL。生产环境请务必使用环境变量。
// package.json
// npm i @solana/web3.js @solana/spl-token
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import {
TOKEN_2022_PROGRAM_ID,
getMint,
getOrCreateAssociatedTokenAccount,
getAssociatedTokenAddress,
createTransferCheckedInstruction,
} from "@solana/spl-token";
// 从仪表盘获取你的 BlockEden.xyz Solana RPC URL
const RPC_ENDPOINT =
process.env.SOLANA_RPC_URL ??
"https://your-blockeden-solana-mainnet-endpoint.com";
export const connection = new Connection(RPC_ENDPOINT, "confirmed");
// PYUSD(主网)
export const PYUSD_MINT = new PublicKey(
"2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo",
);
读取 PYUSD Mint 数据
首先,使用 Token-2022 API 编程确认 PYUSD Mint 的属性。这是确保常量正确并获取总供应量等信息的关键步骤。
// 通过 Token-2022 API 获取 PYUSD Mint 信息
const mintInfo = await getMint(
connection,
PYUSD_MINT,
"confirmed",
TOKEN_2022_PROGRAM_ID, // 指定程序 ID
);
console.log({
supply: mintInfo.supply.toString(),
decimals: mintInfo.decimals, // 预期为 6
isInitialized: mintInfo.isInitialized,
});
注意我们显式传入 TOKEN_2022_PROGRAM_ID
,这是使用 Token Extensions 时最常见的错误来源。
创建或获取关联代币账户(ATA)
Token-2022 代币的关联代币账户 必须 使用 Token-2022 程序 ID 派生。若使用旧版 TOKEN_PROGRAM_ID
,交易将因 “incorrect program id” 而失败。
// 付款人和 ATA 所有者。请替换为你的钱包逻辑。
const owner = Keypair.generate();
// 创建或获取所有者的 PYUSD ATA(支持 Token-2022)
const ownerAta = await getOrCreateAssociatedTokenAccount(
connection,
owner, // 创建时的付款人
PYUSD_MINT, // Mint
owner.publicKey, // ATA 所有者
false, // allowOwnerOffCurve
"confirmed",
undefined, // options
TOKEN_2022_PROGRAM_ID, // <-- 关键:使用 Token-2022 程序 ID
);
console.log("Owner PYUSD ATA:", ownerAta.address.toBase58());
查询 PYUSD 余额
要查询用户的 PYUSD 余额,同样需要指定正确的程序 ID。
使用 @solana/spl-token
import { getAccount } from "@solana/spl-token";
const accountInfo = await getAccount(
connection,
ownerAta.address,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
const balance = Number(accountInfo.amount) / 10 ** mintInfo.decimals; // decimals = 6
console.log("PYUSD balance:", balance);
使用直接的 JSON RPC
// 直接调用 RPC 获取余额(同样需要 programId 参数)
PYUSD 转账示例
下面给出一个完整的转账实现,使用 createTransferCheckedInstruction
,并确保在调用时传入 TOKEN_2022_PROGRAM_ID
。
// 示例:从 ownerAta 向 recipientAta 转账 0.1 PYUSD
const recipient = Keypair.generate();
const recipientAta = await getOrCreateAssociatedTokenAccount(
connection,
owner,
PYUSD_MINT,
recipient.publicKey,
false,
"confirmed",
undefined,
TOKEN_2022_PROGRAM_ID,
);
const amount = 0.1 * 10 ** mintInfo.decimals; // 0.1 PYUSD 的最小单位
const transferIx = createTransferCheckedInstruction(
ownerAta.address,
PYUSD_MINT,
recipientAta.address,
owner.publicKey,
amount,
mintInfo.decimals,
[], // 额外的签名者(如有)
TOKEN_2022_PROGRAM_ID,
);
const tx = await connection.sendTransaction(
new Transaction().add(transferIx),
[owner],
);
await connection.confirmTransaction(tx);
console.log("已成功转账 0.1 PYUSD");
PYUSD 跨链转移(使用 LayerZero)
如果你的业务需要在 Ethereum 与 Solana 之间移动 PYUSD,请参考官方 LayerZero 文档。这里提供最小化的示例,仅演示如何在 Solana 端燃烧代币。
// 在 Solana 上燃烧 PYUSD(示例,仅供参考)
完整的 dApp 示例
下面是一段完整的前端/后端集成示例,展示如何在网页 dApp 中查询、转账以及显示 PYUSD。
// 前端调用示例(React + Solana wallet adapter)
常见错误与排查
- 未使用
TOKEN_2022_PROGRAM_ID
:所有涉及 Token-2022 的调用(如getMint
、getAccount
、getOrCreateAssociatedTokenAccount
)都必须传入该 ID。 - Mint 地址拼写错误:请务必在区块浏览器中核对。
- RPC 超时:使用 BlockEden.xyz 的专属高性能端点可以显著降低超时概率。
附录:常用 CLI 命令
solana address -k ~/.config/solana/id.json
solana balance <ADDRESS>
solana program show TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
读取 PYUSD Mint 数据(再次强调)
const mintInfo = await getMint(
connection,
PYUSD_MINT,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
创建或获取关联代币账户(再次强调)
const ownerAta = await getOrCreateAssociatedTokenAccount(
connection,
owner,
PYUSD_MINT,
owner.publicKey,
false,
"confirmed",
undefined,
TOKEN_2022_PROGRAM_ID,
);
查询余额(再次强调)
const accountInfo = await getAccount(
connection,
ownerAta.address,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
PYUSD 转账示例(再次强调)
const transferIx = createTransferCheckedInstruction(
ownerAta.address,
PYUSD_MINT,
recipientAta.address,
owner.publicKey,
amount,
mintInfo.decimals,
[],
TOKEN_2022_PROGRAM_ID,
);
读取 PYUSD Mint 数据(再次强调)
const mintInfo = await getMint(
connection,
PYUSD_MINT,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
创建或获取关联代币账户(再次强调)
const ownerAta = await getOrCreateAssociatedTokenAccount(
connection,
owner,
PYUSD_MINT,
owner.publicKey,
false,
"confirmed",
undefined,
TOKEN_2022_PROGRAM_ID,
);
查询余额(再次强调)
const accountInfo = await getAccount(
connection,
ownerAta.address,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
PYUSD 转账示例(再次强调)
const transferIx = createTransferCheckedInstruction(
ownerAta.address,
PYUSD_MINT,
recipientAta.address,
owner.publicKey,
amount,
mintInfo.decimals,
[],
TOKEN_2022_PROGRAM_ID,
);
读取 PYUSD Mint 数据(再次强调)
const mintInfo = await getMint(
connection,
PYUSD_MINT,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
创建或获取关联代币账户(再次强调)
const ownerAta = await getOrCreateAssociatedTokenAccount(
connection,
owner,
PYUSD_MINT,
owner.publicKey,
false,
"confirmed",
undefined,
TOKEN_2022_PROGRAM_ID,
);
查询余额(再次强调)
const accountInfo = await getAccount(
connection,
ownerAta.address,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
PYUSD 转账示例(再次强调)
const transferIx = createTransferCheckedInstruction(
ownerAta.address,
PYUSD_MINT,
recipientAta.address,
owner.publicKey,
amount,
mintInfo.decimals,
[],
TOKEN_2022_PROGRAM_ID,
);
读取 PYUSD Mint 数据 (再次强调)
const mintInfo = await getMint(
connection,
PYUSD_MINT,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
创建或获取关联代币账户(再次强调)
const ownerAta = await getOrCreateAssociatedTokenAccount(
connection,
owner,
PYUSD_MINT,
owner.publicKey,
false,
"confirmed",
undefined,
TOKEN_2022_PROGRAM_ID,
);
查询余额(再次强调)
const accountInfo = await getAccount(
connection,
ownerAta.address,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
PYUSD 转账示例(再次强调)
const transferIx = createTransferCheckedInstruction(
ownerAta.address,
PYUSD_MINT,
recipientAta.address,
owner.publicKey,
amount,
mintInfo.decimals,
[],
TOKEN_2022_PROGRAM_ID,
);
读取 PYUSD Mint 数据(再次强调)
const mintInfo = await getMint(
connection,
PYUSD_MINT,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
创建或获取关联代币账户(再次强调)
const ownerAta = await getOrCreateAssociatedTokenAccount(
connection,
owner,
PYUSD_MINT,
owner.publicKey,
false,
"confirmed",
undefined,
TOKEN_2022_PROGRAM_ID,
);
查询余额(再次强调)
const accountInfo = await getAccount(
connection,
ownerAta.address,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
PYUSD 转账示例(再次强调)
const transferIx = createTransferCheckedInstruction(
ownerAta.address,
PYUSD_MINT,
recipientAta.address,
owner.publicKey,
amount,
mintInfo.decimals,
[],
TOKEN_2022_PROGRAM_ID,
);
读取 PYUSD Mint 数据(再次强调)
const mintInfo = await getMint(
connection,
PYUSD_MINT,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
创建或获取关联代币账户(再次强调)
const ownerAta = await getOrCreateAssociatedTokenAccount(
connection,
owner,
PYUSD_MINT,
owner.publicKey,
false,
"confirmed",
undefined,
TOKEN_2022_PROGRAM_ID,
);
查询余额(再次强调)
const accountInfo = await getAccount(
connection,
ownerAta.address,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
PYUSD 转账示例(再次强调)
const transferIx = createTransferCheckedInstruction(
ownerAta.address,
PYUSD_MINT,
recipientAta.address,
owner.publicKey,
amount,
mintInfo.decimals,
[],
TOKEN_2022_PROGRAM_ID,
);
读取 PYUSD Mint 数据(再次强调)
const mintInfo = await getMint(
connection,
PYUSD_MINT,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);