Paket @solana-commerce/sdk menyediakan hook React untuk membangun pengalaman
pembayaran Solana kustom. Hook ini menawarkan kontrol penuh atas transfer SOL
dan token SPL dengan manajemen state bawaan, logika retry otomatis, penanganan
error, dan helper UI.
Di balik layar, SDK menggunakan TanStack Query
untuk caching dan manajemen state,
@solana/kit untuk primitif Solana, dan
terintegrasi dengan mulus dengan @solana-commerce/connector untuk koneksi
wallet.
Instalasi
pnpm add @solana-commerce/sdk
Pengaturan Provider
ArcProvider
ArcProvider adalah provider root yang menginisialisasi klien RPC Solana,
mengelola konfigurasi jaringan, dan menyediakan konektivitas blockchain ke semua
hook. Provider ini harus membungkus semua komponen yang menggunakan hook SDK.
Props
config(ArcWebClientConfig) - Objek konfigurasi untuk klien Arcchildren(ReactNode) - Komponen anak yang akan memiliki akses ke hookqueryClient(QueryClient, opsional) - Klien TanStack Query kustom. Jika tidak disediakan, instance default dibuat secara internal.
ArcWebClientConfig
Konfigurasi untuk klien Arc yang mengontrol konektivitas RPC dan tingkat commitment.
Field Wajib
Provider secara otomatis terintegrasi dengan @solana-commerce/connector
melalui hook useConnectorClient, sehingga tidak diperlukan konfigurasi
connector eksplisit ketika digunakan dalam ConnectorProvider.
Field Opsional
-
network('mainnet' | 'devnet' | 'testnet') - Jaringan Solana yang akan dihubungkan. Default:'mainnet'. -
rpcUrl(string) - URL endpoint RPC kustom. Jika tidak disediakan, menggunakan endpoint publik untuk jaringan yang dipilih. -
commitment('processed' | 'confirmed' | 'finalized') - Tingkat konfirmasi transaksi. Default:'confirmed'. -
debug(boolean) - Mengaktifkan logging konsol verbose untuk debugging. Default:false. -
autoConnect(boolean) - Otomatis terhubung ke wallet saat komponen dimuat. Default:true. -
storage(Storage) - Adaptor penyimpanan khusus untuk mempertahankan preferensi dompet. Harus mengimplementasikan:getItem(key: string): string | nullsetItem(key: string, value: string): voidremoveItem(key: string): void
Bawaan:
window.localStoragebila tersedia (hanya browser). Gunakan ini untuk React Native (AsyncStorage) atau penyimpanan khusus yang aman untuk SSR.
Integrasi dengan ConnectorProvider
Penyedia terintegrasi dengan ConnectorProvider dari
@solana-commerce/connector. Selalu bungkus aplikasi Anda dengan
ConnectorProvider sebelum ArcProvider:
import { ConnectorProvider } from "@solana-commerce/connector";import { ArcProvider } from "@solana-commerce/sdk";function App() {return (<ConnectorProvider config={{ autoConnect: true }}><ArcProvider config={{ network: "mainnet", commitment: "confirmed" }}><YourApp /></ArcProvider></ConnectorProvider>);}
Hook Inti
useTransferSOL
Hook untuk mentransfer SOL dengan logika percobaan ulang otomatis, manajemen status, dan fungsi bantuan UI. Dibangun di atas TanStack Query untuk caching dan deduplikasi permintaan.
Signature
function useTransferSOL(initialToInput?: string,initialAmountInput?: string): UseTransferSOLReturn;
Parameter
initialToInput(string, opsional) - Nilai awal untuk input alamat penerima. Berguna untuk mengisi formulir sebelumnya.initialAmountInput(string, opsional) - Nilai awal untuk input jumlah dalam SOL. Berguna untuk mengisi formulir sebelumnya.
Nilai Kembalian
interface UseTransferSOLReturn {// Core transfer functiontransferSOL: (options: TransferSOLOptions) => Promise<TransferSOLResult>;// StateisLoading: boolean;error: Error | null;data: TransferSOLResult | null;reset: () => void;// UI HelperstoInput: string;amountInput: string;setToInput: (value: string) => void;setAmountInput: (value: string) => void;handleToInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;handleAmountInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;handleSubmit: (event?: {preventDefault?: () => void;}) => Promise<TransferSOLResult | undefined>;transferFromInputs: () => Promise<TransferSOLResult | undefined>;}
Fungsi Inti
transferSOL- Memulai transfer SOL. Mengembalikan promise yang terpenuhi ketika transaksi dikonfirmasi on-chain.
Properti Status
-
isLoading(boolean) -truesaat transaksi sedang diproses (penandatanganan, pengiriman, konfirmasi). Gunakan ini untuk indikator loading dan status tombol. -
error(Error | null) - Objek error jika transaksi gagal pada tahap mana pun.nullketika tidak ada error. Error termasuk penolakan dompet, saldo tidak cukup, kegagalan jaringan, dll. -
data(TransferSOLResult | null) - Objek hasil ketika transaksi berhasil. Berisi signature, alamat, jumlah, dan metadata blockchain.nullsebelum transfer berhasil pertama kali. -
reset(() => void) - Mereset status mutasi, menghapuserrordandata. Berguna untuk alur percobaan ulang atau mereset formulir setelah selesai.
Properti & Metode Bantuan UI
Hook ini menyediakan manajemen status bawaan untuk input formulir:
-
toInput/setToInput- State terkontrol untuk kolom input alamat penerima -
amountInput/setAmountInput- State terkontrol untuk kolom input jumlah (dalam SOL, bukan lamport) -
handleToInputChange- Handler onChange yang telah diikat sebelumnya untuk input penerima:<input onChange={handleToInputChange} /> -
handleAmountInputChange- Handler onChange yang telah diikat sebelumnya untuk input jumlah:<input onChange={handleAmountInputChange} /> -
transferFromInputs- Metode praktis yang mentransfer SOL menggunakan nilaitoInputdanamountInputsaat ini. Secara otomatis mengonversi jumlah dari SOL ke lamport. -
handleSubmit- Handler pengiriman formulir yang memanggiltransferFromInputs()dan mencegah perilaku formulir default. Gunakan dengan<form onSubmit={handleSubmit}>.
Opsi
interface TransferSOLOptions {to: string | Address; // Recipient wallet addressamount: bigint; // Amount in lamports (1 SOL = 1,000,000,000 lamports)from?: string | Address; // Optional sender address (defaults to connected wallet)}
-
to(wajib) - Alamat Solana penerima. Dapat berupa string atau tipeAddressdari@solana/kit. -
amount(wajib) - Jumlah transfer dalam lamport (bukan SOL). Harus berupabigint. GunakanBigInt()atau notasi literal:1_000_000_000n= 1 SOL. -
from(opsional) - Alamat pengirim. Jika tidak disediakan, menggunakan alamat dari dompet yang terhubung. Hanya diperlukan untuk kasus penggunaan lanjutan (misalnya, menandatangani untuk akun yang berbeda).
Hasil
Hasil mencakup metadata transaksi termasuk detail transfer dan tanda tangan transaksi:
interface TransferSOLResult {signature: string; // Transaction signature (base58)amount: bigint; // Amount transferred in lamportsfrom: Address; // Sender addressto: Address; // Recipient addressblockTime?: number; // Unix timestamp when transaction was processedslot?: number; // Slot number where transaction was confirmed}
Arsitektur Internal
Pembuat Transaksi: Hook menggunakan pembuat transaksi bersama yang:
- Mengambil blockhash segar untuk setiap transaksi
- Membangun pesan transaksi yang dioptimalkan dengan biaya minimal
- Menandatangani transaksi menggunakan dompet yang terhubung
- Mengirim dan mengonfirmasi transaksi dalam satu alur
Pembatalan Cache: Pada transfer yang berhasil, hook secara otomatis membatalkan cache TanStack Query untuk:
- Saldo pengirim (alamat
from) - Saldo penerima (alamat
to)
Ini memastikan bahwa komponen apa pun yang menampilkan saldo (misalnya, melalui
useArcClient) secara otomatis mengambil ulang dan memperbarui tanpa intervensi
manual.
Konversi Jumlah yang Presisi: Saat menggunakan transferFromInputs(),
jumlahnya dikonversi dari SOL ke lamport menggunakan aritmatika berbasis string
untuk menghindari error presisi floating-point. Konversinya:
- Memvalidasi format input (menolak angka negatif atau tidak valid)
- Menangani hingga 9 angka desimal (1 lamport = 0,000000001 SOL)
- Memotong atau mengisi nilai pecahan sesuai kebutuhan
- Menampilkan error deskriptif untuk input yang tidak valid
useTransferToken
Seperti useTransferSOL, hook ini digunakan untuk mentransfer token SPL. Selain
menangani transfer, hook ini juga menangani pembuatan Associated Token Account
(ATA) otomatis saat diperlukan.
Signature
function useTransferToken(initialMintInput?: string,initialToInput?: string,initialAmountInput?: string): UseTransferTokenReturn;
Parameter
initialMintInput(string, opsional) - Alamat mint token awal. Berguna untuk transfer token tetap.initialToInput(string, opsional) - Alamat penerima awal.initialAmountInput(string, opsional) - Jumlah awal dalam unit dasar token (mempertimbangkan desimal).
Nilai Kembalian
interface UseTransferTokenReturn {// Core transfer functiontransferToken: (options: TransferTokenOptions) => Promise<TransferTokenResult>;// StateisLoading: boolean;error: Error | null;data: TransferTokenResult | null;reset: () => void;// UI HelpersmintInput: string;toInput: string;amountInput: string;setMintInput: (value: string) => void;setToInput: (value: string) => void;setAmountInput: (value: string) => void;handleMintInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;handleToInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;handleAmountInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;handleSubmit: (event?: {preventDefault?: () => void;}) => Promise<TransferTokenResult | undefined>;transferFromInputs: () => Promise<TransferTokenResult | undefined>;}
Nilai kembaliannya mirip dengan useTransferSOL tetapi mencakup state
mintInput tambahan untuk pemilihan token.
Opsi
interface TransferTokenOptions {mint: string | Address; // Token mint addressto: string | Address; // Recipient wallet addressamount: bigint; // Amount in token's smallest unitfrom?: string | Address; // Optional sender (defaults to connected wallet)createAccountIfNeeded?: boolean; // Auto-create recipient's ATA (default: true)retryConfig?: TransferRetryConfig; // Optional retry configuration}
Field Wajib
-
mint- Alamat mint token SPL. Contohnya:- USDC:
'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' - USDT:
'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'
- USDC:
-
to- Alamat wallet penerima (bukan akun token mereka). Hook secara otomatis menurunkan Associated Token Account yang benar. -
amount- Jumlah transfer dalam unit terkecil token. Harus mempertimbangkan desimal token:- USDC (6 desimal):
1_000_000n= 1 USDC - Token yang dibungkus SOL (9 desimal):
1_000_000_000n= 1 token
- USDC (6 desimal):
Field Opsional
-
from- Alamat wallet pengirim. Default ke wallet yang terhubung. -
createAccountIfNeeded(default:true) - Jika penerima tidak memiliki akun token untuk mint ini, secara otomatis membuatnya sebagai bagian dari transaksi. Saatfalse, transfer akan gagal jika akun penerima tidak ada.Catatan: Membuat akun token memerlukan biaya ~0,00203 SOL. Biaya ini dibayar oleh pengirim.
-
retryConfig- Konfigurasi untuk percobaan ulang otomatis saat blockhash kedaluwarsa. Lihat Konfigurasi Percobaan Ulang.
Hasil
Hasil mencakup metadata transaksi termasuk detail transfer dan tanda tangan transaksi:
interface TransferTokenResult {signature: string; // Transaction signaturemint: Address; // Token mint addressamount: bigint; // Amount transferredfrom: Address; // Sender wallet addressto: Address; // Recipient wallet addressfromTokenAccount: Address; // Sender's token accounttoTokenAccount: Address; // Recipient's token accountcreatedAccount?: boolean; // Whether recipient's ATA was createdblockTime?: number; // Transaction timestampslot?: number; // Block slot number}
Konfigurasi Percobaan Ulang
Hook ini dilengkapi dengan logika percobaan ulang yang canggih untuk menangani kedaluwarsa blockhash, yang umumnya terjadi saat jaringan mengalami kemacetan.
interface TransferRetryConfig {maxAttempts?: number; // Max retry attempts (default: 3)baseDelay?: number; // Base delay in ms (default: 1000)backoffMultiplier?: number; // Backoff multiplier (default: 1)}
-
maxAttempts- Jumlah maksimum percobaan transaksi. Setiap percobaan mengambil blockhash yang baru. Default:3. -
baseDelay- Jeda dalam milidetik sebelum percobaan ulang pertama. Default:1000(1 detik). -
backoffMultiplier- Pengali backoff eksponensial. Setiap percobaan ulang menunggubaseDelay * (backoffMultiplier ^ attemptNumber)milidetik.1= backoff linear (1d, 1d, 1d)1.5= backoff eksponensial (1d, 1,5d, 2,25d)2= eksponensial agresif (1d, 2d, 4d)
Cara Kerja Percobaan Ulang:
- Percobaan Pertama: Transaksi dibangun dengan blockhash saat ini dan dikirim
- Blockhash Kedaluwarsa: Jika blockhash menjadi usang sebelum konfirmasi, Solana menolak transaksi
- Percobaan Ulang Otomatis: Hook mendeteksi kedaluwarsa, mengambil blockhash baru, membangun ulang transaksi, dan mengirim kembali
- Backoff Eksponensial: Setiap percobaan ulang menunggu lebih lama untuk menghindari kemacetan jaringan
- Kegagalan Akhir: Setelah
maxAttempts, melemparBlockhashExpirationErrordengan konteks
Kapan Percobaan Ulang Tidak Dipicu:
- Error non-blockhash (dana tidak mencukupi, akun tidak valid, dll.) langsung melempar kesalahan tanpa mencoba ulang
- Hanya error kedaluwarsa blockhash yang memicu mekanisme percobaan ulang
Arsitektur Internal
Pengelolaan ATA:
- Menurunkan Associated Token Account secara deterministik menggunakan
findAssociatedTokenPda(Catatan: hanya Token Program yang didukung saat ini) - Memeriksa apakah pengirim memiliki token account (gagal cepat jika pengirim tidak memiliki token)
- Memeriksa apakah penerima memiliki token account (membuat jika diperlukan dan
createAccountIfNeeded: true) - Pemeriksaan akun hanya berjalan pada percobaan pertama untuk menghindari panggilan RPC yang berlebihan selama percobaan ulang
Pembatalan Cache: Saat berhasil, membatalkan cache TanStack Query untuk:
- Saldo token pengirim untuk mint ini
- Saldo token penerima untuk mint ini
- Data akun terkait
Ini menjaga semua komponen UI yang menampilkan saldo tetap sinkron secara otomatis.
useArcClient
Hook untuk mengakses klien RPC Solana yang mendasarinya, status wallet, dan konfigurasi jaringan. Ini adalah hook tingkat rendah untuk kasus penggunaan lanjutan yang memerlukan akses RPC langsung.
Signature
function useArcClient(): ArcClientSnapshot;
Nilai Kembalian
interface ArcClientSnapshot {// Wallet Statewallet: {address: Address | null;signer: TransactionSigner | null;};// Network Configurationnetwork: {cluster: "mainnet" | "devnet" | "testnet";rpcUrl: string;};// Client Configurationconfig: ArcWebClientConfig;// Actionsselect: (walletName: string) => Promise<void>;disconnect: () => Promise<void>;selectAccount: (accountAddress: Address) => Promise<void>;}
State
ArcClientSnapshot memperluas ArcWebClient yang menyediakan akses ke:
- status wallet (alamat, penandatangan, wallet yang tersedia, fitur, dan status wallet)
- konfigurasi jaringan (endpoint RPC, cluster Solana)
Kasus Penggunaan
Query RPC Langsung:
import { useArcClient } from "@solana-commerce/sdk";import { getSharedRpc } from "@solana-commerce/sdk/core/rpc-manager";import { address } from "@solana/kit";function AccountBalance() {const { network, wallet } = useArcClient();const [balance, setBalance] = useState<bigint | null>(null);useEffect(() => {if (!wallet.address) return;const rpc = getSharedRpc(network.rpcUrl);async function fetchBalance() {const result = await rpc.getBalance(wallet.address).send();setBalance(result);}fetchBalance();}, [wallet.address, network.rpcUrl]);if (!wallet.address) return <div>Connect wallet to see balance</div>;return <div>Balance: {(Number(balance) / 1e9).toFixed(4)} SOL</div>;}
Komponen yang Sadar Jaringan:
function NetworkIndicator() {const { network } = useArcClient();return (<div><span>Network: {network.cluster}</span>{network.canAirdrop && <button onClick={handleAirdrop}>Airdrop</button>}</div>);}
Rendering Kondisional Berdasarkan Wallet:
function SendButton() {const { wallet } = useArcClient();const { transferSOL, isLoading } = useTransferSOL();if (!wallet.address) {return <div>Connect wallet to send SOL</div>;}return (<buttononClick={() =>transferSOL({to: "recipient-address",amount: BigInt(1_000_000_000)})}disabled={isLoading}>{isLoading ? "Sending..." : "Send 1 SOL"}</button>);}
Is this page helpful?