錢包 SDK
瞭解如何使用 @stableops/wallet-sdk,讓使用者透過自託管的 EVM、TRON 或 Solana 錢包完成鏈上付款;文件覆蓋付款指令解析、網路切換、代幣轉帳、交易結果處理和安全邊界,並說明前端 SDK 與伺服器端訂單介面的配合方式。
@stableops/wallet-sdk 是僅瀏覽器使用的前端庫:把後端建立訂單時返回的
paymentInstructions 交給使用者的錢包,發起一筆鏈上轉帳到該訂單的指定收款地址。
冪等、地址分配、鏈上掃描、確認數、Webhook 全部仍由 StableOps 後端負責;錢包 SDK 只做一件事:讓使用者把錢轉到正確的地址。
STABLEOPS_API_KEY。訂單建立必須在後端完成,前端只接收訂單 id、amount 和 paymentInstructions。安裝
pnpm add @stableops/wallet-sdk需要支援 fetch 和 EIP-1193 / TronLink / Solana 錢包介面卡的瀏覽器環境。
WalletConnect 為可選能力,依賴在用到時再裝(見下文)。
想看可執行的完整示例?
快速開始(注入式錢包)
getInjectedWalletProviders() 收集頁面裡已注入的錢包(MetaMask、TronLink、Phantom 等),
sendOrderWalletPayment() 自動從訂單候選裡挑一條「有可用錢包」的鏈併發起轉帳。
import { getInjectedWalletProviders, sendOrderWalletPayment } from '@stableops/wallet-sdk'
const sent = await sendOrderWalletPayment({
order, // { amount, paymentInstructions },來自後端
providers: getInjectedWalletProviders(),
})
console.log(sent.txHash)可用 preferredChains 指定優先嚐試的鏈順序:
await sendOrderWalletPayment({
order,
providers: getInjectedWalletProviders(),
preferredChains: ['base', 'arbitrum'],
})手動選擇候選指令
需要自己控制「選哪條鏈」時,先用 selectWalletPaymentInstruction() 選中,
再呼叫底層的 sendWalletPayment():
import {
getInjectedWalletProviders,
selectWalletPaymentInstruction,
sendWalletPayment,
} from '@stableops/wallet-sdk'
const { instruction, provider } = selectWalletPaymentInstruction(
order.paymentInstructions,
getInjectedWalletProviders(),
['base'], // 可選:優先鏈
)
const sent = await sendWalletPayment({
provider,
instruction,
amount: order.amount,
})
console.log(sent.txHash)WalletConnect(移動端 / 自定義 UI)
移動端瀏覽器或沒有注入 EVM provider 的頁面,可以接入可選的 WalletConnect 執行時。 SDK 不內建 UI、也不維護錢包列表:錢包選項由你傳入,介面透過訂閱 controller 的 state 自行渲染(錢包列表、二維碼、連線中 / 失敗狀態)。
pnpm add @walletconnect/universal-providerimport { createWalletConnectController, sendOrderWalletPayment } from '@stableops/wallet-sdk'
const wc = await createWalletConnectController({
projectId: 'YOUR_REOWN_PROJECT_ID',
metadata: {
name: 'Your App',
description: 'StableOps checkout',
url: window.location.origin,
icons: [`${window.location.origin}/icon.png`],
},
// 啟用的名稱空間(按需取捨)
chains: ['base', 'arbitrum'], // EVM
solanaChains: ['solana'], // Solana
tronChains: ['tron'], // TRON
wallets: [
{
id: 'metamask',
name: 'MetaMask',
links: { native: 'metamask://', universal: 'https://metamask.app.link' },
},
],
})
const unsubscribe = wc.subscribe((state) => {
// 按 state.status 渲染:'idle' | 'connecting' | 'uri_ready' | 'connected' | 'failed' | 'disconnected'
// state.status === 'uri_ready' 時,用 state.uri 生成二維碼。
})
await wc.connect({ walletId: 'metamask' })
const sent = await sendOrderWalletPayment({
order,
providers: wc.providers, // 把 controller 的 providers 直接交給傳送函式
})
unsubscribe()
console.log(sent.txHash)EVM、Solana、TRON 三類名稱空間都可經 WalletConnect 走通:
- EVM:行為與注入式一致。
- Solana:取決於錢包是否支援
solana_signTransaction/solana_signAndSendTransaction; 自定義 RPC / devnet 流程需要solana_signTransaction。 - TRON:錢包只做
tron_signTransaction簽名,交易構造與廣播由 SDK 用 tronweb 完成 (預設 trongrid 公共節點,可用tronRpcUrl覆蓋)。
返回值:SentWalletPayment
sendWalletPayment 與 sendOrderWalletPayment 都返回:
{
txHash: string
chain: ChainId
asset: 'USDC' | 'USDT'
fromAddress: string
toAddress: string
tokenContract: string
amount: string // 人類可讀金額,如 '49.00'
amountUnits: string // 最小單位整數字符串
confirmation: Promise<void>
}confirmation 是 best-effort 參考訊號,不阻塞函式返回(交易廣播後在後台查詢):
- resolve:交易已上鍊且合約執行成功(或超時 ~90s 後 best-effort 放行)。
- reject(
code: 'wallet_tx_reverted'):鏈上 revert,沒有代幣轉出(如餘額不足)。 設計目的是儘早捕獲「立即 revert」,避免使用者久等才發現失敗。
sent.confirmation.catch((err) => {
// err.code === 'wallet_tx_reverted'
})detected / confirmed,一律以伺服器端為準,忽略 confirmation 的 reject。支援的鏈
| 鏈 | 走法 |
|---|---|
ethereum base arbitrum polygon optimism bsc(及各自測試網 *-sepolia / polygon-amoy / bsc-testnet) | 呼叫 EIP-1193 錢包,必要時切鏈 / 新增網路,傳送 ERC-20 transfer。可用 chainConfigs 覆蓋 RPC / 瀏覽器地址。 |
tron tron-nile | 呼叫 TronLink / TronWeb(或 WalletConnect TRON),構造、簽名並廣播 TRC-20 transfer。測試網或自建節點傳 tronRpcUrl。 |
solana solana-devnet | 呼叫 Solana 錢包介面卡,冪等建立收款方關聯 token account,傳送 SPL Token TransferChecked。devnet 傳 solanaRpcUrl: 'https://api.devnet.solana.com'(或等價節點)。 |
錯誤處理
所有失敗都會拋 StableOpsWalletError,帶 .code、.message、可選 .details。
import { StableOpsWalletError } from '@stableops/wallet-sdk'
try {
await sendOrderWalletPayment({ order, providers: getInjectedWalletProviders() })
} catch (err) {
if (err instanceof StableOpsWalletError && err.code === 'wallet_user_rejected') {
// 使用者在錢包裡取消了
}
throw err
}常見 code:
| code | 含義 |
|---|---|
payment_instruction_not_found | 訂單沒有可支付的鏈上指令 |
wallet_provider_not_found | 所有候選鏈都沒有可用錢包 provider |
wallet_user_rejected | 使用者在錢包裡拒絕簽名 |
wallet_tx_reverted | 鏈上 revert(多由 confirmation reject 丟擲) |
unsupported_chain | 該鏈不被錢包助手支援 |
chain_config_not_found | 缺少對應 EVM 鏈設定(傳 chainConfigs 補充) |
invalid_amount / invalid_evm_address / invalid_tron_address / invalid_solana_address | 入參非法 |
tron_dependency_missing / solana_dependency_missing | 缺少 TRON / Solana 執行依賴 |
除錯
開啟模組級除錯日誌(字首 [wallet-sdk])便於排查:
import { setWalletSdkDebug } from '@stableops/wallet-sdk'
setWalletSdkDebug(true)也可不改程式碼臨時開啟:瀏覽器控制台設 globalThis.STABLEOPS_WALLET_DEBUG = true,
或建置時注入環境變數 WALLET_SDK_DEBUG=1。
這篇文件怎麼樣?
最後更新