stellar-contracts-kit 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 +21 -0
- package/README.md +434 -0
- package/dist/cli/generate.js +951 -0
- package/dist/index.cjs +844 -0
- package/dist/index.d.cts +95 -0
- package/dist/index.d.ts +95 -0
- package/dist/index.js +831 -0
- package/dist/wallets/index.cjs +199 -0
- package/dist/wallets/index.d.cts +60 -0
- package/dist/wallets/index.d.ts +60 -0
- package/dist/wallets/index.js +191 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fajrin Firmana
|
|
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,434 @@
|
|
|
1
|
+
# stellar-contracts-kit
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/stellar-contracts-kit)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
|
|
7
|
+
TypeScript SDK for Soroban smart contracts on Stellar. Handles wallet connection, typed contract clients, and a CLI that generates TypeScript interfaces directly from any live on-chain contract.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **CLI code generator**: `npx sck` generates fully-typed TypeScript or JavaScript interfaces from any live contract spec
|
|
14
|
+
- **Interactive CLI**: arrow-key command picker, input validation, network selection
|
|
15
|
+
- **Built-in wallet modal**: auto-detects Freighter, Cyphras, and Lobstr, opens a picker UI when no wallet is specified
|
|
16
|
+
- **Three call modes**: auto, read-only, and force-invoke on every contract method
|
|
17
|
+
- **Full type coverage**: structs, enums, unions, tuples, `Uint8Array`, `bigint`, `Option`, `Vec`, `Map`
|
|
18
|
+
- **Contract spec caching**: spec fetched once per contract ID, subsequent calls are instant
|
|
19
|
+
- **Contract restore**: one-call recovery when a contract's on-chain state has expired
|
|
20
|
+
- Works with any frontend framework (React, Vue, Svelte, vanilla JS)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install stellar-contracts-kit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## CLI
|
|
33
|
+
|
|
34
|
+
### Interactive mode
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx sck
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Launches an arrow-key menu to pick a command, then guides you through the rest.
|
|
41
|
+
|
|
42
|
+
### Generate types
|
|
43
|
+
|
|
44
|
+
Fetch a live contract spec and generate a typed TypeScript interface + example file:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx sck generate --contract CABC... --network testnet
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or add it as an npm script so the team can run it without `npx`:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
"scripts": {
|
|
54
|
+
"generate": "sck generate --contract CABC... --network testnet"
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm run generate
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
With options:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx sck generate \
|
|
66
|
+
--contract CABC... \
|
|
67
|
+
--network testnet \
|
|
68
|
+
--name CounterContract \
|
|
69
|
+
--out src/contracts/counter.ts
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
For JavaScript output:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx sck generate --contract CABC... --network testnet --js
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Output files:**
|
|
79
|
+
|
|
80
|
+
| File | Description |
|
|
81
|
+
|------|-------------|
|
|
82
|
+
| `contracts/counter.ts` | TypeScript interface + custom types + contract ID |
|
|
83
|
+
| `contracts/counter.example.ts` | Ready-to-adapt usage example for every method |
|
|
84
|
+
|
|
85
|
+
**Generated `contracts/counter.ts`:**
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import type { ContractMethodFn } from 'stellar-contracts-kit'
|
|
89
|
+
|
|
90
|
+
export interface CounterContract {
|
|
91
|
+
get: ContractMethodFn<number, []>
|
|
92
|
+
increment: ContractMethodFn<number, []>
|
|
93
|
+
reset: ContractMethodFn<void, []>
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const CONTRACT_ID = 'CABC...' as const
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Re-run `npx sck generate` after a contract upgrade to refresh the types.
|
|
100
|
+
|
|
101
|
+
### Inspect a contract
|
|
102
|
+
|
|
103
|
+
Print all functions and custom types for any contract directly in the terminal, without generating files:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npx sck inspect --contract CABC... --network testnet
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Output:**
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
Contract : CABC...
|
|
113
|
+
Network : testnet
|
|
114
|
+
|
|
115
|
+
Functions (5)
|
|
116
|
+
get() -> number
|
|
117
|
+
increment() -> number
|
|
118
|
+
reset() -> void
|
|
119
|
+
transfer(from: string, to: string, amount: bigint) -> void
|
|
120
|
+
balance(account: string) -> bigint
|
|
121
|
+
|
|
122
|
+
Custom Types (2)
|
|
123
|
+
struct TokenInfo { symbol: string, decimals: number }
|
|
124
|
+
enum Status { Active = 0, Inactive = 1 }
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Custom network
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx sck generate \
|
|
131
|
+
--contract CABC... \
|
|
132
|
+
--rpc-url https://my-rpc.example.com \
|
|
133
|
+
--passphrase "My Custom Network"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### CLI options
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
Commands:
|
|
140
|
+
npx sck generate [options] Generate TypeScript types and example file
|
|
141
|
+
npx sck inspect [options] Print contract interface to the terminal
|
|
142
|
+
npx sck Interactive mode (arrow-key selection)
|
|
143
|
+
|
|
144
|
+
Shared options:
|
|
145
|
+
--contract Contract address (C..., 56 chars) [required]
|
|
146
|
+
--network testnet | mainnet | futurenet
|
|
147
|
+
--rpc-url Custom RPC URL
|
|
148
|
+
--passphrase Custom network passphrase
|
|
149
|
+
|
|
150
|
+
Generate-only options:
|
|
151
|
+
--out Output file path (default: ./contracts/<name>.ts)
|
|
152
|
+
--name Interface name (default: derived from --out)
|
|
153
|
+
--alias tsconfig path alias (auto-detected from tsconfig.json)
|
|
154
|
+
--js JavaScript output instead of TypeScript
|
|
155
|
+
--help, -h Show help
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## SDK
|
|
161
|
+
|
|
162
|
+
### Quick start
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
import { StellarContractsKit } from 'stellar-contracts-kit'
|
|
166
|
+
|
|
167
|
+
const kit = new StellarContractsKit({ network: 'testnet' })
|
|
168
|
+
|
|
169
|
+
// Opens built-in wallet picker modal
|
|
170
|
+
const { address } = await kit.connect()
|
|
171
|
+
|
|
172
|
+
// Load a contract client
|
|
173
|
+
const counter = await kit.contract('CABC...')
|
|
174
|
+
|
|
175
|
+
// Read-only (no wallet, no TX)
|
|
176
|
+
const { result } = await counter.get.read()
|
|
177
|
+
|
|
178
|
+
// Write (requires connected wallet)
|
|
179
|
+
const { txHash } = await counter.increment.invoke()
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### With generated types
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import type { CounterContract } from './contracts/counter.js'
|
|
186
|
+
import { CONTRACT_ID } from './contracts/counter.js'
|
|
187
|
+
|
|
188
|
+
const counter = await kit.contract<CounterContract>(CONTRACT_ID)
|
|
189
|
+
|
|
190
|
+
// Full IDE autocomplete + type checking on all methods
|
|
191
|
+
const { result } = await counter.get.read()
|
|
192
|
+
const { txHash } = await counter.increment.invoke()
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Wallet Connection
|
|
198
|
+
|
|
199
|
+
### Built-in modal (recommended)
|
|
200
|
+
|
|
201
|
+
Calling `connect()` with no wallet configured opens a modal that auto-detects installed wallets:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
const kit = new StellarContractsKit({ network: 'testnet' })
|
|
205
|
+
const { address } = await kit.connect()
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
The modal shows all supported wallets in order, with "Install" links for wallets that are not detected.
|
|
209
|
+
|
|
210
|
+
### Specific wallet adapter
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { StellarContractsKit, FreighterAdapter } from 'stellar-contracts-kit'
|
|
214
|
+
|
|
215
|
+
const kit = new StellarContractsKit({
|
|
216
|
+
network: 'testnet',
|
|
217
|
+
wallet: new FreighterAdapter(),
|
|
218
|
+
})
|
|
219
|
+
const { address } = await kit.connect()
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Supported wallets
|
|
223
|
+
|
|
224
|
+
| Wallet | Adapter | Install |
|
|
225
|
+
|--------|---------|---------|
|
|
226
|
+
| [Freighter](https://github.com/stellar/freighter) | `FreighterAdapter` | [freighter.app](https://freighter.app) |
|
|
227
|
+
| [Cyphras](https://github.com/cyphras/cyphras-extension) | `CyphrasAdapter` | [cyphras.com](https://cyphras.com) |
|
|
228
|
+
| [Lobstr](https://github.com/Lobstrco/lobstr-browser-extension) | `LobstrAdapter` | [lobstr.co](https://lobstr.co) |
|
|
229
|
+
|
|
230
|
+
### Other wallet methods
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
await kit.disconnect()
|
|
234
|
+
kit.isConnected() // boolean
|
|
235
|
+
await kit.getAddress() // string, throws WALLET_NOT_CONNECTED if none
|
|
236
|
+
kit.getWallet() // WalletAdapter | null
|
|
237
|
+
kit.setWallet(adapter) // replace active wallet
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Contract Interaction
|
|
243
|
+
|
|
244
|
+
### Call modes
|
|
245
|
+
|
|
246
|
+
Every method on the contract client has three modes:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
// Auto: simulates first, submits TX only if auth is required
|
|
250
|
+
const result = await counter.increment()
|
|
251
|
+
|
|
252
|
+
// Read: simulate only, no wallet needed, no TX submitted
|
|
253
|
+
const { result } = await counter.get.read()
|
|
254
|
+
|
|
255
|
+
// Invoke: always submits a TX, requires a connected wallet
|
|
256
|
+
const { txHash, result } = await counter.increment.invoke()
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Passing arguments
|
|
260
|
+
|
|
261
|
+
Arguments are passed positionally in the order defined by the contract:
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
const { result } = await token.balance.read(userAddress)
|
|
265
|
+
const { txHash } = await token.transfer.invoke(from, to, amount)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Spec caching
|
|
269
|
+
|
|
270
|
+
The contract spec is fetched once per contract ID and cached in memory. Subsequent `kit.contract()` calls with the same ID return instantly:
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
const counter = await kit.contract<CounterContract>(CONTRACT_ID) // fetches spec
|
|
274
|
+
const counter2 = await kit.contract<CounterContract>(CONTRACT_ID) // instant
|
|
275
|
+
|
|
276
|
+
kit.clearSpecCache(CONTRACT_ID) // clear one
|
|
277
|
+
kit.clearSpecCache() // clear all
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Custom Networks
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
const kit = new StellarContractsKit({
|
|
286
|
+
network: {
|
|
287
|
+
rpcUrl: 'https://my-soroban-rpc.example.com',
|
|
288
|
+
networkPassphrase: 'My Custom Network',
|
|
289
|
+
horizonUrl: 'https://my-horizon.example.com',
|
|
290
|
+
},
|
|
291
|
+
})
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Built-in network presets:
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
import { NETWORKS } from 'stellar-contracts-kit'
|
|
298
|
+
|
|
299
|
+
NETWORKS.testnet // Test SDF Network
|
|
300
|
+
NETWORKS.mainnet // Public Global Stellar Network
|
|
301
|
+
NETWORKS.futurenet // Test SDF Future Network
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Error Handling
|
|
307
|
+
|
|
308
|
+
All errors thrown by the kit are `StellarContractError` instances with a `code` property:
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
import { isContractKitError } from 'stellar-contracts-kit'
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
await counter.increment.invoke()
|
|
315
|
+
} catch (err) {
|
|
316
|
+
if (isContractKitError(err)) {
|
|
317
|
+
switch (err.code) {
|
|
318
|
+
case 'WALLET_REJECTED':
|
|
319
|
+
console.log('User rejected the transaction.')
|
|
320
|
+
break
|
|
321
|
+
case 'CONTRACT_RESTORE_REQUIRED':
|
|
322
|
+
await kit.restoreContract(CONTRACT_ID)
|
|
323
|
+
await counter.increment.invoke() // retry
|
|
324
|
+
break
|
|
325
|
+
case 'TX_FAILED':
|
|
326
|
+
console.error('On-chain failure:', err.message)
|
|
327
|
+
break
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Error codes
|
|
334
|
+
|
|
335
|
+
| Code | Description |
|
|
336
|
+
|------|-------------|
|
|
337
|
+
| `WALLET_NOT_FOUND` | Wallet extension not installed |
|
|
338
|
+
| `WALLET_NOT_CONNECTED` | No wallet is connected |
|
|
339
|
+
| `WALLET_REJECTED` | User rejected the connection or signing request |
|
|
340
|
+
| `WALLET_NETWORK_MISMATCH` | Wallet is on a different network than the kit |
|
|
341
|
+
| `CONTRACT_NOT_FOUND` | Contract does not exist on the network |
|
|
342
|
+
| `CONTRACT_SPEC_ERROR` | Could not parse the contract WASM spec |
|
|
343
|
+
| `CONTRACT_SIMULATION_FAILED` | Transaction simulation failed |
|
|
344
|
+
| `CONTRACT_RESTORE_REQUIRED` | Contract state expired, call `restoreContract()` |
|
|
345
|
+
| `INVALID_CONTRACT_ID` | Invalid contract address format |
|
|
346
|
+
| `INVALID_PARAMS` | Wrong number of arguments passed to a method |
|
|
347
|
+
| `TX_SUBMISSION_FAILED` | Transaction rejected at submission |
|
|
348
|
+
| `TX_FAILED` | Transaction accepted but failed on-chain |
|
|
349
|
+
| `TX_TIMEOUT` | Transaction not confirmed within the polling window |
|
|
350
|
+
| `RPC_ERROR` | RPC call failed or returned an unexpected response |
|
|
351
|
+
| `UNKNOWN` | Unexpected error |
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Restoring Expired Contracts
|
|
356
|
+
|
|
357
|
+
Soroban contracts can expire when their TTL runs out. Any call that touches expired state throws `CONTRACT_RESTORE_REQUIRED`. Use `restoreContract()` to recover:
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
try {
|
|
361
|
+
await counter.increment.invoke()
|
|
362
|
+
} catch (err) {
|
|
363
|
+
if (isContractKitError(err) && err.code === 'CONTRACT_RESTORE_REQUIRED') {
|
|
364
|
+
const { txHash } = await kit.restoreContract(CONTRACT_ID)
|
|
365
|
+
console.log('Restored:', txHash)
|
|
366
|
+
await counter.increment.invoke() // retry
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Custom Wallet Adapter
|
|
374
|
+
|
|
375
|
+
Implement `WalletAdapter` to add support for any wallet:
|
|
376
|
+
|
|
377
|
+
```ts
|
|
378
|
+
import type { WalletAdapter } from 'stellar-contracts-kit'
|
|
379
|
+
|
|
380
|
+
class MyWalletAdapter implements WalletAdapter {
|
|
381
|
+
readonly name = 'MyWallet'
|
|
382
|
+
readonly installUrl = 'https://mywallet.example.com'
|
|
383
|
+
|
|
384
|
+
isAvailable(): boolean | Promise<boolean> { ... }
|
|
385
|
+
async connect(): Promise<{ address: string }> { ... }
|
|
386
|
+
async disconnect(): Promise<void> { ... }
|
|
387
|
+
async getAddress(): Promise<string> { ... }
|
|
388
|
+
async getNetworkPassphrase(): Promise<string> { ... }
|
|
389
|
+
async signTransaction(xdr: string, opts): Promise<string> { ... }
|
|
390
|
+
async signAuthEntry(entryXdr: string, opts): Promise<string> { ... }
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## API Reference
|
|
397
|
+
|
|
398
|
+
### `StellarContractsKit`
|
|
399
|
+
|
|
400
|
+
```ts
|
|
401
|
+
new StellarContractsKit(options: StellarContractsKitOptions)
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
| Method | Returns | Description |
|
|
405
|
+
|--------|---------|-------------|
|
|
406
|
+
| `connect()` | `Promise<{ address: string }>` | Connect to wallet or open picker modal |
|
|
407
|
+
| `disconnect()` | `Promise<void>` | Disconnect and clear the active wallet |
|
|
408
|
+
| `isConnected()` | `boolean` | True if a wallet is active |
|
|
409
|
+
| `getAddress()` | `Promise<string>` | Address of the connected wallet |
|
|
410
|
+
| `getWallet()` | `WalletAdapter \| null` | Active wallet adapter |
|
|
411
|
+
| `setWallet(adapter)` | `void` | Set or replace the active wallet |
|
|
412
|
+
| `getNetwork()` | `NetworkConfig` | Current network configuration |
|
|
413
|
+
| `contract<T>(id)` | `Promise<T>` | Load a typed contract client |
|
|
414
|
+
| `restoreContract(id)` | `Promise<{ txHash: string }>` | Restore expired contract state |
|
|
415
|
+
| `clearSpecCache(id?)` | `void` | Clear cached spec for one or all contracts |
|
|
416
|
+
|
|
417
|
+
### `ContractMethodFn<TReturn, TArgs>`
|
|
418
|
+
|
|
419
|
+
The type for each method on a generated contract interface:
|
|
420
|
+
|
|
421
|
+
```ts
|
|
422
|
+
ContractMethodFn<TReturn, TArgs extends unknown[] = unknown[]>
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
| Type param | Description |
|
|
426
|
+
|------------|-------------|
|
|
427
|
+
| `TReturn` | Return value type (`number`, `bigint`, `string`, `void`, custom struct, ...) |
|
|
428
|
+
| `TArgs` | Labeled tuple of argument types (`[from: string, amount: bigint]`) |
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## License
|
|
433
|
+
|
|
434
|
+
[MIT](LICENSE)
|