@arkade-os/sdk 0.3.13 → 0.4.0-next.1
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 +586 -54
- package/dist/cjs/asset/assetGroup.js +141 -0
- package/dist/cjs/asset/assetId.js +88 -0
- package/dist/cjs/asset/assetInput.js +204 -0
- package/dist/cjs/asset/assetOutput.js +159 -0
- package/dist/cjs/asset/assetRef.js +82 -0
- package/dist/cjs/asset/index.js +24 -0
- package/dist/cjs/asset/metadata.js +172 -0
- package/dist/cjs/asset/packet.js +164 -0
- package/dist/cjs/asset/types.js +25 -0
- package/dist/cjs/asset/utils.js +105 -0
- package/dist/cjs/bip322/index.js +270 -0
- package/dist/cjs/contracts/arkcontract.js +148 -0
- package/dist/cjs/contracts/contractManager.js +436 -0
- package/dist/cjs/contracts/contractWatcher.js +567 -0
- package/dist/cjs/contracts/handlers/default.js +85 -0
- package/dist/cjs/contracts/handlers/delegate.js +89 -0
- package/dist/cjs/contracts/handlers/helpers.js +105 -0
- package/dist/cjs/contracts/handlers/index.js +19 -0
- package/dist/cjs/contracts/handlers/registry.js +89 -0
- package/dist/cjs/contracts/handlers/vhtlc.js +193 -0
- package/dist/cjs/contracts/index.js +41 -0
- package/dist/cjs/contracts/types.js +2 -0
- package/dist/cjs/forfeit.js +12 -8
- package/dist/cjs/identity/index.js +1 -0
- package/dist/cjs/identity/seedIdentity.js +255 -0
- package/dist/cjs/index.js +72 -14
- package/dist/cjs/intent/index.js +47 -11
- package/dist/cjs/providers/ark.js +7 -0
- package/dist/cjs/providers/delegator.js +66 -0
- package/dist/cjs/providers/expoIndexer.js +5 -0
- package/dist/cjs/providers/indexer.js +68 -1
- package/dist/cjs/providers/utils.js +1 -0
- package/dist/cjs/repositories/contractRepository.js +0 -103
- package/dist/cjs/repositories/inMemory/contractRepository.js +55 -0
- package/dist/cjs/repositories/inMemory/walletRepository.js +80 -0
- package/dist/cjs/repositories/index.js +16 -0
- package/dist/cjs/repositories/indexedDB/contractRepository.js +187 -0
- package/dist/cjs/repositories/indexedDB/db.js +19 -0
- package/dist/cjs/repositories/indexedDB/manager.js +97 -0
- package/dist/cjs/repositories/indexedDB/schema.js +159 -0
- package/dist/cjs/repositories/indexedDB/walletRepository.js +338 -0
- package/dist/cjs/repositories/indexedDB/websqlAdapter.js +144 -0
- package/dist/cjs/repositories/migrations/contractRepositoryImpl.js +127 -0
- package/dist/cjs/repositories/migrations/fromStorageAdapter.js +66 -0
- package/dist/cjs/repositories/migrations/walletRepositoryImpl.js +180 -0
- package/dist/cjs/repositories/realm/contractRepository.js +120 -0
- package/dist/cjs/repositories/realm/index.js +9 -0
- package/dist/cjs/repositories/realm/schemas.js +108 -0
- package/dist/cjs/repositories/realm/types.js +7 -0
- package/dist/cjs/repositories/realm/walletRepository.js +273 -0
- package/dist/cjs/repositories/serialization.js +49 -0
- package/dist/cjs/repositories/sqlite/contractRepository.js +139 -0
- package/dist/cjs/repositories/sqlite/index.js +7 -0
- package/dist/cjs/repositories/sqlite/types.js +2 -0
- package/dist/cjs/repositories/sqlite/walletRepository.js +328 -0
- package/dist/cjs/repositories/walletRepository.js +0 -169
- package/dist/cjs/script/base.js +54 -0
- package/dist/cjs/script/delegate.js +49 -0
- package/dist/cjs/storage/asyncStorage.js +4 -1
- package/dist/cjs/storage/fileSystem.js +3 -0
- package/dist/cjs/storage/inMemory.js +3 -0
- package/dist/cjs/storage/indexedDB.js +5 -1
- package/dist/cjs/storage/localStorage.js +3 -0
- package/dist/cjs/utils/arkTransaction.js +16 -0
- package/dist/cjs/utils/transactionHistory.js +50 -0
- package/dist/cjs/wallet/asset-manager.js +338 -0
- package/dist/cjs/wallet/asset.js +117 -0
- package/dist/cjs/wallet/batch.js +1 -1
- package/dist/cjs/wallet/delegator.js +235 -0
- package/dist/cjs/wallet/expo/background.js +133 -0
- package/dist/cjs/wallet/expo/index.js +9 -0
- package/dist/cjs/wallet/expo/wallet.js +231 -0
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +568 -0
- package/dist/cjs/wallet/serviceWorker/wallet.js +383 -102
- package/dist/cjs/wallet/utils.js +58 -0
- package/dist/cjs/wallet/validation.js +151 -0
- package/dist/cjs/wallet/vtxo-manager.js +8 -1
- package/dist/cjs/wallet/wallet.js +702 -260
- package/dist/cjs/worker/browser/service-worker-manager.js +82 -0
- package/dist/cjs/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
- package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +78 -0
- package/dist/cjs/worker/expo/index.js +12 -0
- package/dist/cjs/worker/expo/processors/contractPollProcessor.js +61 -0
- package/dist/cjs/worker/expo/processors/index.js +6 -0
- package/dist/cjs/worker/expo/taskQueue.js +41 -0
- package/dist/cjs/worker/expo/taskRunner.js +57 -0
- package/dist/cjs/worker/messageBus.js +252 -0
- package/dist/esm/asset/assetGroup.js +137 -0
- package/dist/esm/asset/assetId.js +84 -0
- package/dist/esm/asset/assetInput.js +199 -0
- package/dist/esm/asset/assetOutput.js +154 -0
- package/dist/esm/asset/assetRef.js +78 -0
- package/dist/esm/asset/index.js +8 -0
- package/dist/esm/asset/metadata.js +167 -0
- package/dist/esm/asset/packet.js +159 -0
- package/dist/esm/asset/types.js +22 -0
- package/dist/esm/asset/utils.js +99 -0
- package/dist/esm/bip322/index.js +267 -0
- package/dist/esm/contracts/arkcontract.js +141 -0
- package/dist/esm/contracts/contractManager.js +432 -0
- package/dist/esm/contracts/contractWatcher.js +563 -0
- package/dist/esm/contracts/handlers/default.js +82 -0
- package/dist/esm/contracts/handlers/delegate.js +86 -0
- package/dist/esm/contracts/handlers/helpers.js +66 -0
- package/dist/esm/contracts/handlers/index.js +12 -0
- package/dist/esm/contracts/handlers/registry.js +86 -0
- package/dist/esm/contracts/handlers/vhtlc.js +190 -0
- package/dist/esm/contracts/index.js +13 -0
- package/dist/esm/contracts/types.js +1 -0
- package/dist/esm/forfeit.js +11 -8
- package/dist/esm/identity/index.js +1 -0
- package/dist/esm/identity/seedIdentity.js +249 -0
- package/dist/esm/index.js +28 -15
- package/dist/esm/intent/index.js +44 -9
- package/dist/esm/providers/ark.js +7 -0
- package/dist/esm/providers/delegator.js +62 -0
- package/dist/esm/providers/expoIndexer.js +5 -0
- package/dist/esm/providers/indexer.js +68 -1
- package/dist/esm/providers/utils.js +1 -0
- package/dist/esm/repositories/contractRepository.js +1 -101
- package/dist/esm/repositories/inMemory/contractRepository.js +51 -0
- package/dist/esm/repositories/inMemory/walletRepository.js +76 -0
- package/dist/esm/repositories/index.js +8 -0
- package/dist/esm/repositories/indexedDB/contractRepository.js +183 -0
- package/dist/esm/repositories/indexedDB/db.js +4 -0
- package/dist/esm/repositories/indexedDB/manager.js +92 -0
- package/dist/esm/repositories/indexedDB/schema.js +155 -0
- package/dist/esm/repositories/indexedDB/walletRepository.js +334 -0
- package/dist/esm/repositories/indexedDB/websqlAdapter.js +138 -0
- package/dist/esm/repositories/migrations/contractRepositoryImpl.js +121 -0
- package/dist/esm/repositories/migrations/fromStorageAdapter.js +58 -0
- package/dist/esm/repositories/migrations/walletRepositoryImpl.js +176 -0
- package/dist/esm/repositories/realm/contractRepository.js +116 -0
- package/dist/esm/repositories/realm/index.js +3 -0
- package/dist/esm/repositories/realm/schemas.js +105 -0
- package/dist/esm/repositories/realm/types.js +6 -0
- package/dist/esm/repositories/realm/walletRepository.js +269 -0
- package/dist/esm/repositories/serialization.js +40 -0
- package/dist/esm/repositories/sqlite/contractRepository.js +135 -0
- package/dist/esm/repositories/sqlite/index.js +2 -0
- package/dist/esm/repositories/sqlite/types.js +1 -0
- package/dist/esm/repositories/sqlite/walletRepository.js +324 -0
- package/dist/esm/repositories/walletRepository.js +1 -167
- package/dist/esm/script/base.js +21 -1
- package/dist/esm/script/delegate.js +46 -0
- package/dist/esm/storage/asyncStorage.js +4 -1
- package/dist/esm/storage/fileSystem.js +3 -0
- package/dist/esm/storage/inMemory.js +3 -0
- package/dist/esm/storage/indexedDB.js +5 -1
- package/dist/esm/storage/localStorage.js +3 -0
- package/dist/esm/utils/arkTransaction.js +15 -0
- package/dist/esm/utils/transactionHistory.js +50 -0
- package/dist/esm/wallet/asset-manager.js +333 -0
- package/dist/esm/wallet/asset.js +111 -0
- package/dist/esm/wallet/batch.js +1 -1
- package/dist/esm/wallet/delegator.js +231 -0
- package/dist/esm/wallet/expo/background.js +128 -0
- package/dist/esm/wallet/expo/index.js +2 -0
- package/dist/esm/wallet/expo/wallet.js +194 -0
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +564 -0
- package/dist/esm/wallet/serviceWorker/wallet.js +382 -101
- package/dist/esm/wallet/utils.js +54 -0
- package/dist/esm/wallet/validation.js +139 -0
- package/dist/esm/wallet/vtxo-manager.js +8 -1
- package/dist/esm/wallet/wallet.js +704 -229
- package/dist/esm/worker/browser/service-worker-manager.js +76 -0
- package/dist/esm/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
- package/dist/esm/worker/expo/asyncStorageTaskQueue.js +74 -0
- package/dist/esm/worker/expo/index.js +4 -0
- package/dist/esm/worker/expo/processors/contractPollProcessor.js +58 -0
- package/dist/esm/worker/expo/processors/index.js +1 -0
- package/dist/esm/worker/expo/taskQueue.js +37 -0
- package/dist/esm/worker/expo/taskRunner.js +54 -0
- package/dist/esm/worker/messageBus.js +248 -0
- package/dist/types/asset/assetGroup.d.ts +28 -0
- package/dist/types/asset/assetId.d.ts +19 -0
- package/dist/types/asset/assetInput.d.ts +46 -0
- package/dist/types/asset/assetOutput.d.ts +39 -0
- package/dist/types/asset/assetRef.d.ts +25 -0
- package/dist/types/asset/index.d.ts +8 -0
- package/dist/types/asset/metadata.d.ts +37 -0
- package/dist/types/asset/packet.d.ts +27 -0
- package/dist/types/asset/types.d.ts +18 -0
- package/dist/types/asset/utils.d.ts +21 -0
- package/dist/types/bip322/index.d.ts +55 -0
- package/dist/types/contracts/arkcontract.d.ts +101 -0
- package/dist/types/contracts/contractManager.d.ts +331 -0
- package/dist/types/contracts/contractWatcher.d.ts +192 -0
- package/dist/types/contracts/handlers/default.d.ts +19 -0
- package/dist/types/contracts/handlers/delegate.d.ts +21 -0
- package/dist/types/contracts/handlers/helpers.d.ts +18 -0
- package/dist/types/contracts/handlers/index.d.ts +7 -0
- package/dist/types/contracts/handlers/registry.d.ts +65 -0
- package/dist/types/contracts/handlers/vhtlc.d.ts +32 -0
- package/dist/types/contracts/index.d.ts +14 -0
- package/dist/types/contracts/types.d.ts +222 -0
- package/dist/types/forfeit.d.ts +2 -1
- package/dist/types/identity/index.d.ts +1 -0
- package/dist/types/identity/seedIdentity.d.ts +128 -0
- package/dist/types/index.d.ts +22 -12
- package/dist/types/intent/index.d.ts +15 -1
- package/dist/types/providers/ark.d.ts +11 -2
- package/dist/types/providers/delegator.d.ts +29 -0
- package/dist/types/providers/indexer.d.ts +11 -1
- package/dist/types/repositories/contractRepository.d.ts +30 -19
- package/dist/types/repositories/inMemory/contractRepository.d.ts +17 -0
- package/dist/types/repositories/inMemory/walletRepository.d.ts +26 -0
- package/dist/types/repositories/index.d.ts +7 -0
- package/dist/types/repositories/indexedDB/contractRepository.d.ts +21 -0
- package/dist/types/repositories/indexedDB/db.d.ts +4 -0
- package/dist/types/repositories/indexedDB/manager.d.ts +22 -0
- package/dist/types/repositories/indexedDB/schema.d.ts +8 -0
- package/dist/types/repositories/indexedDB/walletRepository.d.ts +25 -0
- package/dist/types/repositories/indexedDB/websqlAdapter.d.ts +49 -0
- package/dist/types/repositories/migrations/contractRepositoryImpl.d.ts +24 -0
- package/dist/types/repositories/migrations/fromStorageAdapter.d.ts +19 -0
- package/dist/types/repositories/migrations/walletRepositoryImpl.d.ts +27 -0
- package/dist/types/repositories/realm/contractRepository.d.ts +24 -0
- package/dist/types/repositories/realm/index.d.ts +4 -0
- package/dist/types/repositories/realm/schemas.d.ts +208 -0
- package/dist/types/repositories/realm/types.d.ts +16 -0
- package/dist/types/repositories/realm/walletRepository.d.ts +31 -0
- package/dist/types/repositories/serialization.d.ts +40 -0
- package/dist/types/repositories/sqlite/contractRepository.d.ts +33 -0
- package/dist/types/repositories/sqlite/index.d.ts +3 -0
- package/dist/types/repositories/sqlite/types.d.ts +18 -0
- package/dist/types/repositories/sqlite/walletRepository.d.ts +40 -0
- package/dist/types/repositories/walletRepository.d.ts +13 -24
- package/dist/types/script/base.d.ts +1 -0
- package/dist/types/script/delegate.d.ts +36 -0
- package/dist/types/storage/asyncStorage.d.ts +4 -0
- package/dist/types/storage/fileSystem.d.ts +3 -0
- package/dist/types/storage/inMemory.d.ts +3 -0
- package/dist/types/storage/index.d.ts +3 -0
- package/dist/types/storage/indexedDB.d.ts +3 -0
- package/dist/types/storage/localStorage.d.ts +3 -0
- package/dist/types/utils/arkTransaction.d.ts +6 -0
- package/dist/types/wallet/asset-manager.d.ts +78 -0
- package/dist/types/wallet/asset.d.ts +21 -0
- package/dist/types/wallet/batch.d.ts +1 -1
- package/dist/types/wallet/delegator.d.ts +24 -0
- package/dist/types/wallet/expo/background.d.ts +66 -0
- package/dist/types/wallet/expo/index.d.ts +4 -0
- package/dist/types/wallet/expo/wallet.d.ts +97 -0
- package/dist/types/wallet/index.d.ts +75 -2
- package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +366 -0
- package/dist/types/wallet/serviceWorker/wallet.d.ts +20 -11
- package/dist/types/wallet/utils.d.ts +12 -1
- package/dist/types/wallet/validation.d.ts +24 -0
- package/dist/types/wallet/wallet.d.ts +111 -17
- package/dist/types/worker/browser/service-worker-manager.d.ts +21 -0
- package/dist/types/{wallet/serviceWorker → worker/browser}/utils.d.ts +2 -1
- package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +46 -0
- package/dist/types/worker/expo/index.d.ts +7 -0
- package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +14 -0
- package/dist/types/worker/expo/processors/index.d.ts +1 -0
- package/dist/types/worker/expo/taskQueue.d.ts +50 -0
- package/dist/types/worker/expo/taskRunner.d.ts +42 -0
- package/dist/types/worker/messageBus.d.ts +109 -0
- package/package.json +69 -11
- package/dist/cjs/wallet/serviceWorker/request.js +0 -78
- package/dist/cjs/wallet/serviceWorker/response.js +0 -222
- package/dist/cjs/wallet/serviceWorker/worker.js +0 -655
- package/dist/esm/wallet/serviceWorker/request.js +0 -75
- package/dist/esm/wallet/serviceWorker/response.js +0 -219
- package/dist/esm/wallet/serviceWorker/worker.js +0 -651
- package/dist/types/wallet/serviceWorker/request.d.ts +0 -74
- package/dist/types/wallet/serviceWorker/response.d.ts +0 -123
- 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 {
|
|
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
|
-
//
|
|
22
|
-
const
|
|
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:
|
|
31
|
-
// storage:
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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,103 @@ 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
|
+
|
|
437
|
+
### BIP-322 Message Signing
|
|
438
|
+
|
|
439
|
+
Sign and verify messages using [BIP-322](https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki). Supports P2TR (Taproot) signing, and verification for P2TR, P2WPKH, and legacy P2PKH addresses.
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
import { BIP322, SingleKey } from '@arkade-os/sdk'
|
|
443
|
+
|
|
444
|
+
const identity = SingleKey.fromHex('your_private_key_hex')
|
|
445
|
+
|
|
446
|
+
// Sign a message (P2TR key-spend)
|
|
447
|
+
const signature = await BIP322.sign('Hello Bitcoin!', identity)
|
|
448
|
+
|
|
449
|
+
// Verify against a P2TR address
|
|
450
|
+
const valid = BIP322.verify('Hello Bitcoin!', signature, 'bc1p...')
|
|
451
|
+
|
|
452
|
+
// Also works with P2WPKH and legacy P2PKH addresses
|
|
453
|
+
BIP322.verify('Hello Bitcoin!', sig, 'bc1q...') // P2WPKH
|
|
454
|
+
BIP322.verify('Hello Bitcoin!', sig, '1A1zP1...') // legacy P2PKH
|
|
455
|
+
```
|
|
456
|
+
|
|
236
457
|
### Transaction History
|
|
237
458
|
|
|
238
459
|
```typescript
|
|
@@ -329,81 +550,285 @@ await Unroll.completeUnroll(
|
|
|
329
550
|
|
|
330
551
|
### Running the wallet in a service worker
|
|
331
552
|
|
|
332
|
-
|
|
553
|
+
The SDK provides a `MessageBus` orchestrator that runs inside a service worker
|
|
554
|
+
and routes messages to pluggable `MessageHandler`s. The built-in
|
|
555
|
+
`WalletMessageHandler` exposes all wallet operations over this message bus, and
|
|
556
|
+
`ServiceWorkerWallet` is a client-side proxy that communicates with it
|
|
557
|
+
transparently.
|
|
558
|
+
|
|
559
|
+
#### Service worker file
|
|
560
|
+
|
|
561
|
+
```javascript
|
|
562
|
+
// service-worker.js
|
|
563
|
+
import {
|
|
564
|
+
MessageBus,
|
|
565
|
+
WalletMessageHandler,
|
|
566
|
+
IndexedDBWalletRepository,
|
|
567
|
+
IndexedDBContractRepository,
|
|
568
|
+
} from '@arkade-os/sdk'
|
|
569
|
+
|
|
570
|
+
const walletRepo = new IndexedDBWalletRepository()
|
|
571
|
+
const contractRepo = new IndexedDBContractRepository()
|
|
572
|
+
|
|
573
|
+
const bus = new MessageBus(walletRepo, contractRepo, {
|
|
574
|
+
messageHandlers: [new WalletMessageHandler()],
|
|
575
|
+
tickIntervalMs: 10_000, // default 10s
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
bus.start()
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
#### Client-side usage
|
|
333
582
|
|
|
334
583
|
```typescript
|
|
335
|
-
//
|
|
336
|
-
import { ServiceWorkerWallet, SingleKey } from '@arkade-os/sdk'
|
|
584
|
+
// app.ts
|
|
585
|
+
import { ServiceWorkerWallet, SingleKey } from '@arkade-os/sdk'
|
|
337
586
|
|
|
338
|
-
|
|
339
|
-
const identity = SingleKey.fromHex('your_private_key_hex');
|
|
340
|
-
// Or generate a new one:
|
|
341
|
-
// const identity = SingleKey.fromRandomBytes();
|
|
587
|
+
const identity = SingleKey.fromHex('your_private_key_hex')
|
|
342
588
|
|
|
589
|
+
// One-liner: registers the SW, initializes the MessageBus, and creates the wallet
|
|
343
590
|
const wallet = await ServiceWorkerWallet.setup({
|
|
344
591
|
serviceWorkerPath: '/service-worker.js',
|
|
345
592
|
arkServerUrl: 'https://mutinynet.arkade.sh',
|
|
346
|
-
identity
|
|
347
|
-
})
|
|
593
|
+
identity,
|
|
594
|
+
})
|
|
348
595
|
|
|
349
|
-
//
|
|
350
|
-
const address = await wallet.getAddress()
|
|
351
|
-
const balance = await wallet.getBalance()
|
|
596
|
+
// Use like any other wallet — calls are proxied to the service worker
|
|
597
|
+
const address = await wallet.getAddress()
|
|
598
|
+
const balance = await wallet.getBalance()
|
|
352
599
|
```
|
|
353
600
|
|
|
354
|
-
|
|
601
|
+
For watch-only wallets, use `ServiceWorkerReadonlyWallet` with a
|
|
602
|
+
`ReadonlySingleKey` identity instead.
|
|
603
|
+
|
|
604
|
+
### Worker Architecture
|
|
605
|
+
|
|
606
|
+
The _worker_ captures the background processing infrastructure for the SDK.
|
|
607
|
+
Two platform-specific implementations share common patterns (pluggable
|
|
608
|
+
handlers, periodic scheduling, repository/provider dependency injection) but
|
|
609
|
+
differ in orchestration and communication.
|
|
610
|
+
|
|
611
|
+
| Platform | Directory | Orchestrator | Communication |
|
|
612
|
+
|----------|----------------------------------------------|-------------|---------------|
|
|
613
|
+
| **Browser** | [`browser/`](./src/worker/browser/README.md) | `MessageBus` inside a Service Worker | `postMessage` between SW and window clients |
|
|
614
|
+
| **Expo/React Native** | [`expo/`](./src/worker/expo/README.md) | `runTasks()` called from foreground interval and OS background wake | `AsyncStorageTaskQueue` inbox/outbox |
|
|
615
|
+
|
|
616
|
+
See the platform READMEs for architecture details, runtime flow, and usage
|
|
617
|
+
examples.
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
### Repositories (Storage)
|
|
622
|
+
|
|
623
|
+
The `StorageAdapter` API is deprecated. Use repositories instead. If you omit
|
|
624
|
+
`storage`, the SDK uses IndexedDB repositories with the default database name.
|
|
625
|
+
|
|
626
|
+
#### Migration from v1 StorageAdapter
|
|
627
|
+
|
|
628
|
+
> [!WARNING]
|
|
629
|
+
> If you previously used the v1 `StorageAdapter`-based repositories, migrate
|
|
630
|
+
> data into the new IndexedDB repositories before use:
|
|
631
|
+
>
|
|
632
|
+
> ```typescript
|
|
633
|
+
> import {
|
|
634
|
+
> IndexedDBWalletRepository,
|
|
635
|
+
> IndexedDBContractRepository,
|
|
636
|
+
> getMigrationStatus,
|
|
637
|
+
> migrateWalletRepository,
|
|
638
|
+
> rollbackMigration,
|
|
639
|
+
> } from '@arkade-os/sdk'
|
|
640
|
+
> import { IndexedDBStorageAdapter } from '@arkade-os/sdk/adapters/indexedDB'
|
|
641
|
+
>
|
|
642
|
+
> const oldStorage = new IndexedDBStorageAdapter('legacy-wallet', 1)
|
|
643
|
+
> const newDbName = 'my-app-db'
|
|
644
|
+
> const walletRepository = new IndexedDBWalletRepository(newDbName)
|
|
645
|
+
>
|
|
646
|
+
> // Check migration status before running
|
|
647
|
+
> const status = await getMigrationStatus('wallet', oldStorage)
|
|
648
|
+
> // status: "not-needed" | "pending" | "in-progress" | "done"
|
|
649
|
+
>
|
|
650
|
+
> if (status === 'pending' || status === 'in-progress') {
|
|
651
|
+
> try {
|
|
652
|
+
> await migrateWalletRepository(oldStorage, walletRepository, {
|
|
653
|
+
> onchain: [ 'address-1', 'address-2' ],
|
|
654
|
+
> offchain: [ 'onboarding-address-1' ],
|
|
655
|
+
> })
|
|
656
|
+
> } catch (err) {
|
|
657
|
+
> // Reset migration flag so the next attempt starts clean
|
|
658
|
+
> await rollbackMigration('wallet', oldStorage)
|
|
659
|
+
> throw err
|
|
660
|
+
> }
|
|
661
|
+
> }
|
|
662
|
+
> ```
|
|
663
|
+
>
|
|
664
|
+
> **Migration status helpers:**
|
|
665
|
+
>
|
|
666
|
+
> | Helper | Description |
|
|
667
|
+
> |--------|-------------|
|
|
668
|
+
> | `getMigrationStatus(repoType, adapter)` | Returns `"not-needed"` (no legacy DB), `"pending"`, `"in-progress"` (interrupted), or `"done"` |
|
|
669
|
+
> | `requiresMigration(repoType, adapter)` | Returns `true` if status is `"pending"` or `"in-progress"` |
|
|
670
|
+
> | `rollbackMigration(repoType, adapter)` | Removes the migration flag so migration can re-run from scratch |
|
|
671
|
+
> | `MIGRATION_KEY(repoType)` | Returns the storage key used for the migration flag |
|
|
672
|
+
>
|
|
673
|
+
> `migrateWalletRepository` sets an `"in-progress"` flag before copying data.
|
|
674
|
+
> If the process crashes mid-way, the flag remains as `"in-progress"` so the
|
|
675
|
+
> next call to `getMigrationStatus` can detect the partial migration. Old data
|
|
676
|
+
> is never deleted — re-running migration after a rollback is safe.
|
|
677
|
+
>
|
|
678
|
+
> 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.
|
|
679
|
+
>
|
|
680
|
+
> If you persisted custom data in the ContractRepository via its `setContractData` method,
|
|
681
|
+
> or a custom collection via `saveToContractCollection`, you'll need to migrate it manually:
|
|
682
|
+
>
|
|
683
|
+
> ```typescript
|
|
684
|
+
> // Custom data stored in the ContractRepository
|
|
685
|
+
> const oldStorage = new IndexedDBStorageAdapter('legacy-wallet', 1)
|
|
686
|
+
> const oldRepo = new ContractRepositoryImpl(storageAdapter)
|
|
687
|
+
> const customContract = await oldRepo.getContractData('my-contract', 'status')
|
|
688
|
+
> await contractRepository.setContractData('my-contract', 'status', customData)
|
|
689
|
+
> const customCollection = await oldRepo.getContractCollection('swaps')
|
|
690
|
+
> await contractRepository.saveToContractCollection('swaps', customCollection)
|
|
691
|
+
> ```
|
|
692
|
+
|
|
693
|
+
#### Repository Versioning
|
|
694
|
+
|
|
695
|
+
`WalletRepository`, `ContractRepository`, and `SwapRepository` (in
|
|
696
|
+
`@arkade-os/boltz-swap`) each declare a `readonly version` field with a literal
|
|
697
|
+
type. All built-in implementations set this to the current version. If you
|
|
698
|
+
maintain a custom repository implementation, TypeScript will produce a compile
|
|
699
|
+
error when the version is bumped, signaling that a semantic update is required:
|
|
355
700
|
|
|
356
701
|
```typescript
|
|
357
|
-
|
|
358
|
-
import { Worker } from '@arkade-os/sdk'
|
|
702
|
+
import { WalletRepository } from '@arkade-os/sdk'
|
|
359
703
|
|
|
360
|
-
|
|
361
|
-
|
|
704
|
+
class MyWalletRepository implements WalletRepository {
|
|
705
|
+
readonly version = 1 // must match the interface's literal type
|
|
706
|
+
// ...
|
|
707
|
+
}
|
|
362
708
|
```
|
|
363
709
|
|
|
364
|
-
|
|
710
|
+
#### SQLite Repository (Node.js / React Native)
|
|
365
711
|
|
|
366
|
-
|
|
712
|
+
For Node.js or React Native environments, use the SQLite repository with any
|
|
713
|
+
SQLite driver. The SDK accepts a `SQLExecutor` interface — you provide the
|
|
714
|
+
driver, the SDK handles the schema.
|
|
715
|
+
|
|
716
|
+
See [examples/node/multiple-wallets.ts](examples/node/multiple-wallets.ts) for
|
|
717
|
+
a full working example using `better-sqlite3`.
|
|
367
718
|
|
|
368
719
|
```typescript
|
|
369
|
-
import {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
InMemoryStorageAdapter, // Works everywhere, data lost on restart
|
|
373
|
-
} from '@arkade-os/sdk'
|
|
720
|
+
import { SingleKey, Wallet } from '@arkade-os/sdk'
|
|
721
|
+
import { SQLiteWalletRepository, SQLiteContractRepository, SQLExecutor } from '@arkade-os/sdk/repositories/sqlite'
|
|
722
|
+
import Database from 'better-sqlite3'
|
|
374
723
|
|
|
375
|
-
|
|
376
|
-
|
|
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
|
|
724
|
+
const db = new Database('my-wallet.sqlite')
|
|
725
|
+
db.pragma('journal_mode = WAL')
|
|
380
726
|
|
|
381
|
-
|
|
382
|
-
|
|
727
|
+
const executor: SQLExecutor = {
|
|
728
|
+
run: async (sql, params) => { db.prepare(sql).run(...(params ?? [])) },
|
|
729
|
+
get: async (sql, params) => db.prepare(sql).get(...(params ?? [])) as any,
|
|
730
|
+
all: async (sql, params) => db.prepare(sql).all(...(params ?? [])) as any,
|
|
731
|
+
}
|
|
383
732
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
733
|
+
const wallet = await Wallet.create({
|
|
734
|
+
identity: SingleKey.fromHex('your_private_key_hex'),
|
|
735
|
+
arkServerUrl: 'https://mutinynet.arkade.sh',
|
|
736
|
+
storage: {
|
|
737
|
+
walletRepository: new SQLiteWalletRepository(executor),
|
|
738
|
+
contractRepository: new SQLiteContractRepository(executor),
|
|
739
|
+
},
|
|
740
|
+
})
|
|
741
|
+
```
|
|
388
742
|
|
|
389
|
-
|
|
390
|
-
const storage = new AsyncStorageAdapter()
|
|
743
|
+
#### Realm Repository (React Native)
|
|
391
744
|
|
|
392
|
-
|
|
393
|
-
const storage = new IndexedDBStorageAdapter('service-worker-wallet', 1)
|
|
745
|
+
For React Native apps using Realm, pass your Realm instance directly:
|
|
394
746
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
const identity = SingleKey.fromHex(privateKeyHex)
|
|
747
|
+
```typescript
|
|
748
|
+
import { RealmWalletRepository, RealmContractRepository, ArkRealmSchemas } from '@arkade-os/sdk/repositories/realm'
|
|
398
749
|
|
|
399
|
-
|
|
750
|
+
const realm = await Realm.open({ schema: [...ArkRealmSchemas, ...yourSchemas] })
|
|
400
751
|
const wallet = await Wallet.create({
|
|
401
752
|
identity,
|
|
402
753
|
arkServerUrl: 'https://mutinynet.arkade.sh',
|
|
403
|
-
storage
|
|
754
|
+
storage: {
|
|
755
|
+
walletRepository: new RealmWalletRepository(realm),
|
|
756
|
+
contractRepository: new RealmContractRepository(realm),
|
|
757
|
+
},
|
|
758
|
+
})
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
#### IndexedDB Repository (Browser)
|
|
762
|
+
|
|
763
|
+
In the browser, the SDK defaults to IndexedDB repositories when no `storage`
|
|
764
|
+
is provided:
|
|
765
|
+
|
|
766
|
+
```typescript
|
|
767
|
+
import { SingleKey, Wallet } from '@arkade-os/sdk'
|
|
768
|
+
|
|
769
|
+
const wallet = await Wallet.create({
|
|
770
|
+
identity: SingleKey.fromHex('your_private_key_hex'),
|
|
771
|
+
arkServerUrl: 'https://mutinynet.arkade.sh',
|
|
772
|
+
// Uses IndexedDB by default in the browser
|
|
404
773
|
})
|
|
405
774
|
```
|
|
406
775
|
|
|
776
|
+
If you want a custom database name or a different repository implementation,
|
|
777
|
+
pass `storage` explicitly.
|
|
778
|
+
|
|
779
|
+
For ephemeral storage (no persistence), pass the in-memory repositories:
|
|
780
|
+
|
|
781
|
+
```typescript
|
|
782
|
+
import {
|
|
783
|
+
InMemoryWalletRepository,
|
|
784
|
+
InMemoryContractRepository,
|
|
785
|
+
Wallet
|
|
786
|
+
} from '@arkade-os/sdk'
|
|
787
|
+
|
|
788
|
+
const wallet = await Wallet.create({
|
|
789
|
+
identity,
|
|
790
|
+
arkServerUrl: 'https://mutinynet.arkade.sh',
|
|
791
|
+
storage: {
|
|
792
|
+
walletRepository: new InMemoryWalletRepository(),
|
|
793
|
+
contractRepository: new InMemoryContractRepository()
|
|
794
|
+
}
|
|
795
|
+
})
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
### Using with Node.js
|
|
799
|
+
|
|
800
|
+
Node.js does not provide a global `EventSource` implementation. The SDK relies on `EventSource` for Server-Sent Events during settlement (onboarding/offboarding) and contract watching. You must polyfill it before using the SDK:
|
|
801
|
+
|
|
802
|
+
```bash
|
|
803
|
+
npm install eventsource
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
```typescript
|
|
807
|
+
import { EventSource } from "eventsource";
|
|
808
|
+
(globalThis as any).EventSource = EventSource;
|
|
809
|
+
|
|
810
|
+
// Use dynamic import so the polyfill is set before the SDK evaluates
|
|
811
|
+
const { Wallet, SingleKey, Ramps } = await import("@arkade-os/sdk");
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
If you also need IndexedDB persistence (e.g. for `WalletRepository`), set up the shim before any SDK import:
|
|
815
|
+
|
|
816
|
+
```typescript
|
|
817
|
+
// Must define `self` BEFORE calling setGlobalVars
|
|
818
|
+
if (typeof self === "undefined") {
|
|
819
|
+
(globalThis as any).self = globalThis;
|
|
820
|
+
}
|
|
821
|
+
import setGlobalVars from "indexeddbshim/src/node-UnicodeIdentifiers";
|
|
822
|
+
(globalThis as any).window = globalThis;
|
|
823
|
+
setGlobalVars(null, { checkOrigin: false });
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
> **Note:** `eventsource` and `indexeddbshim` are optional peer dependencies.
|
|
827
|
+
> Without the `EventSource` polyfill, settlement operations will fail with
|
|
828
|
+
> `ReferenceError: EventSource is not defined`.
|
|
829
|
+
|
|
830
|
+
See [`examples/node/multiple-wallets.ts`](examples/node/multiple-wallets.ts) for a complete working example.
|
|
831
|
+
|
|
407
832
|
### Using with Expo/React Native
|
|
408
833
|
|
|
409
834
|
For React Native and Expo applications where standard EventSource and fetch streaming may not work properly, use the Expo-compatible providers:
|
|
@@ -432,6 +857,31 @@ Both ExpoArkProvider and ExpoIndexerProvider are available as adapters following
|
|
|
432
857
|
- **ExpoArkProvider**: Handles settlement events and transaction streaming using expo/fetch for Server-Sent Events
|
|
433
858
|
- **ExpoIndexerProvider**: Handles address subscriptions and VTXO updates using expo/fetch for JSON streaming
|
|
434
859
|
|
|
860
|
+
For persistence in Expo/React Native, use the SQLite repository with `expo-sqlite`:
|
|
861
|
+
|
|
862
|
+
```typescript
|
|
863
|
+
import { SQLiteWalletRepository, SQLiteContractRepository } from '@arkade-os/sdk/repositories/sqlite'
|
|
864
|
+
import * as SQLite from 'expo-sqlite'
|
|
865
|
+
|
|
866
|
+
const db = SQLite.openDatabaseSync('my-wallet.db')
|
|
867
|
+
const executor = {
|
|
868
|
+
run: (sql, params) => db.runAsync(sql, params ?? []),
|
|
869
|
+
get: (sql, params) => db.getFirstAsync(sql, params ?? []),
|
|
870
|
+
all: (sql, params) => db.getAllAsync(sql, params ?? []),
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
const wallet = await Wallet.create({
|
|
874
|
+
identity,
|
|
875
|
+
arkServerUrl: 'https://mutinynet.arkade.sh',
|
|
876
|
+
arkProvider: new ExpoArkProvider('https://mutinynet.arkade.sh'),
|
|
877
|
+
indexerProvider: new ExpoIndexerProvider('https://mutinynet.arkade.sh'),
|
|
878
|
+
storage: {
|
|
879
|
+
walletRepository: new SQLiteWalletRepository(executor),
|
|
880
|
+
contractRepository: new SQLiteContractRepository(executor),
|
|
881
|
+
},
|
|
882
|
+
})
|
|
883
|
+
```
|
|
884
|
+
|
|
435
885
|
#### Crypto Polyfill Requirement
|
|
436
886
|
|
|
437
887
|
Install `expo-crypto` and polyfill `crypto.getRandomValues()` at the top of your app entry point:
|
|
@@ -453,6 +903,88 @@ import { ExpoArkProvider, ExpoIndexerProvider } from '@arkade-os/sdk/adapters/ex
|
|
|
453
903
|
|
|
454
904
|
This is required for MuSig2 settlements and cryptographic operations.
|
|
455
905
|
|
|
906
|
+
### Contract Management
|
|
907
|
+
|
|
908
|
+
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.).
|
|
909
|
+
|
|
910
|
+
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.
|
|
911
|
+
|
|
912
|
+
For advanced use cases, you can access the ContractManager directly to register external contracts:
|
|
913
|
+
|
|
914
|
+
```typescript
|
|
915
|
+
// Get the contract manager (wallet's default address is already registered)
|
|
916
|
+
const manager = await wallet.getContractManager()
|
|
917
|
+
|
|
918
|
+
// Register a VHTLC contract (e.g., for a Lightning swap)
|
|
919
|
+
const contract = await manager.createContract({
|
|
920
|
+
type: 'vhtlc',
|
|
921
|
+
params: {
|
|
922
|
+
sender: alicePubKey,
|
|
923
|
+
receiver: bobPubKey,
|
|
924
|
+
server: serverPubKey,
|
|
925
|
+
hash: paymentHash,
|
|
926
|
+
refundLocktime: '800000',
|
|
927
|
+
claimDelay: '100',
|
|
928
|
+
refundDelay: '102',
|
|
929
|
+
refundNoReceiverDelay: '103',
|
|
930
|
+
},
|
|
931
|
+
script: swapScript,
|
|
932
|
+
address: swapAddress,
|
|
933
|
+
})
|
|
934
|
+
|
|
935
|
+
// Listen for all contracts events (wallet address + external contracts)
|
|
936
|
+
const unsubscribe = await manager.onContractEvent((event) => {
|
|
937
|
+
switch (event.type) {
|
|
938
|
+
case 'vtxo_received':
|
|
939
|
+
console.log(`Received ${event.vtxos.length} VTXOs on ${event.contractScript}`)
|
|
940
|
+
break
|
|
941
|
+
case 'vtxo_spent':
|
|
942
|
+
console.log(`Spent VTXOs on ${event.contractScript}`)
|
|
943
|
+
break
|
|
944
|
+
case 'contract_expired':
|
|
945
|
+
console.log(`Contract ${event.contractScript} expired`)
|
|
946
|
+
break
|
|
947
|
+
}
|
|
948
|
+
})
|
|
949
|
+
|
|
950
|
+
// Update contract data (e.g., set preimage when revealed)
|
|
951
|
+
await manager.updateContractParams(contract.script, { preimage: revealedPreimage })
|
|
952
|
+
|
|
953
|
+
// Check spendable paths (requires a specific VTXO)
|
|
954
|
+
const [withVtxos] = await manager.getContractsWithVtxos({ script: contract.script })
|
|
955
|
+
const vtxo = withVtxos.vtxos[0]
|
|
956
|
+
const paths = manager.getSpendablePaths({
|
|
957
|
+
contractScript: contract.script,
|
|
958
|
+
vtxo,
|
|
959
|
+
collaborative: true,
|
|
960
|
+
walletPubKey: myPubKey,
|
|
961
|
+
})
|
|
962
|
+
if (paths.length > 0) {
|
|
963
|
+
console.log('Contract is spendable via:', paths[0].leaf)
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// Or list all possible paths for the current context (no spendability checks)
|
|
967
|
+
const allPaths = manager.getAllSpendingPaths({
|
|
968
|
+
contractScript: contract.script,
|
|
969
|
+
collaborative: true,
|
|
970
|
+
walletPubKey: myPubKey,
|
|
971
|
+
})
|
|
972
|
+
|
|
973
|
+
// Get balances across all contracts
|
|
974
|
+
const balances = await manager.getAllBalances()
|
|
975
|
+
|
|
976
|
+
// Manually sweep all eligible contracts
|
|
977
|
+
const sweepResults = await manager.sweepAll()
|
|
978
|
+
|
|
979
|
+
// Stop watching
|
|
980
|
+
unsubscribe()
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
The watcher features:
|
|
984
|
+
- **Automatic reconnection** with exponential backoff (1s → 30s max)
|
|
985
|
+
- **Failsafe polling** every 60 seconds to catch missed events
|
|
986
|
+
- **Immediate sync** on connection and after failures
|
|
987
|
+
|
|
456
988
|
### Repository Pattern
|
|
457
989
|
|
|
458
990
|
Access low-level data management through repositories:
|