@arkade-os/sdk 0.5.0-rc.3 → 0.5.0-rc.30
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/README.md +223 -83
- package/dist/adapters/expo.cjs +5 -6
- package/dist/adapters/expo.d.cts +5 -5
- package/dist/adapters/expo.d.ts +5 -5
- package/dist/adapters/expo.js +3 -4
- package/dist/{asyncStorageTaskQueue-DAs_n1xr.d.ts → asyncStorageTaskQueue-DAVf4Fyy.d.ts} +2 -2
- package/dist/{asyncStorageTaskQueue-DqGRG66E.d.cts → asyncStorageTaskQueue-fkkUPrhz.d.cts} +2 -2
- package/dist/{chunk-FSF2PGTR.cjs → chunk-3SM7BMIE.cjs} +6736 -5189
- package/dist/chunk-3SM7BMIE.cjs.map +1 -0
- package/dist/{chunk-UCSTNXB4.cjs → chunk-4MCQZYH6.cjs} +501 -1153
- package/dist/chunk-4MCQZYH6.cjs.map +1 -0
- package/dist/{chunk-BCT7DT2J.cjs → chunk-6BTZ6KFI.cjs} +12 -10
- package/dist/chunk-6BTZ6KFI.cjs.map +1 -0
- package/dist/{chunk-L4HZK4KK.cjs → chunk-AICUNREA.cjs} +158 -263
- package/dist/chunk-AICUNREA.cjs.map +1 -0
- package/dist/{chunk-UJTYUYY4.cjs → chunk-ASKOHVGX.cjs} +596 -467
- package/dist/chunk-ASKOHVGX.cjs.map +1 -0
- package/dist/{chunk-43XGA362.cjs → chunk-DLHE4RCH.cjs} +40 -43
- package/dist/chunk-DLHE4RCH.cjs.map +1 -0
- package/dist/{chunk-7W6FHWYN.js → chunk-ESEHYZAY.js} +434 -1109
- package/dist/chunk-ESEHYZAY.js.map +1 -0
- package/dist/{chunk-HSG2GQTM.js → chunk-G6ZPX2GL.js} +586 -462
- package/dist/chunk-G6ZPX2GL.js.map +1 -0
- package/dist/{chunk-G4UPMCKW.js → chunk-KK6GXY4L.js} +33 -36
- package/dist/chunk-KK6GXY4L.js.map +1 -0
- package/dist/{chunk-ERUAQGYF.js → chunk-PY3YQNHP.js} +146 -252
- package/dist/chunk-PY3YQNHP.js.map +1 -0
- package/dist/{chunk-VQCDDGRW.js → chunk-XW72DWYO.js} +6350 -4816
- package/dist/chunk-XW72DWYO.js.map +1 -0
- package/dist/{chunk-ROD5H7RX.js → chunk-YML2N4SC.js} +7 -5
- package/dist/chunk-YML2N4SC.js.map +1 -0
- package/dist/contracts/handlers/index.cjs +9 -10
- package/dist/contracts/handlers/index.d.cts +5 -5
- package/dist/contracts/handlers/index.d.ts +5 -5
- package/dist/contracts/handlers/index.js +2 -3
- package/dist/{delegate-CZzIduW4.d.cts → delegate-BYoNu3lf.d.cts} +1 -1
- package/dist/{delegate-B9Bmrns7.d.ts → delegate-DsqzUVId.d.ts} +1 -1
- package/dist/index-CXNTURO_.d.cts +645 -0
- package/dist/{index-DnNIOqHS.d.ts → index-DhP68WBD.d.cts} +1698 -2402
- package/dist/{index-DnNIOqHS.d.cts → index-DhP68WBD.d.ts} +1698 -2402
- package/dist/index-pQr5y77P.d.ts +645 -0
- package/dist/index.cjs +407 -356
- package/dist/index.d.cts +1045 -1302
- package/dist/index.d.ts +1045 -1302
- package/dist/index.js +4 -5
- package/dist/repositories/realm/index.cjs +201 -106
- package/dist/repositories/realm/index.cjs.map +1 -1
- package/dist/repositories/realm/index.d.cts +28 -16
- package/dist/repositories/realm/index.d.ts +28 -16
- package/dist/repositories/realm/index.js +190 -95
- package/dist/repositories/realm/index.js.map +1 -1
- package/dist/repositories/sqlite/index.cjs +301 -189
- package/dist/repositories/sqlite/index.cjs.map +1 -1
- package/dist/repositories/sqlite/index.d.cts +32 -21
- package/dist/repositories/sqlite/index.d.ts +32 -21
- package/dist/repositories/sqlite/index.js +294 -182
- package/dist/repositories/sqlite/index.js.map +1 -1
- package/dist/{taskRunner-BDb5Ee2J.d.cts → taskRunner-C8H3bSsk.d.cts} +2 -2
- package/dist/{taskRunner-F7wNJcF3.d.ts → taskRunner-DKtBy8Yo.d.ts} +2 -2
- package/dist/wallet/expo/background.cjs +14 -15
- package/dist/wallet/expo/background.cjs.map +1 -1
- package/dist/wallet/expo/background.d.cts +10 -16
- package/dist/wallet/expo/background.d.ts +10 -16
- package/dist/wallet/expo/background.js +6 -7
- package/dist/wallet/expo/background.js.map +1 -1
- package/dist/wallet/expo/index.cjs +20 -23
- package/dist/wallet/expo/index.cjs.map +1 -1
- package/dist/wallet/expo/index.d.cts +8 -9
- package/dist/wallet/expo/index.d.ts +8 -9
- package/dist/wallet/expo/index.js +12 -15
- package/dist/wallet/expo/index.js.map +1 -1
- package/dist/wallet-BmAHDzK3.d.cts +1874 -0
- package/dist/wallet-C0W8EOnA.d.ts +1874 -0
- package/dist/worker/expo/index.cjs +9 -10
- package/dist/worker/expo/index.cjs.map +1 -1
- package/dist/worker/expo/index.d.cts +6 -6
- package/dist/worker/expo/index.d.ts +6 -6
- package/dist/worker/expo/index.js +5 -6
- package/dist/worker/expo/index.js.map +1 -1
- package/package.json +12 -51
- package/dist/adapters/asyncStorage.cjs +0 -48
- package/dist/adapters/asyncStorage.cjs.map +0 -1
- package/dist/adapters/asyncStorage.d.cts +0 -16
- package/dist/adapters/asyncStorage.d.ts +0 -16
- package/dist/adapters/asyncStorage.js +0 -46
- package/dist/adapters/asyncStorage.js.map +0 -1
- package/dist/adapters/fileSystem.cjs +0 -116
- package/dist/adapters/fileSystem.cjs.map +0 -1
- package/dist/adapters/fileSystem.d.cts +0 -17
- package/dist/adapters/fileSystem.d.ts +0 -17
- package/dist/adapters/fileSystem.js +0 -93
- package/dist/adapters/fileSystem.js.map +0 -1
- package/dist/adapters/indexedDB.cjs +0 -103
- package/dist/adapters/indexedDB.cjs.map +0 -1
- package/dist/adapters/indexedDB.d.cts +0 -18
- package/dist/adapters/indexedDB.d.ts +0 -18
- package/dist/adapters/indexedDB.js +0 -101
- package/dist/adapters/indexedDB.js.map +0 -1
- package/dist/adapters/localStorage.cjs +0 -50
- package/dist/adapters/localStorage.cjs.map +0 -1
- package/dist/adapters/localStorage.d.cts +0 -14
- package/dist/adapters/localStorage.d.ts +0 -14
- package/dist/adapters/localStorage.js +0 -48
- package/dist/adapters/localStorage.js.map +0 -1
- package/dist/chunk-43XGA362.cjs.map +0 -1
- package/dist/chunk-5BLDMQED.cjs +0 -18
- package/dist/chunk-5BLDMQED.cjs.map +0 -1
- package/dist/chunk-7W6FHWYN.js.map +0 -1
- package/dist/chunk-BCT7DT2J.cjs.map +0 -1
- package/dist/chunk-ERUAQGYF.js.map +0 -1
- package/dist/chunk-FSF2PGTR.cjs.map +0 -1
- package/dist/chunk-G4UPMCKW.js.map +0 -1
- package/dist/chunk-HSG2GQTM.js.map +0 -1
- package/dist/chunk-L4HZK4KK.cjs.map +0 -1
- package/dist/chunk-NSBPE2FW.js +0 -15
- package/dist/chunk-NSBPE2FW.js.map +0 -1
- package/dist/chunk-ROD5H7RX.js.map +0 -1
- package/dist/chunk-UCSTNXB4.cjs.map +0 -1
- package/dist/chunk-UJTYUYY4.cjs.map +0 -1
- package/dist/chunk-VQCDDGRW.js.map +0 -1
- package/dist/hdWalletCapable-BIl3yLVM.d.cts +0 -2232
- package/dist/hdWalletCapable-Cr5nGpK5.d.ts +0 -2232
- package/dist/index-C0IanN1m.d.cts +0 -11
- package/dist/index-C0IanN1m.d.ts +0 -11
- package/dist/index-Ci5MmNnK.d.cts +0 -850
- package/dist/index-DQ1Hb2w_.d.ts +0 -850
package/README.md
CHANGED
|
@@ -306,6 +306,8 @@ const wallet = await OnchainWallet.create(identity, 'bitcoin', provider)
|
|
|
306
306
|
await provider.close()
|
|
307
307
|
```
|
|
308
308
|
|
|
309
|
+
Where the network is only known at runtime (`Wallet.create`, or a service worker's `MessageBus`), pass a factory instead: `onchainProvider: (network) => new ElectrumOnchainProvider(new ElectrumWS(ELECTRUM_WS_URL[network]), networks[network])`. A `MessageBus` calls it on every init and never closes what it returns, so a worker should hand back one instance per network rather than a new connection each time.
|
|
310
|
+
|
|
309
311
|
#### Atomic 1P1C package broadcast (TRUC / BIP 431)
|
|
310
312
|
|
|
311
313
|
Both providers expose `broadcastTransaction(...txs)` that accepts either a single tx or a 1P1C package (parent first, child last). The package path is **atomic** — the parent doesn't have to independently meet mempool minfee, which is the point of TRUC relay.
|
|
@@ -591,7 +593,6 @@ Access the `VtxoManager` from the wallet after configuring `settlementConfig`:
|
|
|
591
593
|
const manager = await wallet.getVtxoManager()
|
|
592
594
|
```
|
|
593
595
|
|
|
594
|
-
> **Migration from `renewalConfig`:** Directly initializing a `VtxoManager` with `renewalConfig` is still supported but deprecated. Prefer `settlementConfig` where `vtxoThreshold` is expressed in **seconds** instead of milliseconds.
|
|
595
596
|
|
|
596
597
|
#### Renewal: Prevent Expiration
|
|
597
598
|
|
|
@@ -799,6 +800,71 @@ const exitTxid = await new Ramps(wallet).offboard(
|
|
|
799
800
|
service-worker and Expo wallets too. It answers with the server's live `ArkadeInfo`, falling back
|
|
800
801
|
to the snapshot persisted at wallet construction when the server is unreachable.
|
|
801
802
|
|
|
803
|
+
### Concurrent Spending & Coin Reservations
|
|
804
|
+
|
|
805
|
+
By default the wallet runs one spend at a time: a `send` issued while a settle or a collaborative
|
|
806
|
+
exit waits for its batch swap queues until that batch swap finalizes, and an exit with an amount
|
|
807
|
+
spends every spendable VTXO. Opt in to let spends overlap on disjoint VTXOs:
|
|
808
|
+
|
|
809
|
+
```typescript
|
|
810
|
+
const wallet = await Wallet.create({ identity, arkProvider, concurrentSpending: true })
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
With `concurrentSpending`:
|
|
814
|
+
|
|
815
|
+
- `send`, `settle` and asset operations hold the wallet lock only while they pick and reserve their
|
|
816
|
+
inputs; submitting the Arkade transaction and waiting for the batch swap run unlocked.
|
|
817
|
+
- `Ramps.offboard(address, fees, amount)` and `offboardExact` spend only the VTXOs that cover the
|
|
818
|
+
amount (soonest expiry first, as `send` picks), so the rest of the balance stays spendable. A
|
|
819
|
+
full exit, and an exit that names its `vtxos`, behave as before.
|
|
820
|
+
- Naming a VTXO that another operation is spending (`send({ selectedVtxos })`,
|
|
821
|
+
`settle({ inputs })`) throws `VtxoReservedError` before anything is submitted. Exits that pick
|
|
822
|
+
their own VTXOs retry the pick.
|
|
823
|
+
- Boarding UTXOs a settle is spending stay in `getBoardingUtxos()` and the boarding balance, but
|
|
824
|
+
a bare `settle()`, `Ramps.onboard` without explicit UTXOs and the boarding poll skip them until
|
|
825
|
+
that settle finishes, and naming one elsewhere throws `VtxoReservedError`.
|
|
826
|
+
|
|
827
|
+
Concurrency only helps when the balance sits in more than one VTXO: a wallet holding a single VTXO
|
|
828
|
+
still has one operation at a time. Renewal and a bare `settle()` merge the VTXOs they spend into
|
|
829
|
+
one output.
|
|
830
|
+
|
|
831
|
+
#### Holding VTXOs for your own use
|
|
832
|
+
|
|
833
|
+
`reserveVtxos` keeps VTXOs out of every pick the SDK makes for you — `send`, `settle()`, exits,
|
|
834
|
+
renewal, payment-router rails and swap funding — until you release them. You can still spend them
|
|
835
|
+
by naming them. It works with or without `concurrentSpending`.
|
|
836
|
+
|
|
837
|
+
```typescript
|
|
838
|
+
const hold = wallet.reserveVtxos(coinsForThisOrder)
|
|
839
|
+
try {
|
|
840
|
+
await wallet.send({ recipients, selectedVtxos: coinsForThisOrder })
|
|
841
|
+
} finally {
|
|
842
|
+
hold.release()
|
|
843
|
+
}
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
Held VTXOs stay in `getVtxos()` and in `getBalance().total`, and move from `available` to
|
|
847
|
+
`reserved`. Holding a VTXO that is held or being spent throws `VtxoReservedError`. If the SDK had
|
|
848
|
+
already picked a VTXO when you hold it, that spend throws `VtxoReservedError` (`holder: "held"`)
|
|
849
|
+
instead of spending it; exits and renewal pick again or retry on their own.
|
|
850
|
+
|
|
851
|
+
Limits:
|
|
852
|
+
|
|
853
|
+
- Reservations are in memory, per `Wallet` instance. Two processes or two `Wallet` instances on one
|
|
854
|
+
seed do not see each other's reservations; the operator refuses whichever spend loses.
|
|
855
|
+
- Deprecated-signer migration and recovery name the VTXOs they move, so they can spend a held VTXO.
|
|
856
|
+
- Renewal skips a held VTXO even once it is inside the renewal threshold, since renewing would
|
|
857
|
+
change the outpoint you are holding. It logs a warning naming each such VTXO; spend or release a
|
|
858
|
+
long-lived hold before the VTXO expires, or the server sweeps it and it comes back only through
|
|
859
|
+
recovery.
|
|
860
|
+
- `toReadonly()` views and the service worker's balance reads do not see reservations.
|
|
861
|
+
- `reserveVtxos` is on `Wallet`; the service-worker and Expo wallets accept `concurrentSpending`
|
|
862
|
+
but do not expose holds yet.
|
|
863
|
+
|
|
864
|
+
If your app keeps its own reserved-outpoint set, call `reserveVtxos` where you add to it and
|
|
865
|
+
`release()` where you remove, then let the SDK pick: plain `send`, router payments without
|
|
866
|
+
`selectedVtxos`, and exits without `vtxos` all skip what you hold.
|
|
867
|
+
|
|
802
868
|
### Talking to the server through the wallet
|
|
803
869
|
|
|
804
870
|
`getArkadeInfo()` is one of three seams that let a plugin work from a wallet alone, never a
|
|
@@ -1092,6 +1158,37 @@ const balance = await wallet.getBalance()
|
|
|
1092
1158
|
For watch-only wallets, use `ServiceWorkerReadonlyWallet` with a
|
|
1093
1159
|
`ReadonlySingleKey` identity instead.
|
|
1094
1160
|
|
|
1161
|
+
### Faster startup without changing existing reads
|
|
1162
|
+
|
|
1163
|
+
Existing `Wallet` and `ReadonlyWallet` reads (`getVtxos`, `getBalance`, and
|
|
1164
|
+
`getTransactionHistory`) still synchronize before answering. Retryable provider
|
|
1165
|
+
failures retain the existing offline fallback; terminal errors still reject.
|
|
1166
|
+
Contract initialization still awaits synchronization and watcher startup by default.
|
|
1167
|
+
|
|
1168
|
+
For a returning wallet with persisted contracts, opt into `lazyInitialization: true`
|
|
1169
|
+
and use `getStoredVtxos()` or `getStoredBalance()` for the initial display. These
|
|
1170
|
+
methods return cached data and request background synchronization. They can return
|
|
1171
|
+
empty or stale data, so inspect `(await wallet.getContractManager()).getSyncState()`:
|
|
1172
|
+
an absent `lastSyncedAt` means no successful sync this session, `syncing` means work
|
|
1173
|
+
is in flight, and `degraded` means refresh failed. Await `manager.whenBooted()` and
|
|
1174
|
+
inspect that state again before treating initialization as successful. Refresh the
|
|
1175
|
+
display after completion; cached reads do not guarantee a change event.
|
|
1176
|
+
|
|
1177
|
+
`getStoredBalance().boarding.loaded` is false until this wallet instance has fetched
|
|
1178
|
+
boarding inputs. Call `getBoardingUtxos()` to refresh them. Stored methods are for
|
|
1179
|
+
display, not transaction inputs; use the normal reads and spending APIs for actions.
|
|
1180
|
+
New contract registration, identity setup, and server-info validation can still
|
|
1181
|
+
require provider calls even with lazy initialization enabled.
|
|
1182
|
+
|
|
1183
|
+
Service-worker factories expose the same `lazyInitialization` option and a separate
|
|
1184
|
+
`lazyBoarding: true` option. Lazy boarding defers the explorer-backed boarding and
|
|
1185
|
+
history refresh, reports `boarding.loaded: false`, and broadcasts `UTXO_UPDATE`
|
|
1186
|
+
when boarding loading completes. Both options default to false and survive worker
|
|
1187
|
+
reinitialization. Existing `GET_BOARDING_UTXOS` requests remain live reads.
|
|
1188
|
+
|
|
1189
|
+
Boarding addresses are fetched concurrently in both modes, so wallets with rotated
|
|
1190
|
+
addresses benefit without opting into changed initialization timing.
|
|
1191
|
+
|
|
1095
1192
|
### Worker Architecture
|
|
1096
1193
|
|
|
1097
1194
|
The _worker_ captures the background processing infrastructure for the SDK.
|
|
@@ -1109,78 +1206,50 @@ examples.
|
|
|
1109
1206
|
|
|
1110
1207
|
### Repositories (Storage)
|
|
1111
1208
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
> onchain: [ 'address-1', 'address-2' ],
|
|
1142
|
-
> offchain: [ 'onboarding-address-1' ],
|
|
1143
|
-
> })
|
|
1144
|
-
> } catch (err) {
|
|
1145
|
-
> // Reset migration flag so the next attempt starts clean
|
|
1146
|
-
> await rollbackMigration('wallet', oldStorage)
|
|
1147
|
-
> throw err
|
|
1148
|
-
> }
|
|
1149
|
-
> }
|
|
1150
|
-
> ```
|
|
1151
|
-
>
|
|
1152
|
-
> **Migration status helpers:**
|
|
1153
|
-
>
|
|
1154
|
-
> | Helper | Description |
|
|
1155
|
-
> |--------|-------------|
|
|
1156
|
-
> | `getMigrationStatus(repoType, adapter)` | Returns `"not-needed"` (no legacy DB), `"pending"`, `"in-progress"` (interrupted), or `"done"` |
|
|
1157
|
-
> | `requiresMigration(repoType, adapter)` | Returns `true` if status is `"pending"` or `"in-progress"` |
|
|
1158
|
-
> | `rollbackMigration(repoType, adapter)` | Removes the migration flag so migration can re-run from scratch |
|
|
1159
|
-
> | `MIGRATION_KEY(repoType)` | Returns the storage key used for the migration flag |
|
|
1160
|
-
>
|
|
1161
|
-
> `migrateWalletRepository` sets an `"in-progress"` flag before copying data.
|
|
1162
|
-
> If the process crashes mid-way, the flag remains as `"in-progress"` so the
|
|
1163
|
-
> next call to `getMigrationStatus` can detect the partial migration. Old data
|
|
1164
|
-
> is never deleted — re-running migration after a rollback is safe.
|
|
1165
|
-
>
|
|
1166
|
-
> Anything related to contract repository migration must be handled by the
|
|
1167
|
-
> package that created the contracts. The SDK doesn't manage external contracts
|
|
1168
|
-
> in V1; data persisted by other packages remains untouched in its original
|
|
1169
|
-
> location.
|
|
1209
|
+
Use repository implementations via `StorageConfig`. If you omit `storage`, the
|
|
1210
|
+
SDK uses IndexedDB repositories with the default database name.
|
|
1211
|
+
|
|
1212
|
+
#### Paged repository reads
|
|
1213
|
+
|
|
1214
|
+
Collection repositories expose `getVtxosPage`, `getVtxosForScriptPage`, `getUtxosPage`,
|
|
1215
|
+
`getTransactionHistoryPage`, `getContractsPage`, and `getIntentsPage`.
|
|
1216
|
+
Each accepts `{ limit, after? }` and returns
|
|
1217
|
+
`{ items, nextCursor? }`; pass `nextCursor` as `after` until it is absent.
|
|
1218
|
+
Limits must be 1–500. History pages are ordered by `(createdAt, transaction key)`;
|
|
1219
|
+
`since` is inclusive Unix milliseconds. Contract and intent pages are ordered
|
|
1220
|
+
by their script and intent transaction ID. Filters must stay the same across
|
|
1221
|
+
pages. Repository collection reads use pages directly; `collectVtxos`,
|
|
1222
|
+
`collectScriptVtxos`, `collectUtxos`, `collectTransactionHistory`, `collectContracts`, and
|
|
1223
|
+
`collectIntents` traverse all pages when a complete snapshot is required.
|
|
1224
|
+
Wallet spending paths consume every VTXO or UTXO page before coin selection.
|
|
1225
|
+
In `@arkade-os/swap`, RFQ page `since` values use Unix seconds instead.
|
|
1226
|
+
|
|
1227
|
+
```ts
|
|
1228
|
+
let after;
|
|
1229
|
+
do {
|
|
1230
|
+
const page = await walletRepo.getTransactionHistoryPage(
|
|
1231
|
+
{ address, since: Date.now() - 86_400_000 },
|
|
1232
|
+
{ limit: 100, after },
|
|
1233
|
+
);
|
|
1234
|
+
for (const transaction of page.items) handle(transaction);
|
|
1235
|
+
after = page.nextCursor;
|
|
1236
|
+
} while (after);
|
|
1237
|
+
```
|
|
1170
1238
|
|
|
1171
1239
|
#### Repository Versioning
|
|
1172
1240
|
|
|
1173
|
-
`WalletRepository`, `ContractRepository`,
|
|
1174
|
-
`@arkade-os/swap`) each
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1241
|
+
`WalletRepository`, `ContractRepository`, `IntentRepository`,
|
|
1242
|
+
`VirtualTxRepository`, and `AssetSwapRepository` (in `@arkade-os/swap`) each
|
|
1243
|
+
declare a `readonly version` field with a literal type. All built-in
|
|
1244
|
+
implementations set this to the current version. If you maintain a custom
|
|
1245
|
+
repository implementation, TypeScript will produce a compile error when the
|
|
1246
|
+
version is bumped, signaling that a semantic update is required:
|
|
1178
1247
|
|
|
1179
1248
|
```typescript
|
|
1180
1249
|
import { WalletRepository } from '@arkade-os/sdk'
|
|
1181
1250
|
|
|
1182
1251
|
class MyWalletRepository implements WalletRepository {
|
|
1183
|
-
readonly version =
|
|
1252
|
+
readonly version = 2 // must match the interface's literal type
|
|
1184
1253
|
// ...
|
|
1185
1254
|
}
|
|
1186
1255
|
```
|
|
@@ -1190,17 +1259,21 @@ class MyWalletRepository implements WalletRepository {
|
|
|
1190
1259
|
For Node.js or React Native environments, use the SQLite repository with any
|
|
1191
1260
|
SQLite driver. The SDK accepts a `SQLExecutor` interface — you provide the
|
|
1192
1261
|
driver, the SDK handles the schema.
|
|
1262
|
+
Paged wallet reads require SQLite 3.15.0 or newer because they use
|
|
1263
|
+
[row-value comparisons](https://sqlite.org/rowvalue.html#backwards_compatibility).
|
|
1264
|
+
The built-in `node:sqlite` module is experimental in Node.js 22.12.x and stable
|
|
1265
|
+
from Node.js 22.13.0 onward.
|
|
1193
1266
|
|
|
1194
1267
|
See [examples/node/multiple-wallets.ts](examples/node/multiple-wallets.ts) for
|
|
1195
|
-
a full working example using `
|
|
1268
|
+
a full working example using `node:sqlite`.
|
|
1196
1269
|
|
|
1197
1270
|
```typescript
|
|
1198
1271
|
import { MnemonicIdentity, Wallet } from '@arkade-os/sdk'
|
|
1199
1272
|
import { SQLiteWalletRepository, SQLiteContractRepository, SQLExecutor } from '@arkade-os/sdk/repositories/sqlite'
|
|
1200
|
-
import
|
|
1273
|
+
import { DatabaseSync } from 'node:sqlite'
|
|
1201
1274
|
|
|
1202
|
-
const db = new
|
|
1203
|
-
db.
|
|
1275
|
+
const db = new DatabaseSync('my-wallet.sqlite')
|
|
1276
|
+
db.exec('PRAGMA journal_mode = WAL')
|
|
1204
1277
|
|
|
1205
1278
|
const executor: SQLExecutor = {
|
|
1206
1279
|
run: async (sql, params) => { db.prepare(sql).run(...(params ?? [])) },
|
|
@@ -1283,6 +1356,7 @@ const wallet = await Wallet.create({
|
|
|
1283
1356
|
})
|
|
1284
1357
|
```
|
|
1285
1358
|
|
|
1359
|
+
### Using with Node.js
|
|
1286
1360
|
### Using with Node.js
|
|
1287
1361
|
|
|
1288
1362
|
Node.js does not provide a global `EventSource` implementation (24.x has one behind `--experimental-eventsource`). The SDK relies on `EventSource` for Server-Sent Events during settlement (onboarding/offboarding) and contract watching, so tell it which one to use:
|
|
@@ -1402,11 +1476,46 @@ When you call `wallet.notifyIncomingFunds()` or use `waitForIncomingFunds()`, it
|
|
|
1402
1476
|
|
|
1403
1477
|
`watcherConfig.failsafePollIntervalMs` (default `20_000`) controls how often the watcher replays repository changes into contract events; it does not fetch fresh VTXOs from the indexer.
|
|
1404
1478
|
|
|
1479
|
+
#### Compiler artifacts
|
|
1480
|
+
|
|
1481
|
+
Read compiler format v1 JSON with `arkade.programFromArtifact`, which returns a normalized Program at version 1. `arkade.parseArtifact` reads normalized Program JSON and defaults omitted versions to 1. Only version 1 is supported, with typed `{ name, type }` declarations for every constructor parameter and call argument. Explicit version 0 programs, including persisted contracts, are rejected; there is no automatic migration. Older SDKs reject version 1 programs rather than silently reconstructing a different script. An Arkade function and its same-named Taproot leaf share one call, such as `contract.functions.claim(...)`. Standalone Taproot functions use their own names, such as `contract.functions.unilateral()`. Leaf order in the artifact still determines the Taproot tree. This example assumes a `digest: bytes32` constructor and a `claim` function with one `preimage: bytes32` covenant argument; providers, wallet, artifact JSON and matching digest/preimage values are already available.
|
|
1482
|
+
|
|
1483
|
+
Declarations retain the compiler's native scalar names: `pubkey`, `signature`, `bytes`, `bytes20`, `bytes32`, `asset`, `int`, `bool` and `AssetGroup`. There are no `hash` or `sig` type aliases. Byte types take `Uint8Array`; `int`, `bool` and `AssetGroup` take `bigint | number`, with `bool` restricted to `0` or `1`. Fixed widths follow the type itself, without extra width or boolean flags. The SDK requires every `pubkey` to be a 32-byte x-only key, although the language treats it as a bytes alias. Structs and arrays retain the compiler's flattened scalar field names and ordering.
|
|
1484
|
+
|
|
1485
|
+
The normalized Program remains an SDK representation: compiler `constructorInputs` become `params`, spend groups and leaves become named `functions`, and covenant `arkade` becomes `arkadeScript`. `parseArtifact` and `stringifyArtifact` read and write that normalized representation; `programFromArtifact` reads the compiler format. Existing deployment and call methods use the same syntax for imported and hand-written programs.
|
|
1486
|
+
|
|
1487
|
+
Before upgrading a wallet with persisted v0 contracts, back up its contract rows and retain a compatible SDK. After the upgrade, `manager.getUnsupportedContracts()` lists the v0 rows the wallet still holds: they stay stored, but their VTXOs are not synced and they cannot be spent or exited. To recover a contract in v1, reconstruct its program with typed declarations while preserving the stored constructor values, signer keys, leaf order and emulator position. Compile with the stored keys and compare the resulting `pkScript` with the original; reconnecting to a server with new keys or defaults can change the address. Only after the scripts match, register the reconstructed contract: over a v0 row with the same script, `register()` (like `manager.createContract`) replaces the row's params in place, then syncs its VTXOs. The row keeps its history, and its label and metadata unless you pass new ones. It leaves any other existing row unchanged. If the scripts differ, continue managing the contract with the compatible SDK. Changing the version number alone is not a migration.
|
|
1488
|
+
|
|
1489
|
+
```typescript
|
|
1490
|
+
import { arkade, ArkAddress } from '@arkade-os/sdk'
|
|
1491
|
+
|
|
1492
|
+
const program = arkade.programFromArtifact(artifactJson)
|
|
1493
|
+
const client = await arkade.Arkade.connect({
|
|
1494
|
+
arkade: arkProvider,
|
|
1495
|
+
emulator: emulatorProvider,
|
|
1496
|
+
indexer: indexerProvider,
|
|
1497
|
+
identity: wallet.identity,
|
|
1498
|
+
contractManager: await wallet.getContractManager(),
|
|
1499
|
+
})
|
|
1500
|
+
const contract = client.contract(program, { digest })
|
|
1501
|
+
await contract.register({ label: 'Hashlock' })
|
|
1502
|
+
await wallet.send({ address: contract.address, amount: 10_000 })
|
|
1503
|
+
|
|
1504
|
+
// Call after funding appears in contract.getUtxos().
|
|
1505
|
+
const { txid } = await contract.functions.claim(preimage)
|
|
1506
|
+
.to(ArkAddress.decode(recipientAddress).pkScript, 10_000n)
|
|
1507
|
+
.send()
|
|
1508
|
+
```
|
|
1509
|
+
|
|
1510
|
+
The connected server supplies `<SERVER_KEY>` (the reserved `server` parameter in normalized Programs) and `<SERVER_EXIT_DELAY>`; conflicting overrides fail, and time-based delays that are not multiples of 512 seconds fail rather than changing the advertised delay. Resolved bindings are persisted, so restoring the contract keeps its script through server key or policy changes. A declared constructor named `user` defaults to the connected identity; other constructor keys and flattened struct/array fields remain caller-provided, using names such as `owners.0.key`. Child-output placeholders remain explicit `bytes32` constructor bindings. Leaf call inputs used as script operands cannot produce a fixed address and are rejected; raw CSV operands must be canonical BIP68 encodings.
|
|
1511
|
+
|
|
1512
|
+
For compiler-derived programs, call arguments are covenant inputs in declaration order, followed by non-signature leaf inputs in declaration order. Same-named inputs in the two scopes remain separate positional arguments. Leaf signatures are PSBT signatures, not condition arguments: `send()` supports the connected identity and infrastructure signers; additional identities and covenant-tweaked leaf keys require explicit PSBT signing via `build()`. Covenant signature arguments remain caller-provided; transaction-bound Arkade `checkSig` signatures require an Arkade-specific digest helper, which is deferred. CSV leaves require aged onchain outputs and cannot use this offchain builder. Typed call validation and these spending limits apply to every normalized Program. The public `SignerRef` union is unchanged; version 1 programs store emulator signer placement in optional `emulatorIndex` metadata.
|
|
1513
|
+
|
|
1405
1514
|
#### HD look-ahead window
|
|
1406
1515
|
|
|
1407
1516
|
HD wallets (`walletMode: 'hd'`, or an explicit HD `DescriptorProvider`) also watch a band of *unused* offchain receive scripts around their allocation watermark, so a payment to an address that some other party issued from the same seed — a merchant backend such as BTCPay Server, or the .NET SDK driving the same wallet — arrives without the user calling `restore()`. `lookAheadWindow` (default `20`) is the per-side width of that band: the wallet watches `[watermark - N, watermark + N]`. Speculative entries are subscription-only; they become contract rows, and enter balances, only once funded.
|
|
1408
1517
|
|
|
1409
|
-
The issuer, not the wallet, picks the contract shape, so each index is watched at *every* variant the wallet could own there: `default` and `delegate`, crossed with the unilateral-exit timelock matrix and the operator's
|
|
1518
|
+
The issuer, not the wallet, picks the contract shape, so each index is watched at *every* variant the wallet could own there: `default` and `delegate`, crossed with the unilateral-exit timelock matrix and the operator's active plus retired signers. That is the candidate set `restore()` probes too, so watching and restoring cover identical scripts.
|
|
1410
1519
|
|
|
1411
1520
|
```typescript
|
|
1412
1521
|
const wallet = await Wallet.create({
|
|
@@ -1426,6 +1535,35 @@ const swWallet = await ServiceWorkerWallet.setup({
|
|
|
1426
1535
|
|
|
1427
1536
|
Raise it when the external issuer is expected to burn more than `N` consecutive addresses without any of them being paid — every index in such a run is a miss, and the funded one sits past the band. When that happens the funds are invisible until a `restore()` whose `gapLimit` is large enough to cross the run (`wallet.restore({ gapLimit: 200 })`); a default restore closes its gap window before reaching the funded index. Keep the value modest: the band adds up to `2N + 1` indices × the candidate matrix (typically 1-4 scripts each) to the wallet's subscription.
|
|
1428
1537
|
|
|
1538
|
+
#### Restoring plugin state
|
|
1539
|
+
|
|
1540
|
+
`wallet.restore()` is the explicit imported-wallet recovery boundary. It first restores the
|
|
1541
|
+
wallet's own addresses, contracts, history, and balances, then runs every restore hook registered
|
|
1542
|
+
for that wallet instance. `Wallet` and `ServiceWorkerWallet` both follow this ordering, and
|
|
1543
|
+
concurrent calls coalesce until the hooks finish.
|
|
1544
|
+
|
|
1545
|
+
```typescript
|
|
1546
|
+
import { registerWalletRestoreHook } from '@arkade-os/sdk'
|
|
1547
|
+
|
|
1548
|
+
const unregister = registerWalletRestoreHook(wallet, {
|
|
1549
|
+
id: 'my-plugin',
|
|
1550
|
+
restore: async (restoredWallet) => {
|
|
1551
|
+
await rebuildPluginState(await restoredWallet.getTransactionHistory())
|
|
1552
|
+
},
|
|
1553
|
+
})
|
|
1554
|
+
|
|
1555
|
+
await wallet.restore()
|
|
1556
|
+
```
|
|
1557
|
+
|
|
1558
|
+
Registering the same `id` again replaces that hook without changing its position. A run uses a
|
|
1559
|
+
stable snapshot, attempts every hook in registration order, and throws an `AggregateError` after
|
|
1560
|
+
all failures have been collected. If core recovery fails, hooks do not run. The returned function
|
|
1561
|
+
removes only that exact registration and is safe to call more than once.
|
|
1562
|
+
|
|
1563
|
+
Hooks do not run during `Wallet.create()`, `ServiceWorkerWallet.setup()`, or ordinary startup. A
|
|
1564
|
+
plugin should register before an application calls `restore()` and keep its normal incremental
|
|
1565
|
+
reconciliation for state that arrives later.
|
|
1566
|
+
|
|
1429
1567
|
For advanced use cases, you can access the ContractManager directly to register external contracts:
|
|
1430
1568
|
|
|
1431
1569
|
```typescript
|
|
@@ -1471,7 +1609,7 @@ const paths = manager.getSpendablePaths({
|
|
|
1471
1609
|
contractScript: contract.script,
|
|
1472
1610
|
vtxo,
|
|
1473
1611
|
collaborative: true,
|
|
1474
|
-
|
|
1612
|
+
walletDescriptor: myDescriptor,
|
|
1475
1613
|
})
|
|
1476
1614
|
if (paths.length > 0) {
|
|
1477
1615
|
console.log('Contract is spendable via:', paths[0].leaf)
|
|
@@ -1481,7 +1619,7 @@ if (paths.length > 0) {
|
|
|
1481
1619
|
const allPaths = await manager.getAllSpendingPaths({
|
|
1482
1620
|
contractScript: contract.script,
|
|
1483
1621
|
collaborative: true,
|
|
1484
|
-
|
|
1622
|
+
walletDescriptor: myDescriptor,
|
|
1485
1623
|
})
|
|
1486
1624
|
|
|
1487
1625
|
// Fetch contracts together with their current virtual outputs
|
|
@@ -1523,14 +1661,16 @@ versions keep the coverage they have today.
|
|
|
1523
1661
|
Most users don't need to touch repositories directly — `Wallet` reads through them and `ContractManager` owns VTXO/contract synchronization into them. They are documented here for advanced integrations (custom storage backends, offline-first apps, repository inspection).
|
|
1524
1662
|
|
|
1525
1663
|
```typescript
|
|
1664
|
+
import { collectContracts, collectTransactionHistory, collectUtxos, collectVtxos } from '@arkade-os/sdk'
|
|
1665
|
+
|
|
1526
1666
|
// Wallet repository — VTXOs, UTXOs, transaction history, settings
|
|
1527
1667
|
const addr = await wallet.getAddress()
|
|
1528
|
-
const vtxos = await wallet.walletRepository
|
|
1529
|
-
const utxos = await wallet.walletRepository
|
|
1530
|
-
const history = await wallet.walletRepository
|
|
1668
|
+
const vtxos = await collectVtxos(wallet.walletRepository, addr)
|
|
1669
|
+
const utxos = await collectUtxos(wallet.walletRepository, addr)
|
|
1670
|
+
const history = await collectTransactionHistory(wallet.walletRepository, addr)
|
|
1531
1671
|
|
|
1532
1672
|
// Contract repository — script-keyed contracts (default address, VHTLCs, etc.)
|
|
1533
|
-
const contracts = await wallet.contractRepository
|
|
1673
|
+
const contracts = await collectContracts(wallet.contractRepository, { type: 'vhtlc' })
|
|
1534
1674
|
await wallet.contractRepository.saveContract(myContract)
|
|
1535
1675
|
await wallet.contractRepository.deleteContract(myContract.script)
|
|
1536
1676
|
```
|
|
@@ -1544,15 +1684,15 @@ This package is developed inside the [arkade-os/ts-sdk](../..) monorepo. See the
|
|
|
1544
1684
|
Common package-local commands (run from the repo root):
|
|
1545
1685
|
|
|
1546
1686
|
```bash
|
|
1547
|
-
pnpm -C packages/
|
|
1548
|
-
pnpm -C packages/
|
|
1549
|
-
pnpm -C packages/
|
|
1550
|
-
pnpm -C packages/
|
|
1551
|
-
pnpm -C packages/
|
|
1552
|
-
pnpm -C packages/
|
|
1687
|
+
pnpm -C packages/sdk run typecheck # Type-check the SDK
|
|
1688
|
+
pnpm -C packages/sdk test:unit # Unit tests, excluding e2e
|
|
1689
|
+
pnpm -C packages/sdk test:watch # Vitest watch mode
|
|
1690
|
+
pnpm -C packages/sdk test:coverage # Coverage report
|
|
1691
|
+
pnpm -C packages/sdk docs:build # Build TypeDoc API docs
|
|
1692
|
+
pnpm -C packages/sdk docs:open # Open API docs in the browser
|
|
1553
1693
|
```
|
|
1554
1694
|
|
|
1555
|
-
For integration tests, use the root commands (`pnpm run test:integration:
|
|
1695
|
+
For integration tests, use the root commands (`pnpm run test:integration:sdk` and the `regtest:*:sdk` family) — see the root README.
|
|
1556
1696
|
|
|
1557
1697
|
### Releasing
|
|
1558
1698
|
|
package/dist/adapters/expo.cjs
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
5
|
-
require('../chunk-
|
|
6
|
-
require('../chunk-5BLDMQED.cjs');
|
|
3
|
+
var chunkDLHE4RCH_cjs = require('../chunk-DLHE4RCH.cjs');
|
|
4
|
+
require('../chunk-AICUNREA.cjs');
|
|
5
|
+
require('../chunk-ASKOHVGX.cjs');
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
Object.defineProperty(exports, "ExpoArkProvider", {
|
|
11
10
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
11
|
+
get: function () { return chunkDLHE4RCH_cjs.ExpoArkProvider; }
|
|
13
12
|
});
|
|
14
13
|
Object.defineProperty(exports, "ExpoIndexerProvider", {
|
|
15
14
|
enumerable: true,
|
|
16
|
-
get: function () { return
|
|
15
|
+
get: function () { return chunkDLHE4RCH_cjs.ExpoIndexerProvider; }
|
|
17
16
|
});
|
|
18
17
|
//# sourceMappingURL=expo.cjs.map
|
|
19
18
|
//# sourceMappingURL=expo.cjs.map
|
package/dist/adapters/expo.d.cts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { r as RestArkProvider, o as SettlementEvent, T as TxNotificationEvent, s as RestIndexerProvider, t as
|
|
2
|
-
export {
|
|
1
|
+
import { r as RestArkProvider, o as SettlementEvent, T as TxNotificationEvent, s as RestIndexerProvider, t as SubscriptionEvent, u as SubscriptionHeartbeat } from '../index-DhP68WBD.cjs';
|
|
2
|
+
export { v as ArkProvider, w as IndexerProvider } from '../index-DhP68WBD.cjs';
|
|
3
3
|
import '@scure/btc-signer/utils.js';
|
|
4
|
-
import '@scure/btc-signer/transaction.js';
|
|
5
|
-
import '@scure/btc-signer';
|
|
6
4
|
import '@scure/btc-signer/psbt.js';
|
|
5
|
+
import '@scure/btc-signer';
|
|
6
|
+
import '@scure/btc-signer/transaction.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Expo-compatible Arkade provider implementation using expo/fetch for SSE support.
|
|
@@ -39,7 +39,7 @@ declare class ExpoArkProvider extends RestArkProvider {
|
|
|
39
39
|
*/
|
|
40
40
|
declare class ExpoIndexerProvider extends RestIndexerProvider {
|
|
41
41
|
constructor(serverUrl?: string);
|
|
42
|
-
|
|
42
|
+
protected subscriptionStream(url: string, abortSignal: AbortSignal): AsyncIterableIterator<SubscriptionEvent | SubscriptionHeartbeat>;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export { ExpoArkProvider, ExpoIndexerProvider };
|
package/dist/adapters/expo.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { r as RestArkProvider, o as SettlementEvent, T as TxNotificationEvent, s as RestIndexerProvider, t as
|
|
2
|
-
export {
|
|
1
|
+
import { r as RestArkProvider, o as SettlementEvent, T as TxNotificationEvent, s as RestIndexerProvider, t as SubscriptionEvent, u as SubscriptionHeartbeat } from '../index-DhP68WBD.js';
|
|
2
|
+
export { v as ArkProvider, w as IndexerProvider } from '../index-DhP68WBD.js';
|
|
3
3
|
import '@scure/btc-signer/utils.js';
|
|
4
|
-
import '@scure/btc-signer/transaction.js';
|
|
5
|
-
import '@scure/btc-signer';
|
|
6
4
|
import '@scure/btc-signer/psbt.js';
|
|
5
|
+
import '@scure/btc-signer';
|
|
6
|
+
import '@scure/btc-signer/transaction.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Expo-compatible Arkade provider implementation using expo/fetch for SSE support.
|
|
@@ -39,7 +39,7 @@ declare class ExpoArkProvider extends RestArkProvider {
|
|
|
39
39
|
*/
|
|
40
40
|
declare class ExpoIndexerProvider extends RestIndexerProvider {
|
|
41
41
|
constructor(serverUrl?: string);
|
|
42
|
-
|
|
42
|
+
protected subscriptionStream(url: string, abortSignal: AbortSignal): AsyncIterableIterator<SubscriptionEvent | SubscriptionHeartbeat>;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export { ExpoArkProvider, ExpoIndexerProvider };
|
package/dist/adapters/expo.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export { ExpoArkProvider, ExpoIndexerProvider } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
3
|
-
import '../chunk-
|
|
4
|
-
import '../chunk-NSBPE2FW.js';
|
|
1
|
+
export { ExpoArkProvider, ExpoIndexerProvider } from '../chunk-KK6GXY4L.js';
|
|
2
|
+
import '../chunk-PY3YQNHP.js';
|
|
3
|
+
import '../chunk-G6ZPX2GL.js';
|
|
5
4
|
//# sourceMappingURL=expo.js.map
|
|
6
5
|
//# sourceMappingURL=expo.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as TaskQueue, c as TaskItem, d as TaskResult } from './taskRunner-DKtBy8Yo.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Minimal async key-value storage interface.
|
|
@@ -46,4 +46,4 @@ declare class AsyncStorageTaskQueue implements TaskQueue {
|
|
|
46
46
|
private writeList;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export {
|
|
49
|
+
export { AsyncStorageTaskQueue as A, type AsyncStorageLike as a };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as TaskQueue, c as TaskItem, d as TaskResult } from './taskRunner-C8H3bSsk.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Minimal async key-value storage interface.
|
|
@@ -46,4 +46,4 @@ declare class AsyncStorageTaskQueue implements TaskQueue {
|
|
|
46
46
|
private writeList;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export {
|
|
49
|
+
export { AsyncStorageTaskQueue as A, type AsyncStorageLike as a };
|