use-stellar 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +1010 -0
  2. package/package.json +11 -4
package/README.md ADDED
@@ -0,0 +1,1010 @@
1
+ # use-stellar
2
+
3
+ > React hooks for building on the Stellar network.
4
+
5
+ `use-stellar` is a collection of React hooks that abstract the [Stellar SDK](https://github.com/stellar/js-stellar-sdk) and wallet APIs into a simple, typed interface. Instead of writing hundreds of lines of boilerplate to connect a wallet, fetch balances, or submit transactions, you get clean hooks that handle all of that for you.
6
+
7
+ ```tsx
8
+ import { useWallet, useBalance, useSendPayment } from "use-stellar";
9
+
10
+ function PayButton() {
11
+ const { connected, connect } = useWallet();
12
+ const { balance } = useBalance();
13
+ const { send, loading } = useSendPayment();
14
+
15
+ if (!connected) {
16
+ return <button onClick={() => connect()}>Connect wallet</button>;
17
+ }
18
+
19
+ return (
20
+ <div>
21
+ <p>Balance: {balance} XLM</p>
22
+ <button
23
+ onClick={() => send({ to: "G...", asset: "XLM", amount: "10" })}
24
+ disabled={loading}
25
+ >
26
+ {loading ? "Sending..." : "Send 10 XLM"}
27
+ </button>
28
+ </div>
29
+ );
30
+ }
31
+ ```
32
+
33
+ ---
34
+
35
+ ## Table of contents
36
+
37
+ - [Requirements](#requirements)
38
+ - [Installation](#installation)
39
+ - [Quick start](#quick-start)
40
+ - [Provider setup](#provider-setup)
41
+ - [Hooks](#hooks)
42
+ - [useWallet](#usewallet)
43
+ - [useBalance](#usebalance)
44
+ - [useAccount](#useaccount)
45
+ - [useSendPayment](#usesendpayment)
46
+ - [useTransaction](#usetransaction)
47
+ - [useNetwork](#usenetwork)
48
+ - [useAsset](#useasset)
49
+ - [useSorobanContract](#usesorobancontract)
50
+ - [TypeScript](#typescript)
51
+ - [Network configuration](#network-configuration)
52
+ - [Error handling](#error-handling)
53
+ - [Supported wallets](#supported-wallets)
54
+ - [Contributing](#contributing)
55
+ - [License](#license)
56
+
57
+ ---
58
+
59
+ ## Requirements
60
+
61
+ Before installing `use-stellar`, make sure your project meets these requirements:
62
+
63
+ | Requirement | Version |
64
+ |---|---|
65
+ | Node.js | 18 or later |
66
+ | React | 18 or later |
67
+ | TypeScript (optional) | 5.0 or later |
68
+
69
+ `use-stellar` also requires the [Freighter browser extension](https://freighter.app) to be installed for wallet connection to work. Freighter is a free Stellar wallet extension available for Chrome and Firefox.
70
+
71
+ ---
72
+
73
+ ## Installation
74
+
75
+ Install `use-stellar` and its peer dependency using your preferred package manager:
76
+
77
+ ```bash
78
+ # npm
79
+ npm install use-stellar @stellar/stellar-sdk
80
+
81
+ # pnpm
82
+ pnpm add use-stellar @stellar/stellar-sdk
83
+
84
+ # yarn
85
+ yarn add use-stellar @stellar/stellar-sdk
86
+ ```
87
+
88
+ > **Note:** `@stellar/stellar-sdk` is a peer dependency. It must be installed alongside `use-stellar` in your project.
89
+
90
+ ---
91
+
92
+ ## Quick start
93
+
94
+ The fastest way to see `use-stellar` working is to follow these three steps.
95
+
96
+ ### Step 1 — Wrap your app in `StellarProvider`
97
+
98
+ Open your root component (usually `app/layout.tsx` in Next.js, or `main.tsx` in Vite) and wrap your application:
99
+
100
+ ```tsx
101
+ // app/layout.tsx (Next.js App Router)
102
+ import { StellarProvider } from "use-stellar";
103
+
104
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
105
+ return (
106
+ <html lang="en">
107
+ <body>
108
+ <StellarProvider network="testnet">
109
+ {children}
110
+ </StellarProvider>
111
+ </body>
112
+ </html>
113
+ );
114
+ }
115
+ ```
116
+
117
+ ```tsx
118
+ // main.tsx (Vite / CRA)
119
+ import React from "react";
120
+ import ReactDOM from "react-dom/client";
121
+ import { StellarProvider } from "use-stellar";
122
+ import App from "./App";
123
+
124
+ ReactDOM.createRoot(document.getElementById("root")!).render(
125
+ <React.StrictMode>
126
+ <StellarProvider network="testnet">
127
+ <App />
128
+ </StellarProvider>
129
+ </React.StrictMode>
130
+ );
131
+ ```
132
+
133
+ ### Step 2 — Use a hook in any component
134
+
135
+ ```tsx
136
+ // components/WalletButton.tsx
137
+ "use client"; // Next.js only — remove this line for Vite/CRA
138
+
139
+ import { useWallet } from "use-stellar";
140
+
141
+ export function WalletButton() {
142
+ const { connected, connecting, address, error, connect, disconnect } = useWallet();
143
+
144
+ if (connecting) return <button disabled>Connecting...</button>;
145
+
146
+ if (connected) {
147
+ return (
148
+ <div>
149
+ <p>Connected: {address}</p>
150
+ <button onClick={disconnect}>Disconnect</button>
151
+ </div>
152
+ );
153
+ }
154
+
155
+ return (
156
+ <div>
157
+ <button onClick={() => connect()}>Connect Freighter</button>
158
+ {error && <p style={{ color: "red" }}>{error}</p>}
159
+ </div>
160
+ );
161
+ }
162
+ ```
163
+
164
+ ### Step 3 — Run your app
165
+
166
+ ```bash
167
+ npm run dev
168
+ ```
169
+
170
+ Open your browser, install [Freighter](https://freighter.app) if you haven't already, and click the connect button. That's it.
171
+
172
+ ---
173
+
174
+ ## Provider setup
175
+
176
+ Every hook in `use-stellar` reads its configuration from `StellarProvider`. You must wrap your application — or at minimum the part that uses Stellar hooks — in this provider.
177
+
178
+ ### Props
179
+
180
+ | Prop | Type | Default | Description |
181
+ |---|---|---|---|
182
+ | `network` | `"testnet"` \| `"mainnet"` | `"testnet"` | The Stellar network to connect to |
183
+ | `children` | `ReactNode` | — | Your application |
184
+
185
+ ### Example
186
+
187
+ ```tsx
188
+ import { StellarProvider } from "use-stellar";
189
+
190
+ // Development — connect to testnet
191
+ <StellarProvider network="testnet">
192
+ <App />
193
+ </StellarProvider>
194
+
195
+ // Production — connect to mainnet
196
+ <StellarProvider network="mainnet">
197
+ <App />
198
+ </StellarProvider>
199
+ ```
200
+
201
+ > **Testnet vs mainnet:** Testnet uses fake tokens and is free to use. Use it during development. Mainnet uses real tokens with real value. Never test on mainnet.
202
+
203
+ ---
204
+
205
+ ## Hooks
206
+
207
+ ### useWallet
208
+
209
+ Connects and disconnects a Stellar wallet. Exposes the connected address and connection state.
210
+
211
+ #### Usage
212
+
213
+ ```tsx
214
+ import { useWallet } from "use-stellar";
215
+
216
+ function MyComponent() {
217
+ const {
218
+ connected, // boolean — whether a wallet is connected
219
+ connecting, // boolean — true while the connection is in progress
220
+ address, // string | null — the connected Stellar address (G...)
221
+ network, // "testnet" | "mainnet" | null
222
+ wallet, // "freighter" | "albedo" | "rabet" | null
223
+ error, // string | null — last connection error
224
+ connect, // (wallet?: WalletType) => Promise<void>
225
+ disconnect, // () => void
226
+ } = useWallet();
227
+ }
228
+ ```
229
+
230
+ #### Return values
231
+
232
+ | Property | Type | Description |
233
+ |---|---|---|
234
+ | `connected` | `boolean` | `true` if a wallet is currently connected |
235
+ | `connecting` | `boolean` | `true` while a wallet connection is in progress |
236
+ | `address` | `string \| null` | The connected wallet's Stellar address, or `null` if disconnected |
237
+ | `network` | `StellarNetwork \| null` | The network the connected wallet is on |
238
+ | `wallet` | `WalletType \| null` | Which wallet is connected (`"freighter"`, etc.) |
239
+ | `error` | `string \| null` | The error message from the last failed connection attempt |
240
+ | `connect` | `(wallet?: WalletType) => Promise<void>` | Call this to initiate wallet connection |
241
+ | `disconnect` | `() => void` | Call this to disconnect the wallet |
242
+
243
+ #### Parameters
244
+
245
+ `connect` accepts an optional wallet type:
246
+
247
+ ```tsx
248
+ connect() // defaults to Freighter
249
+ connect("freighter") // explicitly use Freighter
250
+ ```
251
+
252
+ #### Examples
253
+
254
+ **Basic connect / disconnect button:**
255
+
256
+ ```tsx
257
+ import { useWallet } from "use-stellar";
258
+
259
+ export function ConnectButton() {
260
+ const { connected, connecting, address, error, connect, disconnect } = useWallet();
261
+
262
+ if (connecting) {
263
+ return <button disabled>Connecting...</button>;
264
+ }
265
+
266
+ if (connected) {
267
+ return (
268
+ <button onClick={disconnect}>
269
+ {address!.slice(0, 4)}...{address!.slice(-4)}
270
+ </button>
271
+ );
272
+ }
273
+
274
+ return (
275
+ <>
276
+ <button onClick={() => connect()}>Connect wallet</button>
277
+ {error && <p className="error">{error}</p>}
278
+ </>
279
+ );
280
+ }
281
+ ```
282
+
283
+ **Gate content behind wallet connection:**
284
+
285
+ ```tsx
286
+ import { useWallet } from "use-stellar";
287
+
288
+ export function ProtectedPage() {
289
+ const { connected, connect } = useWallet();
290
+
291
+ if (!connected) {
292
+ return (
293
+ <div>
294
+ <p>You need to connect your wallet to continue.</p>
295
+ <button onClick={() => connect()}>Connect Freighter</button>
296
+ </div>
297
+ );
298
+ }
299
+
300
+ return <div>Welcome! You are connected.</div>;
301
+ }
302
+ ```
303
+
304
+ ---
305
+
306
+ ### useBalance
307
+
308
+ Fetches the balance of any Stellar asset for any address. Optionally polls for live updates.
309
+
310
+ #### Usage
311
+
312
+ ```tsx
313
+ import { useBalance } from "use-stellar";
314
+
315
+ function MyComponent() {
316
+ const {
317
+ balance, // string | null — the balance of the requested asset
318
+ balances, // Balance[] — all balances for the account
319
+ loading, // boolean
320
+ error, // string | null
321
+ refetch, // () => void — manually re-fetch
322
+ } = useBalance();
323
+ }
324
+ ```
325
+
326
+ #### Options
327
+
328
+ Pass an options object to customise the behaviour:
329
+
330
+ | Option | Type | Default | Description |
331
+ |---|---|---|---|
332
+ | `address` | `string \| null` | Connected wallet address | The Stellar address to fetch balances for. Defaults to the connected wallet. |
333
+ | `asset` | `Asset` | `"XLM"` | The asset to return in `balance`. See [asset format](#asset-format). |
334
+ | `watch` | `boolean` | `false` | When `true`, re-fetches every 10 seconds automatically |
335
+
336
+ #### Return values
337
+
338
+ | Property | Type | Description |
339
+ |---|---|---|
340
+ | `balance` | `string \| null` | The balance of the requested `asset`, as a decimal string (e.g. `"100.5000000"`). `null` if no trustline exists or address not loaded yet. |
341
+ | `balances` | `Balance[]` | All asset balances for the account |
342
+ | `loading` | `boolean` | `true` while the first fetch is in progress |
343
+ | `error` | `string \| null` | Error message if the fetch failed |
344
+ | `refetch` | `() => void` | Manually trigger a re-fetch |
345
+
346
+ #### Asset format
347
+
348
+ `useBalance` accepts an `asset` option that determines which balance is returned in `balance`. An asset is either:
349
+
350
+ ```tsx
351
+ // Native XLM
352
+ asset: "XLM"
353
+
354
+ // Any issued asset (USDC, AQUA, etc.)
355
+ asset: { code: "USDC", issuer: "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN" }
356
+ ```
357
+
358
+ #### Examples
359
+
360
+ **XLM balance of the connected wallet:**
361
+
362
+ ```tsx
363
+ import { useBalance } from "use-stellar";
364
+
365
+ export function XlmBalance() {
366
+ const { balance, loading, error } = useBalance();
367
+
368
+ if (loading) return <p>Loading...</p>;
369
+ if (error) return <p>Error: {error}</p>;
370
+
371
+ return <p>XLM Balance: {balance ?? "0"}</p>;
372
+ }
373
+ ```
374
+
375
+ **USDC balance:**
376
+
377
+ ```tsx
378
+ import { useBalance } from "use-stellar";
379
+
380
+ const USDC = {
381
+ code: "USDC",
382
+ issuer: "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
383
+ };
384
+
385
+ export function UsdcBalance() {
386
+ const { balance, loading } = useBalance({ asset: USDC });
387
+
388
+ return <p>USDC Balance: {loading ? "..." : (balance ?? "0")}</p>;
389
+ }
390
+ ```
391
+
392
+ **Live balance with polling:**
393
+
394
+ ```tsx
395
+ // Re-fetches every 10 seconds automatically
396
+ const { balance } = useBalance({ watch: true });
397
+ ```
398
+
399
+ **Balance of a specific address:**
400
+
401
+ ```tsx
402
+ const { balance } = useBalance({
403
+ address: "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN",
404
+ asset: "XLM",
405
+ });
406
+ ```
407
+
408
+ **All balances for an account:**
409
+
410
+ ```tsx
411
+ const { balances } = useBalance();
412
+
413
+ return (
414
+ <ul>
415
+ {balances.map((b, i) => (
416
+ <li key={i}>
417
+ {b.asset === "XLM" ? "XLM" : b.asset.code}: {b.balance}
418
+ </li>
419
+ ))}
420
+ </ul>
421
+ );
422
+ ```
423
+
424
+ ---
425
+
426
+ ### useAccount
427
+
428
+ Fetches full account information from Horizon — balances, signers, sequence number, thresholds, and flags.
429
+
430
+ #### Usage
431
+
432
+ ```tsx
433
+ import { useAccount } from "use-stellar";
434
+
435
+ function MyComponent() {
436
+ const {
437
+ data, // AccountInfo | null
438
+ loading, // boolean
439
+ error, // string | null
440
+ refetch, // () => void
441
+ } = useAccount();
442
+ }
443
+ ```
444
+
445
+ #### Parameters
446
+
447
+ | Parameter | Type | Default | Description |
448
+ |---|---|---|---|
449
+ | `address` | `string` (optional) | Connected wallet address | The address to fetch. Defaults to the connected wallet. |
450
+
451
+ #### `AccountInfo` shape
452
+
453
+ ```ts
454
+ interface AccountInfo {
455
+ address: string;
456
+ sequence: string; // current sequence number
457
+ balances: Balance[]; // all asset balances
458
+ subentryCount: number; // number of subentries (trustlines, offers, etc.)
459
+ thresholds: {
460
+ lowThreshold: number;
461
+ medThreshold: number;
462
+ highThreshold: number;
463
+ };
464
+ signers: {
465
+ key: string; // signer Stellar address
466
+ weight: number;
467
+ type: string;
468
+ }[];
469
+ }
470
+ ```
471
+
472
+ #### Examples
473
+
474
+ **Show full account info:**
475
+
476
+ ```tsx
477
+ import { useAccount } from "use-stellar";
478
+
479
+ export function AccountInfo() {
480
+ const { data: account, loading, error } = useAccount();
481
+
482
+ if (loading) return <p>Loading account...</p>;
483
+ if (error) return <p>Error: {error}</p>;
484
+ if (!account) return <p>No account loaded</p>;
485
+
486
+ return (
487
+ <div>
488
+ <p>Address: {account.address}</p>
489
+ <p>Sequence: {account.sequence}</p>
490
+ <p>Subentries: {account.subentryCount}</p>
491
+ <p>Signers: {account.signers.length}</p>
492
+ </div>
493
+ );
494
+ }
495
+ ```
496
+
497
+ **Check if account has multiple signers (multisig):**
498
+
499
+ ```tsx
500
+ const { data: account } = useAccount();
501
+ const isMultisig = account ? account.signers.length > 1 : false;
502
+ ```
503
+
504
+ **Fetch a different address:**
505
+
506
+ ```tsx
507
+ const { data: account } = useAccount("GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN");
508
+ ```
509
+
510
+ ---
511
+
512
+ ### useSendPayment
513
+
514
+ Builds, signs, and submits a Stellar payment transaction. Uses the connected wallet to sign.
515
+
516
+ #### Usage
517
+
518
+ ```tsx
519
+ import { useSendPayment } from "use-stellar";
520
+
521
+ function MyComponent() {
522
+ const {
523
+ send, // (options: SendPaymentOptions) => Promise<SendPaymentResult>
524
+ loading, // boolean — true while tx is being built/signed/submitted
525
+ error, // string | null
526
+ result, // SendPaymentResult | null — the result of the last send
527
+ reset, // () => void — clear error and result
528
+ } = useSendPayment();
529
+ }
530
+ ```
531
+
532
+ #### `SendPaymentOptions`
533
+
534
+ | Property | Type | Required | Description |
535
+ |---|---|---|---|
536
+ | `to` | `string` | Yes | Destination Stellar address (must start with `G`) |
537
+ | `asset` | `Asset` | Yes | Asset to send — `"XLM"` or `{ code, issuer }` |
538
+ | `amount` | `string` | Yes | Amount as a string, e.g. `"10"` or `"0.5"` |
539
+ | `memo` | `string` | No | Optional text memo attached to the transaction |
540
+
541
+ > **Why is `amount` a string?** JavaScript floating point arithmetic is imprecise. Using a string avoids rounding errors when working with financial values. Pass amounts as strings: `"10"` not `10`.
542
+
543
+ #### `SendPaymentResult`
544
+
545
+ ```ts
546
+ interface SendPaymentResult {
547
+ hash: string; // transaction hash on Stellar
548
+ status: TransactionStatus; // "success" | "failed" | "pending" | "not_found"
549
+ }
550
+ ```
551
+
552
+ #### Examples
553
+
554
+ **Send XLM:**
555
+
556
+ ```tsx
557
+ import { useSendPayment } from "use-stellar";
558
+
559
+ export function SendXlm() {
560
+ const { send, loading, error, result } = useSendPayment();
561
+
562
+ async function handleSend() {
563
+ await send({
564
+ to: "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN",
565
+ asset: "XLM",
566
+ amount: "10",
567
+ });
568
+ }
569
+
570
+ return (
571
+ <div>
572
+ <button onClick={handleSend} disabled={loading}>
573
+ {loading ? "Sending..." : "Send 10 XLM"}
574
+ </button>
575
+ {error && <p style={{ color: "red" }}>Error: {error}</p>}
576
+ {result && <p style={{ color: "green" }}>Sent! Hash: {result.hash}</p>}
577
+ </div>
578
+ );
579
+ }
580
+ ```
581
+
582
+ **Send USDC with a memo:**
583
+
584
+ ```tsx
585
+ const { send } = useSendPayment();
586
+
587
+ await send({
588
+ to: "G...",
589
+ asset: { code: "USDC", issuer: "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN" },
590
+ amount: "50",
591
+ memo: "Invoice #42",
592
+ });
593
+ ```
594
+
595
+ **Full send form:**
596
+
597
+ ```tsx
598
+ import { useState } from "react";
599
+ import { useSendPayment, useWallet } from "use-stellar";
600
+
601
+ export function SendForm() {
602
+ const { connected } = useWallet();
603
+ const { send, loading, error, result, reset } = useSendPayment();
604
+
605
+ const [to, setTo] = useState("");
606
+ const [amount, setAmount] = useState("");
607
+
608
+ if (!connected) return <p>Connect your wallet first.</p>;
609
+
610
+ return (
611
+ <form
612
+ onSubmit={async (e) => {
613
+ e.preventDefault();
614
+ reset();
615
+ await send({ to, asset: "XLM", amount });
616
+ }}
617
+ >
618
+ <input
619
+ placeholder="Destination address (G...)"
620
+ value={to}
621
+ onChange={(e) => setTo(e.target.value)}
622
+ required
623
+ />
624
+ <input
625
+ type="number"
626
+ placeholder="Amount"
627
+ value={amount}
628
+ onChange={(e) => setAmount(e.target.value)}
629
+ min="0"
630
+ step="0.0000001"
631
+ required
632
+ />
633
+ <button type="submit" disabled={loading}>
634
+ {loading ? "Sending..." : "Send XLM"}
635
+ </button>
636
+ {error && <p style={{ color: "red" }}>{error}</p>}
637
+ {result && <p style={{ color: "green" }}>Transaction confirmed: {result.hash}</p>}
638
+ </form>
639
+ );
640
+ }
641
+ ```
642
+
643
+ ---
644
+
645
+ ### useTransaction
646
+
647
+ Fetches a transaction by its hash. Useful for checking the status of a transaction after submission.
648
+
649
+ #### Usage
650
+
651
+ ```tsx
652
+ import { useTransaction } from "use-stellar";
653
+
654
+ function MyComponent() {
655
+ const {
656
+ data, // TransactionResult | null
657
+ loading, // boolean
658
+ error, // string | null
659
+ refetch, // () => void
660
+ } = useTransaction("abc123...");
661
+ }
662
+ ```
663
+
664
+ #### Parameters
665
+
666
+ | Parameter | Type | Description |
667
+ |---|---|---|
668
+ | `hash` | `string \| null \| undefined` | The transaction hash to look up. Pass `null` or `undefined` to skip fetching. |
669
+
670
+ #### `TransactionResult`
671
+
672
+ ```ts
673
+ interface TransactionResult {
674
+ hash: string;
675
+ status: "pending" | "success" | "failed" | "not_found";
676
+ ledger?: number;
677
+ createdAt?: string;
678
+ fee?: string;
679
+ }
680
+ ```
681
+
682
+ #### Examples
683
+
684
+ **Check a transaction after sending:**
685
+
686
+ ```tsx
687
+ import { useState } from "react";
688
+ import { useSendPayment, useTransaction } from "use-stellar";
689
+
690
+ export function SendAndTrack() {
691
+ const [hash, setHash] = useState<string | null>(null);
692
+ const { send, loading: sending } = useSendPayment();
693
+ const { data: tx, loading: fetching } = useTransaction(hash);
694
+
695
+ async function handleSend() {
696
+ const result = await send({ to: "G...", asset: "XLM", amount: "1" });
697
+ if (result) setHash(result.hash);
698
+ }
699
+
700
+ return (
701
+ <div>
702
+ <button onClick={handleSend} disabled={sending}>
703
+ {sending ? "Sending..." : "Send 1 XLM"}
704
+ </button>
705
+
706
+ {hash && (
707
+ <div>
708
+ <p>Hash: {hash}</p>
709
+ <p>Status: {fetching ? "checking..." : tx?.status}</p>
710
+ {tx?.ledger && <p>Ledger: {tx.ledger}</p>}
711
+ </div>
712
+ )}
713
+ </div>
714
+ );
715
+ }
716
+ ```
717
+
718
+ ---
719
+
720
+ ### useNetwork
721
+
722
+ Returns the current network configuration. Useful for displaying the active network to users or conditionally rendering content based on which network is active.
723
+
724
+ #### Usage
725
+
726
+ ```tsx
727
+ import { useNetwork } from "use-stellar";
728
+
729
+ function MyComponent() {
730
+ const {
731
+ network, // "testnet" | "mainnet"
732
+ networkConfig, // { network, horizonUrl, sorobanUrl }
733
+ isTestnet, // boolean shorthand
734
+ isMainnet, // boolean shorthand
735
+ } = useNetwork();
736
+ }
737
+ ```
738
+
739
+ #### Examples
740
+
741
+ **Show a testnet warning banner:**
742
+
743
+ ```tsx
744
+ import { useNetwork } from "use-stellar";
745
+
746
+ export function NetworkBanner() {
747
+ const { isTestnet } = useNetwork();
748
+
749
+ if (!isTestnet) return null;
750
+
751
+ return (
752
+ <div style={{ background: "orange", padding: "8px", textAlign: "center" }}>
753
+ You are on testnet. Tokens have no real value.
754
+ </div>
755
+ );
756
+ }
757
+ ```
758
+
759
+ **Display the current Horizon URL:**
760
+
761
+ ```tsx
762
+ const { networkConfig } = useNetwork();
763
+ console.log(networkConfig.horizonUrl); // "https://horizon-testnet.stellar.org"
764
+ ```
765
+
766
+ ---
767
+
768
+ ### useAsset
769
+
770
+ Fetches metadata about a Stellar asset — total supply, number of trustlines, and the issuer's home domain.
771
+
772
+ #### Usage
773
+
774
+ ```tsx
775
+ import { useAsset } from "use-stellar";
776
+
777
+ const { data, loading, error, refetch } = useAsset("USDC", "GA5Z...");
778
+ ```
779
+
780
+ #### Parameters
781
+
782
+ | Parameter | Type | Description |
783
+ |---|---|---|
784
+ | `code` | `string` | The asset code, e.g. `"USDC"` |
785
+ | `issuer` | `string` | The issuer's Stellar address |
786
+
787
+ #### Example
788
+
789
+ ```tsx
790
+ import { useAsset } from "use-stellar";
791
+
792
+ export function AssetInfo() {
793
+ const { data, loading, error } = useAsset(
794
+ "USDC",
795
+ "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
796
+ );
797
+
798
+ if (loading) return <p>Loading asset info...</p>;
799
+ if (error) return <p>Error: {error}</p>;
800
+ if (!data) return null;
801
+
802
+ return (
803
+ <div>
804
+ <p>Code: {data.code}</p>
805
+ <p>Home domain: {data.homeDomain ?? "not set"}</p>
806
+ <p>Total supply: {data.supply}</p>
807
+ <p>Trustlines: {data.numAccounts}</p>
808
+ </div>
809
+ );
810
+ }
811
+ ```
812
+
813
+ ---
814
+
815
+ ### useSorobanContract
816
+
817
+ Calls a read function on a deployed Soroban smart contract.
818
+
819
+ > **Note:** This hook currently supports read-only simulation calls. Write calls (with signing) are tracked in [GitHub issue #8](https://github.com/YOUR_HANDLE/use-stellar/issues/8) — contributions welcome.
820
+
821
+ #### Usage
822
+
823
+ ```tsx
824
+ import { useSorobanContract } from "use-stellar";
825
+
826
+ function MyComponent() {
827
+ const {
828
+ call, // (options: ContractCallOptions) => Promise<unknown>
829
+ loading, // boolean
830
+ error, // string | null
831
+ result, // unknown — the return value from the contract
832
+ } = useSorobanContract();
833
+ }
834
+ ```
835
+
836
+ #### `ContractCallOptions`
837
+
838
+ | Property | Type | Required | Description |
839
+ |---|---|---|---|
840
+ | `contractId` | `string` | Yes | The deployed contract address (starts with `C`) |
841
+ | `method` | `string` | Yes | The contract function name to call |
842
+ | `args` | `unknown[]` | No | Arguments to pass to the function |
843
+
844
+ #### Example
845
+
846
+ ```tsx
847
+ import { useSorobanContract } from "use-stellar";
848
+
849
+ export function ContractReader() {
850
+ const { call, loading, error, result } = useSorobanContract();
851
+
852
+ async function readPrice() {
853
+ await call({
854
+ contractId: "CABC123...",
855
+ method: "get_price",
856
+ args: ["XLM"],
857
+ });
858
+ }
859
+
860
+ return (
861
+ <div>
862
+ <button onClick={readPrice} disabled={loading}>
863
+ {loading ? "Reading..." : "Read contract"}
864
+ </button>
865
+ {error && <p style={{ color: "red" }}>{error}</p>}
866
+ {result && <pre>{JSON.stringify(result, null, 2)}</pre>}
867
+ </div>
868
+ );
869
+ }
870
+ ```
871
+
872
+ ---
873
+
874
+ ## TypeScript
875
+
876
+ `use-stellar` is written in TypeScript and ships with full type definitions. No additional `@types` package is needed.
877
+
878
+ ### Importing types
879
+
880
+ ```ts
881
+ import type {
882
+ StellarNetwork, // "testnet" | "mainnet"
883
+ NetworkConfig, // { network, horizonUrl, sorobanUrl }
884
+ WalletType, // "freighter" | "albedo" | "rabet"
885
+ WalletState, // { connected, address, network, wallet, connecting, error }
886
+ Asset, // "XLM" | { code: string, issuer: string }
887
+ NativeAsset, // "XLM"
888
+ IssuedAsset, // { code: string, issuer: string }
889
+ Balance, // { asset, balance, limit?, buying?, selling? }
890
+ AccountInfo, // full account shape
891
+ TransactionResult, // { hash, status, ledger?, createdAt?, fee? }
892
+ TransactionStatus, // "pending" | "success" | "failed" | "not_found"
893
+ SendPaymentOptions, // { to, asset, amount, memo? }
894
+ SendPaymentResult, // { hash, status }
895
+ ContractCallOptions,// { contractId, method, args? }
896
+ } from "use-stellar";
897
+ ```
898
+
899
+ ### Working with `Asset`
900
+
901
+ The `Asset` type is a discriminated union. When working with it you can check whether it is native or issued:
902
+
903
+ ```ts
904
+ import type { Asset, NativeAsset, IssuedAsset } from "use-stellar";
905
+
906
+ function getAssetCode(asset: Asset): string {
907
+ if (asset === "XLM") {
908
+ return "XLM"; // NativeAsset
909
+ }
910
+ return (asset as IssuedAsset).code; // IssuedAsset
911
+ }
912
+ ```
913
+
914
+ ---
915
+
916
+ ## Network configuration
917
+
918
+ ### Switching between testnet and mainnet
919
+
920
+ Pass the `network` prop to `StellarProvider`:
921
+
922
+ ```tsx
923
+ // testnet (development)
924
+ <StellarProvider network="testnet">
925
+
926
+ // mainnet (production)
927
+ <StellarProvider network="mainnet">
928
+ ```
929
+
930
+ ### Reading network config in a hook
931
+
932
+ All hooks read the network from `StellarProvider` automatically. You can also access the full config directly:
933
+
934
+ ```tsx
935
+ import { useNetwork } from "use-stellar";
936
+
937
+ const { networkConfig } = useNetwork();
938
+
939
+ // networkConfig.horizonUrl — Horizon REST API endpoint
940
+ // networkConfig.sorobanUrl — Soroban RPC endpoint
941
+ // networkConfig.network — "testnet" | "mainnet"
942
+ ```
943
+
944
+ ### Default endpoints
945
+
946
+ | Network | Horizon URL | Soroban RPC URL |
947
+ |---|---|---|
948
+ | testnet | `https://horizon-testnet.stellar.org` | `https://soroban-testnet.stellar.org` |
949
+ | mainnet | `https://horizon.stellar.org` | `https://soroban.stellar.org` |
950
+
951
+ ---
952
+
953
+ ## Error handling
954
+
955
+ All hooks expose an `error` string when something goes wrong. Errors are human-readable messages you can display directly to users.
956
+
957
+ ### Pattern
958
+
959
+ ```tsx
960
+ const { data, loading, error, refetch } = useBalance();
961
+
962
+ if (loading) return <p>Loading...</p>;
963
+ if (error) return <p>{error} — <button onClick={refetch}>Retry</button></p>;
964
+ if (!data) return null;
965
+
966
+ return <p>Balance: {data.balance}</p>;
967
+ ```
968
+
969
+ ### Common errors
970
+
971
+ | Error | Cause | Fix |
972
+ |---|---|---|
973
+ | `Freighter wallet not found` | Freighter extension is not installed | Direct the user to [freighter.app](https://freighter.app) |
974
+ | `Wallet not connected. Call connect() first.` | `useSendPayment().send()` was called without a wallet | Gate the action behind a wallet connect check |
975
+ | `Failed to fetch balance` | The address doesn't exist on the network, or Horizon is unreachable | Check the address is funded on the correct network |
976
+ | `Transaction failed` | The transaction was rejected by the network | Check the user has sufficient balance and correct asset trustlines |
977
+
978
+ ---
979
+
980
+ ## Supported wallets
981
+
982
+ | Wallet | Status | Notes |
983
+ |---|---|---|
984
+ | [Freighter](https://freighter.app) | Supported | Default wallet |
985
+ | Albedo | Coming soon | Tracked in [issue #3](https://github.com/YOUR_HANDLE/use-stellar/issues/3) |
986
+ | Rabet | Coming soon | Tracked in [issue #4](https://github.com/YOUR_HANDLE/use-stellar/issues/4) |
987
+
988
+ Contributions for new wallet integrations are welcome — see [CONTRIBUTING.md](https://github.com/YOUR_HANDLE/use-stellar/blob/main/CONTRIBUTING.md).
989
+
990
+ ---
991
+
992
+ ## Contributing
993
+
994
+ `use-stellar` is open source and welcomes contributions. Every hook is a self-contained TypeScript file — you do not need Rust or blockchain expertise to contribute.
995
+
996
+ See [CONTRIBUTING.md](https://github.com/YOUR_HANDLE/use-stellar/blob/main/CONTRIBUTING.md) for setup instructions and a guide to adding new hooks and wallet integrations.
997
+
998
+ ```bash
999
+ git clone https://github.com/YOUR_HANDLE/use-stellar
1000
+ cd use-stellar
1001
+ pnpm install
1002
+ pnpm --filter use-stellar build
1003
+ pnpm --filter @use-stellar/demo dev
1004
+ ```
1005
+
1006
+ ---
1007
+
1008
+ ## License
1009
+
1010
+ MIT © [RACEEY](https://github.com/israelolrunfemi)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "use-stellar",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "React hooks for the Stellar network - the wagmi of Stellar",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,7 +21,9 @@
21
21
  "require": "./dist/index.js"
22
22
  }
23
23
  },
24
- "files": ["dist"],
24
+ "files": [
25
+ "dist"
26
+ ],
25
27
  "sideEffects": false,
26
28
  "publishConfig": {
27
29
  "access": "public"
@@ -56,8 +58,13 @@
56
58
  "jest": {
57
59
  "preset": "ts-jest",
58
60
  "testEnvironment": "jsdom",
59
- "testMatch": ["**/*.test.ts", "**/*.test.tsx"],
60
- "setupFilesAfterEnv": ["@testing-library/jest-dom"]
61
+ "testMatch": [
62
+ "**/*.test.ts",
63
+ "**/*.test.tsx"
64
+ ],
65
+ "setupFilesAfterEnv": [
66
+ "@testing-library/jest-dom"
67
+ ]
61
68
  },
62
69
  "keywords": [
63
70
  "stellar",