@arkade-os/sdk 0.4.43 → 0.4.45
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 +100 -0
- package/dist/adapters/expo.cjs +4 -4
- package/dist/adapters/expo.d.cts +2 -2
- package/dist/adapters/expo.d.ts +2 -2
- package/dist/adapters/expo.js +2 -2
- package/dist/adapters/indexedDB.cjs +3 -3
- package/dist/adapters/indexedDB.js +2 -2
- package/dist/{ark-I8jfe5VE.d.cts → ark-C-PjOngm.d.cts} +89 -1
- package/dist/{ark-I8jfe5VE.d.ts → ark-C-PjOngm.d.ts} +89 -1
- package/dist/{asyncStorageTaskQueue-D1FfHfgK.d.cts → asyncStorageTaskQueue-BmBPvTyh.d.cts} +1 -1
- package/dist/{asyncStorageTaskQueue-CjoL-35w.d.ts → asyncStorageTaskQueue-CHpI3moJ.d.ts} +1 -1
- package/dist/{chunk-VKKLOT2E.js → chunk-BOA4SHCD.js} +3 -3
- package/dist/{chunk-VKKLOT2E.js.map → chunk-BOA4SHCD.js.map} +1 -1
- package/dist/{chunk-PLJZRIFZ.cjs → chunk-HZ7VIN7P.cjs} +11 -11
- package/dist/{chunk-PLJZRIFZ.cjs.map → chunk-HZ7VIN7P.cjs.map} +1 -1
- package/dist/{chunk-JIWCE2IK.cjs → chunk-OFQGANH2.cjs} +7 -7
- package/dist/{chunk-JIWCE2IK.cjs.map → chunk-OFQGANH2.cjs.map} +1 -1
- package/dist/{chunk-US274KZO.js → chunk-QZ6HZZZK.js} +3 -3
- package/dist/{chunk-US274KZO.js.map → chunk-QZ6HZZZK.js.map} +1 -1
- package/dist/{chunk-QGNTDGMN.cjs → chunk-SRCWBFSZ.cjs} +1945 -357
- package/dist/chunk-SRCWBFSZ.cjs.map +1 -0
- package/dist/{chunk-B4R36PRN.js → chunk-TGRJ5WAX.js} +1868 -285
- package/dist/chunk-TGRJ5WAX.js.map +1 -0
- package/dist/{chunk-3AQNLQPM.cjs → chunk-UHOHLN3C.cjs} +119 -69
- package/dist/chunk-UHOHLN3C.cjs.map +1 -0
- package/dist/{chunk-763XHDAJ.js → chunk-YBQV7XBC.js} +119 -70
- package/dist/chunk-YBQV7XBC.js.map +1 -0
- package/dist/contracts/handlers/index.d.cts +3 -3
- package/dist/contracts/handlers/index.d.ts +3 -3
- package/dist/{delegate-CgjVjYOP.d.ts → delegate-BKNqva1j.d.ts} +1 -1
- package/dist/{delegate-BRqbh2fW.d.cts → delegate-DOEobYwH.d.cts} +1 -1
- package/dist/{index-DHuXlDEg.d.cts → index-BlW4I30l.d.cts} +2 -2
- package/dist/{index-DvWNB_rl.d.ts → index-Cm2fGeox.d.ts} +2 -2
- package/dist/index.cjs +150 -126
- package/dist/index.d.cts +275 -19
- package/dist/index.d.ts +275 -19
- package/dist/index.js +2 -2
- package/dist/repositories/realm/index.cjs +17 -17
- package/dist/repositories/realm/index.d.cts +2 -2
- package/dist/repositories/realm/index.d.ts +2 -2
- package/dist/repositories/realm/index.js +3 -3
- package/dist/repositories/sqlite/index.cjs +16 -16
- package/dist/repositories/sqlite/index.d.cts +2 -2
- package/dist/repositories/sqlite/index.d.ts +2 -2
- package/dist/repositories/sqlite/index.js +3 -3
- package/dist/{taskRunner-Djlhfgi1.d.ts → taskRunner-BngWSFMi.d.ts} +1 -1
- package/dist/{taskRunner-BSnslNmq.d.cts → taskRunner-DOiyRuJa.d.cts} +1 -1
- package/dist/wallet/expo/background.cjs +12 -12
- package/dist/wallet/expo/background.d.cts +3 -3
- package/dist/wallet/expo/background.d.ts +3 -3
- package/dist/wallet/expo/background.js +4 -4
- package/dist/wallet/expo/index.cjs +21 -12
- 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 +12 -3
- package/dist/wallet/expo/index.js.map +1 -1
- package/dist/{wallet-BsqRU8KM.d.cts → wallet-B3awP1Nj.d.ts} +105 -3
- package/dist/{wallet-D9z7wssl.d.ts → wallet-DBjumS42.d.cts} +105 -3
- package/dist/worker/expo/index.cjs +7 -7
- package/dist/worker/expo/index.d.cts +4 -4
- package/dist/worker/expo/index.d.ts +4 -4
- package/dist/worker/expo/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-3AQNLQPM.cjs.map +0 -1
- package/dist/chunk-763XHDAJ.js.map +0 -1
- package/dist/chunk-B4R36PRN.js.map +0 -1
- package/dist/chunk-QGNTDGMN.cjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkUHOHLN3C_cjs = require('./chunk-UHOHLN3C.cjs');
|
|
4
4
|
var chunk32YKLQPS_cjs = require('./chunk-32YKLQPS.cjs');
|
|
5
5
|
var chunkHXDZ2QTW_cjs = require('./chunk-HXDZ2QTW.cjs');
|
|
6
6
|
var utils_js = require('@scure/btc-signer/utils.js');
|
|
@@ -181,7 +181,7 @@ var TreeSignerSession = class _TreeSignerSession {
|
|
|
181
181
|
noncesByPubkey.set(base.hex.encode(myPublicKey.subarray(1)), myNonce);
|
|
182
182
|
const tx = this.graph.find(txid);
|
|
183
183
|
if (!tx) throw new Error(`missing tx for txid ${txid}`);
|
|
184
|
-
const cosigners =
|
|
184
|
+
const cosigners = chunkUHOHLN3C_cjs.getArkPsbtFields(tx.root, 0, chunkUHOHLN3C_cjs.CosignerPublicKey).map(
|
|
185
185
|
(c) => base.hex.encode(c.key.subarray(1))
|
|
186
186
|
// xonly pubkey
|
|
187
187
|
);
|
|
@@ -233,7 +233,7 @@ var TreeSignerSession = class _TreeSignerSession {
|
|
|
233
233
|
if (!aggNonce) throw new Error("missing aggregate nonce");
|
|
234
234
|
const prevoutAmounts = [];
|
|
235
235
|
const prevoutScripts = [];
|
|
236
|
-
const cosigners =
|
|
236
|
+
const cosigners = chunkUHOHLN3C_cjs.getArkPsbtFields(g.root, 0, chunkUHOHLN3C_cjs.CosignerPublicKey).map((c) => c.key);
|
|
237
237
|
const { finalKey } = aggregateKeys(cosigners, true, {
|
|
238
238
|
taprootTweak: this.scriptRoot
|
|
239
239
|
});
|
|
@@ -980,14 +980,14 @@ var RestDelegateProvider = class {
|
|
|
980
980
|
*/
|
|
981
981
|
async delegate(intent, forfeitTxs, options) {
|
|
982
982
|
const url = `${this.url}/v1/delegate`;
|
|
983
|
-
const response = await
|
|
983
|
+
const response = await chunkUHOHLN3C_cjs.baseFetch(url, {
|
|
984
984
|
method: "POST",
|
|
985
985
|
headers: {
|
|
986
986
|
"Content-Type": "application/json"
|
|
987
987
|
},
|
|
988
988
|
body: JSON.stringify({
|
|
989
989
|
intent: {
|
|
990
|
-
message:
|
|
990
|
+
message: chunkUHOHLN3C_cjs.Intent.encodeMessage(intent.message),
|
|
991
991
|
proof: intent.proof
|
|
992
992
|
},
|
|
993
993
|
forfeit_txs: forfeitTxs,
|
|
@@ -1007,7 +1007,7 @@ var RestDelegateProvider = class {
|
|
|
1007
1007
|
*/
|
|
1008
1008
|
async getDelegateInfo() {
|
|
1009
1009
|
const url = `${this.url}/v1/delegator/info`;
|
|
1010
|
-
const response = await
|
|
1010
|
+
const response = await chunkUHOHLN3C_cjs.baseFetch(url);
|
|
1011
1011
|
if (!response.ok) {
|
|
1012
1012
|
const errorText2 = await response.text();
|
|
1013
1013
|
throw new Error(`Failed to get delegate info: ${errorText2}`);
|
|
@@ -1042,14 +1042,14 @@ var EsploraProvider = class {
|
|
|
1042
1042
|
pollingInterval;
|
|
1043
1043
|
forcePolling;
|
|
1044
1044
|
async getCoins(address) {
|
|
1045
|
-
const response = await
|
|
1045
|
+
const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/address/${address}/utxo`);
|
|
1046
1046
|
if (!response.ok) {
|
|
1047
1047
|
throw new Error(`Failed to fetch UTXOs: ${response.statusText}`);
|
|
1048
1048
|
}
|
|
1049
1049
|
return response.json();
|
|
1050
1050
|
}
|
|
1051
1051
|
async getFeeRate() {
|
|
1052
|
-
const response = await
|
|
1052
|
+
const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/fee-estimates`);
|
|
1053
1053
|
if (response.status === 404) {
|
|
1054
1054
|
return void 0;
|
|
1055
1055
|
}
|
|
@@ -1070,7 +1070,7 @@ var EsploraProvider = class {
|
|
|
1070
1070
|
}
|
|
1071
1071
|
}
|
|
1072
1072
|
async getTxOutspends(txid) {
|
|
1073
|
-
const response = await
|
|
1073
|
+
const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/outspends`);
|
|
1074
1074
|
if (!response.ok) {
|
|
1075
1075
|
const error = await response.text();
|
|
1076
1076
|
throw new Error(`Failed to get transaction outspends: ${error}`);
|
|
@@ -1078,7 +1078,7 @@ var EsploraProvider = class {
|
|
|
1078
1078
|
return response.json();
|
|
1079
1079
|
}
|
|
1080
1080
|
async getTransactions(address) {
|
|
1081
|
-
const response = await
|
|
1081
|
+
const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/address/${address}/txs`);
|
|
1082
1082
|
if (!response.ok) {
|
|
1083
1083
|
const error = await response.text();
|
|
1084
1084
|
throw new Error(`Failed to get transactions: ${error}`);
|
|
@@ -1086,7 +1086,7 @@ var EsploraProvider = class {
|
|
|
1086
1086
|
return response.json();
|
|
1087
1087
|
}
|
|
1088
1088
|
async getTxStatus(txid) {
|
|
1089
|
-
const txresponse = await
|
|
1089
|
+
const txresponse = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/tx/${txid}`);
|
|
1090
1090
|
if (!txresponse.ok) {
|
|
1091
1091
|
throw new Error(txresponse.statusText);
|
|
1092
1092
|
}
|
|
@@ -1094,7 +1094,7 @@ var EsploraProvider = class {
|
|
|
1094
1094
|
if (!tx.status.confirmed) {
|
|
1095
1095
|
return { confirmed: false };
|
|
1096
1096
|
}
|
|
1097
|
-
const response = await
|
|
1097
|
+
const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/status`);
|
|
1098
1098
|
if (!response.ok) {
|
|
1099
1099
|
throw new Error(`Failed to get transaction status: ${response.statusText}`);
|
|
1100
1100
|
}
|
|
@@ -1178,7 +1178,7 @@ var EsploraProvider = class {
|
|
|
1178
1178
|
return stopFunc;
|
|
1179
1179
|
}
|
|
1180
1180
|
async getChainTip() {
|
|
1181
|
-
const tipBlocks = await
|
|
1181
|
+
const tipBlocks = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/blocks`);
|
|
1182
1182
|
if (!tipBlocks.ok) {
|
|
1183
1183
|
throw new Error(`Failed to get chain tip: ${tipBlocks.statusText}`);
|
|
1184
1184
|
}
|
|
@@ -1197,7 +1197,7 @@ var EsploraProvider = class {
|
|
|
1197
1197
|
};
|
|
1198
1198
|
}
|
|
1199
1199
|
async broadcastPackage(parent, child) {
|
|
1200
|
-
const response = await
|
|
1200
|
+
const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/txs/package`, {
|
|
1201
1201
|
method: "POST",
|
|
1202
1202
|
headers: {
|
|
1203
1203
|
"Content-Type": "application/json"
|
|
@@ -1211,7 +1211,7 @@ var EsploraProvider = class {
|
|
|
1211
1211
|
return response.json();
|
|
1212
1212
|
}
|
|
1213
1213
|
async broadcastTx(tx) {
|
|
1214
|
-
const response = await
|
|
1214
|
+
const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/tx`, {
|
|
1215
1215
|
method: "POST",
|
|
1216
1216
|
headers: {
|
|
1217
1217
|
"Content-Type": "text/plain"
|
|
@@ -1237,6 +1237,114 @@ var isExplorerTransaction = (tx) => {
|
|
|
1237
1237
|
(vout) => typeof vout.scriptpubkey_address === "string" && typeof vout.value === "number"
|
|
1238
1238
|
) && typeof tx.status === "object" && typeof tx.status.confirmed === "boolean";
|
|
1239
1239
|
};
|
|
1240
|
+
var getVarIntSize = (n) => {
|
|
1241
|
+
if (n < 253) return 1;
|
|
1242
|
+
if (n <= 65535) return 3;
|
|
1243
|
+
if (n <= 4294967295) return 5;
|
|
1244
|
+
return 9;
|
|
1245
|
+
};
|
|
1246
|
+
var TxWeightEstimator = class _TxWeightEstimator {
|
|
1247
|
+
static P2PKH_SCRIPT_SIG_SIZE = 1 + 73 + 1 + 33;
|
|
1248
|
+
static INPUT_SIZE = 32 + 4 + 1 + 4;
|
|
1249
|
+
static BASE_CONTROL_BLOCK_SIZE = 1 + 32;
|
|
1250
|
+
static OUTPUT_SIZE = 8 + 1;
|
|
1251
|
+
static P2WPKH_OUTPUT_SIZE = 1 + 1 + 20;
|
|
1252
|
+
static BASE_TX_SIZE = 8 + 2;
|
|
1253
|
+
// Version + LockTime
|
|
1254
|
+
static WITNESS_HEADER_SIZE = 2;
|
|
1255
|
+
// Flag + Marker
|
|
1256
|
+
static WITNESS_SCALE_FACTOR = 4;
|
|
1257
|
+
static P2TR_OUTPUT_SIZE = 1 + 1 + 32;
|
|
1258
|
+
hasWitness;
|
|
1259
|
+
inputCount;
|
|
1260
|
+
outputCount;
|
|
1261
|
+
inputSize;
|
|
1262
|
+
inputWitnessSize;
|
|
1263
|
+
outputSize;
|
|
1264
|
+
constructor(hasWitness, inputCount, outputCount, inputSize, inputWitnessSize, outputSize) {
|
|
1265
|
+
this.hasWitness = hasWitness;
|
|
1266
|
+
this.inputCount = inputCount;
|
|
1267
|
+
this.outputCount = outputCount;
|
|
1268
|
+
this.inputSize = inputSize;
|
|
1269
|
+
this.inputWitnessSize = inputWitnessSize;
|
|
1270
|
+
this.outputSize = outputSize;
|
|
1271
|
+
}
|
|
1272
|
+
static create() {
|
|
1273
|
+
return new _TxWeightEstimator(false, 0, 0, 0, 0, 0);
|
|
1274
|
+
}
|
|
1275
|
+
addP2AInput() {
|
|
1276
|
+
this.inputCount++;
|
|
1277
|
+
this.inputSize += _TxWeightEstimator.INPUT_SIZE;
|
|
1278
|
+
return this;
|
|
1279
|
+
}
|
|
1280
|
+
addKeySpendInput(isDefault = true) {
|
|
1281
|
+
this.inputCount++;
|
|
1282
|
+
this.inputWitnessSize += 64 + 1 + (isDefault ? 0 : 1);
|
|
1283
|
+
this.inputSize += _TxWeightEstimator.INPUT_SIZE;
|
|
1284
|
+
this.hasWitness = true;
|
|
1285
|
+
return this;
|
|
1286
|
+
}
|
|
1287
|
+
addP2PKHInput() {
|
|
1288
|
+
this.inputCount++;
|
|
1289
|
+
this.inputWitnessSize++;
|
|
1290
|
+
this.inputSize += _TxWeightEstimator.INPUT_SIZE + _TxWeightEstimator.P2PKH_SCRIPT_SIG_SIZE;
|
|
1291
|
+
return this;
|
|
1292
|
+
}
|
|
1293
|
+
addTapscriptInput(leafWitnessSize, leafScriptSize, leafControlBlockSize) {
|
|
1294
|
+
const controlBlockWitnessSize = 1 + _TxWeightEstimator.BASE_CONTROL_BLOCK_SIZE + 1 + leafScriptSize + 1 + leafControlBlockSize;
|
|
1295
|
+
this.inputCount++;
|
|
1296
|
+
this.inputWitnessSize += leafWitnessSize + 1 + controlBlockWitnessSize;
|
|
1297
|
+
this.inputSize += _TxWeightEstimator.INPUT_SIZE;
|
|
1298
|
+
this.hasWitness = true;
|
|
1299
|
+
return this;
|
|
1300
|
+
}
|
|
1301
|
+
addP2WPKHOutput() {
|
|
1302
|
+
this.outputCount++;
|
|
1303
|
+
this.outputSize += _TxWeightEstimator.OUTPUT_SIZE + _TxWeightEstimator.P2WPKH_OUTPUT_SIZE;
|
|
1304
|
+
return this;
|
|
1305
|
+
}
|
|
1306
|
+
addP2TROutput() {
|
|
1307
|
+
this.outputCount++;
|
|
1308
|
+
this.outputSize += _TxWeightEstimator.OUTPUT_SIZE + _TxWeightEstimator.P2TR_OUTPUT_SIZE;
|
|
1309
|
+
return this;
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Adds an output given a raw script.
|
|
1313
|
+
* Cost = 8 bytes (amount) + varint(scriptLen) + scriptLen
|
|
1314
|
+
*/
|
|
1315
|
+
addOutputScript(script) {
|
|
1316
|
+
this.outputCount++;
|
|
1317
|
+
this.outputSize += 8 + getVarIntSize(script.length) + script.length;
|
|
1318
|
+
return this;
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
1321
|
+
* Adds an output by decoding the address to get the exact script size.
|
|
1322
|
+
*/
|
|
1323
|
+
addOutputAddress(address, network) {
|
|
1324
|
+
const payment = btcSigner.Address(network).decode(address);
|
|
1325
|
+
const script = btcSigner.OutScript.encode(payment);
|
|
1326
|
+
return this.addOutputScript(script);
|
|
1327
|
+
}
|
|
1328
|
+
vsize() {
|
|
1329
|
+
const inputCount = getVarIntSize(this.inputCount);
|
|
1330
|
+
const outputCount = getVarIntSize(this.outputCount);
|
|
1331
|
+
const txSizeStripped = _TxWeightEstimator.BASE_TX_SIZE + inputCount + this.inputSize + outputCount + this.outputSize;
|
|
1332
|
+
let weight = txSizeStripped * _TxWeightEstimator.WITNESS_SCALE_FACTOR;
|
|
1333
|
+
if (this.hasWitness) {
|
|
1334
|
+
weight += _TxWeightEstimator.WITNESS_HEADER_SIZE + this.inputWitnessSize;
|
|
1335
|
+
}
|
|
1336
|
+
return vsize(weight);
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
var vsize = (weight) => {
|
|
1340
|
+
const value = BigInt(Math.ceil(weight / TxWeightEstimator.WITNESS_SCALE_FACTOR));
|
|
1341
|
+
return {
|
|
1342
|
+
value,
|
|
1343
|
+
fee: (feeRate) => feeRate * value
|
|
1344
|
+
};
|
|
1345
|
+
};
|
|
1346
|
+
|
|
1347
|
+
// src/utils/anchor.ts
|
|
1240
1348
|
var ANCHOR_VALUE = 0n;
|
|
1241
1349
|
var ANCHOR_PKSCRIPT = new Uint8Array([81, 2, 78, 115]);
|
|
1242
1350
|
var P2A = {
|
|
@@ -1262,6 +1370,37 @@ function findP2AOutput(tx) {
|
|
|
1262
1370
|
}
|
|
1263
1371
|
throw new Error("P2A output not found");
|
|
1264
1372
|
}
|
|
1373
|
+
var CHILD_DUST_AMOUNT = 546;
|
|
1374
|
+
function buildAnchorChild(params) {
|
|
1375
|
+
const { parent, feeRate, fundingCoins, changeAddress, tapInternalKey, network } = params;
|
|
1376
|
+
const child = new chunkUHOHLN3C_cjs.Transaction({ version: 3, allowLegacyWitnessUtxo: true });
|
|
1377
|
+
child.addInput(findP2AOutput(parent));
|
|
1378
|
+
const estimator = TxWeightEstimator.create().addP2AInput();
|
|
1379
|
+
for (const _ of fundingCoins) {
|
|
1380
|
+
estimator.addKeySpendInput(true);
|
|
1381
|
+
}
|
|
1382
|
+
estimator.addOutputAddress(changeAddress, network);
|
|
1383
|
+
const childVsize = Number(estimator.vsize().value);
|
|
1384
|
+
const fee = Math.ceil(feeRate * (parent.vsize + childVsize));
|
|
1385
|
+
let total = 0n;
|
|
1386
|
+
for (const coin of fundingCoins) {
|
|
1387
|
+
total += BigInt(coin.value);
|
|
1388
|
+
child.addInput({
|
|
1389
|
+
txid: coin.txid,
|
|
1390
|
+
index: coin.vout,
|
|
1391
|
+
witnessUtxo: { script: params.changeScript, amount: BigInt(coin.value) },
|
|
1392
|
+
tapInternalKey
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
const change = total + P2A.amount - BigInt(fee);
|
|
1396
|
+
if (change < BigInt(CHILD_DUST_AMOUNT)) {
|
|
1397
|
+
throw new Error(
|
|
1398
|
+
`insufficient funding for anchor child: need change >= ${CHILD_DUST_AMOUNT}, got ${change}`
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
child.addOutputAddress(changeAddress, change, network);
|
|
1402
|
+
return { child, fee };
|
|
1403
|
+
}
|
|
1265
1404
|
|
|
1266
1405
|
// src/forfeit.ts
|
|
1267
1406
|
function buildForfeitTx(inputs, forfeitPkScript, txLocktime) {
|
|
@@ -1282,7 +1421,7 @@ function buildForfeitTx(inputs, forfeitPkScript, txLocktime) {
|
|
|
1282
1421
|
);
|
|
1283
1422
|
}
|
|
1284
1423
|
function buildForfeitTxWithOutput(inputs, output, txLocktime) {
|
|
1285
|
-
const tx = new
|
|
1424
|
+
const tx = new chunkUHOHLN3C_cjs.Transaction({
|
|
1286
1425
|
version: 3,
|
|
1287
1426
|
lockTime: txLocktime
|
|
1288
1427
|
});
|
|
@@ -1358,7 +1497,7 @@ function validateVtxoTxGraph(graph, roundTransaction, sweepTapTreeRoot) {
|
|
|
1358
1497
|
if (previousScriptKey.length !== 32) {
|
|
1359
1498
|
throw new Error(`parent output ${childIndex} has invalid script`);
|
|
1360
1499
|
}
|
|
1361
|
-
const cosigners =
|
|
1500
|
+
const cosigners = chunkUHOHLN3C_cjs.getArkPsbtFields(child.root, 0, chunkUHOHLN3C_cjs.CosignerPublicKey);
|
|
1362
1501
|
if (cosigners.length === 0) {
|
|
1363
1502
|
throw ErrMissingCosignersPublicKeys;
|
|
1364
1503
|
}
|
|
@@ -1458,7 +1597,7 @@ var Extension = class _Extension {
|
|
|
1458
1597
|
`expected magic prefix ${base.hex.encode(ARKADE_MAGIC)}, got ${base.hex.encode(payload.slice(0, Math.min(payload.length, ARKADE_MAGIC.length)))}`
|
|
1459
1598
|
);
|
|
1460
1599
|
}
|
|
1461
|
-
const reader = new
|
|
1600
|
+
const reader = new chunkUHOHLN3C_cjs.BufferReader(payload.slice(ARKADE_MAGIC.length));
|
|
1462
1601
|
const packets = [];
|
|
1463
1602
|
while (reader.remaining() > 0) {
|
|
1464
1603
|
const packetType = reader.readByte();
|
|
@@ -1532,7 +1671,7 @@ var Extension = class _Extension {
|
|
|
1532
1671
|
*/
|
|
1533
1672
|
getAssetPacket() {
|
|
1534
1673
|
for (const p of this.packets) {
|
|
1535
|
-
if (p instanceof
|
|
1674
|
+
if (p instanceof chunkUHOHLN3C_cjs.Packet) {
|
|
1536
1675
|
return p;
|
|
1537
1676
|
}
|
|
1538
1677
|
}
|
|
@@ -1540,8 +1679,8 @@ var Extension = class _Extension {
|
|
|
1540
1679
|
}
|
|
1541
1680
|
};
|
|
1542
1681
|
function parsePacket(packetType, data) {
|
|
1543
|
-
if (packetType ===
|
|
1544
|
-
return
|
|
1682
|
+
if (packetType === chunkUHOHLN3C_cjs.Packet.PACKET_TYPE) {
|
|
1683
|
+
return chunkUHOHLN3C_cjs.Packet.fromBytes(data);
|
|
1545
1684
|
}
|
|
1546
1685
|
return new UnknownPacket(packetType, data);
|
|
1547
1686
|
}
|
|
@@ -1848,7 +1987,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
|
|
|
1848
1987
|
const existing = inputsByAssetId.get(asset.assetId);
|
|
1849
1988
|
inputsByAssetId.set(asset.assetId, [
|
|
1850
1989
|
...existing ?? [],
|
|
1851
|
-
|
|
1990
|
+
chunkUHOHLN3C_cjs.AssetInput.create(inputIndex, asset.amount)
|
|
1852
1991
|
]);
|
|
1853
1992
|
}
|
|
1854
1993
|
}
|
|
@@ -1860,7 +1999,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
|
|
|
1860
1999
|
const existing = outputsByAssetId.get(asset.assetId);
|
|
1861
2000
|
outputsByAssetId.set(asset.assetId, [
|
|
1862
2001
|
...existing ?? [],
|
|
1863
|
-
|
|
2002
|
+
chunkUHOHLN3C_cjs.AssetOutput.create(outputIndex, asset.amount)
|
|
1864
2003
|
]);
|
|
1865
2004
|
}
|
|
1866
2005
|
}
|
|
@@ -1871,7 +2010,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
|
|
|
1871
2010
|
const existing = outputsByAssetId.get(asset.assetId);
|
|
1872
2011
|
outputsByAssetId.set(asset.assetId, [
|
|
1873
2012
|
...existing ?? [],
|
|
1874
|
-
|
|
2013
|
+
chunkUHOHLN3C_cjs.AssetOutput.create(outputIndex, asset.amount)
|
|
1875
2014
|
]);
|
|
1876
2015
|
}
|
|
1877
2016
|
}
|
|
@@ -1880,11 +2019,11 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
|
|
|
1880
2019
|
for (const assetIdStr of allAssetIds) {
|
|
1881
2020
|
const inputs = inputsByAssetId.get(assetIdStr);
|
|
1882
2021
|
const outputs = outputsByAssetId.get(assetIdStr);
|
|
1883
|
-
const assetId =
|
|
1884
|
-
const group =
|
|
2022
|
+
const assetId = chunkUHOHLN3C_cjs.AssetId.fromString(assetIdStr);
|
|
2023
|
+
const group = chunkUHOHLN3C_cjs.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
|
|
1885
2024
|
groups.push(group);
|
|
1886
2025
|
}
|
|
1887
|
-
return
|
|
2026
|
+
return chunkUHOHLN3C_cjs.Packet.create(groups);
|
|
1888
2027
|
}
|
|
1889
2028
|
function selectCoinsWithAsset(coins, assetId, requiredAmount) {
|
|
1890
2029
|
const coinsWithAsset = coins.filter((coin) => coin.assets?.some((a) => a.assetId === assetId));
|
|
@@ -2001,7 +2140,7 @@ function buildVirtualTx(inputs, outputs) {
|
|
|
2001
2140
|
}
|
|
2002
2141
|
}
|
|
2003
2142
|
}
|
|
2004
|
-
const tx = new
|
|
2143
|
+
const tx = new chunkUHOHLN3C_cjs.Transaction({
|
|
2005
2144
|
version: 3,
|
|
2006
2145
|
lockTime: Number(lockTime)
|
|
2007
2146
|
});
|
|
@@ -2016,7 +2155,7 @@ function buildVirtualTx(inputs, outputs) {
|
|
|
2016
2155
|
},
|
|
2017
2156
|
tapLeafScript: [input.tapLeafScript]
|
|
2018
2157
|
});
|
|
2019
|
-
|
|
2158
|
+
chunkUHOHLN3C_cjs.setArkPsbtField(tx, i, chunkUHOHLN3C_cjs.VtxoTaprootTree, input.tapTree);
|
|
2020
2159
|
}
|
|
2021
2160
|
for (const output of outputs) {
|
|
2022
2161
|
tx.addOutput(output);
|
|
@@ -2176,112 +2315,6 @@ function isValidArkAddress(address) {
|
|
|
2176
2315
|
return false;
|
|
2177
2316
|
}
|
|
2178
2317
|
}
|
|
2179
|
-
var getVarIntSize = (n) => {
|
|
2180
|
-
if (n < 253) return 1;
|
|
2181
|
-
if (n <= 65535) return 3;
|
|
2182
|
-
if (n <= 4294967295) return 5;
|
|
2183
|
-
return 9;
|
|
2184
|
-
};
|
|
2185
|
-
var TxWeightEstimator = class _TxWeightEstimator {
|
|
2186
|
-
static P2PKH_SCRIPT_SIG_SIZE = 1 + 73 + 1 + 33;
|
|
2187
|
-
static INPUT_SIZE = 32 + 4 + 1 + 4;
|
|
2188
|
-
static BASE_CONTROL_BLOCK_SIZE = 1 + 32;
|
|
2189
|
-
static OUTPUT_SIZE = 8 + 1;
|
|
2190
|
-
static P2WPKH_OUTPUT_SIZE = 1 + 1 + 20;
|
|
2191
|
-
static BASE_TX_SIZE = 8 + 2;
|
|
2192
|
-
// Version + LockTime
|
|
2193
|
-
static WITNESS_HEADER_SIZE = 2;
|
|
2194
|
-
// Flag + Marker
|
|
2195
|
-
static WITNESS_SCALE_FACTOR = 4;
|
|
2196
|
-
static P2TR_OUTPUT_SIZE = 1 + 1 + 32;
|
|
2197
|
-
hasWitness;
|
|
2198
|
-
inputCount;
|
|
2199
|
-
outputCount;
|
|
2200
|
-
inputSize;
|
|
2201
|
-
inputWitnessSize;
|
|
2202
|
-
outputSize;
|
|
2203
|
-
constructor(hasWitness, inputCount, outputCount, inputSize, inputWitnessSize, outputSize) {
|
|
2204
|
-
this.hasWitness = hasWitness;
|
|
2205
|
-
this.inputCount = inputCount;
|
|
2206
|
-
this.outputCount = outputCount;
|
|
2207
|
-
this.inputSize = inputSize;
|
|
2208
|
-
this.inputWitnessSize = inputWitnessSize;
|
|
2209
|
-
this.outputSize = outputSize;
|
|
2210
|
-
}
|
|
2211
|
-
static create() {
|
|
2212
|
-
return new _TxWeightEstimator(false, 0, 0, 0, 0, 0);
|
|
2213
|
-
}
|
|
2214
|
-
addP2AInput() {
|
|
2215
|
-
this.inputCount++;
|
|
2216
|
-
this.inputSize += _TxWeightEstimator.INPUT_SIZE;
|
|
2217
|
-
return this;
|
|
2218
|
-
}
|
|
2219
|
-
addKeySpendInput(isDefault = true) {
|
|
2220
|
-
this.inputCount++;
|
|
2221
|
-
this.inputWitnessSize += 64 + 1 + (isDefault ? 0 : 1);
|
|
2222
|
-
this.inputSize += _TxWeightEstimator.INPUT_SIZE;
|
|
2223
|
-
this.hasWitness = true;
|
|
2224
|
-
return this;
|
|
2225
|
-
}
|
|
2226
|
-
addP2PKHInput() {
|
|
2227
|
-
this.inputCount++;
|
|
2228
|
-
this.inputWitnessSize++;
|
|
2229
|
-
this.inputSize += _TxWeightEstimator.INPUT_SIZE + _TxWeightEstimator.P2PKH_SCRIPT_SIG_SIZE;
|
|
2230
|
-
return this;
|
|
2231
|
-
}
|
|
2232
|
-
addTapscriptInput(leafWitnessSize, leafScriptSize, leafControlBlockSize) {
|
|
2233
|
-
const controlBlockWitnessSize = 1 + _TxWeightEstimator.BASE_CONTROL_BLOCK_SIZE + 1 + leafScriptSize + 1 + leafControlBlockSize;
|
|
2234
|
-
this.inputCount++;
|
|
2235
|
-
this.inputWitnessSize += leafWitnessSize + 1 + controlBlockWitnessSize;
|
|
2236
|
-
this.inputSize += _TxWeightEstimator.INPUT_SIZE;
|
|
2237
|
-
this.hasWitness = true;
|
|
2238
|
-
return this;
|
|
2239
|
-
}
|
|
2240
|
-
addP2WPKHOutput() {
|
|
2241
|
-
this.outputCount++;
|
|
2242
|
-
this.outputSize += _TxWeightEstimator.OUTPUT_SIZE + _TxWeightEstimator.P2WPKH_OUTPUT_SIZE;
|
|
2243
|
-
return this;
|
|
2244
|
-
}
|
|
2245
|
-
addP2TROutput() {
|
|
2246
|
-
this.outputCount++;
|
|
2247
|
-
this.outputSize += _TxWeightEstimator.OUTPUT_SIZE + _TxWeightEstimator.P2TR_OUTPUT_SIZE;
|
|
2248
|
-
return this;
|
|
2249
|
-
}
|
|
2250
|
-
/**
|
|
2251
|
-
* Adds an output given a raw script.
|
|
2252
|
-
* Cost = 8 bytes (amount) + varint(scriptLen) + scriptLen
|
|
2253
|
-
*/
|
|
2254
|
-
addOutputScript(script) {
|
|
2255
|
-
this.outputCount++;
|
|
2256
|
-
this.outputSize += 8 + getVarIntSize(script.length) + script.length;
|
|
2257
|
-
return this;
|
|
2258
|
-
}
|
|
2259
|
-
/**
|
|
2260
|
-
* Adds an output by decoding the address to get the exact script size.
|
|
2261
|
-
*/
|
|
2262
|
-
addOutputAddress(address, network) {
|
|
2263
|
-
const payment = btcSigner.Address(network).decode(address);
|
|
2264
|
-
const script = btcSigner.OutScript.encode(payment);
|
|
2265
|
-
return this.addOutputScript(script);
|
|
2266
|
-
}
|
|
2267
|
-
vsize() {
|
|
2268
|
-
const inputCount = getVarIntSize(this.inputCount);
|
|
2269
|
-
const outputCount = getVarIntSize(this.outputCount);
|
|
2270
|
-
const txSizeStripped = _TxWeightEstimator.BASE_TX_SIZE + inputCount + this.inputSize + outputCount + this.outputSize;
|
|
2271
|
-
let weight = txSizeStripped * _TxWeightEstimator.WITNESS_SCALE_FACTOR;
|
|
2272
|
-
if (this.hasWitness) {
|
|
2273
|
-
weight += _TxWeightEstimator.WITNESS_HEADER_SIZE + this.inputWitnessSize;
|
|
2274
|
-
}
|
|
2275
|
-
return vsize(weight);
|
|
2276
|
-
}
|
|
2277
|
-
};
|
|
2278
|
-
var vsize = (weight) => {
|
|
2279
|
-
const value = BigInt(Math.ceil(weight / TxWeightEstimator.WITNESS_SCALE_FACTOR));
|
|
2280
|
-
return {
|
|
2281
|
-
value,
|
|
2282
|
-
fee: (feeRate) => feeRate * value
|
|
2283
|
-
};
|
|
2284
|
-
};
|
|
2285
2318
|
var AmountVariableName = "amount";
|
|
2286
2319
|
var ExpiryVariableName = "expiry";
|
|
2287
2320
|
var BirthVariableName = "birth";
|
|
@@ -3124,7 +3157,7 @@ var VtxoManager = class _VtxoManager {
|
|
|
3124
3157
|
`Sweep not economical: output ${outputAmount} sats after ${fee} sats fee is below dust (${dustAmount} sats)`
|
|
3125
3158
|
);
|
|
3126
3159
|
}
|
|
3127
|
-
const tx = new
|
|
3160
|
+
const tx = new chunkUHOHLN3C_cjs.Transaction();
|
|
3128
3161
|
for (const utxo of expiredUtxos) {
|
|
3129
3162
|
const utxoScript = chunkHXDZ2QTW_cjs.VtxoScript.decode(utxo.tapTree);
|
|
3130
3163
|
const utxoExitLeaf = utxoScript.leaves.find(
|
|
@@ -3763,7 +3796,7 @@ var VtxoManager = class _VtxoManager {
|
|
|
3763
3796
|
* or doesn't carry the metadata.
|
|
3764
3797
|
*/
|
|
3765
3798
|
extractSpentOutpoint(error) {
|
|
3766
|
-
const ark =
|
|
3799
|
+
const ark = chunkUHOHLN3C_cjs.maybeArkError(error);
|
|
3767
3800
|
if (!ark || ark.name !== "VTXO_ALREADY_SPENT") return void 0;
|
|
3768
3801
|
const raw = ark.metadata?.vtxo_outpoint;
|
|
3769
3802
|
if (typeof raw !== "string") return void 0;
|
|
@@ -4276,17 +4309,603 @@ function wrapHandlerWithIntentPersistence(base, deps) {
|
|
|
4276
4309
|
}
|
|
4277
4310
|
};
|
|
4278
4311
|
}
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4312
|
+
|
|
4313
|
+
// src/repositories/virtualTxRepository.ts
|
|
4314
|
+
var ChainedTxType = /* @__PURE__ */ ((ChainedTxType2) => {
|
|
4315
|
+
ChainedTxType2[ChainedTxType2["Unspecified"] = 0] = "Unspecified";
|
|
4316
|
+
ChainedTxType2[ChainedTxType2["Commitment"] = 1] = "Commitment";
|
|
4317
|
+
ChainedTxType2[ChainedTxType2["Ark"] = 2] = "Ark";
|
|
4318
|
+
ChainedTxType2[ChainedTxType2["Tree"] = 3] = "Tree";
|
|
4319
|
+
ChainedTxType2[ChainedTxType2["Checkpoint"] = 4] = "Checkpoint";
|
|
4320
|
+
return ChainedTxType2;
|
|
4321
|
+
})(ChainedTxType || {});
|
|
4322
|
+
function mergeChainedTxType(incoming, prev) {
|
|
4323
|
+
if (incoming !== 0 /* Unspecified */) return incoming;
|
|
4324
|
+
return prev ?? 0 /* Unspecified */;
|
|
4325
|
+
}
|
|
4326
|
+
|
|
4327
|
+
// src/wallet/exit/chain.ts
|
|
4328
|
+
var isCommitment = (t) => t === "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */ || t === "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
|
|
4329
|
+
async function buildExitDag(params) {
|
|
4330
|
+
const byTxid = /* @__PURE__ */ new Map();
|
|
4331
|
+
for (const vtxo of params.vtxos) {
|
|
4332
|
+
const outpoint = `${vtxo.txid}:${vtxo.vout}`;
|
|
4333
|
+
const chain = await params.chain.getVtxoChain({ txid: vtxo.txid, vout: vtxo.vout });
|
|
4334
|
+
for (const chainTx of chain) {
|
|
4335
|
+
const existing = byTxid.get(chainTx.txid);
|
|
4336
|
+
if (existing) {
|
|
4337
|
+
existing.forVtxos.add(outpoint);
|
|
4338
|
+
} else {
|
|
4339
|
+
byTxid.set(chainTx.txid, { ...chainTx, forVtxos: /* @__PURE__ */ new Set([outpoint]) });
|
|
4340
|
+
}
|
|
4341
|
+
}
|
|
4283
4342
|
}
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4343
|
+
const pending = new Map(
|
|
4344
|
+
[...byTxid.values()].filter((tx) => !isCommitment(tx.type)).map((tx) => [tx.txid, tx])
|
|
4345
|
+
);
|
|
4346
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
4347
|
+
for (const tx of pending.values()) {
|
|
4348
|
+
const parents = tx.spends.filter((p) => pending.has(p));
|
|
4349
|
+
inDegree.set(tx.txid, parents.length);
|
|
4350
|
+
}
|
|
4351
|
+
const order = [];
|
|
4352
|
+
const queue = [...pending.values()].filter((tx) => inDegree.get(tx.txid) === 0).sort((a, b) => a.txid.localeCompare(b.txid));
|
|
4353
|
+
while (queue.length > 0) {
|
|
4354
|
+
const tx = queue.shift();
|
|
4355
|
+
order.push(tx);
|
|
4356
|
+
const children = [...pending.values()].filter((c) => c.spends.includes(tx.txid)).sort((a, b) => a.txid.localeCompare(b.txid));
|
|
4357
|
+
for (const child of children) {
|
|
4358
|
+
const deg = inDegree.get(child.txid) - 1;
|
|
4359
|
+
inDegree.set(child.txid, deg);
|
|
4360
|
+
if (deg === 0) queue.push(child);
|
|
4361
|
+
}
|
|
4362
|
+
}
|
|
4363
|
+
if (order.length !== pending.size) {
|
|
4364
|
+
throw new Error("inconsistent vtxo chain from indexer (cycle detected)");
|
|
4365
|
+
}
|
|
4366
|
+
const nodes = [];
|
|
4367
|
+
for (const tx of order) {
|
|
4368
|
+
let confirmed = false;
|
|
4369
|
+
try {
|
|
4370
|
+
const status = await params.onchain.getTxStatus(tx.txid);
|
|
4371
|
+
confirmed = status.confirmed;
|
|
4372
|
+
} catch {
|
|
4373
|
+
confirmed = false;
|
|
4374
|
+
}
|
|
4375
|
+
const expires = Number(tx.expiresAt);
|
|
4376
|
+
nodes.push({
|
|
4377
|
+
txid: tx.txid,
|
|
4378
|
+
type: tx.type,
|
|
4379
|
+
expiresAt: Number.isFinite(expires) && expires > 0 ? expires : void 0,
|
|
4380
|
+
forVtxos: [...tx.forVtxos].sort(),
|
|
4381
|
+
confirmed
|
|
4382
|
+
});
|
|
4383
|
+
}
|
|
4384
|
+
return nodes;
|
|
4385
|
+
}
|
|
4386
|
+
function topoSortByDeps(items, idOf, depsOf) {
|
|
4387
|
+
const produced = new Set(items.map(idOf));
|
|
4388
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
4389
|
+
const ordered = [];
|
|
4390
|
+
let remaining = items;
|
|
4391
|
+
while (remaining.length > 0) {
|
|
4392
|
+
const next = [];
|
|
4393
|
+
let progress = false;
|
|
4394
|
+
for (const item of remaining) {
|
|
4395
|
+
if (depsOf(item).every((d) => !produced.has(d) || emitted.has(d))) {
|
|
4396
|
+
ordered.push(item);
|
|
4397
|
+
emitted.add(idOf(item));
|
|
4398
|
+
progress = true;
|
|
4399
|
+
} else {
|
|
4400
|
+
next.push(item);
|
|
4401
|
+
}
|
|
4287
4402
|
}
|
|
4288
|
-
|
|
4289
|
-
|
|
4403
|
+
if (!progress) {
|
|
4404
|
+
throw new Error("topological sort: cycle or unsatisfiable dependency");
|
|
4405
|
+
}
|
|
4406
|
+
remaining = next;
|
|
4407
|
+
}
|
|
4408
|
+
return ordered;
|
|
4409
|
+
}
|
|
4410
|
+
|
|
4411
|
+
// src/wallet/exit/capture.ts
|
|
4412
|
+
var DEFAULT_MIN_EXIT_WORTH_SATS = 1e3;
|
|
4413
|
+
var DEFAULT_EXIT_CAPTURE_MODE = "lite";
|
|
4414
|
+
function chainTxTypeToChainedExit(t) {
|
|
4415
|
+
switch (t) {
|
|
4416
|
+
case "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */:
|
|
4417
|
+
return 1 /* Commitment */;
|
|
4418
|
+
case "INDEXER_CHAINED_TX_TYPE_ARK" /* ARK */:
|
|
4419
|
+
return 2 /* Ark */;
|
|
4420
|
+
case "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */:
|
|
4421
|
+
return 3 /* Tree */;
|
|
4422
|
+
case "INDEXER_CHAINED_TX_TYPE_CHECKPOINT" /* CHECKPOINT */:
|
|
4423
|
+
return 4 /* Checkpoint */;
|
|
4424
|
+
default:
|
|
4425
|
+
return 0 /* Unspecified */;
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4428
|
+
function orderAncestryFirst(chain) {
|
|
4429
|
+
const ids = new Set(chain.map((c) => c.txid));
|
|
4430
|
+
return topoSortByDeps(
|
|
4431
|
+
chain,
|
|
4432
|
+
(c) => c.txid,
|
|
4433
|
+
(c) => c.spends.filter((s) => ids.has(s))
|
|
4434
|
+
);
|
|
4435
|
+
}
|
|
4436
|
+
async function captureExitBranch(params) {
|
|
4437
|
+
const { resolver, repository, vtxo, value, mode, minExitWorthSats } = params;
|
|
4438
|
+
if (value < minExitWorthSats) return;
|
|
4439
|
+
if (await repository.hasBranch(vtxo)) return;
|
|
4440
|
+
const ordered = orderAncestryFirst(await resolver.getVtxoChain(vtxo));
|
|
4441
|
+
const psbtByTxid = /* @__PURE__ */ new Map();
|
|
4442
|
+
if (mode === "full") {
|
|
4443
|
+
const nonCommitment = ordered.filter((c) => chainTxTypeToChainedExit(c.type) !== 1 /* Commitment */).map((c) => c.txid);
|
|
4444
|
+
if (nonCommitment.length > 0) {
|
|
4445
|
+
for (const psbt of await resolver.getVirtualTxs(nonCommitment)) {
|
|
4446
|
+
psbtByTxid.set(chunkUHOHLN3C_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
|
|
4447
|
+
}
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
const virtualTxs = ordered.map((c) => {
|
|
4451
|
+
const expires = Number(c.expiresAt);
|
|
4452
|
+
return {
|
|
4453
|
+
txid: c.txid,
|
|
4454
|
+
psbt: psbtByTxid.get(c.txid) ?? null,
|
|
4455
|
+
expiresAt: Number.isFinite(expires) && expires > 0 ? expires : null,
|
|
4456
|
+
type: chainTxTypeToChainedExit(c.type)
|
|
4457
|
+
};
|
|
4458
|
+
});
|
|
4459
|
+
const branch = ordered.map((c, i) => ({
|
|
4460
|
+
vtxoTxid: vtxo.txid,
|
|
4461
|
+
vtxoVout: vtxo.vout,
|
|
4462
|
+
virtualTxid: c.txid,
|
|
4463
|
+
position: i
|
|
4464
|
+
}));
|
|
4465
|
+
await repository.upsertVirtualTxs(virtualTxs);
|
|
4466
|
+
await repository.setBranch(vtxo, branch);
|
|
4467
|
+
}
|
|
4468
|
+
async function pruneExitBranches(repository, outpoints) {
|
|
4469
|
+
for (const outpoint of outpoints) {
|
|
4470
|
+
try {
|
|
4471
|
+
await repository.pruneForSpentVtxo(outpoint);
|
|
4472
|
+
} catch {
|
|
4473
|
+
}
|
|
4474
|
+
}
|
|
4475
|
+
}
|
|
4476
|
+
var IndexerExitDataSource = class {
|
|
4477
|
+
constructor(indexer) {
|
|
4478
|
+
this.indexer = indexer;
|
|
4479
|
+
}
|
|
4480
|
+
name = "indexer";
|
|
4481
|
+
async getVtxoChain(vtxo) {
|
|
4482
|
+
const chain = [];
|
|
4483
|
+
let pageIndex = 0;
|
|
4484
|
+
let hasMore = true;
|
|
4485
|
+
while (hasMore) {
|
|
4486
|
+
const { chain: page, page: meta } = await this.indexer.getVtxoChain(
|
|
4487
|
+
{ txid: vtxo.txid, vout: vtxo.vout },
|
|
4488
|
+
{ pageIndex, pageSize: chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE }
|
|
4489
|
+
);
|
|
4490
|
+
chain.push(...page);
|
|
4491
|
+
hasMore = meta ? page.length === chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE : false;
|
|
4492
|
+
pageIndex++;
|
|
4493
|
+
}
|
|
4494
|
+
return chain;
|
|
4495
|
+
}
|
|
4496
|
+
async getVirtualTxs(txids) {
|
|
4497
|
+
const out = /* @__PURE__ */ new Map();
|
|
4498
|
+
let pageIndex = 0;
|
|
4499
|
+
let hasMore = true;
|
|
4500
|
+
while (hasMore) {
|
|
4501
|
+
const { txs, page } = await this.indexer.getVirtualTxs(txids, {
|
|
4502
|
+
pageIndex,
|
|
4503
|
+
pageSize: chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE
|
|
4504
|
+
});
|
|
4505
|
+
for (const psbt of txs) {
|
|
4506
|
+
out.set(chunkUHOHLN3C_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
|
|
4507
|
+
}
|
|
4508
|
+
hasMore = page ? txs.length === chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE : false;
|
|
4509
|
+
pageIndex++;
|
|
4510
|
+
}
|
|
4511
|
+
return out;
|
|
4512
|
+
}
|
|
4513
|
+
};
|
|
4514
|
+
function chainedTxTypeToChainTxType(t) {
|
|
4515
|
+
switch (t) {
|
|
4516
|
+
case 1 /* Commitment */:
|
|
4517
|
+
return "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */;
|
|
4518
|
+
case 2 /* Ark */:
|
|
4519
|
+
return "INDEXER_CHAINED_TX_TYPE_ARK" /* ARK */;
|
|
4520
|
+
case 3 /* Tree */:
|
|
4521
|
+
return "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */;
|
|
4522
|
+
case 4 /* Checkpoint */:
|
|
4523
|
+
return "INDEXER_CHAINED_TX_TYPE_CHECKPOINT" /* CHECKPOINT */;
|
|
4524
|
+
default:
|
|
4525
|
+
return "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
|
|
4526
|
+
}
|
|
4527
|
+
}
|
|
4528
|
+
function psbtInputTxids(psbtBase64) {
|
|
4529
|
+
const tx = chunkUHOHLN3C_cjs.Transaction.fromPSBT(base.base64.decode(psbtBase64));
|
|
4530
|
+
const ids = [];
|
|
4531
|
+
for (let i = 0; i < tx.inputsLength; i++) {
|
|
4532
|
+
const txid = tx.getInput(i).txid;
|
|
4533
|
+
if (txid) ids.push(base.hex.encode(txid));
|
|
4534
|
+
}
|
|
4535
|
+
return ids;
|
|
4536
|
+
}
|
|
4537
|
+
var RepositoryExitDataSource = class {
|
|
4538
|
+
constructor(repo) {
|
|
4539
|
+
this.repo = repo;
|
|
4540
|
+
}
|
|
4541
|
+
name = "repository";
|
|
4542
|
+
async getVtxoChain(vtxo) {
|
|
4543
|
+
const branch = await this.repo.getBranch(vtxo);
|
|
4544
|
+
if (branch.length === 0) return null;
|
|
4545
|
+
const chain = [];
|
|
4546
|
+
for (const v of branch) {
|
|
4547
|
+
const type = chainedTxTypeToChainTxType(v.type);
|
|
4548
|
+
let spends = [];
|
|
4549
|
+
if (v.type !== 1 /* Commitment */) {
|
|
4550
|
+
if (!v.psbt) return null;
|
|
4551
|
+
spends = psbtInputTxids(v.psbt);
|
|
4552
|
+
}
|
|
4553
|
+
chain.push({
|
|
4554
|
+
txid: v.txid,
|
|
4555
|
+
type,
|
|
4556
|
+
expiresAt: v.expiresAt != null ? String(v.expiresAt) : "",
|
|
4557
|
+
spends
|
|
4558
|
+
});
|
|
4559
|
+
}
|
|
4560
|
+
return chain;
|
|
4561
|
+
}
|
|
4562
|
+
async getVirtualTxs(txids) {
|
|
4563
|
+
const out = /* @__PURE__ */ new Map();
|
|
4564
|
+
for (const txid of txids) {
|
|
4565
|
+
const stored = await this.repo.getVirtualTx(txid);
|
|
4566
|
+
if (stored?.psbt) out.set(txid, stored.psbt);
|
|
4567
|
+
}
|
|
4568
|
+
return out;
|
|
4569
|
+
}
|
|
4570
|
+
};
|
|
4571
|
+
|
|
4572
|
+
// src/wallet/exit/resolver.ts
|
|
4573
|
+
var OrderedExitChainResolver = class {
|
|
4574
|
+
constructor(sources, persist) {
|
|
4575
|
+
this.sources = sources;
|
|
4576
|
+
this.persist = persist;
|
|
4577
|
+
}
|
|
4578
|
+
async getVtxoChain(vtxo) {
|
|
4579
|
+
let lastErr;
|
|
4580
|
+
for (const source of this.sources) {
|
|
4581
|
+
try {
|
|
4582
|
+
const chain = await source.getVtxoChain(vtxo);
|
|
4583
|
+
if (chain) return chain;
|
|
4584
|
+
} catch (e) {
|
|
4585
|
+
lastErr = e;
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
if (lastErr) throw lastErr;
|
|
4589
|
+
throw new Error(`no exit-data source resolved the chain for ${vtxo.txid}:${vtxo.vout}`);
|
|
4590
|
+
}
|
|
4591
|
+
async getVirtualTxs(txids) {
|
|
4592
|
+
const found = /* @__PURE__ */ new Map();
|
|
4593
|
+
let remaining = txids;
|
|
4594
|
+
for (const [i, source] of this.sources.entries()) {
|
|
4595
|
+
if (remaining.length === 0) break;
|
|
4596
|
+
let got;
|
|
4597
|
+
try {
|
|
4598
|
+
got = await source.getVirtualTxs(remaining);
|
|
4599
|
+
} catch {
|
|
4600
|
+
continue;
|
|
4601
|
+
}
|
|
4602
|
+
const fresh = [];
|
|
4603
|
+
for (const [txid, psbt] of got) {
|
|
4604
|
+
if (found.has(txid)) continue;
|
|
4605
|
+
found.set(txid, psbt);
|
|
4606
|
+
fresh.push({ txid, psbt, expiresAt: null, type: 0 /* Unspecified */ });
|
|
4607
|
+
}
|
|
4608
|
+
if (i > 0 && this.persist && fresh.length > 0) {
|
|
4609
|
+
try {
|
|
4610
|
+
await this.persist.upsertVirtualTxs(fresh);
|
|
4611
|
+
} catch {
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
remaining = txids.filter((t) => !found.has(t));
|
|
4615
|
+
}
|
|
4616
|
+
return [...found.values()];
|
|
4617
|
+
}
|
|
4618
|
+
};
|
|
4619
|
+
function createExitChainResolver(params) {
|
|
4620
|
+
const sources = [];
|
|
4621
|
+
if (params.repository) sources.push(new RepositoryExitDataSource(params.repository));
|
|
4622
|
+
if (params.extraSources) sources.push(...params.extraSources);
|
|
4623
|
+
sources.push(new IndexerExitDataSource(params.indexer));
|
|
4624
|
+
return new OrderedExitChainResolver(sources, params.repository);
|
|
4625
|
+
}
|
|
4626
|
+
|
|
4627
|
+
// src/providers/availability.ts
|
|
4628
|
+
function isRetryableProviderError(error) {
|
|
4629
|
+
return error instanceof chunkUHOHLN3C_cjs.ProviderUnavailableError || error instanceof chunkUHOHLN3C_cjs.FetchError || chunkUHOHLN3C_cjs.isFetchTimeoutError(error);
|
|
4630
|
+
}
|
|
4631
|
+
|
|
4632
|
+
// src/utils/syncCursors.ts
|
|
4633
|
+
var SAFETY_LAG_MS = 3e4;
|
|
4634
|
+
var OVERLAP_MS = 24 * 60 * 60 * 1e3;
|
|
4635
|
+
var walletStateLocks = /* @__PURE__ */ new WeakMap();
|
|
4636
|
+
async function updateWalletState(repo, updater) {
|
|
4637
|
+
const prev = walletStateLocks.get(repo) ?? Promise.resolve();
|
|
4638
|
+
const op = prev.then(async () => {
|
|
4639
|
+
const state = await repo.getWalletState() ?? {};
|
|
4640
|
+
await repo.saveWalletState(updater(state));
|
|
4641
|
+
});
|
|
4642
|
+
walletStateLocks.set(
|
|
4643
|
+
repo,
|
|
4644
|
+
op.catch(() => {
|
|
4645
|
+
})
|
|
4646
|
+
);
|
|
4647
|
+
return op;
|
|
4648
|
+
}
|
|
4649
|
+
var CURSOR_MIGRATED_KEY = "vtxoCursorMigrated";
|
|
4650
|
+
function hasMigrationMarker(state) {
|
|
4651
|
+
return state?.settings?.[CURSOR_MIGRATED_KEY] === true;
|
|
4652
|
+
}
|
|
4653
|
+
async function getSyncCursor(repo) {
|
|
4654
|
+
const state = await repo.getWalletState();
|
|
4655
|
+
if (!hasMigrationMarker(state)) return 0;
|
|
4656
|
+
return state?.lastSyncTime ?? 0;
|
|
4657
|
+
}
|
|
4658
|
+
async function advanceSyncCursor(repo, lastUpdatedAt) {
|
|
4659
|
+
await updateWalletState(repo, (state) => {
|
|
4660
|
+
const current = hasMigrationMarker(state) ? state.lastSyncTime ?? 0 : 0;
|
|
4661
|
+
return {
|
|
4662
|
+
...state,
|
|
4663
|
+
lastSyncTime: Math.max(current, lastUpdatedAt),
|
|
4664
|
+
settings: {
|
|
4665
|
+
...state.settings ?? {},
|
|
4666
|
+
[CURSOR_MIGRATED_KEY]: true
|
|
4667
|
+
}
|
|
4668
|
+
};
|
|
4669
|
+
});
|
|
4670
|
+
}
|
|
4671
|
+
async function clearSyncCursor(repo) {
|
|
4672
|
+
await updateWalletState(repo, (state) => {
|
|
4673
|
+
const { [CURSOR_MIGRATED_KEY]: _, ...restSettings } = state.settings ?? {};
|
|
4674
|
+
return {
|
|
4675
|
+
...state,
|
|
4676
|
+
lastSyncTime: void 0,
|
|
4677
|
+
settings: restSettings
|
|
4678
|
+
};
|
|
4679
|
+
});
|
|
4680
|
+
}
|
|
4681
|
+
function computeSyncWindow(cursor) {
|
|
4682
|
+
const after = Math.max(0, cursor - OVERLAP_MS);
|
|
4683
|
+
return { after };
|
|
4684
|
+
}
|
|
4685
|
+
function cursorCutoff(requestStartedAt) {
|
|
4686
|
+
return (requestStartedAt ?? Date.now()) - SAFETY_LAG_MS;
|
|
4687
|
+
}
|
|
4688
|
+
|
|
4689
|
+
// src/wallet/arkInfoSnapshot.ts
|
|
4690
|
+
var ARK_INFO_SNAPSHOT_KEY = "arkInfoSnapshot";
|
|
4691
|
+
var MalformedArkInfoSnapshotError = class extends Error {
|
|
4692
|
+
constructor(message, options) {
|
|
4693
|
+
super(message, { cause: options?.cause });
|
|
4694
|
+
this.name = "MalformedArkInfoSnapshotError";
|
|
4695
|
+
}
|
|
4696
|
+
};
|
|
4697
|
+
var CURRENT_VERSION = 1;
|
|
4698
|
+
function serializeArkInfoSnapshot(info, savedAt) {
|
|
4699
|
+
return {
|
|
4700
|
+
version: CURRENT_VERSION,
|
|
4701
|
+
savedAt,
|
|
4702
|
+
source: "arkade.getInfo",
|
|
4703
|
+
arkInfo: {
|
|
4704
|
+
network: info.network,
|
|
4705
|
+
signerPubkey: info.signerPubkey,
|
|
4706
|
+
checkpointTapscript: info.checkpointTapscript,
|
|
4707
|
+
forfeitAddress: info.forfeitAddress,
|
|
4708
|
+
forfeitPubkey: info.forfeitPubkey,
|
|
4709
|
+
unilateralExitDelay: info.unilateralExitDelay.toString(),
|
|
4710
|
+
boardingExitDelay: info.boardingExitDelay.toString(),
|
|
4711
|
+
sessionDuration: info.sessionDuration.toString(),
|
|
4712
|
+
dust: info.dust.toString(),
|
|
4713
|
+
fees: info.fees,
|
|
4714
|
+
digest: info.digest,
|
|
4715
|
+
version: info.version,
|
|
4716
|
+
vtxoMinAmount: info.vtxoMinAmount.toString(),
|
|
4717
|
+
vtxoMaxAmount: info.vtxoMaxAmount.toString(),
|
|
4718
|
+
utxoMinAmount: info.utxoMinAmount.toString(),
|
|
4719
|
+
utxoMaxAmount: info.utxoMaxAmount.toString(),
|
|
4720
|
+
deprecatedSigners: info.deprecatedSigners.map((s) => ({
|
|
4721
|
+
pubkey: s.pubkey,
|
|
4722
|
+
cutoffDate: s.cutoffDate.toString()
|
|
4723
|
+
})),
|
|
4724
|
+
scheduledSession: info.scheduledSession ? {
|
|
4725
|
+
duration: info.scheduledSession.duration.toString(),
|
|
4726
|
+
fees: info.scheduledSession.fees,
|
|
4727
|
+
nextEndTime: info.scheduledSession.nextEndTime.toString(),
|
|
4728
|
+
nextStartTime: info.scheduledSession.nextStartTime.toString(),
|
|
4729
|
+
period: info.scheduledSession.period.toString()
|
|
4730
|
+
} : void 0
|
|
4731
|
+
}
|
|
4732
|
+
};
|
|
4733
|
+
}
|
|
4734
|
+
function hydrateArkInfo(snapshot) {
|
|
4735
|
+
const a = snapshot.arkInfo;
|
|
4736
|
+
return {
|
|
4737
|
+
boardingExitDelay: BigInt(a.boardingExitDelay),
|
|
4738
|
+
checkpointTapscript: a.checkpointTapscript,
|
|
4739
|
+
deprecatedSigners: a.deprecatedSigners.map((s) => ({
|
|
4740
|
+
cutoffDate: BigInt(s.cutoffDate),
|
|
4741
|
+
pubkey: s.pubkey
|
|
4742
|
+
})),
|
|
4743
|
+
digest: a.digest,
|
|
4744
|
+
dust: BigInt(a.dust),
|
|
4745
|
+
fees: a.fees,
|
|
4746
|
+
forfeitAddress: a.forfeitAddress,
|
|
4747
|
+
forfeitPubkey: a.forfeitPubkey,
|
|
4748
|
+
network: a.network,
|
|
4749
|
+
scheduledSession: a.scheduledSession ? {
|
|
4750
|
+
duration: BigInt(a.scheduledSession.duration),
|
|
4751
|
+
fees: a.scheduledSession.fees,
|
|
4752
|
+
nextEndTime: BigInt(a.scheduledSession.nextEndTime),
|
|
4753
|
+
nextStartTime: BigInt(a.scheduledSession.nextStartTime),
|
|
4754
|
+
period: BigInt(a.scheduledSession.period)
|
|
4755
|
+
} : void 0,
|
|
4756
|
+
serviceStatus: {},
|
|
4757
|
+
sessionDuration: BigInt(a.sessionDuration),
|
|
4758
|
+
signerPubkey: a.signerPubkey,
|
|
4759
|
+
unilateralExitDelay: BigInt(a.unilateralExitDelay),
|
|
4760
|
+
utxoMaxAmount: BigInt(a.utxoMaxAmount),
|
|
4761
|
+
utxoMinAmount: BigInt(a.utxoMinAmount),
|
|
4762
|
+
version: a.version,
|
|
4763
|
+
vtxoMaxAmount: BigInt(a.vtxoMaxAmount),
|
|
4764
|
+
vtxoMinAmount: BigInt(a.vtxoMinAmount)
|
|
4765
|
+
};
|
|
4766
|
+
}
|
|
4767
|
+
var DECIMAL_STRING = /^-?\d+$/;
|
|
4768
|
+
function assertString(value, path) {
|
|
4769
|
+
if (typeof value !== "string") {
|
|
4770
|
+
throw new MalformedArkInfoSnapshotError(`${path} must be a string`);
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
function assertDecimalString(value, path) {
|
|
4774
|
+
assertString(value, path);
|
|
4775
|
+
if (!DECIMAL_STRING.test(value)) {
|
|
4776
|
+
throw new MalformedArkInfoSnapshotError(`${path} must be a decimal integer string`);
|
|
4777
|
+
}
|
|
4778
|
+
}
|
|
4779
|
+
function assertFeeInfo(value, path) {
|
|
4780
|
+
if (typeof value !== "object" || value === null) {
|
|
4781
|
+
throw new MalformedArkInfoSnapshotError(`${path} must be an object`);
|
|
4782
|
+
}
|
|
4783
|
+
const fees = value;
|
|
4784
|
+
assertString(fees.txFeeRate, `${path}.txFeeRate`);
|
|
4785
|
+
if (typeof fees.intentFee !== "object" || fees.intentFee === null) {
|
|
4786
|
+
throw new MalformedArkInfoSnapshotError(`${path}.intentFee must be an object`);
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
function parseStoredArkInfoSnapshot(raw) {
|
|
4790
|
+
if (typeof raw !== "object" || raw === null) {
|
|
4791
|
+
throw new MalformedArkInfoSnapshotError("snapshot must be an object");
|
|
4792
|
+
}
|
|
4793
|
+
const snap = raw;
|
|
4794
|
+
if (snap.version !== CURRENT_VERSION) {
|
|
4795
|
+
throw new MalformedArkInfoSnapshotError(
|
|
4796
|
+
`unsupported snapshot version: ${String(snap.version)}`
|
|
4797
|
+
);
|
|
4798
|
+
}
|
|
4799
|
+
if (typeof snap.savedAt !== "number") {
|
|
4800
|
+
throw new MalformedArkInfoSnapshotError("savedAt must be a number");
|
|
4801
|
+
}
|
|
4802
|
+
if (snap.source !== "arkade.getInfo") {
|
|
4803
|
+
throw new MalformedArkInfoSnapshotError(`unexpected source: ${String(snap.source)}`);
|
|
4804
|
+
}
|
|
4805
|
+
if (typeof snap.arkInfo !== "object" || snap.arkInfo === null) {
|
|
4806
|
+
throw new MalformedArkInfoSnapshotError("arkInfo must be an object");
|
|
4807
|
+
}
|
|
4808
|
+
const a = snap.arkInfo;
|
|
4809
|
+
for (const field of [
|
|
4810
|
+
"network",
|
|
4811
|
+
"signerPubkey",
|
|
4812
|
+
"checkpointTapscript",
|
|
4813
|
+
"forfeitAddress",
|
|
4814
|
+
"forfeitPubkey",
|
|
4815
|
+
"digest",
|
|
4816
|
+
"version"
|
|
4817
|
+
]) {
|
|
4818
|
+
assertString(a[field], `arkInfo.${field}`);
|
|
4819
|
+
}
|
|
4820
|
+
for (const field of [
|
|
4821
|
+
"unilateralExitDelay",
|
|
4822
|
+
"boardingExitDelay",
|
|
4823
|
+
"sessionDuration",
|
|
4824
|
+
"dust",
|
|
4825
|
+
"vtxoMinAmount",
|
|
4826
|
+
"vtxoMaxAmount",
|
|
4827
|
+
"utxoMinAmount",
|
|
4828
|
+
"utxoMaxAmount"
|
|
4829
|
+
]) {
|
|
4830
|
+
assertDecimalString(a[field], `arkInfo.${field}`);
|
|
4831
|
+
}
|
|
4832
|
+
assertFeeInfo(a.fees, "arkInfo.fees");
|
|
4833
|
+
if (!Array.isArray(a.deprecatedSigners)) {
|
|
4834
|
+
throw new MalformedArkInfoSnapshotError("arkInfo.deprecatedSigners must be an array");
|
|
4835
|
+
}
|
|
4836
|
+
a.deprecatedSigners.forEach((s, i) => {
|
|
4837
|
+
if (typeof s !== "object" || s === null) {
|
|
4838
|
+
throw new MalformedArkInfoSnapshotError(
|
|
4839
|
+
`arkInfo.deprecatedSigners[${i}] must be an object`
|
|
4840
|
+
);
|
|
4841
|
+
}
|
|
4842
|
+
const signer = s;
|
|
4843
|
+
assertString(signer.pubkey, `arkInfo.deprecatedSigners[${i}].pubkey`);
|
|
4844
|
+
assertDecimalString(signer.cutoffDate, `arkInfo.deprecatedSigners[${i}].cutoffDate`);
|
|
4845
|
+
});
|
|
4846
|
+
if (a.scheduledSession !== void 0) {
|
|
4847
|
+
if (typeof a.scheduledSession !== "object" || a.scheduledSession === null) {
|
|
4848
|
+
throw new MalformedArkInfoSnapshotError("arkInfo.scheduledSession must be an object");
|
|
4849
|
+
}
|
|
4850
|
+
const s = a.scheduledSession;
|
|
4851
|
+
for (const field of ["duration", "nextEndTime", "nextStartTime", "period"]) {
|
|
4852
|
+
assertDecimalString(s[field], `arkInfo.scheduledSession.${field}`);
|
|
4853
|
+
}
|
|
4854
|
+
assertFeeInfo(s.fees, "arkInfo.scheduledSession.fees");
|
|
4855
|
+
}
|
|
4856
|
+
return raw;
|
|
4857
|
+
}
|
|
4858
|
+
async function loadArkInfoSnapshot(repo) {
|
|
4859
|
+
const state = await repo.getWalletState();
|
|
4860
|
+
const raw = state?.settings?.[ARK_INFO_SNAPSHOT_KEY];
|
|
4861
|
+
if (raw === void 0 || raw === null) return null;
|
|
4862
|
+
return parseStoredArkInfoSnapshot(raw);
|
|
4863
|
+
}
|
|
4864
|
+
async function saveArkInfoSnapshot(repo, info, savedAt) {
|
|
4865
|
+
const snapshot = serializeArkInfoSnapshot(info, savedAt);
|
|
4866
|
+
await updateWalletState(repo, (state) => ({
|
|
4867
|
+
...state,
|
|
4868
|
+
settings: {
|
|
4869
|
+
...state.settings ?? {},
|
|
4870
|
+
[ARK_INFO_SNAPSHOT_KEY]: snapshot
|
|
4871
|
+
}
|
|
4872
|
+
}));
|
|
4873
|
+
}
|
|
4874
|
+
async function resolveArkInfo(arkProvider, walletRepository) {
|
|
4875
|
+
let info;
|
|
4876
|
+
try {
|
|
4877
|
+
info = await arkProvider.getInfo();
|
|
4878
|
+
} catch (err) {
|
|
4879
|
+
if (!isRetryableProviderError(err)) throw err;
|
|
4880
|
+
const snapshot = await loadArkInfoSnapshot(walletRepository);
|
|
4881
|
+
if (!snapshot) {
|
|
4882
|
+
throw new chunkUHOHLN3C_cjs.ProviderUnavailableError(
|
|
4883
|
+
"Arkade server info is unavailable and no cached snapshot exists",
|
|
4884
|
+
{ cause: err }
|
|
4885
|
+
);
|
|
4886
|
+
}
|
|
4887
|
+
return { info: hydrateArkInfo(snapshot), source: "cache", lastOnlineAt: snapshot.savedAt };
|
|
4888
|
+
}
|
|
4889
|
+
return { info, source: "live" };
|
|
4890
|
+
}
|
|
4891
|
+
async function saveValidatedArkInfoSnapshot(repo, info, savedAt) {
|
|
4892
|
+
try {
|
|
4893
|
+
await saveArkInfoSnapshot(repo, info, savedAt);
|
|
4894
|
+
} catch (err) {
|
|
4895
|
+
console.warn("Failed to persist Ark info snapshot", err);
|
|
4896
|
+
}
|
|
4897
|
+
}
|
|
4898
|
+
var TxTree = class {
|
|
4899
|
+
constructor(root, children = /* @__PURE__ */ new Map()) {
|
|
4900
|
+
this.root = root;
|
|
4901
|
+
this.children = children;
|
|
4902
|
+
}
|
|
4903
|
+
static create(chunks) {
|
|
4904
|
+
if (chunks.length === 0) {
|
|
4905
|
+
throw new Error("empty chunks");
|
|
4906
|
+
}
|
|
4907
|
+
const chunksByTxid = /* @__PURE__ */ new Map();
|
|
4908
|
+
for (const chunk of chunks) {
|
|
4290
4909
|
const decodedChunk = decodeNode(chunk);
|
|
4291
4910
|
const txid = decodedChunk.tx.id;
|
|
4292
4911
|
chunksByTxid.set(txid, decodedChunk);
|
|
@@ -4791,7 +5410,7 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4791
5410
|
const virtualCoins = await this.wallet.getVtxos({
|
|
4792
5411
|
withRecoverable: false
|
|
4793
5412
|
});
|
|
4794
|
-
const controlAssetRef = params.controlAssetId ?
|
|
5413
|
+
const controlAssetRef = params.controlAssetId ? chunkUHOHLN3C_cjs.AssetRef.fromId(chunkUHOHLN3C_cjs.AssetId.fromString(params.controlAssetId)) : null;
|
|
4795
5414
|
const coinSelection = selectVirtualCoins(virtualCoins, Number(this.wallet.dustAmount));
|
|
4796
5415
|
let totalBtcSelected = 0n;
|
|
4797
5416
|
const assetChanges = /* @__PURE__ */ new Map();
|
|
@@ -4804,8 +5423,8 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4804
5423
|
}
|
|
4805
5424
|
}
|
|
4806
5425
|
const groups = [];
|
|
4807
|
-
const issuedAssetOutput =
|
|
4808
|
-
const issuedAssetGroup =
|
|
5426
|
+
const issuedAssetOutput = chunkUHOHLN3C_cjs.AssetOutput.create(0, params.amount);
|
|
5427
|
+
const issuedAssetGroup = chunkUHOHLN3C_cjs.AssetGroup.create(
|
|
4809
5428
|
null,
|
|
4810
5429
|
controlAssetRef,
|
|
4811
5430
|
[],
|
|
@@ -4820,15 +5439,15 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4820
5439
|
for (const [inputIndex, assets] of assetInputs) {
|
|
4821
5440
|
for (const asset of assets) {
|
|
4822
5441
|
if (asset.assetId !== assetId) continue;
|
|
4823
|
-
changeInputs.push(
|
|
5442
|
+
changeInputs.push(chunkUHOHLN3C_cjs.AssetInput.create(inputIndex, asset.amount));
|
|
4824
5443
|
}
|
|
4825
5444
|
}
|
|
4826
5445
|
groups.push(
|
|
4827
|
-
|
|
4828
|
-
|
|
5446
|
+
chunkUHOHLN3C_cjs.AssetGroup.create(
|
|
5447
|
+
chunkUHOHLN3C_cjs.AssetId.fromString(assetId),
|
|
4829
5448
|
null,
|
|
4830
5449
|
changeInputs,
|
|
4831
|
-
[
|
|
5450
|
+
[chunkUHOHLN3C_cjs.AssetOutput.create(0, amount)],
|
|
4832
5451
|
[]
|
|
4833
5452
|
)
|
|
4834
5453
|
);
|
|
@@ -4841,7 +5460,7 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4841
5460
|
script: outputAddress.pkScript,
|
|
4842
5461
|
amount: BigInt(totalBtcSelected)
|
|
4843
5462
|
},
|
|
4844
|
-
Extension.create([
|
|
5463
|
+
Extension.create([chunkUHOHLN3C_cjs.Packet.create(groups)]).txOut()
|
|
4845
5464
|
];
|
|
4846
5465
|
const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(
|
|
4847
5466
|
coinSelection.inputs,
|
|
@@ -4849,7 +5468,7 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4849
5468
|
);
|
|
4850
5469
|
return {
|
|
4851
5470
|
arkTxId: arkTxid,
|
|
4852
|
-
assetId:
|
|
5471
|
+
assetId: chunkUHOHLN3C_cjs.AssetId.create(arkTxid, 0).toString()
|
|
4853
5472
|
};
|
|
4854
5473
|
}
|
|
4855
5474
|
/**
|
|
@@ -4921,16 +5540,16 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4921
5540
|
for (const [inputIndex, assets] of assetInputs) {
|
|
4922
5541
|
for (const asset of assets) {
|
|
4923
5542
|
if (asset.assetId !== params.assetId) continue;
|
|
4924
|
-
reissueInputs.push(
|
|
5543
|
+
reissueInputs.push(chunkUHOHLN3C_cjs.AssetInput.create(inputIndex, asset.amount));
|
|
4925
5544
|
}
|
|
4926
5545
|
}
|
|
4927
5546
|
const totalAssetAmount = assetToReissueAmount + params.amount;
|
|
4928
|
-
const reissueAssetIdObj =
|
|
4929
|
-
const reissueAssetGroup =
|
|
5547
|
+
const reissueAssetIdObj = chunkUHOHLN3C_cjs.AssetId.fromString(params.assetId);
|
|
5548
|
+
const reissueAssetGroup = chunkUHOHLN3C_cjs.AssetGroup.create(
|
|
4930
5549
|
reissueAssetIdObj,
|
|
4931
5550
|
null,
|
|
4932
5551
|
reissueInputs,
|
|
4933
|
-
[
|
|
5552
|
+
[chunkUHOHLN3C_cjs.AssetOutput.create(0, totalAssetAmount)],
|
|
4934
5553
|
[]
|
|
4935
5554
|
);
|
|
4936
5555
|
const groups = [reissueAssetGroup];
|
|
@@ -4939,15 +5558,15 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4939
5558
|
for (const [inputIndex, assets] of assetInputs) {
|
|
4940
5559
|
for (const asset of assets) {
|
|
4941
5560
|
if (asset.assetId !== assetId) continue;
|
|
4942
|
-
changeInputs.push(
|
|
5561
|
+
changeInputs.push(chunkUHOHLN3C_cjs.AssetInput.create(inputIndex, asset.amount));
|
|
4943
5562
|
}
|
|
4944
5563
|
}
|
|
4945
5564
|
groups.push(
|
|
4946
|
-
|
|
4947
|
-
|
|
5565
|
+
chunkUHOHLN3C_cjs.AssetGroup.create(
|
|
5566
|
+
chunkUHOHLN3C_cjs.AssetId.fromString(assetId),
|
|
4948
5567
|
null,
|
|
4949
5568
|
changeInputs,
|
|
4950
|
-
[
|
|
5569
|
+
[chunkUHOHLN3C_cjs.AssetOutput.create(0, amount)],
|
|
4951
5570
|
[]
|
|
4952
5571
|
)
|
|
4953
5572
|
);
|
|
@@ -4959,7 +5578,7 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4959
5578
|
script: outputAddress.pkScript,
|
|
4960
5579
|
amount: BigInt(totalBtcSelected)
|
|
4961
5580
|
},
|
|
4962
|
-
Extension.create([
|
|
5581
|
+
Extension.create([chunkUHOHLN3C_cjs.Packet.create(groups)]).txOut()
|
|
4963
5582
|
];
|
|
4964
5583
|
const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
|
|
4965
5584
|
return arkTxid;
|
|
@@ -5026,15 +5645,15 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
5026
5645
|
for (const [inputIndex, assets] of assetInputs) {
|
|
5027
5646
|
for (const asset of assets) {
|
|
5028
5647
|
if (asset.assetId !== assetId) continue;
|
|
5029
|
-
changeInputs.push(
|
|
5648
|
+
changeInputs.push(chunkUHOHLN3C_cjs.AssetInput.create(inputIndex, asset.amount));
|
|
5030
5649
|
}
|
|
5031
5650
|
}
|
|
5032
5651
|
groups.push(
|
|
5033
|
-
|
|
5034
|
-
|
|
5652
|
+
chunkUHOHLN3C_cjs.AssetGroup.create(
|
|
5653
|
+
chunkUHOHLN3C_cjs.AssetId.fromString(assetId),
|
|
5035
5654
|
null,
|
|
5036
5655
|
changeInputs,
|
|
5037
|
-
amount > 0n ? [
|
|
5656
|
+
amount > 0n ? [chunkUHOHLN3C_cjs.AssetOutput.create(0, amount)] : [],
|
|
5038
5657
|
[]
|
|
5039
5658
|
)
|
|
5040
5659
|
);
|
|
@@ -5046,7 +5665,7 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
5046
5665
|
script: outputAddress.pkScript,
|
|
5047
5666
|
amount: BigInt(totalBtcSelected)
|
|
5048
5667
|
},
|
|
5049
|
-
Extension.create([
|
|
5668
|
+
Extension.create([chunkUHOHLN3C_cjs.Packet.create(groups)]).txOut()
|
|
5050
5669
|
];
|
|
5051
5670
|
const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
|
|
5052
5671
|
return arkTxid;
|
|
@@ -5071,7 +5690,7 @@ function castMetadata(metadata) {
|
|
|
5071
5690
|
} else {
|
|
5072
5691
|
throw new Error("Invalid metadata value type");
|
|
5073
5692
|
}
|
|
5074
|
-
md.push(
|
|
5693
|
+
md.push(chunkUHOHLN3C_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
|
|
5075
5694
|
}
|
|
5076
5695
|
return md;
|
|
5077
5696
|
}
|
|
@@ -5356,7 +5975,7 @@ async function makeSignedDelegateIntent(identity, coins, outputs, onchainOutputs
|
|
|
5356
5975
|
expire_at: 0,
|
|
5357
5976
|
cosigners_public_keys: cosignerPubKeys
|
|
5358
5977
|
};
|
|
5359
|
-
const proof =
|
|
5978
|
+
const proof = chunkUHOHLN3C_cjs.Intent.create(message, coins, outputs);
|
|
5360
5979
|
const signedProof = await identity.sign(proof);
|
|
5361
5980
|
return {
|
|
5362
5981
|
proof: base.base64.encode(signedProof.toPSBT()),
|
|
@@ -5385,20 +6004,6 @@ function isAnnotated(v) {
|
|
|
5385
6004
|
return v.tapTree !== void 0 && v.forfeitTapLeafScript !== void 0 && v.intentTapLeafScript !== void 0;
|
|
5386
6005
|
}
|
|
5387
6006
|
|
|
5388
|
-
// src/repositories/virtualTxRepository.ts
|
|
5389
|
-
var ChainedTxType = /* @__PURE__ */ ((ChainedTxType2) => {
|
|
5390
|
-
ChainedTxType2[ChainedTxType2["Unspecified"] = 0] = "Unspecified";
|
|
5391
|
-
ChainedTxType2[ChainedTxType2["Commitment"] = 1] = "Commitment";
|
|
5392
|
-
ChainedTxType2[ChainedTxType2["Ark"] = 2] = "Ark";
|
|
5393
|
-
ChainedTxType2[ChainedTxType2["Tree"] = 3] = "Tree";
|
|
5394
|
-
ChainedTxType2[ChainedTxType2["Checkpoint"] = 4] = "Checkpoint";
|
|
5395
|
-
return ChainedTxType2;
|
|
5396
|
-
})(ChainedTxType || {});
|
|
5397
|
-
function mergeChainedTxType(incoming, prev) {
|
|
5398
|
-
if (incoming !== 0 /* Unspecified */) return incoming;
|
|
5399
|
-
return prev ?? 0 /* Unspecified */;
|
|
5400
|
-
}
|
|
5401
|
-
|
|
5402
6007
|
// src/repositories/inMemory/intentRepository.ts
|
|
5403
6008
|
var InMemoryIntentRepository = class {
|
|
5404
6009
|
version = 1;
|
|
@@ -7454,7 +8059,7 @@ var ContractWatcher = class {
|
|
|
7454
8059
|
this.connectionState = "connected";
|
|
7455
8060
|
this.reconnectAttempts = 0;
|
|
7456
8061
|
this.listenLoop().catch((e) => {
|
|
7457
|
-
if (
|
|
8062
|
+
if (chunkUHOHLN3C_cjs.isEventSourceError(e)) {
|
|
7458
8063
|
console.debug("ContractWatcher subscription disconnected; reconnecting");
|
|
7459
8064
|
} else {
|
|
7460
8065
|
console.error(e);
|
|
@@ -7818,66 +8423,9 @@ function dedupeOutpoints(outpoints) {
|
|
|
7818
8423
|
return out;
|
|
7819
8424
|
}
|
|
7820
8425
|
|
|
7821
|
-
// src/
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
var walletStateLocks = /* @__PURE__ */ new WeakMap();
|
|
7825
|
-
async function updateWalletState(repo, updater) {
|
|
7826
|
-
const prev = walletStateLocks.get(repo) ?? Promise.resolve();
|
|
7827
|
-
const op = prev.then(async () => {
|
|
7828
|
-
const state = await repo.getWalletState() ?? {};
|
|
7829
|
-
await repo.saveWalletState(updater(state));
|
|
7830
|
-
});
|
|
7831
|
-
walletStateLocks.set(
|
|
7832
|
-
repo,
|
|
7833
|
-
op.catch(() => {
|
|
7834
|
-
})
|
|
7835
|
-
);
|
|
7836
|
-
return op;
|
|
7837
|
-
}
|
|
7838
|
-
var CURSOR_MIGRATED_KEY = "vtxoCursorMigrated";
|
|
7839
|
-
function hasMigrationMarker(state) {
|
|
7840
|
-
return state?.settings?.[CURSOR_MIGRATED_KEY] === true;
|
|
7841
|
-
}
|
|
7842
|
-
async function getSyncCursor(repo) {
|
|
7843
|
-
const state = await repo.getWalletState();
|
|
7844
|
-
if (!hasMigrationMarker(state)) return 0;
|
|
7845
|
-
return state?.lastSyncTime ?? 0;
|
|
7846
|
-
}
|
|
7847
|
-
async function advanceSyncCursor(repo, lastUpdatedAt) {
|
|
7848
|
-
await updateWalletState(repo, (state) => {
|
|
7849
|
-
const current = hasMigrationMarker(state) ? state.lastSyncTime ?? 0 : 0;
|
|
7850
|
-
return {
|
|
7851
|
-
...state,
|
|
7852
|
-
lastSyncTime: Math.max(current, lastUpdatedAt),
|
|
7853
|
-
settings: {
|
|
7854
|
-
...state.settings ?? {},
|
|
7855
|
-
[CURSOR_MIGRATED_KEY]: true
|
|
7856
|
-
}
|
|
7857
|
-
};
|
|
7858
|
-
});
|
|
7859
|
-
}
|
|
7860
|
-
async function clearSyncCursor(repo) {
|
|
7861
|
-
await updateWalletState(repo, (state) => {
|
|
7862
|
-
const { [CURSOR_MIGRATED_KEY]: _, ...restSettings } = state.settings ?? {};
|
|
7863
|
-
return {
|
|
7864
|
-
...state,
|
|
7865
|
-
lastSyncTime: void 0,
|
|
7866
|
-
settings: restSettings
|
|
7867
|
-
};
|
|
7868
|
-
});
|
|
7869
|
-
}
|
|
7870
|
-
function computeSyncWindow(cursor) {
|
|
7871
|
-
const after = Math.max(0, cursor - OVERLAP_MS);
|
|
7872
|
-
return { after };
|
|
7873
|
-
}
|
|
7874
|
-
function cursorCutoff(requestStartedAt) {
|
|
7875
|
-
return (requestStartedAt ?? Date.now()) - SAFETY_LAG_MS;
|
|
7876
|
-
}
|
|
7877
|
-
|
|
7878
|
-
// src/contracts/contractManager.ts
|
|
7879
|
-
function areCoalescibleContractTypes(a, b) {
|
|
7880
|
-
return a === "default" && b === "boarding" || a === "boarding" && b === "default";
|
|
8426
|
+
// src/contracts/contractManager.ts
|
|
8427
|
+
function areCoalescibleContractTypes(a, b) {
|
|
8428
|
+
return a === "default" && b === "boarding" || a === "boarding" && b === "default";
|
|
7881
8429
|
}
|
|
7882
8430
|
var SCAN_MAX_INDEX = 1e4;
|
|
7883
8431
|
var DEFAULT_SCAN_BATCH = 10;
|
|
@@ -7887,6 +8435,10 @@ var ContractManager = class _ContractManager {
|
|
|
7887
8435
|
initialized = false;
|
|
7888
8436
|
eventCallbacks = /* @__PURE__ */ new Set();
|
|
7889
8437
|
stopWatcherFn;
|
|
8438
|
+
/** `undefined` while online; the failure reason once a sync degrades. */
|
|
8439
|
+
syncDegradedReason;
|
|
8440
|
+
/** Epoch-ms of the last successful provider sync, if any. */
|
|
8441
|
+
lastSyncedAt;
|
|
7890
8442
|
constructor(config) {
|
|
7891
8443
|
this.config = config;
|
|
7892
8444
|
this.watcher = new ContractWatcher({
|
|
@@ -7909,6 +8461,26 @@ var ContractManager = class _ContractManager {
|
|
|
7909
8461
|
await cm.initialize();
|
|
7910
8462
|
return cm;
|
|
7911
8463
|
}
|
|
8464
|
+
/**
|
|
8465
|
+
* Latest provider-sync health. See {@link ContractSyncState}. Degradation is
|
|
8466
|
+
* recorded by {@link initialize}, {@link getContractsWithVtxos}, and
|
|
8467
|
+
* {@link createContract}; it flips back to `online` on the next successful
|
|
8468
|
+
* sync. Purely a freshness signal — not a source of truth for wallet data.
|
|
8469
|
+
*/
|
|
8470
|
+
getSyncState() {
|
|
8471
|
+
return this.syncDegradedReason === void 0 ? { mode: "online", lastSyncedAt: this.lastSyncedAt } : {
|
|
8472
|
+
mode: "degraded",
|
|
8473
|
+
reason: this.syncDegradedReason,
|
|
8474
|
+
lastSyncedAt: this.lastSyncedAt
|
|
8475
|
+
};
|
|
8476
|
+
}
|
|
8477
|
+
markSyncOnline() {
|
|
8478
|
+
this.syncDegradedReason = void 0;
|
|
8479
|
+
this.lastSyncedAt = Date.now();
|
|
8480
|
+
}
|
|
8481
|
+
markSyncDegraded(err) {
|
|
8482
|
+
this.syncDegradedReason = err instanceof Error ? err.message : String(err);
|
|
8483
|
+
}
|
|
7912
8484
|
async initialize() {
|
|
7913
8485
|
if (this.initialized) {
|
|
7914
8486
|
return;
|
|
@@ -7917,7 +8489,13 @@ var ContractManager = class _ContractManager {
|
|
|
7917
8489
|
for (const contract of contracts) {
|
|
7918
8490
|
await this.watcher.addContract(contract);
|
|
7919
8491
|
}
|
|
7920
|
-
|
|
8492
|
+
try {
|
|
8493
|
+
await this.reconcileWatched();
|
|
8494
|
+
this.markSyncOnline();
|
|
8495
|
+
} catch (err) {
|
|
8496
|
+
if (!isRetryableProviderError(err)) throw err;
|
|
8497
|
+
this.markSyncDegraded(err);
|
|
8498
|
+
}
|
|
7921
8499
|
this.initialized = true;
|
|
7922
8500
|
this.stopWatcherFn = await this.watcher.startWatching((event) => {
|
|
7923
8501
|
this.handleContractEvent(event).catch((error) => {
|
|
@@ -7971,7 +8549,13 @@ var ContractManager = class _ContractManager {
|
|
|
7971
8549
|
async createContract(params) {
|
|
7972
8550
|
const { contract, persisted } = await this.upsertContract(params);
|
|
7973
8551
|
if (persisted) {
|
|
7974
|
-
|
|
8552
|
+
try {
|
|
8553
|
+
await this.fetchContractVxosFromIndexer([contract]);
|
|
8554
|
+
this.markSyncOnline();
|
|
8555
|
+
} catch (err) {
|
|
8556
|
+
if (!isRetryableProviderError(err)) throw err;
|
|
8557
|
+
this.markSyncDegraded(err);
|
|
8558
|
+
}
|
|
7975
8559
|
await this.watcher.addContract(contract);
|
|
7976
8560
|
}
|
|
7977
8561
|
return contract;
|
|
@@ -8170,7 +8754,13 @@ var ContractManager = class _ContractManager {
|
|
|
8170
8754
|
}
|
|
8171
8755
|
async getContractsWithVtxos(filter, pageSize) {
|
|
8172
8756
|
const contracts = await this.getContracts(filter);
|
|
8173
|
-
|
|
8757
|
+
try {
|
|
8758
|
+
await this.syncContracts({ contracts, pageSize });
|
|
8759
|
+
this.markSyncOnline();
|
|
8760
|
+
} catch (err) {
|
|
8761
|
+
if (!isRetryableProviderError(err)) throw err;
|
|
8762
|
+
this.markSyncDegraded(err);
|
|
8763
|
+
}
|
|
8174
8764
|
const vtxos = await this.getVtxosForContracts(contracts);
|
|
8175
8765
|
return contracts.map((contract) => ({
|
|
8176
8766
|
contract,
|
|
@@ -8408,15 +8998,33 @@ var ContractManager = class _ContractManager {
|
|
|
8408
8998
|
* Handle events from the watcher.
|
|
8409
8999
|
*/
|
|
8410
9000
|
async handleContractEvent(event) {
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
9001
|
+
try {
|
|
9002
|
+
switch (event.type) {
|
|
9003
|
+
// Delta-sync only the changed virtual outputs for this contract.
|
|
9004
|
+
case "vtxo_received":
|
|
9005
|
+
await this.syncContracts({ contracts: [event.contract] });
|
|
9006
|
+
this.markSyncOnline();
|
|
9007
|
+
break;
|
|
9008
|
+
case "vtxo_spent":
|
|
9009
|
+
await this.syncContracts({ contracts: [event.contract] });
|
|
9010
|
+
this.markSyncOnline();
|
|
9011
|
+
if (this.config.onVtxosSpent) {
|
|
9012
|
+
try {
|
|
9013
|
+
await this.config.onVtxosSpent(
|
|
9014
|
+
event.vtxos.map((v) => ({ txid: v.txid, vout: v.vout }))
|
|
9015
|
+
);
|
|
9016
|
+
} catch {
|
|
9017
|
+
}
|
|
9018
|
+
}
|
|
9019
|
+
break;
|
|
9020
|
+
case "connection_reset":
|
|
9021
|
+
await this.reconcileWatched();
|
|
9022
|
+
this.markSyncOnline();
|
|
9023
|
+
break;
|
|
9024
|
+
}
|
|
9025
|
+
} catch (err) {
|
|
9026
|
+
if (!isRetryableProviderError(err)) throw err;
|
|
9027
|
+
this.markSyncDegraded(err);
|
|
8420
9028
|
}
|
|
8421
9029
|
this.emitEvent(event);
|
|
8422
9030
|
}
|
|
@@ -8498,6 +9106,12 @@ var ContractManager = class _ContractManager {
|
|
|
8498
9106
|
contract,
|
|
8499
9107
|
filtered
|
|
8500
9108
|
);
|
|
9109
|
+
if (this.config.onVtxosPersisted) {
|
|
9110
|
+
try {
|
|
9111
|
+
await this.config.onVtxosPersisted(contract, filtered);
|
|
9112
|
+
} catch {
|
|
9113
|
+
}
|
|
9114
|
+
}
|
|
8501
9115
|
}
|
|
8502
9116
|
}
|
|
8503
9117
|
async fetchContractVxosFromIndexer(contracts, pageSize, syncWindow) {
|
|
@@ -8518,6 +9132,15 @@ var ContractManager = class _ContractManager {
|
|
|
8518
9132
|
contract,
|
|
8519
9133
|
filtered
|
|
8520
9134
|
);
|
|
9135
|
+
if (this.config.onVtxosPersisted) {
|
|
9136
|
+
try {
|
|
9137
|
+
await this.config.onVtxosPersisted(
|
|
9138
|
+
contract,
|
|
9139
|
+
filtered
|
|
9140
|
+
);
|
|
9141
|
+
} catch {
|
|
9142
|
+
}
|
|
9143
|
+
}
|
|
8521
9144
|
}
|
|
8522
9145
|
}
|
|
8523
9146
|
return result;
|
|
@@ -9391,6 +10014,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9391
10014
|
* (ContractManager isn't given it); `undefined` ⇒ no-op.
|
|
9392
10015
|
*/
|
|
9393
10016
|
virtualTxRepository;
|
|
10017
|
+
/** Opt-in exit-data capture settings; see {@link StorageConfig.exitDataCapture}. */
|
|
10018
|
+
exitDataCapture;
|
|
9394
10019
|
_assetManager;
|
|
9395
10020
|
walletContractTimelocks;
|
|
9396
10021
|
// Outpoints ("txid:vout") committed to an in-flight settle/send. Filtered
|
|
@@ -9433,6 +10058,72 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9433
10058
|
* construction-time snapshot for their lifetime.
|
|
9434
10059
|
*/
|
|
9435
10060
|
_arkServerPublicKey;
|
|
10061
|
+
/**
|
|
10062
|
+
* Whether this wallet was constructed from live operator server-info
|
|
10063
|
+
* (`"live"`) or from a cached snapshot because the operator was unreachable
|
|
10064
|
+
* (`"cache"`). Freshness signal for {@link getProviderConnectionState}.
|
|
10065
|
+
*/
|
|
10066
|
+
_serverInfoSource = "live";
|
|
10067
|
+
/**
|
|
10068
|
+
* Epoch-ms of the last known live operator contact: construction time on the
|
|
10069
|
+
* `live` boot path, the cached snapshot's `savedAt` on the `cache` path.
|
|
10070
|
+
*/
|
|
10071
|
+
_serverInfoLastOnlineAt;
|
|
10072
|
+
/** @see {@link _serverInfoSource} */
|
|
10073
|
+
get serverInfoSource() {
|
|
10074
|
+
return this._serverInfoSource;
|
|
10075
|
+
}
|
|
10076
|
+
/**
|
|
10077
|
+
* Composed provider-connection freshness: the boot server-info source
|
|
10078
|
+
* (Arkade) combined with the contract-manager's indexer-sync health, if the
|
|
10079
|
+
* manager has been initialized. Reads no live provider state — it never
|
|
10080
|
+
* forces a `ContractManager` to construct — so it is safe for readonly
|
|
10081
|
+
* callers that only use address/balance APIs.
|
|
10082
|
+
*
|
|
10083
|
+
* - Boot fell back to a cached snapshot → degraded on `arkade` (`cache`).
|
|
10084
|
+
* - Otherwise, if the contract manager has degraded to repository data →
|
|
10085
|
+
* degraded on `indexer` (`repository`).
|
|
10086
|
+
* - Otherwise online.
|
|
10087
|
+
*
|
|
10088
|
+
* This only describes sync freshness; wallet balances/VTXOs are always read
|
|
10089
|
+
* from the repository regardless of this state.
|
|
10090
|
+
*/
|
|
10091
|
+
getProviderConnectionState() {
|
|
10092
|
+
if (this._serverInfoSource === "cache") {
|
|
10093
|
+
return {
|
|
10094
|
+
mode: "degraded",
|
|
10095
|
+
source: "cache",
|
|
10096
|
+
provider: "arkade",
|
|
10097
|
+
reason: "constructed from cached server-info; operator was unreachable at boot",
|
|
10098
|
+
lastOnlineAt: this._serverInfoLastOnlineAt
|
|
10099
|
+
};
|
|
10100
|
+
}
|
|
10101
|
+
const sync = this._contractManager?.getSyncState();
|
|
10102
|
+
if (sync?.mode === "degraded") {
|
|
10103
|
+
return {
|
|
10104
|
+
mode: "degraded",
|
|
10105
|
+
source: "repository",
|
|
10106
|
+
provider: "indexer",
|
|
10107
|
+
reason: sync.reason,
|
|
10108
|
+
lastOnlineAt: sync.lastSyncedAt ?? this._serverInfoLastOnlineAt
|
|
10109
|
+
};
|
|
10110
|
+
}
|
|
10111
|
+
return {
|
|
10112
|
+
mode: "online",
|
|
10113
|
+
source: "live",
|
|
10114
|
+
lastOnlineAt: sync?.lastSyncedAt ?? this._serverInfoLastOnlineAt ?? 0
|
|
10115
|
+
};
|
|
10116
|
+
}
|
|
10117
|
+
/**
|
|
10118
|
+
* The contract-manager's current provider-sync health **without forcing it
|
|
10119
|
+
* to initialize** — reads the already-constructed manager, or reports
|
|
10120
|
+
* `online` when none exists yet. Unlike {@link getContractManager}, this
|
|
10121
|
+
* never triggers a remote sync, so it is safe on a pure diagnostics path
|
|
10122
|
+
* (e.g. the service-worker sync-state message).
|
|
10123
|
+
*/
|
|
10124
|
+
getContractSyncState() {
|
|
10125
|
+
return this._contractManager?.getSyncState() ?? { mode: "online" };
|
|
10126
|
+
}
|
|
9436
10127
|
/**
|
|
9437
10128
|
* x-only hex of the operator's deprecated signer keys (from
|
|
9438
10129
|
* `ArkInfo.deprecatedSigners`), cached for the OFFLINE read/watch paths.
|
|
@@ -9548,7 +10239,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9548
10239
|
*/
|
|
9549
10240
|
static async setupWalletConfig(config, pubKey) {
|
|
9550
10241
|
const arkadeServerUrl = getArkadeServerUrl(config);
|
|
9551
|
-
const arkProvider = config.arkProvider || new
|
|
10242
|
+
const arkProvider = config.arkProvider || new chunkUHOHLN3C_cjs.RestArkProvider(arkadeServerUrl);
|
|
9552
10243
|
let indexerProvider = config.indexerProvider;
|
|
9553
10244
|
if (!indexerProvider) {
|
|
9554
10245
|
let indexerUrl = config.indexerUrl;
|
|
@@ -9565,9 +10256,15 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9565
10256
|
indexerUrl = arkadeServerUrl;
|
|
9566
10257
|
}
|
|
9567
10258
|
}
|
|
9568
|
-
indexerProvider = new
|
|
10259
|
+
indexerProvider = new chunkUHOHLN3C_cjs.RestIndexerProvider(indexerUrl);
|
|
9569
10260
|
}
|
|
9570
|
-
const
|
|
10261
|
+
const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
|
|
10262
|
+
const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
|
|
10263
|
+
const {
|
|
10264
|
+
info,
|
|
10265
|
+
source: serverInfoSource,
|
|
10266
|
+
lastOnlineAt: serverInfoLastOnlineAt
|
|
10267
|
+
} = await resolveArkInfo(arkProvider, walletRepository);
|
|
9571
10268
|
const network = chunkHXDZ2QTW_cjs.getNetwork(info.network);
|
|
9572
10269
|
if ("descriptor" in config.identity) {
|
|
9573
10270
|
const descriptor = config.identity.descriptor;
|
|
@@ -9621,8 +10318,6 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9621
10318
|
serverPubKey: base.hex.encode(serverPubKey),
|
|
9622
10319
|
csvTimelock: chunkHXDZ2QTW_cjs.timelockToSequence(boardingTimelock).toString()
|
|
9623
10320
|
});
|
|
9624
|
-
const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
|
|
9625
|
-
const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
|
|
9626
10321
|
return {
|
|
9627
10322
|
arkProvider,
|
|
9628
10323
|
indexerProvider,
|
|
@@ -9636,6 +10331,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9636
10331
|
walletRepository,
|
|
9637
10332
|
contractRepository,
|
|
9638
10333
|
info,
|
|
10334
|
+
serverInfoSource,
|
|
10335
|
+
serverInfoLastOnlineAt,
|
|
9639
10336
|
delegateProvider: config.delegateProvider || config.delegatorProvider,
|
|
9640
10337
|
/** @deprecated alias for `delegateProvider` */
|
|
9641
10338
|
delegatorProvider: config.delegateProvider || config.delegatorProvider,
|
|
@@ -9671,6 +10368,15 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9671
10368
|
);
|
|
9672
10369
|
wallet.intentRepository = config.storage?.intentRepository;
|
|
9673
10370
|
wallet.virtualTxRepository = config.storage?.virtualTxRepository;
|
|
10371
|
+
wallet.exitDataCapture = config.storage?.exitDataCapture;
|
|
10372
|
+
wallet._serverInfoSource = setup.serverInfoSource;
|
|
10373
|
+
if (setup.serverInfoSource === "live") {
|
|
10374
|
+
const now = Date.now();
|
|
10375
|
+
await saveValidatedArkInfoSnapshot(setup.walletRepository, setup.info, now);
|
|
10376
|
+
wallet._serverInfoLastOnlineAt = now;
|
|
10377
|
+
} else {
|
|
10378
|
+
wallet._serverInfoLastOnlineAt = setup.serverInfoLastOnlineAt;
|
|
10379
|
+
}
|
|
9674
10380
|
wallet.refreshDeprecatedSigners(setup.info);
|
|
9675
10381
|
return wallet;
|
|
9676
10382
|
}
|
|
@@ -9801,7 +10507,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
9801
10507
|
const response = await contractManager.getContractsWithVtxos();
|
|
9802
10508
|
const allVtxos = response.flatMap((_) => _.vtxos);
|
|
9803
10509
|
const { boardingTxs, commitmentsToIgnore } = await this.getBoardingTxs();
|
|
9804
|
-
const getTxCreatedAt = (txid) => this.indexerProvider.getVtxos({ outpoints: [{ txid, vout: 0 }] }).then((res) => res.vtxos[0]?.createdAt.getTime())
|
|
10510
|
+
const getTxCreatedAt = (txid) => this.indexerProvider.getVtxos({ outpoints: [{ txid, vout: 0 }] }).then((res) => res.vtxos[0]?.createdAt.getTime()).catch((err) => {
|
|
10511
|
+
if (isRetryableProviderError(err)) return void 0;
|
|
10512
|
+
throw err;
|
|
10513
|
+
});
|
|
9805
10514
|
return buildTransactionHistory(allVtxos, boardingTxs, commitmentsToIgnore, getTxCreatedAt);
|
|
9806
10515
|
}
|
|
9807
10516
|
/**
|
|
@@ -10220,11 +10929,39 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
10220
10929
|
}
|
|
10221
10930
|
}
|
|
10222
10931
|
async initializeContractManager() {
|
|
10932
|
+
const virtualTxRepository = this.virtualTxRepository;
|
|
10933
|
+
let onVtxosPersisted;
|
|
10934
|
+
let onVtxosSpent;
|
|
10935
|
+
if (virtualTxRepository) {
|
|
10936
|
+
const capture = this.exitDataCapture;
|
|
10937
|
+
const resolver = createExitChainResolver({
|
|
10938
|
+
indexer: this.indexerProvider,
|
|
10939
|
+
repository: virtualTxRepository,
|
|
10940
|
+
extraSources: capture?.sources
|
|
10941
|
+
});
|
|
10942
|
+
onVtxosPersisted = async (_contract, vtxos) => {
|
|
10943
|
+
for (const v of vtxos) {
|
|
10944
|
+
if (v.virtualStatus.state === "spent") continue;
|
|
10945
|
+
await captureExitBranch({
|
|
10946
|
+
resolver,
|
|
10947
|
+
repository: virtualTxRepository,
|
|
10948
|
+
vtxo: { txid: v.txid, vout: v.vout },
|
|
10949
|
+
value: v.value,
|
|
10950
|
+
mode: capture?.mode ?? DEFAULT_EXIT_CAPTURE_MODE,
|
|
10951
|
+
minExitWorthSats: capture?.minExitWorthSats ?? DEFAULT_MIN_EXIT_WORTH_SATS
|
|
10952
|
+
}).catch(() => {
|
|
10953
|
+
});
|
|
10954
|
+
}
|
|
10955
|
+
};
|
|
10956
|
+
onVtxosSpent = (vtxos) => pruneExitBranches(virtualTxRepository, vtxos);
|
|
10957
|
+
}
|
|
10223
10958
|
const manager = await ContractManager.create({
|
|
10224
10959
|
indexerProvider: this.indexerProvider,
|
|
10225
10960
|
contractRepository: this.contractRepository,
|
|
10226
10961
|
walletRepository: this.walletRepository,
|
|
10227
10962
|
intentRepository: this.intentRepository,
|
|
10963
|
+
onVtxosPersisted,
|
|
10964
|
+
onVtxosSpent,
|
|
10228
10965
|
watcherConfig: this.watcherConfig
|
|
10229
10966
|
});
|
|
10230
10967
|
const baselinePubkey = await this.identity.xOnlyPublicKey();
|
|
@@ -10899,6 +11636,14 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
10899
11636
|
boot?.rotator,
|
|
10900
11637
|
boot?.provider
|
|
10901
11638
|
);
|
|
11639
|
+
wallet._serverInfoSource = setup.serverInfoSource;
|
|
11640
|
+
if (setup.serverInfoSource === "live") {
|
|
11641
|
+
const now = Date.now();
|
|
11642
|
+
await saveValidatedArkInfoSnapshot(setup.walletRepository, setup.info, now);
|
|
11643
|
+
wallet._serverInfoLastOnlineAt = now;
|
|
11644
|
+
} else {
|
|
11645
|
+
wallet._serverInfoLastOnlineAt = setup.serverInfoLastOnlineAt;
|
|
11646
|
+
}
|
|
10902
11647
|
wallet.refreshDeprecatedSigners(setup.info);
|
|
10903
11648
|
{
|
|
10904
11649
|
const ap = setup.arkProvider;
|
|
@@ -10920,6 +11665,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
10920
11665
|
}
|
|
10921
11666
|
wallet.intentRepository = config.storage?.intentRepository;
|
|
10922
11667
|
wallet.virtualTxRepository = config.storage?.virtualTxRepository;
|
|
11668
|
+
wallet.exitDataCapture = config.storage?.exitDataCapture;
|
|
10923
11669
|
await wallet.getVtxoManager();
|
|
10924
11670
|
return wallet;
|
|
10925
11671
|
}
|
|
@@ -11580,9 +12326,9 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
11580
12326
|
...existing ?? {},
|
|
11581
12327
|
intentTxId,
|
|
11582
12328
|
registerProof: intent.proof,
|
|
11583
|
-
registerProofMessage:
|
|
12329
|
+
registerProofMessage: chunkUHOHLN3C_cjs.Intent.encodeMessage(intent.message),
|
|
11584
12330
|
deleteProof: deleteIntent.proof,
|
|
11585
|
-
deleteProofMessage:
|
|
12331
|
+
deleteProofMessage: chunkUHOHLN3C_cjs.Intent.encodeMessage(deleteIntent.message),
|
|
11586
12332
|
intentVtxos: inputs.map((i) => ({
|
|
11587
12333
|
txid: i.txid,
|
|
11588
12334
|
vout: i.vout
|
|
@@ -11614,7 +12360,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
11614
12360
|
try {
|
|
11615
12361
|
return await this.arkProvider.registerIntent(intent);
|
|
11616
12362
|
} catch (error) {
|
|
11617
|
-
if (error instanceof
|
|
12363
|
+
if (error instanceof chunkUHOHLN3C_cjs.ArkError && error.code === 0 && error.message.includes("duplicated input")) {
|
|
11618
12364
|
const deleteIntent = await this.makeDeleteIntentSignature(inputs);
|
|
11619
12365
|
await this.arkProvider.deleteIntent(deleteIntent);
|
|
11620
12366
|
return this.arkProvider.registerIntent(intent);
|
|
@@ -11630,7 +12376,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
11630
12376
|
expire_at: 0,
|
|
11631
12377
|
cosigners_public_keys: cosignerPubKeys
|
|
11632
12378
|
};
|
|
11633
|
-
const proof =
|
|
12379
|
+
const proof = chunkUHOHLN3C_cjs.Intent.create(message, coins, outputs);
|
|
11634
12380
|
const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
|
|
11635
12381
|
return {
|
|
11636
12382
|
proof: base.base64.encode(signedProof.toPSBT()),
|
|
@@ -11642,7 +12388,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
11642
12388
|
type: "delete",
|
|
11643
12389
|
expire_at: 0
|
|
11644
12390
|
};
|
|
11645
|
-
const proof =
|
|
12391
|
+
const proof = chunkUHOHLN3C_cjs.Intent.create(message, coins, []);
|
|
11646
12392
|
const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
|
|
11647
12393
|
return {
|
|
11648
12394
|
proof: base.base64.encode(signedProof.toPSBT()),
|
|
@@ -11654,7 +12400,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
11654
12400
|
type: "get-pending-tx",
|
|
11655
12401
|
expire_at: 0
|
|
11656
12402
|
};
|
|
11657
|
-
const proof =
|
|
12403
|
+
const proof = chunkUHOHLN3C_cjs.Intent.create(message, coins, []);
|
|
11658
12404
|
const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
|
|
11659
12405
|
return {
|
|
11660
12406
|
proof: base.base64.encode(signedProof.toPSBT()),
|
|
@@ -12612,7 +13358,7 @@ var MessageBus = class {
|
|
|
12612
13358
|
this.initialized = true;
|
|
12613
13359
|
}
|
|
12614
13360
|
async buildServices(config) {
|
|
12615
|
-
const arkProvider = new
|
|
13361
|
+
const arkProvider = new chunkUHOHLN3C_cjs.RestArkProvider(config.arkServer.url);
|
|
12616
13362
|
const storage = {
|
|
12617
13363
|
walletRepository: this.walletRepository,
|
|
12618
13364
|
contractRepository: this.contractRepository
|
|
@@ -13437,10 +14183,18 @@ var WalletMessageHandler = class {
|
|
|
13437
14183
|
type: "WALLET_STATUS",
|
|
13438
14184
|
payload: {
|
|
13439
14185
|
walletInitialized: true,
|
|
13440
|
-
xOnlyPublicKey: pubKey
|
|
14186
|
+
xOnlyPublicKey: pubKey,
|
|
14187
|
+
providerConnectionState: this.readonlyWallet.getProviderConnectionState()
|
|
13441
14188
|
}
|
|
13442
14189
|
});
|
|
13443
14190
|
}
|
|
14191
|
+
case "GET_CONTRACT_SYNC_STATE": {
|
|
14192
|
+
return this.tagged({
|
|
14193
|
+
id,
|
|
14194
|
+
type: "CONTRACT_SYNC_STATE",
|
|
14195
|
+
payload: { syncState: this.readonlyWallet.getContractSyncState() }
|
|
14196
|
+
});
|
|
14197
|
+
}
|
|
13444
14198
|
case "CLEAR": {
|
|
13445
14199
|
await this.clear();
|
|
13446
14200
|
return this.tagged({
|
|
@@ -13769,7 +14523,7 @@ var WalletMessageHandler = class {
|
|
|
13769
14523
|
// Wallet methods
|
|
13770
14524
|
async handleInitWallet({ payload }) {
|
|
13771
14525
|
const { arkServerUrl } = payload;
|
|
13772
|
-
this.indexerProvider = new
|
|
14526
|
+
this.indexerProvider = new chunkUHOHLN3C_cjs.RestIndexerProvider(arkServerUrl);
|
|
13773
14527
|
await this.onWalletInitialized();
|
|
13774
14528
|
}
|
|
13775
14529
|
async handleGetBalance() {
|
|
@@ -14203,6 +14957,7 @@ var DEFAULT_MESSAGE_TIMEOUTS = {
|
|
|
14203
14957
|
GET_BALANCE: 1e4,
|
|
14204
14958
|
GET_BOARDING_ADDRESS: 1e4,
|
|
14205
14959
|
GET_STATUS: 1e4,
|
|
14960
|
+
GET_CONTRACT_SYNC_STATE: 1e4,
|
|
14206
14961
|
GET_DELEGATE_INFO: 1e4,
|
|
14207
14962
|
IS_CONTRACT_MANAGER_WATCHING: 1e4,
|
|
14208
14963
|
// Medium reads — may involve indexer queries
|
|
@@ -14811,6 +15566,19 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
14811
15566
|
throw new Error(`Failed to get status: ${error}`);
|
|
14812
15567
|
}
|
|
14813
15568
|
}
|
|
15569
|
+
/**
|
|
15570
|
+
* Wallet-level provider-connection freshness, delegated to the worker via
|
|
15571
|
+
* `GET_STATUS`. Async by necessity (the worker boundary is asynchronous); no
|
|
15572
|
+
* synchronous variant is offered because it would have the same transport
|
|
15573
|
+
* mismatch as the contract-manager proxy's cached `getSyncState()`.
|
|
15574
|
+
*/
|
|
15575
|
+
async getProviderConnectionState() {
|
|
15576
|
+
const { providerConnectionState } = await this.getStatus();
|
|
15577
|
+
if (!providerConnectionState) {
|
|
15578
|
+
throw new Error("Worker did not report provider connection state");
|
|
15579
|
+
}
|
|
15580
|
+
return providerConnectionState;
|
|
15581
|
+
}
|
|
14814
15582
|
async getActivityHistory() {
|
|
14815
15583
|
return buildActivities(await this.getTransactionHistory(), this.activity.all());
|
|
14816
15584
|
}
|
|
@@ -14865,6 +15633,32 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
14865
15633
|
return wallet.sendMessage(message);
|
|
14866
15634
|
};
|
|
14867
15635
|
const messageTag = this.messageTag;
|
|
15636
|
+
const fetchSyncState = async () => {
|
|
15637
|
+
const message = {
|
|
15638
|
+
type: "GET_CONTRACT_SYNC_STATE",
|
|
15639
|
+
id: getRandomId(),
|
|
15640
|
+
tag: messageTag
|
|
15641
|
+
};
|
|
15642
|
+
const response = await sendContractMessage(message);
|
|
15643
|
+
return response.payload.syncState;
|
|
15644
|
+
};
|
|
15645
|
+
const UNKNOWN_STATE = {
|
|
15646
|
+
mode: "degraded",
|
|
15647
|
+
reason: "contract sync state unavailable from the worker"
|
|
15648
|
+
};
|
|
15649
|
+
let syncState = UNKNOWN_STATE;
|
|
15650
|
+
let everProbed = false;
|
|
15651
|
+
const refreshSyncState = async () => {
|
|
15652
|
+
try {
|
|
15653
|
+
syncState = await fetchSyncState();
|
|
15654
|
+
everProbed = true;
|
|
15655
|
+
} catch {
|
|
15656
|
+
if (!everProbed) {
|
|
15657
|
+
syncState = UNKNOWN_STATE;
|
|
15658
|
+
}
|
|
15659
|
+
}
|
|
15660
|
+
};
|
|
15661
|
+
await refreshSyncState();
|
|
14868
15662
|
const manager = {
|
|
14869
15663
|
async createContract(params) {
|
|
14870
15664
|
const message = {
|
|
@@ -14875,6 +15669,7 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
14875
15669
|
};
|
|
14876
15670
|
try {
|
|
14877
15671
|
const response = await sendContractMessage(message);
|
|
15672
|
+
await refreshSyncState();
|
|
14878
15673
|
return response.payload.contract;
|
|
14879
15674
|
} catch (e) {
|
|
14880
15675
|
throw new Error("Failed to create contract");
|
|
@@ -14903,11 +15698,15 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
14903
15698
|
};
|
|
14904
15699
|
try {
|
|
14905
15700
|
const response = await sendContractMessage(message);
|
|
15701
|
+
await refreshSyncState();
|
|
14906
15702
|
return response.payload.contracts;
|
|
14907
15703
|
} catch (e) {
|
|
14908
15704
|
throw new Error("Failed to get contracts with vtxos");
|
|
14909
15705
|
}
|
|
14910
15706
|
},
|
|
15707
|
+
getSyncState() {
|
|
15708
|
+
return syncState;
|
|
15709
|
+
},
|
|
14911
15710
|
async annotateVtxos(vtxos) {
|
|
14912
15711
|
if (vtxos.length === 0) return [];
|
|
14913
15712
|
const message = {
|
|
@@ -15016,7 +15815,11 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
15016
15815
|
tag: messageTag,
|
|
15017
15816
|
payload: opts
|
|
15018
15817
|
};
|
|
15019
|
-
|
|
15818
|
+
try {
|
|
15819
|
+
await sendContractMessage(message);
|
|
15820
|
+
} finally {
|
|
15821
|
+
await refreshSyncState();
|
|
15822
|
+
}
|
|
15020
15823
|
},
|
|
15021
15824
|
async refreshOutpoints(outpoints) {
|
|
15022
15825
|
const message = {
|
|
@@ -15025,7 +15828,11 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
15025
15828
|
tag: messageTag,
|
|
15026
15829
|
payload: { outpoints }
|
|
15027
15830
|
};
|
|
15028
|
-
|
|
15831
|
+
try {
|
|
15832
|
+
await sendContractMessage(message);
|
|
15833
|
+
} finally {
|
|
15834
|
+
await refreshSyncState();
|
|
15835
|
+
}
|
|
15029
15836
|
},
|
|
15030
15837
|
scanContracts() {
|
|
15031
15838
|
return Promise.reject(
|
|
@@ -15576,7 +16383,7 @@ var OnchainWallet = class _OnchainWallet {
|
|
|
15576
16383
|
if (!inputs) {
|
|
15577
16384
|
throw new Error("Fee estimation failed");
|
|
15578
16385
|
}
|
|
15579
|
-
let tx = new
|
|
16386
|
+
let tx = new chunkUHOHLN3C_cjs.Transaction();
|
|
15580
16387
|
for (const input of inputs) {
|
|
15581
16388
|
tx.addInput({
|
|
15582
16389
|
txid: input.txid,
|
|
@@ -15606,42 +16413,11 @@ var OnchainWallet = class _OnchainWallet {
|
|
|
15606
16413
|
* @see send
|
|
15607
16414
|
*/
|
|
15608
16415
|
async bumpP2A(parent) {
|
|
15609
|
-
const parentVsize = parent.vsize;
|
|
15610
|
-
let child = new chunk3AQNLQPM_cjs.Transaction({
|
|
15611
|
-
version: 3,
|
|
15612
|
-
allowLegacyWitnessUtxo: true
|
|
15613
|
-
});
|
|
15614
|
-
child.addInput(findP2AOutput(parent));
|
|
15615
|
-
const childVsize = TxWeightEstimator.create().addKeySpendInput(true).addP2AInput().addOutputAddress(this.address, this.network).vsize().value;
|
|
15616
|
-
const packageVSize = parentVsize + Number(childVsize);
|
|
15617
16416
|
let feeRate = await this.provider.getFeeRate();
|
|
15618
16417
|
if (!feeRate || feeRate < _OnchainWallet.MIN_FEE_RATE) {
|
|
15619
16418
|
feeRate = _OnchainWallet.MIN_FEE_RATE;
|
|
15620
16419
|
}
|
|
15621
|
-
const
|
|
15622
|
-
if (!fee) {
|
|
15623
|
-
throw new Error(
|
|
15624
|
-
`invalid fee, got ${fee} with vsize ${packageVSize}, feeRate ${feeRate}`
|
|
15625
|
-
);
|
|
15626
|
-
}
|
|
15627
|
-
const coins = await this.getCoins();
|
|
15628
|
-
const selected = selectCoins(coins, fee, true);
|
|
15629
|
-
for (const input of selected.inputs) {
|
|
15630
|
-
child.addInput({
|
|
15631
|
-
txid: input.txid,
|
|
15632
|
-
index: input.vout,
|
|
15633
|
-
witnessUtxo: {
|
|
15634
|
-
script: this.onchainP2TR.script,
|
|
15635
|
-
amount: BigInt(input.value)
|
|
15636
|
-
},
|
|
15637
|
-
tapInternalKey: this.onchainP2TR.tapInternalKey
|
|
15638
|
-
});
|
|
15639
|
-
}
|
|
15640
|
-
child.addOutputAddress(this.address, P2A.amount + selected.changeAmount, this.network);
|
|
15641
|
-
child = await this.identity.sign(child);
|
|
15642
|
-
for (let i = 1; i < child.inputsLength; i++) {
|
|
15643
|
-
child.finalizeIdx(i);
|
|
15644
|
-
}
|
|
16420
|
+
const child = await this.buildBumpPackage(parent, feeRate, await this.getCoins());
|
|
15645
16421
|
try {
|
|
15646
16422
|
await this.provider.broadcastTransaction(parent.hex, child.hex);
|
|
15647
16423
|
} catch (error) {
|
|
@@ -15650,6 +16426,59 @@ var OnchainWallet = class _OnchainWallet {
|
|
|
15650
16426
|
return [parent.hex, child.hex];
|
|
15651
16427
|
}
|
|
15652
16428
|
}
|
|
16429
|
+
/**
|
|
16430
|
+
* Build and sign a CPFP fee child for a parent tx (given as raw hex)
|
|
16431
|
+
* carrying a P2A anchor, funding it from this wallet's **confirmed**
|
|
16432
|
+
* coins, and return the 1P1C package hexes WITHOUT broadcasting.
|
|
16433
|
+
*
|
|
16434
|
+
* This is the graph-mode fee source ({@link ExitFeeWallet}): the exit
|
|
16435
|
+
* executor calls it to bump each transported virtual tx at execution
|
|
16436
|
+
* time, so funding can be deferred rather than pre-signed.
|
|
16437
|
+
*
|
|
16438
|
+
* @param parentHex - Finalized parent transaction, raw network hex
|
|
16439
|
+
* @param feeRate - sat/vB floor for the package (raised to MIN_FEE_RATE)
|
|
16440
|
+
* @returns Tuple of parent hex (unchanged) and signed child hex
|
|
16441
|
+
* @throws If the parent has no anchor, or funding cannot be selected/signed
|
|
16442
|
+
*/
|
|
16443
|
+
async bumpAnchor(parentHex, feeRate) {
|
|
16444
|
+
const parent = chunkUHOHLN3C_cjs.Transaction.fromRaw(base.hex.decode(parentHex));
|
|
16445
|
+
const coins = (await this.getCoins()).filter((c) => c.status.confirmed);
|
|
16446
|
+
const child = await this.buildBumpPackage(parent, feeRate, coins);
|
|
16447
|
+
return [parent.hex, child.hex];
|
|
16448
|
+
}
|
|
16449
|
+
/**
|
|
16450
|
+
* Shared core of {@link bumpP2A} and {@link bumpAnchor}: probe the package
|
|
16451
|
+
* fee with a single-input child, select coins for it, then build and sign
|
|
16452
|
+
* with the actual selection (the fee grows per extra input).
|
|
16453
|
+
*/
|
|
16454
|
+
async buildBumpPackage(parent, feeRate, coins) {
|
|
16455
|
+
let rate = feeRate;
|
|
16456
|
+
if (!rate || rate < _OnchainWallet.MIN_FEE_RATE) {
|
|
16457
|
+
rate = _OnchainWallet.MIN_FEE_RATE;
|
|
16458
|
+
}
|
|
16459
|
+
const probeVsize = TxWeightEstimator.create().addKeySpendInput(true).addP2AInput().addOutputAddress(this.address, this.network).vsize().value;
|
|
16460
|
+
const probeFee = Math.ceil(rate * (parent.vsize + Number(probeVsize)));
|
|
16461
|
+
if (!probeFee) {
|
|
16462
|
+
throw new Error(
|
|
16463
|
+
`invalid fee, got ${probeFee} with vsize ${parent.vsize + Number(probeVsize)}, feeRate ${rate}`
|
|
16464
|
+
);
|
|
16465
|
+
}
|
|
16466
|
+
const selected = selectCoins(coins, probeFee, true);
|
|
16467
|
+
const { child } = buildAnchorChild({
|
|
16468
|
+
parent,
|
|
16469
|
+
feeRate: rate,
|
|
16470
|
+
fundingCoins: selected.inputs,
|
|
16471
|
+
changeAddress: this.address,
|
|
16472
|
+
changeScript: this.onchainP2TR.script,
|
|
16473
|
+
tapInternalKey: this.onchainP2TR.tapInternalKey,
|
|
16474
|
+
network: this.network
|
|
16475
|
+
});
|
|
16476
|
+
const signed = await this.identity.sign(child);
|
|
16477
|
+
for (let i = 1; i < signed.inputsLength; i++) {
|
|
16478
|
+
signed.finalizeIdx(i);
|
|
16479
|
+
}
|
|
16480
|
+
return signed;
|
|
16481
|
+
}
|
|
15653
16482
|
};
|
|
15654
16483
|
function selectCoins(coins, targetAmount, forceChange = false) {
|
|
15655
16484
|
if (isNaN(targetAmount)) {
|
|
@@ -16373,7 +17202,7 @@ exports.BIP322 = void 0;
|
|
|
16373
17202
|
async function sign2(message, identity, network) {
|
|
16374
17203
|
const xOnlyPubKey = await identity.xOnlyPublicKey();
|
|
16375
17204
|
const payment = btcSigner.p2tr(xOnlyPubKey, void 0, network);
|
|
16376
|
-
const toSpend =
|
|
17205
|
+
const toSpend = chunkUHOHLN3C_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
|
|
16377
17206
|
const toSign = craftBIP322ToSignP2TR(toSpend, payment.script, xOnlyPubKey);
|
|
16378
17207
|
const signed = await identity.sign(toSign, [0]);
|
|
16379
17208
|
signed.finalizeIdx(0);
|
|
@@ -16431,7 +17260,7 @@ function verifyP2TR(message, witnessItems, pkScript, pubkey) {
|
|
|
16431
17260
|
if (sighashType !== btcSigner.SigHash.DEFAULT && sighashType !== btcSigner.SigHash.ALL) {
|
|
16432
17261
|
return false;
|
|
16433
17262
|
}
|
|
16434
|
-
const toSpend =
|
|
17263
|
+
const toSpend = chunkUHOHLN3C_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
|
|
16435
17264
|
const toSign = craftBIP322ToSignP2TR(toSpend, pkScript, pubkey);
|
|
16436
17265
|
const sighash = toSign.preimageWitnessV1(0, [pkScript], sighashType, [0n]);
|
|
16437
17266
|
const rawSig = sig.length === 65 ? sig.subarray(0, 64) : sig;
|
|
@@ -16452,7 +17281,7 @@ function verifyP2WPKH(message, witnessItems, pkScript, addressHash) {
|
|
|
16452
17281
|
}
|
|
16453
17282
|
const sighashType = sigWithHash[sigWithHash.length - 1];
|
|
16454
17283
|
const derSig = sigWithHash.subarray(0, sigWithHash.length - 1);
|
|
16455
|
-
const toSpend =
|
|
17284
|
+
const toSpend = chunkUHOHLN3C_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
|
|
16456
17285
|
const toSign = craftBIP322ToSignSimple(toSpend, pkScript);
|
|
16457
17286
|
const scriptCode = btcSigner.OutScript.encode({ type: "pkh", hash: addressHash });
|
|
16458
17287
|
const sighash = toSign.preimageWitnessV0(0, scriptCode, sighashType, 0n);
|
|
@@ -16505,7 +17334,7 @@ function encodeCompactSize(n) {
|
|
|
16505
17334
|
return buf;
|
|
16506
17335
|
}
|
|
16507
17336
|
function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
|
|
16508
|
-
const tx = new
|
|
17337
|
+
const tx = new chunkUHOHLN3C_cjs.Transaction({ version: 0 });
|
|
16509
17338
|
tx.addInput({
|
|
16510
17339
|
txid: toSpend.id,
|
|
16511
17340
|
index: 0,
|
|
@@ -16519,12 +17348,12 @@ function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
|
|
|
16519
17348
|
});
|
|
16520
17349
|
tx.addOutput({
|
|
16521
17350
|
amount: 0n,
|
|
16522
|
-
script:
|
|
17351
|
+
script: chunkUHOHLN3C_cjs.OP_RETURN_EMPTY_PKSCRIPT
|
|
16523
17352
|
});
|
|
16524
17353
|
return tx;
|
|
16525
17354
|
}
|
|
16526
17355
|
function craftBIP322ToSignSimple(toSpend, pkScript) {
|
|
16527
|
-
const tx = new
|
|
17356
|
+
const tx = new chunkUHOHLN3C_cjs.Transaction({ version: 0 });
|
|
16528
17357
|
tx.addInput({
|
|
16529
17358
|
txid: toSpend.id,
|
|
16530
17359
|
index: 0,
|
|
@@ -16536,11 +17365,89 @@ function craftBIP322ToSignSimple(toSpend, pkScript) {
|
|
|
16536
17365
|
});
|
|
16537
17366
|
tx.addOutput({
|
|
16538
17367
|
amount: 0n,
|
|
16539
|
-
script:
|
|
17368
|
+
script: chunkUHOHLN3C_cjs.OP_RETURN_EMPTY_PKSCRIPT
|
|
16540
17369
|
});
|
|
16541
17370
|
return tx;
|
|
16542
17371
|
}
|
|
16543
|
-
function
|
|
17372
|
+
function finalizeVirtualTx(type, psbtBase64) {
|
|
17373
|
+
const tx = chunkUHOHLN3C_cjs.Transaction.fromPSBT(base.base64.decode(psbtBase64));
|
|
17374
|
+
if (type === "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */) {
|
|
17375
|
+
const input = tx.getInput(0);
|
|
17376
|
+
if (!input) {
|
|
17377
|
+
throw new Error("Input not found");
|
|
17378
|
+
}
|
|
17379
|
+
const tapKeySig = input.tapKeySig;
|
|
17380
|
+
if (!tapKeySig) {
|
|
17381
|
+
throw new Error("Tap key sig not found");
|
|
17382
|
+
}
|
|
17383
|
+
tx.updateInput(0, {
|
|
17384
|
+
finalScriptWitness: [tapKeySig]
|
|
17385
|
+
});
|
|
17386
|
+
return tx;
|
|
17387
|
+
}
|
|
17388
|
+
tx.finalize();
|
|
17389
|
+
return tx;
|
|
17390
|
+
}
|
|
17391
|
+
var ExitPathError = class extends Error {
|
|
17392
|
+
constructor(reason, message) {
|
|
17393
|
+
super(message);
|
|
17394
|
+
this.reason = reason;
|
|
17395
|
+
this.name = "ExitPathError";
|
|
17396
|
+
}
|
|
17397
|
+
};
|
|
17398
|
+
function delayWeight(sequence) {
|
|
17399
|
+
const t = chunkHXDZ2QTW_cjs.sequenceToTimelock(sequence);
|
|
17400
|
+
return t.type === "blocks" ? Number(t.value) : Number(t.value) / 600;
|
|
17401
|
+
}
|
|
17402
|
+
async function resolveUnilateralPath(params) {
|
|
17403
|
+
const { vtxo, scriptHex, contractRepository } = params;
|
|
17404
|
+
const contract = contractRepository ? (await contractRepository.getContracts({ script: scriptHex }))[0] : void 0;
|
|
17405
|
+
if (contract) {
|
|
17406
|
+
const handler = chunk32YKLQPS_cjs.contractHandlers.get(contract.type);
|
|
17407
|
+
if (!handler) {
|
|
17408
|
+
throw new ExitPathError(
|
|
17409
|
+
"no-handler",
|
|
17410
|
+
`no contract handler registered for type '${contract.type}'`
|
|
17411
|
+
);
|
|
17412
|
+
}
|
|
17413
|
+
const script = handler.createScript(contract.params);
|
|
17414
|
+
const paths = handler.getAllSpendingPaths(script, contract, {
|
|
17415
|
+
collaborative: false,
|
|
17416
|
+
currentTime: params.currentTime,
|
|
17417
|
+
walletDescriptor: params.walletDescriptor,
|
|
17418
|
+
walletPubKey: params.walletPubKeyHex
|
|
17419
|
+
}).filter((p) => p.sequence !== void 0);
|
|
17420
|
+
if (paths.length === 0) {
|
|
17421
|
+
throw new ExitPathError(
|
|
17422
|
+
"no-unilateral-path",
|
|
17423
|
+
`no unilateral path for vtxo ${vtxo.txid}:${vtxo.vout} (type '${contract.type}')`
|
|
17424
|
+
);
|
|
17425
|
+
}
|
|
17426
|
+
paths.sort((a, b) => delayWeight(a.sequence) - delayWeight(b.sequence));
|
|
17427
|
+
return { selection: paths[0], label: `${contract.type}:unilateral` };
|
|
17428
|
+
}
|
|
17429
|
+
const decoded = chunkHXDZ2QTW_cjs.VtxoScript.decode(vtxo.tapTree);
|
|
17430
|
+
let best;
|
|
17431
|
+
for (const exit of decoded.exitPaths()) {
|
|
17432
|
+
const leaf = decoded.findLeaf(base.hex.encode(exit.script));
|
|
17433
|
+
if (!leaf) continue;
|
|
17434
|
+
const sequence = chunkHXDZ2QTW_cjs.timelockToSequence(exit.params.timelock);
|
|
17435
|
+
const weight = delayWeight(sequence);
|
|
17436
|
+
if (!best || weight < best.weight) {
|
|
17437
|
+
best = { selection: { leaf, sequence }, weight };
|
|
17438
|
+
}
|
|
17439
|
+
}
|
|
17440
|
+
if (!best) {
|
|
17441
|
+
throw new ExitPathError(
|
|
17442
|
+
"no-unilateral-path",
|
|
17443
|
+
`no exit path found for vtxo ${vtxo.txid}:${vtxo.vout}`
|
|
17444
|
+
);
|
|
17445
|
+
}
|
|
17446
|
+
return { selection: best.selection, label: "default:exit" };
|
|
17447
|
+
}
|
|
17448
|
+
|
|
17449
|
+
// src/wallet/unroll.ts
|
|
17450
|
+
function chainTxTypeToChainedExit2(t) {
|
|
16544
17451
|
switch (t) {
|
|
16545
17452
|
case "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */:
|
|
16546
17453
|
return 1 /* Commitment */;
|
|
@@ -16603,7 +17510,7 @@ exports.Unroll = void 0;
|
|
|
16603
17510
|
txid: next.txid,
|
|
16604
17511
|
psbt,
|
|
16605
17512
|
expiresAt: null,
|
|
16606
|
-
type:
|
|
17513
|
+
type: chainTxTypeToChainedExit2(next.type)
|
|
16607
17514
|
};
|
|
16608
17515
|
try {
|
|
16609
17516
|
await repo.upsertVirtualTxs([cached]);
|
|
@@ -16649,22 +17556,7 @@ exports.Unroll = void 0;
|
|
|
16649
17556
|
if (!virtualTxBase64) {
|
|
16650
17557
|
throw new Error(`Tx ${nextTxToBroadcast.txid} not found`);
|
|
16651
17558
|
}
|
|
16652
|
-
const tx =
|
|
16653
|
-
if (nextTxToBroadcast.type === "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */) {
|
|
16654
|
-
const input = tx.getInput(0);
|
|
16655
|
-
if (!input) {
|
|
16656
|
-
throw new Error("Input not found");
|
|
16657
|
-
}
|
|
16658
|
-
const tapKeySig = input.tapKeySig;
|
|
16659
|
-
if (!tapKeySig) {
|
|
16660
|
-
throw new Error("Tap key sig not found");
|
|
16661
|
-
}
|
|
16662
|
-
tx.updateInput(0, {
|
|
16663
|
-
finalScriptWitness: [tapKeySig]
|
|
16664
|
-
});
|
|
16665
|
-
} else {
|
|
16666
|
-
tx.finalize();
|
|
16667
|
-
}
|
|
17559
|
+
const tx = finalizeVirtualTx(nextTxToBroadcast.type, virtualTxBase64);
|
|
16668
17560
|
const pkg = await this.bumper.bumpP2A(tx);
|
|
16669
17561
|
return {
|
|
16670
17562
|
type: 0 /* UNROLL */,
|
|
@@ -16718,20 +17610,21 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
|
|
|
16718
17610
|
if (!txStatus.confirmed) {
|
|
16719
17611
|
throw new Error(`tx ${vtxo.txid} is not confirmed`);
|
|
16720
17612
|
}
|
|
16721
|
-
const
|
|
16722
|
-
|
|
16723
|
-
|
|
16724
|
-
|
|
16725
|
-
|
|
16726
|
-
|
|
17613
|
+
const resolved = await resolveUnilateralPath({
|
|
17614
|
+
vtxo,
|
|
17615
|
+
scriptHex: base.hex.encode(chunkHXDZ2QTW_cjs.VtxoScript.decode(vtxo.tapTree).pkScript),
|
|
17616
|
+
contractRepository: wallet.contractRepository,
|
|
17617
|
+
walletPubKeyHex: base.hex.encode(await wallet.identity.xOnlyPublicKey()),
|
|
17618
|
+
currentTime: Date.now()
|
|
17619
|
+
});
|
|
17620
|
+
const spendingLeaf = resolved.selection.leaf;
|
|
17621
|
+
const sequence = resolved.selection.sequence;
|
|
17622
|
+
const timelock = chunkHXDZ2QTW_cjs.sequenceToTimelock(sequence);
|
|
17623
|
+
const elapsed = timelock.type === "blocks" ? chainTip.height >= txStatus.blockHeight + Number(timelock.value) : chainTip.time >= txStatus.blockTime + Number(timelock.value);
|
|
17624
|
+
if (!elapsed) {
|
|
16727
17625
|
throw new Error(`no available exit path found for vtxo ${vtxo.txid}:${vtxo.vout}`);
|
|
16728
17626
|
}
|
|
16729
|
-
const spendingLeaf = chunkHXDZ2QTW_cjs.VtxoScript.decode(vtxo.tapTree).findLeaf(base.hex.encode(exit.script));
|
|
16730
|
-
if (!spendingLeaf) {
|
|
16731
|
-
throw new Error(`spending leaf not found for vtxo ${vtxo.txid}:${vtxo.vout}`);
|
|
16732
|
-
}
|
|
16733
17627
|
totalAmount += BigInt(vtxo.value);
|
|
16734
|
-
const sequence = chunkHXDZ2QTW_cjs.timelockToSequence(exit.params.timelock);
|
|
16735
17628
|
inputs.push({
|
|
16736
17629
|
txid: vtxo.txid,
|
|
16737
17630
|
index: vtxo.vout,
|
|
@@ -16749,7 +17642,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
|
|
|
16749
17642
|
btcSigner.TaprootControlBlock.encode(spendingLeaf[0]).length
|
|
16750
17643
|
);
|
|
16751
17644
|
}
|
|
16752
|
-
const tx = new
|
|
17645
|
+
const tx = new chunkUHOHLN3C_cjs.Transaction({ version: 2 });
|
|
16753
17646
|
for (const input of inputs) {
|
|
16754
17647
|
tx.addInput(input);
|
|
16755
17648
|
}
|
|
@@ -16795,21 +17688,711 @@ function doWait(onchainProvider, txid) {
|
|
|
16795
17688
|
});
|
|
16796
17689
|
};
|
|
16797
17690
|
}
|
|
16798
|
-
function
|
|
16799
|
-
|
|
16800
|
-
|
|
16801
|
-
|
|
16802
|
-
|
|
16803
|
-
|
|
17691
|
+
function extraWitnessSize(path) {
|
|
17692
|
+
return (path.extraWitness ?? []).reduce((sum, item) => sum + 1 + item.length, 0);
|
|
17693
|
+
}
|
|
17694
|
+
function sweepFeeFor(path, outputAddress, network, feeRate) {
|
|
17695
|
+
const [controlBlock, scriptWithVersion] = path.leaf;
|
|
17696
|
+
const estimator = TxWeightEstimator.create().addTapscriptInput(
|
|
17697
|
+
64 + extraWitnessSize(path),
|
|
17698
|
+
scriptWithVersion.length,
|
|
17699
|
+
btcSigner.TaprootControlBlock.encode(controlBlock).length
|
|
17700
|
+
).addOutputAddress(outputAddress, network);
|
|
17701
|
+
return Number(estimator.vsize().fee(BigInt(Math.ceil(feeRate))));
|
|
17702
|
+
}
|
|
17703
|
+
async function buildSignedSweep(params) {
|
|
17704
|
+
const { vtxo, path, outputAddress, feeRate, network, identity } = params;
|
|
17705
|
+
const fee = sweepFeeFor(path, outputAddress, network, feeRate);
|
|
17706
|
+
const sendAmount = BigInt(vtxo.value) - BigInt(fee);
|
|
17707
|
+
if (sendAmount < BigInt(DUST_AMOUNT)) {
|
|
17708
|
+
throw new Error(
|
|
17709
|
+
`uneconomic vtxo ${vtxo.txid}:${vtxo.vout}: value ${vtxo.value} - fee ${fee} < dust`
|
|
17710
|
+
);
|
|
17711
|
+
}
|
|
17712
|
+
const tx = new chunkUHOHLN3C_cjs.Transaction({ version: 2 });
|
|
17713
|
+
tx.addInput({
|
|
17714
|
+
txid: vtxo.txid,
|
|
17715
|
+
index: vtxo.vout,
|
|
17716
|
+
tapLeafScript: [path.leaf],
|
|
17717
|
+
sequence: path.sequence,
|
|
17718
|
+
witnessUtxo: { amount: BigInt(vtxo.value), script: vtxo.pkScript },
|
|
17719
|
+
sighashType: btcSigner.SigHash.DEFAULT
|
|
17720
|
+
});
|
|
17721
|
+
tx.addOutputAddress(outputAddress, sendAmount, network);
|
|
17722
|
+
const signed = await identity.sign(tx);
|
|
17723
|
+
if (!path.extraWitness || path.extraWitness.length === 0) {
|
|
17724
|
+
signed.finalize();
|
|
17725
|
+
return { tx: signed, fee };
|
|
17726
|
+
}
|
|
17727
|
+
const input = signed.getInput(0);
|
|
17728
|
+
const tapScriptSig = input.tapScriptSig;
|
|
17729
|
+
if (!tapScriptSig || tapScriptSig.length === 0) {
|
|
17730
|
+
throw new Error("exit path requires additional signers");
|
|
17731
|
+
}
|
|
17732
|
+
const [controlBlock] = path.leaf;
|
|
17733
|
+
signed.updateInput(0, {
|
|
17734
|
+
finalScriptWitness: [
|
|
17735
|
+
tapScriptSig[0][1],
|
|
17736
|
+
...path.extraWitness,
|
|
17737
|
+
chunkHXDZ2QTW_cjs.scriptFromTapLeafScript(path.leaf),
|
|
17738
|
+
btcSigner.TaprootControlBlock.encode(controlBlock)
|
|
17739
|
+
]
|
|
17740
|
+
});
|
|
17741
|
+
return { tx: signed, fee };
|
|
17742
|
+
}
|
|
17743
|
+
|
|
17744
|
+
// src/wallet/exit/estimate.ts
|
|
17745
|
+
var CHILD_OUTPUT_DUST = 546;
|
|
17746
|
+
function stepFundingAmount(stepFee) {
|
|
17747
|
+
return stepFee + CHILD_OUTPUT_DUST;
|
|
17748
|
+
}
|
|
17749
|
+
function resolveMode(opts) {
|
|
17750
|
+
return opts.mode ?? "funded";
|
|
17751
|
+
}
|
|
17752
|
+
function resolveNetworkName(opts) {
|
|
17753
|
+
if (opts.networkName) return opts.networkName;
|
|
17754
|
+
const { bech32 } = opts.wallet.network;
|
|
17755
|
+
if (bech32 === "bc") return "bitcoin";
|
|
17756
|
+
if (bech32 === "bcrt") return "regtest";
|
|
17757
|
+
return "testnet";
|
|
17758
|
+
}
|
|
17759
|
+
async function resolveFeeRate(opts) {
|
|
17760
|
+
if (opts.feeRate) return Math.ceil(opts.feeRate);
|
|
17761
|
+
const feeRate = await opts.wallet.onchainProvider.getFeeRate();
|
|
17762
|
+
if (!feeRate || feeRate < OnchainWallet.MIN_FEE_RATE) return OnchainWallet.MIN_FEE_RATE;
|
|
17763
|
+
return Math.ceil(feeRate);
|
|
17764
|
+
}
|
|
17765
|
+
async function selectExitVtxos(opts) {
|
|
17766
|
+
if (!opts.vtxos) return opts.wallet.getVtxos();
|
|
17767
|
+
const res = await opts.wallet.indexerProvider.getVtxos({ outpoints: opts.vtxos });
|
|
17768
|
+
const tapTrees = /* @__PURE__ */ new Map();
|
|
17769
|
+
const out = [];
|
|
17770
|
+
for (const vtxo of res.vtxos) {
|
|
17771
|
+
if (vtxo.isSpent) continue;
|
|
17772
|
+
let tapTree = tapTrees.get(vtxo.script);
|
|
17773
|
+
if (!tapTree) {
|
|
17774
|
+
const [contract] = await opts.wallet.contractRepository.getContracts({
|
|
17775
|
+
script: vtxo.script
|
|
17776
|
+
});
|
|
17777
|
+
if (!contract) {
|
|
17778
|
+
throw new Error(
|
|
17779
|
+
`no contract registered for vtxo script ${vtxo.script} \u2014 register the contract before exiting`
|
|
17780
|
+
);
|
|
16804
17781
|
}
|
|
16805
|
-
|
|
16806
|
-
if (
|
|
16807
|
-
|
|
17782
|
+
const handler = chunk32YKLQPS_cjs.contractHandlers.get(contract.type);
|
|
17783
|
+
if (!handler) {
|
|
17784
|
+
throw new Error(`no contract handler registered for type '${contract.type}'`);
|
|
16808
17785
|
}
|
|
17786
|
+
tapTree = handler.createScript(contract.params).encode();
|
|
17787
|
+
tapTrees.set(vtxo.script, tapTree);
|
|
16809
17788
|
}
|
|
17789
|
+
out.push({ txid: vtxo.txid, vout: vtxo.vout, value: vtxo.value, tapTree });
|
|
16810
17790
|
}
|
|
16811
|
-
return
|
|
17791
|
+
return out;
|
|
17792
|
+
}
|
|
17793
|
+
async function computeExitLayout(opts, feeRate) {
|
|
17794
|
+
const { wallet, onchainWallet } = opts;
|
|
17795
|
+
const vtxos = await selectExitVtxos(opts);
|
|
17796
|
+
if (vtxos.length === 0) throw new Error("no vtxos to exit");
|
|
17797
|
+
const resolver = createExitChainResolver({
|
|
17798
|
+
indexer: wallet.indexerProvider,
|
|
17799
|
+
repository: wallet.virtualTxRepository,
|
|
17800
|
+
extraSources: wallet.exitDataCapture?.sources
|
|
17801
|
+
});
|
|
17802
|
+
const dag = await buildExitDag({
|
|
17803
|
+
vtxos,
|
|
17804
|
+
chain: resolver,
|
|
17805
|
+
onchain: wallet.onchainProvider
|
|
17806
|
+
});
|
|
17807
|
+
const pendingNodes = dag.filter((n) => !n.confirmed);
|
|
17808
|
+
const psbts = /* @__PURE__ */ new Map();
|
|
17809
|
+
if (pendingNodes.length > 0) {
|
|
17810
|
+
const txs = await resolver.getVirtualTxs(pendingNodes.map((n) => n.txid));
|
|
17811
|
+
for (const psbt of txs) {
|
|
17812
|
+
psbts.set(chunkUHOHLN3C_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
|
|
17813
|
+
}
|
|
17814
|
+
}
|
|
17815
|
+
const childVsize = Number(
|
|
17816
|
+
TxWeightEstimator.create().addP2AInput().addKeySpendInput(true).addOutputAddress(onchainWallet.address, wallet.network).vsize().value
|
|
17817
|
+
);
|
|
17818
|
+
const rawSteps = pendingNodes.map((node) => {
|
|
17819
|
+
const psbt = psbts.get(node.txid);
|
|
17820
|
+
if (!psbt) {
|
|
17821
|
+
throw new Error(`indexer did not return virtual tx ${node.txid}`);
|
|
17822
|
+
}
|
|
17823
|
+
const parent = finalizeVirtualTx(node.type, psbt);
|
|
17824
|
+
const stepFee = Math.ceil(feeRate * (parent.vsize + childVsize));
|
|
17825
|
+
return { node, parent, stepFee, funding: stepFundingAmount(stepFee) };
|
|
17826
|
+
});
|
|
17827
|
+
const parentInputTxids = (tx) => {
|
|
17828
|
+
const ids = [];
|
|
17829
|
+
for (let i = 0; i < tx.inputsLength; i++) {
|
|
17830
|
+
const txid = tx.getInput(i).txid;
|
|
17831
|
+
if (txid) ids.push(base.hex.encode(txid));
|
|
17832
|
+
}
|
|
17833
|
+
return ids;
|
|
17834
|
+
};
|
|
17835
|
+
const steps = topoSortByDeps(
|
|
17836
|
+
rawSteps,
|
|
17837
|
+
(s) => s.parent.id,
|
|
17838
|
+
(s) => parentInputTxids(s.parent)
|
|
17839
|
+
);
|
|
17840
|
+
const walletPubKeyHex = base.hex.encode(await wallet.identity.xOnlyPublicKey());
|
|
17841
|
+
const infos = [];
|
|
17842
|
+
const sweeps = [];
|
|
17843
|
+
for (const vtxo of vtxos) {
|
|
17844
|
+
const outpoint = `${vtxo.txid}:${vtxo.vout}`;
|
|
17845
|
+
try {
|
|
17846
|
+
const resolved = await resolveUnilateralPath({
|
|
17847
|
+
vtxo,
|
|
17848
|
+
scriptHex: base.hex.encode(chunkHXDZ2QTW_cjs.VtxoScript.decode(vtxo.tapTree).pkScript),
|
|
17849
|
+
contractRepository: wallet.contractRepository,
|
|
17850
|
+
walletPubKeyHex,
|
|
17851
|
+
currentTime: Date.now()
|
|
17852
|
+
});
|
|
17853
|
+
const sweepFee = sweepFeeFor(
|
|
17854
|
+
resolved.selection,
|
|
17855
|
+
opts.sweepAddress,
|
|
17856
|
+
wallet.network,
|
|
17857
|
+
feeRate
|
|
17858
|
+
);
|
|
17859
|
+
if (vtxo.value - sweepFee < CHILD_OUTPUT_DUST) {
|
|
17860
|
+
infos.push({
|
|
17861
|
+
outpoint,
|
|
17862
|
+
value: vtxo.value,
|
|
17863
|
+
skipped: `uneconomic: value ${vtxo.value} <= sweep fee + dust`
|
|
17864
|
+
});
|
|
17865
|
+
continue;
|
|
17866
|
+
}
|
|
17867
|
+
const t = chunkHXDZ2QTW_cjs.sequenceToTimelock(resolved.selection.sequence);
|
|
17868
|
+
const delay = { type: t.type, value: Number(t.value) };
|
|
17869
|
+
infos.push({ outpoint, value: vtxo.value, sweepFee, path: resolved.label, delay });
|
|
17870
|
+
sweeps.push({ vtxo, resolved, sweepFee, delay });
|
|
17871
|
+
} catch (e) {
|
|
17872
|
+
if (e instanceof ExitPathError) {
|
|
17873
|
+
infos.push({ outpoint, value: vtxo.value, skipped: e.message });
|
|
17874
|
+
continue;
|
|
17875
|
+
}
|
|
17876
|
+
throw e;
|
|
17877
|
+
}
|
|
17878
|
+
}
|
|
17879
|
+
const coins = (await onchainWallet.getCoins()).filter((c) => c.status.confirmed);
|
|
17880
|
+
const balance = coins.reduce((sum, c) => sum + c.value, 0);
|
|
17881
|
+
const fundingTotal = steps.reduce((sum, s) => sum + s.funding, 0);
|
|
17882
|
+
const splitterFeeFor = (inputCount) => {
|
|
17883
|
+
if (steps.length === 0) return 0;
|
|
17884
|
+
const est = TxWeightEstimator.create();
|
|
17885
|
+
for (let i = 0; i < inputCount; i++) est.addKeySpendInput(true);
|
|
17886
|
+
for (let i = 0; i < steps.length + 1; i++) {
|
|
17887
|
+
est.addOutputAddress(onchainWallet.address, wallet.network);
|
|
17888
|
+
}
|
|
17889
|
+
return Number(est.vsize().fee(BigInt(feeRate)));
|
|
17890
|
+
};
|
|
17891
|
+
const graph = resolveMode(opts) === "graph";
|
|
17892
|
+
let splitterFee = 0;
|
|
17893
|
+
if (!graph) {
|
|
17894
|
+
splitterFee = splitterFeeFor(Math.max(1, coins.length));
|
|
17895
|
+
if (steps.length > 0 && balance < fundingTotal + splitterFee) {
|
|
17896
|
+
splitterFee = splitterFeeFor(coins.length + 1);
|
|
17897
|
+
}
|
|
17898
|
+
}
|
|
17899
|
+
const stepFees = steps.reduce((s, x) => s + x.stepFee, 0);
|
|
17900
|
+
const sweepFees = sweeps.reduce((s, x) => s + x.sweepFee, 0);
|
|
17901
|
+
const totals = {
|
|
17902
|
+
// graph: each unroll step is parent + a live-built child (2 txs), no
|
|
17903
|
+
// splitter. funded: + 1 splitter tx and pre-signed children.
|
|
17904
|
+
txCount: (graph ? 0 : steps.length > 0 ? 1 : 0) + steps.length * 2 + sweeps.length,
|
|
17905
|
+
totalFeeSats: splitterFee + stepFees + sweepFees,
|
|
17906
|
+
// graph funding is what the executor sends to its own fee address:
|
|
17907
|
+
// just the CPFP fees (change recycles); funded also locks the
|
|
17908
|
+
// per-child dust into the splitter.
|
|
17909
|
+
fundingRequiredSats: graph ? stepFees : splitterFee + fundingTotal,
|
|
17910
|
+
recoveredSats: sweeps.reduce((s, x) => s + (x.vtxo.value - x.sweepFee), 0)
|
|
17911
|
+
};
|
|
17912
|
+
const expiries = pendingNodes.map((n) => n.expiresAt).filter((x) => x !== void 0);
|
|
17913
|
+
const validUntil = expiries.length > 0 ? Math.min(...expiries) : void 0;
|
|
17914
|
+
return {
|
|
17915
|
+
vtxos,
|
|
17916
|
+
dag,
|
|
17917
|
+
steps,
|
|
17918
|
+
sweeps,
|
|
17919
|
+
infos,
|
|
17920
|
+
totals,
|
|
17921
|
+
splitterFee,
|
|
17922
|
+
validUntil,
|
|
17923
|
+
balance,
|
|
17924
|
+
coins
|
|
17925
|
+
};
|
|
16812
17926
|
}
|
|
17927
|
+
async function estimate(opts) {
|
|
17928
|
+
const feeRate = await resolveFeeRate(opts);
|
|
17929
|
+
const layout = await computeExitLayout(opts, feeRate);
|
|
17930
|
+
if (resolveMode(opts) === "graph") {
|
|
17931
|
+
return {
|
|
17932
|
+
feeRate,
|
|
17933
|
+
fundingAddress: "",
|
|
17934
|
+
currentBalanceSats: 0,
|
|
17935
|
+
shortfallSats: layout.totals.fundingRequiredSats,
|
|
17936
|
+
validUntil: layout.validUntil,
|
|
17937
|
+
totals: layout.totals,
|
|
17938
|
+
vtxos: layout.infos
|
|
17939
|
+
};
|
|
17940
|
+
}
|
|
17941
|
+
return {
|
|
17942
|
+
feeRate,
|
|
17943
|
+
fundingAddress: opts.onchainWallet.address,
|
|
17944
|
+
currentBalanceSats: layout.balance,
|
|
17945
|
+
shortfallSats: Math.max(0, layout.totals.fundingRequiredSats - layout.balance),
|
|
17946
|
+
validUntil: layout.validUntil,
|
|
17947
|
+
totals: layout.totals,
|
|
17948
|
+
vtxos: layout.infos
|
|
17949
|
+
};
|
|
17950
|
+
}
|
|
17951
|
+
|
|
17952
|
+
// src/wallet/exit/executor.ts
|
|
17953
|
+
var Executor = class {
|
|
17954
|
+
constructor(pkg, provider, opts) {
|
|
17955
|
+
this.pkg = pkg;
|
|
17956
|
+
this.provider = provider;
|
|
17957
|
+
this.pollIntervalMs = opts?.pollIntervalMs ?? 5e3;
|
|
17958
|
+
this.feeWallet = opts?.feeWallet;
|
|
17959
|
+
}
|
|
17960
|
+
pollIntervalMs;
|
|
17961
|
+
feeWallet;
|
|
17962
|
+
sleep() {
|
|
17963
|
+
return new Promise((r) => setTimeout(r, this.pollIntervalMs));
|
|
17964
|
+
}
|
|
17965
|
+
async status(txid) {
|
|
17966
|
+
try {
|
|
17967
|
+
return await this.provider.getTxStatus(txid);
|
|
17968
|
+
} catch {
|
|
17969
|
+
return void 0;
|
|
17970
|
+
}
|
|
17971
|
+
}
|
|
17972
|
+
async waitConfirmed(txid) {
|
|
17973
|
+
for (; ; ) {
|
|
17974
|
+
const s = await this.status(txid);
|
|
17975
|
+
if (s?.confirmed) return s;
|
|
17976
|
+
await this.sleep();
|
|
17977
|
+
}
|
|
17978
|
+
}
|
|
17979
|
+
async *[Symbol.asyncIterator]() {
|
|
17980
|
+
const dead = /* @__PURE__ */ new Set();
|
|
17981
|
+
if (this.pkg.validUntil && Date.now() / 1e3 > this.pkg.validUntil) {
|
|
17982
|
+
yield {
|
|
17983
|
+
stepIndex: -1,
|
|
17984
|
+
kind: "broadcast",
|
|
17985
|
+
status: "warning",
|
|
17986
|
+
reason: `package validUntil ${this.pkg.validUntil} has passed; the operator may have swept \u2014 attempting anyway`
|
|
17987
|
+
};
|
|
17988
|
+
}
|
|
17989
|
+
const sweeps = [];
|
|
17990
|
+
for (let i = 0; i < this.pkg.steps.length; i++) {
|
|
17991
|
+
const step = this.pkg.steps[i];
|
|
17992
|
+
if (step.kind === "sweep") {
|
|
17993
|
+
sweeps.push({ index: i, step });
|
|
17994
|
+
continue;
|
|
17995
|
+
}
|
|
17996
|
+
const forVtxos = step.kind === "package" || step.kind === "bump" ? step.forVtxos : void 0;
|
|
17997
|
+
if (forVtxos && forVtxos.every((v) => dead.has(v))) {
|
|
17998
|
+
yield {
|
|
17999
|
+
stepIndex: i,
|
|
18000
|
+
kind: step.kind,
|
|
18001
|
+
status: "skipped",
|
|
18002
|
+
forVtxos,
|
|
18003
|
+
reason: "branch failed earlier"
|
|
18004
|
+
};
|
|
18005
|
+
continue;
|
|
18006
|
+
}
|
|
18007
|
+
const anchorTxid = step.kind === "package" || step.kind === "bump" ? step.parentTxid : step.txid;
|
|
18008
|
+
const existing = await this.status(anchorTxid);
|
|
18009
|
+
if (existing?.confirmed) {
|
|
18010
|
+
yield {
|
|
18011
|
+
stepIndex: i,
|
|
18012
|
+
kind: step.kind,
|
|
18013
|
+
status: "skipped",
|
|
18014
|
+
txid: anchorTxid,
|
|
18015
|
+
forVtxos
|
|
18016
|
+
};
|
|
18017
|
+
continue;
|
|
18018
|
+
}
|
|
18019
|
+
if (!existing) {
|
|
18020
|
+
try {
|
|
18021
|
+
if (step.kind === "package") {
|
|
18022
|
+
await this.provider.broadcastTransaction(step.parentHex, step.childHex);
|
|
18023
|
+
} else if (step.kind === "bump") {
|
|
18024
|
+
if (!this.feeWallet) {
|
|
18025
|
+
throw new Error(
|
|
18026
|
+
"graph package requires a fee wallet (opts.feeWallet) to fund CPFP bumps"
|
|
18027
|
+
);
|
|
18028
|
+
}
|
|
18029
|
+
const [parentHex, childHex] = await this.feeWallet.bumpAnchor(
|
|
18030
|
+
step.parentHex,
|
|
18031
|
+
this.pkg.feeRate
|
|
18032
|
+
);
|
|
18033
|
+
await this.provider.broadcastTransaction(parentHex, childHex);
|
|
18034
|
+
} else {
|
|
18035
|
+
await this.provider.broadcastTransaction(step.hex);
|
|
18036
|
+
}
|
|
18037
|
+
yield {
|
|
18038
|
+
stepIndex: i,
|
|
18039
|
+
kind: step.kind,
|
|
18040
|
+
status: "broadcast",
|
|
18041
|
+
txid: anchorTxid,
|
|
18042
|
+
forVtxos
|
|
18043
|
+
};
|
|
18044
|
+
} catch (e) {
|
|
18045
|
+
const reason = e instanceof Error ? e.message : String(e);
|
|
18046
|
+
if (step.kind === "broadcast") {
|
|
18047
|
+
for (const s of this.pkg.steps) {
|
|
18048
|
+
if (s.kind === "package") s.forVtxos.forEach((v) => dead.add(v));
|
|
18049
|
+
}
|
|
18050
|
+
} else if (step.kind === "package" || step.kind === "bump") {
|
|
18051
|
+
step.forVtxos.forEach((v) => dead.add(v));
|
|
18052
|
+
}
|
|
18053
|
+
yield {
|
|
18054
|
+
stepIndex: i,
|
|
18055
|
+
kind: step.kind,
|
|
18056
|
+
status: "failed",
|
|
18057
|
+
txid: anchorTxid,
|
|
18058
|
+
forVtxos,
|
|
18059
|
+
reason
|
|
18060
|
+
};
|
|
18061
|
+
continue;
|
|
18062
|
+
}
|
|
18063
|
+
}
|
|
18064
|
+
await this.waitConfirmed(anchorTxid);
|
|
18065
|
+
yield {
|
|
18066
|
+
stepIndex: i,
|
|
18067
|
+
kind: step.kind,
|
|
18068
|
+
status: "confirmed",
|
|
18069
|
+
txid: anchorTxid,
|
|
18070
|
+
forVtxos
|
|
18071
|
+
};
|
|
18072
|
+
}
|
|
18073
|
+
for (const { index, step } of sweeps) {
|
|
18074
|
+
if (dead.has(step.vtxo)) {
|
|
18075
|
+
yield {
|
|
18076
|
+
stepIndex: index,
|
|
18077
|
+
kind: "sweep",
|
|
18078
|
+
status: "failed",
|
|
18079
|
+
txid: step.txid,
|
|
18080
|
+
forVtxos: [step.vtxo],
|
|
18081
|
+
reason: "branch failed earlier"
|
|
18082
|
+
};
|
|
18083
|
+
}
|
|
18084
|
+
}
|
|
18085
|
+
const pending = sweeps.filter(({ step }) => !dead.has(step.vtxo));
|
|
18086
|
+
const waitingAnnounced = /* @__PURE__ */ new Set();
|
|
18087
|
+
const done = /* @__PURE__ */ new Set();
|
|
18088
|
+
while (done.size < pending.length) {
|
|
18089
|
+
for (const { index, step } of pending) {
|
|
18090
|
+
if (done.has(index)) continue;
|
|
18091
|
+
const swept = await this.status(step.txid);
|
|
18092
|
+
if (swept?.confirmed) {
|
|
18093
|
+
done.add(index);
|
|
18094
|
+
yield {
|
|
18095
|
+
stepIndex: index,
|
|
18096
|
+
kind: "sweep",
|
|
18097
|
+
status: "confirmed",
|
|
18098
|
+
txid: step.txid,
|
|
18099
|
+
forVtxos: [step.vtxo]
|
|
18100
|
+
};
|
|
18101
|
+
continue;
|
|
18102
|
+
}
|
|
18103
|
+
if (swept) continue;
|
|
18104
|
+
const dep = await this.status(step.dependsOnTxid);
|
|
18105
|
+
if (!dep?.confirmed) continue;
|
|
18106
|
+
const tip = await this.provider.getChainTip();
|
|
18107
|
+
const mature = step.delay.type === "blocks" ? tip.height >= (dep.blockHeight ?? 0) + step.delay.value : tip.time >= (dep.blockTime ?? 0) + step.delay.value;
|
|
18108
|
+
if (!mature) {
|
|
18109
|
+
if (!waitingAnnounced.has(index)) {
|
|
18110
|
+
waitingAnnounced.add(index);
|
|
18111
|
+
yield {
|
|
18112
|
+
stepIndex: index,
|
|
18113
|
+
kind: "sweep",
|
|
18114
|
+
status: "waiting_csv",
|
|
18115
|
+
txid: step.txid,
|
|
18116
|
+
forVtxos: [step.vtxo],
|
|
18117
|
+
...step.delay.type === "blocks" ? { maturesAtHeight: (dep.blockHeight ?? 0) + step.delay.value } : { maturesAtTime: (dep.blockTime ?? 0) + step.delay.value }
|
|
18118
|
+
};
|
|
18119
|
+
}
|
|
18120
|
+
continue;
|
|
18121
|
+
}
|
|
18122
|
+
try {
|
|
18123
|
+
await this.provider.broadcastTransaction(step.hex);
|
|
18124
|
+
yield {
|
|
18125
|
+
stepIndex: index,
|
|
18126
|
+
kind: "sweep",
|
|
18127
|
+
status: "broadcast",
|
|
18128
|
+
txid: step.txid,
|
|
18129
|
+
forVtxos: [step.vtxo]
|
|
18130
|
+
};
|
|
18131
|
+
} catch (e) {
|
|
18132
|
+
const reason = e instanceof Error ? e.message : String(e);
|
|
18133
|
+
if (/non-?bip68|non-?final|premature/i.test(reason)) {
|
|
18134
|
+
continue;
|
|
18135
|
+
}
|
|
18136
|
+
done.add(index);
|
|
18137
|
+
yield {
|
|
18138
|
+
stepIndex: index,
|
|
18139
|
+
kind: "sweep",
|
|
18140
|
+
status: "failed",
|
|
18141
|
+
txid: step.txid,
|
|
18142
|
+
forVtxos: [step.vtxo],
|
|
18143
|
+
reason
|
|
18144
|
+
};
|
|
18145
|
+
}
|
|
18146
|
+
}
|
|
18147
|
+
if (done.size < pending.length) await this.sleep();
|
|
18148
|
+
}
|
|
18149
|
+
}
|
|
18150
|
+
};
|
|
18151
|
+
async function prepare(opts) {
|
|
18152
|
+
const { wallet, onchainWallet } = opts;
|
|
18153
|
+
const feeRate = await resolveFeeRate(opts);
|
|
18154
|
+
const mode = resolveMode(opts);
|
|
18155
|
+
if (mode === "funded") {
|
|
18156
|
+
const walletKey = await wallet.identity.xOnlyPublicKey();
|
|
18157
|
+
if (base.hex.encode(onchainWallet.onchainP2TR.tapInternalKey) !== base.hex.encode(walletKey)) {
|
|
18158
|
+
throw new Error("onchainWallet must share the wallet identity");
|
|
18159
|
+
}
|
|
18160
|
+
}
|
|
18161
|
+
const layout = await computeExitLayout(opts, feeRate);
|
|
18162
|
+
const sweepSteps = [];
|
|
18163
|
+
const activeOutpoints = /* @__PURE__ */ new Set();
|
|
18164
|
+
for (const sweep of layout.sweeps) {
|
|
18165
|
+
const outpoint = `${sweep.vtxo.txid}:${sweep.vtxo.vout}`;
|
|
18166
|
+
try {
|
|
18167
|
+
const { tx } = await buildSignedSweep({
|
|
18168
|
+
vtxo: {
|
|
18169
|
+
txid: sweep.vtxo.txid,
|
|
18170
|
+
vout: sweep.vtxo.vout,
|
|
18171
|
+
value: sweep.vtxo.value,
|
|
18172
|
+
pkScript: chunkHXDZ2QTW_cjs.VtxoScript.decode(sweep.vtxo.tapTree).pkScript
|
|
18173
|
+
},
|
|
18174
|
+
path: sweep.resolved.selection,
|
|
18175
|
+
outputAddress: opts.sweepAddress,
|
|
18176
|
+
feeRate,
|
|
18177
|
+
network: wallet.network,
|
|
18178
|
+
identity: wallet.identity
|
|
18179
|
+
});
|
|
18180
|
+
activeOutpoints.add(outpoint);
|
|
18181
|
+
sweepSteps.push({
|
|
18182
|
+
kind: "sweep",
|
|
18183
|
+
vtxo: outpoint,
|
|
18184
|
+
txid: tx.id,
|
|
18185
|
+
hex: tx.hex,
|
|
18186
|
+
dependsOnTxid: sweep.vtxo.txid,
|
|
18187
|
+
delay: sweep.delay
|
|
18188
|
+
});
|
|
18189
|
+
} catch (e) {
|
|
18190
|
+
const info = layout.infos.find((i) => i.outpoint === outpoint);
|
|
18191
|
+
if (info) {
|
|
18192
|
+
info.skipped = e instanceof Error ? e.message : String(e);
|
|
18193
|
+
delete info.sweepFee;
|
|
18194
|
+
delete info.path;
|
|
18195
|
+
delete info.delay;
|
|
18196
|
+
}
|
|
18197
|
+
}
|
|
18198
|
+
}
|
|
18199
|
+
const steps = layout.steps.filter((s) => s.node.forVtxos.some((v) => activeOutpoints.has(v)));
|
|
18200
|
+
if (steps.length === 0 && sweepSteps.length === 0) {
|
|
18201
|
+
throw new Error("no exitable vtxos (all skipped)");
|
|
18202
|
+
}
|
|
18203
|
+
if (mode === "graph") {
|
|
18204
|
+
const bumpSteps = steps.map((step) => ({
|
|
18205
|
+
kind: "bump",
|
|
18206
|
+
parentTxid: step.parent.id,
|
|
18207
|
+
parentHex: step.parent.hex,
|
|
18208
|
+
forVtxos: step.node.forVtxos.filter((v) => activeOutpoints.has(v))
|
|
18209
|
+
}));
|
|
18210
|
+
const stepFees2 = steps.reduce((s, x) => s + x.stepFee, 0);
|
|
18211
|
+
const activeInfos2 = layout.infos.filter((i) => !i.skipped);
|
|
18212
|
+
const sweepFees2 = activeInfos2.reduce((s, i) => s + (i.sweepFee ?? 0), 0);
|
|
18213
|
+
const recovered2 = activeInfos2.reduce((s, i) => s + (i.value ?? 0) - (i.sweepFee ?? 0), 0);
|
|
18214
|
+
return {
|
|
18215
|
+
version: 1,
|
|
18216
|
+
mode: "graph",
|
|
18217
|
+
network: resolveNetworkName(opts),
|
|
18218
|
+
createdAt: Math.floor(Date.now() / 1e3),
|
|
18219
|
+
validUntil: layout.validUntil,
|
|
18220
|
+
feeRate,
|
|
18221
|
+
sweepAddress: opts.sweepAddress,
|
|
18222
|
+
totals: {
|
|
18223
|
+
txCount: bumpSteps.length * 2 + sweepSteps.length,
|
|
18224
|
+
totalFeeSats: stepFees2 + sweepFees2,
|
|
18225
|
+
fundingRequiredSats: stepFees2,
|
|
18226
|
+
recoveredSats: recovered2
|
|
18227
|
+
},
|
|
18228
|
+
vtxos: layout.infos,
|
|
18229
|
+
steps: [...bumpSteps, ...sweepSteps]
|
|
18230
|
+
};
|
|
18231
|
+
}
|
|
18232
|
+
const packageSteps = [];
|
|
18233
|
+
let broadcastStep;
|
|
18234
|
+
let splitterFee = 0;
|
|
18235
|
+
if (steps.length > 0) {
|
|
18236
|
+
const fundingTotal = steps.reduce((sum, s) => sum + s.funding, 0);
|
|
18237
|
+
let selected = { inputs: [], changeAmount: 0n };
|
|
18238
|
+
for (let i = 0; i < 10; i++) {
|
|
18239
|
+
const target = fundingTotal + splitterFee;
|
|
18240
|
+
try {
|
|
18241
|
+
selected = selectCoins(layout.coins, target);
|
|
18242
|
+
} catch {
|
|
18243
|
+
throw new Error(
|
|
18244
|
+
`insufficient confirmed onchain funds: need ${target} sats, have ${layout.balance} (deposit the shortfall to ${onchainWallet.address})`
|
|
18245
|
+
);
|
|
18246
|
+
}
|
|
18247
|
+
const est = TxWeightEstimator.create();
|
|
18248
|
+
for (const _ of selected.inputs) est.addKeySpendInput(true);
|
|
18249
|
+
for (const _ of steps) est.addOutputAddress(onchainWallet.address, wallet.network);
|
|
18250
|
+
if (selected.changeAmount >= BigInt(DUST_AMOUNT)) {
|
|
18251
|
+
est.addOutputAddress(onchainWallet.address, wallet.network);
|
|
18252
|
+
}
|
|
18253
|
+
const newFee = Number(est.vsize().fee(BigInt(feeRate)));
|
|
18254
|
+
if (newFee <= splitterFee) break;
|
|
18255
|
+
splitterFee = newFee;
|
|
18256
|
+
}
|
|
18257
|
+
const splitter = new chunkUHOHLN3C_cjs.Transaction({ version: 2 });
|
|
18258
|
+
for (const coin of selected.inputs) {
|
|
18259
|
+
splitter.addInput({
|
|
18260
|
+
txid: coin.txid,
|
|
18261
|
+
index: coin.vout,
|
|
18262
|
+
witnessUtxo: {
|
|
18263
|
+
script: onchainWallet.onchainP2TR.script,
|
|
18264
|
+
amount: BigInt(coin.value)
|
|
18265
|
+
},
|
|
18266
|
+
tapInternalKey: onchainWallet.onchainP2TR.tapInternalKey
|
|
18267
|
+
});
|
|
18268
|
+
}
|
|
18269
|
+
for (const step of steps) {
|
|
18270
|
+
splitter.addOutputAddress(onchainWallet.address, BigInt(step.funding), wallet.network);
|
|
18271
|
+
}
|
|
18272
|
+
const inputSum = selected.inputs.reduce((s, c) => s + c.value, 0);
|
|
18273
|
+
const change = BigInt(inputSum - fundingTotal - splitterFee);
|
|
18274
|
+
if (change < 0n) {
|
|
18275
|
+
throw new Error(
|
|
18276
|
+
`insufficient confirmed onchain funds for the splitter fee: need ${fundingTotal + splitterFee} sats, have ${inputSum} (deposit the shortfall to ${onchainWallet.address})`
|
|
18277
|
+
);
|
|
18278
|
+
}
|
|
18279
|
+
if (change >= BigInt(DUST_AMOUNT)) {
|
|
18280
|
+
splitter.addOutputAddress(onchainWallet.address, change, wallet.network);
|
|
18281
|
+
} else if (change > 0n) {
|
|
18282
|
+
splitterFee += Number(change);
|
|
18283
|
+
}
|
|
18284
|
+
const signedSplitter = await wallet.identity.sign(splitter);
|
|
18285
|
+
signedSplitter.finalize();
|
|
18286
|
+
for (let k = 0; k < steps.length; k++) {
|
|
18287
|
+
const step = steps[k];
|
|
18288
|
+
const { child } = buildAnchorChild({
|
|
18289
|
+
parent: step.parent,
|
|
18290
|
+
feeRate,
|
|
18291
|
+
fundingCoins: [{ txid: signedSplitter.id, vout: k, value: step.funding }],
|
|
18292
|
+
changeAddress: onchainWallet.address,
|
|
18293
|
+
changeScript: onchainWallet.onchainP2TR.script,
|
|
18294
|
+
tapInternalKey: onchainWallet.onchainP2TR.tapInternalKey,
|
|
18295
|
+
network: wallet.network
|
|
18296
|
+
});
|
|
18297
|
+
const signedChild = await wallet.identity.sign(child);
|
|
18298
|
+
for (let i = 1; i < signedChild.inputsLength; i++) {
|
|
18299
|
+
signedChild.finalizeIdx(i);
|
|
18300
|
+
}
|
|
18301
|
+
packageSteps.push({
|
|
18302
|
+
kind: "package",
|
|
18303
|
+
parentTxid: step.parent.id,
|
|
18304
|
+
parentHex: step.parent.hex,
|
|
18305
|
+
childTxid: signedChild.id,
|
|
18306
|
+
childHex: signedChild.hex,
|
|
18307
|
+
forVtxos: step.node.forVtxos.filter((v) => activeOutpoints.has(v))
|
|
18308
|
+
});
|
|
18309
|
+
}
|
|
18310
|
+
broadcastStep = { kind: "broadcast", txid: signedSplitter.id, hex: signedSplitter.hex };
|
|
18311
|
+
await onchainWallet.provider.broadcastTransaction(signedSplitter.hex);
|
|
18312
|
+
}
|
|
18313
|
+
const stepFees = steps.reduce((s, x) => s + x.stepFee, 0);
|
|
18314
|
+
const activeInfos = layout.infos.filter((i) => !i.skipped);
|
|
18315
|
+
const sweepFees = activeInfos.reduce((s, i) => s + (i.sweepFee ?? 0), 0);
|
|
18316
|
+
const recovered = activeInfos.reduce((s, i) => s + (i.value ?? 0) - (i.sweepFee ?? 0), 0);
|
|
18317
|
+
const fundingRequired = splitterFee + steps.reduce((s, x) => s + x.funding, 0);
|
|
18318
|
+
return {
|
|
18319
|
+
version: 1,
|
|
18320
|
+
mode: "funded",
|
|
18321
|
+
network: resolveNetworkName(opts),
|
|
18322
|
+
createdAt: Math.floor(Date.now() / 1e3),
|
|
18323
|
+
validUntil: layout.validUntil,
|
|
18324
|
+
feeRate,
|
|
18325
|
+
sweepAddress: opts.sweepAddress,
|
|
18326
|
+
totals: {
|
|
18327
|
+
txCount: (broadcastStep ? 1 : 0) + packageSteps.length * 2 + sweepSteps.length,
|
|
18328
|
+
totalFeeSats: splitterFee + stepFees + sweepFees,
|
|
18329
|
+
fundingRequiredSats: fundingRequired,
|
|
18330
|
+
recoveredSats: recovered
|
|
18331
|
+
},
|
|
18332
|
+
vtxos: layout.infos,
|
|
18333
|
+
steps: [...broadcastStep ? [broadcastStep] : [], ...packageSteps, ...sweepSteps]
|
|
18334
|
+
};
|
|
18335
|
+
}
|
|
18336
|
+
|
|
18337
|
+
// src/wallet/exit/types.ts
|
|
18338
|
+
function serializeExitPackage(pkg) {
|
|
18339
|
+
return JSON.stringify(pkg);
|
|
18340
|
+
}
|
|
18341
|
+
function deserializeExitPackage(json) {
|
|
18342
|
+
const data = JSON.parse(json);
|
|
18343
|
+
if (data?.version !== 1) {
|
|
18344
|
+
throw new Error(`unsupported exit package version: ${data?.version}`);
|
|
18345
|
+
}
|
|
18346
|
+
if (typeof data.network !== "string" || typeof data.sweepAddress !== "string") {
|
|
18347
|
+
throw new Error("invalid exit package: missing network or sweepAddress");
|
|
18348
|
+
}
|
|
18349
|
+
if (typeof data.feeRate !== "number" || typeof data.createdAt !== "number") {
|
|
18350
|
+
throw new Error("invalid exit package: missing feeRate or createdAt");
|
|
18351
|
+
}
|
|
18352
|
+
if (!Array.isArray(data.steps) || !Array.isArray(data.vtxos)) {
|
|
18353
|
+
throw new Error("invalid exit package: steps and vtxos must be arrays");
|
|
18354
|
+
}
|
|
18355
|
+
if (!isValidTotals(data.totals)) {
|
|
18356
|
+
throw new Error("invalid exit package: malformed totals");
|
|
18357
|
+
}
|
|
18358
|
+
for (const step of data.steps) {
|
|
18359
|
+
if (!isValidStep(step)) {
|
|
18360
|
+
throw new Error(`invalid step: ${JSON.stringify(step)}`);
|
|
18361
|
+
}
|
|
18362
|
+
}
|
|
18363
|
+
return data;
|
|
18364
|
+
}
|
|
18365
|
+
function isValidDelay(d) {
|
|
18366
|
+
const delay = d;
|
|
18367
|
+
return !!delay && (delay.type === "blocks" || delay.type === "seconds") && typeof delay.value === "number";
|
|
18368
|
+
}
|
|
18369
|
+
function isValidTotals(t) {
|
|
18370
|
+
const totals = t;
|
|
18371
|
+
return !!totals && typeof totals === "object" && typeof totals.txCount === "number" && typeof totals.totalFeeSats === "number" && typeof totals.fundingRequiredSats === "number" && typeof totals.recoveredSats === "number";
|
|
18372
|
+
}
|
|
18373
|
+
function isValidStep(step) {
|
|
18374
|
+
const s = step;
|
|
18375
|
+
if (!s || typeof s !== "object") return false;
|
|
18376
|
+
switch (s.kind) {
|
|
18377
|
+
case "broadcast":
|
|
18378
|
+
return typeof s.txid === "string" && typeof s.hex === "string";
|
|
18379
|
+
case "package":
|
|
18380
|
+
return typeof s.parentTxid === "string" && typeof s.parentHex === "string" && typeof s.childTxid === "string" && typeof s.childHex === "string" && Array.isArray(s.forVtxos);
|
|
18381
|
+
case "bump":
|
|
18382
|
+
return typeof s.parentTxid === "string" && typeof s.parentHex === "string" && Array.isArray(s.forVtxos);
|
|
18383
|
+
case "sweep":
|
|
18384
|
+
return typeof s.vtxo === "string" && typeof s.txid === "string" && typeof s.hex === "string" && typeof s.dependsOnTxid === "string" && isValidDelay(s.delay);
|
|
18385
|
+
default:
|
|
18386
|
+
return false;
|
|
18387
|
+
}
|
|
18388
|
+
}
|
|
18389
|
+
|
|
18390
|
+
// src/wallet/exit/index.ts
|
|
18391
|
+
var UnilateralExit = {
|
|
18392
|
+
estimate,
|
|
18393
|
+
prepare,
|
|
18394
|
+
Executor
|
|
18395
|
+
};
|
|
16813
18396
|
var ARKCONTRACT_PREFIX = "arkcontract";
|
|
16814
18397
|
function encodeArkContract(contract) {
|
|
16815
18398
|
const params = new URLSearchParams();
|
|
@@ -16926,6 +18509,7 @@ exports.SingleKey = SingleKey;
|
|
|
16926
18509
|
exports.TxTree = TxTree;
|
|
16927
18510
|
exports.TxType = TxType;
|
|
16928
18511
|
exports.TxWeightEstimator = TxWeightEstimator;
|
|
18512
|
+
exports.UnilateralExit = UnilateralExit;
|
|
16929
18513
|
exports.VtxoManager = VtxoManager;
|
|
16930
18514
|
exports.Wallet = Wallet2;
|
|
16931
18515
|
exports.WalletMessageHandler = WalletMessageHandler;
|
|
@@ -16943,8 +18527,10 @@ exports.combineTapscriptSigs = combineTapscriptSigs;
|
|
|
16943
18527
|
exports.contractFromArkContract = contractFromArkContract;
|
|
16944
18528
|
exports.contractFromArkContractWithAddress = contractFromArkContractWithAddress;
|
|
16945
18529
|
exports.createDefaultActivityRegistry = createDefaultActivityRegistry;
|
|
18530
|
+
exports.createExitChainResolver = createExitChainResolver;
|
|
16946
18531
|
exports.decodeArkContract = decodeArkContract;
|
|
16947
18532
|
exports.deserializeAssets = deserializeAssets;
|
|
18533
|
+
exports.deserializeExitPackage = deserializeExitPackage;
|
|
16948
18534
|
exports.deserializeUtxo = deserializeUtxo;
|
|
16949
18535
|
exports.deserializeVtxo = deserializeVtxo;
|
|
16950
18536
|
exports.encodeArkContract = encodeArkContract;
|
|
@@ -16960,6 +18546,7 @@ exports.isCooperativelyMigratable = isCooperativelyMigratable;
|
|
|
16960
18546
|
exports.isDiscoverable = isDiscoverable;
|
|
16961
18547
|
exports.isExpired = isExpired;
|
|
16962
18548
|
exports.isRecoverable = isRecoverable;
|
|
18549
|
+
exports.isRetryableProviderError = isRetryableProviderError;
|
|
16963
18550
|
exports.isSpendable = isSpendable;
|
|
16964
18551
|
exports.isSubdust = isSubdust;
|
|
16965
18552
|
exports.isTerminalIntentState = isTerminalIntentState;
|
|
@@ -16974,6 +18561,7 @@ exports.rollbackMigration = rollbackMigration;
|
|
|
16974
18561
|
exports.saveVtxosForContract = saveVtxosForContract;
|
|
16975
18562
|
exports.scriptFromArkAddress = scriptFromArkAddress;
|
|
16976
18563
|
exports.serializeAssets = serializeAssets;
|
|
18564
|
+
exports.serializeExitPackage = serializeExitPackage;
|
|
16977
18565
|
exports.serializeUtxo = serializeUtxo;
|
|
16978
18566
|
exports.serializeVtxo = serializeVtxo;
|
|
16979
18567
|
exports.setupServiceWorker = setupServiceWorker;
|
|
@@ -16984,5 +18572,5 @@ exports.validateVtxoTxGraph = validateVtxoTxGraph;
|
|
|
16984
18572
|
exports.verifyTapscriptSignatures = verifyTapscriptSignatures;
|
|
16985
18573
|
exports.waitForIncomingFunds = waitForIncomingFunds;
|
|
16986
18574
|
exports.warnAndFilterVtxosForScript = warnAndFilterVtxosForScript;
|
|
16987
|
-
//# sourceMappingURL=chunk-
|
|
16988
|
-
//# sourceMappingURL=chunk-
|
|
18575
|
+
//# sourceMappingURL=chunk-SRCWBFSZ.cjs.map
|
|
18576
|
+
//# sourceMappingURL=chunk-SRCWBFSZ.cjs.map
|