@spield/sdk 0.4.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/CHANGELOG.md +67 -0
- package/README.md +94 -0
- package/RELEASE.md +8 -0
- package/USAGE.md +215 -0
- package/dist/index.cjs +1520 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +783 -0
- package/dist/index.d.ts +783 -0
- package/dist/index.js +1474 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
Breaking. The SDK now targets only the SR-based (v2) contracts on Testnet.
|
|
6
|
+
|
|
7
|
+
- Remove the legacy v1 protocol: the `wrapper`, `vault`, `market`, `tokens`, `portfolio` and
|
|
8
|
+
`protocol` clients, their config addresses, and the PT+YT dual-trustline path. YT is a contract
|
|
9
|
+
token issued by the yield engine and never needed a trustline.
|
|
10
|
+
- Promote the protocol namespaces to the client itself: `client.sr`, `client.yield`, `client.market`
|
|
11
|
+
and friends replace `client.current.*` / `client.v2.*`, which are gone along with `SpieldV2Client`.
|
|
12
|
+
- Flatten the network config: the former `v2.contracts` / `v2.assets` are now `contracts` / `assets`,
|
|
13
|
+
so `SpieldV2NetworkConfig` and the `requireV2` guard are no longer needed.
|
|
14
|
+
- Remove `mainnetPreview()`. The SDK ships Testnet only; use `customNetwork()` for anything else.
|
|
15
|
+
- Map contract errors from `contracts/shared/src/errors.rs` instead of guessing from message text.
|
|
16
|
+
A failed `sr.deposit` previously reported "The wallet needs PT and YT trustlines before receiving
|
|
17
|
+
minted tokens", which was both v1-shaped and wrong for a USDC wrap; `Error(Contract, #N)` codes
|
|
18
|
+
such as the deposit cap (#107), slippage floors (#105) and dust (#106) were not surfaced at all.
|
|
19
|
+
- Move `fromScalar12` to `./sr` alongside `SCALAR_12`; it is still exported from the package root.
|
|
20
|
+
- Cover the USDC → SR → PT + YT path in the integration suite, asserting the exact contract,
|
|
21
|
+
method and argument layout of `sr.deposit` and `yield.mint_py`.
|
|
22
|
+
- Update the six examples and the browser test app to the flat client.
|
|
23
|
+
|
|
24
|
+
## Unreleased
|
|
25
|
+
|
|
26
|
+
- Point the v2 Testnet config at the 2026-08-27 SR redeploy. The SDK was still pinned to the
|
|
27
|
+
superseded stack recorded in `deploy_sr_testnet.state.pre-redeploy-20260827`, whose deposit cap is
|
|
28
|
+
full (zero headroom), so wraps and deposits could not succeed. SR, strategy, yield engine, market,
|
|
29
|
+
vault, router and the PT SAC all move, and the PT trustline asset becomes `SPLDPT6`.
|
|
30
|
+
- Assert the SR deposit-cap invariant in the Testnet read smoke instead of pinning a live headroom
|
|
31
|
+
value that changes with every deposit.
|
|
32
|
+
- Fix a packaging defect that made the tarball uninstallable under npm: `@spield/sdk` declared
|
|
33
|
+
itself as a `link:` dependency on a machine-local path, so `npm install` failed with
|
|
34
|
+
`EUNSUPPORTEDPROTOCOL`.
|
|
35
|
+
- Drop the unused `dotenv` runtime dependency, so consumers only pull in `@stellar/stellar-sdk`.
|
|
36
|
+
- Fill in the unset `allowBuilds` placeholder in `pnpm-workspace.yaml`; `pnpm install` exited 1 with
|
|
37
|
+
`ERR_PNPM_IGNORED_BUILDS` on a fresh clone.
|
|
38
|
+
- Stop type-checking `examples/sdk-test-app` from the root `tsconfig.json`; its browser wallet
|
|
39
|
+
dependencies are not part of the root install, so `pnpm run typecheck` exited 2. The demo is still
|
|
40
|
+
type-checked by its own `pnpm --dir examples/sdk-test-app run build`.
|
|
41
|
+
- Drop the unfulfilled `MIT` license declaration and its `files` entry; the package ships no
|
|
42
|
+
license for now.
|
|
43
|
+
|
|
44
|
+
## 0.3.1
|
|
45
|
+
|
|
46
|
+
- Track the Testnet SR deposit-cap rollout with `SrState.depositCapReached`, while preserving the
|
|
47
|
+
existing typed cap and headroom amounts.
|
|
48
|
+
- Verify the live 100 USDC cap and zero headroom without treating the cap as a withdrawal pause.
|
|
49
|
+
|
|
50
|
+
## 0.3.0
|
|
51
|
+
|
|
52
|
+
- Integrate the 2026-08-27 contract-source changes: Blend strategy reads, holder/LP/receipt
|
|
53
|
+
keep-alives, caller-controlled LP `minShares`, resumable vault redemption state, and vault surplus.
|
|
54
|
+
- Detect the deployed old market ABI for zero-bound liquidity adds and normalize old vault
|
|
55
|
+
receipts/stats so the latest SDK continues to work before the Testnet contracts are upgraded.
|
|
56
|
+
- Track the latest router deployment from `deploy_sr_testnet.state`.
|
|
57
|
+
|
|
58
|
+
## 0.2.0
|
|
59
|
+
|
|
60
|
+
- Add the current SR-based protocol under `client.current` / `client.v2`.
|
|
61
|
+
- Ship the live 2026-08-25 Testnet SR, yield-engine, PT/SR market, vault, router, PT, and USDC addresses.
|
|
62
|
+
- Add live-safe YT buy/sell orchestration, SR partial exits, v2 health/portfolio reads, and PT-only trustline setup.
|
|
63
|
+
- Keep the original v1 top-level clients for backward compatibility.
|
|
64
|
+
|
|
65
|
+
## 0.1.0
|
|
66
|
+
|
|
67
|
+
- Initial SDK scaffold for Spield Testnet fixed-rate vault, wrapper, market, tokens, portfolio, and protocol APIs.
|
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @spield/sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the Spield Protocol on Stellar Testnet. The SDK targets the SR-based contracts
|
|
4
|
+
recorded in `deploy_sr_testnet.state` (2026-08-27 redeploy).
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { FreighterSigner, SpieldClient, testnet } from '@spield/sdk';
|
|
8
|
+
|
|
9
|
+
const client = new SpieldClient({
|
|
10
|
+
network: testnet(),
|
|
11
|
+
signer: new FreighterSigner(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const health = await client.protocol.getHealth();
|
|
15
|
+
const srQuote = await client.sr.previewDeposit({ amount: '100' });
|
|
16
|
+
const ptQuote = await client.router.quoteBuyPt({ usdcIn: '100' });
|
|
17
|
+
|
|
18
|
+
await client.tokens.ensurePtTrustline();
|
|
19
|
+
await client.router.buyPt({ usdcIn: '100' });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## The protocol model
|
|
23
|
+
|
|
24
|
+
USDC wraps into **SR**, a yield-bearing share token over a Blend strategy. SR splits into **PT**
|
|
25
|
+
(principal) and **YT** (yield). PT trades against SR on the market, and the fixed-rate vault sells a
|
|
26
|
+
guaranteed coupon out of its PT inventory.
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
USDC ──sr.deposit──▶ SR ──yield.mintPy──▶ PT + YT
|
|
30
|
+
▲ │
|
|
31
|
+
└──yield.redeemPy─────┘
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
SR is a share token, so **one SR is not one USDC** — use `sr.previewDeposit` / `sr.previewRedeem`, or
|
|
35
|
+
`sr.srToUnderlying` / `sr.underlyingToSr` with the current `exchangeRate`.
|
|
36
|
+
|
|
37
|
+
## Namespaces
|
|
38
|
+
|
|
39
|
+
| Namespace | What it does |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `client.sr` | Wrap USDC into SR shares; unwrap fully or partially |
|
|
42
|
+
| `client.strategy` | Blend rate guard, position value, withdrawable liquidity |
|
|
43
|
+
| `client.yield` | Mint/redeem PT + YT, read and claim interest, transfer YT |
|
|
44
|
+
| `client.market` | PT/SR quotes, PT and YT trades, liquidity |
|
|
45
|
+
| `client.vault` | Fixed-rate quotes, receipts, deposit, redeem, harvest |
|
|
46
|
+
| `client.router` | One-transaction USDC routes for PT, redemption, and yield claims |
|
|
47
|
+
| `client.tokens` | USDC/SR/PT/YT balances and the single required PT trustline |
|
|
48
|
+
| `client.portfolio` | Wallet-wide balances, interest, LP position, vault receipts |
|
|
49
|
+
| `client.protocol` | Cross-contract health and yield-engine solvency |
|
|
50
|
+
|
|
51
|
+
**Trustlines:** PT is the only classic asset, so it is the only trustline a wallet needs. The yield
|
|
52
|
+
engine contract *is* the YT token — YT is a contract token with no trustline. Call
|
|
53
|
+
`client.tokens.ensurePtTrustline()` once before receiving PT.
|
|
54
|
+
|
|
55
|
+
**YT trades take two signatures.** The deployed Blend-backed stack cannot fit a YT wrap+trade or
|
|
56
|
+
trade+unwrap into a single Soroban transaction. `client.buyYtFromUsdc()` and
|
|
57
|
+
`client.sellYtToUsdc()` deliberately use up to two wallet signatures and report progress.
|
|
58
|
+
|
|
59
|
+
See [USAGE.md](./USAGE.md) for complete examples.
|
|
60
|
+
|
|
61
|
+
## Scope
|
|
62
|
+
|
|
63
|
+
Testnet only. There is no mainnet configuration in this SDK. Point it at another deployment with
|
|
64
|
+
`customNetwork()` if you need one.
|
|
65
|
+
|
|
66
|
+
## Development and verification
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pnpm install
|
|
70
|
+
pnpm run typecheck
|
|
71
|
+
pnpm test
|
|
72
|
+
pnpm run build
|
|
73
|
+
pnpm run test:package
|
|
74
|
+
pnpm run test:e2e:testnet
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The Testnet read suite validates SR, Blend liquidity, yield-engine solvency, PT/SR reserves and
|
|
78
|
+
prices, vault backing, and router quotes against the checked-in live deployment, and cross-checks
|
|
79
|
+
that the engine, market and vault all agree on one series expiry. The write smoke test is skipped
|
|
80
|
+
unless a disposable funded `SPIELD_E2E_SECRET` is provided; it only creates/verifies the PT
|
|
81
|
+
trustline.
|
|
82
|
+
|
|
83
|
+
## Manual SDK test app
|
|
84
|
+
|
|
85
|
+
A browser console that exercises every SDK method against Testnet:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pnpm --dir examples/sdk-test-app install
|
|
89
|
+
pnpm demo
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Reads work without a wallet. Writing uses the same multi-wallet connector as the Protocol frontend
|
|
93
|
+
and requires a disposable funded Testnet account.
|
|
94
|
+
See [the demo README](./examples/sdk-test-app/README.md) for details.
|
package/RELEASE.md
ADDED
package/USAGE.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Using the Spield SDK
|
|
2
|
+
|
|
3
|
+
## Create a client
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { FreighterSigner, SpieldClient, testnet } from '@spield/sdk';
|
|
7
|
+
|
|
8
|
+
// Omit the signer for read-only use.
|
|
9
|
+
const client = new SpieldClient({
|
|
10
|
+
network: testnet(),
|
|
11
|
+
signer: new FreighterSigner(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Protocol namespaces live directly on the client: client.sr, client.yield, client.market, ...
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`testnet()` contains the verified SR deployment from the 2026-08-27 redeploy, and is the default
|
|
18
|
+
when no `network` is given. The SDK ships Testnet only — use `customNetwork()` to point it at any
|
|
19
|
+
other deployment.
|
|
20
|
+
|
|
21
|
+
## Amounts
|
|
22
|
+
|
|
23
|
+
Strings and numbers are human token amounts. A `bigint` is already in base units.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { fromBaseUnits, toBaseUnits } from '@spield/sdk';
|
|
27
|
+
|
|
28
|
+
toBaseUnits('10.25'); // 102500000n
|
|
29
|
+
fromBaseUnits(102500000n); // "10.25"
|
|
30
|
+
|
|
31
|
+
const quote = await client.vault.quoteFixedRate({ amount: '100' });
|
|
32
|
+
console.log(quote.payout.formatted, quote.payout.raw);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
All protocol tokens use seven decimals. Prices, APYs, and exchange-rate indexes use 12-decimal
|
|
36
|
+
fixed point and are returned as exact `bigint` values plus display-friendly fields where useful.
|
|
37
|
+
|
|
38
|
+
## PT trustline
|
|
39
|
+
|
|
40
|
+
Only PT requires a trustline. The yield engine itself is the YT token, so creating a YT trustline
|
|
41
|
+
is incorrect.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
const status = await client.tokens.getPtTrustline({ owner: walletAddress });
|
|
45
|
+
if (!status.ready) await client.tokens.ensurePtTrustline();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Set this up before any flow that delivers PT: buying PT, minting PT+YT, or removing liquidity.
|
|
49
|
+
|
|
50
|
+
## SR: wrap and unwrap
|
|
51
|
+
|
|
52
|
+
SR represents shares in the Blend-backed strategy. Its USDC value is `shares × exchangeRate / 1e12`.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
const preview = await client.sr.previewDeposit({ amount: '50' });
|
|
56
|
+
await client.sr.deposit({ amount: '50', minSharesOut: preview.raw * 99n / 100n });
|
|
57
|
+
|
|
58
|
+
const state = await client.sr.getState();
|
|
59
|
+
const balance = await client.sr.getBalance({ owner: walletAddress });
|
|
60
|
+
const value = client.sr.srToUnderlying(balance.raw, state.exchangeRate);
|
|
61
|
+
|
|
62
|
+
await client.sr.redeem({ shares: balance.raw, minUnderlyingOut: 0n });
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
During a Blend liquidity crunch, query `getState().maxRedeemable` and use `redeemPartial()` so the
|
|
66
|
+
available portion can exit while the rest remains held.
|
|
67
|
+
|
|
68
|
+
`getState()` also reports `depositCap`, `depositHeadroom`, and `depositCapReached`. A reached cap
|
|
69
|
+
blocks new deposits only; it does not block `redeem()` or `redeemPartial()`. The live Testnet cap is
|
|
70
|
+
currently 100 USDC and is below its existing TVL, so `depositCapReached` is expected to be `true`.
|
|
71
|
+
|
|
72
|
+
## PT and YT engine
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
await client.tokens.ensurePtTrustline();
|
|
76
|
+
await client.yield.mintPy({ srIn: '50' });
|
|
77
|
+
|
|
78
|
+
const interest = await client.yield.getClaimableInterest({ owner: walletAddress });
|
|
79
|
+
await client.yield.claimYield();
|
|
80
|
+
|
|
81
|
+
await client.yield.transferYt({ to: receiver, amount: '5' });
|
|
82
|
+
await client.yield.redeemPy({ amount: '10' });
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Before expiry, `redeemPy()` burns both PT and YT. After expiry, it burns PT only and redeems
|
|
86
|
+
principal at face value.
|
|
87
|
+
|
|
88
|
+
## Buy and sell PT with USDC
|
|
89
|
+
|
|
90
|
+
The router wraps/unwraps SR inside supported routes and applies a 1% output floor by default.
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
await client.tokens.ensurePtTrustline();
|
|
94
|
+
|
|
95
|
+
const buyQuote = await client.router.quoteBuyPt({ usdcIn: '100' });
|
|
96
|
+
await client.router.buyPt({ usdcIn: '100', slippageBps: 100 });
|
|
97
|
+
|
|
98
|
+
const sellQuote = await client.router.quoteSellPt({ ptIn: '25' });
|
|
99
|
+
await client.router.sellPt({ ptIn: '25', slippageBps: 100 });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Pass an explicit `minPtOut` or `minUsdcOut` to replace the quote-derived floor. Zero is valid when
|
|
103
|
+
the caller intentionally disables the floor.
|
|
104
|
+
|
|
105
|
+
## Buy and sell YT with USDC
|
|
106
|
+
|
|
107
|
+
Use the high-level two-step methods. Against the deployed Blend pool, the combined router YT paths
|
|
108
|
+
exceed Soroban's transaction resource budget even though each leg succeeds separately.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
await client.buyYtFromUsdc({
|
|
112
|
+
ytOut: '100',
|
|
113
|
+
onProgress: (step, index, total) => console.log(step, `${index}/${total}`),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
await client.sellYtToUsdc({
|
|
117
|
+
ytIn: '50',
|
|
118
|
+
onProgress: (step, index, total) => console.log(step, `${index}/${total}`),
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`buyYtFromUsdc()` checks the wallet's SR balance, wraps only the shortfall, pads `max_sr_in` by 3%
|
|
123
|
+
to keep authorization stable across index drift, and then buys exact YT output. Excess SR is
|
|
124
|
+
refunded by the market. `sellYtToUsdc()` sells YT, reads the actual SR received, and unwraps it.
|
|
125
|
+
|
|
126
|
+
For wallets that already hold SR, use direct market routes:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
const quote = await client.market.quoteBuyYt({ ytOut: '100' });
|
|
130
|
+
await client.market.buyYt({ ytOut: '100' });
|
|
131
|
+
await client.market.sellYt({ ytIn: '25', minSrOut: 0n });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Fixed-rate vault
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const quote = await client.vault.quoteFixedRate({ amount: '100' });
|
|
138
|
+
const deposit = await client.vault.deposit({ amount: '100' });
|
|
139
|
+
|
|
140
|
+
const stats = await client.vault.getStats();
|
|
141
|
+
const receipts = await client.vault.getOwnerReceipts({ owner: walletAddress });
|
|
142
|
+
const remaining = receipts[0]
|
|
143
|
+
? await client.vault.getRedeemRemaining({ receiptId: receipts[0].receiptId })
|
|
144
|
+
: null;
|
|
145
|
+
|
|
146
|
+
if (receipts[0]?.open && Date.now() >= receipts[0].maturityDate.getTime()) {
|
|
147
|
+
await client.vault.redeemReceipt({ receiptId: receipts[0].receiptId });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
await client.vault.harvest();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The vault quote and receipt payout are USDC-denominated. On the latest contract ABI, redemption is
|
|
154
|
+
resumable: a liquidity-constrained call banks progress in `receipt.collected`, while
|
|
155
|
+
`getRedeemRemaining()` reports what is still owed. The SDK derives the same value from old receipts
|
|
156
|
+
when connected to the currently deployed pre-upgrade Testnet vault.
|
|
157
|
+
|
|
158
|
+
## Market, portfolio, and health
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const stats = await client.market.getStats();
|
|
162
|
+
const lp = await client.market.getLpPosition({ owner: walletAddress });
|
|
163
|
+
|
|
164
|
+
await client.market.addLiquidity({ ptIn: '10', srIn: '10', minShares: '9.9' });
|
|
165
|
+
await client.market.removeLiquidity({ shares: lp.shares.raw, minPtOut: 0n, minSrOut: 0n });
|
|
166
|
+
|
|
167
|
+
const portfolio = await client.portfolio.getPortfolio({ owner: walletAddress });
|
|
168
|
+
const health = await client.protocol.getHealth();
|
|
169
|
+
const solvency = await client.protocol.getSolvency();
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Raw market routes use SR, not USDC. Quote methods return `available: false` when the on-chain quote
|
|
173
|
+
is zero; this means the pool cannot fill the requested size.
|
|
174
|
+
|
|
175
|
+
`minShares` is supported by the latest market ABI. The SDK detects the currently deployed older
|
|
176
|
+
market and uses its three-argument liquidity call when `minShares` is zero. A positive bound on an
|
|
177
|
+
old deployment fails before wallet signing with `SpieldConfigurationError`.
|
|
178
|
+
|
|
179
|
+
## Contract ABI compatibility
|
|
180
|
+
|
|
181
|
+
The SDK includes the latest source-contract additions: SR/YT/LP/receipt keep-alives, caller-bounded
|
|
182
|
+
LP minting, Blend liquidity state, resumable vault receipt fields, remaining redemption reads, and
|
|
183
|
+
vault surplus reads. As verified on 2026-08-27, the public Testnet SR/market/vault addresses still
|
|
184
|
+
carry the preceding ABI. Read mappings and default liquidity adds remain backward-compatible; new
|
|
185
|
+
write entry points become usable when those contracts are upgraded on chain.
|
|
186
|
+
|
|
187
|
+
## Custom deployments
|
|
188
|
+
|
|
189
|
+
Supply the full contract set:
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
const network = customNetwork({
|
|
193
|
+
key: 'custom',
|
|
194
|
+
networkName: 'TESTNET',
|
|
195
|
+
networkPassphrase: 'Test SDF Network ; September 2015',
|
|
196
|
+
rpcUrl: 'https://soroban-testnet.stellar.org',
|
|
197
|
+
horizonUrl: 'https://horizon-testnet.stellar.org',
|
|
198
|
+
explorerUrl: 'https://stellar.expert/explorer/testnet',
|
|
199
|
+
decimals: 7,
|
|
200
|
+
contracts: {
|
|
201
|
+
sr: '...', strategy: '...', yieldEngine: '...', market: '...',
|
|
202
|
+
vault: '...', router: '...', pt: '...', usdc: '...',
|
|
203
|
+
},
|
|
204
|
+
assets: { pt: { code: '...', issuer: '...' } },
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Errors
|
|
209
|
+
|
|
210
|
+
The SDK exports `SpieldValidationError`, `SpieldSignerError`, `SpieldContractError`,
|
|
211
|
+
`SpieldRpcError`, and `SpieldConfigurationError`. Write calls simulate before signing, submit only
|
|
212
|
+
after wallet approval, and return `{ hash, status: 'success', explorerUrl }` after confirmation.
|
|
213
|
+
The SDK polls Testnet RPC for up to two minutes by default because an accepted transaction can be
|
|
214
|
+
indexed after ledger close. Override `confirmationTimeoutMs` and `confirmationPollIntervalMs` in
|
|
215
|
+
`SpieldClient` options when your application needs different confirmation behavior.
|