@radiant-core/sdk 0.1.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Radiant Core
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,230 @@
1
+ # @radiant-core/sdk
2
+
3
+ A clean TypeScript SDK for building [Radiant (RXD)](https://radiantcore.org) dapps — without reading internal Photonic/radiantjs source.
4
+
5
+ It wraps [`@radiant-core/radiantjs`](https://www.npmjs.com/package/@radiant-core/radiantjs) (the low‑level tx/script library) and gives you the primitives most web/app developers actually need: an ElectrumX client, **ref‑safe** UTXO selection that never burns tokens, Glyph token mint/transfer, WAVE name resolution, and SLIP‑0044 HD wallets.
6
+
7
+ - 🔌 **ElectrumX WebSocket client** — balance, UTXOs, broadcast, subscribe, auto‑reconnect with backoff
8
+ - 🛡️ **Ref‑safe funding** — token‑bearing UTXOs are *never* spent as RXD funding (no silent token burns)
9
+ - 🪙 **Glyph tokens** — mint FT/NFT and transfer via the commit/reveal pattern
10
+ - 🌊 **WAVE names** — resolve `alice` → address
11
+ - 🔑 **HD wallets** — `m/44'/512'/0'/0/k` (Radiant coin type 512, the v3.0.0+ default)
12
+ - 📦 **Dual ESM + CJS**, tree‑shakeable, TypeScript types included
13
+ - 🔢 **Photons as `BigInt`** everywhere internally, with RXD helpers at the edge
14
+
15
+ ```bash
16
+ npm install @radiant-core/sdk
17
+ # radiantjs is a peer of the token/wallet APIs; install it too:
18
+ npm install @radiant-core/radiantjs
19
+ # On Node < 22 (no global WebSocket), also:
20
+ npm install ws
21
+ ```
22
+
23
+ > **Units.** The base unit is the *photon*. `1 RXD = 100,000,000 photons`. All
24
+ > amounts inside the SDK are `BigInt` photons. Use `rxdToPhotons()` /
25
+ > `photonsToRxd()` only at your UI/input boundary — never do balance math in
26
+ > floating point.
27
+
28
+ ---
29
+
30
+ ## Quickstart
31
+
32
+ ### Connect and read a balance
33
+
34
+ ```ts
35
+ import { ElectrumClient, photonsToRxd } from "@radiant-core/sdk";
36
+
37
+ const client = new ElectrumClient({ network: "mainnet" });
38
+ await client.connect();
39
+
40
+ const address = "1Yourradiantaddress...";
41
+ const { confirmed, unconfirmed } = await client.getBalance(address);
42
+ console.log(`Confirmed: ${photonsToRxd(confirmed)} RXD`);
43
+
44
+ const utxos = await client.listUnspent(address); // Utxo[] (photons as BigInt)
45
+ ```
46
+
47
+ ### Create / restore an HD wallet
48
+
49
+ ```ts
50
+ import { HDWallet } from "@radiant-core/sdk";
51
+
52
+ // New wallet
53
+ const mnemonic = HDWallet.generateMnemonic();
54
+ const wallet = HDWallet.fromMnemonic(mnemonic, { network: "mainnet" });
55
+
56
+ // Address #0 at m/44'/512'/0'/0/0
57
+ const acct0 = wallet.deriveKey(0);
58
+ console.log(acct0.path); // m/44'/512'/0'/0/0
59
+ console.log(acct0.address); // base58 address
60
+ console.log(acct0.scriptHash); // ElectrumX scripthash
61
+
62
+ // Batch derive a gap of receive addresses
63
+ const receive = wallet.deriveRange(0, 20); // DerivedKey[]
64
+ ```
65
+
66
+ ### Send RXD (ref‑safe funding)
67
+
68
+ ```ts
69
+ import { ElectrumClient, HDWallet, buildRxdTransfer, rxdToPhotons } from "@radiant-core/sdk";
70
+
71
+ const client = new ElectrumClient({ network: "mainnet" });
72
+ const wallet = HDWallet.fromMnemonic(mnemonic);
73
+ const me = wallet.deriveKey(0);
74
+
75
+ const utxos = await client.listUnspent(me.address);
76
+
77
+ const { hex, txid } = buildRxdTransfer({
78
+ address: me.address,
79
+ wif: me.wif,
80
+ to: "1Recipient...",
81
+ amount: rxdToPhotons("1.25"), // 1.25 RXD -> photons
82
+ utxos, // token‑bearing UTXOs are auto‑excluded
83
+ feeRate: 10_000n, // photons/byte (mainnet min‑relay)
84
+ });
85
+
86
+ await client.broadcastTx(hex);
87
+ console.log("sent", txid);
88
+ ```
89
+
90
+ ### Ref‑safe selection, explicitly
91
+
92
+ The single most important safety property: **funding is never gathered by a
93
+ value heuristic.** A UTXO that carries a token ref (FT/NFT/dMint) looks like
94
+ plain value to a naive selector, but spending it as funding *burns the token*.
95
+ `selectRxdFunding` screens every candidate two ways — indexer‑reported `refs`
96
+ and a local script scan (`isTokenBearing`) — and throws `TokenBurnGuardError`
97
+ rather than risk a burn.
98
+
99
+ ```ts
100
+ import { selectRxdFunding, filterFundingCandidates, isTokenBearing } from "@radiant-core/sdk";
101
+
102
+ const safe = filterFundingCandidates(allUtxos); // drops anything token‑bearing
103
+ const sel = selectRxdFunding(allUtxos, rxdToPhotons("0.5"), 10_000n);
104
+ console.log(sel.inputs, sel.fee, sel.change);
105
+
106
+ isTokenBearing(scriptHex); // true if the script has an OP_PUSHINPUTREF opcode
107
+ ```
108
+
109
+ ### Mint a Glyph token
110
+
111
+ ```ts
112
+ import { mintFT, mintNFT, filterFundingCandidates } from "@radiant-core/sdk";
113
+
114
+ const funding = filterFundingCandidates(await client.listUnspent(me.address));
115
+
116
+ // Fungible token (FT amount == output photons)
117
+ const ft = await mintFT({
118
+ client,
119
+ address: me.address,
120
+ wif: me.wif,
121
+ ticker: "DEMO",
122
+ supply: 1_000_000n,
123
+ metadata: { name: "Demo Token", desc: "Minted with @radiant-core/sdk" },
124
+ fundingUtxos: funding,
125
+ });
126
+ console.log("FT ref:", ft.refDisplay, ft.commitTxid, ft.revealTxid);
127
+
128
+ // Non‑fungible token (singleton)
129
+ const nft = await mintNFT({
130
+ client,
131
+ address: me.address,
132
+ wif: me.wif,
133
+ metadata: { name: "My NFT", attrs: { rarity: "rare" } },
134
+ fundingUtxos: funding,
135
+ });
136
+ ```
137
+
138
+ ### Transfer a token
139
+
140
+ ```ts
141
+ import { transferToken } from "@radiant-core/sdk";
142
+
143
+ // `tokenUtxo` must include its on‑chain `script` (the token output script).
144
+ await transferToken({
145
+ client,
146
+ address: me.address,
147
+ wif: me.wif,
148
+ tokenUtxo, // the FT/NFT UTXO to move
149
+ toAddress: "1Recipient...",
150
+ fundingUtxos: funding, // covers the fee only; token value is conserved
151
+ });
152
+ ```
153
+
154
+ ### Resolve a WAVE name
155
+
156
+ ```ts
157
+ import { waveResolve, waveResolveAddress } from "@radiant-core/sdk";
158
+
159
+ const rec = await waveResolve("alice"); // "alice.rxd" works too (suffix stripped)
160
+ if (rec.registered) console.log(rec.address, rec.owner, rec.expires);
161
+
162
+ const addr = await waveResolveAddress("alice"); // string | null
163
+ ```
164
+
165
+ ### Subscribe to address activity
166
+
167
+ ```ts
168
+ const status = await client.subscribe(me.address, (newStatus) => {
169
+ console.log("address changed:", newStatus); // re‑fetch UTXOs/balance here
170
+ });
171
+ ```
172
+
173
+ ---
174
+
175
+ ## API surface
176
+
177
+ | Area | Exports |
178
+ | --- | --- |
179
+ | Client | `ElectrumClient` |
180
+ | Wallet | `HDWallet`, `Keys` |
181
+ | Funding | `selectRxdFunding`, `filterFundingCandidates`, `isFundingSafe`, `estimateFee`, `sumValue` |
182
+ | Tx | `buildTx`, `buildRxdTransfer` |
183
+ | Tokens | `mintFT`, `mintNFT`, `transferToken`, `encodeGlyph`, `ftScript`, `nftScript`, `parseTokenRef` |
184
+ | WAVE | `waveResolve`, `waveResolveAddress`, `waveLabel` |
185
+ | Script | `scriptHash`, `addressToScriptHash`, `p2pkhScript`, `isTokenBearing`, `zeroRefs`, `packRef`, `unpackRef` |
186
+ | Units | `rxdToPhotons`, `photonsToRxd` |
187
+ | Errors | `RadiantSdkError`, `InsufficientFundsError`, `TokenBurnGuardError`, `ElectrumError`, `ValidationError` |
188
+
189
+ ---
190
+
191
+ ## Design notes
192
+
193
+ - **radiantjs is wrapped, not duplicated.** All key/tx/script work delegates to
194
+ `@radiant-core/radiantjs`; the SDK adds BigInt photons, ref‑safety, the
195
+ ElectrumX transport, and Glyph/WAVE conveniences. The raw library is available
196
+ via the `radiantjs` export if you need an escape hatch.
197
+ - **Fee rate.** Mainnet min‑relay is `10,000` photons/byte (since the V2 upgrade
198
+ at block 410,000); testnet/regtest is `1,000`. These are exposed as
199
+ `MIN_RELAY_FEE_RATE` and used as defaults — pin them, don't tune them.
200
+ `buildTx` sets the fee from the *measured signed transaction size* (not an
201
+ estimate), so token transactions carrying a CBOR envelope reliably clear the
202
+ node's min‑relay floor. Funding selection reserves a little extra so a
203
+ tightly‑funded wallet still has enough inputs; any surplus returns as change.
204
+ - **Endpoints.** The public mainnet ElectrumX is `wss://electrumx.radiantcore.org:443`
205
+ (TLS on :443 only). WAVE resolution defaults to `https://radiantcore.org/api`.
206
+ Both are overridable.
207
+
208
+ > ✅ **Mint/transfer flows are regtest‑validated.** `mintFT` / `mintNFT` /
209
+ > `transferToken` reproduce the proven Photonic‑Wallet on‑chain templates and
210
+ > have been run end‑to‑end against a real `radiantd` regtest node — commit +
211
+ > reveal accepted, outputs match `ftScript`/`nftScript` and carry the ref, FT
212
+ > amount and singleton ref preserved across transfers. They still broadcast
213
+ > real, irreversible transactions, so smoke‑test your own flow on
214
+ > regtest/testnet before mainnet.
215
+
216
+ ## Building from source
217
+
218
+ Requires Node 20.19+ or 22+ (`require(ESM)` support; radiantjs pulls in an
219
+ ESM-only dependency).
220
+
221
+ ```bash
222
+ npm install
223
+ npm run build # tsup -> dist/ (ESM + CJS + d.ts)
224
+ npm run typecheck # tsc --noEmit
225
+ npm test # node --test against the built bundle
226
+ ```
227
+
228
+ ## License
229
+
230
+ MIT