@arkade-os/sdk 0.4.32 → 0.4.34
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 +1 -1
- package/dist/adapters/expo.cjs +5 -5
- package/dist/adapters/expo.d.cts +2 -2
- package/dist/adapters/expo.d.ts +2 -2
- package/dist/adapters/expo.js +3 -3
- package/dist/adapters/indexedDB.cjs +5 -5
- package/dist/adapters/indexedDB.js +4 -4
- package/dist/{ark-ibLW4Hte.d.cts → ark-Dsv5Jq4E.d.cts} +81 -10
- package/dist/{ark-ibLW4Hte.d.ts → ark-Dsv5Jq4E.d.ts} +81 -10
- package/dist/{asyncStorageTaskQueue-BEOFPNc0.d.ts → asyncStorageTaskQueue-BH-zuth5.d.ts} +1 -1
- package/dist/{asyncStorageTaskQueue-VGHXWR9F.d.cts → asyncStorageTaskQueue-D92ch8yI.d.cts} +1 -1
- package/dist/{chunk-ABWRLTX5.js → chunk-5WDBHWX3.js} +4 -4
- package/dist/{chunk-ABWRLTX5.js.map → chunk-5WDBHWX3.js.map} +1 -1
- package/dist/{chunk-GIGILVVP.cjs → chunk-CCLNFHJ5.cjs} +11 -11
- package/dist/{chunk-GIGILVVP.cjs.map → chunk-CCLNFHJ5.cjs.map} +1 -1
- package/dist/{chunk-WMIPYZSB.cjs → chunk-CMPJR3HS.cjs} +42 -9
- package/dist/chunk-CMPJR3HS.cjs.map +1 -0
- package/dist/{chunk-YA4G7RFB.js → chunk-CUSABEUQ.js} +166 -38
- package/dist/chunk-CUSABEUQ.js.map +1 -0
- package/dist/{chunk-6FLL2Q36.cjs → chunk-FSAXPBGP.cjs} +9 -9
- package/dist/chunk-FSAXPBGP.cjs.map +1 -0
- package/dist/{chunk-6NWNOLL3.js → chunk-FXFBPXV3.js} +4 -4
- package/dist/chunk-FXFBPXV3.js.map +1 -0
- package/dist/{chunk-IEO3XDKI.cjs → chunk-GUTKJMSF.cjs} +190 -58
- package/dist/chunk-GUTKJMSF.cjs.map +1 -0
- package/dist/{chunk-XROGFOPX.js → chunk-HFXEUW55.js} +740 -175
- package/dist/chunk-HFXEUW55.js.map +1 -0
- package/dist/{chunk-TU3LVAPX.js → chunk-OUVTG72A.js} +43 -11
- package/dist/chunk-OUVTG72A.js.map +1 -0
- package/dist/{chunk-SHEBNWOQ.js → chunk-VVGD3JIP.js} +3 -3
- package/dist/{chunk-SHEBNWOQ.js.map → chunk-VVGD3JIP.js.map} +1 -1
- package/dist/{chunk-KQK4PP6L.cjs → chunk-XCHBQVMK.cjs} +879 -314
- package/dist/chunk-XCHBQVMK.cjs.map +1 -0
- package/dist/{chunk-I2UIKZM5.cjs → chunk-ZS3OZHC7.cjs} +7 -7
- package/dist/{chunk-I2UIKZM5.cjs.map → chunk-ZS3OZHC7.cjs.map} +1 -1
- package/dist/contracts/handlers/index.cjs +10 -6
- package/dist/contracts/handlers/index.d.cts +3 -3
- package/dist/contracts/handlers/index.d.ts +3 -3
- package/dist/contracts/handlers/index.js +2 -2
- package/dist/{delegate-BvNTw44a.d.cts → delegate-BaS5SCIW.d.cts} +10 -2
- package/dist/{delegate-BXaR1RNG.d.ts → delegate-Baz_hb83.d.ts} +10 -2
- package/dist/{index-BusKawmy.d.ts → index-FwXZveaX.d.ts} +63 -3
- package/dist/{index-C-5Tw7VA.d.cts → index-lNZ6qaO3.d.cts} +63 -3
- package/dist/index.cjs +143 -127
- package/dist/index.d.cts +89 -16
- package/dist/index.d.ts +89 -16
- package/dist/index.js +4 -4
- package/dist/repositories/realm/index.cjs +13 -13
- package/dist/repositories/realm/index.d.cts +1 -1
- package/dist/repositories/realm/index.d.ts +1 -1
- package/dist/repositories/realm/index.js +4 -4
- package/dist/repositories/sqlite/index.cjs +13 -13
- package/dist/repositories/sqlite/index.d.cts +1 -1
- package/dist/repositories/sqlite/index.d.ts +1 -1
- package/dist/repositories/sqlite/index.js +4 -4
- package/dist/{taskRunner-B1igKGAo.d.ts → taskRunner-B1NUWyWR.d.ts} +1 -1
- package/dist/{taskRunner-By92TQ1m.d.cts → taskRunner-vFRA3F9b.d.cts} +1 -1
- package/dist/wallet/expo/background.cjs +14 -14
- package/dist/wallet/expo/background.d.cts +3 -3
- package/dist/wallet/expo/background.d.ts +3 -3
- package/dist/wallet/expo/background.js +6 -6
- package/dist/wallet/expo/index.cjs +14 -14
- package/dist/wallet/expo/index.cjs.map +1 -1
- package/dist/wallet/expo/index.d.cts +5 -5
- package/dist/wallet/expo/index.d.ts +5 -5
- package/dist/wallet/expo/index.js +6 -6
- package/dist/wallet/expo/index.js.map +1 -1
- package/dist/{wallet-B_rxgQTu.d.cts → wallet-By9HIo0Q.d.cts} +160 -5
- package/dist/{wallet-CyM4F7Bs.d.ts → wallet-D6uoBLmS.d.ts} +160 -5
- package/dist/worker/expo/index.cjs +9 -9
- package/dist/worker/expo/index.d.cts +4 -4
- package/dist/worker/expo/index.d.ts +4 -4
- package/dist/worker/expo/index.js +5 -5
- package/package.json +4 -4
- package/dist/chunk-6FLL2Q36.cjs.map +0 -1
- package/dist/chunk-6NWNOLL3.js.map +0 -1
- package/dist/chunk-IEO3XDKI.cjs.map +0 -1
- package/dist/chunk-KQK4PP6L.cjs.map +0 -1
- package/dist/chunk-TU3LVAPX.js.map +0 -1
- package/dist/chunk-WMIPYZSB.cjs.map +0 -1
- package/dist/chunk-XROGFOPX.js.map +0 -1
- package/dist/chunk-YA4G7RFB.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
3
|
+
var chunkFSAXPBGP_cjs = require('./chunk-FSAXPBGP.cjs');
|
|
4
|
+
var chunkGUTKJMSF_cjs = require('./chunk-GUTKJMSF.cjs');
|
|
5
|
+
var chunkCMPJR3HS_cjs = require('./chunk-CMPJR3HS.cjs');
|
|
6
6
|
var utils_js = require('@scure/btc-signer/utils.js');
|
|
7
7
|
var btcSigner = require('@scure/btc-signer');
|
|
8
8
|
var base = require('@scure/base');
|
|
@@ -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 = chunkFSAXPBGP_cjs.getArkPsbtFields(tx.root, 0, chunkFSAXPBGP_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 = chunkFSAXPBGP_cjs.getArkPsbtFields(g.root, 0, chunkFSAXPBGP_cjs.CosignerPublicKey).map((c) => c.key);
|
|
237
237
|
const { finalKey } = aggregateKeys(cosigners, true, {
|
|
238
238
|
taprootTweak: this.scriptRoot
|
|
239
239
|
});
|
|
@@ -411,7 +411,7 @@ var SeedIdentity = class _SeedIdentity {
|
|
|
411
411
|
let network;
|
|
412
412
|
if ("descriptor" in opts && typeof opts.descriptor === "string") {
|
|
413
413
|
descriptor = opts.descriptor;
|
|
414
|
-
network =
|
|
414
|
+
network = chunkGUTKJMSF_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
|
|
415
415
|
} else {
|
|
416
416
|
network = opts.isMainnet ?? true ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
|
|
417
417
|
descriptor = descriptorsScure.scriptExpressions.trBIP32({
|
|
@@ -496,7 +496,7 @@ var SeedIdentity = class _SeedIdentity {
|
|
|
496
496
|
* `StaticDescriptorProvider` for legacy single-key wallets.
|
|
497
497
|
*/
|
|
498
498
|
isOurs(descriptor) {
|
|
499
|
-
return
|
|
499
|
+
return chunkGUTKJMSF_cjs.descriptorIsOurs(descriptor, this.descriptor, utils_js.pubSchnorr(this.derivedKey));
|
|
500
500
|
}
|
|
501
501
|
/**
|
|
502
502
|
* Signs each request with the key derived from its descriptor.
|
|
@@ -533,7 +533,7 @@ var SeedIdentity = class _SeedIdentity {
|
|
|
533
533
|
}
|
|
534
534
|
// ── internal helpers ─────────────────────────────────────────────
|
|
535
535
|
derivePrivateKeyForDescriptor(descriptor) {
|
|
536
|
-
const network =
|
|
536
|
+
const network = chunkGUTKJMSF_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
|
|
537
537
|
const expansion = descriptorsScure.expand({ descriptor, network });
|
|
538
538
|
if (expansion.isRanged) {
|
|
539
539
|
throw new Error(
|
|
@@ -619,7 +619,7 @@ var ReadonlyDescriptorIdentity = class _ReadonlyDescriptorIdentity {
|
|
|
619
619
|
*/
|
|
620
620
|
descriptor;
|
|
621
621
|
constructor(descriptor) {
|
|
622
|
-
const network =
|
|
622
|
+
const network = chunkGUTKJMSF_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
|
|
623
623
|
let expansion;
|
|
624
624
|
try {
|
|
625
625
|
expansion = descriptorsScure.expand({ descriptor, network, index: 0 });
|
|
@@ -669,7 +669,7 @@ var ReadonlyDescriptorIdentity = class _ReadonlyDescriptorIdentity {
|
|
|
669
669
|
* `StaticDescriptorProvider` for legacy single-key wallets.
|
|
670
670
|
*/
|
|
671
671
|
isOurs(descriptor) {
|
|
672
|
-
return
|
|
672
|
+
return chunkGUTKJMSF_cjs.descriptorIsOurs(descriptor, this.descriptor, this.indexZero.pubkey);
|
|
673
673
|
}
|
|
674
674
|
};
|
|
675
675
|
function serializeSeedOwnedSigningIdentity(identity) {
|
|
@@ -987,7 +987,7 @@ var RestDelegateProvider = class {
|
|
|
987
987
|
},
|
|
988
988
|
body: JSON.stringify({
|
|
989
989
|
intent: {
|
|
990
|
-
message:
|
|
990
|
+
message: chunkFSAXPBGP_cjs.Intent.encodeMessage(intent.message),
|
|
991
991
|
proof: intent.proof
|
|
992
992
|
},
|
|
993
993
|
forfeit_txs: forfeitTxs,
|
|
@@ -1031,10 +1031,10 @@ var ESPLORA_URL = {
|
|
|
1031
1031
|
testnet: "https://mempool.space/testnet/api",
|
|
1032
1032
|
signet: "https://mempool.signet.arkade.sh/api",
|
|
1033
1033
|
mutinynet: "https://mempool.mutinynet.arkade.sh/api",
|
|
1034
|
-
regtest: "http://localhost:3000"
|
|
1034
|
+
regtest: "http://localhost:3000/api"
|
|
1035
1035
|
};
|
|
1036
1036
|
var EsploraProvider = class {
|
|
1037
|
-
constructor(baseUrl = ESPLORA_URL[
|
|
1037
|
+
constructor(baseUrl = ESPLORA_URL[chunkCMPJR3HS_cjs.DEFAULT_NETWORK_NAME], opts) {
|
|
1038
1038
|
this.baseUrl = baseUrl;
|
|
1039
1039
|
this.pollingInterval = opts?.pollingInterval ?? 15e3;
|
|
1040
1040
|
this.forcePolling = opts?.forcePolling ?? false;
|
|
@@ -1050,6 +1050,9 @@ var EsploraProvider = class {
|
|
|
1050
1050
|
}
|
|
1051
1051
|
async getFeeRate() {
|
|
1052
1052
|
const response = await fetch(`${this.baseUrl}/fee-estimates`);
|
|
1053
|
+
if (response.status === 404) {
|
|
1054
|
+
return void 0;
|
|
1055
|
+
}
|
|
1053
1056
|
if (!response.ok) {
|
|
1054
1057
|
throw new Error(`Failed to fetch fee rate: ${response.statusText}`);
|
|
1055
1058
|
}
|
|
@@ -1175,7 +1178,7 @@ var EsploraProvider = class {
|
|
|
1175
1178
|
return stopFunc;
|
|
1176
1179
|
}
|
|
1177
1180
|
async getChainTip() {
|
|
1178
|
-
const tipBlocks = await fetch(`${this.baseUrl}/blocks
|
|
1181
|
+
const tipBlocks = await fetch(`${this.baseUrl}/blocks`);
|
|
1179
1182
|
if (!tipBlocks.ok) {
|
|
1180
1183
|
throw new Error(`Failed to get chain tip: ${tipBlocks.statusText}`);
|
|
1181
1184
|
}
|
|
@@ -1277,7 +1280,7 @@ function buildForfeitTx(inputs, forfeitPkScript, txLocktime) {
|
|
|
1277
1280
|
);
|
|
1278
1281
|
}
|
|
1279
1282
|
function buildForfeitTxWithOutput(inputs, output, txLocktime) {
|
|
1280
|
-
const tx = new
|
|
1283
|
+
const tx = new chunkFSAXPBGP_cjs.Transaction({
|
|
1281
1284
|
version: 3,
|
|
1282
1285
|
lockTime: txLocktime
|
|
1283
1286
|
});
|
|
@@ -1353,7 +1356,7 @@ function validateVtxoTxGraph(graph, roundTransaction, sweepTapTreeRoot) {
|
|
|
1353
1356
|
if (previousScriptKey.length !== 32) {
|
|
1354
1357
|
throw new Error(`parent output ${childIndex} has invalid script`);
|
|
1355
1358
|
}
|
|
1356
|
-
const cosigners =
|
|
1359
|
+
const cosigners = chunkFSAXPBGP_cjs.getArkPsbtFields(child.root, 0, chunkFSAXPBGP_cjs.CosignerPublicKey);
|
|
1357
1360
|
if (cosigners.length === 0) {
|
|
1358
1361
|
throw ErrMissingCosignersPublicKeys;
|
|
1359
1362
|
}
|
|
@@ -1453,7 +1456,7 @@ var Extension = class _Extension {
|
|
|
1453
1456
|
`expected magic prefix ${base.hex.encode(ARKADE_MAGIC)}, got ${base.hex.encode(payload.slice(0, Math.min(payload.length, ARKADE_MAGIC.length)))}`
|
|
1454
1457
|
);
|
|
1455
1458
|
}
|
|
1456
|
-
const reader = new
|
|
1459
|
+
const reader = new chunkFSAXPBGP_cjs.BufferReader(payload.slice(ARKADE_MAGIC.length));
|
|
1457
1460
|
const packets = [];
|
|
1458
1461
|
while (reader.remaining() > 0) {
|
|
1459
1462
|
const packetType = reader.readByte();
|
|
@@ -1527,7 +1530,7 @@ var Extension = class _Extension {
|
|
|
1527
1530
|
*/
|
|
1528
1531
|
getAssetPacket() {
|
|
1529
1532
|
for (const p of this.packets) {
|
|
1530
|
-
if (p instanceof
|
|
1533
|
+
if (p instanceof chunkFSAXPBGP_cjs.Packet) {
|
|
1531
1534
|
return p;
|
|
1532
1535
|
}
|
|
1533
1536
|
}
|
|
@@ -1535,8 +1538,8 @@ var Extension = class _Extension {
|
|
|
1535
1538
|
}
|
|
1536
1539
|
};
|
|
1537
1540
|
function parsePacket(packetType, data) {
|
|
1538
|
-
if (packetType ===
|
|
1539
|
-
return
|
|
1541
|
+
if (packetType === chunkFSAXPBGP_cjs.Packet.PACKET_TYPE) {
|
|
1542
|
+
return chunkFSAXPBGP_cjs.Packet.fromBytes(data);
|
|
1540
1543
|
}
|
|
1541
1544
|
return new UnknownPacket(packetType, data);
|
|
1542
1545
|
}
|
|
@@ -1594,7 +1597,7 @@ function validateBatchRecipients(commitmentTx, vtxoTreeLeaves, recipients, netwo
|
|
|
1594
1597
|
for (const recipient of recipients) {
|
|
1595
1598
|
let arkAddress;
|
|
1596
1599
|
try {
|
|
1597
|
-
arkAddress =
|
|
1600
|
+
arkAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(recipient.address);
|
|
1598
1601
|
} catch {
|
|
1599
1602
|
validateOnchainRecipient(commitmentTx, recipient, network, usedOnchainOutputs);
|
|
1600
1603
|
continue;
|
|
@@ -1727,7 +1730,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
|
|
|
1727
1730
|
const existing = inputsByAssetId.get(asset.assetId);
|
|
1728
1731
|
inputsByAssetId.set(asset.assetId, [
|
|
1729
1732
|
...existing ?? [],
|
|
1730
|
-
|
|
1733
|
+
chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount)
|
|
1731
1734
|
]);
|
|
1732
1735
|
}
|
|
1733
1736
|
}
|
|
@@ -1739,7 +1742,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
|
|
|
1739
1742
|
const existing = outputsByAssetId.get(asset.assetId);
|
|
1740
1743
|
outputsByAssetId.set(asset.assetId, [
|
|
1741
1744
|
...existing ?? [],
|
|
1742
|
-
|
|
1745
|
+
chunkFSAXPBGP_cjs.AssetOutput.create(outputIndex, asset.amount)
|
|
1743
1746
|
]);
|
|
1744
1747
|
}
|
|
1745
1748
|
}
|
|
@@ -1750,7 +1753,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
|
|
|
1750
1753
|
const existing = outputsByAssetId.get(asset.assetId);
|
|
1751
1754
|
outputsByAssetId.set(asset.assetId, [
|
|
1752
1755
|
...existing ?? [],
|
|
1753
|
-
|
|
1756
|
+
chunkFSAXPBGP_cjs.AssetOutput.create(outputIndex, asset.amount)
|
|
1754
1757
|
]);
|
|
1755
1758
|
}
|
|
1756
1759
|
}
|
|
@@ -1759,11 +1762,11 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
|
|
|
1759
1762
|
for (const assetIdStr of allAssetIds) {
|
|
1760
1763
|
const inputs = inputsByAssetId.get(assetIdStr);
|
|
1761
1764
|
const outputs = outputsByAssetId.get(assetIdStr);
|
|
1762
|
-
const assetId =
|
|
1763
|
-
const group =
|
|
1765
|
+
const assetId = chunkFSAXPBGP_cjs.AssetId.fromString(assetIdStr);
|
|
1766
|
+
const group = chunkFSAXPBGP_cjs.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
|
|
1764
1767
|
groups.push(group);
|
|
1765
1768
|
}
|
|
1766
|
-
return
|
|
1769
|
+
return chunkFSAXPBGP_cjs.Packet.create(groups);
|
|
1767
1770
|
}
|
|
1768
1771
|
function selectCoinsWithAsset(coins, assetId, requiredAmount) {
|
|
1769
1772
|
const coinsWithAsset = coins.filter((coin) => coin.assets?.some((a) => a.assetId === assetId));
|
|
@@ -1829,8 +1832,8 @@ function buildOffchainTx(inputs, outputs, serverUnrollScript) {
|
|
|
1829
1832
|
function buildVirtualTx(inputs, outputs) {
|
|
1830
1833
|
let lockTime = 0n;
|
|
1831
1834
|
for (const input of inputs) {
|
|
1832
|
-
const tapscript =
|
|
1833
|
-
if (
|
|
1835
|
+
const tapscript = chunkCMPJR3HS_cjs.decodeTapscript(chunkCMPJR3HS_cjs.scriptFromTapLeafScript(input.tapLeafScript));
|
|
1836
|
+
if (chunkCMPJR3HS_cjs.CLTVMultisigTapscript.is(tapscript)) {
|
|
1834
1837
|
if (lockTime !== 0n) {
|
|
1835
1838
|
if (isSeconds(lockTime) !== isSeconds(tapscript.params.absoluteTimelock)) {
|
|
1836
1839
|
throw new Error("cannot mix seconds and blocks locktime");
|
|
@@ -1841,7 +1844,7 @@ function buildVirtualTx(inputs, outputs) {
|
|
|
1841
1844
|
}
|
|
1842
1845
|
}
|
|
1843
1846
|
}
|
|
1844
|
-
const tx = new
|
|
1847
|
+
const tx = new chunkFSAXPBGP_cjs.Transaction({
|
|
1845
1848
|
version: 3,
|
|
1846
1849
|
lockTime: Number(lockTime)
|
|
1847
1850
|
});
|
|
@@ -1851,12 +1854,12 @@ function buildVirtualTx(inputs, outputs) {
|
|
|
1851
1854
|
index: input.vout,
|
|
1852
1855
|
sequence: lockTime ? btcSigner.DEFAULT_SEQUENCE - 1 : void 0,
|
|
1853
1856
|
witnessUtxo: {
|
|
1854
|
-
script:
|
|
1857
|
+
script: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript,
|
|
1855
1858
|
amount: BigInt(input.value)
|
|
1856
1859
|
},
|
|
1857
1860
|
tapLeafScript: [input.tapLeafScript]
|
|
1858
1861
|
});
|
|
1859
|
-
|
|
1862
|
+
chunkFSAXPBGP_cjs.setArkPsbtField(tx, i, chunkFSAXPBGP_cjs.VtxoTaprootTree, input.tapTree);
|
|
1860
1863
|
}
|
|
1861
1864
|
for (const output of outputs) {
|
|
1862
1865
|
tx.addOutput(output);
|
|
@@ -1865,8 +1868,8 @@ function buildVirtualTx(inputs, outputs) {
|
|
|
1865
1868
|
return tx;
|
|
1866
1869
|
}
|
|
1867
1870
|
function buildCheckpointTx(vtxo, serverUnrollScript) {
|
|
1868
|
-
const collaborativeClosure =
|
|
1869
|
-
const checkpointVtxoScript = new
|
|
1871
|
+
const collaborativeClosure = chunkCMPJR3HS_cjs.decodeTapscript(chunkCMPJR3HS_cjs.scriptFromTapLeafScript(vtxo.tapLeafScript));
|
|
1872
|
+
const checkpointVtxoScript = new chunkCMPJR3HS_cjs.VtxoScript([
|
|
1870
1873
|
serverUnrollScript.script,
|
|
1871
1874
|
collaborativeClosure.script
|
|
1872
1875
|
]);
|
|
@@ -1988,19 +1991,29 @@ function verifyTapscriptSignatures(tx, inputIndex, requiredSigners, excludePubke
|
|
|
1988
1991
|
}
|
|
1989
1992
|
}
|
|
1990
1993
|
function combineTapscriptSigs(signedTx, originalTx) {
|
|
1994
|
+
if (signedTx.inputsLength !== originalTx.inputsLength) {
|
|
1995
|
+
throw new Error(
|
|
1996
|
+
`combineTapscriptSigs: input count mismatch (signedTx ${signedTx.inputsLength}, originalTx ${originalTx.inputsLength})`
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1991
1999
|
for (let i = 0; i < signedTx.inputsLength; i++) {
|
|
1992
2000
|
const input = originalTx.getInput(i);
|
|
1993
2001
|
const signedInput = signedTx.getInput(i);
|
|
1994
|
-
if (!input.tapScriptSig)
|
|
2002
|
+
if (!input.tapScriptSig) {
|
|
2003
|
+
throw new Error(`combineTapscriptSigs: originalTx input ${i} has no tapScriptSig`);
|
|
2004
|
+
}
|
|
2005
|
+
if (!signedInput.tapScriptSig) {
|
|
2006
|
+
throw new Error(`combineTapscriptSigs: signedTx input ${i} has no tapScriptSig`);
|
|
2007
|
+
}
|
|
1995
2008
|
originalTx.updateInput(i, {
|
|
1996
|
-
tapScriptSig: input.tapScriptSig
|
|
2009
|
+
tapScriptSig: input.tapScriptSig.concat(signedInput.tapScriptSig)
|
|
1997
2010
|
});
|
|
1998
2011
|
}
|
|
1999
2012
|
return originalTx;
|
|
2000
2013
|
}
|
|
2001
2014
|
function isValidArkAddress(address) {
|
|
2002
2015
|
try {
|
|
2003
|
-
|
|
2016
|
+
chunkCMPJR3HS_cjs.ArkAddress.decode(address);
|
|
2004
2017
|
return true;
|
|
2005
2018
|
} catch (e) {
|
|
2006
2019
|
return false;
|
|
@@ -2270,16 +2283,16 @@ var FALLBACK_WALLET_DUST_AMOUNT = 330n;
|
|
|
2270
2283
|
function getDustAmount(wallet) {
|
|
2271
2284
|
return "dustAmount" in wallet ? wallet.dustAmount : FALLBACK_WALLET_DUST_AMOUNT;
|
|
2272
2285
|
}
|
|
2273
|
-
function
|
|
2286
|
+
function extendCoinWithTapscript(boardingTapscript, utxo) {
|
|
2274
2287
|
return {
|
|
2275
2288
|
...utxo,
|
|
2276
|
-
forfeitTapLeafScript:
|
|
2277
|
-
intentTapLeafScript:
|
|
2278
|
-
tapTree:
|
|
2289
|
+
forfeitTapLeafScript: boardingTapscript.forfeit(),
|
|
2290
|
+
intentTapLeafScript: boardingTapscript.forfeit(),
|
|
2291
|
+
tapTree: boardingTapscript.encode()
|
|
2279
2292
|
};
|
|
2280
2293
|
}
|
|
2281
2294
|
function deriveContractTapscripts(contract) {
|
|
2282
|
-
const handler =
|
|
2295
|
+
const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
|
|
2283
2296
|
if (!handler) {
|
|
2284
2297
|
throw new Error(`No handler for contract type '${contract.type}'`);
|
|
2285
2298
|
}
|
|
@@ -2349,7 +2362,7 @@ function validateRecipients(recipients, dustAmount) {
|
|
|
2349
2362
|
for (const recipient of recipients) {
|
|
2350
2363
|
let address;
|
|
2351
2364
|
try {
|
|
2352
|
-
address =
|
|
2365
|
+
address = chunkCMPJR3HS_cjs.ArkAddress.decode(recipient.address);
|
|
2353
2366
|
} catch (e) {
|
|
2354
2367
|
throw new Error(`Invalid Arkade address: ${recipient.address}`);
|
|
2355
2368
|
}
|
|
@@ -2369,12 +2382,12 @@ function validateRecipients(recipients, dustAmount) {
|
|
|
2369
2382
|
|
|
2370
2383
|
// src/wallet/vtxo-manager.ts
|
|
2371
2384
|
function isSweepCapable(wallet) {
|
|
2372
|
-
return "boardingTapscript" in wallet && "onchainProvider" in wallet && "arkProvider" in wallet && "network" in wallet;
|
|
2385
|
+
return "boardingTapscript" in wallet && "onchainProvider" in wallet && "arkProvider" in wallet && "network" in wallet && "signOnchainBoardingTx" in wallet;
|
|
2373
2386
|
}
|
|
2374
2387
|
function assertSweepCapable(wallet) {
|
|
2375
2388
|
if (!isSweepCapable(wallet)) {
|
|
2376
2389
|
throw new Error(
|
|
2377
|
-
"Boarding UTXO sweep requires a Wallet instance with boardingTapscript, onchainProvider, arkProvider, and
|
|
2390
|
+
"Boarding UTXO sweep requires a Wallet instance with boardingTapscript, onchainProvider, arkProvider, network, and signOnchainBoardingTx"
|
|
2378
2391
|
);
|
|
2379
2392
|
}
|
|
2380
2393
|
}
|
|
@@ -2390,6 +2403,21 @@ async function runWithCrossInstanceLock(name, fn) {
|
|
|
2390
2403
|
await fn();
|
|
2391
2404
|
});
|
|
2392
2405
|
}
|
|
2406
|
+
var MAX_VTXOS_PER_SETTLEMENT = 50;
|
|
2407
|
+
function byValueDescending(vtxos) {
|
|
2408
|
+
return [...vtxos].sort((a, b) => b.value - a.value);
|
|
2409
|
+
}
|
|
2410
|
+
function byExpiryAscending(vtxos) {
|
|
2411
|
+
const expiryKey = (vtxo) => {
|
|
2412
|
+
if (isRecoverable(vtxo)) return -Infinity;
|
|
2413
|
+
const batchExpiry = vtxo.virtualStatus.batchExpiry;
|
|
2414
|
+
if (isExpired(vtxo)) return batchExpiry ?? -Infinity;
|
|
2415
|
+
if (!batchExpiry) return Infinity;
|
|
2416
|
+
if (new Date(batchExpiry).getFullYear() < 2025) return Infinity;
|
|
2417
|
+
return batchExpiry;
|
|
2418
|
+
};
|
|
2419
|
+
return [...vtxos].sort((a, b) => expiryKey(a) - expiryKey(b));
|
|
2420
|
+
}
|
|
2393
2421
|
var DEFAULT_THRESHOLD_SECONDS = 259200;
|
|
2394
2422
|
var DEFAULT_THRESHOLD_MS = DEFAULT_THRESHOLD_SECONDS * 1e3;
|
|
2395
2423
|
var DEFAULT_RENEWAL_CONFIG = {
|
|
@@ -2549,10 +2577,20 @@ var VtxoManager = class _VtxoManager {
|
|
|
2549
2577
|
withUnrolled: false
|
|
2550
2578
|
});
|
|
2551
2579
|
const dustAmount = getDustAmount(this.wallet);
|
|
2552
|
-
|
|
2580
|
+
let { vtxosToRecover, totalAmount } = getRecoverableWithSubdust(allVtxos, dustAmount);
|
|
2553
2581
|
if (vtxosToRecover.length === 0) {
|
|
2554
2582
|
throw new Error("No recoverable VTXOs found");
|
|
2555
2583
|
}
|
|
2584
|
+
if (vtxosToRecover.length > MAX_VTXOS_PER_SETTLEMENT) {
|
|
2585
|
+
const recoverableCount = vtxosToRecover.length;
|
|
2586
|
+
const capped = byValueDescending(vtxosToRecover).slice(0, MAX_VTXOS_PER_SETTLEMENT);
|
|
2587
|
+
({ vtxosToRecover, totalAmount } = getRecoverableWithSubdust(capped, dustAmount));
|
|
2588
|
+
if (vtxosToRecover.length === 0) {
|
|
2589
|
+
throw new Error(
|
|
2590
|
+
`Capped recovery batch (highest-value ${MAX_VTXOS_PER_SETTLEMENT} of ${recoverableCount} recoverable VTXOs) is below the dust threshold ${dustAmount}`
|
|
2591
|
+
);
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2556
2594
|
const arkAddress = await this.wallet.getAddress();
|
|
2557
2595
|
return this.wallet.settle(
|
|
2558
2596
|
{
|
|
@@ -2702,6 +2740,9 @@ var VtxoManager = class _VtxoManager {
|
|
|
2702
2740
|
if (vtxos.length === 0) {
|
|
2703
2741
|
throw new Error("No VTXOs available to renew");
|
|
2704
2742
|
}
|
|
2743
|
+
if (vtxos.length > MAX_VTXOS_PER_SETTLEMENT) {
|
|
2744
|
+
vtxos = byExpiryAscending(vtxos).slice(0, MAX_VTXOS_PER_SETTLEMENT);
|
|
2745
|
+
}
|
|
2705
2746
|
const totalAmount = vtxos.reduce((sum, vtxo) => sum + vtxo.value, 0);
|
|
2706
2747
|
const dustAmount = getDustAmount(this.wallet);
|
|
2707
2748
|
if (BigInt(totalAmount) < dustAmount) {
|
|
@@ -2809,7 +2850,6 @@ var VtxoManager = class _VtxoManager {
|
|
|
2809
2850
|
const boardingAddress = await this.wallet.getBoardingAddress();
|
|
2810
2851
|
const feeRate = await this.getOnchainProvider().getFeeRate() ?? 1;
|
|
2811
2852
|
const exitTapLeafScript = this.getBoardingExitLeaf();
|
|
2812
|
-
const sequence = chunkWMIPYZSB_cjs.getSequence(exitTapLeafScript);
|
|
2813
2853
|
const leafScript = exitTapLeafScript[1];
|
|
2814
2854
|
const leafScriptSize = leafScript.length - 1;
|
|
2815
2855
|
const controlBlockSize = exitTapLeafScript[0].merklePath.length * 32;
|
|
@@ -2828,21 +2868,30 @@ var VtxoManager = class _VtxoManager {
|
|
|
2828
2868
|
`Sweep not economical: output ${outputAmount} sats after ${fee} sats fee is below dust (${dustAmount} sats)`
|
|
2829
2869
|
);
|
|
2830
2870
|
}
|
|
2831
|
-
const tx = new
|
|
2871
|
+
const tx = new chunkFSAXPBGP_cjs.Transaction();
|
|
2832
2872
|
for (const utxo of expiredUtxos) {
|
|
2873
|
+
const utxoScript = chunkCMPJR3HS_cjs.VtxoScript.decode(utxo.tapTree);
|
|
2874
|
+
const utxoExitLeaf = utxoScript.leaves.find(
|
|
2875
|
+
(leaf) => chunkCMPJR3HS_cjs.CSVMultisigTapscript.isScriptValid(chunkCMPJR3HS_cjs.scriptFromTapLeafScript(leaf)) === true
|
|
2876
|
+
);
|
|
2877
|
+
if (!utxoExitLeaf) {
|
|
2878
|
+
throw new Error(
|
|
2879
|
+
`Boarding sweep: no CSV exit leaf for UTXO ${utxo.txid}:${utxo.vout}`
|
|
2880
|
+
);
|
|
2881
|
+
}
|
|
2833
2882
|
tx.addInput({
|
|
2834
2883
|
txid: utxo.txid,
|
|
2835
2884
|
index: utxo.vout,
|
|
2836
2885
|
witnessUtxo: {
|
|
2837
|
-
script:
|
|
2886
|
+
script: utxoScript.pkScript,
|
|
2838
2887
|
amount: BigInt(utxo.value)
|
|
2839
2888
|
},
|
|
2840
|
-
tapLeafScript: [
|
|
2841
|
-
sequence
|
|
2889
|
+
tapLeafScript: [utxoExitLeaf],
|
|
2890
|
+
sequence: chunkCMPJR3HS_cjs.getSequence(utxoExitLeaf)
|
|
2842
2891
|
});
|
|
2843
2892
|
}
|
|
2844
2893
|
tx.addOutputAddress(boardingAddress, outputAmount, this.getNetwork());
|
|
2845
|
-
const signedTx = await this.
|
|
2894
|
+
const signedTx = await this.getSweepWallet().signOnchainBoardingTx(tx);
|
|
2846
2895
|
signedTx.finalize();
|
|
2847
2896
|
const txid = await this.getOnchainProvider().broadcastTransaction(signedTx.hex);
|
|
2848
2897
|
for (const u of expiredUtxos) {
|
|
@@ -2860,7 +2909,7 @@ var VtxoManager = class _VtxoManager {
|
|
|
2860
2909
|
/** Decodes the boarding tapscript exit path to extract the CSV timelock. */
|
|
2861
2910
|
getBoardingTimelock() {
|
|
2862
2911
|
const wallet = this.getSweepWallet();
|
|
2863
|
-
const exitScript =
|
|
2912
|
+
const exitScript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.decode(
|
|
2864
2913
|
base.hex.decode(wallet.boardingTapscript.exitScript)
|
|
2865
2914
|
);
|
|
2866
2915
|
return exitScript.params.timelock;
|
|
@@ -2869,10 +2918,6 @@ var VtxoManager = class _VtxoManager {
|
|
|
2869
2918
|
getBoardingExitLeaf() {
|
|
2870
2919
|
return this.getSweepWallet().boardingTapscript.exit();
|
|
2871
2920
|
}
|
|
2872
|
-
/** Returns the pkScript (output script) of the boarding tapscript. */
|
|
2873
|
-
getBoardingOutputScript() {
|
|
2874
|
-
return this.getSweepWallet().boardingTapscript.pkScript;
|
|
2875
|
-
}
|
|
2876
2921
|
/** Returns the onchain provider for fee estimation and broadcasting. */
|
|
2877
2922
|
getOnchainProvider() {
|
|
2878
2923
|
return this.getSweepWallet().onchainProvider;
|
|
@@ -2885,10 +2930,6 @@ var VtxoManager = class _VtxoManager {
|
|
|
2885
2930
|
getNetwork() {
|
|
2886
2931
|
return this.getSweepWallet().network;
|
|
2887
2932
|
}
|
|
2888
|
-
/** Returns the wallet's identity for transaction signing. */
|
|
2889
|
-
getIdentity() {
|
|
2890
|
-
return this.wallet.identity;
|
|
2891
|
-
}
|
|
2892
2933
|
async initializeSubscription() {
|
|
2893
2934
|
if (this.settlementConfig === false) {
|
|
2894
2935
|
return void 0;
|
|
@@ -2989,7 +3030,7 @@ var VtxoManager = class _VtxoManager {
|
|
|
2989
3030
|
* or doesn't carry the metadata.
|
|
2990
3031
|
*/
|
|
2991
3032
|
extractSpentOutpoint(error) {
|
|
2992
|
-
const ark =
|
|
3033
|
+
const ark = chunkFSAXPBGP_cjs.maybeArkError(error);
|
|
2993
3034
|
if (!ark || ark.name !== "VTXO_ALREADY_SPENT") return void 0;
|
|
2994
3035
|
const raw = ark.metadata?.vtxo_outpoint;
|
|
2995
3036
|
if (typeof raw !== "string") return void 0;
|
|
@@ -3169,7 +3210,10 @@ var VtxoManager = class _VtxoManager {
|
|
|
3169
3210
|
totalAmount += BigInt(u.value) - BigInt(inputFee.satoshis);
|
|
3170
3211
|
}
|
|
3171
3212
|
const filteredVtxos = [];
|
|
3172
|
-
for (const v of expiringVtxos) {
|
|
3213
|
+
for (const v of byExpiryAscending(expiringVtxos)) {
|
|
3214
|
+
if (filteredVtxos.length >= MAX_VTXOS_PER_SETTLEMENT) {
|
|
3215
|
+
break;
|
|
3216
|
+
}
|
|
3173
3217
|
const inputFee = estimator.evalOffchainInput({
|
|
3174
3218
|
amount: BigInt(v.value),
|
|
3175
3219
|
type: v.virtualStatus.state === "swept" ? "recoverable" : "vtxo",
|
|
@@ -3189,7 +3233,7 @@ var VtxoManager = class _VtxoManager {
|
|
|
3189
3233
|
const arkAddress = await this.wallet.getAddress();
|
|
3190
3234
|
const outputFee = estimator.evalOffchainOutput({
|
|
3191
3235
|
amount: totalAmount,
|
|
3192
|
-
script: base.hex.encode(
|
|
3236
|
+
script: base.hex.encode(chunkCMPJR3HS_cjs.ArkAddress.decode(arkAddress).pkScript)
|
|
3193
3237
|
});
|
|
3194
3238
|
totalAmount -= BigInt(outputFee.satoshis);
|
|
3195
3239
|
if (totalAmount < dustAmount) return;
|
|
@@ -3270,7 +3314,7 @@ var ArkNote = class _ArkNote {
|
|
|
3270
3314
|
this.value = value;
|
|
3271
3315
|
this.HRP = HRP;
|
|
3272
3316
|
const preimageHash = utils_js.sha256(this.preimage);
|
|
3273
|
-
this.vtxoScript = new
|
|
3317
|
+
this.vtxoScript = new chunkCMPJR3HS_cjs.VtxoScript([noteTapscript(preimageHash)]);
|
|
3274
3318
|
const leaf = this.vtxoScript.leaves[0];
|
|
3275
3319
|
this.txid = base.hex.encode(new Uint8Array(preimageHash).reverse());
|
|
3276
3320
|
this.tapTree = this.vtxoScript.encode();
|
|
@@ -3884,7 +3928,7 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
3884
3928
|
const virtualCoins = await this.wallet.getVtxos({
|
|
3885
3929
|
withRecoverable: false
|
|
3886
3930
|
});
|
|
3887
|
-
const controlAssetRef = params.controlAssetId ?
|
|
3931
|
+
const controlAssetRef = params.controlAssetId ? chunkFSAXPBGP_cjs.AssetRef.fromId(chunkFSAXPBGP_cjs.AssetId.fromString(params.controlAssetId)) : null;
|
|
3888
3932
|
const coinSelection = selectVirtualCoins(virtualCoins, Number(this.wallet.dustAmount));
|
|
3889
3933
|
let totalBtcSelected = 0n;
|
|
3890
3934
|
const assetChanges = /* @__PURE__ */ new Map();
|
|
@@ -3897,8 +3941,8 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
3897
3941
|
}
|
|
3898
3942
|
}
|
|
3899
3943
|
const groups = [];
|
|
3900
|
-
const issuedAssetOutput =
|
|
3901
|
-
const issuedAssetGroup =
|
|
3944
|
+
const issuedAssetOutput = chunkFSAXPBGP_cjs.AssetOutput.create(0, params.amount);
|
|
3945
|
+
const issuedAssetGroup = chunkFSAXPBGP_cjs.AssetGroup.create(
|
|
3902
3946
|
null,
|
|
3903
3947
|
controlAssetRef,
|
|
3904
3948
|
[],
|
|
@@ -3913,28 +3957,28 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
3913
3957
|
for (const [inputIndex, assets] of assetInputs) {
|
|
3914
3958
|
for (const asset of assets) {
|
|
3915
3959
|
if (asset.assetId !== assetId) continue;
|
|
3916
|
-
changeInputs.push(
|
|
3960
|
+
changeInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
|
|
3917
3961
|
}
|
|
3918
3962
|
}
|
|
3919
3963
|
groups.push(
|
|
3920
|
-
|
|
3921
|
-
|
|
3964
|
+
chunkFSAXPBGP_cjs.AssetGroup.create(
|
|
3965
|
+
chunkFSAXPBGP_cjs.AssetId.fromString(assetId),
|
|
3922
3966
|
null,
|
|
3923
3967
|
changeInputs,
|
|
3924
|
-
[
|
|
3968
|
+
[chunkFSAXPBGP_cjs.AssetOutput.create(0, amount)],
|
|
3925
3969
|
[]
|
|
3926
3970
|
)
|
|
3927
3971
|
);
|
|
3928
3972
|
}
|
|
3929
3973
|
}
|
|
3930
3974
|
const address = await this.wallet.getAddress();
|
|
3931
|
-
const outputAddress =
|
|
3975
|
+
const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(address);
|
|
3932
3976
|
const outputs = [
|
|
3933
3977
|
{
|
|
3934
3978
|
script: outputAddress.pkScript,
|
|
3935
3979
|
amount: BigInt(totalBtcSelected)
|
|
3936
3980
|
},
|
|
3937
|
-
Extension.create([
|
|
3981
|
+
Extension.create([chunkFSAXPBGP_cjs.Packet.create(groups)]).txOut()
|
|
3938
3982
|
];
|
|
3939
3983
|
const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(
|
|
3940
3984
|
coinSelection.inputs,
|
|
@@ -3942,7 +3986,7 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
3942
3986
|
);
|
|
3943
3987
|
return {
|
|
3944
3988
|
arkTxId: arkTxid,
|
|
3945
|
-
assetId:
|
|
3989
|
+
assetId: chunkFSAXPBGP_cjs.AssetId.create(arkTxid, 0).toString()
|
|
3946
3990
|
};
|
|
3947
3991
|
}
|
|
3948
3992
|
/**
|
|
@@ -4014,16 +4058,16 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4014
4058
|
for (const [inputIndex, assets] of assetInputs) {
|
|
4015
4059
|
for (const asset of assets) {
|
|
4016
4060
|
if (asset.assetId !== params.assetId) continue;
|
|
4017
|
-
reissueInputs.push(
|
|
4061
|
+
reissueInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
|
|
4018
4062
|
}
|
|
4019
4063
|
}
|
|
4020
4064
|
const totalAssetAmount = assetToReissueAmount + params.amount;
|
|
4021
|
-
const reissueAssetIdObj =
|
|
4022
|
-
const reissueAssetGroup =
|
|
4065
|
+
const reissueAssetIdObj = chunkFSAXPBGP_cjs.AssetId.fromString(params.assetId);
|
|
4066
|
+
const reissueAssetGroup = chunkFSAXPBGP_cjs.AssetGroup.create(
|
|
4023
4067
|
reissueAssetIdObj,
|
|
4024
4068
|
null,
|
|
4025
4069
|
reissueInputs,
|
|
4026
|
-
[
|
|
4070
|
+
[chunkFSAXPBGP_cjs.AssetOutput.create(0, totalAssetAmount)],
|
|
4027
4071
|
[]
|
|
4028
4072
|
);
|
|
4029
4073
|
const groups = [reissueAssetGroup];
|
|
@@ -4032,27 +4076,27 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4032
4076
|
for (const [inputIndex, assets] of assetInputs) {
|
|
4033
4077
|
for (const asset of assets) {
|
|
4034
4078
|
if (asset.assetId !== assetId) continue;
|
|
4035
|
-
changeInputs.push(
|
|
4079
|
+
changeInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
|
|
4036
4080
|
}
|
|
4037
4081
|
}
|
|
4038
4082
|
groups.push(
|
|
4039
|
-
|
|
4040
|
-
|
|
4083
|
+
chunkFSAXPBGP_cjs.AssetGroup.create(
|
|
4084
|
+
chunkFSAXPBGP_cjs.AssetId.fromString(assetId),
|
|
4041
4085
|
null,
|
|
4042
4086
|
changeInputs,
|
|
4043
|
-
[
|
|
4087
|
+
[chunkFSAXPBGP_cjs.AssetOutput.create(0, amount)],
|
|
4044
4088
|
[]
|
|
4045
4089
|
)
|
|
4046
4090
|
);
|
|
4047
4091
|
}
|
|
4048
4092
|
const address = await this.wallet.getAddress();
|
|
4049
|
-
const outputAddress =
|
|
4093
|
+
const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(address);
|
|
4050
4094
|
const outputs = [
|
|
4051
4095
|
{
|
|
4052
4096
|
script: outputAddress.pkScript,
|
|
4053
4097
|
amount: BigInt(totalBtcSelected)
|
|
4054
4098
|
},
|
|
4055
|
-
Extension.create([
|
|
4099
|
+
Extension.create([chunkFSAXPBGP_cjs.Packet.create(groups)]).txOut()
|
|
4056
4100
|
];
|
|
4057
4101
|
const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
|
|
4058
4102
|
return arkTxid;
|
|
@@ -4119,27 +4163,27 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
4119
4163
|
for (const [inputIndex, assets] of assetInputs) {
|
|
4120
4164
|
for (const asset of assets) {
|
|
4121
4165
|
if (asset.assetId !== assetId) continue;
|
|
4122
|
-
changeInputs.push(
|
|
4166
|
+
changeInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
|
|
4123
4167
|
}
|
|
4124
4168
|
}
|
|
4125
4169
|
groups.push(
|
|
4126
|
-
|
|
4127
|
-
|
|
4170
|
+
chunkFSAXPBGP_cjs.AssetGroup.create(
|
|
4171
|
+
chunkFSAXPBGP_cjs.AssetId.fromString(assetId),
|
|
4128
4172
|
null,
|
|
4129
4173
|
changeInputs,
|
|
4130
|
-
amount > 0n ? [
|
|
4174
|
+
amount > 0n ? [chunkFSAXPBGP_cjs.AssetOutput.create(0, amount)] : [],
|
|
4131
4175
|
[]
|
|
4132
4176
|
)
|
|
4133
4177
|
);
|
|
4134
4178
|
}
|
|
4135
4179
|
const address = await this.wallet.getAddress();
|
|
4136
|
-
const outputAddress =
|
|
4180
|
+
const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(address);
|
|
4137
4181
|
const outputs = [
|
|
4138
4182
|
{
|
|
4139
4183
|
script: outputAddress.pkScript,
|
|
4140
4184
|
amount: BigInt(totalBtcSelected)
|
|
4141
4185
|
},
|
|
4142
|
-
Extension.create([
|
|
4186
|
+
Extension.create([chunkFSAXPBGP_cjs.Packet.create(groups)]).txOut()
|
|
4143
4187
|
];
|
|
4144
4188
|
const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
|
|
4145
4189
|
return arkTxid;
|
|
@@ -4164,7 +4208,7 @@ function castMetadata(metadata) {
|
|
|
4164
4208
|
} else {
|
|
4165
4209
|
throw new Error("Invalid metadata value type");
|
|
4166
4210
|
}
|
|
4167
|
-
md.push(
|
|
4211
|
+
md.push(chunkFSAXPBGP_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
|
|
4168
4212
|
}
|
|
4169
4213
|
return md;
|
|
4170
4214
|
}
|
|
@@ -4182,7 +4226,7 @@ var DelegateManagerImpl = class {
|
|
|
4182
4226
|
if (vtxos.length === 0) {
|
|
4183
4227
|
return { delegated: [], failed: [] };
|
|
4184
4228
|
}
|
|
4185
|
-
const destinationScript =
|
|
4229
|
+
const destinationScript = chunkCMPJR3HS_cjs.ArkAddress.decode(destination).pkScript;
|
|
4186
4230
|
const arkInfo = await this.arkInfoProvider.getInfo();
|
|
4187
4231
|
const delegateInfo = await this.delegateProvider.getDelegateInfo();
|
|
4188
4232
|
const eligible = vtxos.filter(
|
|
@@ -4330,7 +4374,7 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
|
|
|
4330
4374
|
const delegateFee = BigInt(Number(fee));
|
|
4331
4375
|
if (delegateFee > 0n) {
|
|
4332
4376
|
outputs.push({
|
|
4333
|
-
script:
|
|
4377
|
+
script: chunkCMPJR3HS_cjs.ArkAddress.decode(delegateAddress).pkScript,
|
|
4334
4378
|
amount: delegateFee
|
|
4335
4379
|
});
|
|
4336
4380
|
}
|
|
@@ -4363,7 +4407,7 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
|
|
|
4363
4407
|
destinationScript
|
|
4364
4408
|
);
|
|
4365
4409
|
const forfeitOutputScript = btcSigner.OutScript.encode(
|
|
4366
|
-
btcSigner.Address(
|
|
4410
|
+
btcSigner.Address(chunkCMPJR3HS_cjs.getNetwork(network)).decode(forfeitAddress)
|
|
4367
4411
|
);
|
|
4368
4412
|
const forfeits = await Promise.all(
|
|
4369
4413
|
vtxos.filter((v) => !isRecoverable(v)).map(async (coin) => {
|
|
@@ -4391,7 +4435,7 @@ async function makeDelegateForfeitTx(input, connectorAmount, delegatePubkey, for
|
|
|
4391
4435
|
index: input.vout,
|
|
4392
4436
|
witnessUtxo: {
|
|
4393
4437
|
amount: BigInt(input.value),
|
|
4394
|
-
script:
|
|
4438
|
+
script: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
|
|
4395
4439
|
},
|
|
4396
4440
|
sighashType: btcSigner.SigHash.ALL_ANYONECANPAY,
|
|
4397
4441
|
tapLeafScript: [delegateTapLeaf]
|
|
@@ -4449,7 +4493,7 @@ async function makeSignedDelegateIntent(identity, coins, outputs, onchainOutputs
|
|
|
4449
4493
|
expire_at: 0,
|
|
4450
4494
|
cosigners_public_keys: cosignerPubKeys
|
|
4451
4495
|
};
|
|
4452
|
-
const proof =
|
|
4496
|
+
const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, outputs);
|
|
4453
4497
|
const signedProof = await identity.sign(proof);
|
|
4454
4498
|
return {
|
|
4455
4499
|
proof: base.base64.encode(signedProof.toPSBT()),
|
|
@@ -4467,10 +4511,10 @@ function getDayTimestamp(timestamp) {
|
|
|
4467
4511
|
function findDelegateTapLeaf(vtxo, delegatePubkey) {
|
|
4468
4512
|
if (!vtxo.tapTree) return void 0;
|
|
4469
4513
|
const pk = delegatePubkey.length === 66 ? delegatePubkey.slice(2) : delegatePubkey;
|
|
4470
|
-
const vtxoScript =
|
|
4514
|
+
const vtxoScript = chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree);
|
|
4471
4515
|
return vtxoScript.leaves.find((tapLeaf) => {
|
|
4472
|
-
const arkTapscript =
|
|
4473
|
-
if (!
|
|
4516
|
+
const arkTapscript = chunkCMPJR3HS_cjs.decodeTapscript(chunkCMPJR3HS_cjs.scriptFromTapLeafScript(tapLeaf));
|
|
4517
|
+
if (!chunkCMPJR3HS_cjs.MultisigTapscript.is(arkTapscript)) return false;
|
|
4474
4518
|
return arkTapscript.params.pubkeys.map(base.hex.encode).includes(pk);
|
|
4475
4519
|
});
|
|
4476
4520
|
}
|
|
@@ -4674,7 +4718,7 @@ var InMemoryContractRepository = class {
|
|
|
4674
4718
|
}
|
|
4675
4719
|
};
|
|
4676
4720
|
function scriptFromArkAddress(address) {
|
|
4677
|
-
return base.hex.encode(
|
|
4721
|
+
return base.hex.encode(chunkCMPJR3HS_cjs.ArkAddress.decode(address).pkScript);
|
|
4678
4722
|
}
|
|
4679
4723
|
|
|
4680
4724
|
// src/repositories/indexedDB/schema.ts
|
|
@@ -6189,7 +6233,7 @@ var ContractWatcher = class {
|
|
|
6189
6233
|
this.connectionState = "connected";
|
|
6190
6234
|
this.reconnectAttempts = 0;
|
|
6191
6235
|
this.listenLoop().catch((e) => {
|
|
6192
|
-
if (
|
|
6236
|
+
if (chunkFSAXPBGP_cjs.isEventSourceError(e)) {
|
|
6193
6237
|
console.debug("ContractWatcher subscription disconnected; reconnecting");
|
|
6194
6238
|
} else {
|
|
6195
6239
|
console.error(e);
|
|
@@ -6527,8 +6571,11 @@ function cursorCutoff(requestStartedAt) {
|
|
|
6527
6571
|
}
|
|
6528
6572
|
|
|
6529
6573
|
// src/contracts/contractManager.ts
|
|
6530
|
-
|
|
6574
|
+
function areCoalescibleContractTypes(a, b) {
|
|
6575
|
+
return a === "default" && b === "boarding" || a === "boarding" && b === "default";
|
|
6576
|
+
}
|
|
6531
6577
|
var SCAN_MAX_INDEX = 1e4;
|
|
6578
|
+
var DEFAULT_SCAN_BATCH = 10;
|
|
6532
6579
|
var ContractManager = class _ContractManager {
|
|
6533
6580
|
config;
|
|
6534
6581
|
watcher;
|
|
@@ -6629,7 +6676,7 @@ var ContractManager = class _ContractManager {
|
|
|
6629
6676
|
* `persisted` is `true`.
|
|
6630
6677
|
*/
|
|
6631
6678
|
async upsertContract(params) {
|
|
6632
|
-
const handler =
|
|
6679
|
+
const handler = chunkGUTKJMSF_cjs.contractHandlers.get(params.type);
|
|
6633
6680
|
if (!handler) {
|
|
6634
6681
|
throw new Error(`No handler registered for contract type '${params.type}'`);
|
|
6635
6682
|
}
|
|
@@ -6652,8 +6699,11 @@ var ContractManager = class _ContractManager {
|
|
|
6652
6699
|
const [existing] = await this.getContracts({ script: params.script });
|
|
6653
6700
|
if (existing) {
|
|
6654
6701
|
if (existing.type === params.type) return { contract: existing, persisted: false };
|
|
6702
|
+
if (areCoalescibleContractTypes(existing.type, params.type)) {
|
|
6703
|
+
return { contract: existing, persisted: false };
|
|
6704
|
+
}
|
|
6655
6705
|
throw new Error(
|
|
6656
|
-
`Contract with script ${params.script} already exists with
|
|
6706
|
+
`Contract with script ${params.script} already exists with type ${existing.type}.`
|
|
6657
6707
|
);
|
|
6658
6708
|
}
|
|
6659
6709
|
const contract = {
|
|
@@ -6682,6 +6732,19 @@ var ContractManager = class _ContractManager {
|
|
|
6682
6732
|
* other handler hit it).
|
|
6683
6733
|
* - `persistAndWatchContract` rejecting is operational/fatal and
|
|
6684
6734
|
* propagates (only `discoverAt` is guarded).
|
|
6735
|
+
* - Within an index the handler probes run concurrently (independent
|
|
6736
|
+
* network reads); their hits are persisted sequentially in
|
|
6737
|
+
* `discoverables` order to preserve the first-wins collision tie-break.
|
|
6738
|
+
* - Indices are probed `batchSize` at a time (a second concurrency layer
|
|
6739
|
+
* over the per-index probes), but each window is CAPPED to
|
|
6740
|
+
* `gapLimit - unused` indices — the most a serial scan could still reach
|
|
6741
|
+
* before the gap window is guaranteed to close. So every index probed in
|
|
6742
|
+
* a window is one a one-index-at-a-time scan would also reach: nothing is
|
|
6743
|
+
* over-scanned, nothing is discarded, and `materialize`/`discoverAt` are
|
|
6744
|
+
* invoked on exactly the same index set. The window's hits are still
|
|
6745
|
+
* processed strictly in ascending index order, so the discovered set,
|
|
6746
|
+
* persisted rows, `lastIndexUsed`, and `handlerErrors` are byte-for-byte
|
|
6747
|
+
* identical to the serial path — only the wall-clock differs.
|
|
6685
6748
|
*/
|
|
6686
6749
|
async scanContracts(opts) {
|
|
6687
6750
|
const gapLimit = opts.gapLimit ?? 20;
|
|
@@ -6690,35 +6753,69 @@ var ContractManager = class _ContractManager {
|
|
|
6690
6753
|
`scanContracts: gapLimit must be a positive integer (got ${String(opts.gapLimit)})`
|
|
6691
6754
|
);
|
|
6692
6755
|
}
|
|
6693
|
-
const
|
|
6756
|
+
const batchSize = opts.batchSize ?? DEFAULT_SCAN_BATCH;
|
|
6757
|
+
if (!Number.isInteger(batchSize) || batchSize <= 0) {
|
|
6758
|
+
throw new Error(
|
|
6759
|
+
`scanContracts: batchSize must be a positive integer (got ${String(opts.batchSize)})`
|
|
6760
|
+
);
|
|
6761
|
+
}
|
|
6762
|
+
const registered = chunkGUTKJMSF_cjs.contractHandlers.getRegisteredTypes().map((t) => chunkGUTKJMSF_cjs.contractHandlers.get(t)).filter(isDiscoverable);
|
|
6763
|
+
const discoverables = [
|
|
6764
|
+
...registered.filter((h) => h.type === "boarding"),
|
|
6765
|
+
...registered.filter((h) => h.type !== "boarding")
|
|
6766
|
+
];
|
|
6694
6767
|
const maxIdx = opts.hd ? SCAN_MAX_INDEX : 0;
|
|
6695
6768
|
const handlerErrors = [];
|
|
6696
6769
|
let lastIndexUsed = -1;
|
|
6697
6770
|
let unused = 0;
|
|
6698
6771
|
let i = 0;
|
|
6772
|
+
const probeIndex = async (index) => {
|
|
6773
|
+
const descriptor = opts.materialize(index);
|
|
6774
|
+
return Promise.all(
|
|
6775
|
+
discoverables.map(async (h) => {
|
|
6776
|
+
try {
|
|
6777
|
+
return {
|
|
6778
|
+
ok: true,
|
|
6779
|
+
found: await h.discoverAt(index, descriptor, opts.deps)
|
|
6780
|
+
};
|
|
6781
|
+
} catch (error) {
|
|
6782
|
+
return { ok: false, error };
|
|
6783
|
+
}
|
|
6784
|
+
})
|
|
6785
|
+
);
|
|
6786
|
+
};
|
|
6699
6787
|
while (i <= maxIdx && unused < gapLimit) {
|
|
6700
|
-
const
|
|
6701
|
-
|
|
6702
|
-
for (
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6788
|
+
const windowEnd = Math.min(maxIdx, i + Math.min(batchSize, gapLimit - unused) - 1);
|
|
6789
|
+
const windowIndices = [];
|
|
6790
|
+
for (let idx = i; idx <= windowEnd; idx++) windowIndices.push(idx);
|
|
6791
|
+
const windowProbes = await Promise.all(windowIndices.map(probeIndex));
|
|
6792
|
+
for (let w = 0; w < windowIndices.length; w++) {
|
|
6793
|
+
const index = windowIndices[w];
|
|
6794
|
+
const probes = windowProbes[w];
|
|
6795
|
+
let hitAtThisIndex = false;
|
|
6796
|
+
for (let h = 0; h < discoverables.length; h++) {
|
|
6797
|
+
const probe = probes[h];
|
|
6798
|
+
if (!probe.ok) {
|
|
6799
|
+
handlerErrors.push({
|
|
6800
|
+
handler: discoverables[h].type,
|
|
6801
|
+
index,
|
|
6802
|
+
error: probe.error
|
|
6803
|
+
});
|
|
6804
|
+
continue;
|
|
6805
|
+
}
|
|
6806
|
+
for (const c of probe.found) {
|
|
6807
|
+
await this.persistAndWatchContract(c);
|
|
6808
|
+
hitAtThisIndex = true;
|
|
6809
|
+
}
|
|
6709
6810
|
}
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6811
|
+
if (hitAtThisIndex) {
|
|
6812
|
+
lastIndexUsed = index;
|
|
6813
|
+
unused = 0;
|
|
6814
|
+
} else {
|
|
6815
|
+
unused += 1;
|
|
6713
6816
|
}
|
|
6714
6817
|
}
|
|
6715
|
-
|
|
6716
|
-
lastIndexUsed = i;
|
|
6717
|
-
unused = 0;
|
|
6718
|
-
} else {
|
|
6719
|
-
unused += 1;
|
|
6720
|
-
}
|
|
6721
|
-
i += 1;
|
|
6818
|
+
i = windowEnd + 1;
|
|
6722
6819
|
}
|
|
6723
6820
|
if (opts.hd && i > maxIdx && unused < gapLimit) {
|
|
6724
6821
|
throw new Error(
|
|
@@ -6846,7 +6943,7 @@ var ContractManager = class _ContractManager {
|
|
|
6846
6943
|
const { contractScript, collaborative = true, walletPubKey, vtxo } = options;
|
|
6847
6944
|
const [contract] = await this.getContracts({ script: contractScript });
|
|
6848
6945
|
if (!contract) return [];
|
|
6849
|
-
const handler =
|
|
6946
|
+
const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
|
|
6850
6947
|
if (!handler) return [];
|
|
6851
6948
|
const script = handler.createScript(contract.params);
|
|
6852
6949
|
const context = {
|
|
@@ -6866,7 +6963,7 @@ var ContractManager = class _ContractManager {
|
|
|
6866
6963
|
const { contractScript, collaborative = true, walletPubKey } = options;
|
|
6867
6964
|
const [contract] = await this.getContracts({ script: contractScript });
|
|
6868
6965
|
if (!contract) return [];
|
|
6869
|
-
const handler =
|
|
6966
|
+
const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
|
|
6870
6967
|
if (!handler) return [];
|
|
6871
6968
|
const script = handler.createScript(contract.params);
|
|
6872
6969
|
const context = {
|
|
@@ -7100,7 +7197,7 @@ var ContractManager = class _ContractManager {
|
|
|
7100
7197
|
}
|
|
7101
7198
|
return result;
|
|
7102
7199
|
}
|
|
7103
|
-
async fetchContractVtxosBulk(contracts, pageSize = DEFAULT_PAGE_SIZE, syncWindow) {
|
|
7200
|
+
async fetchContractVtxosBulk(contracts, pageSize = chunkGUTKJMSF_cjs.DEFAULT_PAGE_SIZE, syncWindow) {
|
|
7104
7201
|
if (contracts.length === 0) {
|
|
7105
7202
|
return /* @__PURE__ */ new Map();
|
|
7106
7203
|
}
|
|
@@ -7276,7 +7373,7 @@ var HDDescriptorProvider = class _HDDescriptorProvider {
|
|
|
7276
7373
|
*/
|
|
7277
7374
|
materializeDescriptorAt(index) {
|
|
7278
7375
|
const descriptor = this.identity.descriptor;
|
|
7279
|
-
const network =
|
|
7376
|
+
const network = chunkGUTKJMSF_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
|
|
7280
7377
|
const expansion = descriptorsScure.expand({ descriptor, network, index });
|
|
7281
7378
|
const keyInfo = expansion.expansionMap?.["@0"];
|
|
7282
7379
|
if (!keyInfo?.keyExpression) {
|
|
@@ -7419,12 +7516,13 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
|
|
|
7419
7516
|
const provider = await resolveDescriptorProvider(config, setup.walletRepository);
|
|
7420
7517
|
if (!provider) return void 0;
|
|
7421
7518
|
const allowSilentFallback = (config.walletMode ?? "auto") === "auto";
|
|
7422
|
-
const expectedContractType = setup.offchainTapscript instanceof
|
|
7519
|
+
const expectedContractType = setup.offchainTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script ? "delegate" : "default";
|
|
7423
7520
|
const factoryOpts = {
|
|
7424
7521
|
walletRepository: setup.walletRepository,
|
|
7425
7522
|
contractRepository: setup.contractRepository,
|
|
7426
7523
|
serverPubKey: setup.serverPubKey,
|
|
7427
|
-
expectedContractType
|
|
7524
|
+
expectedContractType,
|
|
7525
|
+
baselineReceivePubKey: setup.offchainTapscript.options.pubKey
|
|
7428
7526
|
};
|
|
7429
7527
|
let boot;
|
|
7430
7528
|
try {
|
|
@@ -7469,14 +7567,17 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
|
|
|
7469
7567
|
receivePubkey: existing.pubKey
|
|
7470
7568
|
};
|
|
7471
7569
|
}
|
|
7472
|
-
|
|
7473
|
-
if (
|
|
7474
|
-
descriptor = await provider.
|
|
7570
|
+
const current = hasPeekableDescriptor(provider) ? await provider.getCurrentSigningDescriptor() : void 0;
|
|
7571
|
+
if (current === void 0) {
|
|
7572
|
+
const descriptor = await provider.getNextSigningDescriptor();
|
|
7573
|
+
return {
|
|
7574
|
+
rotator: new _WalletReceiveRotator(provider, void 0, opts.logger),
|
|
7575
|
+
receivePubkey: deriveLeafPubkey(descriptor)
|
|
7576
|
+
};
|
|
7475
7577
|
}
|
|
7476
|
-
descriptor ??= await provider.getNextSigningDescriptor();
|
|
7477
7578
|
return {
|
|
7478
7579
|
rotator: new _WalletReceiveRotator(provider, void 0, opts.logger),
|
|
7479
|
-
receivePubkey: deriveLeafPubkey(
|
|
7580
|
+
receivePubkey: opts.baselineReceivePubKey ?? deriveLeafPubkey(current)
|
|
7480
7581
|
};
|
|
7481
7582
|
}
|
|
7482
7583
|
/**
|
|
@@ -7581,8 +7682,8 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
|
|
|
7581
7682
|
const newScript = base.hex.encode(newTapscript.pkScript);
|
|
7582
7683
|
const newAddress = newTapscript.address(wallet.network.hrp, wallet.arkServerPublicKey).encode();
|
|
7583
7684
|
const manager = await wallet.getContractManager();
|
|
7584
|
-
const csvTimelock = newTapscript.options.csvTimelock
|
|
7585
|
-
const csvTimelockStr =
|
|
7685
|
+
const csvTimelock = newTapscript.options.csvTimelock;
|
|
7686
|
+
const csvTimelockStr = chunkCMPJR3HS_cjs.timelockToSequence(csvTimelock).toString();
|
|
7586
7687
|
const serverPubKeyHex = base.hex.encode(newTapscript.options.serverPubKey);
|
|
7587
7688
|
const baseParams = {
|
|
7588
7689
|
script: newScript,
|
|
@@ -7596,11 +7697,11 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
|
|
|
7596
7697
|
// produce unsigned PSBTs that the server rejects with
|
|
7597
7698
|
// `INVALID_PSBT_INPUT (5): missing tapscript spend sig`.
|
|
7598
7699
|
metadata: {
|
|
7599
|
-
source:
|
|
7700
|
+
source: chunkGUTKJMSF_cjs.WALLET_RECEIVE_SOURCE,
|
|
7600
7701
|
signingDescriptor: descriptor
|
|
7601
7702
|
}
|
|
7602
7703
|
};
|
|
7603
|
-
if (newTapscript instanceof
|
|
7704
|
+
if (newTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script) {
|
|
7604
7705
|
await manager.createContract({
|
|
7605
7706
|
...baseParams,
|
|
7606
7707
|
type: "delegate",
|
|
@@ -7632,7 +7733,7 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
|
|
|
7632
7733
|
};
|
|
7633
7734
|
function deriveLeafPubkey(descriptor) {
|
|
7634
7735
|
try {
|
|
7635
|
-
return
|
|
7736
|
+
return chunkGUTKJMSF_cjs.deriveDescriptorLeafPubKey(descriptor);
|
|
7636
7737
|
} catch (e) {
|
|
7637
7738
|
throw new NonRangeableDescriptorError(
|
|
7638
7739
|
"Cannot derive leaf pubkey: descriptor is not a materialized, parsable tr(...) shape.",
|
|
@@ -7641,10 +7742,10 @@ function deriveLeafPubkey(descriptor) {
|
|
|
7641
7742
|
}
|
|
7642
7743
|
}
|
|
7643
7744
|
function rebuildTapscript(current, pubKey) {
|
|
7644
|
-
if (current instanceof
|
|
7645
|
-
return new
|
|
7745
|
+
if (current instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script) {
|
|
7746
|
+
return new chunkGUTKJMSF_cjs.DelegateVtxo.Script({ ...current.options, pubKey });
|
|
7646
7747
|
}
|
|
7647
|
-
return new
|
|
7748
|
+
return new chunkGUTKJMSF_cjs.DefaultVtxo.Script({ ...current.options, pubKey });
|
|
7648
7749
|
}
|
|
7649
7750
|
async function pickActiveReceive(contractRepository, serverPubKey, expectedType) {
|
|
7650
7751
|
const candidates = await contractRepository.getContracts({
|
|
@@ -7653,7 +7754,7 @@ async function pickActiveReceive(contractRepository, serverPubKey, expectedType)
|
|
|
7653
7754
|
});
|
|
7654
7755
|
const serverPubKeyHex = base.hex.encode(serverPubKey);
|
|
7655
7756
|
const matching = candidates.filter(
|
|
7656
|
-
(c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source ===
|
|
7757
|
+
(c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunkGUTKJMSF_cjs.WALLET_RECEIVE_SOURCE
|
|
7657
7758
|
).sort((a, b) => {
|
|
7658
7759
|
if (b.createdAt !== a.createdAt) return b.createdAt - a.createdAt;
|
|
7659
7760
|
return signingDescriptorIndex(b.metadata?.signingDescriptor) - signingDescriptorIndex(a.metadata?.signingDescriptor);
|
|
@@ -7709,13 +7810,29 @@ var DescriptorSigningProviderMissingError = class extends Error {
|
|
|
7709
7810
|
};
|
|
7710
7811
|
|
|
7711
7812
|
// src/wallet/inputSignerRouter.ts
|
|
7712
|
-
var DESCRIPTOR_CAPABLE_CONTRACT_TYPES = /* @__PURE__ */ new Set(["default", "delegate"]);
|
|
7813
|
+
var DESCRIPTOR_CAPABLE_CONTRACT_TYPES = /* @__PURE__ */ new Set(["default", "delegate", "boarding"]);
|
|
7713
7814
|
var InputSignerRouter = class {
|
|
7714
7815
|
constructor(deps) {
|
|
7715
7816
|
this.deps = deps;
|
|
7716
7817
|
}
|
|
7717
|
-
|
|
7718
|
-
|
|
7818
|
+
/**
|
|
7819
|
+
* Resolve each job to its target signer without invoking signing. The
|
|
7820
|
+
* returned plan is the single source of truth for both {@link sign} and
|
|
7821
|
+
* the batch-eligibility predicate {@link canBatch} — callers that want
|
|
7822
|
+
* to pre-flight a batch path call {@link canBatch} (which delegates
|
|
7823
|
+
* here) so the routing rules never live in two places.
|
|
7824
|
+
*
|
|
7825
|
+
* Throws {@link MissingSigningDescriptorError} for a non-baseline
|
|
7826
|
+
* default/delegate contract whose `metadata.signingDescriptor` is
|
|
7827
|
+
* missing — the same condition that would later abort signing. Failing
|
|
7828
|
+
* here moves the failure earlier, before any PSBT is mutated.
|
|
7829
|
+
*/
|
|
7830
|
+
async classify(jobs) {
|
|
7831
|
+
const identityIndexes = [];
|
|
7832
|
+
const descriptorGroups = /* @__PURE__ */ new Map();
|
|
7833
|
+
if (jobs.length === 0) {
|
|
7834
|
+
return { identityIndexes, descriptorGroups };
|
|
7835
|
+
}
|
|
7719
7836
|
const distinctScripts = Array.from(new Set(jobs.map((j) => base.hex.encode(j.lookupScript))));
|
|
7720
7837
|
const contracts = await this.deps.contractRepository.getContracts({
|
|
7721
7838
|
script: distinctScripts
|
|
@@ -7728,8 +7845,6 @@ var InputSignerRouter = class {
|
|
|
7728
7845
|
}
|
|
7729
7846
|
const baselinePubKeyHex = base.hex.encode(await this.deps.identity.xOnlyPublicKey());
|
|
7730
7847
|
const boardingScriptHex = base.hex.encode(this.deps.boardingPkScript);
|
|
7731
|
-
const identityIndexes = [];
|
|
7732
|
-
const descriptorGroups = /* @__PURE__ */ new Map();
|
|
7733
7848
|
for (const job of jobs) {
|
|
7734
7849
|
const scriptHex = base.hex.encode(job.lookupScript);
|
|
7735
7850
|
const contract = scriptToContract.get(scriptHex);
|
|
@@ -7762,6 +7877,31 @@ var InputSignerRouter = class {
|
|
|
7762
7877
|
descriptorGroups.set(descriptor, [job.index]);
|
|
7763
7878
|
}
|
|
7764
7879
|
}
|
|
7880
|
+
return { identityIndexes, descriptorGroups };
|
|
7881
|
+
}
|
|
7882
|
+
/**
|
|
7883
|
+
* Returns `true` when every signable input across all `jobSets` resolves
|
|
7884
|
+
* to the baseline {@link Identity} key — i.e. the descriptor provider
|
|
7885
|
+
* would not be invoked. Used by the wallet's send/recovery paths to
|
|
7886
|
+
* pre-flight the {@link BatchSignableIdentity.signMultiple} fast path,
|
|
7887
|
+
* which can only fold work a single identity key can sign.
|
|
7888
|
+
*
|
|
7889
|
+
* Accepts several job sets (e.g. an arkTx's jobs plus one set per
|
|
7890
|
+
* checkpoint) and classifies their union in a single pass. Eligibility
|
|
7891
|
+
* is monotonic — the union routes entirely to the baseline key iff every
|
|
7892
|
+
* set does — so this returns the same answer as ANDing the per-set
|
|
7893
|
+
* results, but with one {@link classify} (one repo round-trip + one
|
|
7894
|
+
* `xOnlyPublicKey` call) instead of one per set. Only the routing buckets
|
|
7895
|
+
* matter here, so the input-index collisions produced by flattening jobs
|
|
7896
|
+
* from different transactions are irrelevant.
|
|
7897
|
+
*/
|
|
7898
|
+
async canBatch(...jobSets) {
|
|
7899
|
+
const plan = await this.classify(jobSets.flat());
|
|
7900
|
+
return plan.descriptorGroups.size === 0;
|
|
7901
|
+
}
|
|
7902
|
+
async sign(tx, jobs) {
|
|
7903
|
+
if (jobs.length === 0) return tx;
|
|
7904
|
+
const { identityIndexes, descriptorGroups } = await this.classify(jobs);
|
|
7765
7905
|
let signed = tx;
|
|
7766
7906
|
if (identityIndexes.length > 0) {
|
|
7767
7907
|
signed = await this.deps.identity.sign(signed, identityIndexes);
|
|
@@ -7788,12 +7928,12 @@ var InputSignerRouter = class {
|
|
|
7788
7928
|
};
|
|
7789
7929
|
|
|
7790
7930
|
// src/wallet/wallet.ts
|
|
7791
|
-
var getArkadeServerUrl = ({ arkServerUrl }) => arkServerUrl ||
|
|
7931
|
+
var getArkadeServerUrl = ({ arkServerUrl }) => arkServerUrl || chunkCMPJR3HS_cjs.DEFAULT_ARKADE_SERVER_URL;
|
|
7792
7932
|
function intentProofJobs(coins) {
|
|
7793
7933
|
if (coins.length === 0) return [];
|
|
7794
7934
|
const coinJobs = coins.map((coin, i) => ({
|
|
7795
7935
|
index: i + 1,
|
|
7796
|
-
lookupScript:
|
|
7936
|
+
lookupScript: chunkCMPJR3HS_cjs.VtxoScript.decode(coin.tapTree).pkScript
|
|
7797
7937
|
}));
|
|
7798
7938
|
return [{ index: 0, lookupScript: coinJobs[0].lookupScript }, ...coinJobs];
|
|
7799
7939
|
}
|
|
@@ -7802,6 +7942,11 @@ function extractArkProviderUrl(provider) {
|
|
|
7802
7942
|
return typeof serverUrl === "string" && serverUrl.length > 0 ? serverUrl : void 0;
|
|
7803
7943
|
}
|
|
7804
7944
|
var MAINNET_UNILATERAL_EXIT_DELAY = 605184n;
|
|
7945
|
+
function toXOnlyPubKey(pubkey) {
|
|
7946
|
+
if (pubkey.length === 33) return pubkey.slice(1);
|
|
7947
|
+
if (pubkey.length === 32) return pubkey;
|
|
7948
|
+
throw new Error(`invalid signer pubkey length: expected 32 or 33, got ${pubkey.length}`);
|
|
7949
|
+
}
|
|
7805
7950
|
function delayToTimelock(delay) {
|
|
7806
7951
|
return {
|
|
7807
7952
|
value: delay,
|
|
@@ -7812,13 +7957,37 @@ function dedupeTimelocks(timelocks) {
|
|
|
7812
7957
|
const seen = /* @__PURE__ */ new Set();
|
|
7813
7958
|
const deduped = [];
|
|
7814
7959
|
for (const timelock of timelocks) {
|
|
7815
|
-
const sequence =
|
|
7960
|
+
const sequence = chunkCMPJR3HS_cjs.timelockToSequence(timelock).toString();
|
|
7816
7961
|
if (seen.has(sequence)) continue;
|
|
7817
7962
|
seen.add(sequence);
|
|
7818
7963
|
deduped.push(timelock);
|
|
7819
7964
|
}
|
|
7820
7965
|
return deduped;
|
|
7821
7966
|
}
|
|
7967
|
+
async function ensureWalletContract(manager, params) {
|
|
7968
|
+
await manager.createContract(params);
|
|
7969
|
+
}
|
|
7970
|
+
async function resolveBoardingBootTapscript(contractRepository, serverPubKey, baseline) {
|
|
7971
|
+
const serverPubKeyHex = base.hex.encode(serverPubKey);
|
|
7972
|
+
const candidates = await contractRepository.getContracts({
|
|
7973
|
+
type: ["boarding"],
|
|
7974
|
+
state: "active"
|
|
7975
|
+
});
|
|
7976
|
+
const newest = candidates.filter(
|
|
7977
|
+
(c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunkGUTKJMSF_cjs.WALLET_RECEIVE_SOURCE
|
|
7978
|
+
).sort((a, b) => {
|
|
7979
|
+
if (b.createdAt !== a.createdAt) return b.createdAt - a.createdAt;
|
|
7980
|
+
return signingDescriptorIndex(b.metadata?.signingDescriptor) - signingDescriptorIndex(a.metadata?.signingDescriptor);
|
|
7981
|
+
})[0];
|
|
7982
|
+
if (!newest?.params.pubKey) return baseline;
|
|
7983
|
+
try {
|
|
7984
|
+
const pubKey = base.hex.decode(newest.params.pubKey);
|
|
7985
|
+
return new chunkGUTKJMSF_cjs.DefaultVtxo.Script({ ...baseline.options, pubKey });
|
|
7986
|
+
} catch (e) {
|
|
7987
|
+
console.warn("Skipping malformed boarding contract at boot", newest.script, e);
|
|
7988
|
+
return baseline;
|
|
7989
|
+
}
|
|
7990
|
+
}
|
|
7822
7991
|
function hasToReadonly(identity) {
|
|
7823
7992
|
return typeof identity === "object" && identity !== null && "toReadonly" in identity && typeof identity.toReadonly === "function";
|
|
7824
7993
|
}
|
|
@@ -7829,7 +7998,6 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
7829
7998
|
this.onchainProvider = onchainProvider;
|
|
7830
7999
|
this.indexerProvider = indexerProvider;
|
|
7831
8000
|
this.arkServerPublicKey = arkServerPublicKey;
|
|
7832
|
-
this.boardingTapscript = boardingTapscript;
|
|
7833
8001
|
this.dustAmount = dustAmount;
|
|
7834
8002
|
this.walletRepository = walletRepository;
|
|
7835
8003
|
this.contractRepository = contractRepository;
|
|
@@ -7845,11 +8013,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
7845
8013
|
}
|
|
7846
8014
|
}
|
|
7847
8015
|
this._offchainTapscript = offchainTapscript;
|
|
8016
|
+
this._boardingTapscript = boardingTapscript;
|
|
7848
8017
|
this.watcherConfig = watcherConfig;
|
|
7849
8018
|
this._assetManager = new ReadonlyAssetManager(this.indexerProvider);
|
|
7850
|
-
this.walletContractTimelocks = walletContractTimelocks && walletContractTimelocks.length > 0 ? dedupeTimelocks(walletContractTimelocks) : [
|
|
7851
|
-
this.offchainTapscript.options.csvTimelock ?? chunkIEO3XDKI_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK
|
|
7852
|
-
];
|
|
8019
|
+
this.walletContractTimelocks = walletContractTimelocks && walletContractTimelocks.length > 0 ? dedupeTimelocks(walletContractTimelocks) : [this.offchainTapscript.options.csvTimelock];
|
|
7853
8020
|
}
|
|
7854
8021
|
_contractManager;
|
|
7855
8022
|
_contractManagerInitializing;
|
|
@@ -7873,6 +8040,17 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
7873
8040
|
* {@link WalletReceiveRotator.rotate} is the sole intended caller of.
|
|
7874
8041
|
*/
|
|
7875
8042
|
_offchainTapscript;
|
|
8043
|
+
/**
|
|
8044
|
+
* Backing field for the current boarding tapscript (the QR / onboarding
|
|
8045
|
+
* target). Read via the public `boardingTapscript` getter; written only
|
|
8046
|
+
* by {@link Wallet.setBoardingTapscriptForRotation}, the sanctioned
|
|
8047
|
+
* boarding-rotation write path (analogue of `_offchainTapscript`). It is
|
|
8048
|
+
* a *current value*, not a fixed setup constant, because per-derivation
|
|
8049
|
+
* boarding rotation (plan §6-II) swaps it when a fresh boarding address
|
|
8050
|
+
* is explicitly allocated. Static / `auto` wallets never rotate it, so
|
|
8051
|
+
* it stays the index-0 baseline for their lifetime.
|
|
8052
|
+
*/
|
|
8053
|
+
_boardingTapscript;
|
|
7876
8054
|
/**
|
|
7877
8055
|
* Currently-active receive tapscript. Read-only from the outside;
|
|
7878
8056
|
* mutated only via {@link Wallet.setOffchainTapscriptForRotation}
|
|
@@ -7881,13 +8059,59 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
7881
8059
|
get offchainTapscript() {
|
|
7882
8060
|
return this._offchainTapscript;
|
|
7883
8061
|
}
|
|
8062
|
+
/**
|
|
8063
|
+
* The wallet's current boarding tapscript (the on-chain onboarding
|
|
8064
|
+
* target). Read-only from the outside; mutated only via
|
|
8065
|
+
* {@link Wallet.setBoardingTapscriptForRotation} when a fresh boarding
|
|
8066
|
+
* address is explicitly allocated. Single-valued for static / `auto`
|
|
8067
|
+
* wallets.
|
|
8068
|
+
*/
|
|
8069
|
+
get boardingTapscript() {
|
|
8070
|
+
return this._boardingTapscript;
|
|
8071
|
+
}
|
|
8072
|
+
/**
|
|
8073
|
+
* Listeners fired after the boarding tapscript rotates to a fresh index
|
|
8074
|
+
* (see {@link Wallet.setBoardingTapscriptForRotation}). A live
|
|
8075
|
+
* {@link notifyIncomingFunds} onchain watcher registers one so it can
|
|
8076
|
+
* re-subscribe to include the newly allocated boarding address within the
|
|
8077
|
+
* same session — without it, a deposit to the fresh address wouldn't fire
|
|
8078
|
+
* a notification until the watcher's next re-init. Always empty for
|
|
8079
|
+
* readonly / static / `auto` wallets, which never rotate boarding.
|
|
8080
|
+
*/
|
|
8081
|
+
_boardingRotationListeners = /* @__PURE__ */ new Set();
|
|
8082
|
+
/**
|
|
8083
|
+
* Register a listener invoked synchronously after each boarding rotation.
|
|
8084
|
+
* Returns an unsubscribe function. Protected: only internal subscribers
|
|
8085
|
+
* (the incoming-funds watcher) participate.
|
|
8086
|
+
*/
|
|
8087
|
+
onBoardingRotation(listener) {
|
|
8088
|
+
this._boardingRotationListeners.add(listener);
|
|
8089
|
+
return () => {
|
|
8090
|
+
this._boardingRotationListeners.delete(listener);
|
|
8091
|
+
};
|
|
8092
|
+
}
|
|
8093
|
+
/**
|
|
8094
|
+
* Notify boarding-rotation listeners. Called by the boarding-rotation
|
|
8095
|
+
* write path ({@link Wallet.setBoardingTapscriptForRotation}) once the new
|
|
8096
|
+
* tapscript is in place. A throwing listener is isolated so it can neither
|
|
8097
|
+
* break the rotation nor starve sibling listeners.
|
|
8098
|
+
*/
|
|
8099
|
+
notifyBoardingRotation() {
|
|
8100
|
+
for (const listener of this._boardingRotationListeners) {
|
|
8101
|
+
try {
|
|
8102
|
+
listener();
|
|
8103
|
+
} catch (e) {
|
|
8104
|
+
console.warn("Boarding-rotation listener failed", e);
|
|
8105
|
+
}
|
|
8106
|
+
}
|
|
8107
|
+
}
|
|
7884
8108
|
/**
|
|
7885
8109
|
* Protected helper to set up shared wallet configuration.
|
|
7886
8110
|
* Extracts common logic used by both ReadonlyWallet.create() and Wallet.create().
|
|
7887
8111
|
*/
|
|
7888
8112
|
static async setupWalletConfig(config, pubKey) {
|
|
7889
8113
|
const arkadeServerUrl = getArkadeServerUrl(config);
|
|
7890
|
-
const arkProvider = config.arkProvider || new
|
|
8114
|
+
const arkProvider = config.arkProvider || new chunkFSAXPBGP_cjs.RestArkProvider(arkadeServerUrl);
|
|
7891
8115
|
let indexerProvider = config.indexerProvider;
|
|
7892
8116
|
if (!indexerProvider) {
|
|
7893
8117
|
let indexerUrl = config.indexerUrl;
|
|
@@ -7904,10 +8128,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
7904
8128
|
indexerUrl = arkadeServerUrl;
|
|
7905
8129
|
}
|
|
7906
8130
|
}
|
|
7907
|
-
indexerProvider = new
|
|
8131
|
+
indexerProvider = new chunkFSAXPBGP_cjs.RestIndexerProvider(indexerUrl);
|
|
7908
8132
|
}
|
|
7909
8133
|
const info = await arkProvider.getInfo();
|
|
7910
|
-
const network =
|
|
8134
|
+
const network = chunkCMPJR3HS_cjs.getNetwork(info.network);
|
|
7911
8135
|
if ("descriptor" in config.identity) {
|
|
7912
8136
|
const descriptor = config.identity.descriptor;
|
|
7913
8137
|
const identityIsMainnet = !descriptor.includes("tpub");
|
|
@@ -7954,10 +8178,11 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
7954
8178
|
serverPubKey,
|
|
7955
8179
|
csvTimelock: exitTimelock
|
|
7956
8180
|
};
|
|
7957
|
-
const offchainTapscript = !delegatePubKey ? new
|
|
7958
|
-
const boardingTapscript =
|
|
7959
|
-
|
|
7960
|
-
|
|
8181
|
+
const offchainTapscript = !delegatePubKey ? new chunkGUTKJMSF_cjs.DefaultVtxo.Script(offchainOptions) : new chunkGUTKJMSF_cjs.DelegateVtxo.Script({ ...offchainOptions, delegatePubKey });
|
|
8182
|
+
const boardingTapscript = chunkGUTKJMSF_cjs.BoardingContractHandler.createScript({
|
|
8183
|
+
pubKey: base.hex.encode(pubKey),
|
|
8184
|
+
serverPubKey: base.hex.encode(serverPubKey),
|
|
8185
|
+
csvTimelock: chunkCMPJR3HS_cjs.timelockToSequence(boardingTimelock).toString()
|
|
7961
8186
|
});
|
|
7962
8187
|
const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
|
|
7963
8188
|
const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
|
|
@@ -8120,43 +8345,59 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
8120
8345
|
await clearSyncCursor(this.walletRepository);
|
|
8121
8346
|
}
|
|
8122
8347
|
/**
|
|
8123
|
-
*
|
|
8348
|
+
* The on-chain (P2TR) addresses of every boarding tapscript this wallet
|
|
8349
|
+
* uses — the current address plus any historical rotated boarding
|
|
8350
|
+
* addresses. The aggregating boarding readers (history, notifications) fan
|
|
8351
|
+
* out over this set so deposits at previous boarding addresses are still
|
|
8352
|
+
* surfaced (plan §6-IV); {@link getBoardingAddress} stays single-valued.
|
|
8353
|
+
*/
|
|
8354
|
+
async getBoardingAddresses() {
|
|
8355
|
+
const tapscripts = await this.getBoardingTapscripts();
|
|
8356
|
+
return tapscripts.map((t) => t.onchainAddress(this.network));
|
|
8357
|
+
}
|
|
8358
|
+
/**
|
|
8359
|
+
* Build a transaction history view across the wallet's boarding addresses
|
|
8360
|
+
* (current + historical rotated; plan §6-IV.1).
|
|
8124
8361
|
*/
|
|
8125
8362
|
async getBoardingTxs() {
|
|
8126
8363
|
const utxos = [];
|
|
8127
8364
|
const commitmentsToIgnore = /* @__PURE__ */ new Set();
|
|
8128
|
-
const
|
|
8129
|
-
const txs = await this.onchainProvider.getTransactions(boardingAddress);
|
|
8365
|
+
const tapscripts = await this.getBoardingTapscripts();
|
|
8130
8366
|
const outspendCache = /* @__PURE__ */ new Map();
|
|
8131
|
-
for (const
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8367
|
+
for (const tapscript of tapscripts) {
|
|
8368
|
+
const boardingAddress = tapscript.onchainAddress(this.network);
|
|
8369
|
+
const scriptHex = base.hex.encode(tapscript.pkScript);
|
|
8370
|
+
const txs = await this.onchainProvider.getTransactions(boardingAddress);
|
|
8371
|
+
for (const tx of txs) {
|
|
8372
|
+
for (let i = 0; i < tx.vout.length; i++) {
|
|
8373
|
+
const vout = tx.vout[i];
|
|
8374
|
+
if (vout.scriptpubkey_address === boardingAddress) {
|
|
8375
|
+
let spentStatuses = outspendCache.get(tx.txid);
|
|
8376
|
+
if (!spentStatuses) {
|
|
8377
|
+
spentStatuses = await this.onchainProvider.getTxOutspends(tx.txid);
|
|
8378
|
+
outspendCache.set(tx.txid, spentStatuses);
|
|
8379
|
+
}
|
|
8380
|
+
const spentStatus = spentStatuses[i];
|
|
8381
|
+
if (spentStatus?.spent) {
|
|
8382
|
+
commitmentsToIgnore.add(spentStatus.txid);
|
|
8383
|
+
}
|
|
8384
|
+
utxos.push({
|
|
8385
|
+
txid: tx.txid,
|
|
8386
|
+
vout: i,
|
|
8387
|
+
value: Number(vout.value),
|
|
8388
|
+
status: {
|
|
8389
|
+
confirmed: tx.status.confirmed,
|
|
8390
|
+
block_time: tx.status.block_time
|
|
8391
|
+
},
|
|
8392
|
+
isUnrolled: true,
|
|
8393
|
+
virtualStatus: {
|
|
8394
|
+
state: spentStatus?.spent ? "spent" : "settled",
|
|
8395
|
+
commitmentTxIds: spentStatus?.spent ? [spentStatus.txid] : void 0
|
|
8396
|
+
},
|
|
8397
|
+
createdAt: tx.status.confirmed ? new Date(tx.status.block_time * 1e3) : /* @__PURE__ */ new Date(0),
|
|
8398
|
+
script: scriptHex
|
|
8399
|
+
});
|
|
8143
8400
|
}
|
|
8144
|
-
utxos.push({
|
|
8145
|
-
txid: tx.txid,
|
|
8146
|
-
vout: i,
|
|
8147
|
-
value: Number(vout.value),
|
|
8148
|
-
status: {
|
|
8149
|
-
confirmed: tx.status.confirmed,
|
|
8150
|
-
block_time: tx.status.block_time
|
|
8151
|
-
},
|
|
8152
|
-
isUnrolled: true,
|
|
8153
|
-
virtualStatus: {
|
|
8154
|
-
state: spentStatus?.spent ? "spent" : "settled",
|
|
8155
|
-
commitmentTxIds: spentStatus?.spent ? [spentStatus.txid] : void 0
|
|
8156
|
-
},
|
|
8157
|
-
createdAt: tx.status.confirmed ? new Date(tx.status.block_time * 1e3) : /* @__PURE__ */ new Date(0),
|
|
8158
|
-
script: base.hex.encode(this.boardingTapscript.pkScript)
|
|
8159
|
-
});
|
|
8160
8401
|
}
|
|
8161
8402
|
}
|
|
8162
8403
|
}
|
|
@@ -8186,48 +8427,130 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
8186
8427
|
};
|
|
8187
8428
|
}
|
|
8188
8429
|
/**
|
|
8189
|
-
*
|
|
8430
|
+
* The set of boarding tapscripts whose on-chain UTXOs belong to this
|
|
8431
|
+
* wallet — the current display tapscript plus every historical boarding
|
|
8432
|
+
* address it has used. Under per-derivation rotation (plan §6-II) a wallet
|
|
8433
|
+
* can hold unspent boarding UTXOs at several addresses at once, so fund
|
|
8434
|
+
* discovery / spending must enumerate them all, not just the current one
|
|
8435
|
+
* (plan §6-III.1). Deduplicated by scriptPubKey.
|
|
8436
|
+
*
|
|
8437
|
+
* Always includes the index-0 baseline (identity x-only key), which covers
|
|
8438
|
+
* the degenerate equal-delay case where the index-0 boarding row is
|
|
8439
|
+
* coalesced onto a `default` row and so isn't a `boarding`-typed contract.
|
|
8190
8440
|
*/
|
|
8191
|
-
async
|
|
8192
|
-
const
|
|
8193
|
-
const
|
|
8194
|
-
const
|
|
8195
|
-
|
|
8441
|
+
async getBoardingTapscripts() {
|
|
8442
|
+
const byScript = /* @__PURE__ */ new Map();
|
|
8443
|
+
const add = (s) => byScript.set(base.hex.encode(s.pkScript), s);
|
|
8444
|
+
const boardingCsv = this.boardingTapscript.options.csvTimelock ?? chunkGUTKJMSF_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
|
|
8445
|
+
add(
|
|
8446
|
+
new chunkGUTKJMSF_cjs.DefaultVtxo.Script({
|
|
8447
|
+
pubKey: await this.identity.xOnlyPublicKey(),
|
|
8448
|
+
serverPubKey: this.boardingTapscript.options.serverPubKey,
|
|
8449
|
+
csvTimelock: boardingCsv
|
|
8450
|
+
})
|
|
8451
|
+
);
|
|
8452
|
+
add(this.boardingTapscript);
|
|
8453
|
+
const serverPubKeyHex = base.hex.encode(this.boardingTapscript.options.serverPubKey);
|
|
8454
|
+
const boardingContracts = await this.contractRepository.getContracts({
|
|
8455
|
+
type: ["boarding"]
|
|
8196
8456
|
});
|
|
8197
|
-
|
|
8198
|
-
|
|
8457
|
+
for (const c of boardingContracts) {
|
|
8458
|
+
if (c.params.serverPubKey !== serverPubKeyHex) continue;
|
|
8459
|
+
try {
|
|
8460
|
+
add(chunkGUTKJMSF_cjs.BoardingContractHandler.createScript(c.params));
|
|
8461
|
+
} catch (e) {
|
|
8462
|
+
console.warn("Skipping malformed boarding contract", c.script, e);
|
|
8463
|
+
}
|
|
8464
|
+
}
|
|
8465
|
+
return [...byScript.values()];
|
|
8466
|
+
}
|
|
8467
|
+
/**
|
|
8468
|
+
* Fetch and cache onchain inputs (UTXOs) received at the wallet's boarding
|
|
8469
|
+
* addresses — the current address plus any historical rotated boarding
|
|
8470
|
+
* addresses that still hold unspent UTXOs (plan §6-III.1). Each UTXO is
|
|
8471
|
+
* annotated with the tapscript of the address it actually sits on, so the
|
|
8472
|
+
* spending path forfeits / exits it with the correct per-index leaves.
|
|
8473
|
+
*/
|
|
8474
|
+
async getBoardingUtxos() {
|
|
8475
|
+
const tapscripts = await this.getBoardingTapscripts();
|
|
8476
|
+
const all = [];
|
|
8477
|
+
for (const tapscript of tapscripts) {
|
|
8478
|
+
const address = tapscript.onchainAddress(this.network);
|
|
8479
|
+
const coins = await this.onchainProvider.getCoins(address);
|
|
8480
|
+
const utxos = coins.map((utxo) => extendCoinWithTapscript(tapscript, utxo));
|
|
8481
|
+
await this.walletRepository.saveUtxos(address, utxos);
|
|
8482
|
+
all.push(...utxos);
|
|
8483
|
+
}
|
|
8484
|
+
return all;
|
|
8199
8485
|
}
|
|
8200
8486
|
/**
|
|
8201
8487
|
* Subscribe to onchain and offchain notifications for newly received funds.
|
|
8202
8488
|
*
|
|
8489
|
+
* The onchain watcher tracks the full boarding-address set (current +
|
|
8490
|
+
* historical rotated). When boarding rotates *after* subscribing — e.g.
|
|
8491
|
+
* rotate-on-board allocates a fresh address via
|
|
8492
|
+
* {@link getNewBoardingAddress} — the watcher automatically re-subscribes
|
|
8493
|
+
* to widen its set, so a deposit to the new address fires a notification
|
|
8494
|
+
* within the same session (no watcher re-init required). The re-subscribe
|
|
8495
|
+
* is driven by {@link onBoardingRotation}; static / `auto` / readonly
|
|
8496
|
+
* wallets never rotate boarding, so it never fires for them.
|
|
8497
|
+
*
|
|
8203
8498
|
* @param eventCallback - Callback invoked when matching funds are detected
|
|
8204
8499
|
* @returns A function that stops the subscriptions
|
|
8205
8500
|
*/
|
|
8206
8501
|
async notifyIncomingFunds(eventCallback) {
|
|
8207
8502
|
const arkAddress = await this.getAddress();
|
|
8208
|
-
const boardingAddress = await this.getBoardingAddress();
|
|
8209
8503
|
let onchainStopFunc;
|
|
8210
8504
|
let indexerStopFunc;
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
(
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8505
|
+
let boardingRotationStopFunc;
|
|
8506
|
+
let stopped = false;
|
|
8507
|
+
let onchainChain = Promise.resolve();
|
|
8508
|
+
const subscribeOnchain = () => {
|
|
8509
|
+
onchainChain = onchainChain.then(async () => {
|
|
8510
|
+
if (stopped || !this.onchainProvider) return;
|
|
8511
|
+
const boardingAddresses = await this.getBoardingAddresses();
|
|
8512
|
+
if (boardingAddresses.length === 0) return;
|
|
8513
|
+
const boardingAddressSet = new Set(boardingAddresses);
|
|
8514
|
+
const previousStop = onchainStopFunc;
|
|
8515
|
+
const stop = await this.onchainProvider.watchAddresses(
|
|
8516
|
+
boardingAddresses,
|
|
8517
|
+
(txs) => {
|
|
8518
|
+
const coins = txs.flatMap((tx) => {
|
|
8519
|
+
const { txid, status } = tx;
|
|
8520
|
+
const matched = [];
|
|
8521
|
+
tx.vout.forEach((v, vout) => {
|
|
8522
|
+
if (boardingAddressSet.has(v.scriptpubkey_address)) {
|
|
8523
|
+
matched.push({
|
|
8524
|
+
txid,
|
|
8525
|
+
vout,
|
|
8526
|
+
value: Number(v.value),
|
|
8527
|
+
status
|
|
8528
|
+
});
|
|
8529
|
+
}
|
|
8530
|
+
});
|
|
8531
|
+
return matched;
|
|
8532
|
+
});
|
|
8533
|
+
eventCallback({
|
|
8534
|
+
type: "utxo",
|
|
8535
|
+
coins
|
|
8536
|
+
});
|
|
8537
|
+
}
|
|
8538
|
+
);
|
|
8539
|
+
if (stopped) {
|
|
8540
|
+
stop();
|
|
8541
|
+
return;
|
|
8228
8542
|
}
|
|
8229
|
-
|
|
8230
|
-
|
|
8543
|
+
onchainStopFunc = stop;
|
|
8544
|
+
previousStop?.();
|
|
8545
|
+
}).catch((e) => {
|
|
8546
|
+
console.warn("Failed to (re)subscribe boarding-funds watcher", e);
|
|
8547
|
+
});
|
|
8548
|
+
return onchainChain;
|
|
8549
|
+
};
|
|
8550
|
+
boardingRotationStopFunc = this.onBoardingRotation(() => {
|
|
8551
|
+
void subscribeOnchain();
|
|
8552
|
+
});
|
|
8553
|
+
await subscribeOnchain();
|
|
8231
8554
|
if (this.indexerProvider && arkAddress) {
|
|
8232
8555
|
const cm = await this.getContractManager();
|
|
8233
8556
|
let annotationQueue = Promise.resolve();
|
|
@@ -8256,7 +8579,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
8256
8579
|
});
|
|
8257
8580
|
}
|
|
8258
8581
|
const stopFunc = () => {
|
|
8582
|
+
stopped = true;
|
|
8583
|
+
boardingRotationStopFunc?.();
|
|
8259
8584
|
onchainStopFunc?.();
|
|
8585
|
+
onchainStopFunc = void 0;
|
|
8260
8586
|
indexerStopFunc?.();
|
|
8261
8587
|
};
|
|
8262
8588
|
return stopFunc;
|
|
@@ -8297,7 +8623,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
8297
8623
|
});
|
|
8298
8624
|
for (const contract of contracts) {
|
|
8299
8625
|
if (map.has(contract.script)) continue;
|
|
8300
|
-
const handler =
|
|
8626
|
+
const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
|
|
8301
8627
|
if (handler) {
|
|
8302
8628
|
const script = handler.createScript(contract.params);
|
|
8303
8629
|
map.set(contract.script, script);
|
|
@@ -8363,14 +8689,14 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
8363
8689
|
});
|
|
8364
8690
|
const baselinePubkey = await this.identity.xOnlyPublicKey();
|
|
8365
8691
|
for (const csvTimelock of this.walletContractTimelocks) {
|
|
8366
|
-
const csvTimelockStr =
|
|
8367
|
-
const defaultScript = new
|
|
8692
|
+
const csvTimelockStr = chunkCMPJR3HS_cjs.timelockToSequence(csvTimelock).toString();
|
|
8693
|
+
const defaultScript = new chunkGUTKJMSF_cjs.DefaultVtxo.Script({
|
|
8368
8694
|
pubKey: baselinePubkey,
|
|
8369
8695
|
serverPubKey: this.offchainTapscript.options.serverPubKey,
|
|
8370
8696
|
csvTimelock
|
|
8371
8697
|
});
|
|
8372
8698
|
const defaultScriptHex = base.hex.encode(defaultScript.pkScript);
|
|
8373
|
-
await manager
|
|
8699
|
+
await ensureWalletContract(manager, {
|
|
8374
8700
|
type: "default",
|
|
8375
8701
|
params: {
|
|
8376
8702
|
pubKey: base.hex.encode(defaultScript.options.pubKey),
|
|
@@ -8381,8 +8707,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
8381
8707
|
address: defaultScript.address(this.network.hrp, this.arkServerPublicKey).encode(),
|
|
8382
8708
|
state: "active"
|
|
8383
8709
|
});
|
|
8384
|
-
if (this.offchainTapscript instanceof
|
|
8385
|
-
const delegateScript = new
|
|
8710
|
+
if (this.offchainTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script) {
|
|
8711
|
+
const delegateScript = new chunkGUTKJMSF_cjs.DelegateVtxo.Script({
|
|
8386
8712
|
pubKey: baselinePubkey,
|
|
8387
8713
|
serverPubKey: this.offchainTapscript.options.serverPubKey,
|
|
8388
8714
|
delegatePubKey: this.offchainTapscript.options.delegatePubKey,
|
|
@@ -8403,6 +8729,23 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
8403
8729
|
});
|
|
8404
8730
|
}
|
|
8405
8731
|
}
|
|
8732
|
+
const boardingCsvTimelock = this.boardingTapscript.options.csvTimelock ?? chunkGUTKJMSF_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
|
|
8733
|
+
const baselineBoarding = new chunkGUTKJMSF_cjs.DefaultVtxo.Script({
|
|
8734
|
+
pubKey: baselinePubkey,
|
|
8735
|
+
serverPubKey: this.boardingTapscript.options.serverPubKey,
|
|
8736
|
+
csvTimelock: boardingCsvTimelock
|
|
8737
|
+
});
|
|
8738
|
+
await ensureWalletContract(manager, {
|
|
8739
|
+
type: "boarding",
|
|
8740
|
+
params: {
|
|
8741
|
+
pubKey: base.hex.encode(baselineBoarding.options.pubKey),
|
|
8742
|
+
serverPubKey: base.hex.encode(baselineBoarding.options.serverPubKey),
|
|
8743
|
+
csvTimelock: chunkCMPJR3HS_cjs.timelockToSequence(boardingCsvTimelock).toString()
|
|
8744
|
+
},
|
|
8745
|
+
script: base.hex.encode(baselineBoarding.pkScript),
|
|
8746
|
+
address: baselineBoarding.address(this.network.hrp, this.arkServerPublicKey).encode(),
|
|
8747
|
+
state: "active"
|
|
8748
|
+
});
|
|
8406
8749
|
return manager;
|
|
8407
8750
|
}
|
|
8408
8751
|
/** Dispose wallet-owned managers and release background resources. */
|
|
@@ -8500,6 +8843,72 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
8500
8843
|
setOffchainTapscriptForRotation(tapscript) {
|
|
8501
8844
|
this._offchainTapscript = tapscript;
|
|
8502
8845
|
}
|
|
8846
|
+
/**
|
|
8847
|
+
* @internal Sole write path for `boardingTapscript` after construction.
|
|
8848
|
+
* Called by {@link Wallet.getNewBoardingAddress} once the rotated
|
|
8849
|
+
* boarding contract has been persisted. External code must treat
|
|
8850
|
+
* `boardingTapscript` as read-only.
|
|
8851
|
+
*/
|
|
8852
|
+
setBoardingTapscriptForRotation(tapscript) {
|
|
8853
|
+
this._boardingTapscript = tapscript;
|
|
8854
|
+
this.notifyBoardingRotation();
|
|
8855
|
+
}
|
|
8856
|
+
/**
|
|
8857
|
+
* Allocate and return a *fresh* on-chain boarding address, rotating the
|
|
8858
|
+
* wallet's current boarding tapscript to a new HD index.
|
|
8859
|
+
*
|
|
8860
|
+
* This is the explicit boarding allocator — the analogue of dotnet's
|
|
8861
|
+
* `GetNextContract(NextContractPurpose.Boarding)`. Unlike
|
|
8862
|
+
* {@link getBoardingAddress} (a stable read of the current display
|
|
8863
|
+
* address that never burns an index), each call here:
|
|
8864
|
+
*
|
|
8865
|
+
* - allocates the next index from the shared HD stream (so boarding and
|
|
8866
|
+
* L2 receive interleave on one monotonic index);
|
|
8867
|
+
* - builds the boarding tapscript at that index with the boarding-exit
|
|
8868
|
+
* CSV;
|
|
8869
|
+
* - persists an `active` `boarding` contract tagged
|
|
8870
|
+
* {@link WALLET_RECEIVE_SOURCE} (with its `signingDescriptor`) so the
|
|
8871
|
+
* ContractWatcher monitors it, boot can restore it as the current
|
|
8872
|
+
* boarding address, and descriptor-aware signing can recover the
|
|
8873
|
+
* per-index key;
|
|
8874
|
+
* - swaps the wallet's current `boardingTapscript`.
|
|
8875
|
+
*
|
|
8876
|
+
* Gated by `walletMode`: a static / `auto` wallet has no descriptor
|
|
8877
|
+
* provider and keeps a single index-0 boarding address for its lifetime,
|
|
8878
|
+
* so this returns the existing {@link getBoardingAddress} unchanged
|
|
8879
|
+
* (no rotation, no index burned).
|
|
8880
|
+
*/
|
|
8881
|
+
async getNewBoardingAddress() {
|
|
8882
|
+
const provider = this._descriptorProvider;
|
|
8883
|
+
if (!provider) {
|
|
8884
|
+
return this.getBoardingAddress();
|
|
8885
|
+
}
|
|
8886
|
+
const descriptor = await provider.getNextSigningDescriptor();
|
|
8887
|
+
const pubKey = chunkGUTKJMSF_cjs.deriveDescriptorLeafPubKey(descriptor);
|
|
8888
|
+
const newBoarding = new chunkGUTKJMSF_cjs.DefaultVtxo.Script({
|
|
8889
|
+
...this._boardingTapscript.options,
|
|
8890
|
+
pubKey
|
|
8891
|
+
});
|
|
8892
|
+
const csvTimelock = newBoarding.options.csvTimelock ?? chunkGUTKJMSF_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
|
|
8893
|
+
const manager = await this.getContractManager();
|
|
8894
|
+
await manager.createContract({
|
|
8895
|
+
type: "boarding",
|
|
8896
|
+
params: {
|
|
8897
|
+
pubKey: base.hex.encode(pubKey),
|
|
8898
|
+
serverPubKey: base.hex.encode(newBoarding.options.serverPubKey),
|
|
8899
|
+
csvTimelock: chunkCMPJR3HS_cjs.timelockToSequence(csvTimelock).toString()
|
|
8900
|
+
},
|
|
8901
|
+
script: base.hex.encode(newBoarding.pkScript),
|
|
8902
|
+
address: newBoarding.address(this.network.hrp, this.arkServerPublicKey).encode(),
|
|
8903
|
+
state: "active",
|
|
8904
|
+
metadata: {
|
|
8905
|
+
source: chunkGUTKJMSF_cjs.WALLET_RECEIVE_SOURCE,
|
|
8906
|
+
signingDescriptor: descriptor
|
|
8907
|
+
}
|
|
8908
|
+
});
|
|
8909
|
+
this.setBoardingTapscriptForRotation(newBoarding);
|
|
8910
|
+
return newBoarding.onchainAddress(this.network);
|
|
8911
|
+
}
|
|
8503
8912
|
/**
|
|
8504
8913
|
* Async mutex that serializes all operations submitting VTXOs to the Arkade
|
|
8505
8914
|
* server (`settle`, `send`, `sendBitcoin`). This prevents VtxoManager's
|
|
@@ -8583,13 +8992,26 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
8583
8992
|
const hd = provider instanceof HDDescriptorProvider;
|
|
8584
8993
|
const staticDescriptor = hd ? void 0 : `tr(${base.hex.encode(await this.identity.xOnlyPublicKey())})`;
|
|
8585
8994
|
const materialize = (index) => hd ? provider.materializeDescriptorAt(index) : staticDescriptor;
|
|
8586
|
-
const delegatePubKey = this.offchainTapscript instanceof
|
|
8995
|
+
const delegatePubKey = this.offchainTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script ? this.offchainTapscript.options.delegatePubKey : void 0;
|
|
8996
|
+
const arkInfo = await this.arkProvider.getInfo();
|
|
8997
|
+
const currentSignerPubKey = toXOnlyPubKey(base.hex.decode(arkInfo.signerPubkey));
|
|
8998
|
+
const deprecatedSignerPubKeys = arkInfo.deprecatedSigners.map(
|
|
8999
|
+
(s) => toXOnlyPubKey(base.hex.decode(s.pubkey))
|
|
9000
|
+
);
|
|
8587
9001
|
const deps = {
|
|
8588
9002
|
indexerProvider: this.indexerProvider,
|
|
8589
9003
|
onchainProvider: this.onchainProvider,
|
|
8590
9004
|
network: { hrp: this.network.hrp },
|
|
8591
|
-
|
|
9005
|
+
// Full network for the boarding on-chain (P2TR) probe — the
|
|
9006
|
+
// `{ hrp }` shape above lacks the `bech32` data
|
|
9007
|
+
// `VtxoScript.onchainAddress` needs (plan §6-I.1).
|
|
9008
|
+
onchainNetwork: this.network,
|
|
9009
|
+
serverPubKey: currentSignerPubKey,
|
|
9010
|
+
deprecatedSignerPubKeys,
|
|
8592
9011
|
csvTimelocks: this.walletContractTimelocks,
|
|
9012
|
+
// Boarding-exit CSV so the boarding handler can build its
|
|
9013
|
+
// candidate script (distinct from the unilateral-exit matrix).
|
|
9014
|
+
boardingTimelock: this.boardingTapscript.options.csvTimelock ?? chunkGUTKJMSF_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK,
|
|
8593
9015
|
delegatePubKey
|
|
8594
9016
|
};
|
|
8595
9017
|
const result = await manager.scanContracts({
|
|
@@ -8690,7 +9112,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
8690
9112
|
let serverUnrollScript;
|
|
8691
9113
|
try {
|
|
8692
9114
|
const raw = base.hex.decode(setup.info.checkpointTapscript);
|
|
8693
|
-
serverUnrollScript =
|
|
9115
|
+
serverUnrollScript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.decode(raw);
|
|
8694
9116
|
} catch (e) {
|
|
8695
9117
|
throw new Error("Invalid checkpointTapscript from server");
|
|
8696
9118
|
}
|
|
@@ -8721,6 +9143,16 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
8721
9143
|
boot?.rotator,
|
|
8722
9144
|
boot?.provider
|
|
8723
9145
|
);
|
|
9146
|
+
if (boot?.provider) {
|
|
9147
|
+
const resolvedBoarding = await resolveBoardingBootTapscript(
|
|
9148
|
+
setup.contractRepository,
|
|
9149
|
+
setup.serverPubKey,
|
|
9150
|
+
setup.boardingTapscript
|
|
9151
|
+
);
|
|
9152
|
+
if (resolvedBoarding !== setup.boardingTapscript) {
|
|
9153
|
+
wallet.setBoardingTapscriptForRotation(resolvedBoarding);
|
|
9154
|
+
}
|
|
9155
|
+
}
|
|
8724
9156
|
await wallet.getVtxoManager();
|
|
8725
9157
|
return wallet;
|
|
8726
9158
|
}
|
|
@@ -8796,7 +9228,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
8796
9228
|
inputs: params.selectedVtxos,
|
|
8797
9229
|
changeAmount: BigInt(changeAmount)
|
|
8798
9230
|
};
|
|
8799
|
-
const outputAddress =
|
|
9231
|
+
const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(params.address);
|
|
8800
9232
|
const outputScript = BigInt(params.amount) < this.dustAmount ? outputAddress.subdustPkScript : outputAddress.pkScript;
|
|
8801
9233
|
const outputs = [
|
|
8802
9234
|
{
|
|
@@ -8863,7 +9295,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
8863
9295
|
const { fees } = await this.arkProvider.getInfo();
|
|
8864
9296
|
const estimator = new Estimator(fees.intentFee);
|
|
8865
9297
|
let amount = 0;
|
|
8866
|
-
const exitScript =
|
|
9298
|
+
const exitScript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.decode(
|
|
8867
9299
|
base.hex.decode(this.boardingTapscript.exitScript)
|
|
8868
9300
|
);
|
|
8869
9301
|
const boardingTimelock = exitScript.params.timelock;
|
|
@@ -8888,7 +9320,10 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
8888
9320
|
}
|
|
8889
9321
|
const vtxos = await this.getVtxos({ withRecoverable: true });
|
|
8890
9322
|
const filteredVtxos = [];
|
|
8891
|
-
for (const vtxo of vtxos) {
|
|
9323
|
+
for (const vtxo of byValueDescending(vtxos)) {
|
|
9324
|
+
if (filteredVtxos.length >= MAX_VTXOS_PER_SETTLEMENT) {
|
|
9325
|
+
break;
|
|
9326
|
+
}
|
|
8892
9327
|
const inputFee = estimator.evalOffchainInput({
|
|
8893
9328
|
amount: BigInt(vtxo.value),
|
|
8894
9329
|
type: vtxo.virtualStatus.state === "swept" ? "recoverable" : "vtxo",
|
|
@@ -8912,7 +9347,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
8912
9347
|
};
|
|
8913
9348
|
const outputFee = estimator.evalOffchainOutput({
|
|
8914
9349
|
amount: output.amount,
|
|
8915
|
-
script: base.hex.encode(
|
|
9350
|
+
script: base.hex.encode(chunkCMPJR3HS_cjs.ArkAddress.decode(output.address).pkScript)
|
|
8916
9351
|
});
|
|
8917
9352
|
output.amount -= BigInt(outputFee.satoshis);
|
|
8918
9353
|
if (output.amount <= this.dustAmount) {
|
|
@@ -8929,7 +9364,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
8929
9364
|
for (const [index, output] of params.outputs.entries()) {
|
|
8930
9365
|
let script;
|
|
8931
9366
|
try {
|
|
8932
|
-
const addr =
|
|
9367
|
+
const addr = chunkCMPJR3HS_cjs.ArkAddress.decode(output.address);
|
|
8933
9368
|
script = addr.pkScript;
|
|
8934
9369
|
hasOffchainOutputs = true;
|
|
8935
9370
|
} catch {
|
|
@@ -8952,7 +9387,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
8952
9387
|
}
|
|
8953
9388
|
}
|
|
8954
9389
|
let outputAssets;
|
|
8955
|
-
const destinationScript =
|
|
9390
|
+
const destinationScript = chunkCMPJR3HS_cjs.ArkAddress.decode(await this.getAddress()).pkScript;
|
|
8956
9391
|
const assetOutputIndex = findDestinationOutputIndex(outputs, destinationScript);
|
|
8957
9392
|
if (assetInputs.size > 0) {
|
|
8958
9393
|
if (assetOutputIndex === -1) {
|
|
@@ -9021,6 +9456,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9021
9456
|
eventCallback: eventCallback ? (event) => Promise.resolve(eventCallback(event)) : void 0
|
|
9022
9457
|
});
|
|
9023
9458
|
await this.updateDbAfterSettle(params.inputs, commitmentTxid);
|
|
9459
|
+
await this.maybeRotateBoardingAfterBoard(params.inputs);
|
|
9024
9460
|
return commitmentTxid;
|
|
9025
9461
|
} catch (error) {
|
|
9026
9462
|
const inputIds = params.inputs.map((i) => `${i.txid}:${i.vout}`).join(",");
|
|
@@ -9038,6 +9474,41 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9038
9474
|
});
|
|
9039
9475
|
}
|
|
9040
9476
|
}
|
|
9477
|
+
/**
|
|
9478
|
+
* Rotate the boarding address after a board (rotate-on-board trigger).
|
|
9479
|
+
*
|
|
9480
|
+
* Mirrors {@link WalletReceiveRotator}'s L2 rotation, but driven by a
|
|
9481
|
+
* board instead of a `vtxo_received` event: when a settle consumes at
|
|
9482
|
+
* least one boarding (on-chain) UTXO, the current boarding address has
|
|
9483
|
+
* served its purpose, so we allocate a fresh one via
|
|
9484
|
+
* {@link getNewBoardingAddress}. A settle that consumed only VTXOs (a
|
|
9485
|
+
* renewal / offboard) is not a board and leaves the boarding address
|
|
9486
|
+
* untouched.
|
|
9487
|
+
*
|
|
9488
|
+
* Boarding inputs are the non-VTXO coins (no `virtualStatus`), the same
|
|
9489
|
+
* discriminator {@link handleSettlementFinalizationEvent} uses; the
|
|
9490
|
+
* `typeof` guard skips arknote string inputs before the `in` test.
|
|
9491
|
+
*
|
|
9492
|
+
* No-ops for static / `auto` wallets (no descriptor provider — boarding
|
|
9493
|
+
* stays on its fixed index-0 address). Best-effort and non-fatal: the
|
|
9494
|
+
* settle has already committed and its txid must be returned, so a
|
|
9495
|
+
* rotation failure is logged and swallowed rather than thrown. Funds at
|
|
9496
|
+
* the retired boarding address remain discoverable — the old `boarding`
|
|
9497
|
+
* contract stays active and {@link getBoardingUtxos} fans out over the
|
|
9498
|
+
* full historical boarding set.
|
|
9499
|
+
*/
|
|
9500
|
+
async maybeRotateBoardingAfterBoard(inputs) {
|
|
9501
|
+
if (!this._descriptorProvider) return;
|
|
9502
|
+
const consumedBoarding = inputs.some(
|
|
9503
|
+
(input) => typeof input !== "string" && !("virtualStatus" in input)
|
|
9504
|
+
);
|
|
9505
|
+
if (!consumedBoarding) return;
|
|
9506
|
+
try {
|
|
9507
|
+
await this.getNewBoardingAddress();
|
|
9508
|
+
} catch (e) {
|
|
9509
|
+
console.warn("Failed to rotate boarding address after board", e);
|
|
9510
|
+
}
|
|
9511
|
+
}
|
|
9041
9512
|
async handleSettlementFinalizationEvent(event, inputs, forfeitOutputScript, connectorsGraph) {
|
|
9042
9513
|
const signedForfeits = [];
|
|
9043
9514
|
const isVtxo = (input) => "virtualStatus" in input;
|
|
@@ -9102,7 +9573,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9102
9573
|
index: input.vout,
|
|
9103
9574
|
witnessUtxo: {
|
|
9104
9575
|
amount: BigInt(input.value),
|
|
9105
|
-
script:
|
|
9576
|
+
script: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
|
|
9106
9577
|
},
|
|
9107
9578
|
sighashType: btcSigner.SigHash.DEFAULT,
|
|
9108
9579
|
tapLeafScript: [input.forfeitTapLeafScript]
|
|
@@ -9121,7 +9592,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9121
9592
|
forfeitTx = await this._signerRouter.sign(forfeitTx, [
|
|
9122
9593
|
{
|
|
9123
9594
|
index: 0,
|
|
9124
|
-
lookupScript:
|
|
9595
|
+
lookupScript: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
|
|
9125
9596
|
}
|
|
9126
9597
|
]);
|
|
9127
9598
|
signedForfeits.push(base.base64.encode(forfeitTx.toPSBT()));
|
|
@@ -9161,7 +9632,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9161
9632
|
if (skip) {
|
|
9162
9633
|
return { skip };
|
|
9163
9634
|
}
|
|
9164
|
-
const sweepTapscript =
|
|
9635
|
+
const sweepTapscript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.encode({
|
|
9165
9636
|
timelock: {
|
|
9166
9637
|
value: event.batchExpiry,
|
|
9167
9638
|
type: event.batchExpiry >= 512n ? "seconds" : "blocks"
|
|
@@ -9248,11 +9719,24 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9248
9719
|
}
|
|
9249
9720
|
return jobs;
|
|
9250
9721
|
}
|
|
9722
|
+
/**
|
|
9723
|
+
* @internal Sign an on-chain boarding exit / sweep transaction, routing
|
|
9724
|
+
* each input to the correct key by its `witnessUtxo.script`: the identity
|
|
9725
|
+
* for index-0 / static boarding, the per-index descriptor for a rotated
|
|
9726
|
+
* boarding UTXO (plan §6-III.3). Used by
|
|
9727
|
+
* {@link VtxoManager.sweepExpiredBoardingUtxos}; without it, the
|
|
9728
|
+
* unilateral exit of a rotated boarding UTXO would be signed with the
|
|
9729
|
+
* wrong (index-0) key and rejected.
|
|
9730
|
+
*/
|
|
9731
|
+
async signOnchainBoardingTx(tx) {
|
|
9732
|
+
const signed = await this._signerRouter.sign(tx, this.inputSigningJobsFromWitnessUtxos(tx));
|
|
9733
|
+
return signed;
|
|
9734
|
+
}
|
|
9251
9735
|
async safeRegisterIntent(intent, inputs) {
|
|
9252
9736
|
try {
|
|
9253
9737
|
return await this.arkProvider.registerIntent(intent);
|
|
9254
9738
|
} catch (error) {
|
|
9255
|
-
if (error instanceof
|
|
9739
|
+
if (error instanceof chunkFSAXPBGP_cjs.ArkError && error.code === 0 && error.message.includes("duplicated input")) {
|
|
9256
9740
|
const deleteIntent = await this.makeDeleteIntentSignature(inputs);
|
|
9257
9741
|
await this.arkProvider.deleteIntent(deleteIntent);
|
|
9258
9742
|
return this.arkProvider.registerIntent(intent);
|
|
@@ -9268,7 +9752,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9268
9752
|
expire_at: 0,
|
|
9269
9753
|
cosigners_public_keys: cosignerPubKeys
|
|
9270
9754
|
};
|
|
9271
|
-
const proof =
|
|
9755
|
+
const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, outputs);
|
|
9272
9756
|
const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
|
|
9273
9757
|
return {
|
|
9274
9758
|
proof: base.base64.encode(signedProof.toPSBT()),
|
|
@@ -9280,7 +9764,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9280
9764
|
type: "delete",
|
|
9281
9765
|
expire_at: 0
|
|
9282
9766
|
};
|
|
9283
|
-
const proof =
|
|
9767
|
+
const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, []);
|
|
9284
9768
|
const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
|
|
9285
9769
|
return {
|
|
9286
9770
|
proof: base.base64.encode(signedProof.toPSBT()),
|
|
@@ -9292,7 +9776,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9292
9776
|
type: "get-pending-tx",
|
|
9293
9777
|
expire_at: 0
|
|
9294
9778
|
};
|
|
9295
|
-
const proof =
|
|
9779
|
+
const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, []);
|
|
9296
9780
|
const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
|
|
9297
9781
|
return {
|
|
9298
9782
|
proof: base.base64.encode(signedProof.toPSBT()),
|
|
@@ -9352,16 +9836,38 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9352
9836
|
seen.add(pendingTx.arkTxid);
|
|
9353
9837
|
batchPending.push(pendingTx.arkTxid);
|
|
9354
9838
|
try {
|
|
9355
|
-
const
|
|
9356
|
-
|
|
9357
|
-
const tx = btcSigner.Transaction.fromPSBT(base.base64.decode(c));
|
|
9358
|
-
const signedCheckpoint = await this._signerRouter.sign(
|
|
9359
|
-
tx,
|
|
9360
|
-
this.inputSigningJobsFromWitnessUtxos(tx)
|
|
9361
|
-
);
|
|
9362
|
-
return base.base64.encode(signedCheckpoint.toPSBT());
|
|
9363
|
-
})
|
|
9839
|
+
const checkpointTxs = pendingTx.signedCheckpointTxs.map(
|
|
9840
|
+
(c) => btcSigner.Transaction.fromPSBT(base.base64.decode(c))
|
|
9364
9841
|
);
|
|
9842
|
+
const checkpointJobs = checkpointTxs.map(
|
|
9843
|
+
(tx) => this.inputSigningJobsFromWitnessUtxos(tx)
|
|
9844
|
+
);
|
|
9845
|
+
const identity = this.identity;
|
|
9846
|
+
const batchEligible = isBatchSignable(identity) && await this._signerRouter.canBatch(...checkpointJobs);
|
|
9847
|
+
let finalCheckpoints;
|
|
9848
|
+
if (batchEligible) {
|
|
9849
|
+
const requests = checkpointTxs.map((tx, i) => ({
|
|
9850
|
+
tx,
|
|
9851
|
+
inputIndexes: checkpointJobs[i].map((j) => j.index)
|
|
9852
|
+
}));
|
|
9853
|
+
const signed = await identity.signMultiple(requests);
|
|
9854
|
+
if (signed.length !== requests.length) {
|
|
9855
|
+
throw new Error(
|
|
9856
|
+
`signMultiple returned ${signed.length} transactions, expected ${requests.length}`
|
|
9857
|
+
);
|
|
9858
|
+
}
|
|
9859
|
+
finalCheckpoints = signed.map((tx) => base.base64.encode(tx.toPSBT()));
|
|
9860
|
+
} else {
|
|
9861
|
+
finalCheckpoints = await Promise.all(
|
|
9862
|
+
checkpointTxs.map(async (tx, i) => {
|
|
9863
|
+
const signedCheckpoint = await this._signerRouter.sign(
|
|
9864
|
+
tx,
|
|
9865
|
+
checkpointJobs[i]
|
|
9866
|
+
);
|
|
9867
|
+
return base.base64.encode(signedCheckpoint.toPSBT());
|
|
9868
|
+
})
|
|
9869
|
+
);
|
|
9870
|
+
}
|
|
9365
9871
|
await this.arkProvider.finalizeTx(pendingTx.arkTxid, finalCheckpoints);
|
|
9366
9872
|
batchFinalized.push(pendingTx.arkTxid);
|
|
9367
9873
|
} catch (error) {
|
|
@@ -9587,24 +10093,67 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9587
10093
|
);
|
|
9588
10094
|
const arkTxJobs = inputs.map((input, index) => ({
|
|
9589
10095
|
index,
|
|
9590
|
-
lookupScript:
|
|
10096
|
+
lookupScript: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
|
|
9591
10097
|
}));
|
|
9592
|
-
const
|
|
10098
|
+
const checkpointJobs = offchainTx.checkpoints.map(
|
|
10099
|
+
(c) => this.inputSigningJobsFromWitnessUtxos(c)
|
|
10100
|
+
);
|
|
10101
|
+
let signedVirtualTx;
|
|
10102
|
+
let userSignedCheckpoints;
|
|
10103
|
+
const identity = this.identity;
|
|
10104
|
+
const batchEligible = isBatchSignable(identity) && await this._signerRouter.canBatch(arkTxJobs, ...checkpointJobs);
|
|
10105
|
+
if (batchEligible) {
|
|
10106
|
+
const requests = [
|
|
10107
|
+
{
|
|
10108
|
+
tx: offchainTx.arkTx.clone(),
|
|
10109
|
+
inputIndexes: arkTxJobs.map((j) => j.index)
|
|
10110
|
+
},
|
|
10111
|
+
...offchainTx.checkpoints.map((c, i) => ({
|
|
10112
|
+
tx: c.clone(),
|
|
10113
|
+
inputIndexes: checkpointJobs[i].map((j) => j.index)
|
|
10114
|
+
}))
|
|
10115
|
+
];
|
|
10116
|
+
const signed = await identity.signMultiple(requests);
|
|
10117
|
+
if (signed.length !== requests.length) {
|
|
10118
|
+
throw new Error(
|
|
10119
|
+
`signMultiple returned ${signed.length} transactions, expected ${requests.length}`
|
|
10120
|
+
);
|
|
10121
|
+
}
|
|
10122
|
+
const [firstSignedTx, ...signedCheckpoints] = signed;
|
|
10123
|
+
signedVirtualTx = firstSignedTx;
|
|
10124
|
+
userSignedCheckpoints = signedCheckpoints;
|
|
10125
|
+
} else {
|
|
10126
|
+
signedVirtualTx = await this._signerRouter.sign(offchainTx.arkTx, arkTxJobs);
|
|
10127
|
+
}
|
|
9593
10128
|
await this.setPendingTxFlag(true);
|
|
9594
10129
|
const { arkTxid, signedCheckpointTxs } = await this.arkProvider.submitTx(
|
|
9595
10130
|
base.base64.encode(signedVirtualTx.toPSBT()),
|
|
9596
10131
|
offchainTx.checkpoints.map((c) => base.base64.encode(c.toPSBT()))
|
|
9597
10132
|
);
|
|
9598
|
-
|
|
9599
|
-
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
this.inputSigningJobsFromWitnessUtxos(tx)
|
|
10133
|
+
let finalCheckpoints;
|
|
10134
|
+
if (userSignedCheckpoints) {
|
|
10135
|
+
if (signedCheckpointTxs.length !== userSignedCheckpoints.length) {
|
|
10136
|
+
throw new Error(
|
|
10137
|
+
`submitTx returned ${signedCheckpointTxs.length} checkpoints, expected ${userSignedCheckpoints.length}`
|
|
9604
10138
|
);
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
10139
|
+
}
|
|
10140
|
+
finalCheckpoints = signedCheckpointTxs.map((c, i) => {
|
|
10141
|
+
const serverSigned = btcSigner.Transaction.fromPSBT(base.base64.decode(c));
|
|
10142
|
+
combineTapscriptSigs(userSignedCheckpoints[i], serverSigned);
|
|
10143
|
+
return base.base64.encode(serverSigned.toPSBT());
|
|
10144
|
+
});
|
|
10145
|
+
} else {
|
|
10146
|
+
finalCheckpoints = await Promise.all(
|
|
10147
|
+
signedCheckpointTxs.map(async (c) => {
|
|
10148
|
+
const tx = btcSigner.Transaction.fromPSBT(base.base64.decode(c));
|
|
10149
|
+
const signedCheckpoint = await this._signerRouter.sign(
|
|
10150
|
+
tx,
|
|
10151
|
+
this.inputSigningJobsFromWitnessUtxos(tx)
|
|
10152
|
+
);
|
|
10153
|
+
return base.base64.encode(signedCheckpoint.toPSBT());
|
|
10154
|
+
})
|
|
10155
|
+
);
|
|
10156
|
+
}
|
|
9608
10157
|
await this.arkProvider.finalizeTx(arkTxid, finalCheckpoints);
|
|
9609
10158
|
try {
|
|
9610
10159
|
await this.setPendingTxFlag(false);
|
|
@@ -9749,10 +10298,9 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9749
10298
|
// mark virtual outputs as spent/settled, remove boarding inputs
|
|
9750
10299
|
async updateDbAfterSettle(inputs, commitmentTxid) {
|
|
9751
10300
|
try {
|
|
9752
|
-
const boardingAddress = await this.getBoardingAddress();
|
|
9753
10301
|
const spentVtxos = [];
|
|
9754
10302
|
const inputArkTxIds = /* @__PURE__ */ new Set();
|
|
9755
|
-
const
|
|
10303
|
+
const boardingRemovalsByAddress = /* @__PURE__ */ new Map();
|
|
9756
10304
|
const isVtxo = (input) => "virtualStatus" in input;
|
|
9757
10305
|
const vtxoInputs = inputs.filter(isVtxo);
|
|
9758
10306
|
const cm = await this.getContractManager();
|
|
@@ -9774,7 +10322,20 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9774
10322
|
isSpent: true
|
|
9775
10323
|
});
|
|
9776
10324
|
} else {
|
|
9777
|
-
|
|
10325
|
+
let sourceAddress;
|
|
10326
|
+
try {
|
|
10327
|
+
sourceAddress = chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).onchainAddress(
|
|
10328
|
+
this.network
|
|
10329
|
+
);
|
|
10330
|
+
} catch {
|
|
10331
|
+
sourceAddress = this.boardingTapscript.onchainAddress(this.network);
|
|
10332
|
+
}
|
|
10333
|
+
let set = boardingRemovalsByAddress.get(sourceAddress);
|
|
10334
|
+
if (!set) {
|
|
10335
|
+
set = /* @__PURE__ */ new Set();
|
|
10336
|
+
boardingRemovalsByAddress.set(sourceAddress, set);
|
|
10337
|
+
}
|
|
10338
|
+
set.add(`${input.txid}:${input.vout}`);
|
|
9778
10339
|
}
|
|
9779
10340
|
}
|
|
9780
10341
|
if (spentVtxos.length > 0) {
|
|
@@ -9806,14 +10367,12 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
9806
10367
|
);
|
|
9807
10368
|
}
|
|
9808
10369
|
}
|
|
9809
|
-
|
|
9810
|
-
const currentUtxos = await this.walletRepository.getUtxos(
|
|
9811
|
-
const filtered = currentUtxos.filter(
|
|
9812
|
-
|
|
9813
|
-
);
|
|
9814
|
-
await this.walletRepository.deleteUtxos(boardingAddress);
|
|
10370
|
+
for (const [address, toRemove] of boardingRemovalsByAddress) {
|
|
10371
|
+
const currentUtxos = await this.walletRepository.getUtxos(address);
|
|
10372
|
+
const filtered = currentUtxos.filter((u) => !toRemove.has(`${u.txid}:${u.vout}`));
|
|
10373
|
+
await this.walletRepository.deleteUtxos(address);
|
|
9815
10374
|
if (filtered.length > 0) {
|
|
9816
|
-
await this.walletRepository.saveUtxos(
|
|
10375
|
+
await this.walletRepository.saveUtxos(address, filtered);
|
|
9817
10376
|
}
|
|
9818
10377
|
}
|
|
9819
10378
|
} catch (e) {
|
|
@@ -9854,12 +10413,17 @@ function selectVirtualCoins(coins, targetAmount) {
|
|
|
9854
10413
|
}
|
|
9855
10414
|
async function waitForIncomingFunds(wallet) {
|
|
9856
10415
|
let stopFunc;
|
|
10416
|
+
let settled = false;
|
|
9857
10417
|
return new Promise((resolve) => {
|
|
9858
|
-
wallet.notifyIncomingFunds((
|
|
9859
|
-
|
|
9860
|
-
if (
|
|
10418
|
+
wallet.notifyIncomingFunds((funds) => {
|
|
10419
|
+
const hasFunds = funds.type === "utxo" ? funds.coins.length > 0 : funds.newVtxos.length > 0;
|
|
10420
|
+
if (settled || !hasFunds) return;
|
|
10421
|
+
settled = true;
|
|
10422
|
+
resolve(funds);
|
|
10423
|
+
stopFunc?.();
|
|
9861
10424
|
}).then((stop) => {
|
|
9862
10425
|
stopFunc = stop;
|
|
10426
|
+
if (settled) stop();
|
|
9863
10427
|
});
|
|
9864
10428
|
});
|
|
9865
10429
|
}
|
|
@@ -10016,7 +10580,7 @@ var MessageBus = class {
|
|
|
10016
10580
|
this.initialized = true;
|
|
10017
10581
|
}
|
|
10018
10582
|
async buildServices(config) {
|
|
10019
|
-
const arkProvider = new
|
|
10583
|
+
const arkProvider = new chunkFSAXPBGP_cjs.RestArkProvider(config.arkServer.url);
|
|
10020
10584
|
const storage = {
|
|
10021
10585
|
walletRepository: this.walletRepository,
|
|
10022
10586
|
contractRepository: this.contractRepository
|
|
@@ -10392,7 +10956,7 @@ var Ramps = class {
|
|
|
10392
10956
|
}
|
|
10393
10957
|
amount = amount ?? totalAmount;
|
|
10394
10958
|
const offchainAddress = await this.wallet.getAddress();
|
|
10395
|
-
const offchainAddr =
|
|
10959
|
+
const offchainAddr = chunkCMPJR3HS_cjs.ArkAddress.decode(offchainAddress);
|
|
10396
10960
|
const offchainScript = base.hex.encode(offchainAddr.pkScript);
|
|
10397
10961
|
const outputFee = estimator.evalOffchainOutput({
|
|
10398
10962
|
amount,
|
|
@@ -10490,7 +11054,7 @@ var Ramps = class {
|
|
|
10490
11054
|
let destinationScript;
|
|
10491
11055
|
for (const networkName of networkNames) {
|
|
10492
11056
|
try {
|
|
10493
|
-
const network =
|
|
11057
|
+
const network = chunkCMPJR3HS_cjs.networks[networkName];
|
|
10494
11058
|
const addr = btcSigner.Address(network).decode(destinationAddress);
|
|
10495
11059
|
destinationScript = btcSigner.OutScript.encode(addr);
|
|
10496
11060
|
break;
|
|
@@ -11059,7 +11623,7 @@ var WalletMessageHandler = class {
|
|
|
11059
11623
|
// Wallet methods
|
|
11060
11624
|
async handleInitWallet({ payload }) {
|
|
11061
11625
|
const { arkServerUrl } = payload;
|
|
11062
|
-
this.indexerProvider = new
|
|
11626
|
+
this.indexerProvider = new chunkFSAXPBGP_cjs.RestIndexerProvider(arkServerUrl);
|
|
11063
11627
|
await this.onWalletInitialized();
|
|
11064
11628
|
}
|
|
11065
11629
|
async handleGetBalance() {
|
|
@@ -11208,9 +11772,7 @@ var WalletMessageHandler = class {
|
|
|
11208
11772
|
);
|
|
11209
11773
|
}
|
|
11210
11774
|
if (funds.type === "utxo") {
|
|
11211
|
-
const utxos =
|
|
11212
|
-
const boardingAddress = await this.readonlyWallet.getBoardingAddress();
|
|
11213
|
-
await this.walletRepository?.saveUtxos(boardingAddress, utxos);
|
|
11775
|
+
const utxos = await this.readonlyWallet.getBoardingUtxos();
|
|
11214
11776
|
this.scheduleForNextTick(
|
|
11215
11777
|
() => this.tagged({
|
|
11216
11778
|
type: "UTXO_UPDATE",
|
|
@@ -11239,13 +11801,16 @@ var WalletMessageHandler = class {
|
|
|
11239
11801
|
return;
|
|
11240
11802
|
}
|
|
11241
11803
|
const vtxos = await this.getVtxosFromRepo();
|
|
11242
|
-
const
|
|
11243
|
-
const
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
|
|
11804
|
+
const boardingAddresses = await this.readonlyWallet.getBoardingAddresses();
|
|
11805
|
+
const fresh = await this.readonlyWallet.getBoardingUtxos();
|
|
11806
|
+
const freshKeys = new Set(fresh.map((u) => `${u.txid}:${u.vout}`));
|
|
11807
|
+
for (const addr of boardingAddresses) {
|
|
11808
|
+
const cached = await this.walletRepository.getUtxos(addr);
|
|
11809
|
+
const kept = cached.filter((u) => freshKeys.has(`${u.txid}:${u.vout}`));
|
|
11810
|
+
if (kept.length === cached.length) continue;
|
|
11811
|
+
await this.walletRepository.deleteUtxos(addr);
|
|
11812
|
+
if (kept.length > 0) await this.walletRepository.saveUtxos(addr, kept);
|
|
11813
|
+
}
|
|
11249
11814
|
const address = await this.readonlyWallet.getAddress();
|
|
11250
11815
|
const txs = await this.buildTransactionHistoryFromCache(vtxos);
|
|
11251
11816
|
if (txs) await this.walletRepository.saveTransactions(address, txs);
|
|
@@ -12692,12 +13257,12 @@ var OnchainWallet = class _OnchainWallet {
|
|
|
12692
13257
|
* @returns Configured onchain wallet
|
|
12693
13258
|
* @throws Error if the configured identity cannot produce a valid x-only public key
|
|
12694
13259
|
*/
|
|
12695
|
-
static async create(identity, networkName =
|
|
13260
|
+
static async create(identity, networkName = chunkCMPJR3HS_cjs.DEFAULT_NETWORK_NAME, provider) {
|
|
12696
13261
|
const pubkey = await identity.xOnlyPublicKey();
|
|
12697
13262
|
if (!pubkey) {
|
|
12698
13263
|
throw new Error("Invalid configured public key");
|
|
12699
13264
|
}
|
|
12700
|
-
const network =
|
|
13265
|
+
const network = chunkCMPJR3HS_cjs.getNetwork(networkName);
|
|
12701
13266
|
const onchainProvider = provider || new EsploraProvider(ESPLORA_URL[networkName]);
|
|
12702
13267
|
const onchainP2TR = btcSigner.p2tr(pubkey, void 0, network);
|
|
12703
13268
|
return new _OnchainWallet(identity, network, onchainP2TR, onchainProvider);
|
|
@@ -12803,7 +13368,7 @@ var OnchainWallet = class _OnchainWallet {
|
|
|
12803
13368
|
if (!inputs) {
|
|
12804
13369
|
throw new Error("Fee estimation failed");
|
|
12805
13370
|
}
|
|
12806
|
-
let tx = new
|
|
13371
|
+
let tx = new chunkFSAXPBGP_cjs.Transaction();
|
|
12807
13372
|
for (const input of inputs) {
|
|
12808
13373
|
tx.addInput({
|
|
12809
13374
|
txid: input.txid,
|
|
@@ -12834,7 +13399,7 @@ var OnchainWallet = class _OnchainWallet {
|
|
|
12834
13399
|
*/
|
|
12835
13400
|
async bumpP2A(parent) {
|
|
12836
13401
|
const parentVsize = parent.vsize;
|
|
12837
|
-
let child = new
|
|
13402
|
+
let child = new chunkFSAXPBGP_cjs.Transaction({
|
|
12838
13403
|
version: 3,
|
|
12839
13404
|
allowLegacyWitnessUtxo: true
|
|
12840
13405
|
});
|
|
@@ -13591,7 +14156,7 @@ exports.BIP322 = void 0;
|
|
|
13591
14156
|
async function sign2(message, identity, network) {
|
|
13592
14157
|
const xOnlyPubKey = await identity.xOnlyPublicKey();
|
|
13593
14158
|
const payment = btcSigner.p2tr(xOnlyPubKey, void 0, network);
|
|
13594
|
-
const toSpend =
|
|
14159
|
+
const toSpend = chunkFSAXPBGP_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
|
|
13595
14160
|
const toSign = craftBIP322ToSignP2TR(toSpend, payment.script, xOnlyPubKey);
|
|
13596
14161
|
const signed = await identity.sign(toSign, [0]);
|
|
13597
14162
|
signed.finalizeIdx(0);
|
|
@@ -13649,7 +14214,7 @@ function verifyP2TR(message, witnessItems, pkScript, pubkey) {
|
|
|
13649
14214
|
if (sighashType !== btcSigner.SigHash.DEFAULT && sighashType !== btcSigner.SigHash.ALL) {
|
|
13650
14215
|
return false;
|
|
13651
14216
|
}
|
|
13652
|
-
const toSpend =
|
|
14217
|
+
const toSpend = chunkFSAXPBGP_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
|
|
13653
14218
|
const toSign = craftBIP322ToSignP2TR(toSpend, pkScript, pubkey);
|
|
13654
14219
|
const sighash = toSign.preimageWitnessV1(0, [pkScript], sighashType, [0n]);
|
|
13655
14220
|
const rawSig = sig.length === 65 ? sig.subarray(0, 64) : sig;
|
|
@@ -13670,7 +14235,7 @@ function verifyP2WPKH(message, witnessItems, pkScript, addressHash) {
|
|
|
13670
14235
|
}
|
|
13671
14236
|
const sighashType = sigWithHash[sigWithHash.length - 1];
|
|
13672
14237
|
const derSig = sigWithHash.subarray(0, sigWithHash.length - 1);
|
|
13673
|
-
const toSpend =
|
|
14238
|
+
const toSpend = chunkFSAXPBGP_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
|
|
13674
14239
|
const toSign = craftBIP322ToSignSimple(toSpend, pkScript);
|
|
13675
14240
|
const scriptCode = btcSigner.OutScript.encode({ type: "pkh", hash: addressHash });
|
|
13676
14241
|
const sighash = toSign.preimageWitnessV0(0, scriptCode, sighashType, 0n);
|
|
@@ -13723,7 +14288,7 @@ function encodeCompactSize(n) {
|
|
|
13723
14288
|
return buf;
|
|
13724
14289
|
}
|
|
13725
14290
|
function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
|
|
13726
|
-
const tx = new
|
|
14291
|
+
const tx = new chunkFSAXPBGP_cjs.Transaction({ version: 0 });
|
|
13727
14292
|
tx.addInput({
|
|
13728
14293
|
txid: toSpend.id,
|
|
13729
14294
|
index: 0,
|
|
@@ -13737,12 +14302,12 @@ function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
|
|
|
13737
14302
|
});
|
|
13738
14303
|
tx.addOutput({
|
|
13739
14304
|
amount: 0n,
|
|
13740
|
-
script:
|
|
14305
|
+
script: chunkFSAXPBGP_cjs.OP_RETURN_EMPTY_PKSCRIPT
|
|
13741
14306
|
});
|
|
13742
14307
|
return tx;
|
|
13743
14308
|
}
|
|
13744
14309
|
function craftBIP322ToSignSimple(toSpend, pkScript) {
|
|
13745
|
-
const tx = new
|
|
14310
|
+
const tx = new chunkFSAXPBGP_cjs.Transaction({ version: 0 });
|
|
13746
14311
|
tx.addInput({
|
|
13747
14312
|
txid: toSpend.id,
|
|
13748
14313
|
index: 0,
|
|
@@ -13754,7 +14319,7 @@ function craftBIP322ToSignSimple(toSpend, pkScript) {
|
|
|
13754
14319
|
});
|
|
13755
14320
|
tx.addOutput({
|
|
13756
14321
|
amount: 0n,
|
|
13757
|
-
script:
|
|
14322
|
+
script: chunkFSAXPBGP_cjs.OP_RETURN_EMPTY_PKSCRIPT
|
|
13758
14323
|
});
|
|
13759
14324
|
return tx;
|
|
13760
14325
|
}
|
|
@@ -13815,7 +14380,7 @@ exports.Unroll = void 0;
|
|
|
13815
14380
|
if (virtualTxs.txs.length === 0) {
|
|
13816
14381
|
throw new Error(`Tx ${nextTxToBroadcast.txid} not found`);
|
|
13817
14382
|
}
|
|
13818
|
-
const tx =
|
|
14383
|
+
const tx = chunkFSAXPBGP_cjs.Transaction.fromPSBT(base.base64.decode(virtualTxs.txs[0]));
|
|
13819
14384
|
if (nextTxToBroadcast.type === "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */) {
|
|
13820
14385
|
const input = tx.getInput(0);
|
|
13821
14386
|
if (!input) {
|
|
@@ -13892,12 +14457,12 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
|
|
|
13892
14457
|
if (!exit) {
|
|
13893
14458
|
throw new Error(`no available exit path found for vtxo ${vtxo.txid}:${vtxo.vout}`);
|
|
13894
14459
|
}
|
|
13895
|
-
const spendingLeaf =
|
|
14460
|
+
const spendingLeaf = chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree).findLeaf(base.hex.encode(exit.script));
|
|
13896
14461
|
if (!spendingLeaf) {
|
|
13897
14462
|
throw new Error(`spending leaf not found for vtxo ${vtxo.txid}:${vtxo.vout}`);
|
|
13898
14463
|
}
|
|
13899
14464
|
totalAmount += BigInt(vtxo.value);
|
|
13900
|
-
const sequence =
|
|
14465
|
+
const sequence = chunkCMPJR3HS_cjs.timelockToSequence(exit.params.timelock);
|
|
13901
14466
|
inputs.push({
|
|
13902
14467
|
txid: vtxo.txid,
|
|
13903
14468
|
index: vtxo.vout,
|
|
@@ -13905,7 +14470,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
|
|
|
13905
14470
|
sequence,
|
|
13906
14471
|
witnessUtxo: {
|
|
13907
14472
|
amount: BigInt(vtxo.value),
|
|
13908
|
-
script:
|
|
14473
|
+
script: chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree).pkScript
|
|
13909
14474
|
},
|
|
13910
14475
|
sighashType: btcSigner.SigHash.DEFAULT
|
|
13911
14476
|
});
|
|
@@ -13915,7 +14480,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
|
|
|
13915
14480
|
btcSigner.TaprootControlBlock.encode(spendingLeaf[0]).length
|
|
13916
14481
|
);
|
|
13917
14482
|
}
|
|
13918
|
-
const tx = new
|
|
14483
|
+
const tx = new chunkFSAXPBGP_cjs.Transaction({ version: 2 });
|
|
13919
14484
|
for (const input of inputs) {
|
|
13920
14485
|
tx.addInput(input);
|
|
13921
14486
|
}
|
|
@@ -13962,7 +14527,7 @@ function doWait(onchainProvider, txid) {
|
|
|
13962
14527
|
};
|
|
13963
14528
|
}
|
|
13964
14529
|
function availableExitPath(confirmedAt, current, vtxo) {
|
|
13965
|
-
const exits =
|
|
14530
|
+
const exits = chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree).exitPaths();
|
|
13966
14531
|
for (const exit of exits) {
|
|
13967
14532
|
if (exit.params.timelock.type === "blocks") {
|
|
13968
14533
|
if (current.height >= confirmedAt.height + Number(exit.params.timelock.value)) {
|
|
@@ -14001,7 +14566,7 @@ function decodeArkContract(encoded) {
|
|
|
14001
14566
|
}
|
|
14002
14567
|
function contractFromArkContract(encoded, options = {}) {
|
|
14003
14568
|
const parsed = decodeArkContract(encoded);
|
|
14004
|
-
const handler =
|
|
14569
|
+
const handler = chunkGUTKJMSF_cjs.contractHandlers.get(parsed.type);
|
|
14005
14570
|
if (!handler) {
|
|
14006
14571
|
throw new Error(`No handler registered for contract type '${parsed.type}'`);
|
|
14007
14572
|
}
|
|
@@ -14015,9 +14580,9 @@ function contractFromArkContract(encoded, options = {}) {
|
|
|
14015
14580
|
metadata: options.metadata
|
|
14016
14581
|
};
|
|
14017
14582
|
}
|
|
14018
|
-
function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix =
|
|
14583
|
+
function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix = chunkCMPJR3HS_cjs.DEFAULT_NETWORK.hrp, options = {}) {
|
|
14019
14584
|
const parsed = decodeArkContract(encoded);
|
|
14020
|
-
const handler =
|
|
14585
|
+
const handler = chunkGUTKJMSF_cjs.contractHandlers.getOrThrow(parsed.type);
|
|
14021
14586
|
const params = parsed.data;
|
|
14022
14587
|
const vtxoScript = handler.createScript(params);
|
|
14023
14588
|
return {
|
|
@@ -14129,5 +14694,5 @@ exports.validateVtxoTxGraph = validateVtxoTxGraph;
|
|
|
14129
14694
|
exports.verifyTapscriptSignatures = verifyTapscriptSignatures;
|
|
14130
14695
|
exports.waitForIncomingFunds = waitForIncomingFunds;
|
|
14131
14696
|
exports.warnAndFilterVtxosForScript = warnAndFilterVtxosForScript;
|
|
14132
|
-
//# sourceMappingURL=chunk-
|
|
14133
|
-
//# sourceMappingURL=chunk-
|
|
14697
|
+
//# sourceMappingURL=chunk-XCHBQVMK.cjs.map
|
|
14698
|
+
//# sourceMappingURL=chunk-XCHBQVMK.cjs.map
|