@arkade-os/sdk 0.3.0-alpha.6 → 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/script/base.js +16 -95
- 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/script/base.js +13 -92
- 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
|
@@ -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;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { Output, SettlementEvent } from "../providers/ark";
|
|
1
|
+
import { Output, SettlementEvent, ArkProvider } from "../providers/ark";
|
|
2
|
+
import { IndexerProvider } from "../providers/indexer";
|
|
3
|
+
import { OnchainProvider } from "../providers/onchain";
|
|
2
4
|
import { Identity } from "../identity";
|
|
3
5
|
import { RelativeTimelock } from "../script/tapscript";
|
|
4
6
|
import { EncodedVtxoScript, TapLeafScript } from "../script/base";
|
|
@@ -7,19 +9,54 @@ import { StorageAdapter } from "../storage";
|
|
|
7
9
|
/**
|
|
8
10
|
* Configuration options for wallet initialization.
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Supports two configuration modes:
|
|
13
|
+
* 1. URL-based: Provide arkServerUrl, indexerUrl (optional), and esploraUrl
|
|
14
|
+
* 2. Provider-based: Provide arkProvider, indexerProvider, and onchainProvider instances
|
|
15
|
+
*
|
|
16
|
+
* At least one of the following must be provided:
|
|
17
|
+
* - arkServerUrl OR arkProvider
|
|
18
|
+
*
|
|
19
|
+
* The wallet will use provided URLs to create default providers if custom provider
|
|
20
|
+
* instances are not supplied. If optional parameters are not provided, the wallet
|
|
21
|
+
* will fetch configuration from the Ark server.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // URL-based configuration
|
|
26
|
+
* const wallet = await Wallet.create({
|
|
27
|
+
* identity: SingleKey.fromHex('...'),
|
|
28
|
+
* arkServerUrl: 'https://ark.example.com',
|
|
29
|
+
* esploraUrl: 'https://mempool.space/api'
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Provider-based configuration (e.g., for Expo/React Native)
|
|
33
|
+
* const wallet = await Wallet.create({
|
|
34
|
+
* identity: SingleKey.fromHex('...'),
|
|
35
|
+
* arkProvider: new ExpoArkProvider('https://ark.example.com'),
|
|
36
|
+
* indexerProvider: new ExpoIndexerProvider('https://ark.example.com'),
|
|
37
|
+
* onchainProvider: new EsploraProvider('https://mempool.space/api')
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
14
40
|
*/
|
|
15
41
|
export interface WalletConfig {
|
|
16
42
|
identity: Identity;
|
|
17
|
-
arkServerUrl
|
|
43
|
+
arkServerUrl?: string;
|
|
44
|
+
indexerUrl?: string;
|
|
18
45
|
esploraUrl?: string;
|
|
19
46
|
arkServerPublicKey?: string;
|
|
20
47
|
boardingTimelock?: RelativeTimelock;
|
|
21
48
|
exitTimelock?: RelativeTimelock;
|
|
22
49
|
storage?: StorageAdapter;
|
|
50
|
+
arkProvider?: ArkProvider;
|
|
51
|
+
indexerProvider?: IndexerProvider;
|
|
52
|
+
onchainProvider?: OnchainProvider;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Provider class constructor interface for dependency injection.
|
|
56
|
+
* Ensures provider classes follow the consistent constructor pattern.
|
|
57
|
+
*/
|
|
58
|
+
export interface ProviderClass<T> {
|
|
59
|
+
new (serverUrl: string): T;
|
|
23
60
|
}
|
|
24
61
|
export interface WalletBalance {
|
|
25
62
|
boarding: {
|
|
@@ -73,6 +110,7 @@ export interface VirtualCoin extends Coin {
|
|
|
73
110
|
arkTxId?: string;
|
|
74
111
|
createdAt: Date;
|
|
75
112
|
isUnrolled: boolean;
|
|
113
|
+
isSpent?: boolean;
|
|
76
114
|
}
|
|
77
115
|
export declare enum TxType {
|
|
78
116
|
TxSent = "SENT",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ExtendedVirtualCoin, VirtualCoin, Wallet } from "../..";
|
|
2
1
|
/**
|
|
3
2
|
* setupServiceWorker sets up the service worker.
|
|
4
3
|
* @param path - the path to the service worker script
|
|
@@ -8,4 +7,3 @@ import { ExtendedVirtualCoin, VirtualCoin, Wallet } from "../..";
|
|
|
8
7
|
* ```
|
|
9
8
|
*/
|
|
10
9
|
export declare function setupServiceWorker(path: string): Promise<ServiceWorker>;
|
|
11
|
-
export declare function extendVirtualCoin(wallet: Wallet, vtxo: VirtualCoin): ExtendedVirtualCoin;
|
|
@@ -25,13 +25,21 @@ export type IncomingFunds = {
|
|
|
25
25
|
*
|
|
26
26
|
* @example
|
|
27
27
|
* ```typescript
|
|
28
|
-
* // Create a wallet
|
|
28
|
+
* // Create a wallet with URL configuration
|
|
29
29
|
* const wallet = await Wallet.create({
|
|
30
30
|
* identity: SingleKey.fromHex('your_private_key'),
|
|
31
31
|
* arkServerUrl: 'https://ark.example.com',
|
|
32
32
|
* esploraUrl: 'https://mempool.space/api'
|
|
33
33
|
* });
|
|
34
34
|
*
|
|
35
|
+
* // Or with custom provider instances (e.g., for Expo/React Native)
|
|
36
|
+
* const wallet = await Wallet.create({
|
|
37
|
+
* identity: SingleKey.fromHex('your_private_key'),
|
|
38
|
+
* arkProvider: new ExpoArkProvider('https://ark.example.com'),
|
|
39
|
+
* indexerProvider: new ExpoIndexerProvider('https://ark.example.com'),
|
|
40
|
+
* esploraUrl: 'https://mempool.space/api'
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
35
43
|
* // Get addresses
|
|
36
44
|
* const arkAddress = await wallet.getAddress();
|
|
37
45
|
* const boardingAddress = await wallet.getBoardingAddress();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arkade-os/sdk",
|
|
3
|
-
"version": "0.3.0-alpha.
|
|
3
|
+
"version": "0.3.0-alpha.8",
|
|
4
4
|
"description": "Bitcoin wallet SDK with Taproot and Ark integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -14,6 +14,12 @@
|
|
|
14
14
|
"require": "./dist/cjs/index.js",
|
|
15
15
|
"default": "./dist/esm/index.js"
|
|
16
16
|
},
|
|
17
|
+
"./adapters/expo": {
|
|
18
|
+
"types": "./dist/types/adapters/expo.d.ts",
|
|
19
|
+
"import": "./dist/esm/adapters/expo.js",
|
|
20
|
+
"require": "./dist/cjs/adapters/expo.js",
|
|
21
|
+
"default": "./dist/esm/adapters/expo.js"
|
|
22
|
+
},
|
|
17
23
|
"./adapters/localStorage": {
|
|
18
24
|
"types": "./dist/types/adapters/localStorage.d.ts",
|
|
19
25
|
"import": "./dist/esm/adapters/localStorage.js",
|
|
@@ -58,6 +64,7 @@
|
|
|
58
64
|
"@types/node": "24.3.1",
|
|
59
65
|
"@vitest/coverage-v8": "3.2.4",
|
|
60
66
|
"esbuild": "^0.25.9",
|
|
67
|
+
"expo": "~52.0.47",
|
|
61
68
|
"eventsource": "4.0.0",
|
|
62
69
|
"glob": "11.0.3",
|
|
63
70
|
"husky": "9.1.7",
|
|
@@ -78,7 +85,7 @@
|
|
|
78
85
|
"author": "Ark Labs",
|
|
79
86
|
"license": "MIT",
|
|
80
87
|
"engines": {
|
|
81
|
-
"node": "
|
|
88
|
+
"node": ">=20.0.0"
|
|
82
89
|
},
|
|
83
90
|
"scripts": {
|
|
84
91
|
"build": "rimraf dist && pnpm run build:esm && node scripts/add-extensions.js && pnpm run build:cjs && pnpm run build:types && node scripts/generate-package-files.js",
|
|
@@ -101,6 +108,8 @@
|
|
|
101
108
|
"test:watch": "vitest",
|
|
102
109
|
"test:coverage": "vitest run --coverage",
|
|
103
110
|
"test:sw": "pnpm run build:browser && node test/serviceWorker/serve.js",
|
|
111
|
+
"expo:web:install": "cd examples/expo-demo && pnpm install",
|
|
112
|
+
"expo:web": "cd examples/expo-demo && pnpm start",
|
|
104
113
|
"format": "prettier --write src test examples",
|
|
105
114
|
"lint": "prettier --check src test examples",
|
|
106
115
|
"audit": "pnpm audit",
|