@arkade-os/sdk 0.4.44 → 0.4.46
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 +35 -0
- package/dist/adapters/expo.cjs +5 -5
- package/dist/adapters/expo.d.cts +2 -2
- package/dist/adapters/expo.d.ts +2 -2
- package/dist/adapters/expo.js +3 -3
- package/dist/adapters/indexedDB.cjs +5 -5
- package/dist/adapters/indexedDB.js +4 -4
- package/dist/{ark-I8jfe5VE.d.cts → ark-C9ognsOV.d.cts} +94 -2
- package/dist/{ark-I8jfe5VE.d.ts → ark-C9ognsOV.d.ts} +94 -2
- package/dist/{asyncStorageTaskQueue-BtSOVZFn.d.ts → asyncStorageTaskQueue-BAKZ5cS5.d.ts} +2 -2
- package/dist/{asyncStorageTaskQueue-Dap7qUlF.d.cts → asyncStorageTaskQueue-CmBYVlxw.d.cts} +2 -2
- package/dist/{chunk-32YKLQPS.cjs → chunk-4KXOCVXP.cjs} +32 -29
- package/dist/chunk-4KXOCVXP.cjs.map +1 -0
- package/dist/{chunk-RJ6XVCX4.cjs → chunk-6TQJOD72.cjs} +7 -7
- package/dist/{chunk-RJ6XVCX4.cjs.map → chunk-6TQJOD72.cjs.map} +1 -1
- package/dist/{chunk-UBYY2TPK.cjs → chunk-7IYIFMF4.cjs} +178 -79
- package/dist/chunk-7IYIFMF4.cjs.map +1 -0
- package/dist/{chunk-LJ35HPJW.js → chunk-CWJ7ZCP7.js} +171 -75
- package/dist/chunk-CWJ7ZCP7.js.map +1 -0
- package/dist/{chunk-XIVCG6EP.cjs → chunk-D46YDM36.cjs} +1173 -425
- package/dist/chunk-D46YDM36.cjs.map +1 -0
- package/dist/{chunk-BE5MUB7T.js → chunk-FWG4TSPN.js} +7 -2
- package/dist/chunk-FWG4TSPN.js.map +1 -0
- package/dist/{chunk-V7WIZR2B.js → chunk-JTCQ6QXQ.js} +4 -4
- package/dist/{chunk-V7WIZR2B.js.map → chunk-JTCQ6QXQ.js.map} +1 -1
- package/dist/{chunk-HXDZ2QTW.cjs → chunk-MQB5H4X5.cjs} +7 -2
- package/dist/chunk-MQB5H4X5.cjs.map +1 -0
- package/dist/{chunk-FMI2GKYO.js → chunk-P6VBP3CT.js} +977 -231
- package/dist/chunk-P6VBP3CT.js.map +1 -0
- package/dist/{chunk-YNEDJTX2.js → chunk-QKC2T54O.js} +6 -3
- package/dist/chunk-QKC2T54O.js.map +1 -0
- package/dist/{chunk-LCQQPOIT.js → chunk-R2SVAM5Q.js} +3 -3
- package/dist/{chunk-LCQQPOIT.js.map → chunk-R2SVAM5Q.js.map} +1 -1
- package/dist/{chunk-X37EKDIH.cjs → chunk-SOXGAA52.cjs} +14 -14
- package/dist/{chunk-X37EKDIH.cjs.map → chunk-SOXGAA52.cjs.map} +1 -1
- package/dist/contracts/handlers/index.cjs +7 -7
- package/dist/contracts/handlers/index.d.cts +3 -3
- package/dist/contracts/handlers/index.d.ts +3 -3
- package/dist/contracts/handlers/index.js +2 -2
- package/dist/{delegate-BRqbh2fW.d.cts → delegate-DVEgyRwI.d.cts} +1 -1
- package/dist/{delegate-CgjVjYOP.d.ts → delegate-aOd5qINr.d.ts} +1 -1
- package/dist/{index-DvWNB_rl.d.ts → index-CPzL4tqg.d.ts} +2 -2
- package/dist/{index-DHuXlDEg.d.cts → index-D8vmtWWO.d.cts} +2 -2
- package/dist/index.cjs +176 -156
- package/dist/index.d.cts +45 -20
- package/dist/index.d.ts +45 -20
- package/dist/index.js +4 -4
- package/dist/repositories/realm/index.cjs +23 -19
- package/dist/repositories/realm/index.cjs.map +1 -1
- package/dist/repositories/realm/index.d.cts +2 -2
- package/dist/repositories/realm/index.d.ts +2 -2
- package/dist/repositories/realm/index.js +9 -5
- package/dist/repositories/realm/index.js.map +1 -1
- package/dist/repositories/sqlite/index.cjs +22 -18
- package/dist/repositories/sqlite/index.cjs.map +1 -1
- package/dist/repositories/sqlite/index.d.cts +2 -2
- package/dist/repositories/sqlite/index.d.ts +2 -2
- package/dist/repositories/sqlite/index.js +9 -5
- package/dist/repositories/sqlite/index.js.map +1 -1
- package/dist/{taskRunner-Bptw9UMa.d.ts → taskRunner-B48-V-Pb.d.ts} +2 -2
- package/dist/{taskRunner-CeFxKhSH.d.cts → taskRunner-nNecmQ2C.d.cts} +2 -2
- package/dist/wallet/expo/background.cjs +14 -14
- package/dist/wallet/expo/background.d.cts +3 -3
- package/dist/wallet/expo/background.d.ts +3 -3
- package/dist/wallet/expo/background.js +6 -6
- package/dist/wallet/expo/index.cjs +27 -14
- package/dist/wallet/expo/index.cjs.map +1 -1
- package/dist/wallet/expo/index.d.cts +11 -4
- package/dist/wallet/expo/index.d.ts +11 -4
- package/dist/wallet/expo/index.js +18 -5
- package/dist/wallet/expo/index.js.map +1 -1
- package/dist/{wallet-BsqRU8KM.d.cts → wallet-BUg3D4WJ.d.cts} +139 -3
- package/dist/{wallet-D9z7wssl.d.ts → wallet-DM0oShTu.d.ts} +139 -3
- package/dist/worker/expo/index.cjs +10 -9
- package/dist/worker/expo/index.cjs.map +1 -1
- package/dist/worker/expo/index.d.cts +4 -4
- package/dist/worker/expo/index.d.ts +4 -4
- package/dist/worker/expo/index.js +6 -5
- package/dist/worker/expo/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-32YKLQPS.cjs.map +0 -1
- package/dist/chunk-BE5MUB7T.js.map +0 -1
- package/dist/chunk-FMI2GKYO.js.map +0 -1
- package/dist/chunk-HXDZ2QTW.cjs.map +0 -1
- package/dist/chunk-LJ35HPJW.js.map +0 -1
- package/dist/chunk-UBYY2TPK.cjs.map +0 -1
- package/dist/chunk-XIVCG6EP.cjs.map +0 -1
- package/dist/chunk-YNEDJTX2.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { craftToSpendTx, Transaction, OP_RETURN_EMPTY_PKSCRIPT, baseFetch, Intent, getArkPsbtFields, CosignerPublicKey, setArkPsbtField, VtxoTaprootTree, maybeArkError, AssetRef, AssetId, AssetOutput, AssetGroup, AssetInput, Packet, Metadata, isEventSourceError, RestArkProvider, RestIndexerProvider, ArkError, BufferReader } from './chunk-
|
|
2
|
-
import { contractHandlers, isMainnetDescriptor, descriptorIsOurs, DEFAULT_PAGE_SIZE, DelegateVtxo, WALLET_RECEIVE_SOURCE, deriveDescriptorLeafPubKey, DefaultVtxo, BoardingContractHandler } from './chunk-
|
|
3
|
-
import { VtxoScript, sequenceToTimelock, timelockToSequence, DEFAULT_NETWORK, DEFAULT_NETWORK_NAME, decodeTapscript, scriptFromTapLeafScript, CLTVMultisigTapscript, ArkAddress, CSVMultisigTapscript, getSequence, getNetwork, MultisigTapscript, networks as networks$1, DEFAULT_ARKADE_SERVER_URL } from './chunk-
|
|
1
|
+
import { craftToSpendTx, Transaction, OP_RETURN_EMPTY_PKSCRIPT, baseFetch, Intent, getArkPsbtFields, CosignerPublicKey, setArkPsbtField, VtxoTaprootTree, maybeArkError, isArkError, ArkErrorName, ProviderUnavailableError, FetchError, isFetchTimeoutError, AssetRef, AssetId, AssetOutput, AssetGroup, AssetInput, Packet, Metadata, isEventSourceError, RestArkProvider, RestIndexerProvider, ArkError, BufferReader } from './chunk-CWJ7ZCP7.js';
|
|
2
|
+
import { contractHandlers, isMainnetDescriptor, descriptorIsOurs, DEFAULT_PAGE_SIZE, DelegateVtxo, WALLET_RECEIVE_SOURCE, deriveDescriptorLeafPubKey, DefaultVtxo, BoardingContractHandler } from './chunk-QKC2T54O.js';
|
|
3
|
+
import { VtxoScript, sequenceToTimelock, timelockToSequence, DEFAULT_NETWORK, DEFAULT_NETWORK_NAME, decodeTapscript, scriptFromTapLeafScript, CLTVMultisigTapscript, ArkAddress, CSVMultisigTapscript, getSequence, getNetwork, MultisigTapscript, networks as networks$1, DEFAULT_ARKADE_SERVER_URL } from './chunk-FWG4TSPN.js';
|
|
4
4
|
import { sha256, hash160, sha256x2, concatBytes, randomPrivateKeyBytes, pubECDSA, pubSchnorr, equalBytes as equalBytes$1 } from '@scure/btc-signer/utils.js';
|
|
5
5
|
import { SigHash, Script, p2tr, RawWitness, Address, OutScript, p2wpkh, TaprootControlBlock, DEFAULT_SEQUENCE, Transaction as Transaction$2 } from '@scure/btc-signer';
|
|
6
6
|
import { hex, base58, base64 } from '@scure/base';
|
|
@@ -62,6 +62,8 @@ var PartialSig = class _PartialSig {
|
|
|
62
62
|
throw new PartialSignatureError("Invalid R length");
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
+
s;
|
|
66
|
+
R;
|
|
65
67
|
/**
|
|
66
68
|
* Encodes the partial signature into bytes
|
|
67
69
|
* Returns a 32-byte array containing just the s value
|
|
@@ -111,6 +113,7 @@ var TreeSignerSession = class _TreeSignerSession {
|
|
|
111
113
|
constructor(secretKey) {
|
|
112
114
|
this.secretKey = secretKey;
|
|
113
115
|
}
|
|
116
|
+
secretKey;
|
|
114
117
|
static NOT_INITIALIZED = new Error("session not initialized, call init method");
|
|
115
118
|
myNonces = null;
|
|
116
119
|
aggregateNonces = null;
|
|
@@ -337,6 +340,7 @@ var ReadonlySingleKey = class _ReadonlySingleKey {
|
|
|
337
340
|
throw new Error("Invalid public key length");
|
|
338
341
|
}
|
|
339
342
|
}
|
|
343
|
+
publicKey;
|
|
340
344
|
/**
|
|
341
345
|
* Create a ReadonlySingleKey from a compressed public key.
|
|
342
346
|
*
|
|
@@ -948,6 +952,7 @@ var RestDelegateProvider = class {
|
|
|
948
952
|
constructor(url) {
|
|
949
953
|
this.url = url;
|
|
950
954
|
}
|
|
955
|
+
url;
|
|
951
956
|
/**
|
|
952
957
|
* Submit a delegation request to the remote delegation service.
|
|
953
958
|
*
|
|
@@ -1017,6 +1022,7 @@ var EsploraProvider = class {
|
|
|
1017
1022
|
this.pollingInterval = opts?.pollingInterval ?? 15e3;
|
|
1018
1023
|
this.forcePolling = opts?.forcePolling ?? false;
|
|
1019
1024
|
}
|
|
1025
|
+
baseUrl;
|
|
1020
1026
|
pollingInterval;
|
|
1021
1027
|
forcePolling;
|
|
1022
1028
|
async getCoins(address) {
|
|
@@ -1496,6 +1502,8 @@ var UnknownPacket = class {
|
|
|
1496
1502
|
this.packetType = packetType;
|
|
1497
1503
|
this.data = data;
|
|
1498
1504
|
}
|
|
1505
|
+
packetType;
|
|
1506
|
+
data;
|
|
1499
1507
|
type() {
|
|
1500
1508
|
return this.packetType;
|
|
1501
1509
|
}
|
|
@@ -1516,6 +1524,7 @@ var Extension = class _Extension {
|
|
|
1516
1524
|
constructor(packets) {
|
|
1517
1525
|
this.packets = packets;
|
|
1518
1526
|
}
|
|
1527
|
+
packets;
|
|
1519
1528
|
static create(packets) {
|
|
1520
1529
|
if (packets.length === 0) {
|
|
1521
1530
|
throw new Error("missing packets");
|
|
@@ -1954,6 +1963,7 @@ function isExpired(vtxo) {
|
|
|
1954
1963
|
return expiry <= Date.now();
|
|
1955
1964
|
}
|
|
1956
1965
|
function isSubdust(vtxo, dust) {
|
|
1966
|
+
if (typeof vtxo === "bigint") return vtxo < dust;
|
|
1957
1967
|
return vtxo.value < dust;
|
|
1958
1968
|
}
|
|
1959
1969
|
|
|
@@ -2312,6 +2322,7 @@ var FeeAmount = class _FeeAmount {
|
|
|
2312
2322
|
constructor(value) {
|
|
2313
2323
|
this.value = value;
|
|
2314
2324
|
}
|
|
2325
|
+
value;
|
|
2315
2326
|
static ZERO = new _FeeAmount(0);
|
|
2316
2327
|
/** Returns the fee amount rounded up to whole satoshis. */
|
|
2317
2328
|
get satoshis() {
|
|
@@ -2336,6 +2347,7 @@ var Estimator = class {
|
|
|
2336
2347
|
this.intentOffchainOutput = config.offchainOutput ? parseProgram(config.offchainOutput, IntentOutputEnv) : void 0;
|
|
2337
2348
|
this.intentOnchainOutput = config.onchainOutput ? parseProgram(config.onchainOutput, IntentOutputEnv) : void 0;
|
|
2338
2349
|
}
|
|
2350
|
+
config;
|
|
2339
2351
|
intentOffchainInput;
|
|
2340
2352
|
intentOnchainInput;
|
|
2341
2353
|
intentOffchainOutput;
|
|
@@ -2738,6 +2750,8 @@ var VtxoManager = class _VtxoManager {
|
|
|
2738
2750
|
}
|
|
2739
2751
|
this.contractEventsSubscriptionReady = this.initializeSubscription();
|
|
2740
2752
|
}
|
|
2753
|
+
wallet;
|
|
2754
|
+
renewalConfig;
|
|
2741
2755
|
settlementConfig;
|
|
2742
2756
|
contractEventsSubscriptionReady;
|
|
2743
2757
|
disposePromise;
|
|
@@ -3775,7 +3789,7 @@ var VtxoManager = class _VtxoManager {
|
|
|
3775
3789
|
*/
|
|
3776
3790
|
extractSpentOutpoint(error) {
|
|
3777
3791
|
const ark = maybeArkError(error);
|
|
3778
|
-
if (!ark
|
|
3792
|
+
if (!isArkError(ark, ArkErrorName.VTXO_ALREADY_SPENT)) return void 0;
|
|
3779
3793
|
const raw = ark.metadata?.vtxo_outpoint;
|
|
3780
3794
|
if (typeof raw !== "string") return void 0;
|
|
3781
3795
|
const [txid, voutStr] = raw.split(":");
|
|
@@ -4079,6 +4093,9 @@ var ArkNote = class _ArkNote {
|
|
|
4079
4093
|
this.status = { confirmed: true };
|
|
4080
4094
|
this.extraWitness = [this.preimage];
|
|
4081
4095
|
}
|
|
4096
|
+
preimage;
|
|
4097
|
+
value;
|
|
4098
|
+
HRP;
|
|
4082
4099
|
static DefaultHRP = "arknote";
|
|
4083
4100
|
static PreimageLength = 32;
|
|
4084
4101
|
// 32 bytes for the preimage
|
|
@@ -4287,11 +4304,603 @@ function wrapHandlerWithIntentPersistence(base, deps) {
|
|
|
4287
4304
|
}
|
|
4288
4305
|
};
|
|
4289
4306
|
}
|
|
4307
|
+
|
|
4308
|
+
// src/repositories/virtualTxRepository.ts
|
|
4309
|
+
var ChainedTxType = /* @__PURE__ */ ((ChainedTxType2) => {
|
|
4310
|
+
ChainedTxType2[ChainedTxType2["Unspecified"] = 0] = "Unspecified";
|
|
4311
|
+
ChainedTxType2[ChainedTxType2["Commitment"] = 1] = "Commitment";
|
|
4312
|
+
ChainedTxType2[ChainedTxType2["Ark"] = 2] = "Ark";
|
|
4313
|
+
ChainedTxType2[ChainedTxType2["Tree"] = 3] = "Tree";
|
|
4314
|
+
ChainedTxType2[ChainedTxType2["Checkpoint"] = 4] = "Checkpoint";
|
|
4315
|
+
return ChainedTxType2;
|
|
4316
|
+
})(ChainedTxType || {});
|
|
4317
|
+
function mergeChainedTxType(incoming, prev) {
|
|
4318
|
+
if (incoming !== 0 /* Unspecified */) return incoming;
|
|
4319
|
+
return prev ?? 0 /* Unspecified */;
|
|
4320
|
+
}
|
|
4321
|
+
|
|
4322
|
+
// src/wallet/exit/chain.ts
|
|
4323
|
+
var isCommitment = (t) => t === "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */ || t === "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
|
|
4324
|
+
async function buildExitDag(params) {
|
|
4325
|
+
const byTxid = /* @__PURE__ */ new Map();
|
|
4326
|
+
for (const vtxo of params.vtxos) {
|
|
4327
|
+
const outpoint = `${vtxo.txid}:${vtxo.vout}`;
|
|
4328
|
+
const chain = await params.chain.getVtxoChain({ txid: vtxo.txid, vout: vtxo.vout });
|
|
4329
|
+
for (const chainTx of chain) {
|
|
4330
|
+
const existing = byTxid.get(chainTx.txid);
|
|
4331
|
+
if (existing) {
|
|
4332
|
+
existing.forVtxos.add(outpoint);
|
|
4333
|
+
} else {
|
|
4334
|
+
byTxid.set(chainTx.txid, { ...chainTx, forVtxos: /* @__PURE__ */ new Set([outpoint]) });
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
const pending = new Map(
|
|
4339
|
+
[...byTxid.values()].filter((tx) => !isCommitment(tx.type)).map((tx) => [tx.txid, tx])
|
|
4340
|
+
);
|
|
4341
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
4342
|
+
for (const tx of pending.values()) {
|
|
4343
|
+
const parents = tx.spends.filter((p) => pending.has(p));
|
|
4344
|
+
inDegree.set(tx.txid, parents.length);
|
|
4345
|
+
}
|
|
4346
|
+
const order = [];
|
|
4347
|
+
const queue = [...pending.values()].filter((tx) => inDegree.get(tx.txid) === 0).sort((a, b) => a.txid.localeCompare(b.txid));
|
|
4348
|
+
while (queue.length > 0) {
|
|
4349
|
+
const tx = queue.shift();
|
|
4350
|
+
order.push(tx);
|
|
4351
|
+
const children = [...pending.values()].filter((c) => c.spends.includes(tx.txid)).sort((a, b) => a.txid.localeCompare(b.txid));
|
|
4352
|
+
for (const child of children) {
|
|
4353
|
+
const deg = inDegree.get(child.txid) - 1;
|
|
4354
|
+
inDegree.set(child.txid, deg);
|
|
4355
|
+
if (deg === 0) queue.push(child);
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4358
|
+
if (order.length !== pending.size) {
|
|
4359
|
+
throw new Error("inconsistent vtxo chain from indexer (cycle detected)");
|
|
4360
|
+
}
|
|
4361
|
+
const nodes = [];
|
|
4362
|
+
for (const tx of order) {
|
|
4363
|
+
let confirmed = false;
|
|
4364
|
+
try {
|
|
4365
|
+
const status = await params.onchain.getTxStatus(tx.txid);
|
|
4366
|
+
confirmed = status.confirmed;
|
|
4367
|
+
} catch {
|
|
4368
|
+
confirmed = false;
|
|
4369
|
+
}
|
|
4370
|
+
const expires = Number(tx.expiresAt);
|
|
4371
|
+
nodes.push({
|
|
4372
|
+
txid: tx.txid,
|
|
4373
|
+
type: tx.type,
|
|
4374
|
+
expiresAt: Number.isFinite(expires) && expires > 0 ? expires : void 0,
|
|
4375
|
+
forVtxos: [...tx.forVtxos].sort(),
|
|
4376
|
+
confirmed
|
|
4377
|
+
});
|
|
4378
|
+
}
|
|
4379
|
+
return nodes;
|
|
4380
|
+
}
|
|
4381
|
+
function topoSortByDeps(items, idOf, depsOf) {
|
|
4382
|
+
const produced = new Set(items.map(idOf));
|
|
4383
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
4384
|
+
const ordered = [];
|
|
4385
|
+
let remaining = items;
|
|
4386
|
+
while (remaining.length > 0) {
|
|
4387
|
+
const next = [];
|
|
4388
|
+
let progress = false;
|
|
4389
|
+
for (const item of remaining) {
|
|
4390
|
+
if (depsOf(item).every((d) => !produced.has(d) || emitted.has(d))) {
|
|
4391
|
+
ordered.push(item);
|
|
4392
|
+
emitted.add(idOf(item));
|
|
4393
|
+
progress = true;
|
|
4394
|
+
} else {
|
|
4395
|
+
next.push(item);
|
|
4396
|
+
}
|
|
4397
|
+
}
|
|
4398
|
+
if (!progress) {
|
|
4399
|
+
throw new Error("topological sort: cycle or unsatisfiable dependency");
|
|
4400
|
+
}
|
|
4401
|
+
remaining = next;
|
|
4402
|
+
}
|
|
4403
|
+
return ordered;
|
|
4404
|
+
}
|
|
4405
|
+
|
|
4406
|
+
// src/wallet/exit/capture.ts
|
|
4407
|
+
var DEFAULT_MIN_EXIT_WORTH_SATS = 1e3;
|
|
4408
|
+
var DEFAULT_EXIT_CAPTURE_MODE = "lite";
|
|
4409
|
+
function chainTxTypeToChainedExit(t) {
|
|
4410
|
+
switch (t) {
|
|
4411
|
+
case "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */:
|
|
4412
|
+
return 1 /* Commitment */;
|
|
4413
|
+
case "INDEXER_CHAINED_TX_TYPE_ARK" /* ARK */:
|
|
4414
|
+
return 2 /* Ark */;
|
|
4415
|
+
case "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */:
|
|
4416
|
+
return 3 /* Tree */;
|
|
4417
|
+
case "INDEXER_CHAINED_TX_TYPE_CHECKPOINT" /* CHECKPOINT */:
|
|
4418
|
+
return 4 /* Checkpoint */;
|
|
4419
|
+
default:
|
|
4420
|
+
return 0 /* Unspecified */;
|
|
4421
|
+
}
|
|
4422
|
+
}
|
|
4423
|
+
function orderAncestryFirst(chain) {
|
|
4424
|
+
const ids = new Set(chain.map((c) => c.txid));
|
|
4425
|
+
return topoSortByDeps(
|
|
4426
|
+
chain,
|
|
4427
|
+
(c) => c.txid,
|
|
4428
|
+
(c) => c.spends.filter((s) => ids.has(s))
|
|
4429
|
+
);
|
|
4430
|
+
}
|
|
4431
|
+
async function captureExitBranch(params) {
|
|
4432
|
+
const { resolver, repository, vtxo, value, mode, minExitWorthSats } = params;
|
|
4433
|
+
if (value < minExitWorthSats) return;
|
|
4434
|
+
if (await repository.hasBranch(vtxo)) return;
|
|
4435
|
+
const ordered = orderAncestryFirst(await resolver.getVtxoChain(vtxo));
|
|
4436
|
+
const psbtByTxid = /* @__PURE__ */ new Map();
|
|
4437
|
+
if (mode === "full") {
|
|
4438
|
+
const nonCommitment = ordered.filter((c) => chainTxTypeToChainedExit(c.type) !== 1 /* Commitment */).map((c) => c.txid);
|
|
4439
|
+
if (nonCommitment.length > 0) {
|
|
4440
|
+
for (const psbt of await resolver.getVirtualTxs(nonCommitment)) {
|
|
4441
|
+
psbtByTxid.set(Transaction.fromPSBT(base64.decode(psbt)).id, psbt);
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
const virtualTxs = ordered.map((c) => {
|
|
4446
|
+
const expires = Number(c.expiresAt);
|
|
4447
|
+
return {
|
|
4448
|
+
txid: c.txid,
|
|
4449
|
+
psbt: psbtByTxid.get(c.txid) ?? null,
|
|
4450
|
+
expiresAt: Number.isFinite(expires) && expires > 0 ? expires : null,
|
|
4451
|
+
type: chainTxTypeToChainedExit(c.type)
|
|
4452
|
+
};
|
|
4453
|
+
});
|
|
4454
|
+
const branch = ordered.map((c, i) => ({
|
|
4455
|
+
vtxoTxid: vtxo.txid,
|
|
4456
|
+
vtxoVout: vtxo.vout,
|
|
4457
|
+
virtualTxid: c.txid,
|
|
4458
|
+
position: i
|
|
4459
|
+
}));
|
|
4460
|
+
await repository.upsertVirtualTxs(virtualTxs);
|
|
4461
|
+
await repository.setBranch(vtxo, branch);
|
|
4462
|
+
}
|
|
4463
|
+
async function pruneExitBranches(repository, outpoints) {
|
|
4464
|
+
for (const outpoint of outpoints) {
|
|
4465
|
+
try {
|
|
4466
|
+
await repository.pruneForSpentVtxo(outpoint);
|
|
4467
|
+
} catch {
|
|
4468
|
+
}
|
|
4469
|
+
}
|
|
4470
|
+
}
|
|
4471
|
+
var IndexerExitDataSource = class {
|
|
4472
|
+
constructor(indexer) {
|
|
4473
|
+
this.indexer = indexer;
|
|
4474
|
+
}
|
|
4475
|
+
indexer;
|
|
4476
|
+
name = "indexer";
|
|
4477
|
+
async getVtxoChain(vtxo) {
|
|
4478
|
+
const chain = [];
|
|
4479
|
+
let pageIndex = 0;
|
|
4480
|
+
let hasMore = true;
|
|
4481
|
+
while (hasMore) {
|
|
4482
|
+
const { chain: page, page: meta } = await this.indexer.getVtxoChain(
|
|
4483
|
+
{ txid: vtxo.txid, vout: vtxo.vout },
|
|
4484
|
+
{ pageIndex, pageSize: DEFAULT_PAGE_SIZE }
|
|
4485
|
+
);
|
|
4486
|
+
chain.push(...page);
|
|
4487
|
+
hasMore = meta ? page.length === DEFAULT_PAGE_SIZE : false;
|
|
4488
|
+
pageIndex++;
|
|
4489
|
+
}
|
|
4490
|
+
return chain;
|
|
4491
|
+
}
|
|
4492
|
+
async getVirtualTxs(txids) {
|
|
4493
|
+
const out = /* @__PURE__ */ new Map();
|
|
4494
|
+
let pageIndex = 0;
|
|
4495
|
+
let hasMore = true;
|
|
4496
|
+
while (hasMore) {
|
|
4497
|
+
const { txs, page } = await this.indexer.getVirtualTxs(txids, {
|
|
4498
|
+
pageIndex,
|
|
4499
|
+
pageSize: DEFAULT_PAGE_SIZE
|
|
4500
|
+
});
|
|
4501
|
+
for (const psbt of txs) {
|
|
4502
|
+
out.set(Transaction.fromPSBT(base64.decode(psbt)).id, psbt);
|
|
4503
|
+
}
|
|
4504
|
+
hasMore = page ? txs.length === DEFAULT_PAGE_SIZE : false;
|
|
4505
|
+
pageIndex++;
|
|
4506
|
+
}
|
|
4507
|
+
return out;
|
|
4508
|
+
}
|
|
4509
|
+
};
|
|
4510
|
+
function chainedTxTypeToChainTxType(t) {
|
|
4511
|
+
switch (t) {
|
|
4512
|
+
case 1 /* Commitment */:
|
|
4513
|
+
return "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */;
|
|
4514
|
+
case 2 /* Ark */:
|
|
4515
|
+
return "INDEXER_CHAINED_TX_TYPE_ARK" /* ARK */;
|
|
4516
|
+
case 3 /* Tree */:
|
|
4517
|
+
return "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */;
|
|
4518
|
+
case 4 /* Checkpoint */:
|
|
4519
|
+
return "INDEXER_CHAINED_TX_TYPE_CHECKPOINT" /* CHECKPOINT */;
|
|
4520
|
+
default:
|
|
4521
|
+
return "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
|
|
4522
|
+
}
|
|
4523
|
+
}
|
|
4524
|
+
function psbtInputTxids(psbtBase64) {
|
|
4525
|
+
const tx = Transaction.fromPSBT(base64.decode(psbtBase64));
|
|
4526
|
+
const ids = [];
|
|
4527
|
+
for (let i = 0; i < tx.inputsLength; i++) {
|
|
4528
|
+
const txid = tx.getInput(i).txid;
|
|
4529
|
+
if (txid) ids.push(hex.encode(txid));
|
|
4530
|
+
}
|
|
4531
|
+
return ids;
|
|
4532
|
+
}
|
|
4533
|
+
var RepositoryExitDataSource = class {
|
|
4534
|
+
constructor(repo) {
|
|
4535
|
+
this.repo = repo;
|
|
4536
|
+
}
|
|
4537
|
+
repo;
|
|
4538
|
+
name = "repository";
|
|
4539
|
+
async getVtxoChain(vtxo) {
|
|
4540
|
+
const branch = await this.repo.getBranch(vtxo);
|
|
4541
|
+
if (branch.length === 0) return null;
|
|
4542
|
+
const chain = [];
|
|
4543
|
+
for (const v of branch) {
|
|
4544
|
+
const type = chainedTxTypeToChainTxType(v.type);
|
|
4545
|
+
let spends = [];
|
|
4546
|
+
if (v.type !== 1 /* Commitment */) {
|
|
4547
|
+
if (!v.psbt) return null;
|
|
4548
|
+
spends = psbtInputTxids(v.psbt);
|
|
4549
|
+
}
|
|
4550
|
+
chain.push({
|
|
4551
|
+
txid: v.txid,
|
|
4552
|
+
type,
|
|
4553
|
+
expiresAt: v.expiresAt != null ? String(v.expiresAt) : "",
|
|
4554
|
+
spends
|
|
4555
|
+
});
|
|
4556
|
+
}
|
|
4557
|
+
return chain;
|
|
4558
|
+
}
|
|
4559
|
+
async getVirtualTxs(txids) {
|
|
4560
|
+
const out = /* @__PURE__ */ new Map();
|
|
4561
|
+
for (const txid of txids) {
|
|
4562
|
+
const stored = await this.repo.getVirtualTx(txid);
|
|
4563
|
+
if (stored?.psbt) out.set(txid, stored.psbt);
|
|
4564
|
+
}
|
|
4565
|
+
return out;
|
|
4566
|
+
}
|
|
4567
|
+
};
|
|
4568
|
+
|
|
4569
|
+
// src/wallet/exit/resolver.ts
|
|
4570
|
+
var OrderedExitChainResolver = class {
|
|
4571
|
+
constructor(sources, persist) {
|
|
4572
|
+
this.sources = sources;
|
|
4573
|
+
this.persist = persist;
|
|
4574
|
+
}
|
|
4575
|
+
sources;
|
|
4576
|
+
persist;
|
|
4577
|
+
async getVtxoChain(vtxo) {
|
|
4578
|
+
let lastErr;
|
|
4579
|
+
for (const source of this.sources) {
|
|
4580
|
+
try {
|
|
4581
|
+
const chain = await source.getVtxoChain(vtxo);
|
|
4582
|
+
if (chain) return chain;
|
|
4583
|
+
} catch (e) {
|
|
4584
|
+
lastErr = e;
|
|
4585
|
+
}
|
|
4586
|
+
}
|
|
4587
|
+
if (lastErr) throw lastErr;
|
|
4588
|
+
throw new Error(`no exit-data source resolved the chain for ${vtxo.txid}:${vtxo.vout}`);
|
|
4589
|
+
}
|
|
4590
|
+
async getVirtualTxs(txids) {
|
|
4591
|
+
const found = /* @__PURE__ */ new Map();
|
|
4592
|
+
let remaining = txids;
|
|
4593
|
+
for (const [i, source] of this.sources.entries()) {
|
|
4594
|
+
if (remaining.length === 0) break;
|
|
4595
|
+
let got;
|
|
4596
|
+
try {
|
|
4597
|
+
got = await source.getVirtualTxs(remaining);
|
|
4598
|
+
} catch {
|
|
4599
|
+
continue;
|
|
4600
|
+
}
|
|
4601
|
+
const fresh = [];
|
|
4602
|
+
for (const [txid, psbt] of got) {
|
|
4603
|
+
if (found.has(txid)) continue;
|
|
4604
|
+
found.set(txid, psbt);
|
|
4605
|
+
fresh.push({ txid, psbt, expiresAt: null, type: 0 /* Unspecified */ });
|
|
4606
|
+
}
|
|
4607
|
+
if (i > 0 && this.persist && fresh.length > 0) {
|
|
4608
|
+
try {
|
|
4609
|
+
await this.persist.upsertVirtualTxs(fresh);
|
|
4610
|
+
} catch {
|
|
4611
|
+
}
|
|
4612
|
+
}
|
|
4613
|
+
remaining = txids.filter((t) => !found.has(t));
|
|
4614
|
+
}
|
|
4615
|
+
return [...found.values()];
|
|
4616
|
+
}
|
|
4617
|
+
};
|
|
4618
|
+
function createExitChainResolver(params) {
|
|
4619
|
+
const sources = [];
|
|
4620
|
+
if (params.repository) sources.push(new RepositoryExitDataSource(params.repository));
|
|
4621
|
+
if (params.extraSources) sources.push(...params.extraSources);
|
|
4622
|
+
sources.push(new IndexerExitDataSource(params.indexer));
|
|
4623
|
+
return new OrderedExitChainResolver(sources, params.repository);
|
|
4624
|
+
}
|
|
4625
|
+
|
|
4626
|
+
// src/providers/availability.ts
|
|
4627
|
+
function isRetryableProviderError(error) {
|
|
4628
|
+
return error instanceof ProviderUnavailableError || error instanceof FetchError || isFetchTimeoutError(error);
|
|
4629
|
+
}
|
|
4630
|
+
|
|
4631
|
+
// src/utils/syncCursors.ts
|
|
4632
|
+
var SAFETY_LAG_MS = 3e4;
|
|
4633
|
+
var OVERLAP_MS = 24 * 60 * 60 * 1e3;
|
|
4634
|
+
var walletStateLocks = /* @__PURE__ */ new WeakMap();
|
|
4635
|
+
async function updateWalletState(repo, updater) {
|
|
4636
|
+
const prev = walletStateLocks.get(repo) ?? Promise.resolve();
|
|
4637
|
+
const op = prev.then(async () => {
|
|
4638
|
+
const state = await repo.getWalletState() ?? {};
|
|
4639
|
+
await repo.saveWalletState(updater(state));
|
|
4640
|
+
});
|
|
4641
|
+
walletStateLocks.set(
|
|
4642
|
+
repo,
|
|
4643
|
+
op.catch(() => {
|
|
4644
|
+
})
|
|
4645
|
+
);
|
|
4646
|
+
return op;
|
|
4647
|
+
}
|
|
4648
|
+
var CURSOR_MIGRATED_KEY = "vtxoCursorMigrated";
|
|
4649
|
+
function hasMigrationMarker(state) {
|
|
4650
|
+
return state?.settings?.[CURSOR_MIGRATED_KEY] === true;
|
|
4651
|
+
}
|
|
4652
|
+
async function getSyncCursor(repo) {
|
|
4653
|
+
const state = await repo.getWalletState();
|
|
4654
|
+
if (!hasMigrationMarker(state)) return 0;
|
|
4655
|
+
return state?.lastSyncTime ?? 0;
|
|
4656
|
+
}
|
|
4657
|
+
async function advanceSyncCursor(repo, lastUpdatedAt) {
|
|
4658
|
+
await updateWalletState(repo, (state) => {
|
|
4659
|
+
const current = hasMigrationMarker(state) ? state.lastSyncTime ?? 0 : 0;
|
|
4660
|
+
return {
|
|
4661
|
+
...state,
|
|
4662
|
+
lastSyncTime: Math.max(current, lastUpdatedAt),
|
|
4663
|
+
settings: {
|
|
4664
|
+
...state.settings ?? {},
|
|
4665
|
+
[CURSOR_MIGRATED_KEY]: true
|
|
4666
|
+
}
|
|
4667
|
+
};
|
|
4668
|
+
});
|
|
4669
|
+
}
|
|
4670
|
+
async function clearSyncCursor(repo) {
|
|
4671
|
+
await updateWalletState(repo, (state) => {
|
|
4672
|
+
const { [CURSOR_MIGRATED_KEY]: _, ...restSettings } = state.settings ?? {};
|
|
4673
|
+
return {
|
|
4674
|
+
...state,
|
|
4675
|
+
lastSyncTime: void 0,
|
|
4676
|
+
settings: restSettings
|
|
4677
|
+
};
|
|
4678
|
+
});
|
|
4679
|
+
}
|
|
4680
|
+
function computeSyncWindow(cursor) {
|
|
4681
|
+
const after = Math.max(0, cursor - OVERLAP_MS);
|
|
4682
|
+
return { after };
|
|
4683
|
+
}
|
|
4684
|
+
function cursorCutoff(requestStartedAt) {
|
|
4685
|
+
return (requestStartedAt ?? Date.now()) - SAFETY_LAG_MS;
|
|
4686
|
+
}
|
|
4687
|
+
|
|
4688
|
+
// src/wallet/arkInfoSnapshot.ts
|
|
4689
|
+
var ARK_INFO_SNAPSHOT_KEY = "arkInfoSnapshot";
|
|
4690
|
+
var MalformedArkInfoSnapshotError = class extends Error {
|
|
4691
|
+
constructor(message, options) {
|
|
4692
|
+
super(message, { cause: options?.cause });
|
|
4693
|
+
this.name = "MalformedArkInfoSnapshotError";
|
|
4694
|
+
}
|
|
4695
|
+
};
|
|
4696
|
+
var CURRENT_VERSION = 1;
|
|
4697
|
+
function serializeArkInfoSnapshot(info, savedAt) {
|
|
4698
|
+
return {
|
|
4699
|
+
version: CURRENT_VERSION,
|
|
4700
|
+
savedAt,
|
|
4701
|
+
source: "arkade.getInfo",
|
|
4702
|
+
arkInfo: {
|
|
4703
|
+
network: info.network,
|
|
4704
|
+
signerPubkey: info.signerPubkey,
|
|
4705
|
+
checkpointTapscript: info.checkpointTapscript,
|
|
4706
|
+
forfeitAddress: info.forfeitAddress,
|
|
4707
|
+
forfeitPubkey: info.forfeitPubkey,
|
|
4708
|
+
unilateralExitDelay: info.unilateralExitDelay.toString(),
|
|
4709
|
+
boardingExitDelay: info.boardingExitDelay.toString(),
|
|
4710
|
+
sessionDuration: info.sessionDuration.toString(),
|
|
4711
|
+
dust: info.dust.toString(),
|
|
4712
|
+
fees: info.fees,
|
|
4713
|
+
digest: info.digest,
|
|
4714
|
+
version: info.version,
|
|
4715
|
+
vtxoMinAmount: info.vtxoMinAmount.toString(),
|
|
4716
|
+
vtxoMaxAmount: info.vtxoMaxAmount.toString(),
|
|
4717
|
+
utxoMinAmount: info.utxoMinAmount.toString(),
|
|
4718
|
+
utxoMaxAmount: info.utxoMaxAmount.toString(),
|
|
4719
|
+
deprecatedSigners: info.deprecatedSigners.map((s) => ({
|
|
4720
|
+
pubkey: s.pubkey,
|
|
4721
|
+
cutoffDate: s.cutoffDate.toString()
|
|
4722
|
+
})),
|
|
4723
|
+
scheduledSession: info.scheduledSession ? {
|
|
4724
|
+
duration: info.scheduledSession.duration.toString(),
|
|
4725
|
+
fees: info.scheduledSession.fees,
|
|
4726
|
+
nextEndTime: info.scheduledSession.nextEndTime.toString(),
|
|
4727
|
+
nextStartTime: info.scheduledSession.nextStartTime.toString(),
|
|
4728
|
+
period: info.scheduledSession.period.toString()
|
|
4729
|
+
} : void 0
|
|
4730
|
+
}
|
|
4731
|
+
};
|
|
4732
|
+
}
|
|
4733
|
+
function hydrateArkInfo(snapshot) {
|
|
4734
|
+
const a = snapshot.arkInfo;
|
|
4735
|
+
return {
|
|
4736
|
+
boardingExitDelay: BigInt(a.boardingExitDelay),
|
|
4737
|
+
checkpointTapscript: a.checkpointTapscript,
|
|
4738
|
+
deprecatedSigners: a.deprecatedSigners.map((s) => ({
|
|
4739
|
+
cutoffDate: BigInt(s.cutoffDate),
|
|
4740
|
+
pubkey: s.pubkey
|
|
4741
|
+
})),
|
|
4742
|
+
digest: a.digest,
|
|
4743
|
+
dust: BigInt(a.dust),
|
|
4744
|
+
fees: a.fees,
|
|
4745
|
+
forfeitAddress: a.forfeitAddress,
|
|
4746
|
+
forfeitPubkey: a.forfeitPubkey,
|
|
4747
|
+
network: a.network,
|
|
4748
|
+
scheduledSession: a.scheduledSession ? {
|
|
4749
|
+
duration: BigInt(a.scheduledSession.duration),
|
|
4750
|
+
fees: a.scheduledSession.fees,
|
|
4751
|
+
nextEndTime: BigInt(a.scheduledSession.nextEndTime),
|
|
4752
|
+
nextStartTime: BigInt(a.scheduledSession.nextStartTime),
|
|
4753
|
+
period: BigInt(a.scheduledSession.period)
|
|
4754
|
+
} : void 0,
|
|
4755
|
+
serviceStatus: {},
|
|
4756
|
+
sessionDuration: BigInt(a.sessionDuration),
|
|
4757
|
+
signerPubkey: a.signerPubkey,
|
|
4758
|
+
unilateralExitDelay: BigInt(a.unilateralExitDelay),
|
|
4759
|
+
utxoMaxAmount: BigInt(a.utxoMaxAmount),
|
|
4760
|
+
utxoMinAmount: BigInt(a.utxoMinAmount),
|
|
4761
|
+
version: a.version,
|
|
4762
|
+
vtxoMaxAmount: BigInt(a.vtxoMaxAmount),
|
|
4763
|
+
vtxoMinAmount: BigInt(a.vtxoMinAmount)
|
|
4764
|
+
};
|
|
4765
|
+
}
|
|
4766
|
+
var DECIMAL_STRING = /^-?\d+$/;
|
|
4767
|
+
function assertString(value, path) {
|
|
4768
|
+
if (typeof value !== "string") {
|
|
4769
|
+
throw new MalformedArkInfoSnapshotError(`${path} must be a string`);
|
|
4770
|
+
}
|
|
4771
|
+
}
|
|
4772
|
+
function assertDecimalString(value, path) {
|
|
4773
|
+
assertString(value, path);
|
|
4774
|
+
if (!DECIMAL_STRING.test(value)) {
|
|
4775
|
+
throw new MalformedArkInfoSnapshotError(`${path} must be a decimal integer string`);
|
|
4776
|
+
}
|
|
4777
|
+
}
|
|
4778
|
+
function assertFeeInfo(value, path) {
|
|
4779
|
+
if (typeof value !== "object" || value === null) {
|
|
4780
|
+
throw new MalformedArkInfoSnapshotError(`${path} must be an object`);
|
|
4781
|
+
}
|
|
4782
|
+
const fees = value;
|
|
4783
|
+
assertString(fees.txFeeRate, `${path}.txFeeRate`);
|
|
4784
|
+
if (typeof fees.intentFee !== "object" || fees.intentFee === null) {
|
|
4785
|
+
throw new MalformedArkInfoSnapshotError(`${path}.intentFee must be an object`);
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4788
|
+
function parseStoredArkInfoSnapshot(raw) {
|
|
4789
|
+
if (typeof raw !== "object" || raw === null) {
|
|
4790
|
+
throw new MalformedArkInfoSnapshotError("snapshot must be an object");
|
|
4791
|
+
}
|
|
4792
|
+
const snap = raw;
|
|
4793
|
+
if (snap.version !== CURRENT_VERSION) {
|
|
4794
|
+
throw new MalformedArkInfoSnapshotError(
|
|
4795
|
+
`unsupported snapshot version: ${String(snap.version)}`
|
|
4796
|
+
);
|
|
4797
|
+
}
|
|
4798
|
+
if (typeof snap.savedAt !== "number") {
|
|
4799
|
+
throw new MalformedArkInfoSnapshotError("savedAt must be a number");
|
|
4800
|
+
}
|
|
4801
|
+
if (snap.source !== "arkade.getInfo") {
|
|
4802
|
+
throw new MalformedArkInfoSnapshotError(`unexpected source: ${String(snap.source)}`);
|
|
4803
|
+
}
|
|
4804
|
+
if (typeof snap.arkInfo !== "object" || snap.arkInfo === null) {
|
|
4805
|
+
throw new MalformedArkInfoSnapshotError("arkInfo must be an object");
|
|
4806
|
+
}
|
|
4807
|
+
const a = snap.arkInfo;
|
|
4808
|
+
for (const field of [
|
|
4809
|
+
"network",
|
|
4810
|
+
"signerPubkey",
|
|
4811
|
+
"checkpointTapscript",
|
|
4812
|
+
"forfeitAddress",
|
|
4813
|
+
"forfeitPubkey",
|
|
4814
|
+
"digest",
|
|
4815
|
+
"version"
|
|
4816
|
+
]) {
|
|
4817
|
+
assertString(a[field], `arkInfo.${field}`);
|
|
4818
|
+
}
|
|
4819
|
+
for (const field of [
|
|
4820
|
+
"unilateralExitDelay",
|
|
4821
|
+
"boardingExitDelay",
|
|
4822
|
+
"sessionDuration",
|
|
4823
|
+
"dust",
|
|
4824
|
+
"vtxoMinAmount",
|
|
4825
|
+
"vtxoMaxAmount",
|
|
4826
|
+
"utxoMinAmount",
|
|
4827
|
+
"utxoMaxAmount"
|
|
4828
|
+
]) {
|
|
4829
|
+
assertDecimalString(a[field], `arkInfo.${field}`);
|
|
4830
|
+
}
|
|
4831
|
+
assertFeeInfo(a.fees, "arkInfo.fees");
|
|
4832
|
+
if (!Array.isArray(a.deprecatedSigners)) {
|
|
4833
|
+
throw new MalformedArkInfoSnapshotError("arkInfo.deprecatedSigners must be an array");
|
|
4834
|
+
}
|
|
4835
|
+
a.deprecatedSigners.forEach((s, i) => {
|
|
4836
|
+
if (typeof s !== "object" || s === null) {
|
|
4837
|
+
throw new MalformedArkInfoSnapshotError(
|
|
4838
|
+
`arkInfo.deprecatedSigners[${i}] must be an object`
|
|
4839
|
+
);
|
|
4840
|
+
}
|
|
4841
|
+
const signer = s;
|
|
4842
|
+
assertString(signer.pubkey, `arkInfo.deprecatedSigners[${i}].pubkey`);
|
|
4843
|
+
assertDecimalString(signer.cutoffDate, `arkInfo.deprecatedSigners[${i}].cutoffDate`);
|
|
4844
|
+
});
|
|
4845
|
+
if (a.scheduledSession !== void 0) {
|
|
4846
|
+
if (typeof a.scheduledSession !== "object" || a.scheduledSession === null) {
|
|
4847
|
+
throw new MalformedArkInfoSnapshotError("arkInfo.scheduledSession must be an object");
|
|
4848
|
+
}
|
|
4849
|
+
const s = a.scheduledSession;
|
|
4850
|
+
for (const field of ["duration", "nextEndTime", "nextStartTime", "period"]) {
|
|
4851
|
+
assertDecimalString(s[field], `arkInfo.scheduledSession.${field}`);
|
|
4852
|
+
}
|
|
4853
|
+
assertFeeInfo(s.fees, "arkInfo.scheduledSession.fees");
|
|
4854
|
+
}
|
|
4855
|
+
return raw;
|
|
4856
|
+
}
|
|
4857
|
+
async function loadArkInfoSnapshot(repo) {
|
|
4858
|
+
const state = await repo.getWalletState();
|
|
4859
|
+
const raw = state?.settings?.[ARK_INFO_SNAPSHOT_KEY];
|
|
4860
|
+
if (raw === void 0 || raw === null) return null;
|
|
4861
|
+
return parseStoredArkInfoSnapshot(raw);
|
|
4862
|
+
}
|
|
4863
|
+
async function saveArkInfoSnapshot(repo, info, savedAt) {
|
|
4864
|
+
const snapshot = serializeArkInfoSnapshot(info, savedAt);
|
|
4865
|
+
await updateWalletState(repo, (state) => ({
|
|
4866
|
+
...state,
|
|
4867
|
+
settings: {
|
|
4868
|
+
...state.settings ?? {},
|
|
4869
|
+
[ARK_INFO_SNAPSHOT_KEY]: snapshot
|
|
4870
|
+
}
|
|
4871
|
+
}));
|
|
4872
|
+
}
|
|
4873
|
+
async function resolveArkInfo(arkProvider, walletRepository) {
|
|
4874
|
+
let info;
|
|
4875
|
+
try {
|
|
4876
|
+
info = await arkProvider.getInfo();
|
|
4877
|
+
} catch (err) {
|
|
4878
|
+
if (!isRetryableProviderError(err)) throw err;
|
|
4879
|
+
const snapshot = await loadArkInfoSnapshot(walletRepository);
|
|
4880
|
+
if (!snapshot) {
|
|
4881
|
+
throw new ProviderUnavailableError(
|
|
4882
|
+
"Arkade server info is unavailable and no cached snapshot exists",
|
|
4883
|
+
{ cause: err }
|
|
4884
|
+
);
|
|
4885
|
+
}
|
|
4886
|
+
return { info: hydrateArkInfo(snapshot), source: "cache", lastOnlineAt: snapshot.savedAt };
|
|
4887
|
+
}
|
|
4888
|
+
return { info, source: "live" };
|
|
4889
|
+
}
|
|
4890
|
+
async function saveValidatedArkInfoSnapshot(repo, info, savedAt) {
|
|
4891
|
+
try {
|
|
4892
|
+
await saveArkInfoSnapshot(repo, info, savedAt);
|
|
4893
|
+
} catch (err) {
|
|
4894
|
+
console.warn("Failed to persist Ark info snapshot", err);
|
|
4895
|
+
}
|
|
4896
|
+
}
|
|
4290
4897
|
var TxTree = class {
|
|
4291
4898
|
constructor(root, children = /* @__PURE__ */ new Map()) {
|
|
4292
4899
|
this.root = root;
|
|
4293
4900
|
this.children = children;
|
|
4294
4901
|
}
|
|
4902
|
+
root;
|
|
4903
|
+
children;
|
|
4295
4904
|
static create(chunks) {
|
|
4296
4905
|
if (chunks.length === 0) {
|
|
4297
4906
|
throw new Error("empty chunks");
|
|
@@ -4763,6 +5372,7 @@ var ReadonlyAssetManager = class {
|
|
|
4763
5372
|
constructor(indexer) {
|
|
4764
5373
|
this.indexer = indexer;
|
|
4765
5374
|
}
|
|
5375
|
+
indexer;
|
|
4766
5376
|
async getAssetDetails(assetId) {
|
|
4767
5377
|
return this.indexer.getAssetDetails(assetId);
|
|
4768
5378
|
}
|
|
@@ -4772,6 +5382,7 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4772
5382
|
super(wallet.indexerProvider);
|
|
4773
5383
|
this.wallet = wallet;
|
|
4774
5384
|
}
|
|
5385
|
+
wallet;
|
|
4775
5386
|
/**
|
|
4776
5387
|
* Issue a new asset.
|
|
4777
5388
|
* @param params - Parameters for asset issuance
|
|
@@ -5093,6 +5704,9 @@ var DelegateManagerImpl = class {
|
|
|
5093
5704
|
this.arkInfoProvider = arkInfoProvider;
|
|
5094
5705
|
this.identity = identity;
|
|
5095
5706
|
}
|
|
5707
|
+
delegateProvider;
|
|
5708
|
+
arkInfoProvider;
|
|
5709
|
+
identity;
|
|
5096
5710
|
async getDelegateInfo() {
|
|
5097
5711
|
return this.delegateProvider.getDelegateInfo();
|
|
5098
5712
|
}
|
|
@@ -5259,12 +5873,12 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
|
|
|
5259
5873
|
script: hex.encode(output.script)
|
|
5260
5874
|
}).satoshis;
|
|
5261
5875
|
}, 0);
|
|
5262
|
-
if (amount - BigInt(outputFee)
|
|
5876
|
+
if (isSubdust(amount - BigInt(outputFee), dust)) {
|
|
5263
5877
|
throw new Error("Amount is below dust limit, cannot delegate");
|
|
5264
5878
|
}
|
|
5265
5879
|
amount -= BigInt(outputFee);
|
|
5266
5880
|
amount -= delegateFee;
|
|
5267
|
-
if (amount
|
|
5881
|
+
if (isSubdust(amount, dust)) {
|
|
5268
5882
|
throw new Error("Amount is below dust limit, cannot delegate");
|
|
5269
5883
|
}
|
|
5270
5884
|
outputs.push({
|
|
@@ -5396,20 +6010,6 @@ function isAnnotated(v) {
|
|
|
5396
6010
|
return v.tapTree !== void 0 && v.forfeitTapLeafScript !== void 0 && v.intentTapLeafScript !== void 0;
|
|
5397
6011
|
}
|
|
5398
6012
|
|
|
5399
|
-
// src/repositories/virtualTxRepository.ts
|
|
5400
|
-
var ChainedTxType = /* @__PURE__ */ ((ChainedTxType2) => {
|
|
5401
|
-
ChainedTxType2[ChainedTxType2["Unspecified"] = 0] = "Unspecified";
|
|
5402
|
-
ChainedTxType2[ChainedTxType2["Commitment"] = 1] = "Commitment";
|
|
5403
|
-
ChainedTxType2[ChainedTxType2["Ark"] = 2] = "Ark";
|
|
5404
|
-
ChainedTxType2[ChainedTxType2["Tree"] = 3] = "Tree";
|
|
5405
|
-
ChainedTxType2[ChainedTxType2["Checkpoint"] = 4] = "Checkpoint";
|
|
5406
|
-
return ChainedTxType2;
|
|
5407
|
-
})(ChainedTxType || {});
|
|
5408
|
-
function mergeChainedTxType(incoming, prev) {
|
|
5409
|
-
if (incoming !== 0 /* Unspecified */) return incoming;
|
|
5410
|
-
return prev ?? 0 /* Unspecified */;
|
|
5411
|
-
}
|
|
5412
|
-
|
|
5413
6013
|
// src/repositories/inMemory/intentRepository.ts
|
|
5414
6014
|
var InMemoryIntentRepository = class {
|
|
5415
6015
|
version = 1;
|
|
@@ -5875,6 +6475,7 @@ var IndexedDBVirtualTxRepository = class {
|
|
|
5875
6475
|
constructor(dbName = DEFAULT_DB_NAME) {
|
|
5876
6476
|
this.dbName = dbName;
|
|
5877
6477
|
}
|
|
6478
|
+
dbName;
|
|
5878
6479
|
version = 1;
|
|
5879
6480
|
db = null;
|
|
5880
6481
|
async getDB() {
|
|
@@ -6004,6 +6605,7 @@ var IndexedDBIntentRepository = class {
|
|
|
6004
6605
|
constructor(dbName = DEFAULT_DB_NAME) {
|
|
6005
6606
|
this.dbName = dbName;
|
|
6006
6607
|
}
|
|
6608
|
+
dbName;
|
|
6007
6609
|
version = 1;
|
|
6008
6610
|
db = null;
|
|
6009
6611
|
async getDB() {
|
|
@@ -6314,6 +6916,7 @@ var IndexedDBContractRepository = class {
|
|
|
6314
6916
|
constructor(dbName = DEFAULT_DB_NAME) {
|
|
6315
6917
|
this.dbName = dbName;
|
|
6316
6918
|
}
|
|
6919
|
+
dbName;
|
|
6317
6920
|
version = 1;
|
|
6318
6921
|
db = null;
|
|
6319
6922
|
async clear() {
|
|
@@ -6480,6 +7083,7 @@ var IndexedDBWalletRepository = class {
|
|
|
6480
7083
|
constructor(dbName = DEFAULT_DB_NAME) {
|
|
6481
7084
|
this.dbName = dbName;
|
|
6482
7085
|
}
|
|
7086
|
+
dbName;
|
|
6483
7087
|
version = 1;
|
|
6484
7088
|
db = null;
|
|
6485
7089
|
async clear() {
|
|
@@ -7803,87 +8407,30 @@ async function reconcileIntents(deps) {
|
|
|
7803
8407
|
if (!next) continue;
|
|
7804
8408
|
const [fresh] = await deps.intentRepository.getIntents({
|
|
7805
8409
|
intentTxIds: [intent.intentTxId]
|
|
7806
|
-
});
|
|
7807
|
-
if (!fresh || fresh.state !== intent.state) continue;
|
|
7808
|
-
await deps.intentRepository.saveIntent(next);
|
|
7809
|
-
} catch (e) {
|
|
7810
|
-
console.error(`reconcileIntents: failed to reconcile intent ${intent.intentTxId}`, e);
|
|
7811
|
-
}
|
|
7812
|
-
}
|
|
7813
|
-
}
|
|
7814
|
-
function terminal(intent, state, now, patch) {
|
|
7815
|
-
return { ...intent, ...patch, state, updatedAt: now };
|
|
7816
|
-
}
|
|
7817
|
-
function outpointKey(o) {
|
|
7818
|
-
return `${o.txid}:${o.vout}`;
|
|
7819
|
-
}
|
|
7820
|
-
function dedupeOutpoints(outpoints) {
|
|
7821
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7822
|
-
const out = [];
|
|
7823
|
-
for (const o of outpoints) {
|
|
7824
|
-
const k = outpointKey(o);
|
|
7825
|
-
if (seen.has(k)) continue;
|
|
7826
|
-
seen.add(k);
|
|
7827
|
-
out.push(o);
|
|
7828
|
-
}
|
|
7829
|
-
return out;
|
|
7830
|
-
}
|
|
7831
|
-
|
|
7832
|
-
// src/utils/syncCursors.ts
|
|
7833
|
-
var SAFETY_LAG_MS = 3e4;
|
|
7834
|
-
var OVERLAP_MS = 24 * 60 * 60 * 1e3;
|
|
7835
|
-
var walletStateLocks = /* @__PURE__ */ new WeakMap();
|
|
7836
|
-
async function updateWalletState(repo, updater) {
|
|
7837
|
-
const prev = walletStateLocks.get(repo) ?? Promise.resolve();
|
|
7838
|
-
const op = prev.then(async () => {
|
|
7839
|
-
const state = await repo.getWalletState() ?? {};
|
|
7840
|
-
await repo.saveWalletState(updater(state));
|
|
7841
|
-
});
|
|
7842
|
-
walletStateLocks.set(
|
|
7843
|
-
repo,
|
|
7844
|
-
op.catch(() => {
|
|
7845
|
-
})
|
|
7846
|
-
);
|
|
7847
|
-
return op;
|
|
7848
|
-
}
|
|
7849
|
-
var CURSOR_MIGRATED_KEY = "vtxoCursorMigrated";
|
|
7850
|
-
function hasMigrationMarker(state) {
|
|
7851
|
-
return state?.settings?.[CURSOR_MIGRATED_KEY] === true;
|
|
7852
|
-
}
|
|
7853
|
-
async function getSyncCursor(repo) {
|
|
7854
|
-
const state = await repo.getWalletState();
|
|
7855
|
-
if (!hasMigrationMarker(state)) return 0;
|
|
7856
|
-
return state?.lastSyncTime ?? 0;
|
|
7857
|
-
}
|
|
7858
|
-
async function advanceSyncCursor(repo, lastUpdatedAt) {
|
|
7859
|
-
await updateWalletState(repo, (state) => {
|
|
7860
|
-
const current = hasMigrationMarker(state) ? state.lastSyncTime ?? 0 : 0;
|
|
7861
|
-
return {
|
|
7862
|
-
...state,
|
|
7863
|
-
lastSyncTime: Math.max(current, lastUpdatedAt),
|
|
7864
|
-
settings: {
|
|
7865
|
-
...state.settings ?? {},
|
|
7866
|
-
[CURSOR_MIGRATED_KEY]: true
|
|
7867
|
-
}
|
|
7868
|
-
};
|
|
7869
|
-
});
|
|
8410
|
+
});
|
|
8411
|
+
if (!fresh || fresh.state !== intent.state) continue;
|
|
8412
|
+
await deps.intentRepository.saveIntent(next);
|
|
8413
|
+
} catch (e) {
|
|
8414
|
+
console.error(`reconcileIntents: failed to reconcile intent ${intent.intentTxId}`, e);
|
|
8415
|
+
}
|
|
8416
|
+
}
|
|
7870
8417
|
}
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
const { [CURSOR_MIGRATED_KEY]: _, ...restSettings } = state.settings ?? {};
|
|
7874
|
-
return {
|
|
7875
|
-
...state,
|
|
7876
|
-
lastSyncTime: void 0,
|
|
7877
|
-
settings: restSettings
|
|
7878
|
-
};
|
|
7879
|
-
});
|
|
8418
|
+
function terminal(intent, state, now, patch) {
|
|
8419
|
+
return { ...intent, ...patch, state, updatedAt: now };
|
|
7880
8420
|
}
|
|
7881
|
-
function
|
|
7882
|
-
|
|
7883
|
-
return { after };
|
|
8421
|
+
function outpointKey(o) {
|
|
8422
|
+
return `${o.txid}:${o.vout}`;
|
|
7884
8423
|
}
|
|
7885
|
-
function
|
|
7886
|
-
|
|
8424
|
+
function dedupeOutpoints(outpoints) {
|
|
8425
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8426
|
+
const out = [];
|
|
8427
|
+
for (const o of outpoints) {
|
|
8428
|
+
const k = outpointKey(o);
|
|
8429
|
+
if (seen.has(k)) continue;
|
|
8430
|
+
seen.add(k);
|
|
8431
|
+
out.push(o);
|
|
8432
|
+
}
|
|
8433
|
+
return out;
|
|
7887
8434
|
}
|
|
7888
8435
|
|
|
7889
8436
|
// src/contracts/contractManager.ts
|
|
@@ -7898,6 +8445,10 @@ var ContractManager = class _ContractManager {
|
|
|
7898
8445
|
initialized = false;
|
|
7899
8446
|
eventCallbacks = /* @__PURE__ */ new Set();
|
|
7900
8447
|
stopWatcherFn;
|
|
8448
|
+
/** `undefined` while online; the failure reason once a sync degrades. */
|
|
8449
|
+
syncDegradedReason;
|
|
8450
|
+
/** Epoch-ms of the last successful provider sync, if any. */
|
|
8451
|
+
lastSyncedAt;
|
|
7901
8452
|
constructor(config) {
|
|
7902
8453
|
this.config = config;
|
|
7903
8454
|
this.watcher = new ContractWatcher({
|
|
@@ -7920,6 +8471,26 @@ var ContractManager = class _ContractManager {
|
|
|
7920
8471
|
await cm.initialize();
|
|
7921
8472
|
return cm;
|
|
7922
8473
|
}
|
|
8474
|
+
/**
|
|
8475
|
+
* Latest provider-sync health. See {@link ContractSyncState}. Degradation is
|
|
8476
|
+
* recorded by {@link initialize}, {@link getContractsWithVtxos}, and
|
|
8477
|
+
* {@link createContract}; it flips back to `online` on the next successful
|
|
8478
|
+
* sync. Purely a freshness signal — not a source of truth for wallet data.
|
|
8479
|
+
*/
|
|
8480
|
+
getSyncState() {
|
|
8481
|
+
return this.syncDegradedReason === void 0 ? { mode: "online", lastSyncedAt: this.lastSyncedAt } : {
|
|
8482
|
+
mode: "degraded",
|
|
8483
|
+
reason: this.syncDegradedReason,
|
|
8484
|
+
lastSyncedAt: this.lastSyncedAt
|
|
8485
|
+
};
|
|
8486
|
+
}
|
|
8487
|
+
markSyncOnline() {
|
|
8488
|
+
this.syncDegradedReason = void 0;
|
|
8489
|
+
this.lastSyncedAt = Date.now();
|
|
8490
|
+
}
|
|
8491
|
+
markSyncDegraded(err) {
|
|
8492
|
+
this.syncDegradedReason = err instanceof Error ? err.message : String(err);
|
|
8493
|
+
}
|
|
7923
8494
|
async initialize() {
|
|
7924
8495
|
if (this.initialized) {
|
|
7925
8496
|
return;
|
|
@@ -7928,7 +8499,13 @@ var ContractManager = class _ContractManager {
|
|
|
7928
8499
|
for (const contract of contracts) {
|
|
7929
8500
|
await this.watcher.addContract(contract);
|
|
7930
8501
|
}
|
|
7931
|
-
|
|
8502
|
+
try {
|
|
8503
|
+
await this.reconcileWatched();
|
|
8504
|
+
this.markSyncOnline();
|
|
8505
|
+
} catch (err) {
|
|
8506
|
+
if (!isRetryableProviderError(err)) throw err;
|
|
8507
|
+
this.markSyncDegraded(err);
|
|
8508
|
+
}
|
|
7932
8509
|
this.initialized = true;
|
|
7933
8510
|
this.stopWatcherFn = await this.watcher.startWatching((event) => {
|
|
7934
8511
|
this.handleContractEvent(event).catch((error) => {
|
|
@@ -7982,7 +8559,13 @@ var ContractManager = class _ContractManager {
|
|
|
7982
8559
|
async createContract(params) {
|
|
7983
8560
|
const { contract, persisted } = await this.upsertContract(params);
|
|
7984
8561
|
if (persisted) {
|
|
7985
|
-
|
|
8562
|
+
try {
|
|
8563
|
+
await this.fetchContractVxosFromIndexer([contract]);
|
|
8564
|
+
this.markSyncOnline();
|
|
8565
|
+
} catch (err) {
|
|
8566
|
+
if (!isRetryableProviderError(err)) throw err;
|
|
8567
|
+
this.markSyncDegraded(err);
|
|
8568
|
+
}
|
|
7986
8569
|
await this.watcher.addContract(contract);
|
|
7987
8570
|
}
|
|
7988
8571
|
return contract;
|
|
@@ -8181,7 +8764,13 @@ var ContractManager = class _ContractManager {
|
|
|
8181
8764
|
}
|
|
8182
8765
|
async getContractsWithVtxos(filter, pageSize) {
|
|
8183
8766
|
const contracts = await this.getContracts(filter);
|
|
8184
|
-
|
|
8767
|
+
try {
|
|
8768
|
+
await this.syncContracts({ contracts, pageSize });
|
|
8769
|
+
this.markSyncOnline();
|
|
8770
|
+
} catch (err) {
|
|
8771
|
+
if (!isRetryableProviderError(err)) throw err;
|
|
8772
|
+
this.markSyncDegraded(err);
|
|
8773
|
+
}
|
|
8185
8774
|
const vtxos = await this.getVtxosForContracts(contracts);
|
|
8186
8775
|
return contracts.map((contract) => ({
|
|
8187
8776
|
contract,
|
|
@@ -8419,15 +9008,33 @@ var ContractManager = class _ContractManager {
|
|
|
8419
9008
|
* Handle events from the watcher.
|
|
8420
9009
|
*/
|
|
8421
9010
|
async handleContractEvent(event) {
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
9011
|
+
try {
|
|
9012
|
+
switch (event.type) {
|
|
9013
|
+
// Delta-sync only the changed virtual outputs for this contract.
|
|
9014
|
+
case "vtxo_received":
|
|
9015
|
+
await this.syncContracts({ contracts: [event.contract] });
|
|
9016
|
+
this.markSyncOnline();
|
|
9017
|
+
break;
|
|
9018
|
+
case "vtxo_spent":
|
|
9019
|
+
await this.syncContracts({ contracts: [event.contract] });
|
|
9020
|
+
this.markSyncOnline();
|
|
9021
|
+
if (this.config.onVtxosSpent) {
|
|
9022
|
+
try {
|
|
9023
|
+
await this.config.onVtxosSpent(
|
|
9024
|
+
event.vtxos.map((v) => ({ txid: v.txid, vout: v.vout }))
|
|
9025
|
+
);
|
|
9026
|
+
} catch {
|
|
9027
|
+
}
|
|
9028
|
+
}
|
|
9029
|
+
break;
|
|
9030
|
+
case "connection_reset":
|
|
9031
|
+
await this.reconcileWatched();
|
|
9032
|
+
this.markSyncOnline();
|
|
9033
|
+
break;
|
|
9034
|
+
}
|
|
9035
|
+
} catch (err) {
|
|
9036
|
+
if (!isRetryableProviderError(err)) throw err;
|
|
9037
|
+
this.markSyncDegraded(err);
|
|
8431
9038
|
}
|
|
8432
9039
|
this.emitEvent(event);
|
|
8433
9040
|
}
|
|
@@ -8509,6 +9116,12 @@ var ContractManager = class _ContractManager {
|
|
|
8509
9116
|
contract,
|
|
8510
9117
|
filtered
|
|
8511
9118
|
);
|
|
9119
|
+
if (this.config.onVtxosPersisted) {
|
|
9120
|
+
try {
|
|
9121
|
+
await this.config.onVtxosPersisted(contract, filtered);
|
|
9122
|
+
} catch {
|
|
9123
|
+
}
|
|
9124
|
+
}
|
|
8512
9125
|
}
|
|
8513
9126
|
}
|
|
8514
9127
|
async fetchContractVxosFromIndexer(contracts, pageSize, syncWindow) {
|
|
@@ -8529,6 +9142,15 @@ var ContractManager = class _ContractManager {
|
|
|
8529
9142
|
contract,
|
|
8530
9143
|
filtered
|
|
8531
9144
|
);
|
|
9145
|
+
if (this.config.onVtxosPersisted) {
|
|
9146
|
+
try {
|
|
9147
|
+
await this.config.onVtxosPersisted(
|
|
9148
|
+
contract,
|
|
9149
|
+
filtered
|
|
9150
|
+
);
|
|
9151
|
+
} catch {
|
|
9152
|
+
}
|
|
9153
|
+
}
|
|
8532
9154
|
}
|
|
8533
9155
|
}
|
|
8534
9156
|
return result;
|
|
@@ -8607,6 +9229,8 @@ var HDDescriptorProvider = class _HDDescriptorProvider {
|
|
|
8607
9229
|
this.identity = identity;
|
|
8608
9230
|
this.walletRepository = walletRepository;
|
|
8609
9231
|
}
|
|
9232
|
+
identity;
|
|
9233
|
+
walletRepository;
|
|
8610
9234
|
/**
|
|
8611
9235
|
* Construct an HDDescriptorProvider. No I/O is performed here;
|
|
8612
9236
|
* persisted state is read lazily on the first call to
|
|
@@ -8799,6 +9423,7 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
|
|
|
8799
9423
|
this.currentTaggedScript = priorTaggedScript;
|
|
8800
9424
|
this.logger = logger ?? console;
|
|
8801
9425
|
}
|
|
9426
|
+
provider;
|
|
8802
9427
|
unsubscribe;
|
|
8803
9428
|
chain = Promise.resolve();
|
|
8804
9429
|
/**
|
|
@@ -9152,6 +9777,8 @@ var MissingSigningDescriptorError = class extends Error {
|
|
|
9152
9777
|
this.contractScript = contractScript;
|
|
9153
9778
|
this.contractType = contractType;
|
|
9154
9779
|
}
|
|
9780
|
+
contractScript;
|
|
9781
|
+
contractType;
|
|
9155
9782
|
name = "MissingSigningDescriptorError";
|
|
9156
9783
|
};
|
|
9157
9784
|
var DescriptorSigningProviderMissingError = class extends Error {
|
|
@@ -9167,6 +9794,7 @@ var InputSignerRouter = class {
|
|
|
9167
9794
|
constructor(deps) {
|
|
9168
9795
|
this.deps = deps;
|
|
9169
9796
|
}
|
|
9797
|
+
deps;
|
|
9170
9798
|
/**
|
|
9171
9799
|
* Resolve each job to its target signer without invoking signing. The
|
|
9172
9800
|
* returned plan is the single source of truth for both {@link sign} and
|
|
@@ -9385,6 +10013,14 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9385
10013
|
this._assetManager = new ReadonlyAssetManager(this.indexerProvider);
|
|
9386
10014
|
this.walletContractTimelocks = walletContractTimelocks && walletContractTimelocks.length > 0 ? dedupeTimelocks(walletContractTimelocks) : [this.offchainTapscript.options.csvTimelock];
|
|
9387
10015
|
}
|
|
10016
|
+
identity;
|
|
10017
|
+
network;
|
|
10018
|
+
onchainProvider;
|
|
10019
|
+
indexerProvider;
|
|
10020
|
+
dustAmount;
|
|
10021
|
+
walletRepository;
|
|
10022
|
+
contractRepository;
|
|
10023
|
+
delegateProvider;
|
|
9388
10024
|
_contractManager;
|
|
9389
10025
|
_contractManagerInitializing;
|
|
9390
10026
|
watcherConfig;
|
|
@@ -9402,6 +10038,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9402
10038
|
* (ContractManager isn't given it); `undefined` ⇒ no-op.
|
|
9403
10039
|
*/
|
|
9404
10040
|
virtualTxRepository;
|
|
10041
|
+
/** Opt-in exit-data capture settings; see {@link StorageConfig.exitDataCapture}. */
|
|
10042
|
+
exitDataCapture;
|
|
9405
10043
|
_assetManager;
|
|
9406
10044
|
walletContractTimelocks;
|
|
9407
10045
|
// Outpoints ("txid:vout") committed to an in-flight settle/send. Filtered
|
|
@@ -9444,6 +10082,72 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9444
10082
|
* construction-time snapshot for their lifetime.
|
|
9445
10083
|
*/
|
|
9446
10084
|
_arkServerPublicKey;
|
|
10085
|
+
/**
|
|
10086
|
+
* Whether this wallet was constructed from live operator server-info
|
|
10087
|
+
* (`"live"`) or from a cached snapshot because the operator was unreachable
|
|
10088
|
+
* (`"cache"`). Freshness signal for {@link getProviderConnectionState}.
|
|
10089
|
+
*/
|
|
10090
|
+
_serverInfoSource = "live";
|
|
10091
|
+
/**
|
|
10092
|
+
* Epoch-ms of the last known live operator contact: construction time on the
|
|
10093
|
+
* `live` boot path, the cached snapshot's `savedAt` on the `cache` path.
|
|
10094
|
+
*/
|
|
10095
|
+
_serverInfoLastOnlineAt;
|
|
10096
|
+
/** @see {@link _serverInfoSource} */
|
|
10097
|
+
get serverInfoSource() {
|
|
10098
|
+
return this._serverInfoSource;
|
|
10099
|
+
}
|
|
10100
|
+
/**
|
|
10101
|
+
* Composed provider-connection freshness: the boot server-info source
|
|
10102
|
+
* (Arkade) combined with the contract-manager's indexer-sync health, if the
|
|
10103
|
+
* manager has been initialized. Reads no live provider state — it never
|
|
10104
|
+
* forces a `ContractManager` to construct — so it is safe for readonly
|
|
10105
|
+
* callers that only use address/balance APIs.
|
|
10106
|
+
*
|
|
10107
|
+
* - Boot fell back to a cached snapshot → degraded on `arkade` (`cache`).
|
|
10108
|
+
* - Otherwise, if the contract manager has degraded to repository data →
|
|
10109
|
+
* degraded on `indexer` (`repository`).
|
|
10110
|
+
* - Otherwise online.
|
|
10111
|
+
*
|
|
10112
|
+
* This only describes sync freshness; wallet balances/VTXOs are always read
|
|
10113
|
+
* from the repository regardless of this state.
|
|
10114
|
+
*/
|
|
10115
|
+
getProviderConnectionState() {
|
|
10116
|
+
if (this._serverInfoSource === "cache") {
|
|
10117
|
+
return {
|
|
10118
|
+
mode: "degraded",
|
|
10119
|
+
source: "cache",
|
|
10120
|
+
provider: "arkade",
|
|
10121
|
+
reason: "constructed from cached server-info; operator was unreachable at boot",
|
|
10122
|
+
lastOnlineAt: this._serverInfoLastOnlineAt
|
|
10123
|
+
};
|
|
10124
|
+
}
|
|
10125
|
+
const sync = this._contractManager?.getSyncState();
|
|
10126
|
+
if (sync?.mode === "degraded") {
|
|
10127
|
+
return {
|
|
10128
|
+
mode: "degraded",
|
|
10129
|
+
source: "repository",
|
|
10130
|
+
provider: "indexer",
|
|
10131
|
+
reason: sync.reason,
|
|
10132
|
+
lastOnlineAt: sync.lastSyncedAt ?? this._serverInfoLastOnlineAt
|
|
10133
|
+
};
|
|
10134
|
+
}
|
|
10135
|
+
return {
|
|
10136
|
+
mode: "online",
|
|
10137
|
+
source: "live",
|
|
10138
|
+
lastOnlineAt: sync?.lastSyncedAt ?? this._serverInfoLastOnlineAt ?? 0
|
|
10139
|
+
};
|
|
10140
|
+
}
|
|
10141
|
+
/**
|
|
10142
|
+
* The contract-manager's current provider-sync health **without forcing it
|
|
10143
|
+
* to initialize** — reads the already-constructed manager, or reports
|
|
10144
|
+
* `online` when none exists yet. Unlike {@link getContractManager}, this
|
|
10145
|
+
* never triggers a remote sync, so it is safe on a pure diagnostics path
|
|
10146
|
+
* (e.g. the service-worker sync-state message).
|
|
10147
|
+
*/
|
|
10148
|
+
getContractSyncState() {
|
|
10149
|
+
return this._contractManager?.getSyncState() ?? { mode: "online" };
|
|
10150
|
+
}
|
|
9447
10151
|
/**
|
|
9448
10152
|
* x-only hex of the operator's deprecated signer keys (from
|
|
9449
10153
|
* `ArkInfo.deprecatedSigners`), cached for the OFFLINE read/watch paths.
|
|
@@ -9578,7 +10282,13 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9578
10282
|
}
|
|
9579
10283
|
indexerProvider = new RestIndexerProvider(indexerUrl);
|
|
9580
10284
|
}
|
|
9581
|
-
const
|
|
10285
|
+
const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
|
|
10286
|
+
const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
|
|
10287
|
+
const {
|
|
10288
|
+
info,
|
|
10289
|
+
source: serverInfoSource,
|
|
10290
|
+
lastOnlineAt: serverInfoLastOnlineAt
|
|
10291
|
+
} = await resolveArkInfo(arkProvider, walletRepository);
|
|
9582
10292
|
const network = getNetwork(info.network);
|
|
9583
10293
|
if ("descriptor" in config.identity) {
|
|
9584
10294
|
const descriptor = config.identity.descriptor;
|
|
@@ -9632,8 +10342,6 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9632
10342
|
serverPubKey: hex.encode(serverPubKey),
|
|
9633
10343
|
csvTimelock: timelockToSequence(boardingTimelock).toString()
|
|
9634
10344
|
});
|
|
9635
|
-
const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
|
|
9636
|
-
const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
|
|
9637
10345
|
return {
|
|
9638
10346
|
arkProvider,
|
|
9639
10347
|
indexerProvider,
|
|
@@ -9647,6 +10355,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9647
10355
|
walletRepository,
|
|
9648
10356
|
contractRepository,
|
|
9649
10357
|
info,
|
|
10358
|
+
serverInfoSource,
|
|
10359
|
+
serverInfoLastOnlineAt,
|
|
9650
10360
|
delegateProvider: config.delegateProvider || config.delegatorProvider,
|
|
9651
10361
|
/** @deprecated alias for `delegateProvider` */
|
|
9652
10362
|
delegatorProvider: config.delegateProvider || config.delegatorProvider,
|
|
@@ -9682,6 +10392,15 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9682
10392
|
);
|
|
9683
10393
|
wallet.intentRepository = config.storage?.intentRepository;
|
|
9684
10394
|
wallet.virtualTxRepository = config.storage?.virtualTxRepository;
|
|
10395
|
+
wallet.exitDataCapture = config.storage?.exitDataCapture;
|
|
10396
|
+
wallet._serverInfoSource = setup.serverInfoSource;
|
|
10397
|
+
if (setup.serverInfoSource === "live") {
|
|
10398
|
+
const now = Date.now();
|
|
10399
|
+
await saveValidatedArkInfoSnapshot(setup.walletRepository, setup.info, now);
|
|
10400
|
+
wallet._serverInfoLastOnlineAt = now;
|
|
10401
|
+
} else {
|
|
10402
|
+
wallet._serverInfoLastOnlineAt = setup.serverInfoLastOnlineAt;
|
|
10403
|
+
}
|
|
9685
10404
|
wallet.refreshDeprecatedSigners(setup.info);
|
|
9686
10405
|
return wallet;
|
|
9687
10406
|
}
|
|
@@ -9812,7 +10531,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9812
10531
|
const response = await contractManager.getContractsWithVtxos();
|
|
9813
10532
|
const allVtxos = response.flatMap((_) => _.vtxos);
|
|
9814
10533
|
const { boardingTxs, commitmentsToIgnore } = await this.getBoardingTxs();
|
|
9815
|
-
const getTxCreatedAt = (txid) => this.indexerProvider.getVtxos({ outpoints: [{ txid, vout: 0 }] }).then((res) => res.vtxos[0]?.createdAt.getTime())
|
|
10534
|
+
const getTxCreatedAt = (txid) => this.indexerProvider.getVtxos({ outpoints: [{ txid, vout: 0 }] }).then((res) => res.vtxos[0]?.createdAt.getTime()).catch((err) => {
|
|
10535
|
+
if (isRetryableProviderError(err)) return void 0;
|
|
10536
|
+
throw err;
|
|
10537
|
+
});
|
|
9816
10538
|
return buildTransactionHistory(allVtxos, boardingTxs, commitmentsToIgnore, getTxCreatedAt);
|
|
9817
10539
|
}
|
|
9818
10540
|
/**
|
|
@@ -10231,11 +10953,39 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
10231
10953
|
}
|
|
10232
10954
|
}
|
|
10233
10955
|
async initializeContractManager() {
|
|
10956
|
+
const virtualTxRepository = this.virtualTxRepository;
|
|
10957
|
+
let onVtxosPersisted;
|
|
10958
|
+
let onVtxosSpent;
|
|
10959
|
+
if (virtualTxRepository) {
|
|
10960
|
+
const capture = this.exitDataCapture;
|
|
10961
|
+
const resolver = createExitChainResolver({
|
|
10962
|
+
indexer: this.indexerProvider,
|
|
10963
|
+
repository: virtualTxRepository,
|
|
10964
|
+
extraSources: capture?.sources
|
|
10965
|
+
});
|
|
10966
|
+
onVtxosPersisted = async (_contract, vtxos) => {
|
|
10967
|
+
for (const v of vtxos) {
|
|
10968
|
+
if (v.virtualStatus.state === "spent") continue;
|
|
10969
|
+
await captureExitBranch({
|
|
10970
|
+
resolver,
|
|
10971
|
+
repository: virtualTxRepository,
|
|
10972
|
+
vtxo: { txid: v.txid, vout: v.vout },
|
|
10973
|
+
value: v.value,
|
|
10974
|
+
mode: capture?.mode ?? DEFAULT_EXIT_CAPTURE_MODE,
|
|
10975
|
+
minExitWorthSats: capture?.minExitWorthSats ?? DEFAULT_MIN_EXIT_WORTH_SATS
|
|
10976
|
+
}).catch(() => {
|
|
10977
|
+
});
|
|
10978
|
+
}
|
|
10979
|
+
};
|
|
10980
|
+
onVtxosSpent = (vtxos) => pruneExitBranches(virtualTxRepository, vtxos);
|
|
10981
|
+
}
|
|
10234
10982
|
const manager = await ContractManager.create({
|
|
10235
10983
|
indexerProvider: this.indexerProvider,
|
|
10236
10984
|
contractRepository: this.contractRepository,
|
|
10237
10985
|
walletRepository: this.walletRepository,
|
|
10238
10986
|
intentRepository: this.intentRepository,
|
|
10987
|
+
onVtxosPersisted,
|
|
10988
|
+
onVtxosSpent,
|
|
10239
10989
|
watcherConfig: this.watcherConfig
|
|
10240
10990
|
});
|
|
10241
10991
|
const baselinePubkey = await this.identity.xOnlyPublicKey();
|
|
@@ -10377,6 +11127,9 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
10377
11127
|
boardingPkScript: boardingTapscript.pkScript
|
|
10378
11128
|
});
|
|
10379
11129
|
}
|
|
11130
|
+
arkProvider;
|
|
11131
|
+
forfeitOutputScript;
|
|
11132
|
+
forfeitPubkey;
|
|
10380
11133
|
static MIN_FEE_RATE = 1;
|
|
10381
11134
|
// sats/vbyte
|
|
10382
11135
|
identity;
|
|
@@ -10910,6 +11663,14 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
10910
11663
|
boot?.rotator,
|
|
10911
11664
|
boot?.provider
|
|
10912
11665
|
);
|
|
11666
|
+
wallet._serverInfoSource = setup.serverInfoSource;
|
|
11667
|
+
if (setup.serverInfoSource === "live") {
|
|
11668
|
+
const now = Date.now();
|
|
11669
|
+
await saveValidatedArkInfoSnapshot(setup.walletRepository, setup.info, now);
|
|
11670
|
+
wallet._serverInfoLastOnlineAt = now;
|
|
11671
|
+
} else {
|
|
11672
|
+
wallet._serverInfoLastOnlineAt = setup.serverInfoLastOnlineAt;
|
|
11673
|
+
}
|
|
10913
11674
|
wallet.refreshDeprecatedSigners(setup.info);
|
|
10914
11675
|
{
|
|
10915
11676
|
const ap = setup.arkProvider;
|
|
@@ -10931,6 +11692,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
10931
11692
|
}
|
|
10932
11693
|
wallet.intentRepository = config.storage?.intentRepository;
|
|
10933
11694
|
wallet.virtualTxRepository = config.storage?.virtualTxRepository;
|
|
11695
|
+
wallet.exitDataCapture = config.storage?.exitDataCapture;
|
|
10934
11696
|
await wallet.getVtxoManager();
|
|
10935
11697
|
return wallet;
|
|
10936
11698
|
}
|
|
@@ -11132,7 +11894,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
11132
11894
|
script: offchainOutputScript
|
|
11133
11895
|
});
|
|
11134
11896
|
output.amount -= BigInt(outputFee.satoshis);
|
|
11135
|
-
if (output.amount
|
|
11897
|
+
if (isSubdust(output.amount, this.dustAmount)) {
|
|
11136
11898
|
throw new Error("Output amount is below dust limit");
|
|
11137
11899
|
}
|
|
11138
11900
|
params = {
|
|
@@ -11380,7 +12142,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
11380
12142
|
}
|
|
11381
12143
|
continue;
|
|
11382
12144
|
}
|
|
11383
|
-
if (isRecoverable(input) || isSubdust(input, this.dustAmount)) {
|
|
12145
|
+
if (isRecoverable(input) || isSubdust({ value: input.value }, this.dustAmount)) {
|
|
11384
12146
|
continue;
|
|
11385
12147
|
}
|
|
11386
12148
|
if (connectorsLeaves.length === 0) {
|
|
@@ -12459,6 +13221,8 @@ var MessageBus = class {
|
|
|
12459
13221
|
this.debug = debug;
|
|
12460
13222
|
this.buildServicesFn = buildServices ?? this.buildServices.bind(this);
|
|
12461
13223
|
}
|
|
13224
|
+
walletRepository;
|
|
13225
|
+
contractRepository;
|
|
12462
13226
|
handlers;
|
|
12463
13227
|
tickIntervalMs;
|
|
12464
13228
|
messageTimeoutMs;
|
|
@@ -12960,6 +13724,7 @@ var Ramps = class {
|
|
|
12960
13724
|
constructor(wallet) {
|
|
12961
13725
|
this.wallet = wallet;
|
|
12962
13726
|
}
|
|
13727
|
+
wallet;
|
|
12963
13728
|
/**
|
|
12964
13729
|
* Onboard boarding inputs.
|
|
12965
13730
|
*
|
|
@@ -13448,10 +14213,18 @@ var WalletMessageHandler = class {
|
|
|
13448
14213
|
type: "WALLET_STATUS",
|
|
13449
14214
|
payload: {
|
|
13450
14215
|
walletInitialized: true,
|
|
13451
|
-
xOnlyPublicKey: pubKey
|
|
14216
|
+
xOnlyPublicKey: pubKey,
|
|
14217
|
+
providerConnectionState: this.readonlyWallet.getProviderConnectionState()
|
|
13452
14218
|
}
|
|
13453
14219
|
});
|
|
13454
14220
|
}
|
|
14221
|
+
case "GET_CONTRACT_SYNC_STATE": {
|
|
14222
|
+
return this.tagged({
|
|
14223
|
+
id,
|
|
14224
|
+
type: "CONTRACT_SYNC_STATE",
|
|
14225
|
+
payload: { syncState: this.readonlyWallet.getContractSyncState() }
|
|
14226
|
+
});
|
|
14227
|
+
}
|
|
13455
14228
|
case "CLEAR": {
|
|
13456
14229
|
await this.clear();
|
|
13457
14230
|
return this.tagged({
|
|
@@ -14214,6 +14987,7 @@ var DEFAULT_MESSAGE_TIMEOUTS = {
|
|
|
14214
14987
|
GET_BALANCE: 1e4,
|
|
14215
14988
|
GET_BOARDING_ADDRESS: 1e4,
|
|
14216
14989
|
GET_STATUS: 1e4,
|
|
14990
|
+
GET_CONTRACT_SYNC_STATE: 1e4,
|
|
14217
14991
|
GET_DELEGATE_INFO: 1e4,
|
|
14218
14992
|
IS_CONTRACT_MANAGER_WATCHING: 1e4,
|
|
14219
14993
|
// Medium reads — may involve indexer queries
|
|
@@ -14297,6 +15071,8 @@ var ServiceWorkerReadonlyAssetManager = class {
|
|
|
14297
15071
|
this.sendMessage = sendMessage;
|
|
14298
15072
|
this.messageTag = messageTag;
|
|
14299
15073
|
}
|
|
15074
|
+
sendMessage;
|
|
15075
|
+
messageTag;
|
|
14300
15076
|
async getAssetDetails(assetId) {
|
|
14301
15077
|
const message = {
|
|
14302
15078
|
tag: this.messageTag,
|
|
@@ -14381,6 +15157,8 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
14381
15157
|
messageTag
|
|
14382
15158
|
);
|
|
14383
15159
|
}
|
|
15160
|
+
serviceWorker;
|
|
15161
|
+
messageTag;
|
|
14384
15162
|
walletRepository;
|
|
14385
15163
|
contractRepository;
|
|
14386
15164
|
identity;
|
|
@@ -14822,6 +15600,19 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
14822
15600
|
throw new Error(`Failed to get status: ${error}`);
|
|
14823
15601
|
}
|
|
14824
15602
|
}
|
|
15603
|
+
/**
|
|
15604
|
+
* Wallet-level provider-connection freshness, delegated to the worker via
|
|
15605
|
+
* `GET_STATUS`. Async by necessity (the worker boundary is asynchronous); no
|
|
15606
|
+
* synchronous variant is offered because it would have the same transport
|
|
15607
|
+
* mismatch as the contract-manager proxy's cached `getSyncState()`.
|
|
15608
|
+
*/
|
|
15609
|
+
async getProviderConnectionState() {
|
|
15610
|
+
const { providerConnectionState } = await this.getStatus();
|
|
15611
|
+
if (!providerConnectionState) {
|
|
15612
|
+
throw new Error("Worker did not report provider connection state");
|
|
15613
|
+
}
|
|
15614
|
+
return providerConnectionState;
|
|
15615
|
+
}
|
|
14825
15616
|
async getActivityHistory() {
|
|
14826
15617
|
return buildActivities(await this.getTransactionHistory(), this.activity.all());
|
|
14827
15618
|
}
|
|
@@ -14876,6 +15667,32 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
14876
15667
|
return wallet.sendMessage(message);
|
|
14877
15668
|
};
|
|
14878
15669
|
const messageTag = this.messageTag;
|
|
15670
|
+
const fetchSyncState = async () => {
|
|
15671
|
+
const message = {
|
|
15672
|
+
type: "GET_CONTRACT_SYNC_STATE",
|
|
15673
|
+
id: getRandomId(),
|
|
15674
|
+
tag: messageTag
|
|
15675
|
+
};
|
|
15676
|
+
const response = await sendContractMessage(message);
|
|
15677
|
+
return response.payload.syncState;
|
|
15678
|
+
};
|
|
15679
|
+
const UNKNOWN_STATE = {
|
|
15680
|
+
mode: "degraded",
|
|
15681
|
+
reason: "contract sync state unavailable from the worker"
|
|
15682
|
+
};
|
|
15683
|
+
let syncState = UNKNOWN_STATE;
|
|
15684
|
+
let everProbed = false;
|
|
15685
|
+
const refreshSyncState = async () => {
|
|
15686
|
+
try {
|
|
15687
|
+
syncState = await fetchSyncState();
|
|
15688
|
+
everProbed = true;
|
|
15689
|
+
} catch {
|
|
15690
|
+
if (!everProbed) {
|
|
15691
|
+
syncState = UNKNOWN_STATE;
|
|
15692
|
+
}
|
|
15693
|
+
}
|
|
15694
|
+
};
|
|
15695
|
+
await refreshSyncState();
|
|
14879
15696
|
const manager = {
|
|
14880
15697
|
async createContract(params) {
|
|
14881
15698
|
const message = {
|
|
@@ -14886,6 +15703,7 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
14886
15703
|
};
|
|
14887
15704
|
try {
|
|
14888
15705
|
const response = await sendContractMessage(message);
|
|
15706
|
+
await refreshSyncState();
|
|
14889
15707
|
return response.payload.contract;
|
|
14890
15708
|
} catch (e) {
|
|
14891
15709
|
throw new Error("Failed to create contract");
|
|
@@ -14914,11 +15732,15 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
14914
15732
|
};
|
|
14915
15733
|
try {
|
|
14916
15734
|
const response = await sendContractMessage(message);
|
|
15735
|
+
await refreshSyncState();
|
|
14917
15736
|
return response.payload.contracts;
|
|
14918
15737
|
} catch (e) {
|
|
14919
15738
|
throw new Error("Failed to get contracts with vtxos");
|
|
14920
15739
|
}
|
|
14921
15740
|
},
|
|
15741
|
+
getSyncState() {
|
|
15742
|
+
return syncState;
|
|
15743
|
+
},
|
|
14922
15744
|
async annotateVtxos(vtxos) {
|
|
14923
15745
|
if (vtxos.length === 0) return [];
|
|
14924
15746
|
const message = {
|
|
@@ -15027,7 +15849,11 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
15027
15849
|
tag: messageTag,
|
|
15028
15850
|
payload: opts
|
|
15029
15851
|
};
|
|
15030
|
-
|
|
15852
|
+
try {
|
|
15853
|
+
await sendContractMessage(message);
|
|
15854
|
+
} finally {
|
|
15855
|
+
await refreshSyncState();
|
|
15856
|
+
}
|
|
15031
15857
|
},
|
|
15032
15858
|
async refreshOutpoints(outpoints) {
|
|
15033
15859
|
const message = {
|
|
@@ -15036,7 +15862,11 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
15036
15862
|
tag: messageTag,
|
|
15037
15863
|
payload: { outpoints }
|
|
15038
15864
|
};
|
|
15039
|
-
|
|
15865
|
+
try {
|
|
15866
|
+
await sendContractMessage(message);
|
|
15867
|
+
} finally {
|
|
15868
|
+
await refreshSyncState();
|
|
15869
|
+
}
|
|
15040
15870
|
},
|
|
15041
15871
|
scanContracts() {
|
|
15042
15872
|
return Promise.reject(
|
|
@@ -15081,6 +15911,7 @@ var ServiceWorkerWallet = class _ServiceWorkerWallet extends ServiceWorkerReadon
|
|
|
15081
15911
|
);
|
|
15082
15912
|
this.hasDelegate = hasDelegate;
|
|
15083
15913
|
}
|
|
15914
|
+
serviceWorker;
|
|
15084
15915
|
walletRepository;
|
|
15085
15916
|
contractRepository;
|
|
15086
15917
|
identity;
|
|
@@ -15462,6 +16293,7 @@ var OnchainWallet = class _OnchainWallet {
|
|
|
15462
16293
|
this.onchainP2TR = onchainP2TR;
|
|
15463
16294
|
this.provider = provider;
|
|
15464
16295
|
}
|
|
16296
|
+
identity;
|
|
15465
16297
|
static MIN_FEE_RATE = 1;
|
|
15466
16298
|
// sat/vbyte
|
|
15467
16299
|
onchainP2TR;
|
|
@@ -15763,6 +16595,8 @@ var WsElectrumChainSource = class {
|
|
|
15763
16595
|
this.ws = ws;
|
|
15764
16596
|
this.network = network;
|
|
15765
16597
|
}
|
|
16598
|
+
ws;
|
|
16599
|
+
network;
|
|
15766
16600
|
// Cached chain tip kept fresh by the headers subscription. Initialized
|
|
15767
16601
|
// lazily on first call to subscribeHeaders().
|
|
15768
16602
|
cachedTip = null;
|
|
@@ -16045,6 +16879,8 @@ var ElectrumOnchainProvider = class {
|
|
|
16045
16879
|
this.network = network;
|
|
16046
16880
|
this.chain = new WsElectrumChainSource(ws, network);
|
|
16047
16881
|
}
|
|
16882
|
+
ws;
|
|
16883
|
+
network;
|
|
16048
16884
|
chain;
|
|
16049
16885
|
async getCoins(address) {
|
|
16050
16886
|
const script = this.encodeAddress(address);
|
|
@@ -16598,6 +17434,7 @@ var ExitPathError = class extends Error {
|
|
|
16598
17434
|
this.reason = reason;
|
|
16599
17435
|
this.name = "ExitPathError";
|
|
16600
17436
|
}
|
|
17437
|
+
reason;
|
|
16601
17438
|
};
|
|
16602
17439
|
function delayWeight(sequence) {
|
|
16603
17440
|
const t = sequenceToTimelock(sequence);
|
|
@@ -16651,7 +17488,7 @@ async function resolveUnilateralPath(params) {
|
|
|
16651
17488
|
}
|
|
16652
17489
|
|
|
16653
17490
|
// src/wallet/unroll.ts
|
|
16654
|
-
function
|
|
17491
|
+
function chainTxTypeToChainedExit2(t) {
|
|
16655
17492
|
switch (t) {
|
|
16656
17493
|
case "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */:
|
|
16657
17494
|
return 1 /* Commitment */;
|
|
@@ -16681,6 +17518,11 @@ var Unroll;
|
|
|
16681
17518
|
this.indexer = indexer;
|
|
16682
17519
|
this.virtualTxRepository = virtualTxRepository;
|
|
16683
17520
|
}
|
|
17521
|
+
toUnroll;
|
|
17522
|
+
bumper;
|
|
17523
|
+
explorer;
|
|
17524
|
+
indexer;
|
|
17525
|
+
virtualTxRepository;
|
|
16684
17526
|
/** Create an unroll session by loading the virtual output chain from the indexer. */
|
|
16685
17527
|
static async create(toUnroll, bumper, explorer, indexer, virtualTxRepository) {
|
|
16686
17528
|
const { chain } = await indexer.getVtxoChain(toUnroll);
|
|
@@ -16714,7 +17556,7 @@ var Unroll;
|
|
|
16714
17556
|
txid: next.txid,
|
|
16715
17557
|
psbt,
|
|
16716
17558
|
expiresAt: null,
|
|
16717
|
-
type:
|
|
17559
|
+
type: chainTxTypeToChainedExit2(next.type)
|
|
16718
17560
|
};
|
|
16719
17561
|
try {
|
|
16720
17562
|
await repo.upsertVirtualTxs([cached]);
|
|
@@ -16892,99 +17734,6 @@ function doWait(onchainProvider, txid) {
|
|
|
16892
17734
|
});
|
|
16893
17735
|
};
|
|
16894
17736
|
}
|
|
16895
|
-
|
|
16896
|
-
// src/wallet/exit/chain.ts
|
|
16897
|
-
var isCommitment = (t) => t === "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */ || t === "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
|
|
16898
|
-
async function buildExitDag(params) {
|
|
16899
|
-
const byTxid = /* @__PURE__ */ new Map();
|
|
16900
|
-
for (const vtxo of params.vtxos) {
|
|
16901
|
-
const outpoint = `${vtxo.txid}:${vtxo.vout}`;
|
|
16902
|
-
let pageIndex = 0;
|
|
16903
|
-
let hasMore = true;
|
|
16904
|
-
while (hasMore) {
|
|
16905
|
-
const { chain, page } = await params.indexer.getVtxoChain(
|
|
16906
|
-
{ txid: vtxo.txid, vout: vtxo.vout },
|
|
16907
|
-
{ pageIndex, pageSize: DEFAULT_PAGE_SIZE }
|
|
16908
|
-
);
|
|
16909
|
-
for (const chainTx of chain) {
|
|
16910
|
-
const existing = byTxid.get(chainTx.txid);
|
|
16911
|
-
if (existing) {
|
|
16912
|
-
existing.forVtxos.add(outpoint);
|
|
16913
|
-
} else {
|
|
16914
|
-
byTxid.set(chainTx.txid, { ...chainTx, forVtxos: /* @__PURE__ */ new Set([outpoint]) });
|
|
16915
|
-
}
|
|
16916
|
-
}
|
|
16917
|
-
hasMore = page ? chain.length === DEFAULT_PAGE_SIZE : false;
|
|
16918
|
-
pageIndex++;
|
|
16919
|
-
}
|
|
16920
|
-
}
|
|
16921
|
-
const pending = new Map(
|
|
16922
|
-
[...byTxid.values()].filter((tx) => !isCommitment(tx.type)).map((tx) => [tx.txid, tx])
|
|
16923
|
-
);
|
|
16924
|
-
const inDegree = /* @__PURE__ */ new Map();
|
|
16925
|
-
for (const tx of pending.values()) {
|
|
16926
|
-
const parents = tx.spends.filter((p) => pending.has(p));
|
|
16927
|
-
inDegree.set(tx.txid, parents.length);
|
|
16928
|
-
}
|
|
16929
|
-
const order = [];
|
|
16930
|
-
const queue = [...pending.values()].filter((tx) => inDegree.get(tx.txid) === 0).sort((a, b) => a.txid.localeCompare(b.txid));
|
|
16931
|
-
while (queue.length > 0) {
|
|
16932
|
-
const tx = queue.shift();
|
|
16933
|
-
order.push(tx);
|
|
16934
|
-
const children = [...pending.values()].filter((c) => c.spends.includes(tx.txid)).sort((a, b) => a.txid.localeCompare(b.txid));
|
|
16935
|
-
for (const child of children) {
|
|
16936
|
-
const deg = inDegree.get(child.txid) - 1;
|
|
16937
|
-
inDegree.set(child.txid, deg);
|
|
16938
|
-
if (deg === 0) queue.push(child);
|
|
16939
|
-
}
|
|
16940
|
-
}
|
|
16941
|
-
if (order.length !== pending.size) {
|
|
16942
|
-
throw new Error("inconsistent vtxo chain from indexer (cycle detected)");
|
|
16943
|
-
}
|
|
16944
|
-
const nodes = [];
|
|
16945
|
-
for (const tx of order) {
|
|
16946
|
-
let confirmed = false;
|
|
16947
|
-
try {
|
|
16948
|
-
const status = await params.onchain.getTxStatus(tx.txid);
|
|
16949
|
-
confirmed = status.confirmed;
|
|
16950
|
-
} catch {
|
|
16951
|
-
confirmed = false;
|
|
16952
|
-
}
|
|
16953
|
-
const expires = Number(tx.expiresAt);
|
|
16954
|
-
nodes.push({
|
|
16955
|
-
txid: tx.txid,
|
|
16956
|
-
type: tx.type,
|
|
16957
|
-
expiresAt: Number.isFinite(expires) && expires > 0 ? expires : void 0,
|
|
16958
|
-
forVtxos: [...tx.forVtxos].sort(),
|
|
16959
|
-
confirmed
|
|
16960
|
-
});
|
|
16961
|
-
}
|
|
16962
|
-
return nodes;
|
|
16963
|
-
}
|
|
16964
|
-
function topoSortByDeps(items, idOf, depsOf) {
|
|
16965
|
-
const produced = new Set(items.map(idOf));
|
|
16966
|
-
const emitted = /* @__PURE__ */ new Set();
|
|
16967
|
-
const ordered = [];
|
|
16968
|
-
let remaining = items;
|
|
16969
|
-
while (remaining.length > 0) {
|
|
16970
|
-
const next = [];
|
|
16971
|
-
let progress = false;
|
|
16972
|
-
for (const item of remaining) {
|
|
16973
|
-
if (depsOf(item).every((d) => !produced.has(d) || emitted.has(d))) {
|
|
16974
|
-
ordered.push(item);
|
|
16975
|
-
emitted.add(idOf(item));
|
|
16976
|
-
progress = true;
|
|
16977
|
-
} else {
|
|
16978
|
-
next.push(item);
|
|
16979
|
-
}
|
|
16980
|
-
}
|
|
16981
|
-
if (!progress) {
|
|
16982
|
-
throw new Error("topological sort: cycle or unsatisfiable dependency");
|
|
16983
|
-
}
|
|
16984
|
-
remaining = next;
|
|
16985
|
-
}
|
|
16986
|
-
return ordered;
|
|
16987
|
-
}
|
|
16988
17737
|
function extraWitnessSize(path) {
|
|
16989
17738
|
return (path.extraWitness ?? []).reduce((sum, item) => sum + 1 + item.length, 0);
|
|
16990
17739
|
}
|
|
@@ -17091,27 +17840,22 @@ async function computeExitLayout(opts, feeRate) {
|
|
|
17091
17840
|
const { wallet, onchainWallet } = opts;
|
|
17092
17841
|
const vtxos = await selectExitVtxos(opts);
|
|
17093
17842
|
if (vtxos.length === 0) throw new Error("no vtxos to exit");
|
|
17843
|
+
const resolver = createExitChainResolver({
|
|
17844
|
+
indexer: wallet.indexerProvider,
|
|
17845
|
+
repository: wallet.virtualTxRepository,
|
|
17846
|
+
extraSources: wallet.exitDataCapture?.sources
|
|
17847
|
+
});
|
|
17094
17848
|
const dag = await buildExitDag({
|
|
17095
17849
|
vtxos,
|
|
17096
|
-
|
|
17850
|
+
chain: resolver,
|
|
17097
17851
|
onchain: wallet.onchainProvider
|
|
17098
17852
|
});
|
|
17099
17853
|
const pendingNodes = dag.filter((n) => !n.confirmed);
|
|
17100
17854
|
const psbts = /* @__PURE__ */ new Map();
|
|
17101
17855
|
if (pendingNodes.length > 0) {
|
|
17102
|
-
const
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
while (hasMore) {
|
|
17106
|
-
const { txs, page } = await wallet.indexerProvider.getVirtualTxs(txids, {
|
|
17107
|
-
pageIndex,
|
|
17108
|
-
pageSize: DEFAULT_PAGE_SIZE
|
|
17109
|
-
});
|
|
17110
|
-
for (const psbt of txs) {
|
|
17111
|
-
psbts.set(Transaction.fromPSBT(base64.decode(psbt)).id, psbt);
|
|
17112
|
-
}
|
|
17113
|
-
hasMore = page ? txs.length === DEFAULT_PAGE_SIZE : false;
|
|
17114
|
-
pageIndex++;
|
|
17856
|
+
const txs = await resolver.getVirtualTxs(pendingNodes.map((n) => n.txid));
|
|
17857
|
+
for (const psbt of txs) {
|
|
17858
|
+
psbts.set(Transaction.fromPSBT(base64.decode(psbt)).id, psbt);
|
|
17115
17859
|
}
|
|
17116
17860
|
}
|
|
17117
17861
|
const childVsize = Number(
|
|
@@ -17259,6 +18003,8 @@ var Executor = class {
|
|
|
17259
18003
|
this.pollIntervalMs = opts?.pollIntervalMs ?? 5e3;
|
|
17260
18004
|
this.feeWallet = opts?.feeWallet;
|
|
17261
18005
|
}
|
|
18006
|
+
pkg;
|
|
18007
|
+
provider;
|
|
17262
18008
|
pollIntervalMs;
|
|
17263
18009
|
feeWallet;
|
|
17264
18010
|
sleep() {
|
|
@@ -17754,6 +18500,6 @@ function isArkContract(str) {
|
|
|
17754
18500
|
return str.startsWith(ARKCONTRACT_PREFIX + "=");
|
|
17755
18501
|
}
|
|
17756
18502
|
|
|
17757
|
-
export { ActivityRegistry, ArkNote, AssetManager, BIP322, Batch, ChainedTxType, ContractManager, ContractRepositoryImpl, ContractWatcher, DB_VERSION, DEFAULT_MESSAGE_TIMEOUTS, DelegateManagerImpl, DelegateNotConfiguredError, DelegatorManagerImpl, DelegatorNotConfiguredError, DescriptorSigningProviderMissingError, DustChangeError, ELECTRUM_TCP_HOST, ELECTRUM_WS_URL, ESPLORA_URL, ElectrumOnchainProvider, EsploraProvider, Estimator, HDDescriptorProvider, INTENT_TERMINAL_STATES, InMemoryContractRepository, InMemoryIntentRepository, InMemoryVirtualTxRepository, InMemoryWalletRepository, IndexedDBContractRepository, IndexedDBIntentRepository, IndexedDBVirtualTxRepository, IndexedDBWalletRepository, MESSAGE_BUS_INITIALIZING, MESSAGE_BUS_NOT_INITIALIZED, MIGRATION_KEY, MessageBus, MessageBusInitializingError, MessageBusNotInitializedError, MissingSigningDescriptorError, MnemonicIdentity, OnchainWallet, P2A, Ramps, ReadonlyAssetManager, ReadonlyDescriptorIdentity, ReadonlySingleKey, ReadonlyWallet, ReadonlyWalletError, RestDelegateProvider, RestDelegatorProvider, SeedIdentity, ServiceWorkerReadonlyWallet, ServiceWorkerTimeoutError, ServiceWorkerWallet, SingleKey, TxTree, TxType, TxWeightEstimator, UnilateralExit, Unroll, VtxoManager, Wallet2 as Wallet, WalletMessageHandler, WalletNotInitializedError, WalletRepositoryImpl, WsElectrumChainSource, assertIntentIdUnique, boardingResolver, buildForfeitTx, buildOffchainTx, classifyAgainstSignerSet, classifyContractSigner, closeDatabase, combineTapscriptSigs, contractFromArkContract, contractFromArkContractWithAddress, createDefaultActivityRegistry, decodeArkContract, deserializeAssets, deserializeExitPackage, deserializeUtxo, deserializeVtxo, encodeArkContract, extendVirtualCoinForContract, getMigrationStatus, getRandomId, hasBoardingTxExpired, intentMatchesFilter, intentPageBounds, isArkContract, isBatchSignable, isCooperativelyMigratable, isDiscoverable, isExpired, isRecoverable, isSpendable, isSubdust, isTerminalIntentState, isValidArkAddress, isVtxoExpiringSoon, isVtxoForScript, mergeChainedTxType, migrateWalletRepository, openDatabase, requiresMigration, rollbackMigration, saveVtxosForContract, scriptFromArkAddress, serializeAssets, serializeExitPackage, serializeUtxo, serializeVtxo, setupServiceWorker, signerSetFromInfo, toXOnlySignerHex, validateConnectorsTxGraph, validateVtxoTxGraph, verifyTapscriptSignatures, waitForIncomingFunds, warnAndFilterVtxosForScript };
|
|
17758
|
-
//# sourceMappingURL=chunk-
|
|
17759
|
-
//# sourceMappingURL=chunk-
|
|
18503
|
+
export { ActivityRegistry, ArkNote, AssetManager, BIP322, Batch, ChainedTxType, ContractManager, ContractRepositoryImpl, ContractWatcher, DB_VERSION, DEFAULT_MESSAGE_TIMEOUTS, DelegateManagerImpl, DelegateNotConfiguredError, DelegatorManagerImpl, DelegatorNotConfiguredError, DescriptorSigningProviderMissingError, DustChangeError, ELECTRUM_TCP_HOST, ELECTRUM_WS_URL, ESPLORA_URL, ElectrumOnchainProvider, EsploraProvider, Estimator, HDDescriptorProvider, INTENT_TERMINAL_STATES, InMemoryContractRepository, InMemoryIntentRepository, InMemoryVirtualTxRepository, InMemoryWalletRepository, IndexedDBContractRepository, IndexedDBIntentRepository, IndexedDBVirtualTxRepository, IndexedDBWalletRepository, MESSAGE_BUS_INITIALIZING, MESSAGE_BUS_NOT_INITIALIZED, MIGRATION_KEY, MessageBus, MessageBusInitializingError, MessageBusNotInitializedError, MissingSigningDescriptorError, MnemonicIdentity, OnchainWallet, P2A, Ramps, ReadonlyAssetManager, ReadonlyDescriptorIdentity, ReadonlySingleKey, ReadonlyWallet, ReadonlyWalletError, RestDelegateProvider, RestDelegatorProvider, SeedIdentity, ServiceWorkerReadonlyWallet, ServiceWorkerTimeoutError, ServiceWorkerWallet, SingleKey, TxTree, TxType, TxWeightEstimator, UnilateralExit, Unroll, VtxoManager, Wallet2 as Wallet, WalletMessageHandler, WalletNotInitializedError, WalletRepositoryImpl, WsElectrumChainSource, assertIntentIdUnique, boardingResolver, buildForfeitTx, buildOffchainTx, classifyAgainstSignerSet, classifyContractSigner, closeDatabase, combineTapscriptSigs, contractFromArkContract, contractFromArkContractWithAddress, createDefaultActivityRegistry, createExitChainResolver, decodeArkContract, deserializeAssets, deserializeExitPackage, deserializeUtxo, deserializeVtxo, encodeArkContract, extendVirtualCoinForContract, getMigrationStatus, getRandomId, hasBoardingTxExpired, intentMatchesFilter, intentPageBounds, isArkContract, isBatchSignable, isCooperativelyMigratable, isDiscoverable, isExpired, isRecoverable, isRetryableProviderError, isSpendable, isSubdust, isTerminalIntentState, isValidArkAddress, isVtxoExpiringSoon, isVtxoForScript, mergeChainedTxType, migrateWalletRepository, openDatabase, requiresMigration, rollbackMigration, saveVtxosForContract, scriptFromArkAddress, serializeAssets, serializeExitPackage, serializeUtxo, serializeVtxo, setupServiceWorker, signerSetFromInfo, toXOnlySignerHex, validateConnectorsTxGraph, validateVtxoTxGraph, verifyTapscriptSignatures, waitForIncomingFunds, warnAndFilterVtxosForScript };
|
|
18504
|
+
//# sourceMappingURL=chunk-P6VBP3CT.js.map
|
|
18505
|
+
//# sourceMappingURL=chunk-P6VBP3CT.js.map
|