@arkade-os/sdk 0.3.0-alpha.7 → 0.3.0-alpha.8
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 +51 -0
- package/dist/cjs/adapters/expo.js +8 -0
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/providers/expoArk.js +237 -0
- package/dist/cjs/providers/expoIndexer.js +194 -0
- package/dist/cjs/providers/indexer.js +3 -1
- package/dist/cjs/utils/arkTransaction.js +13 -0
- package/dist/cjs/wallet/index.js +1 -1
- package/dist/cjs/wallet/serviceWorker/utils.js +0 -9
- package/dist/cjs/wallet/serviceWorker/worker.js +14 -17
- package/dist/cjs/wallet/utils.js +11 -0
- package/dist/cjs/wallet/wallet.js +69 -51
- package/dist/esm/adapters/expo.js +3 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/providers/expoArk.js +200 -0
- package/dist/esm/providers/expoIndexer.js +157 -0
- package/dist/esm/providers/indexer.js +3 -1
- package/dist/esm/utils/arkTransaction.js +13 -1
- package/dist/esm/wallet/index.js +1 -1
- package/dist/esm/wallet/serviceWorker/utils.js +0 -8
- package/dist/esm/wallet/serviceWorker/worker.js +15 -18
- package/dist/esm/wallet/utils.js +8 -0
- package/dist/esm/wallet/wallet.js +70 -52
- package/dist/types/adapters/expo.d.ts +4 -0
- package/dist/types/index.d.ts +5 -5
- package/dist/types/providers/ark.d.ts +136 -2
- package/dist/types/providers/expoArk.d.ts +22 -0
- package/dist/types/providers/expoIndexer.d.ts +26 -0
- package/dist/types/providers/indexer.d.ts +8 -0
- package/dist/types/utils/arkTransaction.d.ts +3 -1
- package/dist/types/wallet/index.d.ts +44 -6
- package/dist/types/wallet/serviceWorker/utils.d.ts +0 -2
- package/dist/types/wallet/utils.d.ts +2 -0
- package/dist/types/wallet/wallet.d.ts +9 -1
- package/package.json +11 -2
|
@@ -173,6 +173,7 @@ export class RestIndexerProvider {
|
|
|
173
173
|
scripts: data.event.scripts || [],
|
|
174
174
|
newVtxos: (data.event.newVtxos || []).map(convertVtxo),
|
|
175
175
|
spentVtxos: (data.event.spentVtxos || []).map(convertVtxo),
|
|
176
|
+
sweptVtxos: (data.event.sweptVtxos || []).map(convertVtxo),
|
|
176
177
|
tx: data.event.tx,
|
|
177
178
|
checkpointTxs: data.event.checkpointTxs,
|
|
178
179
|
};
|
|
@@ -326,7 +327,7 @@ export class RestIndexerProvider {
|
|
|
326
327
|
});
|
|
327
328
|
if (!res.ok) {
|
|
328
329
|
const errorText = await res.text();
|
|
329
|
-
|
|
330
|
+
console.warn(`Failed to unsubscribe to scripts: ${errorText}`);
|
|
330
331
|
}
|
|
331
332
|
}
|
|
332
333
|
}
|
|
@@ -354,6 +355,7 @@ function convertVtxo(vtxo) {
|
|
|
354
355
|
arkTxId: vtxo.arkTxid,
|
|
355
356
|
createdAt: new Date(Number(vtxo.createdAt) * 1000),
|
|
356
357
|
isUnrolled: vtxo.isUnrolled,
|
|
358
|
+
isSpent: vtxo.isSpent,
|
|
357
359
|
};
|
|
358
360
|
}
|
|
359
361
|
// Unexported namespace for type guards only
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_SEQUENCE, Transaction, } from "@scure/btc-signer/transaction.js";
|
|
2
|
-
import { CLTVMultisigTapscript, decodeTapscript } from '../script/tapscript.js';
|
|
2
|
+
import { CLTVMultisigTapscript, decodeTapscript, } from '../script/tapscript.js';
|
|
3
3
|
import { scriptFromTapLeafScript, VtxoScript, } from '../script/base.js';
|
|
4
4
|
import { P2A } from './anchor.js';
|
|
5
5
|
import { hex } from "@scure/base";
|
|
@@ -103,3 +103,15 @@ const nLocktimeMinSeconds = 500000000n;
|
|
|
103
103
|
function isSeconds(locktime) {
|
|
104
104
|
return locktime >= nLocktimeMinSeconds;
|
|
105
105
|
}
|
|
106
|
+
export function hasBoardingTxExpired(coin, boardingTimelock) {
|
|
107
|
+
if (!coin.status.block_time)
|
|
108
|
+
return false;
|
|
109
|
+
if (boardingTimelock.value === 0n)
|
|
110
|
+
return true;
|
|
111
|
+
if (boardingTimelock.type !== "blocks")
|
|
112
|
+
return false; // TODO: handle get chain tip
|
|
113
|
+
// validate expiry in terms of seconds
|
|
114
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
115
|
+
const blockTime = BigInt(Math.floor(coin.status.block_time));
|
|
116
|
+
return blockTime + boardingTimelock.value <= now;
|
|
117
|
+
}
|
package/dist/esm/wallet/index.js
CHANGED
|
@@ -4,7 +4,7 @@ export var TxType;
|
|
|
4
4
|
TxType["TxReceived"] = "RECEIVED";
|
|
5
5
|
})(TxType || (TxType = {}));
|
|
6
6
|
export function isSpendable(vtxo) {
|
|
7
|
-
return vtxo.
|
|
7
|
+
return !vtxo.isSpent;
|
|
8
8
|
}
|
|
9
9
|
export function isRecoverable(vtxo) {
|
|
10
10
|
return vtxo.virtualStatus.state === "swept" && isSpendable(vtxo);
|
|
@@ -44,11 +44,3 @@ export async function setupServiceWorker(path) {
|
|
|
44
44
|
navigator.serviceWorker.addEventListener("error", onError);
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
|
-
export function extendVirtualCoin(wallet, vtxo) {
|
|
48
|
-
return {
|
|
49
|
-
...vtxo,
|
|
50
|
-
forfeitTapLeafScript: wallet.offchainTapscript.forfeit(),
|
|
51
|
-
intentTapLeafScript: wallet.offchainTapscript.exit(),
|
|
52
|
-
tapTree: wallet.offchainTapscript.encode(),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference lib="webworker" />
|
|
2
2
|
import { SingleKey } from '../../identity/singleKey.js';
|
|
3
|
-
import { isSpendable, isSubdust } from '../index.js';
|
|
3
|
+
import { isRecoverable, isSpendable, isSubdust } from '../index.js';
|
|
4
4
|
import { Wallet } from '../wallet.js';
|
|
5
5
|
import { Request } from './request.js';
|
|
6
6
|
import { Response } from './response.js';
|
|
@@ -10,7 +10,7 @@ import { RestIndexerProvider } from '../../providers/indexer.js';
|
|
|
10
10
|
import { hex } from "@scure/base";
|
|
11
11
|
import { IndexedDBStorageAdapter } from '../../storage/indexedDB.js';
|
|
12
12
|
import { WalletRepositoryImpl, } from '../../repositories/walletRepository.js';
|
|
13
|
-
import { extendVirtualCoin } from '
|
|
13
|
+
import { extendVirtualCoin } from '../utils.js';
|
|
14
14
|
/**
|
|
15
15
|
* Worker is a class letting to interact with ServiceWorkerWallet from the client
|
|
16
16
|
* it aims to be run in a service worker context
|
|
@@ -74,6 +74,8 @@ export class Worker {
|
|
|
74
74
|
this.incomingFundsSubscription();
|
|
75
75
|
// Clear storage - this replaces vtxoRepository.close()
|
|
76
76
|
await this.storage.clear();
|
|
77
|
+
// Reset in-memory caches by recreating the repository
|
|
78
|
+
this.walletRepository = new WalletRepositoryImpl(this.storage);
|
|
77
79
|
this.wallet = undefined;
|
|
78
80
|
this.arkProvider = undefined;
|
|
79
81
|
this.indexerProvider = undefined;
|
|
@@ -102,9 +104,6 @@ export class Worker {
|
|
|
102
104
|
const txs = await this.wallet.getTransactionHistory();
|
|
103
105
|
if (txs)
|
|
104
106
|
await this.walletRepository.saveTransactions(address, txs);
|
|
105
|
-
// stop previous subscriptions if any
|
|
106
|
-
if (this.incomingFundsSubscription)
|
|
107
|
-
this.incomingFundsSubscription();
|
|
108
107
|
// subscribe for incoming funds and notify all clients when new funds arrive
|
|
109
108
|
this.incomingFundsSubscription = await this.wallet.notifyIncomingFunds(async (funds) => {
|
|
110
109
|
if (funds.type === "vtxo") {
|
|
@@ -124,7 +123,7 @@ export class Worker {
|
|
|
124
123
|
// notify all clients about the vtxo update
|
|
125
124
|
this.sendMessageToAllClients("VTXO_UPDATE", JSON.stringify({ newVtxos, spentVtxos }));
|
|
126
125
|
}
|
|
127
|
-
if (funds.type === "utxo"
|
|
126
|
+
if (funds.type === "utxo") {
|
|
128
127
|
// notify all clients about the utxo update
|
|
129
128
|
this.sendMessageToAllClients("UTXO_UPDATE", JSON.stringify(funds.coins));
|
|
130
129
|
}
|
|
@@ -355,17 +354,16 @@ export class Worker {
|
|
|
355
354
|
if (!message.filter?.withRecoverable) {
|
|
356
355
|
if (!this.wallet)
|
|
357
356
|
throw new Error("Wallet not initialized");
|
|
358
|
-
// exclude subdust
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
dustAmount == null
|
|
362
|
-
?
|
|
363
|
-
:
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
vtxos.push(...sweptVtxos.filter(isSpendable));
|
|
357
|
+
// exclude subdust and recoverable if we don't want recoverable
|
|
358
|
+
const notSubdust = (v) => {
|
|
359
|
+
const dustAmount = this.wallet?.dustAmount;
|
|
360
|
+
return dustAmount == null
|
|
361
|
+
? true
|
|
362
|
+
: !isSubdust(v, dustAmount);
|
|
363
|
+
};
|
|
364
|
+
vtxos = vtxos
|
|
365
|
+
.filter(notSubdust)
|
|
366
|
+
.filter((v) => !isRecoverable(v));
|
|
369
367
|
}
|
|
370
368
|
event.source?.postMessage(Response.vtxos(message.id, vtxos));
|
|
371
369
|
}
|
|
@@ -526,7 +524,6 @@ export class Worker {
|
|
|
526
524
|
}
|
|
527
525
|
async handleReloadWallet(event) {
|
|
528
526
|
const message = event.data;
|
|
529
|
-
console.log("RELOAD_WALLET message received", message);
|
|
530
527
|
if (!Request.isReloadWallet(message)) {
|
|
531
528
|
console.error("Invalid RELOAD_WALLET message format", message);
|
|
532
529
|
event.source?.postMessage(Response.error(message.id, "Invalid RELOAD_WALLET message format"));
|
|
@@ -15,7 +15,7 @@ import { isRecoverable, isSpendable, isSubdust, TxType, } from './index.js';
|
|
|
15
15
|
import { sha256, sha256x2 } from "@scure/btc-signer/utils.js";
|
|
16
16
|
import { VtxoScript } from '../script/base.js';
|
|
17
17
|
import { CSVMultisigTapscript } from '../script/tapscript.js';
|
|
18
|
-
import { buildOffchainTx } from '../utils/arkTransaction.js';
|
|
18
|
+
import { buildOffchainTx, hasBoardingTxExpired } from '../utils/arkTransaction.js';
|
|
19
19
|
import { ArkNote } from '../arknote/index.js';
|
|
20
20
|
import { BIP322 } from '../bip322/index.js';
|
|
21
21
|
import { RestIndexerProvider } from '../providers/indexer.js';
|
|
@@ -23,7 +23,7 @@ import { TxTree } from '../tree/txTree.js';
|
|
|
23
23
|
import { InMemoryStorageAdapter } from '../storage/inMemory.js';
|
|
24
24
|
import { WalletRepositoryImpl, } from '../repositories/walletRepository.js';
|
|
25
25
|
import { ContractRepositoryImpl, } from '../repositories/contractRepository.js';
|
|
26
|
-
import { extendVirtualCoin } from './
|
|
26
|
+
import { extendVirtualCoin } from './utils.js';
|
|
27
27
|
/**
|
|
28
28
|
* Main wallet implementation for Bitcoin transactions with Ark protocol support.
|
|
29
29
|
* The wallet does not store any data locally and relies on Ark and onchain
|
|
@@ -31,13 +31,21 @@ import { extendVirtualCoin } from './serviceWorker/utils.js';
|
|
|
31
31
|
*
|
|
32
32
|
* @example
|
|
33
33
|
* ```typescript
|
|
34
|
-
* // Create a wallet
|
|
34
|
+
* // Create a wallet with URL configuration
|
|
35
35
|
* const wallet = await Wallet.create({
|
|
36
36
|
* identity: SingleKey.fromHex('your_private_key'),
|
|
37
37
|
* arkServerUrl: 'https://ark.example.com',
|
|
38
38
|
* esploraUrl: 'https://mempool.space/api'
|
|
39
39
|
* });
|
|
40
40
|
*
|
|
41
|
+
* // Or with custom provider instances (e.g., for Expo/React Native)
|
|
42
|
+
* const wallet = await Wallet.create({
|
|
43
|
+
* identity: SingleKey.fromHex('your_private_key'),
|
|
44
|
+
* arkProvider: new ExpoArkProvider('https://ark.example.com'),
|
|
45
|
+
* indexerProvider: new ExpoIndexerProvider('https://ark.example.com'),
|
|
46
|
+
* esploraUrl: 'https://mempool.space/api'
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
41
49
|
* // Get addresses
|
|
42
50
|
* const arkAddress = await wallet.getAddress();
|
|
43
51
|
* const boardingAddress = await wallet.getBoardingAddress();
|
|
@@ -71,11 +79,29 @@ export class Wallet {
|
|
|
71
79
|
if (!pubkey) {
|
|
72
80
|
throw new Error("Invalid configured public key");
|
|
73
81
|
}
|
|
74
|
-
|
|
75
|
-
const
|
|
82
|
+
// Use provided arkProvider instance or create a new one from arkServerUrl
|
|
83
|
+
const arkProvider = config.arkProvider ||
|
|
84
|
+
(() => {
|
|
85
|
+
if (!config.arkServerUrl) {
|
|
86
|
+
throw new Error("Either arkProvider or arkServerUrl must be provided");
|
|
87
|
+
}
|
|
88
|
+
return new RestArkProvider(config.arkServerUrl);
|
|
89
|
+
})();
|
|
90
|
+
// Extract arkServerUrl from provider if not explicitly provided
|
|
91
|
+
const arkServerUrl = config.arkServerUrl || arkProvider.serverUrl;
|
|
92
|
+
if (!arkServerUrl) {
|
|
93
|
+
throw new Error("Could not determine arkServerUrl from provider");
|
|
94
|
+
}
|
|
95
|
+
// Use provided indexerProvider instance or create a new one
|
|
96
|
+
// indexerUrl defaults to arkServerUrl if not provided
|
|
97
|
+
const indexerUrl = config.indexerUrl || arkServerUrl;
|
|
98
|
+
const indexerProvider = config.indexerProvider || new RestIndexerProvider(indexerUrl);
|
|
76
99
|
const info = await arkProvider.getInfo();
|
|
77
100
|
const network = getNetwork(info.network);
|
|
78
|
-
|
|
101
|
+
// Extract esploraUrl from provider if not explicitly provided
|
|
102
|
+
const esploraUrl = config.esploraUrl || ESPLORA_URL[info.network];
|
|
103
|
+
// Use provided onchainProvider instance or create a new one
|
|
104
|
+
const onchainProvider = config.onchainProvider || new EsploraProvider(esploraUrl);
|
|
79
105
|
const exitTimelock = {
|
|
80
106
|
value: info.unilateralExitDelay,
|
|
81
107
|
type: info.unilateralExitDelay < 512n ? "blocks" : "seconds",
|
|
@@ -99,8 +125,14 @@ export class Wallet {
|
|
|
99
125
|
// Save tapscripts
|
|
100
126
|
const offchainTapscript = bareVtxoTapscript;
|
|
101
127
|
// the serverUnrollScript is the one used to create output scripts of the checkpoint transactions
|
|
102
|
-
|
|
103
|
-
|
|
128
|
+
let serverUnrollScript;
|
|
129
|
+
try {
|
|
130
|
+
const raw = hex.decode(info.checkpointExitClosure);
|
|
131
|
+
serverUnrollScript = CSVMultisigTapscript.decode(raw);
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
throw new Error("Invalid checkpointExitClosure from server");
|
|
135
|
+
}
|
|
104
136
|
// parse the server forfeit address
|
|
105
137
|
// server is expecting funds to be sent to this address
|
|
106
138
|
const forfeitAddress = Address(network).decode(info.forfeitAddress);
|
|
@@ -171,40 +203,24 @@ export class Wallet {
|
|
|
171
203
|
// if (cachedVtxos.length) return cachedVtxos;
|
|
172
204
|
// For now, always fetch fresh data from provider and update cache
|
|
173
205
|
// In future, we can add cache invalidation logic based on timestamps
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
const forfeit = this.offchainTapscript.forfeit();
|
|
177
|
-
const exit = this.offchainTapscript.exit();
|
|
178
|
-
const extendedVtxos = spendableVtxos.map((vtxo) => ({
|
|
179
|
-
...vtxo,
|
|
180
|
-
forfeitTapLeafScript: forfeit,
|
|
181
|
-
intentTapLeafScript: exit,
|
|
182
|
-
tapTree: encodedOffchainTapscript,
|
|
183
|
-
}));
|
|
206
|
+
const vtxos = await this.getVirtualCoins(filter);
|
|
207
|
+
const extendedVtxos = vtxos.map((vtxo) => extendVirtualCoin(this, vtxo));
|
|
184
208
|
// Update cache with fresh data
|
|
185
209
|
await this.walletRepository.saveVtxos(address, extendedVtxos);
|
|
186
210
|
return extendedVtxos;
|
|
187
211
|
}
|
|
188
212
|
async getVirtualCoins(filter = { withRecoverable: true, withUnrolled: false }) {
|
|
189
213
|
const scripts = [hex.encode(this.offchainTapscript.pkScript)];
|
|
190
|
-
const response = await this.indexerProvider.getVtxos({
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const response = await this.indexerProvider.getVtxos({
|
|
197
|
-
scripts,
|
|
198
|
-
recoverableOnly: true,
|
|
199
|
-
});
|
|
200
|
-
vtxos.push(...response.vtxos);
|
|
214
|
+
const response = await this.indexerProvider.getVtxos({ scripts });
|
|
215
|
+
const allVtxos = response.vtxos;
|
|
216
|
+
let vtxos = allVtxos.filter(isSpendable);
|
|
217
|
+
// all recoverable vtxos are spendable by definition
|
|
218
|
+
if (!filter.withRecoverable) {
|
|
219
|
+
vtxos = vtxos.filter((vtxo) => !isRecoverable(vtxo));
|
|
201
220
|
}
|
|
202
221
|
if (filter.withUnrolled) {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
spentOnly: true,
|
|
206
|
-
});
|
|
207
|
-
vtxos.push(...response.vtxos.filter((vtxo) => vtxo.isUnrolled));
|
|
222
|
+
const spentVtxos = allVtxos.filter((vtxo) => !isSpendable(vtxo));
|
|
223
|
+
vtxos.push(...spentVtxos.filter((vtxo) => vtxo.isUnrolled));
|
|
208
224
|
}
|
|
209
225
|
return vtxos;
|
|
210
226
|
}
|
|
@@ -242,10 +258,10 @@ export class Wallet {
|
|
|
242
258
|
return txs;
|
|
243
259
|
}
|
|
244
260
|
async getBoardingTxs() {
|
|
245
|
-
const boardingAddress = await this.getBoardingAddress();
|
|
246
|
-
const txs = await this.onchainProvider.getTransactions(boardingAddress);
|
|
247
261
|
const utxos = [];
|
|
248
262
|
const commitmentsToIgnore = new Set();
|
|
263
|
+
const boardingAddress = await this.getBoardingAddress();
|
|
264
|
+
const txs = await this.onchainProvider.getTransactions(boardingAddress);
|
|
249
265
|
for (const tx of txs) {
|
|
250
266
|
for (let i = 0; i < tx.vout.length; i++) {
|
|
251
267
|
const vout = tx.vout[i];
|
|
@@ -386,13 +402,15 @@ export class Wallet {
|
|
|
386
402
|
}
|
|
387
403
|
}
|
|
388
404
|
}
|
|
389
|
-
// if no params are provided, use all boarding and offchain
|
|
405
|
+
// if no params are provided, use all non expired boarding utxos and offchain vtxos as inputs
|
|
390
406
|
// and send all to the offchain address
|
|
391
407
|
if (!params) {
|
|
392
408
|
let amount = 0;
|
|
393
|
-
const
|
|
409
|
+
const exitScript = CSVMultisigTapscript.decode(hex.decode(this.boardingTapscript.exitScript));
|
|
410
|
+
const boardingTimelock = exitScript.params.timelock;
|
|
411
|
+
const boardingUtxos = (await this.getBoardingUtxos()).filter((utxo) => !hasBoardingTxExpired(utxo, boardingTimelock));
|
|
394
412
|
amount += boardingUtxos.reduce((sum, input) => sum + input.value, 0);
|
|
395
|
-
const vtxos = await this.getVtxos();
|
|
413
|
+
const vtxos = await this.getVtxos({ withRecoverable: true });
|
|
396
414
|
amount += vtxos.reduce((sum, input) => sum + input.value, 0);
|
|
397
415
|
const inputs = [...boardingUtxos, ...vtxos];
|
|
398
416
|
if (inputs.length === 0) {
|
|
@@ -602,22 +620,22 @@ export class Wallet {
|
|
|
602
620
|
let onchainStopFunc;
|
|
603
621
|
let indexerStopFunc;
|
|
604
622
|
if (this.onchainProvider && boardingAddress) {
|
|
623
|
+
const findVoutOnTx = (tx) => {
|
|
624
|
+
return tx.vout.findIndex((v) => v.scriptpubkey_address === boardingAddress);
|
|
625
|
+
};
|
|
605
626
|
onchainStopFunc = await this.onchainProvider.watchAddresses([boardingAddress], (txs) => {
|
|
627
|
+
// find all utxos belonging to our boarding address
|
|
606
628
|
const coins = txs
|
|
629
|
+
// filter txs where address is in output
|
|
630
|
+
.filter((tx) => findVoutOnTx(tx) !== -1)
|
|
631
|
+
// return utxo as Coin
|
|
607
632
|
.map((tx) => {
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
txid: tx.txid,
|
|
615
|
-
vout,
|
|
616
|
-
value: Number(tx.vout[vout].value),
|
|
617
|
-
status: tx.status,
|
|
618
|
-
};
|
|
619
|
-
})
|
|
620
|
-
.filter((coin) => coin !== null);
|
|
633
|
+
const { txid, status } = tx;
|
|
634
|
+
const vout = findVoutOnTx(tx);
|
|
635
|
+
const value = Number(tx.vout[vout].value);
|
|
636
|
+
return { txid, vout, value, status };
|
|
637
|
+
});
|
|
638
|
+
// and notify via callback
|
|
621
639
|
eventCallback({
|
|
622
640
|
type: "utxo",
|
|
623
641
|
coins,
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { ArkAddress } from "./script/address";
|
|
|
5
5
|
import { VHTLC } from "./script/vhtlc";
|
|
6
6
|
import { DefaultVtxo } from "./script/default";
|
|
7
7
|
import { VtxoScript, EncodedVtxoScript, TapLeafScript } from "./script/base";
|
|
8
|
-
import { TxType, IWallet, WalletConfig, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, Recipient, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, GetVtxosFilter, TapLeaves } from "./wallet";
|
|
8
|
+
import { TxType, IWallet, WalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, Recipient, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, GetVtxosFilter, TapLeaves } from "./wallet";
|
|
9
9
|
import { Wallet, waitForIncomingFunds, IncomingFunds } from "./wallet/wallet";
|
|
10
10
|
import { TxTree, TxTreeNode } from "./tree/txTree";
|
|
11
11
|
import { SignerSession, TreeNonces, TreePartialSigs } from "./tree/signingSession";
|
|
@@ -19,17 +19,17 @@ import { Response } from "./wallet/serviceWorker/response";
|
|
|
19
19
|
import { ESPLORA_URL, EsploraProvider, OnchainProvider, ExplorerTransaction } from "./providers/onchain";
|
|
20
20
|
import { RestArkProvider, ArkProvider, SettlementEvent, SettlementEventType, ArkInfo, Intent, Output, TxNotification, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesAggregatedEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, MarketHour } from "./providers/ark";
|
|
21
21
|
import { CLTVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CSVMultisigTapscript, decodeTapscript, MultisigTapscript, TapscriptType, ArkTapscript, RelativeTimelock } from "./script/tapscript";
|
|
22
|
-
import { buildOffchainTx, ArkTxInput, OffchainTx } from "./utils/arkTransaction";
|
|
22
|
+
import { hasBoardingTxExpired, buildOffchainTx, ArkTxInput, OffchainTx } from "./utils/arkTransaction";
|
|
23
23
|
import { VtxoTaprootTree, ConditionWitness, getArkPsbtFields, setArkPsbtField, ArkPsbtFieldCoder, ArkPsbtFieldKey, ArkPsbtFieldKeyType, CosignerPublicKey, VtxoTreeExpiry } from "./utils/unknownFields";
|
|
24
24
|
import { BIP322 } from "./bip322";
|
|
25
25
|
import { ArkNote } from "./arknote";
|
|
26
26
|
import { networks, Network, NetworkName } from "./networks";
|
|
27
|
-
import { RestIndexerProvider, IndexerProvider, IndexerTxType, ChainTxType, PageResponse, Batch, ChainTx, CommitmentTx, TxHistoryRecord, VtxoChain, Tx, Vtxo, PaginationOptions, SubscriptionResponse } from "./providers/indexer";
|
|
27
|
+
import { RestIndexerProvider, IndexerProvider, IndexerTxType, ChainTxType, PageResponse, Batch, ChainTx, CommitmentTx, TxHistoryRecord, VtxoChain, Tx, Vtxo, PaginationOptions, SubscriptionResponse, SubscriptionHeartbeat, SubscriptionEvent } from "./providers/indexer";
|
|
28
28
|
import { Nonces } from "./musig2/nonces";
|
|
29
29
|
import { PartialSig } from "./musig2/sign";
|
|
30
30
|
import { AnchorBumper, P2A } from "./utils/anchor";
|
|
31
31
|
import { Unroll } from "./wallet/unroll";
|
|
32
32
|
import { WalletRepositoryImpl } from "./repositories/walletRepository";
|
|
33
33
|
import { ContractRepositoryImpl } from "./repositories/contractRepository";
|
|
34
|
-
export { Wallet, SingleKey, OnchainWallet, Ramps, ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, Worker, ServiceWorkerWallet, Request, Response, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, waitForIncomingFunds, ArkNote, networks, WalletRepositoryImpl, ContractRepositoryImpl, BIP322, TxTree, P2A, Unroll, Transaction, };
|
|
35
|
-
export type { Identity, IWallet, WalletConfig, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, Recipient, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, IndexerProvider, PageResponse, Batch, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, ArkInfo, Intent, Output, TxNotification, ExplorerTransaction, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesAggregatedEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, MarketHour, PaginationOptions, SubscriptionResponse, Network, NetworkName, ArkTapscript, RelativeTimelock, EncodedVtxoScript, TapLeafScript, SignerSession, TreeNonces, TreePartialSigs, GetVtxosFilter, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, };
|
|
34
|
+
export { Wallet, SingleKey, OnchainWallet, Ramps, ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, Worker, ServiceWorkerWallet, Request, Response, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, waitForIncomingFunds, hasBoardingTxExpired, ArkNote, networks, WalletRepositoryImpl, ContractRepositoryImpl, BIP322, TxTree, P2A, Unroll, Transaction, };
|
|
35
|
+
export type { Identity, IWallet, WalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, Recipient, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, IndexerProvider, PageResponse, Batch, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, ArkInfo, Intent, Output, TxNotification, ExplorerTransaction, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesAggregatedEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, MarketHour, PaginationOptions, SubscriptionResponse, SubscriptionHeartbeat, SubscriptionEvent, Network, NetworkName, ArkTapscript, RelativeTimelock, EncodedVtxoScript, TapLeafScript, SignerSession, TreeNonces, TreePartialSigs, GetVtxosFilter, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, };
|
|
@@ -150,7 +150,141 @@ export declare class RestArkProvider implements ArkProvider {
|
|
|
150
150
|
commitmentTx?: TxNotification;
|
|
151
151
|
arkTx?: TxNotification;
|
|
152
152
|
}>;
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
protected parseSettlementEvent(data: ProtoTypes.GetEventStreamResponse): SettlementEvent | null;
|
|
154
|
+
protected parseTransactionNotification(data: ProtoTypes.GetTransactionsStreamResponse): {
|
|
155
|
+
commitmentTx?: TxNotification;
|
|
156
|
+
arkTx?: TxNotification;
|
|
157
|
+
} | null;
|
|
158
|
+
}
|
|
159
|
+
declare namespace ProtoTypes {
|
|
160
|
+
interface BatchStartedEvent {
|
|
161
|
+
id: string;
|
|
162
|
+
intentIdHashes: string[];
|
|
163
|
+
batchExpiry: number;
|
|
164
|
+
}
|
|
165
|
+
interface BatchFailed {
|
|
166
|
+
id: string;
|
|
167
|
+
reason: string;
|
|
168
|
+
}
|
|
169
|
+
export interface BatchFinalizationEvent {
|
|
170
|
+
id: string;
|
|
171
|
+
commitmentTx: string;
|
|
172
|
+
}
|
|
173
|
+
interface BatchFinalizedEvent {
|
|
174
|
+
id: string;
|
|
175
|
+
commitmentTxid: string;
|
|
176
|
+
}
|
|
177
|
+
interface TreeSigningStartedEvent {
|
|
178
|
+
id: string;
|
|
179
|
+
cosignersPubkeys: string[];
|
|
180
|
+
unsignedCommitmentTx: string;
|
|
181
|
+
}
|
|
182
|
+
interface TreeNoncesAggregatedEvent {
|
|
183
|
+
id: string;
|
|
184
|
+
treeNonces: string;
|
|
185
|
+
}
|
|
186
|
+
interface TreeTxEvent {
|
|
187
|
+
id: string;
|
|
188
|
+
topic: string[];
|
|
189
|
+
batchIndex: number;
|
|
190
|
+
txid: string;
|
|
191
|
+
tx: string;
|
|
192
|
+
children: Record<string, string>;
|
|
193
|
+
}
|
|
194
|
+
interface TreeSignatureEvent {
|
|
195
|
+
id: string;
|
|
196
|
+
topic: string[];
|
|
197
|
+
batchIndex: number;
|
|
198
|
+
txid: string;
|
|
199
|
+
signature: string;
|
|
200
|
+
}
|
|
201
|
+
interface Heartbeat {
|
|
202
|
+
}
|
|
203
|
+
export interface VtxoData {
|
|
204
|
+
outpoint: {
|
|
205
|
+
txid: string;
|
|
206
|
+
vout: number;
|
|
207
|
+
};
|
|
208
|
+
amount: string;
|
|
209
|
+
script: string;
|
|
210
|
+
createdAt: string;
|
|
211
|
+
expiresAt: string | null;
|
|
212
|
+
commitmentTxids: string[];
|
|
213
|
+
isPreconfirmed: boolean;
|
|
214
|
+
isSwept: boolean;
|
|
215
|
+
isUnrolled: boolean;
|
|
216
|
+
isSpent: boolean;
|
|
217
|
+
spentBy: string;
|
|
218
|
+
settledBy?: string;
|
|
219
|
+
arkTxid?: string;
|
|
220
|
+
}
|
|
221
|
+
export interface GetEventStreamResponse {
|
|
222
|
+
batchStarted?: BatchStartedEvent;
|
|
223
|
+
batchFailed?: BatchFailed;
|
|
224
|
+
batchFinalization?: BatchFinalizationEvent;
|
|
225
|
+
batchFinalized?: BatchFinalizedEvent;
|
|
226
|
+
treeSigningStarted?: TreeSigningStartedEvent;
|
|
227
|
+
treeNoncesAggregated?: TreeNoncesAggregatedEvent;
|
|
228
|
+
treeTx?: TreeTxEvent;
|
|
229
|
+
treeSignature?: TreeSignatureEvent;
|
|
230
|
+
heartbeat?: Heartbeat;
|
|
231
|
+
}
|
|
232
|
+
export interface GetTransactionsStreamResponse {
|
|
233
|
+
commitmentTx?: {
|
|
234
|
+
txid: string;
|
|
235
|
+
tx: string;
|
|
236
|
+
spentVtxos: VtxoData[];
|
|
237
|
+
spendableVtxos: VtxoData[];
|
|
238
|
+
checkpointTxs?: Record<string, {
|
|
239
|
+
txid: string;
|
|
240
|
+
tx: string;
|
|
241
|
+
}>;
|
|
242
|
+
};
|
|
243
|
+
arkTx?: {
|
|
244
|
+
txid: string;
|
|
245
|
+
tx: string;
|
|
246
|
+
spentVtxos: VtxoData[];
|
|
247
|
+
spendableVtxos: VtxoData[];
|
|
248
|
+
checkpointTxs?: Record<string, {
|
|
249
|
+
txid: string;
|
|
250
|
+
tx: string;
|
|
251
|
+
}>;
|
|
252
|
+
};
|
|
253
|
+
heartbeat?: Heartbeat;
|
|
254
|
+
}
|
|
255
|
+
export interface EventData {
|
|
256
|
+
batchStarted?: BatchStartedEvent;
|
|
257
|
+
batchFailed?: BatchFailed;
|
|
258
|
+
batchFinalization?: BatchFinalizationEvent;
|
|
259
|
+
batchFinalized?: BatchFinalizedEvent;
|
|
260
|
+
treeSigningStarted?: TreeSigningStartedEvent;
|
|
261
|
+
treeNoncesAggregated?: TreeNoncesAggregatedEvent;
|
|
262
|
+
treeTx?: TreeTxEvent;
|
|
263
|
+
treeSignature?: TreeSignatureEvent;
|
|
264
|
+
}
|
|
265
|
+
export interface TransactionData {
|
|
266
|
+
commitmentTx?: {
|
|
267
|
+
txid: string;
|
|
268
|
+
tx: string;
|
|
269
|
+
spentVtxos: VtxoData[];
|
|
270
|
+
spendableVtxos: VtxoData[];
|
|
271
|
+
checkpointTxs?: Record<string, {
|
|
272
|
+
txid: string;
|
|
273
|
+
tx: string;
|
|
274
|
+
}>;
|
|
275
|
+
};
|
|
276
|
+
arkTx?: {
|
|
277
|
+
txid: string;
|
|
278
|
+
tx: string;
|
|
279
|
+
spentVtxos: VtxoData[];
|
|
280
|
+
spendableVtxos: VtxoData[];
|
|
281
|
+
checkpointTxs?: Record<string, {
|
|
282
|
+
txid: string;
|
|
283
|
+
tx: string;
|
|
284
|
+
}>;
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
export {};
|
|
155
288
|
}
|
|
156
289
|
export declare function isFetchTimeoutError(err: any): boolean;
|
|
290
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RestArkProvider, SettlementEvent, TxNotification } from "./ark";
|
|
2
|
+
/**
|
|
3
|
+
* Expo-compatible Ark provider implementation using expo/fetch for SSE support.
|
|
4
|
+
* This provider works specifically in React Native/Expo environments where
|
|
5
|
+
* standard EventSource is not available but expo/fetch provides SSE capabilities.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { ExpoArkProvider } from '@arkade-os/sdk/providers/expo';
|
|
10
|
+
*
|
|
11
|
+
* const provider = new ExpoArkProvider('https://ark.example.com');
|
|
12
|
+
* const info = await provider.getInfo();
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare class ExpoArkProvider extends RestArkProvider {
|
|
16
|
+
constructor(serverUrl: string);
|
|
17
|
+
getEventStream(signal: AbortSignal, topics: string[]): AsyncIterableIterator<SettlementEvent>;
|
|
18
|
+
getTransactionsStream(signal: AbortSignal): AsyncIterableIterator<{
|
|
19
|
+
commitmentTx?: TxNotification;
|
|
20
|
+
arkTx?: TxNotification;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { RestIndexerProvider } from "./indexer";
|
|
2
|
+
/**
|
|
3
|
+
* Expo-compatible Indexer provider implementation using expo/fetch for streaming support.
|
|
4
|
+
* This provider works specifically in React Native/Expo environments where
|
|
5
|
+
* standard fetch streaming may not work properly but expo/fetch provides streaming capabilities.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { ExpoIndexerProvider } from '@arkade-os/sdk/adapters/expo';
|
|
10
|
+
*
|
|
11
|
+
* const provider = new ExpoIndexerProvider('https://indexer.example.com');
|
|
12
|
+
* const vtxos = await provider.getVtxos({ scripts: ['script1'] });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare class ExpoIndexerProvider extends RestIndexerProvider {
|
|
16
|
+
constructor(serverUrl: string);
|
|
17
|
+
getSubscription(subscriptionId: string, abortSignal: AbortSignal): AsyncGenerator<{
|
|
18
|
+
txid: any;
|
|
19
|
+
scripts: any;
|
|
20
|
+
newVtxos: any;
|
|
21
|
+
spentVtxos: any;
|
|
22
|
+
sweptVtxos: any;
|
|
23
|
+
tx: any;
|
|
24
|
+
checkpointTxs: any;
|
|
25
|
+
}, void, unknown>;
|
|
26
|
+
}
|
|
@@ -80,12 +80,19 @@ export interface SubscriptionResponse {
|
|
|
80
80
|
scripts: string[];
|
|
81
81
|
newVtxos: VirtualCoin[];
|
|
82
82
|
spentVtxos: VirtualCoin[];
|
|
83
|
+
sweptVtxos: VirtualCoin[];
|
|
83
84
|
tx?: string;
|
|
84
85
|
checkpointTxs?: Record<string, {
|
|
85
86
|
txid: string;
|
|
86
87
|
tx: string;
|
|
87
88
|
}>;
|
|
88
89
|
}
|
|
90
|
+
export interface SubscriptionHeartbeat {
|
|
91
|
+
type: "heartbeat";
|
|
92
|
+
}
|
|
93
|
+
export interface SubscriptionEvent extends SubscriptionResponse {
|
|
94
|
+
type: "event";
|
|
95
|
+
}
|
|
89
96
|
export interface IndexerProvider {
|
|
90
97
|
getVtxoTree(batchOutpoint: Outpoint, opts?: PaginationOptions): Promise<{
|
|
91
98
|
vtxoTree: Tx[];
|
|
@@ -163,6 +170,7 @@ export declare class RestIndexerProvider implements IndexerProvider {
|
|
|
163
170
|
scripts: any;
|
|
164
171
|
newVtxos: any;
|
|
165
172
|
spentVtxos: any;
|
|
173
|
+
sweptVtxos: any;
|
|
166
174
|
tx: any;
|
|
167
175
|
checkpointTxs: any;
|
|
168
176
|
}, void, unknown>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Transaction } from "@scure/btc-signer/transaction.js";
|
|
2
|
-
import { VirtualCoin } from "../wallet";
|
|
2
|
+
import { ExtendedCoin, VirtualCoin } from "../wallet";
|
|
3
|
+
import { RelativeTimelock } from "../script/tapscript";
|
|
3
4
|
import { EncodedVtxoScript, TapLeafScript } from "../script/base";
|
|
4
5
|
import { CSVMultisigTapscript } from "../script/tapscript";
|
|
5
6
|
import { TransactionOutput } from "@scure/btc-signer/psbt.js";
|
|
@@ -25,3 +26,4 @@ export type OffchainTx = {
|
|
|
25
26
|
* @returns Object containing the virtual transaction and checkpoint transactions
|
|
26
27
|
*/
|
|
27
28
|
export declare function buildOffchainTx(inputs: ArkTxInput[], outputs: TransactionOutput[], serverUnrollScript: CSVMultisigTapscript.Type): OffchainTx;
|
|
29
|
+
export declare function hasBoardingTxExpired(coin: ExtendedCoin, boardingTimelock: RelativeTimelock): boolean;
|