Pakiet @solana-commerce/sdk udostępnia hooki React do tworzenia
niestandardowych doświadczeń płatniczych w Solana. Te hooki oferują pełną
kontrolę nad transferami SOL i tokenów SPL z wbudowanym zarządzaniem stanem,
automatyczną logiką ponawiania prób, obsługą błędów i pomocnikami interfejsu
użytkownika.
Pod maską SDK wykorzystuje TanStack Query do
cachowania i zarządzania stanem, @solana/kit
do prymitywów Solana i bezproblemowo integruje się z
@solana-commerce/connector w celu połączenia z portfelem.
Instalacja
pnpm add @solana-commerce/sdk
Konfiguracja Providera
ArcProvider
ArcProvider jest głównym providerem, który inicjalizuje klienta RPC Solana,
zarządza konfiguracją sieci i zapewnia łączność z blockchainem dla wszystkich
hooków. Musi owijać wszystkie komponenty, które używają hooków SDK.
Właściwości
config(ArcWebClientConfig) - Obiekt konfiguracyjny dla klienta Arcchildren(ReactNode) - Komponenty potomne, które będą miały dostęp do hookówqueryClient(QueryClient, opcjonalne) - Niestandardowy klient TanStack Query. Jeśli nie zostanie podany, wewnętrznie tworzona jest domyślna instancja.
ArcWebClientConfig
Konfiguracja dla klienta Arc, która kontroluje łączność RPC i poziomy zatwierdzenia.
Wymagane Pola
Provider automatycznie integruje się z @solana-commerce/connector poprzez hook
useConnectorClient, więc nie jest potrzebna jawna konfiguracja konektora
podczas użycia wewnątrz ConnectorProvider.
Pola Opcjonalne
-
network('mainnet' | 'devnet' | 'testnet') - Sieć Solana, z którą należy się połączyć. Domyślnie:'mainnet'. -
rpcUrl(string) - Niestandardowy adres URL punktu końcowego RPC. Jeśli nie zostanie podany, używa publicznych punktów końcowych dla wybranej sieci. -
commitment('processed' | 'confirmed' | 'finalized') - Poziom potwierdzenia transakcji. Domyślnie:'confirmed'. -
debug(boolean) - Włącza szczegółowe logowanie w konsoli do debugowania. Domyślnie:false. -
autoConnect(boolean) - Automatycznie łączy się z portfelem po zamontowaniu komponentu. Domyślnie:true. -
storage(Storage) - Niestandardowy adapter przechowywania dla utrwalania preferencji portfela. Musi implementować:getItem(key: string): string | nullsetItem(key: string, value: string): voidremoveItem(key: string): void
Domyślnie:
window.localStoragegdy dostępny (tylko przeglądarka). Użyj tego dla React Native (AsyncStorage) lub niestandardowego przechowywania kompatybilnego z SSR.
Integracja z ConnectorProvider
Provider integruje się z ConnectorProvider z @solana-commerce/connector.
Zawsze owijaj swoją aplikację za pomocą ConnectorProvider przed 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>);}
Podstawowe Hooki
useTransferSOL
Hook do przesyłania SOL z automatyczną logiką ponownych prób, zarządzaniem stanem i funkcjami pomocniczymi UI. Zbudowany na TanStack Query dla cachowania i deduplikacji żądań.
Sygnatura
function useTransferSOL(initialToInput?: string,initialAmountInput?: string): UseTransferSOLReturn;
Parametry
initialToInput(string, opcjonalny) - Wartość początkowa dla pola adresu odbiorcy. Przydatny do wstępnego wypełniania formularzy.initialAmountInput(string, opcjonalny) - Wartość początkowa dla pola kwoty w SOL. Przydatny do wstępnego wypełniania formularzy.
Zwracana Wartość
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>;}
Funkcja Główna
transferSOL- Inicjuje transfer SOL. Zwraca obietnicę, która jest rozwiązywana, gdy transakcja zostanie potwierdzona w blockchainie.
Właściwości Stanu
-
isLoading(boolean) -truepodczas przetwarzania transakcji (podpisywanie, przesyłanie, potwierdzanie). Użyj tego dla wskaźników ładowania i stanów przycisków. -
error(Error | null) - Obiekt błędu, jeśli transakcja nie powiodła się na dowolnym etapie.nullgdy brak błędu. Błędy obejmują odrzucenia portfela, niewystarczający balans, awarie sieci itp. -
data(TransferSOLResult | null) - Obiekt wyniku, gdy transakcja się powiedzie. Zawiera sygnaturę, adresy, kwoty i metadane blockchain.nullprzed pierwszym udanym transferem. -
reset(() => void) - Resetuje stan mutacji, czyszczącerroridata. Przydatny dla przepływów ponownych prób lub resetowania formularzy po zakończeniu.
Właściwości i Metody Pomocnicze UI
Hook zapewnia wbudowane zarządzanie stanem dla pól formularza:
-
toInput/setToInput- Stan kontrolowany dla pola wprowadzania adresu odbiorcy -
amountInput/setAmountInput- Stan kontrolowany dla pola wprowadzania kwoty (w SOL, nie w lamportach) -
handleToInputChange- Wcześniej powiązany handler onChange dla wprowadzania odbiorcy:<input onChange={handleToInputChange} /> -
handleAmountInputChange- Wcześniej powiązany handler onChange dla wprowadzania kwoty:<input onChange={handleAmountInputChange} /> -
transferFromInputs- Wygodna metoda, która transferuje SOL używając bieżących wartościtoInputiamountInput. Automatycznie konwertuje kwotę z SOL na lamporty. -
handleSubmit- Handler wysyłania formularza, który wywołujetransferFromInputs()i zapobiega domyślnemu zachowaniu formularza. Użyj z<form onSubmit={handleSubmit}>.
Opcje
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(wymagane) - Adres odbiorcy w sieci Solana. Może być ciągiem znaków lub typemAddressz@solana/kit. -
amount(wymagane) - Kwota transferu w lamportach (nie w SOL). Musi byćbigint. UżyjBigInt()lub notacji literalnej:1_000_000_000n= 1 SOL. -
from(opcjonalne) - Adres nadawcy. Jeśli nie zostanie podany, używa adresu z podłączonego portfela. Wymagany tylko w zaawansowanych przypadkach użycia (np. podpisywanie dla innego konta).
Wynik
Wynik zawiera metadane transakcji, w tym szczegóły transferu i podpis transakcji:
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}
Architektura wewnętrzna
Konstruktor transakcji: Hook wykorzystuje współdzielony konstruktor transakcji, który:
- Pobiera świeże blokhashe dla każdej transakcji
- Buduje zoptymalizowane wiadomości transakcji z minimalnymi opłatami
- Podpisuje transakcje przy użyciu podłączonego portfela
- Przesyła i potwierdza transakcje w jednym przepływie
Unieważnienie pamięci podręcznej: Po pomyślnym transferze hook automatycznie unieważnia pamięci podręczne TanStack Query dla:
- Salda nadawcy (adres
from) - Salda odbiorcy (adres
to)
Zapewnia to, że wszystkie komponenty wyświetlające salda (np. za pomocą
useArcClient) automatycznie pobierają i aktualizują dane bez ręcznej
interwencji.
Precyzyjna konwersja kwoty: Podczas korzystania z transferFromInputs(),
kwota jest konwertowana z SOL na lamporty przy użyciu arytmetyki opartej na
ciągach znaków, aby uniknąć błędów precyzji zmiennoprzecinkowej. Konwersja:
- Waliduje format wejściowy (odrzuca liczby ujemne i nieprawidłowe)
- Obsługuje do 9 miejsc po przecinku (1 lamport = 0,000000001 SOL)
- Obcina lub dopełnia wartości ułamkowe w razie potrzeby
- Zwraca opisowe błędy dla nieprawidłowych danych wejściowych
useTransferToken
Podobnie jak useTransferSOL, ten hook jest używany do transferu tokenów SPL.
Oprócz obsługi transferów, hook obsługuje również automatyczne tworzenie
Associated Token Account (ATA) w razie potrzeby.
Sygnatura
function useTransferToken(initialMintInput?: string,initialToInput?: string,initialAmountInput?: string): UseTransferTokenReturn;
Parametry
initialMintInput(string, opcjonalny) - Początkowy adres mint tokena. Przydatny przy transferach o stałym tokenie.initialToInput(string, opcjonalny) - Początkowy adres odbiorcy.initialAmountInput(string, opcjonalny) - Początkowa kwota w jednostkach bazowych tokena (uwzględniając miejsca dziesiętne).
Wartość zwracana
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>;}
Wartość zwracana jest podobna do useTransferSOL, ale zawiera dodatkowy stan
mintInput do wyboru tokena.
Opcje
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}
Pola wymagane
-
mint- Adres mint tokena SPL. Na przykład:- USDC:
'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' - USDT:
'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'
- USDC:
-
to- Adres portfela odbiorcy (nie jego konto tokenowe). Hook automatycznie wyprowadza prawidłowy Associated Token Account. -
amount- Kwota transferu w najmniejszej jednostce tokena. Musi uwzględniać miejsca dziesiętne tokena:- USDC (6 miejsc dziesiętnych):
1_000_000n= 1 USDC - Tokeny opakowane SOL (9 miejsc dziesiętnych):
1_000_000_000n= 1 token
- USDC (6 miejsc dziesiętnych):
Pola opcjonalne
-
from- Adres portfela nadawcy. Domyślnie podłączony portfel. -
createAccountIfNeeded(domyślnie:true) - Jeśli odbiorca nie posiada konta tokenowego dla tego mint, automatycznie utwórz je jako część transakcji. Gdyfalse, transfer zakończy się niepowodzeniem, jeśli konto odbiorcy nie istnieje.Uwaga: Utworzenie konta tokena kosztuje ~0,00203 SOL. Kwotę tę płaci nadawca.
-
retryConfig- Konfiguracja automatycznego ponawiania przy wygaśnięciu blockhash. Zobacz Konfiguracja ponawiania.
Wynik
Wynik zawiera metadane transakcji, w tym szczegóły przelewu oraz sygnaturę transakcji:
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}
Konfiguracja ponawiania
Hook zawiera zaawansowaną logikę ponawiania do obsługi wygaśnięcia blockhash, co często występuje podczas przeciążenia sieci.
interface TransferRetryConfig {maxAttempts?: number; // Max retry attempts (default: 3)baseDelay?: number; // Base delay in ms (default: 1000)backoffMultiplier?: number; // Backoff multiplier (default: 1)}
-
maxAttempts- Maksymalna liczba prób transakcji. Każda próba pobiera świeży blockhash. Domyślnie:3. -
baseDelay- Opóźnienie w milisekundach przed pierwszym ponowieniem. Domyślnie:1000(1 sekunda). -
backoffMultiplier- Mnożnik wykładniczego wycofywania. Każde ponowienie czekabaseDelay * (backoffMultiplier ^ attemptNumber)milisekund.1= wycofywanie liniowe (1s, 1s, 1s)1.5= wycofywanie wykładnicze (1s, 1,5s, 2,25s)2= agresywne wykładnicze (1s, 2s, 4s)
Jak działa ponawianie:
- Pierwsza próba: Transakcja jest budowana z bieżącym blockhash i przesyłana
- Wygasa blockhash: Jeśli blockhash stanie się nieaktualny przed potwierdzeniem, Solana odrzuca transakcję
- Automatyczne ponowienie: Hook wykrywa wygaśnięcie, pobiera świeży blockhash, przebudowuje transakcję i przesyła ponownie
- Wykładnicze wycofywanie: Każde ponowienie czeka dłużej, aby uniknąć przeciążenia sieci
- Ostateczna porażka: Po
maxAttempts, rzucaBlockhashExpirationErrorz kontekstem
Kiedy ponowienia nie są uruchamiane:
- Błędy niezwiązane z blockhash (niewystarczające środki, nieprawidłowe konta itp.) są rzucane natychmiast bez ponawiania
- Tylko błędy wygaśnięcia blockhash uruchamiają mechanizm ponawiania
Architektura wewnętrzna
Zarządzanie ATA:
- Wyprowadza Associated Token Accounts deterministycznie za pomocą
findAssociatedTokenPda(Uwaga: obecnie obsługiwany jest tylko Token Program) - Sprawdza, czy nadawca ma token account (kończy natychmiast, jeśli nadawca nie posiada tokena)
- Sprawdza, czy odbiorca ma token account (tworzy, jeśli potrzeba i
createAccountIfNeeded: true) - Sprawdzanie kont wykonywane jest tylko przy pierwszej próbie, aby uniknąć zbędnych wywołań RPC podczas ponowień
Unieważnianie Cache: Po pomyślnym wykonaniu unieważnia cache TanStack Query dla:
- Salda tokenów nadawcy dla tego mint
- Salda tokenów odbiorcy dla tego mint
- Powiązanych danych konta
Dzięki temu wszystkie komponenty interfejsu wyświetlające salda są automatycznie zsynchronizowane.
useArcClient
Hook do dostępu do podstawowego klienta RPC Solana, stanu portfela i konfiguracji sieci. Jest to hook niższego poziomu przeznaczony dla zaawansowanych przypadków użycia wymagających bezpośredniego dostępu do RPC.
Sygnatura
function useArcClient(): ArcClientSnapshot;
Zwracana wartość
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>;}
Stan
ArcClientSnapshot rozszerza ArcWebClient, który zapewnia dostęp do:
- stanu portfela (adres, signer, dostępne portfele, funkcje i status portfela)
- konfiguracji sieci (endpoint RPC, klaster Solana)
Przypadki użycia
Bezpośrednie zapytania RPC:
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>;}
Komponenty świadome sieci:
function NetworkIndicator() {const { network } = useArcClient();return (<div><span>Network: {network.cluster}</span>{network.canAirdrop && <button onClick={handleAirdrop}>Airdrop</button>}</div>);}
Warunkowe renderowanie na podstawie portfela:
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?