如果你在搭一个让用户连钱包提交交易的 Solana 前端,你会在钱包集成上花的时间比文档让你以为的多。Solana 钱包生态过得去、但不完美;SDK 帮你处理大部分活、但粗糙边角你不处理就会变成生产问题。
这篇我们讲正确集成 Solana 钱包要知道的事:SDK 选择、签名模式、交易提交,以及把"能跑"和"生产级"分开的那些细节。
"Solana 钱包 API"到底指什么
这词有几种不同含义:
- Wallet adapter SDK——让你前端连用户钱包(Phantom、Solflare、Backpack 等)、请求签名的库
- 钱包 provider API——钱包暴露的标准化接口(
window.solana这种),adapter 在它上面包一层 - 钱包操作的 RPC API——读余额、查代币持仓、查交易历史
这篇讲前两个。钱包相关的 RPC 细节大部分在 Solana RPC 开发者指南里。
SDK 全景
大多数前端集成的选择是 @solana/wallet-adapter。它处理:
- 多钱包检测(Phantom、Solflare、Backpack、Glow 等)
- 连接状态管理
- 交易签名请求
- 网络切换
React 前端的话,相关的包提供 hook:
import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import {
PhantomWalletAdapter,
SolflareWalletAdapter,
} from "@solana/wallet-adapter-wallets";
const wallets = [
new PhantomWalletAdapter(),
new SolflareWalletAdapter(),
];
function App() {
return (
<ConnectionProvider endpoint={RPC_URL}>
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>
<YourApp />
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
);
}
非 React 应用直接用底层的 @solana/wallet-adapter-base。
通过钱包发交易
两种模式:
模式 1:wallet adapter 帮你提交。
const tx = new Transaction().add(yourInstruction);
const signature = await sendTransaction(tx, connection, {
skipPreflight: true,
maxRetries: 0,
});
Wallet adapter 用你提供的 connection 签名提交。简单,大多数情况下行。
模式 2:分开签名,自己提交。
const tx = new Transaction().add(yourInstruction);
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.feePayer = publicKey;
const signed = await signTransaction(tx);
const signature = await connection.sendRawTransaction(signed.serialize(), {
skipPreflight: true,
maxRetries: 0,
});
这个模式给你提交侧的更多控制。要给发送用一个跟 wallet provider 不一样的 RPC、或者要在提交前 inspect/log 签名后的交易时,这个模式好用。
为什么经常想要两个不同的 RPC
很多生产应用用这个模式:读 RPC 一个(传给 ConnectionProvider),写 RPC 另一个(直接给 sendRawTransaction 用)。
理由:
- 读流量画像——高频、并行查询、经常缓存。要的是读量大场景下的吞吐量优化
- 写流量画像——需要亚秒级确认、Anti-MEV 保护关键、延迟敏感。要的是交易提交优化
两个用同一个 RPC 是妥协。各用对的能给到更好的用户体验(读 RPC 让 UI 更灵)和更好的经济模型(写 RPC 让被夹代价更低)。
const READ_RPC = "https://your-read-rpc.example/?api-key=...";
const WRITE_RPC = "https://bolttx.io/?api-key=...";
const readConnection = new Connection(READ_RPC, "confirmed");
const writeConnection = new Connection(WRITE_RPC, "processed");
// 给 provider 传 readConnection
<ConnectionProvider endpoint={READ_RPC}>...</ConnectionProvider>
// 直接用 writeConnection 发送
const signature = await writeConnection.sendRawTransaction(signed.serialize(), {
skipPreflight: true,
maxRetries: 0,
});
常见的钱包集成错误
硬编码一个 wallet adapter。 把用户锁死在一个钱包上。永远包含多个选项。
忽略连接失败。 wallet-adapter 在拒绝或没装时会抛错。包 try/catch、显示有意义的错误。
不处理网络不匹配。 用户在 devnet 但你 app 要 mainnet。检测到提示切换。
轮询钱包状态。 Hook 已经给你响应式状态了。别按间隔轮询 wallet.publicKey。
提交交易不确认。 钱包返回签名,但交易可能没上链。永远确认。
忘了 blockhash 新鲜度。 哪儿都一样的问题:陈旧 blockhash 静默失败。签前刷新。
不处理用户取消的情况。 一些钱包返回特定错误码;优雅处理(用户取消时别显示"交易失败")。
移动钱包集成
移动是另一回事。移动钱包用深链做交易签名——你的 dApp 通过深链打开钱包、钱包签、再跳回来。比桌面流程复杂:
- 构建交易
- 编码成钱包深链格式
- 打开深链
- 处理跳回时带的签名交易
- 自己提交签名后的交易
大多数团队用 Mobile Wallet Adapter (MWA) 把这层抽象掉。如果你做移动优先的 dApp,给这块预留时间——它跟桌面不一样。
不同 app 类型的常见模式
DEX UI / swap 接口。 读 RPC 拿 quote、wallet adapter 签、Anti-MEV 写 RPC 提交。给用户反馈展示成交价 vs 预期成交价。
NFT 市场。 读量大用来看列表;写流量给购买/挂单。两边都要可靠;读流量大头。
借贷 dApp。 混合读写。读必须准(别显示陈旧的抵押健康度)。写必须可靠确认。
代币 launchpad / IDO。 发币期间是突发写流量。写 RPC 在拥堵下的表现是关键——你最需要它的时刻,正是大多数服务商表现降级的时刻。
钱包 app 自己。 读量大,主要是余额/历史、偶尔写交易。读 RPC 质量主导用户感知。
这周可以做什么
搭钱包集成 dApp 的话:
- 设 wallet-adapter,带多个钱包选项。 至少 Phantom、Solflare、Backpack。
- 用分开的读写 RPC。 Provider 给读用,
sendRawTransaction给写用。 - 分开签名、自己提交。 给你提交路径的控制权。
- 提交后确认。 别信"签名返回了"等于"上链了"。
- 处理取消情况。 用户拒绝交易时别显示错误。
- 多钱包测试。 Phantom 和 Solflare 在细节行为上有微妙差别。
- 写侧加每笔签名级别的遥测。 跟踪用户实际体验。
在钱包 App 提交侧试一下 BoltTx
BoltTx 专门给钱包集成 dApp 的写侧做了优化:
- 亚秒级确认让用户体验更灵
- 原生 Anti-MEV 路由让用户的 swap 不被夹
- 专属 SWQoS + 优先级连接,拥堵下也能保证上链(高流量事件发生时尤其重要)
- 每笔签名级别的遥测给 debug 用户实际经历的事用
- Tip-based 计费跟成功的用户交易挂钩
集成:
import { Connection } from "@solana/web3.js";
const writeConnection = new Connection(
"https://bolttx.io/?api-key=YOUR_API_KEY",
"processed"
);
const signed = await wallet.signTransaction(tx);
const signature = await writeConnection.sendRawTransaction(signed.serialize(), {
skipPreflight: true,
maxRetries: 0,
});
免费档注册。配你自己挑的读 RPC。用真实用户交易模式跑一周。
常见问题
用 wallet-adapter 还是自己写? 用 wallet-adapter。自己写钱包检测是个泥潭,你不会想跳进去。
该支持哪些钱包? 最少 Phantom、Solflare。加 Backpack 和 Glow 覆盖大多数用户。移动加 Mobile Wallet Adapter。
用户在 devnet 但 app 要 mainnet 怎么处理? 通过 connection 的 genesis hash 检测,让用户在他们钱包里切换。别想用编程方式切。
消息签名做 auth 的对的方式是什么?
Wallet adapter 的 signMessage。后端生成 nonce、让用户签、后端验签名。
所有钱包都支持 signAllTransactions 吗?
大部分主流的支持;一些小钱包不。在你目标的钱包上测一下。
为什么交易显示"成功"但用户没拿到结果?
签名返回不等于上链。永远跟 connection 确认。发送后用 confirmTransaction。