@arkade-os/sdk 0.4.43 → 0.4.44

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.
Files changed (48) hide show
  1. package/README.md +65 -0
  2. package/dist/adapters/expo.cjs +4 -4
  3. package/dist/adapters/expo.js +2 -2
  4. package/dist/adapters/indexedDB.cjs +3 -3
  5. package/dist/adapters/indexedDB.js +2 -2
  6. package/dist/{asyncStorageTaskQueue-CjoL-35w.d.ts → asyncStorageTaskQueue-BtSOVZFn.d.ts} +2 -2
  7. package/dist/{asyncStorageTaskQueue-D1FfHfgK.d.cts → asyncStorageTaskQueue-Dap7qUlF.d.cts} +2 -2
  8. package/dist/{chunk-B4R36PRN.js → chunk-FMI2GKYO.js} +1088 -181
  9. package/dist/chunk-FMI2GKYO.js.map +1 -0
  10. package/dist/{chunk-US274KZO.js → chunk-LCQQPOIT.js} +3 -3
  11. package/dist/{chunk-US274KZO.js.map → chunk-LCQQPOIT.js.map} +1 -1
  12. package/dist/{chunk-763XHDAJ.js → chunk-LJ35HPJW.js} +3 -3
  13. package/dist/{chunk-763XHDAJ.js.map → chunk-LJ35HPJW.js.map} +1 -1
  14. package/dist/{chunk-JIWCE2IK.cjs → chunk-RJ6XVCX4.cjs} +7 -7
  15. package/dist/{chunk-JIWCE2IK.cjs.map → chunk-RJ6XVCX4.cjs.map} +1 -1
  16. package/dist/{chunk-3AQNLQPM.cjs → chunk-UBYY2TPK.cjs} +3 -3
  17. package/dist/{chunk-3AQNLQPM.cjs.map → chunk-UBYY2TPK.cjs.map} +1 -1
  18. package/dist/{chunk-VKKLOT2E.js → chunk-V7WIZR2B.js} +3 -3
  19. package/dist/{chunk-VKKLOT2E.js.map → chunk-V7WIZR2B.js.map} +1 -1
  20. package/dist/{chunk-PLJZRIFZ.cjs → chunk-X37EKDIH.cjs} +11 -11
  21. package/dist/{chunk-PLJZRIFZ.cjs.map → chunk-X37EKDIH.cjs.map} +1 -1
  22. package/dist/{chunk-QGNTDGMN.cjs → chunk-XIVCG6EP.cjs} +1163 -253
  23. package/dist/chunk-XIVCG6EP.cjs.map +1 -0
  24. package/dist/index.cjs +138 -126
  25. package/dist/index.d.cts +232 -1
  26. package/dist/index.d.ts +232 -1
  27. package/dist/index.js +2 -2
  28. package/dist/repositories/realm/index.cjs +17 -17
  29. package/dist/repositories/realm/index.js +3 -3
  30. package/dist/repositories/sqlite/index.cjs +16 -16
  31. package/dist/repositories/sqlite/index.js +3 -3
  32. package/dist/{taskRunner-Djlhfgi1.d.ts → taskRunner-Bptw9UMa.d.ts} +1 -1
  33. package/dist/{taskRunner-BSnslNmq.d.cts → taskRunner-CeFxKhSH.d.cts} +1 -1
  34. package/dist/wallet/expo/background.cjs +12 -12
  35. package/dist/wallet/expo/background.d.cts +2 -2
  36. package/dist/wallet/expo/background.d.ts +2 -2
  37. package/dist/wallet/expo/background.js +4 -4
  38. package/dist/wallet/expo/index.cjs +12 -12
  39. package/dist/wallet/expo/index.d.cts +1 -1
  40. package/dist/wallet/expo/index.d.ts +1 -1
  41. package/dist/wallet/expo/index.js +3 -3
  42. package/dist/worker/expo/index.cjs +7 -7
  43. package/dist/worker/expo/index.d.cts +3 -3
  44. package/dist/worker/expo/index.d.ts +3 -3
  45. package/dist/worker/expo/index.js +3 -3
  46. package/package.json +1 -1
  47. package/dist/chunk-B4R36PRN.js.map +0 -1
  48. package/dist/chunk-QGNTDGMN.cjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk3AQNLQPM_cjs = require('./chunk-3AQNLQPM.cjs');
3
+ var chunkUBYY2TPK_cjs = require('./chunk-UBYY2TPK.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 = chunk3AQNLQPM_cjs.getArkPsbtFields(tx.root, 0, chunk3AQNLQPM_cjs.CosignerPublicKey).map(
184
+ const cosigners = chunkUBYY2TPK_cjs.getArkPsbtFields(tx.root, 0, chunkUBYY2TPK_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 = chunk3AQNLQPM_cjs.getArkPsbtFields(g.root, 0, chunk3AQNLQPM_cjs.CosignerPublicKey).map((c) => c.key);
236
+ const cosigners = chunkUBYY2TPK_cjs.getArkPsbtFields(g.root, 0, chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(url, {
983
+ const response = await chunkUBYY2TPK_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: chunk3AQNLQPM_cjs.Intent.encodeMessage(intent.message),
990
+ message: chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(url);
1010
+ const response = await chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(`${this.baseUrl}/address/${address}/utxo`);
1045
+ const response = await chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(`${this.baseUrl}/fee-estimates`);
1052
+ const response = await chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/outspends`);
1073
+ const response = await chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(`${this.baseUrl}/address/${address}/txs`);
1081
+ const response = await chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(`${this.baseUrl}/tx/${txid}`);
1089
+ const txresponse = await chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/status`);
1097
+ const response = await chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(`${this.baseUrl}/blocks`);
1181
+ const tipBlocks = await chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(`${this.baseUrl}/txs/package`, {
1200
+ const response = await chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.baseFetch(`${this.baseUrl}/tx`, {
1214
+ const response = await chunkUBYY2TPK_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 chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.Transaction({
1424
+ const tx = new chunkUBYY2TPK_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 = chunk3AQNLQPM_cjs.getArkPsbtFields(child.root, 0, chunk3AQNLQPM_cjs.CosignerPublicKey);
1500
+ const cosigners = chunkUBYY2TPK_cjs.getArkPsbtFields(child.root, 0, chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.BufferReader(payload.slice(ARKADE_MAGIC.length));
1600
+ const reader = new chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.Packet) {
1674
+ if (p instanceof chunkUBYY2TPK_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 === chunk3AQNLQPM_cjs.Packet.PACKET_TYPE) {
1544
- return chunk3AQNLQPM_cjs.Packet.fromBytes(data);
1682
+ if (packetType === chunkUBYY2TPK_cjs.Packet.PACKET_TYPE) {
1683
+ return chunkUBYY2TPK_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
- chunk3AQNLQPM_cjs.AssetInput.create(inputIndex, asset.amount)
1990
+ chunkUBYY2TPK_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
- chunk3AQNLQPM_cjs.AssetOutput.create(outputIndex, asset.amount)
2002
+ chunkUBYY2TPK_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
- chunk3AQNLQPM_cjs.AssetOutput.create(outputIndex, asset.amount)
2013
+ chunkUBYY2TPK_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 = chunk3AQNLQPM_cjs.AssetId.fromString(assetIdStr);
1884
- const group = chunk3AQNLQPM_cjs.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
2022
+ const assetId = chunkUBYY2TPK_cjs.AssetId.fromString(assetIdStr);
2023
+ const group = chunkUBYY2TPK_cjs.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
1885
2024
  groups.push(group);
1886
2025
  }
1887
- return chunk3AQNLQPM_cjs.Packet.create(groups);
2026
+ return chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.Transaction({
2143
+ const tx = new chunkUBYY2TPK_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
- chunk3AQNLQPM_cjs.setArkPsbtField(tx, i, chunk3AQNLQPM_cjs.VtxoTaprootTree, input.tapTree);
2158
+ chunkUBYY2TPK_cjs.setArkPsbtField(tx, i, chunkUBYY2TPK_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 chunk3AQNLQPM_cjs.Transaction();
3160
+ const tx = new chunkUBYY2TPK_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 = chunk3AQNLQPM_cjs.maybeArkError(error);
3799
+ const ark = chunkUBYY2TPK_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;
@@ -4791,7 +4824,7 @@ var AssetManager = class extends ReadonlyAssetManager {
4791
4824
  const virtualCoins = await this.wallet.getVtxos({
4792
4825
  withRecoverable: false
4793
4826
  });
4794
- const controlAssetRef = params.controlAssetId ? chunk3AQNLQPM_cjs.AssetRef.fromId(chunk3AQNLQPM_cjs.AssetId.fromString(params.controlAssetId)) : null;
4827
+ const controlAssetRef = params.controlAssetId ? chunkUBYY2TPK_cjs.AssetRef.fromId(chunkUBYY2TPK_cjs.AssetId.fromString(params.controlAssetId)) : null;
4795
4828
  const coinSelection = selectVirtualCoins(virtualCoins, Number(this.wallet.dustAmount));
4796
4829
  let totalBtcSelected = 0n;
4797
4830
  const assetChanges = /* @__PURE__ */ new Map();
@@ -4804,8 +4837,8 @@ var AssetManager = class extends ReadonlyAssetManager {
4804
4837
  }
4805
4838
  }
4806
4839
  const groups = [];
4807
- const issuedAssetOutput = chunk3AQNLQPM_cjs.AssetOutput.create(0, params.amount);
4808
- const issuedAssetGroup = chunk3AQNLQPM_cjs.AssetGroup.create(
4840
+ const issuedAssetOutput = chunkUBYY2TPK_cjs.AssetOutput.create(0, params.amount);
4841
+ const issuedAssetGroup = chunkUBYY2TPK_cjs.AssetGroup.create(
4809
4842
  null,
4810
4843
  controlAssetRef,
4811
4844
  [],
@@ -4820,15 +4853,15 @@ var AssetManager = class extends ReadonlyAssetManager {
4820
4853
  for (const [inputIndex, assets] of assetInputs) {
4821
4854
  for (const asset of assets) {
4822
4855
  if (asset.assetId !== assetId) continue;
4823
- changeInputs.push(chunk3AQNLQPM_cjs.AssetInput.create(inputIndex, asset.amount));
4856
+ changeInputs.push(chunkUBYY2TPK_cjs.AssetInput.create(inputIndex, asset.amount));
4824
4857
  }
4825
4858
  }
4826
4859
  groups.push(
4827
- chunk3AQNLQPM_cjs.AssetGroup.create(
4828
- chunk3AQNLQPM_cjs.AssetId.fromString(assetId),
4860
+ chunkUBYY2TPK_cjs.AssetGroup.create(
4861
+ chunkUBYY2TPK_cjs.AssetId.fromString(assetId),
4829
4862
  null,
4830
4863
  changeInputs,
4831
- [chunk3AQNLQPM_cjs.AssetOutput.create(0, amount)],
4864
+ [chunkUBYY2TPK_cjs.AssetOutput.create(0, amount)],
4832
4865
  []
4833
4866
  )
4834
4867
  );
@@ -4841,7 +4874,7 @@ var AssetManager = class extends ReadonlyAssetManager {
4841
4874
  script: outputAddress.pkScript,
4842
4875
  amount: BigInt(totalBtcSelected)
4843
4876
  },
4844
- Extension.create([chunk3AQNLQPM_cjs.Packet.create(groups)]).txOut()
4877
+ Extension.create([chunkUBYY2TPK_cjs.Packet.create(groups)]).txOut()
4845
4878
  ];
4846
4879
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(
4847
4880
  coinSelection.inputs,
@@ -4849,7 +4882,7 @@ var AssetManager = class extends ReadonlyAssetManager {
4849
4882
  );
4850
4883
  return {
4851
4884
  arkTxId: arkTxid,
4852
- assetId: chunk3AQNLQPM_cjs.AssetId.create(arkTxid, 0).toString()
4885
+ assetId: chunkUBYY2TPK_cjs.AssetId.create(arkTxid, 0).toString()
4853
4886
  };
4854
4887
  }
4855
4888
  /**
@@ -4921,16 +4954,16 @@ var AssetManager = class extends ReadonlyAssetManager {
4921
4954
  for (const [inputIndex, assets] of assetInputs) {
4922
4955
  for (const asset of assets) {
4923
4956
  if (asset.assetId !== params.assetId) continue;
4924
- reissueInputs.push(chunk3AQNLQPM_cjs.AssetInput.create(inputIndex, asset.amount));
4957
+ reissueInputs.push(chunkUBYY2TPK_cjs.AssetInput.create(inputIndex, asset.amount));
4925
4958
  }
4926
4959
  }
4927
4960
  const totalAssetAmount = assetToReissueAmount + params.amount;
4928
- const reissueAssetIdObj = chunk3AQNLQPM_cjs.AssetId.fromString(params.assetId);
4929
- const reissueAssetGroup = chunk3AQNLQPM_cjs.AssetGroup.create(
4961
+ const reissueAssetIdObj = chunkUBYY2TPK_cjs.AssetId.fromString(params.assetId);
4962
+ const reissueAssetGroup = chunkUBYY2TPK_cjs.AssetGroup.create(
4930
4963
  reissueAssetIdObj,
4931
4964
  null,
4932
4965
  reissueInputs,
4933
- [chunk3AQNLQPM_cjs.AssetOutput.create(0, totalAssetAmount)],
4966
+ [chunkUBYY2TPK_cjs.AssetOutput.create(0, totalAssetAmount)],
4934
4967
  []
4935
4968
  );
4936
4969
  const groups = [reissueAssetGroup];
@@ -4939,15 +4972,15 @@ var AssetManager = class extends ReadonlyAssetManager {
4939
4972
  for (const [inputIndex, assets] of assetInputs) {
4940
4973
  for (const asset of assets) {
4941
4974
  if (asset.assetId !== assetId) continue;
4942
- changeInputs.push(chunk3AQNLQPM_cjs.AssetInput.create(inputIndex, asset.amount));
4975
+ changeInputs.push(chunkUBYY2TPK_cjs.AssetInput.create(inputIndex, asset.amount));
4943
4976
  }
4944
4977
  }
4945
4978
  groups.push(
4946
- chunk3AQNLQPM_cjs.AssetGroup.create(
4947
- chunk3AQNLQPM_cjs.AssetId.fromString(assetId),
4979
+ chunkUBYY2TPK_cjs.AssetGroup.create(
4980
+ chunkUBYY2TPK_cjs.AssetId.fromString(assetId),
4948
4981
  null,
4949
4982
  changeInputs,
4950
- [chunk3AQNLQPM_cjs.AssetOutput.create(0, amount)],
4983
+ [chunkUBYY2TPK_cjs.AssetOutput.create(0, amount)],
4951
4984
  []
4952
4985
  )
4953
4986
  );
@@ -4959,7 +4992,7 @@ var AssetManager = class extends ReadonlyAssetManager {
4959
4992
  script: outputAddress.pkScript,
4960
4993
  amount: BigInt(totalBtcSelected)
4961
4994
  },
4962
- Extension.create([chunk3AQNLQPM_cjs.Packet.create(groups)]).txOut()
4995
+ Extension.create([chunkUBYY2TPK_cjs.Packet.create(groups)]).txOut()
4963
4996
  ];
4964
4997
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
4965
4998
  return arkTxid;
@@ -5026,15 +5059,15 @@ var AssetManager = class extends ReadonlyAssetManager {
5026
5059
  for (const [inputIndex, assets] of assetInputs) {
5027
5060
  for (const asset of assets) {
5028
5061
  if (asset.assetId !== assetId) continue;
5029
- changeInputs.push(chunk3AQNLQPM_cjs.AssetInput.create(inputIndex, asset.amount));
5062
+ changeInputs.push(chunkUBYY2TPK_cjs.AssetInput.create(inputIndex, asset.amount));
5030
5063
  }
5031
5064
  }
5032
5065
  groups.push(
5033
- chunk3AQNLQPM_cjs.AssetGroup.create(
5034
- chunk3AQNLQPM_cjs.AssetId.fromString(assetId),
5066
+ chunkUBYY2TPK_cjs.AssetGroup.create(
5067
+ chunkUBYY2TPK_cjs.AssetId.fromString(assetId),
5035
5068
  null,
5036
5069
  changeInputs,
5037
- amount > 0n ? [chunk3AQNLQPM_cjs.AssetOutput.create(0, amount)] : [],
5070
+ amount > 0n ? [chunkUBYY2TPK_cjs.AssetOutput.create(0, amount)] : [],
5038
5071
  []
5039
5072
  )
5040
5073
  );
@@ -5046,7 +5079,7 @@ var AssetManager = class extends ReadonlyAssetManager {
5046
5079
  script: outputAddress.pkScript,
5047
5080
  amount: BigInt(totalBtcSelected)
5048
5081
  },
5049
- Extension.create([chunk3AQNLQPM_cjs.Packet.create(groups)]).txOut()
5082
+ Extension.create([chunkUBYY2TPK_cjs.Packet.create(groups)]).txOut()
5050
5083
  ];
5051
5084
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
5052
5085
  return arkTxid;
@@ -5071,7 +5104,7 @@ function castMetadata(metadata) {
5071
5104
  } else {
5072
5105
  throw new Error("Invalid metadata value type");
5073
5106
  }
5074
- md.push(chunk3AQNLQPM_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
5107
+ md.push(chunkUBYY2TPK_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
5075
5108
  }
5076
5109
  return md;
5077
5110
  }
@@ -5356,7 +5389,7 @@ async function makeSignedDelegateIntent(identity, coins, outputs, onchainOutputs
5356
5389
  expire_at: 0,
5357
5390
  cosigners_public_keys: cosignerPubKeys
5358
5391
  };
5359
- const proof = chunk3AQNLQPM_cjs.Intent.create(message, coins, outputs);
5392
+ const proof = chunkUBYY2TPK_cjs.Intent.create(message, coins, outputs);
5360
5393
  const signedProof = await identity.sign(proof);
5361
5394
  return {
5362
5395
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -7454,7 +7487,7 @@ var ContractWatcher = class {
7454
7487
  this.connectionState = "connected";
7455
7488
  this.reconnectAttempts = 0;
7456
7489
  this.listenLoop().catch((e) => {
7457
- if (chunk3AQNLQPM_cjs.isEventSourceError(e)) {
7490
+ if (chunkUBYY2TPK_cjs.isEventSourceError(e)) {
7458
7491
  console.debug("ContractWatcher subscription disconnected; reconnecting");
7459
7492
  } else {
7460
7493
  console.error(e);
@@ -9548,7 +9581,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
9548
9581
  */
9549
9582
  static async setupWalletConfig(config, pubKey) {
9550
9583
  const arkadeServerUrl = getArkadeServerUrl(config);
9551
- const arkProvider = config.arkProvider || new chunk3AQNLQPM_cjs.RestArkProvider(arkadeServerUrl);
9584
+ const arkProvider = config.arkProvider || new chunkUBYY2TPK_cjs.RestArkProvider(arkadeServerUrl);
9552
9585
  let indexerProvider = config.indexerProvider;
9553
9586
  if (!indexerProvider) {
9554
9587
  let indexerUrl = config.indexerUrl;
@@ -9565,7 +9598,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
9565
9598
  indexerUrl = arkadeServerUrl;
9566
9599
  }
9567
9600
  }
9568
- indexerProvider = new chunk3AQNLQPM_cjs.RestIndexerProvider(indexerUrl);
9601
+ indexerProvider = new chunkUBYY2TPK_cjs.RestIndexerProvider(indexerUrl);
9569
9602
  }
9570
9603
  const info = await arkProvider.getInfo();
9571
9604
  const network = chunkHXDZ2QTW_cjs.getNetwork(info.network);
@@ -11580,9 +11613,9 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
11580
11613
  ...existing ?? {},
11581
11614
  intentTxId,
11582
11615
  registerProof: intent.proof,
11583
- registerProofMessage: chunk3AQNLQPM_cjs.Intent.encodeMessage(intent.message),
11616
+ registerProofMessage: chunkUBYY2TPK_cjs.Intent.encodeMessage(intent.message),
11584
11617
  deleteProof: deleteIntent.proof,
11585
- deleteProofMessage: chunk3AQNLQPM_cjs.Intent.encodeMessage(deleteIntent.message),
11618
+ deleteProofMessage: chunkUBYY2TPK_cjs.Intent.encodeMessage(deleteIntent.message),
11586
11619
  intentVtxos: inputs.map((i) => ({
11587
11620
  txid: i.txid,
11588
11621
  vout: i.vout
@@ -11614,7 +11647,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
11614
11647
  try {
11615
11648
  return await this.arkProvider.registerIntent(intent);
11616
11649
  } catch (error) {
11617
- if (error instanceof chunk3AQNLQPM_cjs.ArkError && error.code === 0 && error.message.includes("duplicated input")) {
11650
+ if (error instanceof chunkUBYY2TPK_cjs.ArkError && error.code === 0 && error.message.includes("duplicated input")) {
11618
11651
  const deleteIntent = await this.makeDeleteIntentSignature(inputs);
11619
11652
  await this.arkProvider.deleteIntent(deleteIntent);
11620
11653
  return this.arkProvider.registerIntent(intent);
@@ -11630,7 +11663,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
11630
11663
  expire_at: 0,
11631
11664
  cosigners_public_keys: cosignerPubKeys
11632
11665
  };
11633
- const proof = chunk3AQNLQPM_cjs.Intent.create(message, coins, outputs);
11666
+ const proof = chunkUBYY2TPK_cjs.Intent.create(message, coins, outputs);
11634
11667
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
11635
11668
  return {
11636
11669
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -11642,7 +11675,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
11642
11675
  type: "delete",
11643
11676
  expire_at: 0
11644
11677
  };
11645
- const proof = chunk3AQNLQPM_cjs.Intent.create(message, coins, []);
11678
+ const proof = chunkUBYY2TPK_cjs.Intent.create(message, coins, []);
11646
11679
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
11647
11680
  return {
11648
11681
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -11654,7 +11687,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
11654
11687
  type: "get-pending-tx",
11655
11688
  expire_at: 0
11656
11689
  };
11657
- const proof = chunk3AQNLQPM_cjs.Intent.create(message, coins, []);
11690
+ const proof = chunkUBYY2TPK_cjs.Intent.create(message, coins, []);
11658
11691
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
11659
11692
  return {
11660
11693
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -12612,7 +12645,7 @@ var MessageBus = class {
12612
12645
  this.initialized = true;
12613
12646
  }
12614
12647
  async buildServices(config) {
12615
- const arkProvider = new chunk3AQNLQPM_cjs.RestArkProvider(config.arkServer.url);
12648
+ const arkProvider = new chunkUBYY2TPK_cjs.RestArkProvider(config.arkServer.url);
12616
12649
  const storage = {
12617
12650
  walletRepository: this.walletRepository,
12618
12651
  contractRepository: this.contractRepository
@@ -13769,7 +13802,7 @@ var WalletMessageHandler = class {
13769
13802
  // Wallet methods
13770
13803
  async handleInitWallet({ payload }) {
13771
13804
  const { arkServerUrl } = payload;
13772
- this.indexerProvider = new chunk3AQNLQPM_cjs.RestIndexerProvider(arkServerUrl);
13805
+ this.indexerProvider = new chunkUBYY2TPK_cjs.RestIndexerProvider(arkServerUrl);
13773
13806
  await this.onWalletInitialized();
13774
13807
  }
13775
13808
  async handleGetBalance() {
@@ -15576,7 +15609,7 @@ var OnchainWallet = class _OnchainWallet {
15576
15609
  if (!inputs) {
15577
15610
  throw new Error("Fee estimation failed");
15578
15611
  }
15579
- let tx = new chunk3AQNLQPM_cjs.Transaction();
15612
+ let tx = new chunkUBYY2TPK_cjs.Transaction();
15580
15613
  for (const input of inputs) {
15581
15614
  tx.addInput({
15582
15615
  txid: input.txid,
@@ -15606,42 +15639,11 @@ var OnchainWallet = class _OnchainWallet {
15606
15639
  * @see send
15607
15640
  */
15608
15641
  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
15642
  let feeRate = await this.provider.getFeeRate();
15618
15643
  if (!feeRate || feeRate < _OnchainWallet.MIN_FEE_RATE) {
15619
15644
  feeRate = _OnchainWallet.MIN_FEE_RATE;
15620
15645
  }
15621
- const fee = Math.ceil(feeRate * packageVSize);
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
- }
15646
+ const child = await this.buildBumpPackage(parent, feeRate, await this.getCoins());
15645
15647
  try {
15646
15648
  await this.provider.broadcastTransaction(parent.hex, child.hex);
15647
15649
  } catch (error) {
@@ -15650,6 +15652,59 @@ var OnchainWallet = class _OnchainWallet {
15650
15652
  return [parent.hex, child.hex];
15651
15653
  }
15652
15654
  }
15655
+ /**
15656
+ * Build and sign a CPFP fee child for a parent tx (given as raw hex)
15657
+ * carrying a P2A anchor, funding it from this wallet's **confirmed**
15658
+ * coins, and return the 1P1C package hexes WITHOUT broadcasting.
15659
+ *
15660
+ * This is the graph-mode fee source ({@link ExitFeeWallet}): the exit
15661
+ * executor calls it to bump each transported virtual tx at execution
15662
+ * time, so funding can be deferred rather than pre-signed.
15663
+ *
15664
+ * @param parentHex - Finalized parent transaction, raw network hex
15665
+ * @param feeRate - sat/vB floor for the package (raised to MIN_FEE_RATE)
15666
+ * @returns Tuple of parent hex (unchanged) and signed child hex
15667
+ * @throws If the parent has no anchor, or funding cannot be selected/signed
15668
+ */
15669
+ async bumpAnchor(parentHex, feeRate) {
15670
+ const parent = chunkUBYY2TPK_cjs.Transaction.fromRaw(base.hex.decode(parentHex));
15671
+ const coins = (await this.getCoins()).filter((c) => c.status.confirmed);
15672
+ const child = await this.buildBumpPackage(parent, feeRate, coins);
15673
+ return [parent.hex, child.hex];
15674
+ }
15675
+ /**
15676
+ * Shared core of {@link bumpP2A} and {@link bumpAnchor}: probe the package
15677
+ * fee with a single-input child, select coins for it, then build and sign
15678
+ * with the actual selection (the fee grows per extra input).
15679
+ */
15680
+ async buildBumpPackage(parent, feeRate, coins) {
15681
+ let rate = feeRate;
15682
+ if (!rate || rate < _OnchainWallet.MIN_FEE_RATE) {
15683
+ rate = _OnchainWallet.MIN_FEE_RATE;
15684
+ }
15685
+ const probeVsize = TxWeightEstimator.create().addKeySpendInput(true).addP2AInput().addOutputAddress(this.address, this.network).vsize().value;
15686
+ const probeFee = Math.ceil(rate * (parent.vsize + Number(probeVsize)));
15687
+ if (!probeFee) {
15688
+ throw new Error(
15689
+ `invalid fee, got ${probeFee} with vsize ${parent.vsize + Number(probeVsize)}, feeRate ${rate}`
15690
+ );
15691
+ }
15692
+ const selected = selectCoins(coins, probeFee, true);
15693
+ const { child } = buildAnchorChild({
15694
+ parent,
15695
+ feeRate: rate,
15696
+ fundingCoins: selected.inputs,
15697
+ changeAddress: this.address,
15698
+ changeScript: this.onchainP2TR.script,
15699
+ tapInternalKey: this.onchainP2TR.tapInternalKey,
15700
+ network: this.network
15701
+ });
15702
+ const signed = await this.identity.sign(child);
15703
+ for (let i = 1; i < signed.inputsLength; i++) {
15704
+ signed.finalizeIdx(i);
15705
+ }
15706
+ return signed;
15707
+ }
15653
15708
  };
15654
15709
  function selectCoins(coins, targetAmount, forceChange = false) {
15655
15710
  if (isNaN(targetAmount)) {
@@ -16373,7 +16428,7 @@ exports.BIP322 = void 0;
16373
16428
  async function sign2(message, identity, network) {
16374
16429
  const xOnlyPubKey = await identity.xOnlyPublicKey();
16375
16430
  const payment = btcSigner.p2tr(xOnlyPubKey, void 0, network);
16376
- const toSpend = chunk3AQNLQPM_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
16431
+ const toSpend = chunkUBYY2TPK_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
16377
16432
  const toSign = craftBIP322ToSignP2TR(toSpend, payment.script, xOnlyPubKey);
16378
16433
  const signed = await identity.sign(toSign, [0]);
16379
16434
  signed.finalizeIdx(0);
@@ -16431,7 +16486,7 @@ function verifyP2TR(message, witnessItems, pkScript, pubkey) {
16431
16486
  if (sighashType !== btcSigner.SigHash.DEFAULT && sighashType !== btcSigner.SigHash.ALL) {
16432
16487
  return false;
16433
16488
  }
16434
- const toSpend = chunk3AQNLQPM_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
16489
+ const toSpend = chunkUBYY2TPK_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
16435
16490
  const toSign = craftBIP322ToSignP2TR(toSpend, pkScript, pubkey);
16436
16491
  const sighash = toSign.preimageWitnessV1(0, [pkScript], sighashType, [0n]);
16437
16492
  const rawSig = sig.length === 65 ? sig.subarray(0, 64) : sig;
@@ -16452,7 +16507,7 @@ function verifyP2WPKH(message, witnessItems, pkScript, addressHash) {
16452
16507
  }
16453
16508
  const sighashType = sigWithHash[sigWithHash.length - 1];
16454
16509
  const derSig = sigWithHash.subarray(0, sigWithHash.length - 1);
16455
- const toSpend = chunk3AQNLQPM_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
16510
+ const toSpend = chunkUBYY2TPK_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
16456
16511
  const toSign = craftBIP322ToSignSimple(toSpend, pkScript);
16457
16512
  const scriptCode = btcSigner.OutScript.encode({ type: "pkh", hash: addressHash });
16458
16513
  const sighash = toSign.preimageWitnessV0(0, scriptCode, sighashType, 0n);
@@ -16505,7 +16560,7 @@ function encodeCompactSize(n) {
16505
16560
  return buf;
16506
16561
  }
16507
16562
  function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
16508
- const tx = new chunk3AQNLQPM_cjs.Transaction({ version: 0 });
16563
+ const tx = new chunkUBYY2TPK_cjs.Transaction({ version: 0 });
16509
16564
  tx.addInput({
16510
16565
  txid: toSpend.id,
16511
16566
  index: 0,
@@ -16519,12 +16574,12 @@ function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
16519
16574
  });
16520
16575
  tx.addOutput({
16521
16576
  amount: 0n,
16522
- script: chunk3AQNLQPM_cjs.OP_RETURN_EMPTY_PKSCRIPT
16577
+ script: chunkUBYY2TPK_cjs.OP_RETURN_EMPTY_PKSCRIPT
16523
16578
  });
16524
16579
  return tx;
16525
16580
  }
16526
16581
  function craftBIP322ToSignSimple(toSpend, pkScript) {
16527
- const tx = new chunk3AQNLQPM_cjs.Transaction({ version: 0 });
16582
+ const tx = new chunkUBYY2TPK_cjs.Transaction({ version: 0 });
16528
16583
  tx.addInput({
16529
16584
  txid: toSpend.id,
16530
16585
  index: 0,
@@ -16536,10 +16591,88 @@ function craftBIP322ToSignSimple(toSpend, pkScript) {
16536
16591
  });
16537
16592
  tx.addOutput({
16538
16593
  amount: 0n,
16539
- script: chunk3AQNLQPM_cjs.OP_RETURN_EMPTY_PKSCRIPT
16594
+ script: chunkUBYY2TPK_cjs.OP_RETURN_EMPTY_PKSCRIPT
16540
16595
  });
16541
16596
  return tx;
16542
16597
  }
16598
+ function finalizeVirtualTx(type, psbtBase64) {
16599
+ const tx = chunkUBYY2TPK_cjs.Transaction.fromPSBT(base.base64.decode(psbtBase64));
16600
+ if (type === "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */) {
16601
+ const input = tx.getInput(0);
16602
+ if (!input) {
16603
+ throw new Error("Input not found");
16604
+ }
16605
+ const tapKeySig = input.tapKeySig;
16606
+ if (!tapKeySig) {
16607
+ throw new Error("Tap key sig not found");
16608
+ }
16609
+ tx.updateInput(0, {
16610
+ finalScriptWitness: [tapKeySig]
16611
+ });
16612
+ return tx;
16613
+ }
16614
+ tx.finalize();
16615
+ return tx;
16616
+ }
16617
+ var ExitPathError = class extends Error {
16618
+ constructor(reason, message) {
16619
+ super(message);
16620
+ this.reason = reason;
16621
+ this.name = "ExitPathError";
16622
+ }
16623
+ };
16624
+ function delayWeight(sequence) {
16625
+ const t = chunkHXDZ2QTW_cjs.sequenceToTimelock(sequence);
16626
+ return t.type === "blocks" ? Number(t.value) : Number(t.value) / 600;
16627
+ }
16628
+ async function resolveUnilateralPath(params) {
16629
+ const { vtxo, scriptHex, contractRepository } = params;
16630
+ const contract = contractRepository ? (await contractRepository.getContracts({ script: scriptHex }))[0] : void 0;
16631
+ if (contract) {
16632
+ const handler = chunk32YKLQPS_cjs.contractHandlers.get(contract.type);
16633
+ if (!handler) {
16634
+ throw new ExitPathError(
16635
+ "no-handler",
16636
+ `no contract handler registered for type '${contract.type}'`
16637
+ );
16638
+ }
16639
+ const script = handler.createScript(contract.params);
16640
+ const paths = handler.getAllSpendingPaths(script, contract, {
16641
+ collaborative: false,
16642
+ currentTime: params.currentTime,
16643
+ walletDescriptor: params.walletDescriptor,
16644
+ walletPubKey: params.walletPubKeyHex
16645
+ }).filter((p) => p.sequence !== void 0);
16646
+ if (paths.length === 0) {
16647
+ throw new ExitPathError(
16648
+ "no-unilateral-path",
16649
+ `no unilateral path for vtxo ${vtxo.txid}:${vtxo.vout} (type '${contract.type}')`
16650
+ );
16651
+ }
16652
+ paths.sort((a, b) => delayWeight(a.sequence) - delayWeight(b.sequence));
16653
+ return { selection: paths[0], label: `${contract.type}:unilateral` };
16654
+ }
16655
+ const decoded = chunkHXDZ2QTW_cjs.VtxoScript.decode(vtxo.tapTree);
16656
+ let best;
16657
+ for (const exit of decoded.exitPaths()) {
16658
+ const leaf = decoded.findLeaf(base.hex.encode(exit.script));
16659
+ if (!leaf) continue;
16660
+ const sequence = chunkHXDZ2QTW_cjs.timelockToSequence(exit.params.timelock);
16661
+ const weight = delayWeight(sequence);
16662
+ if (!best || weight < best.weight) {
16663
+ best = { selection: { leaf, sequence }, weight };
16664
+ }
16665
+ }
16666
+ if (!best) {
16667
+ throw new ExitPathError(
16668
+ "no-unilateral-path",
16669
+ `no exit path found for vtxo ${vtxo.txid}:${vtxo.vout}`
16670
+ );
16671
+ }
16672
+ return { selection: best.selection, label: "default:exit" };
16673
+ }
16674
+
16675
+ // src/wallet/unroll.ts
16543
16676
  function chainTxTypeToChainedExit(t) {
16544
16677
  switch (t) {
16545
16678
  case "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */:
@@ -16649,22 +16782,7 @@ exports.Unroll = void 0;
16649
16782
  if (!virtualTxBase64) {
16650
16783
  throw new Error(`Tx ${nextTxToBroadcast.txid} not found`);
16651
16784
  }
16652
- const tx = chunk3AQNLQPM_cjs.Transaction.fromPSBT(base.base64.decode(virtualTxBase64));
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
- }
16785
+ const tx = finalizeVirtualTx(nextTxToBroadcast.type, virtualTxBase64);
16668
16786
  const pkg = await this.bumper.bumpP2A(tx);
16669
16787
  return {
16670
16788
  type: 0 /* UNROLL */,
@@ -16718,20 +16836,21 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
16718
16836
  if (!txStatus.confirmed) {
16719
16837
  throw new Error(`tx ${vtxo.txid} is not confirmed`);
16720
16838
  }
16721
- const exit = availableExitPath(
16722
- { height: txStatus.blockHeight, time: txStatus.blockTime },
16723
- chainTip,
16724
- vtxo
16725
- );
16726
- if (!exit) {
16839
+ const resolved = await resolveUnilateralPath({
16840
+ vtxo,
16841
+ scriptHex: base.hex.encode(chunkHXDZ2QTW_cjs.VtxoScript.decode(vtxo.tapTree).pkScript),
16842
+ contractRepository: wallet.contractRepository,
16843
+ walletPubKeyHex: base.hex.encode(await wallet.identity.xOnlyPublicKey()),
16844
+ currentTime: Date.now()
16845
+ });
16846
+ const spendingLeaf = resolved.selection.leaf;
16847
+ const sequence = resolved.selection.sequence;
16848
+ const timelock = chunkHXDZ2QTW_cjs.sequenceToTimelock(sequence);
16849
+ const elapsed = timelock.type === "blocks" ? chainTip.height >= txStatus.blockHeight + Number(timelock.value) : chainTip.time >= txStatus.blockTime + Number(timelock.value);
16850
+ if (!elapsed) {
16727
16851
  throw new Error(`no available exit path found for vtxo ${vtxo.txid}:${vtxo.vout}`);
16728
16852
  }
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
16853
  totalAmount += BigInt(vtxo.value);
16734
- const sequence = chunkHXDZ2QTW_cjs.timelockToSequence(exit.params.timelock);
16735
16854
  inputs.push({
16736
16855
  txid: vtxo.txid,
16737
16856
  index: vtxo.vout,
@@ -16749,7 +16868,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
16749
16868
  btcSigner.TaprootControlBlock.encode(spendingLeaf[0]).length
16750
16869
  );
16751
16870
  }
16752
- const tx = new chunk3AQNLQPM_cjs.Transaction({ version: 2 });
16871
+ const tx = new chunkUBYY2TPK_cjs.Transaction({ version: 2 });
16753
16872
  for (const input of inputs) {
16754
16873
  tx.addInput(input);
16755
16874
  }
@@ -16795,21 +16914,809 @@ function doWait(onchainProvider, txid) {
16795
16914
  });
16796
16915
  };
16797
16916
  }
16798
- function availableExitPath(confirmedAt, current, vtxo) {
16799
- const exits = chunkHXDZ2QTW_cjs.VtxoScript.decode(vtxo.tapTree).exitPaths();
16800
- for (const exit of exits) {
16801
- if (exit.params.timelock.type === "blocks") {
16802
- if (current.height >= confirmedAt.height + Number(exit.params.timelock.value)) {
16803
- return exit;
16917
+
16918
+ // src/wallet/exit/chain.ts
16919
+ var isCommitment = (t) => t === "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */ || t === "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
16920
+ async function buildExitDag(params) {
16921
+ const byTxid = /* @__PURE__ */ new Map();
16922
+ for (const vtxo of params.vtxos) {
16923
+ const outpoint = `${vtxo.txid}:${vtxo.vout}`;
16924
+ let pageIndex = 0;
16925
+ let hasMore = true;
16926
+ while (hasMore) {
16927
+ const { chain, page } = await params.indexer.getVtxoChain(
16928
+ { txid: vtxo.txid, vout: vtxo.vout },
16929
+ { pageIndex, pageSize: chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE }
16930
+ );
16931
+ for (const chainTx of chain) {
16932
+ const existing = byTxid.get(chainTx.txid);
16933
+ if (existing) {
16934
+ existing.forVtxos.add(outpoint);
16935
+ } else {
16936
+ byTxid.set(chainTx.txid, { ...chainTx, forVtxos: /* @__PURE__ */ new Set([outpoint]) });
16937
+ }
16804
16938
  }
16805
- } else {
16806
- if (current.time >= confirmedAt.time + Number(exit.params.timelock.value)) {
16807
- return exit;
16939
+ hasMore = page ? chain.length === chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE : false;
16940
+ pageIndex++;
16941
+ }
16942
+ }
16943
+ const pending = new Map(
16944
+ [...byTxid.values()].filter((tx) => !isCommitment(tx.type)).map((tx) => [tx.txid, tx])
16945
+ );
16946
+ const inDegree = /* @__PURE__ */ new Map();
16947
+ for (const tx of pending.values()) {
16948
+ const parents = tx.spends.filter((p) => pending.has(p));
16949
+ inDegree.set(tx.txid, parents.length);
16950
+ }
16951
+ const order = [];
16952
+ const queue = [...pending.values()].filter((tx) => inDegree.get(tx.txid) === 0).sort((a, b) => a.txid.localeCompare(b.txid));
16953
+ while (queue.length > 0) {
16954
+ const tx = queue.shift();
16955
+ order.push(tx);
16956
+ const children = [...pending.values()].filter((c) => c.spends.includes(tx.txid)).sort((a, b) => a.txid.localeCompare(b.txid));
16957
+ for (const child of children) {
16958
+ const deg = inDegree.get(child.txid) - 1;
16959
+ inDegree.set(child.txid, deg);
16960
+ if (deg === 0) queue.push(child);
16961
+ }
16962
+ }
16963
+ if (order.length !== pending.size) {
16964
+ throw new Error("inconsistent vtxo chain from indexer (cycle detected)");
16965
+ }
16966
+ const nodes = [];
16967
+ for (const tx of order) {
16968
+ let confirmed = false;
16969
+ try {
16970
+ const status = await params.onchain.getTxStatus(tx.txid);
16971
+ confirmed = status.confirmed;
16972
+ } catch {
16973
+ confirmed = false;
16974
+ }
16975
+ const expires = Number(tx.expiresAt);
16976
+ nodes.push({
16977
+ txid: tx.txid,
16978
+ type: tx.type,
16979
+ expiresAt: Number.isFinite(expires) && expires > 0 ? expires : void 0,
16980
+ forVtxos: [...tx.forVtxos].sort(),
16981
+ confirmed
16982
+ });
16983
+ }
16984
+ return nodes;
16985
+ }
16986
+ function topoSortByDeps(items, idOf, depsOf) {
16987
+ const produced = new Set(items.map(idOf));
16988
+ const emitted = /* @__PURE__ */ new Set();
16989
+ const ordered = [];
16990
+ let remaining = items;
16991
+ while (remaining.length > 0) {
16992
+ const next = [];
16993
+ let progress = false;
16994
+ for (const item of remaining) {
16995
+ if (depsOf(item).every((d) => !produced.has(d) || emitted.has(d))) {
16996
+ ordered.push(item);
16997
+ emitted.add(idOf(item));
16998
+ progress = true;
16999
+ } else {
17000
+ next.push(item);
16808
17001
  }
16809
17002
  }
17003
+ if (!progress) {
17004
+ throw new Error("topological sort: cycle or unsatisfiable dependency");
17005
+ }
17006
+ remaining = next;
16810
17007
  }
16811
- return void 0;
17008
+ return ordered;
17009
+ }
17010
+ function extraWitnessSize(path) {
17011
+ return (path.extraWitness ?? []).reduce((sum, item) => sum + 1 + item.length, 0);
17012
+ }
17013
+ function sweepFeeFor(path, outputAddress, network, feeRate) {
17014
+ const [controlBlock, scriptWithVersion] = path.leaf;
17015
+ const estimator = TxWeightEstimator.create().addTapscriptInput(
17016
+ 64 + extraWitnessSize(path),
17017
+ scriptWithVersion.length,
17018
+ btcSigner.TaprootControlBlock.encode(controlBlock).length
17019
+ ).addOutputAddress(outputAddress, network);
17020
+ return Number(estimator.vsize().fee(BigInt(Math.ceil(feeRate))));
16812
17021
  }
17022
+ async function buildSignedSweep(params) {
17023
+ const { vtxo, path, outputAddress, feeRate, network, identity } = params;
17024
+ const fee = sweepFeeFor(path, outputAddress, network, feeRate);
17025
+ const sendAmount = BigInt(vtxo.value) - BigInt(fee);
17026
+ if (sendAmount < BigInt(DUST_AMOUNT)) {
17027
+ throw new Error(
17028
+ `uneconomic vtxo ${vtxo.txid}:${vtxo.vout}: value ${vtxo.value} - fee ${fee} < dust`
17029
+ );
17030
+ }
17031
+ const tx = new chunkUBYY2TPK_cjs.Transaction({ version: 2 });
17032
+ tx.addInput({
17033
+ txid: vtxo.txid,
17034
+ index: vtxo.vout,
17035
+ tapLeafScript: [path.leaf],
17036
+ sequence: path.sequence,
17037
+ witnessUtxo: { amount: BigInt(vtxo.value), script: vtxo.pkScript },
17038
+ sighashType: btcSigner.SigHash.DEFAULT
17039
+ });
17040
+ tx.addOutputAddress(outputAddress, sendAmount, network);
17041
+ const signed = await identity.sign(tx);
17042
+ if (!path.extraWitness || path.extraWitness.length === 0) {
17043
+ signed.finalize();
17044
+ return { tx: signed, fee };
17045
+ }
17046
+ const input = signed.getInput(0);
17047
+ const tapScriptSig = input.tapScriptSig;
17048
+ if (!tapScriptSig || tapScriptSig.length === 0) {
17049
+ throw new Error("exit path requires additional signers");
17050
+ }
17051
+ const [controlBlock] = path.leaf;
17052
+ signed.updateInput(0, {
17053
+ finalScriptWitness: [
17054
+ tapScriptSig[0][1],
17055
+ ...path.extraWitness,
17056
+ chunkHXDZ2QTW_cjs.scriptFromTapLeafScript(path.leaf),
17057
+ btcSigner.TaprootControlBlock.encode(controlBlock)
17058
+ ]
17059
+ });
17060
+ return { tx: signed, fee };
17061
+ }
17062
+
17063
+ // src/wallet/exit/estimate.ts
17064
+ var CHILD_OUTPUT_DUST = 546;
17065
+ function stepFundingAmount(stepFee) {
17066
+ return stepFee + CHILD_OUTPUT_DUST;
17067
+ }
17068
+ function resolveMode(opts) {
17069
+ return opts.mode ?? "funded";
17070
+ }
17071
+ function resolveNetworkName(opts) {
17072
+ if (opts.networkName) return opts.networkName;
17073
+ const { bech32 } = opts.wallet.network;
17074
+ if (bech32 === "bc") return "bitcoin";
17075
+ if (bech32 === "bcrt") return "regtest";
17076
+ return "testnet";
17077
+ }
17078
+ async function resolveFeeRate(opts) {
17079
+ if (opts.feeRate) return Math.ceil(opts.feeRate);
17080
+ const feeRate = await opts.wallet.onchainProvider.getFeeRate();
17081
+ if (!feeRate || feeRate < OnchainWallet.MIN_FEE_RATE) return OnchainWallet.MIN_FEE_RATE;
17082
+ return Math.ceil(feeRate);
17083
+ }
17084
+ async function selectExitVtxos(opts) {
17085
+ if (!opts.vtxos) return opts.wallet.getVtxos();
17086
+ const res = await opts.wallet.indexerProvider.getVtxos({ outpoints: opts.vtxos });
17087
+ const tapTrees = /* @__PURE__ */ new Map();
17088
+ const out = [];
17089
+ for (const vtxo of res.vtxos) {
17090
+ if (vtxo.isSpent) continue;
17091
+ let tapTree = tapTrees.get(vtxo.script);
17092
+ if (!tapTree) {
17093
+ const [contract] = await opts.wallet.contractRepository.getContracts({
17094
+ script: vtxo.script
17095
+ });
17096
+ if (!contract) {
17097
+ throw new Error(
17098
+ `no contract registered for vtxo script ${vtxo.script} \u2014 register the contract before exiting`
17099
+ );
17100
+ }
17101
+ const handler = chunk32YKLQPS_cjs.contractHandlers.get(contract.type);
17102
+ if (!handler) {
17103
+ throw new Error(`no contract handler registered for type '${contract.type}'`);
17104
+ }
17105
+ tapTree = handler.createScript(contract.params).encode();
17106
+ tapTrees.set(vtxo.script, tapTree);
17107
+ }
17108
+ out.push({ txid: vtxo.txid, vout: vtxo.vout, value: vtxo.value, tapTree });
17109
+ }
17110
+ return out;
17111
+ }
17112
+ async function computeExitLayout(opts, feeRate) {
17113
+ const { wallet, onchainWallet } = opts;
17114
+ const vtxos = await selectExitVtxos(opts);
17115
+ if (vtxos.length === 0) throw new Error("no vtxos to exit");
17116
+ const dag = await buildExitDag({
17117
+ vtxos,
17118
+ indexer: wallet.indexerProvider,
17119
+ onchain: wallet.onchainProvider
17120
+ });
17121
+ const pendingNodes = dag.filter((n) => !n.confirmed);
17122
+ const psbts = /* @__PURE__ */ new Map();
17123
+ if (pendingNodes.length > 0) {
17124
+ const txids = pendingNodes.map((n) => n.txid);
17125
+ let pageIndex = 0;
17126
+ let hasMore = true;
17127
+ while (hasMore) {
17128
+ const { txs, page } = await wallet.indexerProvider.getVirtualTxs(txids, {
17129
+ pageIndex,
17130
+ pageSize: chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE
17131
+ });
17132
+ for (const psbt of txs) {
17133
+ psbts.set(chunkUBYY2TPK_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
17134
+ }
17135
+ hasMore = page ? txs.length === chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE : false;
17136
+ pageIndex++;
17137
+ }
17138
+ }
17139
+ const childVsize = Number(
17140
+ TxWeightEstimator.create().addP2AInput().addKeySpendInput(true).addOutputAddress(onchainWallet.address, wallet.network).vsize().value
17141
+ );
17142
+ const rawSteps = pendingNodes.map((node) => {
17143
+ const psbt = psbts.get(node.txid);
17144
+ if (!psbt) {
17145
+ throw new Error(`indexer did not return virtual tx ${node.txid}`);
17146
+ }
17147
+ const parent = finalizeVirtualTx(node.type, psbt);
17148
+ const stepFee = Math.ceil(feeRate * (parent.vsize + childVsize));
17149
+ return { node, parent, stepFee, funding: stepFundingAmount(stepFee) };
17150
+ });
17151
+ const parentInputTxids = (tx) => {
17152
+ const ids = [];
17153
+ for (let i = 0; i < tx.inputsLength; i++) {
17154
+ const txid = tx.getInput(i).txid;
17155
+ if (txid) ids.push(base.hex.encode(txid));
17156
+ }
17157
+ return ids;
17158
+ };
17159
+ const steps = topoSortByDeps(
17160
+ rawSteps,
17161
+ (s) => s.parent.id,
17162
+ (s) => parentInputTxids(s.parent)
17163
+ );
17164
+ const walletPubKeyHex = base.hex.encode(await wallet.identity.xOnlyPublicKey());
17165
+ const infos = [];
17166
+ const sweeps = [];
17167
+ for (const vtxo of vtxos) {
17168
+ const outpoint = `${vtxo.txid}:${vtxo.vout}`;
17169
+ try {
17170
+ const resolved = await resolveUnilateralPath({
17171
+ vtxo,
17172
+ scriptHex: base.hex.encode(chunkHXDZ2QTW_cjs.VtxoScript.decode(vtxo.tapTree).pkScript),
17173
+ contractRepository: wallet.contractRepository,
17174
+ walletPubKeyHex,
17175
+ currentTime: Date.now()
17176
+ });
17177
+ const sweepFee = sweepFeeFor(
17178
+ resolved.selection,
17179
+ opts.sweepAddress,
17180
+ wallet.network,
17181
+ feeRate
17182
+ );
17183
+ if (vtxo.value - sweepFee < CHILD_OUTPUT_DUST) {
17184
+ infos.push({
17185
+ outpoint,
17186
+ value: vtxo.value,
17187
+ skipped: `uneconomic: value ${vtxo.value} <= sweep fee + dust`
17188
+ });
17189
+ continue;
17190
+ }
17191
+ const t = chunkHXDZ2QTW_cjs.sequenceToTimelock(resolved.selection.sequence);
17192
+ const delay = { type: t.type, value: Number(t.value) };
17193
+ infos.push({ outpoint, value: vtxo.value, sweepFee, path: resolved.label, delay });
17194
+ sweeps.push({ vtxo, resolved, sweepFee, delay });
17195
+ } catch (e) {
17196
+ if (e instanceof ExitPathError) {
17197
+ infos.push({ outpoint, value: vtxo.value, skipped: e.message });
17198
+ continue;
17199
+ }
17200
+ throw e;
17201
+ }
17202
+ }
17203
+ const coins = (await onchainWallet.getCoins()).filter((c) => c.status.confirmed);
17204
+ const balance = coins.reduce((sum, c) => sum + c.value, 0);
17205
+ const fundingTotal = steps.reduce((sum, s) => sum + s.funding, 0);
17206
+ const splitterFeeFor = (inputCount) => {
17207
+ if (steps.length === 0) return 0;
17208
+ const est = TxWeightEstimator.create();
17209
+ for (let i = 0; i < inputCount; i++) est.addKeySpendInput(true);
17210
+ for (let i = 0; i < steps.length + 1; i++) {
17211
+ est.addOutputAddress(onchainWallet.address, wallet.network);
17212
+ }
17213
+ return Number(est.vsize().fee(BigInt(feeRate)));
17214
+ };
17215
+ const graph = resolveMode(opts) === "graph";
17216
+ let splitterFee = 0;
17217
+ if (!graph) {
17218
+ splitterFee = splitterFeeFor(Math.max(1, coins.length));
17219
+ if (steps.length > 0 && balance < fundingTotal + splitterFee) {
17220
+ splitterFee = splitterFeeFor(coins.length + 1);
17221
+ }
17222
+ }
17223
+ const stepFees = steps.reduce((s, x) => s + x.stepFee, 0);
17224
+ const sweepFees = sweeps.reduce((s, x) => s + x.sweepFee, 0);
17225
+ const totals = {
17226
+ // graph: each unroll step is parent + a live-built child (2 txs), no
17227
+ // splitter. funded: + 1 splitter tx and pre-signed children.
17228
+ txCount: (graph ? 0 : steps.length > 0 ? 1 : 0) + steps.length * 2 + sweeps.length,
17229
+ totalFeeSats: splitterFee + stepFees + sweepFees,
17230
+ // graph funding is what the executor sends to its own fee address:
17231
+ // just the CPFP fees (change recycles); funded also locks the
17232
+ // per-child dust into the splitter.
17233
+ fundingRequiredSats: graph ? stepFees : splitterFee + fundingTotal,
17234
+ recoveredSats: sweeps.reduce((s, x) => s + (x.vtxo.value - x.sweepFee), 0)
17235
+ };
17236
+ const expiries = pendingNodes.map((n) => n.expiresAt).filter((x) => x !== void 0);
17237
+ const validUntil = expiries.length > 0 ? Math.min(...expiries) : void 0;
17238
+ return {
17239
+ vtxos,
17240
+ dag,
17241
+ steps,
17242
+ sweeps,
17243
+ infos,
17244
+ totals,
17245
+ splitterFee,
17246
+ validUntil,
17247
+ balance,
17248
+ coins
17249
+ };
17250
+ }
17251
+ async function estimate(opts) {
17252
+ const feeRate = await resolveFeeRate(opts);
17253
+ const layout = await computeExitLayout(opts, feeRate);
17254
+ if (resolveMode(opts) === "graph") {
17255
+ return {
17256
+ feeRate,
17257
+ fundingAddress: "",
17258
+ currentBalanceSats: 0,
17259
+ shortfallSats: layout.totals.fundingRequiredSats,
17260
+ validUntil: layout.validUntil,
17261
+ totals: layout.totals,
17262
+ vtxos: layout.infos
17263
+ };
17264
+ }
17265
+ return {
17266
+ feeRate,
17267
+ fundingAddress: opts.onchainWallet.address,
17268
+ currentBalanceSats: layout.balance,
17269
+ shortfallSats: Math.max(0, layout.totals.fundingRequiredSats - layout.balance),
17270
+ validUntil: layout.validUntil,
17271
+ totals: layout.totals,
17272
+ vtxos: layout.infos
17273
+ };
17274
+ }
17275
+
17276
+ // src/wallet/exit/executor.ts
17277
+ var Executor = class {
17278
+ constructor(pkg, provider, opts) {
17279
+ this.pkg = pkg;
17280
+ this.provider = provider;
17281
+ this.pollIntervalMs = opts?.pollIntervalMs ?? 5e3;
17282
+ this.feeWallet = opts?.feeWallet;
17283
+ }
17284
+ pollIntervalMs;
17285
+ feeWallet;
17286
+ sleep() {
17287
+ return new Promise((r) => setTimeout(r, this.pollIntervalMs));
17288
+ }
17289
+ async status(txid) {
17290
+ try {
17291
+ return await this.provider.getTxStatus(txid);
17292
+ } catch {
17293
+ return void 0;
17294
+ }
17295
+ }
17296
+ async waitConfirmed(txid) {
17297
+ for (; ; ) {
17298
+ const s = await this.status(txid);
17299
+ if (s?.confirmed) return s;
17300
+ await this.sleep();
17301
+ }
17302
+ }
17303
+ async *[Symbol.asyncIterator]() {
17304
+ const dead = /* @__PURE__ */ new Set();
17305
+ if (this.pkg.validUntil && Date.now() / 1e3 > this.pkg.validUntil) {
17306
+ yield {
17307
+ stepIndex: -1,
17308
+ kind: "broadcast",
17309
+ status: "warning",
17310
+ reason: `package validUntil ${this.pkg.validUntil} has passed; the operator may have swept \u2014 attempting anyway`
17311
+ };
17312
+ }
17313
+ const sweeps = [];
17314
+ for (let i = 0; i < this.pkg.steps.length; i++) {
17315
+ const step = this.pkg.steps[i];
17316
+ if (step.kind === "sweep") {
17317
+ sweeps.push({ index: i, step });
17318
+ continue;
17319
+ }
17320
+ const forVtxos = step.kind === "package" || step.kind === "bump" ? step.forVtxos : void 0;
17321
+ if (forVtxos && forVtxos.every((v) => dead.has(v))) {
17322
+ yield {
17323
+ stepIndex: i,
17324
+ kind: step.kind,
17325
+ status: "skipped",
17326
+ forVtxos,
17327
+ reason: "branch failed earlier"
17328
+ };
17329
+ continue;
17330
+ }
17331
+ const anchorTxid = step.kind === "package" || step.kind === "bump" ? step.parentTxid : step.txid;
17332
+ const existing = await this.status(anchorTxid);
17333
+ if (existing?.confirmed) {
17334
+ yield {
17335
+ stepIndex: i,
17336
+ kind: step.kind,
17337
+ status: "skipped",
17338
+ txid: anchorTxid,
17339
+ forVtxos
17340
+ };
17341
+ continue;
17342
+ }
17343
+ if (!existing) {
17344
+ try {
17345
+ if (step.kind === "package") {
17346
+ await this.provider.broadcastTransaction(step.parentHex, step.childHex);
17347
+ } else if (step.kind === "bump") {
17348
+ if (!this.feeWallet) {
17349
+ throw new Error(
17350
+ "graph package requires a fee wallet (opts.feeWallet) to fund CPFP bumps"
17351
+ );
17352
+ }
17353
+ const [parentHex, childHex] = await this.feeWallet.bumpAnchor(
17354
+ step.parentHex,
17355
+ this.pkg.feeRate
17356
+ );
17357
+ await this.provider.broadcastTransaction(parentHex, childHex);
17358
+ } else {
17359
+ await this.provider.broadcastTransaction(step.hex);
17360
+ }
17361
+ yield {
17362
+ stepIndex: i,
17363
+ kind: step.kind,
17364
+ status: "broadcast",
17365
+ txid: anchorTxid,
17366
+ forVtxos
17367
+ };
17368
+ } catch (e) {
17369
+ const reason = e instanceof Error ? e.message : String(e);
17370
+ if (step.kind === "broadcast") {
17371
+ for (const s of this.pkg.steps) {
17372
+ if (s.kind === "package") s.forVtxos.forEach((v) => dead.add(v));
17373
+ }
17374
+ } else if (step.kind === "package" || step.kind === "bump") {
17375
+ step.forVtxos.forEach((v) => dead.add(v));
17376
+ }
17377
+ yield {
17378
+ stepIndex: i,
17379
+ kind: step.kind,
17380
+ status: "failed",
17381
+ txid: anchorTxid,
17382
+ forVtxos,
17383
+ reason
17384
+ };
17385
+ continue;
17386
+ }
17387
+ }
17388
+ await this.waitConfirmed(anchorTxid);
17389
+ yield {
17390
+ stepIndex: i,
17391
+ kind: step.kind,
17392
+ status: "confirmed",
17393
+ txid: anchorTxid,
17394
+ forVtxos
17395
+ };
17396
+ }
17397
+ for (const { index, step } of sweeps) {
17398
+ if (dead.has(step.vtxo)) {
17399
+ yield {
17400
+ stepIndex: index,
17401
+ kind: "sweep",
17402
+ status: "failed",
17403
+ txid: step.txid,
17404
+ forVtxos: [step.vtxo],
17405
+ reason: "branch failed earlier"
17406
+ };
17407
+ }
17408
+ }
17409
+ const pending = sweeps.filter(({ step }) => !dead.has(step.vtxo));
17410
+ const waitingAnnounced = /* @__PURE__ */ new Set();
17411
+ const done = /* @__PURE__ */ new Set();
17412
+ while (done.size < pending.length) {
17413
+ for (const { index, step } of pending) {
17414
+ if (done.has(index)) continue;
17415
+ const swept = await this.status(step.txid);
17416
+ if (swept?.confirmed) {
17417
+ done.add(index);
17418
+ yield {
17419
+ stepIndex: index,
17420
+ kind: "sweep",
17421
+ status: "confirmed",
17422
+ txid: step.txid,
17423
+ forVtxos: [step.vtxo]
17424
+ };
17425
+ continue;
17426
+ }
17427
+ if (swept) continue;
17428
+ const dep = await this.status(step.dependsOnTxid);
17429
+ if (!dep?.confirmed) continue;
17430
+ const tip = await this.provider.getChainTip();
17431
+ const mature = step.delay.type === "blocks" ? tip.height >= (dep.blockHeight ?? 0) + step.delay.value : tip.time >= (dep.blockTime ?? 0) + step.delay.value;
17432
+ if (!mature) {
17433
+ if (!waitingAnnounced.has(index)) {
17434
+ waitingAnnounced.add(index);
17435
+ yield {
17436
+ stepIndex: index,
17437
+ kind: "sweep",
17438
+ status: "waiting_csv",
17439
+ txid: step.txid,
17440
+ forVtxos: [step.vtxo],
17441
+ ...step.delay.type === "blocks" ? { maturesAtHeight: (dep.blockHeight ?? 0) + step.delay.value } : { maturesAtTime: (dep.blockTime ?? 0) + step.delay.value }
17442
+ };
17443
+ }
17444
+ continue;
17445
+ }
17446
+ try {
17447
+ await this.provider.broadcastTransaction(step.hex);
17448
+ yield {
17449
+ stepIndex: index,
17450
+ kind: "sweep",
17451
+ status: "broadcast",
17452
+ txid: step.txid,
17453
+ forVtxos: [step.vtxo]
17454
+ };
17455
+ } catch (e) {
17456
+ const reason = e instanceof Error ? e.message : String(e);
17457
+ if (/non-?bip68|non-?final|premature/i.test(reason)) {
17458
+ continue;
17459
+ }
17460
+ done.add(index);
17461
+ yield {
17462
+ stepIndex: index,
17463
+ kind: "sweep",
17464
+ status: "failed",
17465
+ txid: step.txid,
17466
+ forVtxos: [step.vtxo],
17467
+ reason
17468
+ };
17469
+ }
17470
+ }
17471
+ if (done.size < pending.length) await this.sleep();
17472
+ }
17473
+ }
17474
+ };
17475
+ async function prepare(opts) {
17476
+ const { wallet, onchainWallet } = opts;
17477
+ const feeRate = await resolveFeeRate(opts);
17478
+ const mode = resolveMode(opts);
17479
+ if (mode === "funded") {
17480
+ const walletKey = await wallet.identity.xOnlyPublicKey();
17481
+ if (base.hex.encode(onchainWallet.onchainP2TR.tapInternalKey) !== base.hex.encode(walletKey)) {
17482
+ throw new Error("onchainWallet must share the wallet identity");
17483
+ }
17484
+ }
17485
+ const layout = await computeExitLayout(opts, feeRate);
17486
+ const sweepSteps = [];
17487
+ const activeOutpoints = /* @__PURE__ */ new Set();
17488
+ for (const sweep of layout.sweeps) {
17489
+ const outpoint = `${sweep.vtxo.txid}:${sweep.vtxo.vout}`;
17490
+ try {
17491
+ const { tx } = await buildSignedSweep({
17492
+ vtxo: {
17493
+ txid: sweep.vtxo.txid,
17494
+ vout: sweep.vtxo.vout,
17495
+ value: sweep.vtxo.value,
17496
+ pkScript: chunkHXDZ2QTW_cjs.VtxoScript.decode(sweep.vtxo.tapTree).pkScript
17497
+ },
17498
+ path: sweep.resolved.selection,
17499
+ outputAddress: opts.sweepAddress,
17500
+ feeRate,
17501
+ network: wallet.network,
17502
+ identity: wallet.identity
17503
+ });
17504
+ activeOutpoints.add(outpoint);
17505
+ sweepSteps.push({
17506
+ kind: "sweep",
17507
+ vtxo: outpoint,
17508
+ txid: tx.id,
17509
+ hex: tx.hex,
17510
+ dependsOnTxid: sweep.vtxo.txid,
17511
+ delay: sweep.delay
17512
+ });
17513
+ } catch (e) {
17514
+ const info = layout.infos.find((i) => i.outpoint === outpoint);
17515
+ if (info) {
17516
+ info.skipped = e instanceof Error ? e.message : String(e);
17517
+ delete info.sweepFee;
17518
+ delete info.path;
17519
+ delete info.delay;
17520
+ }
17521
+ }
17522
+ }
17523
+ const steps = layout.steps.filter((s) => s.node.forVtxos.some((v) => activeOutpoints.has(v)));
17524
+ if (steps.length === 0 && sweepSteps.length === 0) {
17525
+ throw new Error("no exitable vtxos (all skipped)");
17526
+ }
17527
+ if (mode === "graph") {
17528
+ const bumpSteps = steps.map((step) => ({
17529
+ kind: "bump",
17530
+ parentTxid: step.parent.id,
17531
+ parentHex: step.parent.hex,
17532
+ forVtxos: step.node.forVtxos.filter((v) => activeOutpoints.has(v))
17533
+ }));
17534
+ const stepFees2 = steps.reduce((s, x) => s + x.stepFee, 0);
17535
+ const activeInfos2 = layout.infos.filter((i) => !i.skipped);
17536
+ const sweepFees2 = activeInfos2.reduce((s, i) => s + (i.sweepFee ?? 0), 0);
17537
+ const recovered2 = activeInfos2.reduce((s, i) => s + (i.value ?? 0) - (i.sweepFee ?? 0), 0);
17538
+ return {
17539
+ version: 1,
17540
+ mode: "graph",
17541
+ network: resolveNetworkName(opts),
17542
+ createdAt: Math.floor(Date.now() / 1e3),
17543
+ validUntil: layout.validUntil,
17544
+ feeRate,
17545
+ sweepAddress: opts.sweepAddress,
17546
+ totals: {
17547
+ txCount: bumpSteps.length * 2 + sweepSteps.length,
17548
+ totalFeeSats: stepFees2 + sweepFees2,
17549
+ fundingRequiredSats: stepFees2,
17550
+ recoveredSats: recovered2
17551
+ },
17552
+ vtxos: layout.infos,
17553
+ steps: [...bumpSteps, ...sweepSteps]
17554
+ };
17555
+ }
17556
+ const packageSteps = [];
17557
+ let broadcastStep;
17558
+ let splitterFee = 0;
17559
+ if (steps.length > 0) {
17560
+ const fundingTotal = steps.reduce((sum, s) => sum + s.funding, 0);
17561
+ let selected = { inputs: [], changeAmount: 0n };
17562
+ for (let i = 0; i < 10; i++) {
17563
+ const target = fundingTotal + splitterFee;
17564
+ try {
17565
+ selected = selectCoins(layout.coins, target);
17566
+ } catch {
17567
+ throw new Error(
17568
+ `insufficient confirmed onchain funds: need ${target} sats, have ${layout.balance} (deposit the shortfall to ${onchainWallet.address})`
17569
+ );
17570
+ }
17571
+ const est = TxWeightEstimator.create();
17572
+ for (const _ of selected.inputs) est.addKeySpendInput(true);
17573
+ for (const _ of steps) est.addOutputAddress(onchainWallet.address, wallet.network);
17574
+ if (selected.changeAmount >= BigInt(DUST_AMOUNT)) {
17575
+ est.addOutputAddress(onchainWallet.address, wallet.network);
17576
+ }
17577
+ const newFee = Number(est.vsize().fee(BigInt(feeRate)));
17578
+ if (newFee <= splitterFee) break;
17579
+ splitterFee = newFee;
17580
+ }
17581
+ const splitter = new chunkUBYY2TPK_cjs.Transaction({ version: 2 });
17582
+ for (const coin of selected.inputs) {
17583
+ splitter.addInput({
17584
+ txid: coin.txid,
17585
+ index: coin.vout,
17586
+ witnessUtxo: {
17587
+ script: onchainWallet.onchainP2TR.script,
17588
+ amount: BigInt(coin.value)
17589
+ },
17590
+ tapInternalKey: onchainWallet.onchainP2TR.tapInternalKey
17591
+ });
17592
+ }
17593
+ for (const step of steps) {
17594
+ splitter.addOutputAddress(onchainWallet.address, BigInt(step.funding), wallet.network);
17595
+ }
17596
+ const inputSum = selected.inputs.reduce((s, c) => s + c.value, 0);
17597
+ const change = BigInt(inputSum - fundingTotal - splitterFee);
17598
+ if (change < 0n) {
17599
+ throw new Error(
17600
+ `insufficient confirmed onchain funds for the splitter fee: need ${fundingTotal + splitterFee} sats, have ${inputSum} (deposit the shortfall to ${onchainWallet.address})`
17601
+ );
17602
+ }
17603
+ if (change >= BigInt(DUST_AMOUNT)) {
17604
+ splitter.addOutputAddress(onchainWallet.address, change, wallet.network);
17605
+ } else if (change > 0n) {
17606
+ splitterFee += Number(change);
17607
+ }
17608
+ const signedSplitter = await wallet.identity.sign(splitter);
17609
+ signedSplitter.finalize();
17610
+ for (let k = 0; k < steps.length; k++) {
17611
+ const step = steps[k];
17612
+ const { child } = buildAnchorChild({
17613
+ parent: step.parent,
17614
+ feeRate,
17615
+ fundingCoins: [{ txid: signedSplitter.id, vout: k, value: step.funding }],
17616
+ changeAddress: onchainWallet.address,
17617
+ changeScript: onchainWallet.onchainP2TR.script,
17618
+ tapInternalKey: onchainWallet.onchainP2TR.tapInternalKey,
17619
+ network: wallet.network
17620
+ });
17621
+ const signedChild = await wallet.identity.sign(child);
17622
+ for (let i = 1; i < signedChild.inputsLength; i++) {
17623
+ signedChild.finalizeIdx(i);
17624
+ }
17625
+ packageSteps.push({
17626
+ kind: "package",
17627
+ parentTxid: step.parent.id,
17628
+ parentHex: step.parent.hex,
17629
+ childTxid: signedChild.id,
17630
+ childHex: signedChild.hex,
17631
+ forVtxos: step.node.forVtxos.filter((v) => activeOutpoints.has(v))
17632
+ });
17633
+ }
17634
+ broadcastStep = { kind: "broadcast", txid: signedSplitter.id, hex: signedSplitter.hex };
17635
+ await onchainWallet.provider.broadcastTransaction(signedSplitter.hex);
17636
+ }
17637
+ const stepFees = steps.reduce((s, x) => s + x.stepFee, 0);
17638
+ const activeInfos = layout.infos.filter((i) => !i.skipped);
17639
+ const sweepFees = activeInfos.reduce((s, i) => s + (i.sweepFee ?? 0), 0);
17640
+ const recovered = activeInfos.reduce((s, i) => s + (i.value ?? 0) - (i.sweepFee ?? 0), 0);
17641
+ const fundingRequired = splitterFee + steps.reduce((s, x) => s + x.funding, 0);
17642
+ return {
17643
+ version: 1,
17644
+ mode: "funded",
17645
+ network: resolveNetworkName(opts),
17646
+ createdAt: Math.floor(Date.now() / 1e3),
17647
+ validUntil: layout.validUntil,
17648
+ feeRate,
17649
+ sweepAddress: opts.sweepAddress,
17650
+ totals: {
17651
+ txCount: (broadcastStep ? 1 : 0) + packageSteps.length * 2 + sweepSteps.length,
17652
+ totalFeeSats: splitterFee + stepFees + sweepFees,
17653
+ fundingRequiredSats: fundingRequired,
17654
+ recoveredSats: recovered
17655
+ },
17656
+ vtxos: layout.infos,
17657
+ steps: [...broadcastStep ? [broadcastStep] : [], ...packageSteps, ...sweepSteps]
17658
+ };
17659
+ }
17660
+
17661
+ // src/wallet/exit/types.ts
17662
+ function serializeExitPackage(pkg) {
17663
+ return JSON.stringify(pkg);
17664
+ }
17665
+ function deserializeExitPackage(json) {
17666
+ const data = JSON.parse(json);
17667
+ if (data?.version !== 1) {
17668
+ throw new Error(`unsupported exit package version: ${data?.version}`);
17669
+ }
17670
+ if (typeof data.network !== "string" || typeof data.sweepAddress !== "string") {
17671
+ throw new Error("invalid exit package: missing network or sweepAddress");
17672
+ }
17673
+ if (typeof data.feeRate !== "number" || typeof data.createdAt !== "number") {
17674
+ throw new Error("invalid exit package: missing feeRate or createdAt");
17675
+ }
17676
+ if (!Array.isArray(data.steps) || !Array.isArray(data.vtxos)) {
17677
+ throw new Error("invalid exit package: steps and vtxos must be arrays");
17678
+ }
17679
+ if (!isValidTotals(data.totals)) {
17680
+ throw new Error("invalid exit package: malformed totals");
17681
+ }
17682
+ for (const step of data.steps) {
17683
+ if (!isValidStep(step)) {
17684
+ throw new Error(`invalid step: ${JSON.stringify(step)}`);
17685
+ }
17686
+ }
17687
+ return data;
17688
+ }
17689
+ function isValidDelay(d) {
17690
+ const delay = d;
17691
+ return !!delay && (delay.type === "blocks" || delay.type === "seconds") && typeof delay.value === "number";
17692
+ }
17693
+ function isValidTotals(t) {
17694
+ const totals = t;
17695
+ return !!totals && typeof totals === "object" && typeof totals.txCount === "number" && typeof totals.totalFeeSats === "number" && typeof totals.fundingRequiredSats === "number" && typeof totals.recoveredSats === "number";
17696
+ }
17697
+ function isValidStep(step) {
17698
+ const s = step;
17699
+ if (!s || typeof s !== "object") return false;
17700
+ switch (s.kind) {
17701
+ case "broadcast":
17702
+ return typeof s.txid === "string" && typeof s.hex === "string";
17703
+ case "package":
17704
+ return typeof s.parentTxid === "string" && typeof s.parentHex === "string" && typeof s.childTxid === "string" && typeof s.childHex === "string" && Array.isArray(s.forVtxos);
17705
+ case "bump":
17706
+ return typeof s.parentTxid === "string" && typeof s.parentHex === "string" && Array.isArray(s.forVtxos);
17707
+ case "sweep":
17708
+ return typeof s.vtxo === "string" && typeof s.txid === "string" && typeof s.hex === "string" && typeof s.dependsOnTxid === "string" && isValidDelay(s.delay);
17709
+ default:
17710
+ return false;
17711
+ }
17712
+ }
17713
+
17714
+ // src/wallet/exit/index.ts
17715
+ var UnilateralExit = {
17716
+ estimate,
17717
+ prepare,
17718
+ Executor
17719
+ };
16813
17720
  var ARKCONTRACT_PREFIX = "arkcontract";
16814
17721
  function encodeArkContract(contract) {
16815
17722
  const params = new URLSearchParams();
@@ -16926,6 +17833,7 @@ exports.SingleKey = SingleKey;
16926
17833
  exports.TxTree = TxTree;
16927
17834
  exports.TxType = TxType;
16928
17835
  exports.TxWeightEstimator = TxWeightEstimator;
17836
+ exports.UnilateralExit = UnilateralExit;
16929
17837
  exports.VtxoManager = VtxoManager;
16930
17838
  exports.Wallet = Wallet2;
16931
17839
  exports.WalletMessageHandler = WalletMessageHandler;
@@ -16945,6 +17853,7 @@ exports.contractFromArkContractWithAddress = contractFromArkContractWithAddress;
16945
17853
  exports.createDefaultActivityRegistry = createDefaultActivityRegistry;
16946
17854
  exports.decodeArkContract = decodeArkContract;
16947
17855
  exports.deserializeAssets = deserializeAssets;
17856
+ exports.deserializeExitPackage = deserializeExitPackage;
16948
17857
  exports.deserializeUtxo = deserializeUtxo;
16949
17858
  exports.deserializeVtxo = deserializeVtxo;
16950
17859
  exports.encodeArkContract = encodeArkContract;
@@ -16974,6 +17883,7 @@ exports.rollbackMigration = rollbackMigration;
16974
17883
  exports.saveVtxosForContract = saveVtxosForContract;
16975
17884
  exports.scriptFromArkAddress = scriptFromArkAddress;
16976
17885
  exports.serializeAssets = serializeAssets;
17886
+ exports.serializeExitPackage = serializeExitPackage;
16977
17887
  exports.serializeUtxo = serializeUtxo;
16978
17888
  exports.serializeVtxo = serializeVtxo;
16979
17889
  exports.setupServiceWorker = setupServiceWorker;
@@ -16984,5 +17894,5 @@ exports.validateVtxoTxGraph = validateVtxoTxGraph;
16984
17894
  exports.verifyTapscriptSignatures = verifyTapscriptSignatures;
16985
17895
  exports.waitForIncomingFunds = waitForIncomingFunds;
16986
17896
  exports.warnAndFilterVtxosForScript = warnAndFilterVtxosForScript;
16987
- //# sourceMappingURL=chunk-QGNTDGMN.cjs.map
16988
- //# sourceMappingURL=chunk-QGNTDGMN.cjs.map
17897
+ //# sourceMappingURL=chunk-XIVCG6EP.cjs.map
17898
+ //# sourceMappingURL=chunk-XIVCG6EP.cjs.map