@arkade-os/sdk 0.3.12 → 0.4.0-next.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.
Files changed (250) hide show
  1. package/README.md +483 -54
  2. package/dist/cjs/adapters/expo-db.js +35 -0
  3. package/dist/cjs/asset/assetGroup.js +141 -0
  4. package/dist/cjs/asset/assetId.js +88 -0
  5. package/dist/cjs/asset/assetInput.js +204 -0
  6. package/dist/cjs/asset/assetOutput.js +159 -0
  7. package/dist/cjs/asset/assetRef.js +82 -0
  8. package/dist/cjs/asset/index.js +24 -0
  9. package/dist/cjs/asset/metadata.js +172 -0
  10. package/dist/cjs/asset/packet.js +164 -0
  11. package/dist/cjs/asset/types.js +25 -0
  12. package/dist/cjs/asset/utils.js +105 -0
  13. package/dist/cjs/contracts/arkcontract.js +148 -0
  14. package/dist/cjs/contracts/contractManager.js +436 -0
  15. package/dist/cjs/contracts/contractWatcher.js +567 -0
  16. package/dist/cjs/contracts/handlers/default.js +85 -0
  17. package/dist/cjs/contracts/handlers/delegate.js +89 -0
  18. package/dist/cjs/contracts/handlers/helpers.js +105 -0
  19. package/dist/cjs/contracts/handlers/index.js +19 -0
  20. package/dist/cjs/contracts/handlers/registry.js +89 -0
  21. package/dist/cjs/contracts/handlers/vhtlc.js +193 -0
  22. package/dist/cjs/contracts/index.js +41 -0
  23. package/dist/cjs/contracts/types.js +2 -0
  24. package/dist/cjs/db/manager.js +97 -0
  25. package/dist/cjs/forfeit.js +12 -8
  26. package/dist/cjs/identity/index.js +1 -0
  27. package/dist/cjs/identity/seedIdentity.js +255 -0
  28. package/dist/cjs/index.js +70 -14
  29. package/dist/cjs/intent/index.js +28 -2
  30. package/dist/cjs/providers/ark.js +7 -0
  31. package/dist/cjs/providers/delegator.js +66 -0
  32. package/dist/cjs/providers/expoIndexer.js +5 -0
  33. package/dist/cjs/providers/indexer.js +68 -1
  34. package/dist/cjs/providers/onchain.js +2 -2
  35. package/dist/cjs/providers/utils.js +1 -0
  36. package/dist/cjs/repositories/contractRepository.js +0 -103
  37. package/dist/cjs/repositories/inMemory/contractRepository.js +55 -0
  38. package/dist/cjs/repositories/inMemory/walletRepository.js +80 -0
  39. package/dist/cjs/repositories/index.js +16 -0
  40. package/dist/cjs/repositories/indexedDB/contractRepository.js +187 -0
  41. package/dist/cjs/repositories/indexedDB/db.js +57 -0
  42. package/dist/cjs/repositories/indexedDB/schema.js +159 -0
  43. package/dist/cjs/repositories/indexedDB/walletRepository.js +338 -0
  44. package/dist/cjs/repositories/indexedDB/websqlAdapter.js +144 -0
  45. package/dist/cjs/repositories/migrations/contractRepositoryImpl.js +127 -0
  46. package/dist/cjs/repositories/migrations/fromStorageAdapter.js +66 -0
  47. package/dist/cjs/repositories/migrations/walletRepositoryImpl.js +180 -0
  48. package/dist/cjs/repositories/walletRepository.js +0 -169
  49. package/dist/cjs/script/base.js +54 -0
  50. package/dist/cjs/script/delegate.js +49 -0
  51. package/dist/cjs/storage/asyncStorage.js +4 -1
  52. package/dist/cjs/storage/fileSystem.js +3 -0
  53. package/dist/cjs/storage/inMemory.js +3 -0
  54. package/dist/cjs/storage/indexedDB.js +5 -1
  55. package/dist/cjs/storage/localStorage.js +3 -0
  56. package/dist/cjs/utils/arkTransaction.js +16 -0
  57. package/dist/cjs/utils/transactionHistory.js +50 -0
  58. package/dist/cjs/utils/txSizeEstimator.js +39 -14
  59. package/dist/cjs/wallet/asset-manager.js +338 -0
  60. package/dist/cjs/wallet/asset.js +117 -0
  61. package/dist/cjs/wallet/batch.js +1 -1
  62. package/dist/cjs/wallet/delegator.js +235 -0
  63. package/dist/cjs/wallet/expo/background.js +133 -0
  64. package/dist/cjs/wallet/expo/index.js +9 -0
  65. package/dist/cjs/wallet/expo/wallet.js +231 -0
  66. package/dist/cjs/wallet/onchain.js +57 -12
  67. package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +568 -0
  68. package/dist/cjs/wallet/serviceWorker/wallet.js +383 -102
  69. package/dist/cjs/wallet/unroll.js +7 -2
  70. package/dist/cjs/wallet/utils.js +60 -0
  71. package/dist/cjs/wallet/validation.js +151 -0
  72. package/dist/cjs/wallet/vtxo-manager.js +1 -1
  73. package/dist/cjs/wallet/wallet.js +702 -260
  74. package/dist/cjs/worker/browser/service-worker-manager.js +82 -0
  75. package/dist/cjs/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
  76. package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +78 -0
  77. package/dist/cjs/worker/expo/index.js +12 -0
  78. package/dist/cjs/worker/expo/processors/contractPollProcessor.js +61 -0
  79. package/dist/cjs/worker/expo/processors/index.js +6 -0
  80. package/dist/cjs/worker/expo/taskQueue.js +41 -0
  81. package/dist/cjs/worker/expo/taskRunner.js +57 -0
  82. package/dist/cjs/worker/messageBus.js +252 -0
  83. package/dist/esm/adapters/expo-db.js +27 -0
  84. package/dist/esm/asset/assetGroup.js +137 -0
  85. package/dist/esm/asset/assetId.js +84 -0
  86. package/dist/esm/asset/assetInput.js +199 -0
  87. package/dist/esm/asset/assetOutput.js +154 -0
  88. package/dist/esm/asset/assetRef.js +78 -0
  89. package/dist/esm/asset/index.js +8 -0
  90. package/dist/esm/asset/metadata.js +167 -0
  91. package/dist/esm/asset/packet.js +159 -0
  92. package/dist/esm/asset/types.js +22 -0
  93. package/dist/esm/asset/utils.js +99 -0
  94. package/dist/esm/contracts/arkcontract.js +141 -0
  95. package/dist/esm/contracts/contractManager.js +432 -0
  96. package/dist/esm/contracts/contractWatcher.js +563 -0
  97. package/dist/esm/contracts/handlers/default.js +82 -0
  98. package/dist/esm/contracts/handlers/delegate.js +86 -0
  99. package/dist/esm/contracts/handlers/helpers.js +66 -0
  100. package/dist/esm/contracts/handlers/index.js +12 -0
  101. package/dist/esm/contracts/handlers/registry.js +86 -0
  102. package/dist/esm/contracts/handlers/vhtlc.js +190 -0
  103. package/dist/esm/contracts/index.js +13 -0
  104. package/dist/esm/contracts/types.js +1 -0
  105. package/dist/esm/db/manager.js +92 -0
  106. package/dist/esm/forfeit.js +11 -8
  107. package/dist/esm/identity/index.js +1 -0
  108. package/dist/esm/identity/seedIdentity.js +249 -0
  109. package/dist/esm/index.js +25 -15
  110. package/dist/esm/intent/index.js +28 -2
  111. package/dist/esm/providers/ark.js +7 -0
  112. package/dist/esm/providers/delegator.js +62 -0
  113. package/dist/esm/providers/expoIndexer.js +5 -0
  114. package/dist/esm/providers/indexer.js +68 -1
  115. package/dist/esm/providers/onchain.js +2 -2
  116. package/dist/esm/providers/utils.js +1 -0
  117. package/dist/esm/repositories/contractRepository.js +1 -101
  118. package/dist/esm/repositories/inMemory/contractRepository.js +51 -0
  119. package/dist/esm/repositories/inMemory/walletRepository.js +76 -0
  120. package/dist/esm/repositories/index.js +8 -0
  121. package/dist/esm/repositories/indexedDB/contractRepository.js +183 -0
  122. package/dist/esm/repositories/indexedDB/db.js +42 -0
  123. package/dist/esm/repositories/indexedDB/schema.js +155 -0
  124. package/dist/esm/repositories/indexedDB/walletRepository.js +334 -0
  125. package/dist/esm/repositories/indexedDB/websqlAdapter.js +138 -0
  126. package/dist/esm/repositories/migrations/contractRepositoryImpl.js +121 -0
  127. package/dist/esm/repositories/migrations/fromStorageAdapter.js +58 -0
  128. package/dist/esm/repositories/migrations/walletRepositoryImpl.js +176 -0
  129. package/dist/esm/repositories/walletRepository.js +1 -167
  130. package/dist/esm/script/base.js +21 -1
  131. package/dist/esm/script/delegate.js +46 -0
  132. package/dist/esm/storage/asyncStorage.js +4 -1
  133. package/dist/esm/storage/fileSystem.js +3 -0
  134. package/dist/esm/storage/inMemory.js +3 -0
  135. package/dist/esm/storage/indexedDB.js +5 -1
  136. package/dist/esm/storage/localStorage.js +3 -0
  137. package/dist/esm/utils/arkTransaction.js +15 -0
  138. package/dist/esm/utils/transactionHistory.js +50 -0
  139. package/dist/esm/utils/txSizeEstimator.js +39 -14
  140. package/dist/esm/wallet/asset-manager.js +333 -0
  141. package/dist/esm/wallet/asset.js +111 -0
  142. package/dist/esm/wallet/batch.js +1 -1
  143. package/dist/esm/wallet/delegator.js +231 -0
  144. package/dist/esm/wallet/expo/background.js +128 -0
  145. package/dist/esm/wallet/expo/index.js +2 -0
  146. package/dist/esm/wallet/expo/wallet.js +194 -0
  147. package/dist/esm/wallet/onchain.js +57 -12
  148. package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +564 -0
  149. package/dist/esm/wallet/serviceWorker/wallet.js +382 -101
  150. package/dist/esm/wallet/unroll.js +7 -2
  151. package/dist/esm/wallet/utils.js +55 -0
  152. package/dist/esm/wallet/validation.js +139 -0
  153. package/dist/esm/wallet/vtxo-manager.js +1 -1
  154. package/dist/esm/wallet/wallet.js +704 -229
  155. package/dist/esm/worker/browser/service-worker-manager.js +76 -0
  156. package/dist/esm/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
  157. package/dist/esm/worker/expo/asyncStorageTaskQueue.js +74 -0
  158. package/dist/esm/worker/expo/index.js +4 -0
  159. package/dist/esm/worker/expo/processors/contractPollProcessor.js +58 -0
  160. package/dist/esm/worker/expo/processors/index.js +1 -0
  161. package/dist/esm/worker/expo/taskQueue.js +37 -0
  162. package/dist/esm/worker/expo/taskRunner.js +54 -0
  163. package/dist/esm/worker/messageBus.js +248 -0
  164. package/dist/types/adapters/expo-db.d.ts +7 -0
  165. package/dist/types/asset/assetGroup.d.ts +28 -0
  166. package/dist/types/asset/assetId.d.ts +19 -0
  167. package/dist/types/asset/assetInput.d.ts +46 -0
  168. package/dist/types/asset/assetOutput.d.ts +39 -0
  169. package/dist/types/asset/assetRef.d.ts +25 -0
  170. package/dist/types/asset/index.d.ts +8 -0
  171. package/dist/types/asset/metadata.d.ts +37 -0
  172. package/dist/types/asset/packet.d.ts +27 -0
  173. package/dist/types/asset/types.d.ts +18 -0
  174. package/dist/types/asset/utils.d.ts +21 -0
  175. package/dist/types/contracts/arkcontract.d.ts +101 -0
  176. package/dist/types/contracts/contractManager.d.ts +331 -0
  177. package/dist/types/contracts/contractWatcher.d.ts +192 -0
  178. package/dist/types/contracts/handlers/default.d.ts +19 -0
  179. package/dist/types/contracts/handlers/delegate.d.ts +21 -0
  180. package/dist/types/contracts/handlers/helpers.d.ts +18 -0
  181. package/dist/types/contracts/handlers/index.d.ts +7 -0
  182. package/dist/types/contracts/handlers/registry.d.ts +65 -0
  183. package/dist/types/contracts/handlers/vhtlc.d.ts +32 -0
  184. package/dist/types/contracts/index.d.ts +14 -0
  185. package/dist/types/contracts/types.d.ts +222 -0
  186. package/dist/types/db/manager.d.ts +22 -0
  187. package/dist/types/forfeit.d.ts +2 -1
  188. package/dist/types/identity/index.d.ts +1 -0
  189. package/dist/types/identity/seedIdentity.d.ts +128 -0
  190. package/dist/types/index.d.ts +21 -12
  191. package/dist/types/intent/index.d.ts +2 -1
  192. package/dist/types/providers/ark.d.ts +11 -2
  193. package/dist/types/providers/delegator.d.ts +29 -0
  194. package/dist/types/providers/indexer.d.ts +11 -1
  195. package/dist/types/repositories/contractRepository.d.ts +30 -19
  196. package/dist/types/repositories/inMemory/contractRepository.d.ts +17 -0
  197. package/dist/types/repositories/inMemory/walletRepository.d.ts +26 -0
  198. package/dist/types/repositories/index.d.ts +7 -0
  199. package/dist/types/repositories/indexedDB/contractRepository.d.ts +21 -0
  200. package/dist/types/repositories/indexedDB/db.d.ts +56 -0
  201. package/dist/types/repositories/indexedDB/schema.d.ts +8 -0
  202. package/dist/types/repositories/indexedDB/walletRepository.d.ts +25 -0
  203. package/dist/types/repositories/indexedDB/websqlAdapter.d.ts +49 -0
  204. package/dist/types/repositories/migrations/contractRepositoryImpl.d.ts +24 -0
  205. package/dist/types/repositories/migrations/fromStorageAdapter.d.ts +19 -0
  206. package/dist/types/repositories/migrations/walletRepositoryImpl.d.ts +27 -0
  207. package/dist/types/repositories/walletRepository.d.ts +13 -24
  208. package/dist/types/script/base.d.ts +1 -0
  209. package/dist/types/script/delegate.d.ts +36 -0
  210. package/dist/types/storage/asyncStorage.d.ts +4 -0
  211. package/dist/types/storage/fileSystem.d.ts +3 -0
  212. package/dist/types/storage/inMemory.d.ts +3 -0
  213. package/dist/types/storage/index.d.ts +3 -0
  214. package/dist/types/storage/indexedDB.d.ts +3 -0
  215. package/dist/types/storage/localStorage.d.ts +3 -0
  216. package/dist/types/utils/arkTransaction.d.ts +6 -0
  217. package/dist/types/utils/txSizeEstimator.d.ts +12 -2
  218. package/dist/types/wallet/asset-manager.d.ts +78 -0
  219. package/dist/types/wallet/asset.d.ts +21 -0
  220. package/dist/types/wallet/batch.d.ts +1 -1
  221. package/dist/types/wallet/delegator.d.ts +24 -0
  222. package/dist/types/wallet/expo/background.d.ts +66 -0
  223. package/dist/types/wallet/expo/index.d.ts +4 -0
  224. package/dist/types/wallet/expo/wallet.d.ts +97 -0
  225. package/dist/types/wallet/index.d.ts +75 -2
  226. package/dist/types/wallet/onchain.d.ts +22 -1
  227. package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +366 -0
  228. package/dist/types/wallet/serviceWorker/wallet.d.ts +20 -11
  229. package/dist/types/wallet/utils.d.ts +13 -1
  230. package/dist/types/wallet/validation.d.ts +24 -0
  231. package/dist/types/wallet/wallet.d.ts +111 -17
  232. package/dist/types/worker/browser/service-worker-manager.d.ts +21 -0
  233. package/dist/types/{wallet/serviceWorker → worker/browser}/utils.d.ts +2 -1
  234. package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +46 -0
  235. package/dist/types/worker/expo/index.d.ts +7 -0
  236. package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +14 -0
  237. package/dist/types/worker/expo/processors/index.d.ts +1 -0
  238. package/dist/types/worker/expo/taskQueue.d.ts +50 -0
  239. package/dist/types/worker/expo/taskRunner.d.ts +42 -0
  240. package/dist/types/worker/messageBus.d.ts +109 -0
  241. package/package.json +71 -17
  242. package/dist/cjs/wallet/serviceWorker/request.js +0 -78
  243. package/dist/cjs/wallet/serviceWorker/response.js +0 -222
  244. package/dist/cjs/wallet/serviceWorker/worker.js +0 -655
  245. package/dist/esm/wallet/serviceWorker/request.js +0 -75
  246. package/dist/esm/wallet/serviceWorker/response.js +0 -219
  247. package/dist/esm/wallet/serviceWorker/worker.js +0 -651
  248. package/dist/types/wallet/serviceWorker/request.d.ts +0 -74
  249. package/dist/types/wallet/serviceWorker/response.d.ts +0 -123
  250. package/dist/types/wallet/serviceWorker/worker.d.ts +0 -53
package/README.md CHANGED
@@ -16,10 +16,18 @@ npm install @arkade-os/sdk
16
16
  ### Creating a Wallet
17
17
 
18
18
  ```typescript
19
- import { SingleKey, Wallet } from '@arkade-os/sdk'
19
+ import {
20
+ MnemonicIdentity,
21
+ Wallet,
22
+ IndexedDBWalletRepository,
23
+ IndexedDBContractRepository
24
+ } from '@arkade-os/sdk'
25
+ import { generateMnemonic } from '@scure/bip39'
26
+ import { wordlist } from '@scure/bip39/wordlists/english.js'
20
27
 
21
- // Create a new in-memory key (or use an external signer)
22
- const identity = SingleKey.fromHex('your_private_key_hex')
28
+ // Generate a new mnemonic or use an existing one
29
+ const mnemonic = generateMnemonic(wordlist)
30
+ const identity = MnemonicIdentity.fromMnemonic(mnemonic, { isMainnet: false })
23
31
 
24
32
  // Create a wallet with Ark support
25
33
  const wallet = await Wallet.create({
@@ -27,8 +35,11 @@ const wallet = await Wallet.create({
27
35
  // Esplora API, can be left empty - mempool.space API will be used
28
36
  esploraUrl: 'https://mutinynet.com/api',
29
37
  arkServerUrl: 'https://mutinynet.arkade.sh',
30
- // Optional: specify storage adapter (defaults to InMemoryStorageAdapter)
31
- // storage: new LocalStorageAdapter() // for browser persistence
38
+ // Optional: provide repositories for persistence (defaults to IndexedDB)
39
+ // storage: {
40
+ // walletRepository: new IndexedDBWalletRepository('my-wallet-db'),
41
+ // contractRepository: new IndexedDBContractRepository('my-wallet-db')
42
+ // }
32
43
  })
33
44
  ```
34
45
 
@@ -103,11 +114,88 @@ const readonlyWallet = await ReadonlyWallet.create({
103
114
  })
104
115
  ```
105
116
 
106
- **Benefits:**
107
- - ✅ Type-safe: Transaction methods don't exist on readonly types
108
- - Secure: Private keys never leave the signing environment
109
- - ✅ Flexible: Convert between full and readonly wallets as needed
110
- - Same API: Query operations work identically on both wallet types
117
+ ### Seed & Mnemonic Identity (Recommended)
118
+
119
+ The SDK supports key derivation from BIP39 mnemonic phrases or raw seeds using BIP86 (Taproot) output descriptors. This is the recommended identity type for new integrations — it uses standard derivation paths that are interoperable with other wallets and HD-ready for future multi-address support.
120
+
121
+ > **Note:** Prefer `MnemonicIdentity` or `SeedIdentity` over `SingleKey` for new applications. `SingleKey` exists for backward compatibility with raw private keys.
122
+
123
+ #### Creating from Mnemonic
124
+
125
+ ```typescript
126
+ import { MnemonicIdentity, Wallet } from '@arkade-os/sdk'
127
+ import { generateMnemonic } from '@scure/bip39'
128
+ import { wordlist } from '@scure/bip39/wordlists/english.js'
129
+
130
+ // Generate a new 12-word mnemonic
131
+ const mnemonic = generateMnemonic(wordlist)
132
+
133
+ // Create identity from a 12 or 24 word mnemonic
134
+ const identity = MnemonicIdentity.fromMnemonic(mnemonic, { isMainnet: true })
135
+
136
+ // With optional passphrase for additional security
137
+ const identityWithPassphrase = MnemonicIdentity.fromMnemonic(mnemonic, {
138
+ isMainnet: true,
139
+ passphrase: 'my secret passphrase'
140
+ })
141
+
142
+ // Create wallet as usual
143
+ const wallet = await Wallet.create({
144
+ identity,
145
+ arkServerUrl: 'https://mutinynet.arkade.sh'
146
+ })
147
+ ```
148
+
149
+ #### Creating from Raw Seed
150
+
151
+ ```typescript
152
+ import { SeedIdentity } from '@arkade-os/sdk'
153
+ import { mnemonicToSeedSync } from '@scure/bip39'
154
+
155
+ // If you already have a 64-byte seed
156
+ const seed = mnemonicToSeedSync(mnemonic)
157
+ const identity = SeedIdentity.fromSeed(seed, { isMainnet: true })
158
+
159
+ // Or with a custom output descriptor
160
+ const identity2 = SeedIdentity.fromSeed(seed, { descriptor })
161
+
162
+ // Or with a custom descriptor and passphrase (MnemonicIdentity)
163
+ const identity3 = MnemonicIdentity.fromMnemonic(mnemonic, {
164
+ descriptor,
165
+ passphrase: 'my secret passphrase'
166
+ })
167
+ ```
168
+
169
+ #### Watch-Only with ReadonlyDescriptorIdentity
170
+
171
+ Create watch-only wallets from an output descriptor:
172
+
173
+ ```typescript
174
+ import { ReadonlyDescriptorIdentity, ReadonlyWallet } from '@arkade-os/sdk'
175
+
176
+ // From a full identity
177
+ const readonly = await identity.toReadonly()
178
+
179
+ // Or directly from a descriptor (e.g., from another wallet)
180
+ const descriptor = "tr([12345678/86'/0'/0']xpub.../0/0)"
181
+ const readonlyFromDescriptor = ReadonlyDescriptorIdentity.fromDescriptor(descriptor)
182
+
183
+ // Use in a watch-only wallet
184
+ const readonlyWallet = await ReadonlyWallet.create({
185
+ identity: readonly,
186
+ arkServerUrl: 'https://mutinynet.arkade.sh'
187
+ })
188
+
189
+ // Can query but not sign
190
+ const balance = await readonlyWallet.getBalance()
191
+ ```
192
+
193
+ **Derivation Path:** `m/86'/{coinType}'/0'/0/0`
194
+ - BIP86 (Taproot) purpose
195
+ - Coin type 0 for mainnet, 1 for testnet
196
+ - Account 0, external chain, first address
197
+
198
+ The descriptor format (`tr([fingerprint/path']xpub.../0/0)`) is HD-ready — future versions will support deriving multiple addresses and change outputs from the same seed.
111
199
 
112
200
  ### Receiving Bitcoin
113
201
 
@@ -169,6 +257,42 @@ const txid = await wallet.sendBitcoin({
169
257
  })
170
258
  ```
171
259
 
260
+ ### Assets (Issue, Reissue, Burn, Send)
261
+
262
+ The wallet's `assetManager` lets you create and manage assets on Ark. `send` method supports sending assets.
263
+
264
+ ```typescript
265
+ // Issue a new asset (non-reissuable by default)
266
+ const controlAssetIssuance = await wallet.assetManager.issue({
267
+ amount: 1000,
268
+ metadata: { name: 'My Token', ticker: 'MTK', decimals: 8 },
269
+ })
270
+
271
+ // Issue a new asset using the control asset as reference
272
+ const assetIssuance = await wallet.assetManager.issue({
273
+ amount: 500,
274
+ controlAssetId: controlAssetIssuance.assetId,
275
+ })
276
+
277
+ // Reissue more supply of the asset, need ownership of the control asset
278
+ const reissuanceTxid = await wallet.assetManager.reissue({
279
+ assetId: assetIssuance.assetId,
280
+ amount: 500,
281
+ })
282
+
283
+ // Burn some of the asset
284
+ const burnTxid = await wallet.assetManager.burn({
285
+ assetId: assetIssuance.assetId,
286
+ amount: 200,
287
+ })
288
+
289
+ // Send asset to another Ark address
290
+ const sendTxid = await wallet.send({
291
+ address: 'ark1qq4...',
292
+ assets: [{ assetId: assetIssuance.assetId, amount: 100 }],
293
+ })
294
+ ```
295
+
172
296
  ### Batch Settlements
173
297
 
174
298
  This can be used to move preconfirmed balances into finalized balances and to manually convert UTXOs and VTXOs.
@@ -233,6 +357,83 @@ const balance = await manager.getRecoverableBalance()
233
357
  ```
234
358
 
235
359
 
360
+ ### VTXO Delegation
361
+
362
+ Delegation allows you to outsource VTXO renewal to a third-party delegator service. Instead of renewing VTXOs yourself, the delegator will automatically settle them before they expire, sending the funds back to your wallet address (minus a service fee). This is useful for wallets that cannot be online 24/7.
363
+
364
+ When a `delegatorProvider` is configured, the wallet address includes an extra tapscript path that authorizes the delegator to co-sign renewals alongside the Ark server.
365
+
366
+ #### Setting Up a Wallet with Delegation
367
+
368
+ ```typescript
369
+ import { Wallet, SingleKey, RestDelegatorProvider } from '@arkade-os/sdk'
370
+
371
+ const identity = SingleKey.fromHex('your_private_key_hex')
372
+
373
+ const wallet = await Wallet.create({
374
+ identity,
375
+ arkServerUrl: 'https://mutinynet.arkade.sh',
376
+ delegatorProvider: new RestDelegatorProvider('https://delegator.example.com'),
377
+ })
378
+ ```
379
+
380
+ > **Note:** Adding a `delegatorProvider` changes your wallet address because the offchain tapscript includes an additional delegation path. Funds sent to an address without delegation cannot be delegated, and vice versa.
381
+
382
+ #### Delegating VTXOs
383
+
384
+ Once the wallet is configured with a delegator, use `wallet.delegatorManager` to delegate your VTXOs:
385
+
386
+ ```typescript
387
+ // Get spendable VTXOs
388
+ const vtxos = (await wallet.getVtxos({ withRecoverable: true }))
389
+ .filter(v => v.virtualStatus.type === 'confirmed')
390
+
391
+ // Delegate all VTXOs — the delegator will renew them before expiry
392
+ const myAddress = await wallet.getAddress()
393
+ const result = await wallet.delegatorManager.delegate(vtxos, myAddress)
394
+
395
+ console.log('Delegated:', result.delegated.length)
396
+ console.log('Failed:', result.failed.length)
397
+ ```
398
+
399
+ The `delegate` method groups VTXOs by expiry date and submits them to the delegator service. By default, delegation is scheduled at 90% of each VTXO's remaining lifetime. You can override this with an explicit date:
400
+
401
+ ```typescript
402
+ // Delegate with a specific renewal time
403
+ const delegateAt = new Date(Date.now() + 12 * 60 * 60 * 1000) // 12 hours from now
404
+ await wallet.delegatorManager.delegate(vtxos, myAddress, delegateAt)
405
+ ```
406
+
407
+ #### Service Worker Integration
408
+
409
+ When using a service worker wallet, pass the `delegatorUrl` option. The service worker will automatically delegate VTXOs after each VTXO update:
410
+
411
+ ```typescript
412
+ import { ServiceWorkerWallet, SingleKey } from '@arkade-os/sdk'
413
+
414
+ const wallet = await ServiceWorkerWallet.setup({
415
+ serviceWorkerPath: '/service-worker.js',
416
+ arkServerUrl: 'https://mutinynet.arkade.sh',
417
+ identity: SingleKey.fromHex('your_private_key_hex'),
418
+ delegatorUrl: 'https://delegator.example.com',
419
+ })
420
+ ```
421
+
422
+ #### Querying Delegator Info
423
+
424
+ You can query the delegator service directly to inspect its public key, fee, and payment address:
425
+
426
+ ```typescript
427
+ import { RestDelegatorProvider } from '@arkade-os/sdk'
428
+
429
+ const provider = new RestDelegatorProvider('https://delegator.example.com')
430
+ const info = await provider.getDelegateInfo()
431
+
432
+ console.log('Delegator public key:', info.pubkey)
433
+ console.log('Service fee (sats):', info.fee)
434
+ console.log('Fee address:', info.delegatorAddress)
435
+ ```
436
+
236
437
  ### Transaction History
237
438
 
238
439
  ```typescript
@@ -329,78 +530,204 @@ await Unroll.completeUnroll(
329
530
 
330
531
  ### Running the wallet in a service worker
331
532
 
332
- **Ultra-simplified setup!** We handle all the complex service worker registration and identity management for you:
533
+ The SDK provides a `MessageBus` orchestrator that runs inside a service worker
534
+ and routes messages to pluggable `MessageHandler`s. The built-in
535
+ `WalletMessageHandler` exposes all wallet operations over this message bus, and
536
+ `ServiceWorkerWallet` is a client-side proxy that communicates with it
537
+ transparently.
538
+
539
+ #### Service worker file
540
+
541
+ ```javascript
542
+ // service-worker.js
543
+ import {
544
+ MessageBus,
545
+ WalletMessageHandler,
546
+ IndexedDBWalletRepository,
547
+ IndexedDBContractRepository,
548
+ } from '@arkade-os/sdk'
549
+
550
+ const walletRepo = new IndexedDBWalletRepository()
551
+ const contractRepo = new IndexedDBContractRepository()
552
+
553
+ const bus = new MessageBus(walletRepo, contractRepo, {
554
+ messageHandlers: [new WalletMessageHandler()],
555
+ tickIntervalMs: 10_000, // default 10s
556
+ })
557
+
558
+ bus.start()
559
+ ```
560
+
561
+ #### Client-side usage
333
562
 
334
563
  ```typescript
335
- // SIMPLE SETUP with identity! 🎉
336
- import { ServiceWorkerWallet, SingleKey } from '@arkade-os/sdk';
564
+ // app.ts
565
+ import { ServiceWorkerWallet, SingleKey } from '@arkade-os/sdk'
337
566
 
338
- // Create your identity
339
- const identity = SingleKey.fromHex('your_private_key_hex');
340
- // Or generate a new one:
341
- // const identity = SingleKey.fromRandomBytes();
567
+ const identity = SingleKey.fromHex('your_private_key_hex')
342
568
 
569
+ // One-liner: registers the SW, initializes the MessageBus, and creates the wallet
343
570
  const wallet = await ServiceWorkerWallet.setup({
344
571
  serviceWorkerPath: '/service-worker.js',
345
572
  arkServerUrl: 'https://mutinynet.arkade.sh',
346
- identity
347
- });
573
+ identity,
574
+ })
348
575
 
349
- // That's it! Ready to use immediately:
350
- const address = await wallet.getAddress();
351
- const balance = await wallet.getBalance();
576
+ // Use like any other wallet — calls are proxied to the service worker
577
+ const address = await wallet.getAddress()
578
+ const balance = await wallet.getBalance()
352
579
  ```
353
580
 
354
- You'll also need to create a service worker file:
581
+ For watch-only wallets, use `ServiceWorkerReadonlyWallet` with a
582
+ `ReadonlySingleKey` identity instead.
583
+
584
+ ### Worker Architecture
585
+
586
+ The _worker_ captures the background processing infrastructure for the SDK.
587
+ Two platform-specific implementations share common patterns (pluggable
588
+ handlers, periodic scheduling, repository/provider dependency injection) but
589
+ differ in orchestration and communication.
590
+
591
+ | Platform | Directory | Orchestrator | Communication |
592
+ |----------|----------------------------------------------|-------------|---------------|
593
+ | **Browser** | [`browser/`](./src/worker/browser/README.md) | `MessageBus` inside a Service Worker | `postMessage` between SW and window clients |
594
+ | **Expo/React Native** | [`expo/`](./src/worker/expo/README.md) | `runTasks()` called from foreground interval and OS background wake | `AsyncStorageTaskQueue` inbox/outbox |
595
+
596
+ See the platform READMEs for architecture details, runtime flow, and usage
597
+ examples.
598
+
599
+
600
+
601
+ ### Repositories (Storage)
602
+
603
+ The `StorageAdapter` API is deprecated. Use repositories instead. If you omit
604
+ `storage`, the SDK uses IndexedDB repositories with the default database name.
605
+
606
+ #### Migration from v1 StorageAdapter
607
+
608
+ > [!WARNING]
609
+ > If you previously used the v1 `StorageAdapter`-based repositories, migrate
610
+ > data into the new IndexedDB repositories before use:
611
+ >
612
+ > ```typescript
613
+ > import {
614
+ > IndexedDBWalletRepository,
615
+ > IndexedDBContractRepository,
616
+ > getMigrationStatus,
617
+ > migrateWalletRepository,
618
+ > rollbackMigration,
619
+ > } from '@arkade-os/sdk'
620
+ > import { IndexedDBStorageAdapter } from '@arkade-os/sdk/adapters/indexedDB'
621
+ >
622
+ > const oldStorage = new IndexedDBStorageAdapter('legacy-wallet', 1)
623
+ > const newDbName = 'my-app-db'
624
+ > const walletRepository = new IndexedDBWalletRepository(newDbName)
625
+ >
626
+ > // Check migration status before running
627
+ > const status = await getMigrationStatus('wallet', oldStorage)
628
+ > // status: "not-needed" | "pending" | "in-progress" | "done"
629
+ >
630
+ > if (status === 'pending' || status === 'in-progress') {
631
+ > try {
632
+ > await migrateWalletRepository(oldStorage, walletRepository, {
633
+ > onchain: [ 'address-1', 'address-2' ],
634
+ > offchain: [ 'onboarding-address-1' ],
635
+ > })
636
+ > } catch (err) {
637
+ > // Reset migration flag so the next attempt starts clean
638
+ > await rollbackMigration('wallet', oldStorage)
639
+ > throw err
640
+ > }
641
+ > }
642
+ > ```
643
+ >
644
+ > **Migration status helpers:**
645
+ >
646
+ > | Helper | Description |
647
+ > |--------|-------------|
648
+ > | `getMigrationStatus(repoType, adapter)` | Returns `"not-needed"` (no legacy DB), `"pending"`, `"in-progress"` (interrupted), or `"done"` |
649
+ > | `requiresMigration(repoType, adapter)` | Returns `true` if status is `"pending"` or `"in-progress"` |
650
+ > | `rollbackMigration(repoType, adapter)` | Removes the migration flag so migration can re-run from scratch |
651
+ > | `MIGRATION_KEY(repoType)` | Returns the storage key used for the migration flag |
652
+ >
653
+ > `migrateWalletRepository` sets an `"in-progress"` flag before copying data.
654
+ > If the process crashes mid-way, the flag remains as `"in-progress"` so the
655
+ > next call to `getMigrationStatus` can detect the partial migration. Old data
656
+ > is never deleted — re-running migration after a rollback is safe.
657
+ >
658
+ > Anything related to contract repository migration must be handled by the package which created them. The SDK doesn't manage contracts in V1. Data remains untouched and persisted in the same old location.
659
+ >
660
+ > If you persisted custom data in the ContractRepository via its `setContractData` method,
661
+ > or a custom collection via `saveToContractCollection`, you'll need to migrate it manually:
662
+ >
663
+ > ```typescript
664
+ > // Custom data stored in the ContractRepository
665
+ > const oldStorage = new IndexedDBStorageAdapter('legacy-wallet', 1)
666
+ > const oldRepo = new ContractRepositoryImpl(storageAdapter)
667
+ > const customContract = await oldRepo.getContractData('my-contract', 'status')
668
+ > await contractRepository.setContractData('my-contract', 'status', customData)
669
+ > const customCollection = await oldRepo.getContractCollection('swaps')
670
+ > await contractRepository.saveToContractCollection('swaps', customCollection)
671
+ > ```
672
+
673
+ #### Repository Versioning
674
+
675
+ `WalletRepository`, `ContractRepository`, and `SwapRepository` (in
676
+ `@arkade-os/boltz-swap`) each declare a `readonly version` field with a literal
677
+ type. All built-in implementations set this to the current version. If you
678
+ maintain a custom repository implementation, TypeScript will produce a compile
679
+ error when the version is bumped, signaling that a semantic update is required:
355
680
 
356
681
  ```typescript
357
- // service-worker.js
358
- import { Worker } from '@arkade-os/sdk'
682
+ import { WalletRepository } from '@arkade-os/sdk'
359
683
 
360
- // Worker handles communication between the main thread and service worker
361
- new Worker().start()
684
+ class MyWalletRepository implements WalletRepository {
685
+ readonly version = 1 // must match the interface's literal type
686
+ // ...
687
+ }
362
688
  ```
363
689
 
364
- ### Storage Adapters
690
+ Note: `IndexedDB*Repository` requires [indexeddbshim](https://github.com/indexeddbshim/indexeddbshim) in Node or other
691
+ **non-browser environments**. It is a dev dependency of the SDK, so you must
692
+ install and initialize it in your app before using the repositories. This
693
+ also applies when you rely on the default storage behavior (no `storage`).
365
694
 
366
- Choose the appropriate storage adapter for your environment:
695
+ Please see the working example in [examples/node/multiple-wallets.ts](examples/node/multiple-wallets.ts).
367
696
 
368
697
  ```typescript
369
- import {
370
- SingleKey,
371
- Wallet,
372
- InMemoryStorageAdapter, // Works everywhere, data lost on restart
373
- } from '@arkade-os/sdk'
698
+ import { SingleKey, Wallet } from '@arkade-os/sdk'
699
+ import setGlobalVars from 'indexeddbshim'
374
700
 
375
- // Import additional storage adapters as needed:
376
- import { LocalStorageAdapter } from '@arkade-os/sdk/adapters/localStorage' // Browser/PWA persistent storage
377
- import { IndexedDBStorageAdapter } from '@arkade-os/sdk/adapters/indexedDB' // Browser/PWA/Service Worker advanced storage
378
- import { AsyncStorageAdapter } from '@arkade-os/sdk/adapters/asyncStorage' // React Native persistent storage
379
- import { FileSystemStorageAdapter } from '@arkade-os/sdk/adapters/fileSystem' // Node.js file-based storage
701
+ setGlobalVars()
380
702
 
381
- // Node.js
382
- const storage = new FileSystemStorageAdapter('./wallet-data')
703
+ const identity = SingleKey.fromHex('your_private_key_hex')
383
704
 
384
- // Browser/PWA
385
- const storage = new LocalStorageAdapter()
386
- // or for advanced features:
387
- const storage = new IndexedDBStorageAdapter('my-app', 1)
705
+ // Create wallet with default IndexedDB storage
706
+ const wallet = await Wallet.create({
707
+ identity,
708
+ arkServerUrl: 'https://mutinynet.arkade.sh',
709
+ })
710
+ ```
388
711
 
389
- // React Native
390
- const storage = new AsyncStorageAdapter()
712
+ If you want a custom database name or a different repository implementation,
713
+ pass `storage` explicitly.
391
714
 
392
- // Service Worker
393
- const storage = new IndexedDBStorageAdapter('service-worker-wallet', 1)
715
+ For ephemeral storage (no persistence), pass the in-memory repositories:
394
716
 
395
- // Load identity from storage (simple pattern everywhere)
396
- const privateKeyHex = await storage.getItem('private-key')
397
- const identity = SingleKey.fromHex(privateKeyHex)
717
+ ```typescript
718
+ import {
719
+ InMemoryWalletRepository,
720
+ InMemoryContractRepository,
721
+ Wallet
722
+ } from '@arkade-os/sdk'
398
723
 
399
- // Create wallet (same API everywhere)
400
724
  const wallet = await Wallet.create({
401
725
  identity,
402
726
  arkServerUrl: 'https://mutinynet.arkade.sh',
403
- storage // optional
727
+ storage: {
728
+ walletRepository: new InMemoryWalletRepository(),
729
+ contractRepository: new InMemoryContractRepository()
730
+ }
404
731
  })
405
732
  ```
406
733
 
@@ -432,6 +759,26 @@ Both ExpoArkProvider and ExpoIndexerProvider are available as adapters following
432
759
  - **ExpoArkProvider**: Handles settlement events and transaction streaming using expo/fetch for Server-Sent Events
433
760
  - **ExpoIndexerProvider**: Handles address subscriptions and VTXO updates using expo/fetch for JSON streaming
434
761
 
762
+ To use IndexedDB repositories in Expo/React Native, call `setupExpoDb()` before any SDK import.
763
+ This sets up `indexeddbshim` backed by expo-sqlite under the hood:
764
+
765
+ ```typescript
766
+ import { setupExpoDb } from '@arkade-os/sdk/adapters/expo-db';
767
+
768
+ setupExpoDb();
769
+ ```
770
+
771
+ > **Note:** `setupExpoDb` accepts an optional `SetupExpoDbOptions` object to
772
+ > customise `origin`, `checkOrigin`, and `cacheDatabaseInstances`.
773
+
774
+ > **Note:** `expo-sqlite` and `indexeddbshim` are optional peer dependencies,
775
+ > only required when importing from `@arkade-os/sdk/adapters/expo-db`. The
776
+ > streaming providers (`@arkade-os/sdk/adapters/expo`) have no expo-sqlite
777
+ > dependency. Install them with:
778
+ > ```bash
779
+ > npx expo install expo-sqlite && npm install indexeddbshim
780
+ > ```
781
+
435
782
  #### Crypto Polyfill Requirement
436
783
 
437
784
  Install `expo-crypto` and polyfill `crypto.getRandomValues()` at the top of your app entry point:
@@ -453,6 +800,88 @@ import { ExpoArkProvider, ExpoIndexerProvider } from '@arkade-os/sdk/adapters/ex
453
800
 
454
801
  This is required for MuSig2 settlements and cryptographic operations.
455
802
 
803
+ ### Contract Management
804
+
805
+ Both `Wallet` and `ServiceWorkerWallet` use a `ContractManager` internally to watch for VTXOs. This provides resilient connection handling with automatic reconnection and failsafe polling - for your wallet's default address and any external contracts you register (Boltz swaps, HTLCs, etc.).
806
+
807
+ When you call `wallet.notifyIncomingFunds()` or use `waitForIncomingFunds()`, it uses the ContractManager under the hood, giving you automatic reconnection and failsafe polling for free - no code changes needed.
808
+
809
+ For advanced use cases, you can access the ContractManager directly to register external contracts:
810
+
811
+ ```typescript
812
+ // Get the contract manager (wallet's default address is already registered)
813
+ const manager = await wallet.getContractManager()
814
+
815
+ // Register a VHTLC contract (e.g., for a Lightning swap)
816
+ const contract = await manager.createContract({
817
+ type: 'vhtlc',
818
+ params: {
819
+ sender: alicePubKey,
820
+ receiver: bobPubKey,
821
+ server: serverPubKey,
822
+ hash: paymentHash,
823
+ refundLocktime: '800000',
824
+ claimDelay: '100',
825
+ refundDelay: '102',
826
+ refundNoReceiverDelay: '103',
827
+ },
828
+ script: swapScript,
829
+ address: swapAddress,
830
+ })
831
+
832
+ // Listen for all contracts events (wallet address + external contracts)
833
+ const unsubscribe = await manager.onContractEvent((event) => {
834
+ switch (event.type) {
835
+ case 'vtxo_received':
836
+ console.log(`Received ${event.vtxos.length} VTXOs on ${event.contractScript}`)
837
+ break
838
+ case 'vtxo_spent':
839
+ console.log(`Spent VTXOs on ${event.contractScript}`)
840
+ break
841
+ case 'contract_expired':
842
+ console.log(`Contract ${event.contractScript} expired`)
843
+ break
844
+ }
845
+ })
846
+
847
+ // Update contract data (e.g., set preimage when revealed)
848
+ await manager.updateContractParams(contract.script, { preimage: revealedPreimage })
849
+
850
+ // Check spendable paths (requires a specific VTXO)
851
+ const [withVtxos] = await manager.getContractsWithVtxos({ script: contract.script })
852
+ const vtxo = withVtxos.vtxos[0]
853
+ const paths = manager.getSpendablePaths({
854
+ contractScript: contract.script,
855
+ vtxo,
856
+ collaborative: true,
857
+ walletPubKey: myPubKey,
858
+ })
859
+ if (paths.length > 0) {
860
+ console.log('Contract is spendable via:', paths[0].leaf)
861
+ }
862
+
863
+ // Or list all possible paths for the current context (no spendability checks)
864
+ const allPaths = manager.getAllSpendingPaths({
865
+ contractScript: contract.script,
866
+ collaborative: true,
867
+ walletPubKey: myPubKey,
868
+ })
869
+
870
+ // Get balances across all contracts
871
+ const balances = await manager.getAllBalances()
872
+
873
+ // Manually sweep all eligible contracts
874
+ const sweepResults = await manager.sweepAll()
875
+
876
+ // Stop watching
877
+ unsubscribe()
878
+ ```
879
+
880
+ The watcher features:
881
+ - **Automatic reconnection** with exponential backoff (1s → 30s max)
882
+ - **Failsafe polling** every 60 seconds to catch missed events
883
+ - **Immediate sync** on connection and after failures
884
+
456
885
  ### Repository Pattern
457
886
 
458
887
  Access low-level data management through repositories:
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.openDatabase = void 0;
7
+ exports.setupExpoDb = setupExpoDb;
8
+ // Expo IndexedDB polyfill — requires expo-sqlite and indexeddbshim.
9
+ //
10
+ // Separated from ./expo so that consumers who only need the streaming
11
+ // providers (ExpoArkProvider, ExpoIndexerProvider) don't pull in a
12
+ // hard dependency on expo-sqlite at bundle time.
13
+ const indexeddbshim_1 = __importDefault(require("indexeddbshim"));
14
+ const websqlAdapter_1 = require("../repositories/indexedDB/websqlAdapter");
15
+ var websqlAdapter_2 = require("../repositories/indexedDB/websqlAdapter");
16
+ Object.defineProperty(exports, "openDatabase", { enumerable: true, get: function () { return websqlAdapter_2.openDatabase; } });
17
+ let _initialized = false;
18
+ function setupExpoDb(options) {
19
+ if (_initialized)
20
+ return;
21
+ const { origin = "expo://localhost", checkOrigin = false, cacheDatabaseInstances = true, } = options ?? {};
22
+ if (typeof globalThis.window === "undefined") {
23
+ globalThis.window = globalThis;
24
+ }
25
+ if (typeof globalThis.location === "undefined") {
26
+ globalThis.location = { origin };
27
+ }
28
+ globalThis.openDatabase = websqlAdapter_1.openDatabase;
29
+ (0, indexeddbshim_1.default)(globalThis, {
30
+ checkOrigin,
31
+ useSQLiteIndexes: true,
32
+ cacheDatabaseInstances,
33
+ });
34
+ _initialized = true;
35
+ }