@arkade-os/sdk 0.4.66 → 0.4.67
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 +66 -15
- 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/{asyncStorageTaskQueue-BZcIN7sA.d.cts → asyncStorageTaskQueue-LTpeXYaD.d.cts} +2 -2
- package/dist/{asyncStorageTaskQueue-B6SijMi3.d.ts → asyncStorageTaskQueue-Za-e_zMk.d.ts} +2 -2
- package/dist/{chunk-ZIRFXBKL.cjs → chunk-2JV4VQ7C.cjs} +33 -13
- package/dist/chunk-2JV4VQ7C.cjs.map +1 -0
- package/dist/{chunk-J33ZEM3A.js → chunk-3WIWNE4P.js} +33 -14
- package/dist/chunk-3WIWNE4P.js.map +1 -0
- package/dist/{chunk-CYOI4PEA.js → chunk-6TAQF6EV.js} +107 -13
- package/dist/chunk-6TAQF6EV.js.map +1 -0
- package/dist/{chunk-DSC3G6QZ.js → chunk-AEWJU6NZ.js} +1006 -167
- package/dist/chunk-AEWJU6NZ.js.map +1 -0
- package/dist/{chunk-3S3JZUEN.cjs → chunk-CO3KKSWM.cjs} +17 -17
- package/dist/{chunk-3S3JZUEN.cjs.map → chunk-CO3KKSWM.cjs.map} +1 -1
- package/dist/{chunk-55ZZ6RBL.js → chunk-EALWOVHK.js} +4 -4
- package/dist/{chunk-55ZZ6RBL.js.map → chunk-EALWOVHK.js.map} +1 -1
- package/dist/{chunk-5E6IZNRG.cjs → chunk-MJUTO3PY.cjs} +1413 -563
- package/dist/chunk-MJUTO3PY.cjs.map +1 -0
- package/dist/{chunk-R5POS3RS.js → chunk-MZFUZUTQ.js} +4 -4
- package/dist/{chunk-R5POS3RS.js.map → chunk-MZFUZUTQ.js.map} +1 -1
- package/dist/{chunk-PXPPZF5K.cjs → chunk-OIZ2V2VD.cjs} +152 -58
- package/dist/chunk-OIZ2V2VD.cjs.map +1 -0
- package/dist/{chunk-IM6IKNSL.cjs → chunk-R2YAMONM.cjs} +17 -17
- package/dist/{chunk-IM6IKNSL.cjs.map → chunk-R2YAMONM.cjs.map} +1 -1
- package/dist/{chunk-2JZGPXU4.js → chunk-X3VEMUVV.js} +3 -3
- package/dist/{chunk-2JZGPXU4.js.map → chunk-X3VEMUVV.js.map} +1 -1
- package/dist/{chunk-LL47QIHD.cjs → chunk-YDRZDZPP.cjs} +10 -10
- package/dist/{chunk-LL47QIHD.cjs.map → chunk-YDRZDZPP.cjs.map} +1 -1
- package/dist/contracts/handlers/index.cjs +9 -9
- 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-YXupcWWJ.d.cts → delegate-Bz2e2zXY.d.cts} +1 -1
- package/dist/{delegate-T-vgxMYZ.d.ts → delegate-cdmzb2f9.d.ts} +1 -1
- package/dist/{wallet-CNibc3yJ.d.ts → hdWalletCapable-BSjuUYOO.d.cts} +318 -127
- package/dist/{wallet-DJN1QgFt.d.cts → hdWalletCapable-Hi12xjCJ.d.ts} +318 -127
- package/dist/{index-e7LYXk1d.d.cts → index-BiACuWaf.d.ts} +109 -13
- package/dist/{index-D_FgwLH9.d.ts → index-D2GjZxBr.d.cts} +109 -13
- package/dist/{index-uUE_uQPn.d.ts → index-DU5o_hz7.d.cts} +206 -19
- package/dist/{index-uUE_uQPn.d.cts → index-DU5o_hz7.d.ts} +206 -19
- package/dist/index.cjs +322 -278
- package/dist/index.d.cts +291 -41
- package/dist/index.d.ts +291 -41
- package/dist/index.js +4 -4
- package/dist/repositories/realm/index.cjs +19 -19
- package/dist/repositories/realm/index.d.cts +2 -2
- package/dist/repositories/realm/index.d.ts +2 -2
- package/dist/repositories/realm/index.js +5 -5
- package/dist/repositories/sqlite/index.cjs +18 -18
- package/dist/repositories/sqlite/index.d.cts +2 -2
- package/dist/repositories/sqlite/index.d.ts +2 -2
- package/dist/repositories/sqlite/index.js +5 -5
- package/dist/{taskRunner-BOVcIH1N.d.cts → taskRunner-BZJMLQ6g.d.cts} +2 -2
- package/dist/{taskRunner-DNyD1kXG.d.ts → taskRunner-DATaRQus.d.ts} +2 -2
- package/dist/wallet/expo/background.cjs +14 -14
- package/dist/wallet/expo/background.d.cts +3 -3
- package/dist/wallet/expo/background.d.ts +3 -3
- package/dist/wallet/expo/background.js +6 -6
- package/dist/wallet/expo/index.cjs +18 -14
- package/dist/wallet/expo/index.cjs.map +1 -1
- package/dist/wallet/expo/index.d.cts +7 -5
- package/dist/wallet/expo/index.d.ts +7 -5
- package/dist/wallet/expo/index.js +10 -6
- package/dist/wallet/expo/index.js.map +1 -1
- 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 +3 -3
- package/dist/chunk-5E6IZNRG.cjs.map +0 -1
- package/dist/chunk-CYOI4PEA.js.map +0 -1
- package/dist/chunk-DSC3G6QZ.js.map +0 -1
- package/dist/chunk-J33ZEM3A.js.map +0 -1
- package/dist/chunk-PXPPZF5K.cjs.map +0 -1
- package/dist/chunk-ZIRFXBKL.cjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AssetId, AssetGroup, AssetInput, AssetOutput, Metadata, Packet, BufferReader, BufferWriter, AssetRef, RestIndexerProvider } from './chunk-
|
|
2
|
-
import { witnessRefToBytes, validateProgram, toASM, stringifyArtifact, serializeArkadeContractParams, resolveAsm, parseArtifact, getOpcodeValue, getOpcodeName, fromASM, deserializeArkadeContractParams, computeArkadeScriptPublicKey, bytesToASM, asmToBytes, arkadeWitnessHash, arkadeScriptHash, SUPPORTED_PROGRAM_VERSION, OPCODE_VALUES, OPCODE_NAMES, bignum_exports, ArkadeScript, ArkadeProgramScript, ARKADE_OPS, ARKADE_OPCODE_VALUES, ARKADE_OPCODE_NAMES, ARKADE_OPCODES, ARKADE_OP, toXOnly, inputName, contractHandlers, isMainnetDescriptor, descriptorIsOurs, deriveDescriptorLeafPubKey, deriveDescriptorLeafCompressedPubKey, parseHDDescriptor, DefaultVtxo, speculativeReceiveMetadata, DelegateVtxo, WALLET_RECEIVE_SOURCE, BoardingContractHandler
|
|
3
|
-
import { VtxoScript, Transaction, isRecoverable, CSVMultisigTapscript, DEFAULT_NETWORK, resolveEmulatorPubkey, hasTerminalSpend, getNormalizedVtxos, setArkPsbtField, PrevArkTxField, ConditionWitness, craftToSpendTx, ArkAddress, isVirtualCoin, getArkPsbtFields, CosignerPublicKey, ServerResponseMismatchError, OP_RETURN_EMPTY_PKSCRIPT, sequenceToTimelock, decodeTapscript, scriptFromTapLeafScript, CLTVMultisigTapscript, VtxoTaprootTree, timelockToSequence, baseFetch, Intent, rateGate, DEFAULT_NETWORK_NAME, normalizeVtxo, getSequence, toBatchExpiry, maybeArkError, isArkError, ArkErrorName, toOffchainInputFeeParams, canRecoverOnchain, getNetwork, MultisigTapscript, isEventSourceError, isEventSourceUnavailableError, isRetryableProviderError, getAllNormalizedVtxos, DEFAULT_PAGE_SIZE, RestArkProvider, toVirtualStatus, ArkError, TapTreeCoder, resolveTimeHeight, canSpendOffchain, parseLegacyExpiry, isExpired, DEFAULT_ARKADE_SERVER_URL, ProviderUnavailableError, networks as networks$1, isPastExpiry, fetchVtxoCreatedAtByTxid } from './chunk-
|
|
1
|
+
import { AssetId, AssetGroup, AssetInput, AssetOutput, Metadata, Packet, BufferReader, BufferWriter, AssetRef, RestIndexerProvider } from './chunk-X3VEMUVV.js';
|
|
2
|
+
import { witnessRefToBytes, validateProgram, toASM, stringifyArtifact, serializeArkadeContractParams, resolveAsm, parseArtifact, getOpcodeValue, getOpcodeName, fromASM, deserializeArkadeContractParams, computeArkadeScriptPublicKey, bytesToASM, asmToBytes, arkadeWitnessHash, arkadeScriptHash, SUPPORTED_PROGRAM_VERSION, OPCODE_VALUES, OPCODE_NAMES, bignum_exports, ArkadeScript, ArkadeProgramScript, ARKADE_OPS, ARKADE_OPCODE_VALUES, ARKADE_OPCODE_NAMES, ARKADE_OPCODES, ARKADE_OP, toXOnly, inputName, contractHandlers, isMainnetDescriptor, descriptorIsOurs, deriveDescriptorLeafPubKey, deriveDescriptorLeafCompressedPubKey, parseHDDescriptor, identityDescriptor, DefaultVtxo, speculativeReceiveMetadata, DelegateVtxo, WALLET_RECEIVE_SOURCE, BoardingContractHandler } from './chunk-6TAQF6EV.js';
|
|
3
|
+
import { VtxoScript, Transaction, isRecoverable, CSVMultisigTapscript, DEFAULT_NETWORK, resolveEmulatorPubkey, hasTerminalSpend, getNormalizedVtxos, setArkPsbtField, PrevArkTxField, ConditionWitness, craftToSpendTx, ArkAddress, isVirtualCoin, getArkPsbtFields, CosignerPublicKey, ServerResponseMismatchError, OP_RETURN_EMPTY_PKSCRIPT, canSweepOnchain, sequenceToTimelock, decodeTapscript, scriptFromTapLeafScript, CLTVMultisigTapscript, VtxoTaprootTree, timelockToSequence, baseFetch, Intent, rateGate, DEFAULT_NETWORK_NAME, normalizeVtxo, getSequence, toBatchExpiry, maybeArkError, isArkError, ArkErrorName, toOffchainInputFeeParams, canRecoverOnchain, getNetwork, MultisigTapscript, isEventSourceError, isEventSourceUnavailableError, isRetryableProviderError, getAllNormalizedVtxos, DEFAULT_PAGE_SIZE, RestArkProvider, toVirtualStatus, ArkError, TapTreeCoder, resolveTimeHeight, canSpendOffchain, parseLegacyExpiry, isExpired, PrevoutTxField, DEFAULT_ARKADE_SERVER_URL, ProviderUnavailableError, networks as networks$1, isPastExpiry, fetchVtxoCreatedAtByTxid } from './chunk-3WIWNE4P.js';
|
|
4
4
|
import { __export } from './chunk-NSBPE2FW.js';
|
|
5
5
|
import { sha256 as sha256$1, equalBytes, hash160, sha256x2, concatBytes, randomPrivateKeyBytes, pubECDSA, pubSchnorr } from '@scure/btc-signer/utils.js';
|
|
6
6
|
import { SigHash, Script, OP, OutScript, Address, RawWitness, p2tr, p2wpkh, TaprootControlBlock, DEFAULT_SEQUENCE, Transaction as Transaction$2 } from '@scure/btc-signer';
|
|
@@ -917,6 +917,12 @@ var ForeignDescriptorError = class extends Error {
|
|
|
917
917
|
descriptor;
|
|
918
918
|
name = "ForeignDescriptorError";
|
|
919
919
|
};
|
|
920
|
+
var WalletCannotAllocateAddressError = class extends Error {
|
|
921
|
+
name = "WalletCannotAllocateAddressError";
|
|
922
|
+
constructor(reason, options) {
|
|
923
|
+
super(`cannot allocate a fresh address: ${reason}`, options);
|
|
924
|
+
}
|
|
925
|
+
};
|
|
920
926
|
async function resolveDescriptorSigner(descriptor, identity, provider) {
|
|
921
927
|
const owner = provider?.isOurs(descriptor) ? provider : isHDCapableIdentity(identity) && identity.isOurs(descriptor) ? identity : void 0;
|
|
922
928
|
if (owner && parseHDDescriptor(descriptor)) {
|
|
@@ -941,6 +947,10 @@ function isHDAllocationCapable(value) {
|
|
|
941
947
|
const v = value;
|
|
942
948
|
return typeof v.getNextSigningDescriptor === "function" && typeof v.advanceSigningDescriptorWatermark === "function";
|
|
943
949
|
}
|
|
950
|
+
function isAddressAllocationCapable(value) {
|
|
951
|
+
if (typeof value !== "object" || value === null) return false;
|
|
952
|
+
return typeof value.getNewAddresses === "function";
|
|
953
|
+
}
|
|
944
954
|
|
|
945
955
|
// ../../node_modules/@noble/hashes/utils.js
|
|
946
956
|
function isBytes(a) {
|
|
@@ -1302,15 +1312,26 @@ async function provisionDescriptor(wallet) {
|
|
|
1302
1312
|
return allocated ?? await identityDescriptor(wallet.identity);
|
|
1303
1313
|
}
|
|
1304
1314
|
async function provisionRefundKey(wallet) {
|
|
1305
|
-
const descriptor = await
|
|
1315
|
+
const descriptor = await identityDescriptor(wallet.identity);
|
|
1306
1316
|
const signer = await contractSigner(wallet, descriptor);
|
|
1307
|
-
|
|
1317
|
+
const pubkey = await signer.xOnlyPublicKey();
|
|
1318
|
+
const identityPubkey = await wallet.identity.xOnlyPublicKey();
|
|
1319
|
+
if (!equalBytes(pubkey, identityPubkey)) {
|
|
1320
|
+
throw new Error(
|
|
1321
|
+
"provisionRefundKey: descriptor pubkey does not match wallet identity \u2014 the refund key and the refund address would be on different keys"
|
|
1322
|
+
);
|
|
1323
|
+
}
|
|
1324
|
+
const address = await wallet.getAddress();
|
|
1325
|
+
const { pkScript } = ArkAddress.decode(address);
|
|
1326
|
+
return { descriptor, pubkey, pkScript, address };
|
|
1308
1327
|
}
|
|
1309
1328
|
async function provisionClaimSecret(wallet, opts = {}) {
|
|
1310
1329
|
if (opts.preimage && opts.preimage.length !== 32) {
|
|
1311
1330
|
throw new Error(`preimage must be 32 bytes, got ${opts.preimage.length}`);
|
|
1312
1331
|
}
|
|
1313
|
-
const
|
|
1332
|
+
const descriptor = await provisionDescriptor(wallet);
|
|
1333
|
+
const signer = await contractSigner(wallet, descriptor);
|
|
1334
|
+
const pubkey = await signer.xOnlyPublicKey();
|
|
1314
1335
|
const claim = async () => {
|
|
1315
1336
|
if (opts.preimage) return { preimage: opts.preimage, mustPersistPreimage: true };
|
|
1316
1337
|
if (isPerArtifactDescriptor(descriptor)) {
|
|
@@ -1610,8 +1631,6 @@ var RestDelegatorProvider = RestDelegateProvider;
|
|
|
1610
1631
|
function isDelegateInfo(data) {
|
|
1611
1632
|
return !!data && typeof data === "object" && "pubkey" in data && "fee" in data && typeof data.pubkey === "string" && typeof data.fee === "string" && data.pubkey !== "" && data.fee !== "" && (typeof data.delegateAddress === "string" && data.delegateAddress !== "" || typeof data.delegatorAddress === "string" && data.delegatorAddress !== "");
|
|
1612
1633
|
}
|
|
1613
|
-
|
|
1614
|
-
// src/providers/onchain.ts
|
|
1615
1634
|
var ESPLORA_URL = {
|
|
1616
1635
|
bitcoin: "https://mempool.arkade.sh/api",
|
|
1617
1636
|
testnet: "https://mempool.space/testnet/api",
|
|
@@ -1672,6 +1691,14 @@ var EsploraProvider = class {
|
|
|
1672
1691
|
}
|
|
1673
1692
|
return response.json();
|
|
1674
1693
|
}
|
|
1694
|
+
async getRawTransaction(txid) {
|
|
1695
|
+
const response = await baseFetch(`${this.baseUrl}/tx/${txid}/hex`);
|
|
1696
|
+
if (!response.ok) {
|
|
1697
|
+
const error = await response.text();
|
|
1698
|
+
throw new Error(`Failed to get raw transaction ${txid}: ${error}`);
|
|
1699
|
+
}
|
|
1700
|
+
return hex.decode((await response.text()).trim());
|
|
1701
|
+
}
|
|
1675
1702
|
async getTxStatus(txid) {
|
|
1676
1703
|
const txresponse = await baseFetch(`${this.baseUrl}/tx/${txid}`);
|
|
1677
1704
|
if (!txresponse.ok) {
|
|
@@ -1795,7 +1822,9 @@ var EsploraProvider = class {
|
|
|
1795
1822
|
const error = await response.text();
|
|
1796
1823
|
throw new Error(`Failed to broadcast package: ${error}`);
|
|
1797
1824
|
}
|
|
1798
|
-
|
|
1825
|
+
const result = await response.json();
|
|
1826
|
+
assertPackageAccepted(result);
|
|
1827
|
+
return result;
|
|
1799
1828
|
}
|
|
1800
1829
|
async broadcastTx(tx) {
|
|
1801
1830
|
const response = await baseFetch(`${this.baseUrl}/tx`, {
|
|
@@ -1812,6 +1841,24 @@ var EsploraProvider = class {
|
|
|
1812
1841
|
return response.text();
|
|
1813
1842
|
}
|
|
1814
1843
|
};
|
|
1844
|
+
function assertPackageAccepted(result) {
|
|
1845
|
+
if (!result || typeof result !== "object") return;
|
|
1846
|
+
const r = result;
|
|
1847
|
+
const msg = typeof r.package_msg === "string" ? r.package_msg : void 0;
|
|
1848
|
+
if (msg === void 0 || msg === "success") return;
|
|
1849
|
+
const reasons = [];
|
|
1850
|
+
const results = r["tx-results"];
|
|
1851
|
+
if (results && typeof results === "object") {
|
|
1852
|
+
for (const entry of Object.values(results)) {
|
|
1853
|
+
if (!entry || typeof entry !== "object" || entry.error === void 0) continue;
|
|
1854
|
+
const txid = typeof entry.txid === "string" ? entry.txid : "unknown tx";
|
|
1855
|
+
reasons.push(`${txid}: ${String(entry.error)}`);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
throw new Error(
|
|
1859
|
+
reasons.length > 0 ? `Package rejected (${msg}) \u2014 ${reasons.join("; ")}` : `Package rejected (${msg})`
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1815
1862
|
function isValidBlocksTip(tip) {
|
|
1816
1863
|
return Array.isArray(tip) && tip.every((t) => {
|
|
1817
1864
|
return t && typeof t === "object" && typeof t.id === "string" && t.id.length > 0 && typeof t.height === "number" && t.height >= 0 && typeof t.mediantime === "number" && t.mediantime > 0;
|
|
@@ -3709,7 +3756,9 @@ function selectPendingRecoveryOutpoints(contractsWithVtxos, signerSet, nowSecond
|
|
|
3709
3756
|
continue;
|
|
3710
3757
|
}
|
|
3711
3758
|
for (const v of vtxos) {
|
|
3712
|
-
if (!hasTerminalSpend(v) && !v.isSwept
|
|
3759
|
+
if (!hasTerminalSpend(v) && !v.isSwept && !v.isUnrolled) {
|
|
3760
|
+
out.add(`${v.txid}:${v.vout}`);
|
|
3761
|
+
}
|
|
3713
3762
|
}
|
|
3714
3763
|
}
|
|
3715
3764
|
return out;
|
|
@@ -4518,6 +4567,7 @@ var VtxoManager = class _VtxoManager {
|
|
|
4518
4567
|
async getDeprecatedSignerStatus() {
|
|
4519
4568
|
const wallet = this.requireMigrationCapableWallet();
|
|
4520
4569
|
const info = await wallet.arkProvider.getInfo();
|
|
4570
|
+
await wallet.settleServerInfoChanges?.();
|
|
4521
4571
|
const { reports: vtxoReports } = await this.classifyDeprecatedSignerContracts(info);
|
|
4522
4572
|
const { reports: boardingReports } = await this.classifyDeprecatedSignerBoarding(info);
|
|
4523
4573
|
return mergeSignerReports(vtxoReports, boardingReports);
|
|
@@ -4531,26 +4581,33 @@ var VtxoManager = class _VtxoManager {
|
|
|
4531
4581
|
*/
|
|
4532
4582
|
async migrateCore(options) {
|
|
4533
4583
|
const wallet = this.requireMigrationCapableWallet();
|
|
4584
|
+
const signerBeforeRefresh = hex.encode(wallet.arkServerPublicKey);
|
|
4534
4585
|
const info = await wallet.arkProvider.getInfo();
|
|
4586
|
+
await wallet.settleServerInfoChanges?.();
|
|
4587
|
+
const rotatedOnRefresh = signerBeforeRefresh !== hex.encode(wallet.arkServerPublicKey);
|
|
4535
4588
|
wallet.refreshDeprecatedSigners(info);
|
|
4536
4589
|
const signerSet = signerSetFromInfo(info);
|
|
4537
4590
|
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
4538
4591
|
const walletSignerHex = hex.encode(wallet.arkServerPublicKey);
|
|
4539
4592
|
const walletClass = classifyAgainstSignerSet(walletSignerHex, signerSet, nowSeconds);
|
|
4540
4593
|
if (signerSet.deprecated.size === 0 && walletClass.status === "CURRENT") {
|
|
4541
|
-
return { rotated:
|
|
4594
|
+
return { rotated: rotatedOnRefresh, expired: [], signers: [] };
|
|
4542
4595
|
}
|
|
4543
4596
|
if (walletClass.status === "UNKNOWN_SIGNER") {
|
|
4544
4597
|
const { reports: vtxoReports2 } = await this.classifyDeprecatedSignerContracts(info);
|
|
4545
4598
|
const { reports: boardingReports2 } = await this.classifyDeprecatedSignerBoarding(info);
|
|
4546
4599
|
return {
|
|
4547
|
-
|
|
4600
|
+
// Normally false here — a drained rotation targets the active
|
|
4601
|
+
// signer, which classifies CURRENT, not UNKNOWN. It is true only
|
|
4602
|
+
// when a second rotation landed inside the drain, leaving us on a
|
|
4603
|
+
// signer newer than `info`: still a rotation this pass applied.
|
|
4604
|
+
rotated: rotatedOnRefresh,
|
|
4548
4605
|
expired: [],
|
|
4549
4606
|
signers: mergeSignerReports(vtxoReports2, boardingReports2),
|
|
4550
4607
|
skipped: "unknown-wallet-signer"
|
|
4551
4608
|
};
|
|
4552
4609
|
}
|
|
4553
|
-
const rotated = await this.ensureReceiveOnActiveSigner(info);
|
|
4610
|
+
const rotated = await this.ensureReceiveOnActiveSigner(info) || rotatedOnRefresh;
|
|
4554
4611
|
const {
|
|
4555
4612
|
reports: vtxoReports,
|
|
4556
4613
|
migratable: vtxoMigratable,
|
|
@@ -4719,8 +4776,9 @@ var VtxoManager = class _VtxoManager {
|
|
|
4719
4776
|
if (!serverPubKey) continue;
|
|
4720
4777
|
const cls = classifyAgainstSignerSet(serverPubKey, signerSet, nowSeconds);
|
|
4721
4778
|
if (cls.status === "CURRENT") continue;
|
|
4722
|
-
const
|
|
4723
|
-
const
|
|
4779
|
+
const live = vtxos.filter((v) => !v.isUnrolled);
|
|
4780
|
+
const recoverable = live.filter((v) => v.isSwept && !hasTerminalSpend(v));
|
|
4781
|
+
const spendable = live.filter((v) => !hasTerminalSpend(v) && !v.isSwept);
|
|
4724
4782
|
const value = spendable.reduce((sum, v) => sum + v.value, 0);
|
|
4725
4783
|
let recoverableCount = 0;
|
|
4726
4784
|
let recoverableValue = 0;
|
|
@@ -8985,7 +9043,7 @@ var NON_TERMINAL_INTENT_STATES = ALL_INTENT_STATES.filter(
|
|
|
8985
9043
|
(s) => !isTerminalIntentState(s)
|
|
8986
9044
|
);
|
|
8987
9045
|
function isConsumed(vtxo) {
|
|
8988
|
-
return vtxo !== void 0 && (vtxo
|
|
9046
|
+
return vtxo !== void 0 && hasTerminalSpend(vtxo);
|
|
8989
9047
|
}
|
|
8990
9048
|
async function classifyIntent(intent, vtxosByOutpoint, now) {
|
|
8991
9049
|
if (isTerminalIntentState(intent.state)) return void 0;
|
|
@@ -8995,6 +9053,11 @@ async function classifyIntent(intent, vtxosByOutpoint, now) {
|
|
|
8995
9053
|
const commitmentTransactionId = intent.commitmentTransactionId ?? consumed.map((v) => v?.settledBy).find((s) => !!s);
|
|
8996
9054
|
return terminal(intent, "batch_succeeded", now, { commitmentTransactionId });
|
|
8997
9055
|
}
|
|
9056
|
+
if (consumed.some((vtxo) => vtxo?.isUnrolled)) {
|
|
9057
|
+
return terminal(intent, "cancelled", now, {
|
|
9058
|
+
cancellationReason: "reconciliation: an input was unilaterally exited"
|
|
9059
|
+
});
|
|
9060
|
+
}
|
|
8998
9061
|
if (intent.state === "waiting_to_submit") {
|
|
8999
9062
|
return terminal(intent, "cancelled", now, {
|
|
9000
9063
|
cancellationReason: "reconciliation: intent was never submitted before restart"
|
|
@@ -11604,7 +11667,9 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
|
|
|
11604
11667
|
const { tapscript: newTapscript, params } = buildReceiveContract(
|
|
11605
11668
|
wallet.offchainTapscript,
|
|
11606
11669
|
descriptor,
|
|
11607
|
-
wallet.network.hrp
|
|
11670
|
+
wallet.network.hrp,
|
|
11671
|
+
true
|
|
11672
|
+
);
|
|
11608
11673
|
const newScript = params.script;
|
|
11609
11674
|
const manager = await wallet.getContractManager();
|
|
11610
11675
|
await manager.createContract(params);
|
|
@@ -11646,7 +11711,7 @@ function buildReceiveContract(current, descriptor, hrp, tagSource) {
|
|
|
11646
11711
|
// index-0 key. Without it, spends produce unsigned PSBTs that the
|
|
11647
11712
|
// server rejects with `INVALID_PSBT_INPUT (5): missing tapscript spend sig`.
|
|
11648
11713
|
metadata: {
|
|
11649
|
-
...{ source: WALLET_RECEIVE_SOURCE },
|
|
11714
|
+
...tagSource && { source: WALLET_RECEIVE_SOURCE },
|
|
11650
11715
|
signingDescriptor: descriptor
|
|
11651
11716
|
}
|
|
11652
11717
|
};
|
|
@@ -11730,6 +11795,7 @@ function computeOffchainBalance(vtxos, caps) {
|
|
|
11730
11795
|
let intentLocked = 0;
|
|
11731
11796
|
let recoverable = 0;
|
|
11732
11797
|
let pendingRecovery = 0;
|
|
11798
|
+
let unrolled = 0;
|
|
11733
11799
|
const owned = /* @__PURE__ */ new Map();
|
|
11734
11800
|
const spendable = /* @__PURE__ */ new Map();
|
|
11735
11801
|
const addAssets = (into, vtxo) => {
|
|
@@ -11740,6 +11806,10 @@ function computeOffchainBalance(vtxos, caps) {
|
|
|
11740
11806
|
for (const vtxo of vtxos) {
|
|
11741
11807
|
if (hasTerminalSpend(vtxo)) continue;
|
|
11742
11808
|
addAssets(owned, vtxo);
|
|
11809
|
+
if (vtxo.isUnrolled) {
|
|
11810
|
+
unrolled += vtxo.value;
|
|
11811
|
+
continue;
|
|
11812
|
+
}
|
|
11743
11813
|
if (isPendingRecovery(vtxo)) {
|
|
11744
11814
|
pendingRecovery += vtxo.value;
|
|
11745
11815
|
continue;
|
|
@@ -11772,7 +11842,8 @@ function computeOffchainBalance(vtxos, caps) {
|
|
|
11772
11842
|
intentLocked,
|
|
11773
11843
|
recoverable,
|
|
11774
11844
|
pendingRecovery,
|
|
11775
|
-
|
|
11845
|
+
unrolled,
|
|
11846
|
+
total: settled + preconfirmed + recoverable + pendingRecovery + unrolled,
|
|
11776
11847
|
assets: toAssets(owned),
|
|
11777
11848
|
availableAssets: toAssets(spendable)
|
|
11778
11849
|
};
|
|
@@ -11995,13 +12066,16 @@ function filterSnapshotVtxos(snapshot, filter, pendingSpendOutpoints) {
|
|
|
11995
12066
|
if (pendingSpendOutpoints.has(`${vtxo.txid}:${vtxo.vout}`)) {
|
|
11996
12067
|
return false;
|
|
11997
12068
|
}
|
|
11998
|
-
if (
|
|
11999
|
-
|
|
12000
|
-
return false;
|
|
12001
|
-
}
|
|
12002
|
-
return true;
|
|
12069
|
+
if (vtxo.isUnrolled) {
|
|
12070
|
+
return !!f.withUnrolled;
|
|
12003
12071
|
}
|
|
12004
|
-
|
|
12072
|
+
if (hasTerminalSpend(vtxo)) {
|
|
12073
|
+
return false;
|
|
12074
|
+
}
|
|
12075
|
+
if (!f.withRecoverable && canRecoverOnchain(vtxo, now)) {
|
|
12076
|
+
return false;
|
|
12077
|
+
}
|
|
12078
|
+
return true;
|
|
12005
12079
|
});
|
|
12006
12080
|
}
|
|
12007
12081
|
var PENDING_RECOVERY_REASON = "is past its operator signer's rotation cutoff \u2014 the operator will not co-sign it until it recovers";
|
|
@@ -12504,7 +12578,11 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
12504
12578
|
this.getBoardingUtxos(),
|
|
12505
12579
|
this.contractSnapshot()
|
|
12506
12580
|
]);
|
|
12507
|
-
const vtxos = filterSnapshotVtxos(
|
|
12581
|
+
const vtxos = filterSnapshotVtxos(
|
|
12582
|
+
snapshot,
|
|
12583
|
+
{ withRecoverable: true, withUnrolled: true },
|
|
12584
|
+
this._pendingSpendOutpoints
|
|
12585
|
+
);
|
|
12508
12586
|
let confirmed = 0;
|
|
12509
12587
|
let unconfirmed = 0;
|
|
12510
12588
|
for (const utxo of boardingUtxos) {
|
|
@@ -12532,6 +12610,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
12532
12610
|
intentLocked: offchain.intentLocked,
|
|
12533
12611
|
recoverable: offchain.recoverable,
|
|
12534
12612
|
pendingRecovery: offchain.pendingRecovery,
|
|
12613
|
+
unrolled: offchain.unrolled,
|
|
12535
12614
|
total: totalBoarding + offchain.total,
|
|
12536
12615
|
assets: offchain.assets,
|
|
12537
12616
|
availableAssets: offchain.availableAssets
|
|
@@ -13391,6 +13470,27 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
13391
13470
|
console.warn("server-signer rotation on info change failed", e);
|
|
13392
13471
|
}
|
|
13393
13472
|
}
|
|
13473
|
+
/**
|
|
13474
|
+
* Await an `onServerInfoChanged` handler still applying a rotation.
|
|
13475
|
+
*
|
|
13476
|
+
* The provider emits synchronously but {@link handleServerInfoChanged} runs
|
|
13477
|
+
* off the emit, so between the two a caller can observe a half-applied
|
|
13478
|
+
* rotation: {@link rotateServerSigner} persists the active signer's contract
|
|
13479
|
+
* rows *before* committing the tapscripts, so `arkServerPublicKey` still
|
|
13480
|
+
* reads the old key while the new key's rows are already in the repository.
|
|
13481
|
+
* A path that refreshes server info and then reads signer-derived state must
|
|
13482
|
+
* drain the chain first, or it both reads that torn state and races the
|
|
13483
|
+
* handler for the rotation itself.
|
|
13484
|
+
*
|
|
13485
|
+
* Resolves once the chain is idle; a handler that threw already logged, and
|
|
13486
|
+
* its rejection is swallowed here.
|
|
13487
|
+
*
|
|
13488
|
+
* @internal Invoked by {@link dispose} and the {@link VtxoManager} migration
|
|
13489
|
+
* pass; not part of the stable public API.
|
|
13490
|
+
*/
|
|
13491
|
+
async settleServerInfoChanges() {
|
|
13492
|
+
await this._serverInfoInFlight?.catch(() => void 0);
|
|
13493
|
+
}
|
|
13394
13494
|
_receiveRotatorInstalled = false;
|
|
13395
13495
|
/**
|
|
13396
13496
|
* Descriptor-aware signer used by {@link _signerRouter} to sign
|
|
@@ -13525,43 +13625,250 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
13525
13625
|
* provider and keeps a single index-0 boarding address for its lifetime,
|
|
13526
13626
|
* so this returns the existing {@link getBoardingAddress} unchanged
|
|
13527
13627
|
* (no rotation, no index burned).
|
|
13628
|
+
*
|
|
13629
|
+
* **Behaviour change.** A wallet configured with a custom
|
|
13630
|
+
* {@link DescriptorProvider} (`walletMode: <provider>`) now rotates here.
|
|
13631
|
+
* It previously did not: allocation went through the contract manager,
|
|
13632
|
+
* which only wires an `allocate` hook for {@link HDDescriptorProvider}, so
|
|
13633
|
+
* such a wallet read as "declined to allocate" and silently kept its
|
|
13634
|
+
* index-0 boarding address forever. Those wallets now burn an index per
|
|
13635
|
+
* call — including via {@link maybeRotateBoardingAfterBoard}, which fires
|
|
13636
|
+
* on every settle that consumes a boarding UTXO. Funds at retired
|
|
13637
|
+
* addresses stay reachable: each rotation persists its `boarding` contract
|
|
13638
|
+
* before swapping, and {@link getBoardingUtxos} fans out over the full
|
|
13639
|
+
* historical set.
|
|
13640
|
+
*
|
|
13641
|
+
* @deprecated Use {@link getNewAddresses} — it mints any combination of
|
|
13642
|
+
* address types at one shared index, and reports the contract row behind
|
|
13643
|
+
* each. Note the difference in display behaviour: this method *swaps* the
|
|
13644
|
+
* advertised boarding address, where `getNewAddresses` mints side
|
|
13645
|
+
* addresses and leaves {@link getBoardingAddress} alone. To keep this
|
|
13646
|
+
* method's behaviour, keep calling this method.
|
|
13528
13647
|
*/
|
|
13529
13648
|
async getNewBoardingAddress() {
|
|
13530
|
-
const
|
|
13531
|
-
if (!
|
|
13532
|
-
|
|
13649
|
+
const [minted] = await this.allocateAddresses(["boarding"], false, true);
|
|
13650
|
+
if (!minted?.allocated) return this.getBoardingAddress();
|
|
13651
|
+
if (minted.type === "boarding") this.setBoardingTapscriptForRotation(minted.tapscript);
|
|
13652
|
+
return minted.address;
|
|
13653
|
+
}
|
|
13654
|
+
/**
|
|
13655
|
+
* Allocate a *fresh* address of each requested type, all derived from one
|
|
13656
|
+
* newly allocated HD index.
|
|
13657
|
+
*
|
|
13658
|
+
* This is the explicit allocator the receive path otherwise lacks:
|
|
13659
|
+
* {@link getAddress} and {@link getBoardingAddress} are stable reads of the
|
|
13660
|
+
* wallet's display addresses, and the display receive address only advances
|
|
13661
|
+
* when a payment arrives ({@link WalletReceiveRotator} rotates on
|
|
13662
|
+
* `vtxo_received`). Issuing a second address before the first is paid — one
|
|
13663
|
+
* invoice for Alice, another for Bob — has to go through here.
|
|
13664
|
+
*
|
|
13665
|
+
* Each call:
|
|
13666
|
+
*
|
|
13667
|
+
* - allocates **one** index from the shared HD stream, however many types
|
|
13668
|
+
* were asked for, so a `default` + `boarding` pair are siblings rather
|
|
13669
|
+
* than two burnt indices;
|
|
13670
|
+
* - builds each requested script at that index, preserving every other
|
|
13671
|
+
* option of the wallet's current script for that flavour (including a
|
|
13672
|
+
* delegate wallet's `delegate` shape);
|
|
13673
|
+
* - persists each as an `active` contract carrying its `signingDescriptor`,
|
|
13674
|
+
* so the ContractWatcher monitors it, the balance counts it, and
|
|
13675
|
+
* {@link signerForDescriptor} can recover the key;
|
|
13676
|
+
* - slides the look-ahead band, since the watermark moved past indices an
|
|
13677
|
+
* external issuer may still be handing out.
|
|
13678
|
+
*
|
|
13679
|
+
* The minted rows are deliberately left **untagged**: the boot lookups
|
|
13680
|
+
* adopt the newest {@link WALLET_RECEIVE_SOURCE}-tagged row as the display
|
|
13681
|
+
* address, and a side address issued to one counterparty must not become
|
|
13682
|
+
* the address the wallet advertises to everyone else. {@link getAddress}
|
|
13683
|
+
* and {@link getBoardingAddress} are unchanged by this call.
|
|
13684
|
+
*
|
|
13685
|
+
* A wallet with no HD stream (`walletMode: 'static'` / `'auto'`) has one
|
|
13686
|
+
* address per flavour for its lifetime. Without `forceNew` it returns those
|
|
13687
|
+
* — the real persisted rows, no index burned; with `forceNew` it throws
|
|
13688
|
+
* {@link WalletCannotAllocateAddressError} rather than hand back an address
|
|
13689
|
+
* that is not in fact fresh.
|
|
13690
|
+
*
|
|
13691
|
+
* @example
|
|
13692
|
+
* ```typescript
|
|
13693
|
+
* const [invoice] = await wallet.getNewAddresses({ forceNew: true });
|
|
13694
|
+
* // hand `invoice.address` to Alice, keep the descriptor with the invoice
|
|
13695
|
+
* const signer = await wallet.signerForDescriptor(invoice.signingDescriptor);
|
|
13696
|
+
* ```
|
|
13697
|
+
*/
|
|
13698
|
+
async getNewAddresses(opts) {
|
|
13699
|
+
const minted = await this.allocateAddresses(
|
|
13700
|
+
opts?.types ?? ["default"],
|
|
13701
|
+
opts?.forceNew ?? false,
|
|
13702
|
+
false
|
|
13703
|
+
);
|
|
13704
|
+
return minted.map(({ address, signingDescriptor, contract }) => ({
|
|
13705
|
+
address,
|
|
13706
|
+
signingDescriptor,
|
|
13707
|
+
contract
|
|
13708
|
+
}));
|
|
13709
|
+
}
|
|
13710
|
+
/**
|
|
13711
|
+
* Shared allocation core behind {@link getNewAddresses} and the deprecated
|
|
13712
|
+
* {@link getNewBoardingAddress}, so the two cannot drift on what an
|
|
13713
|
+
* allocation costs or what gets persisted.
|
|
13714
|
+
*
|
|
13715
|
+
* @param tagSource - Tag the persisted rows {@link WALLET_RECEIVE_SOURCE},
|
|
13716
|
+
* making the next boot adopt them as the display address. Only the
|
|
13717
|
+
* deprecated boarding allocator passes `true`; `getNewAddresses` mints side
|
|
13718
|
+
* addresses and must not hijack what the wallet advertises.
|
|
13719
|
+
*/
|
|
13720
|
+
async allocateAddresses(types, forceNew, tagSource) {
|
|
13721
|
+
if (types.length === 0) {
|
|
13722
|
+
throw new Error("getNewAddresses: `types` must name at least one address type");
|
|
13533
13723
|
}
|
|
13534
13724
|
const manager = await this.getContractManager();
|
|
13535
|
-
const
|
|
13536
|
-
|
|
13537
|
-
|
|
13538
|
-
|
|
13725
|
+
const provider = this._descriptorProvider;
|
|
13726
|
+
const descriptor = !provider ? void 0 : provider instanceof HDDescriptorProvider ? await manager.getNextSigningDescriptor() : await provider.getNextSigningDescriptor();
|
|
13727
|
+
if (!descriptor) {
|
|
13728
|
+
if (forceNew) {
|
|
13729
|
+
throw new WalletCannotAllocateAddressError(
|
|
13730
|
+
provider ? "the descriptor provider declined to allocate an index" : "this wallet has no HD stream (walletMode 'static' / 'auto')"
|
|
13731
|
+
);
|
|
13732
|
+
}
|
|
13733
|
+
return this.currentAddresses(manager, types);
|
|
13734
|
+
}
|
|
13735
|
+
const allocated = [];
|
|
13736
|
+
try {
|
|
13737
|
+
for (const type of types) {
|
|
13738
|
+
allocated.push(await this.mintAddress(manager, type, descriptor, tagSource, true));
|
|
13739
|
+
}
|
|
13740
|
+
} finally {
|
|
13741
|
+
try {
|
|
13742
|
+
await manager.refillLookAhead();
|
|
13743
|
+
} catch (e) {
|
|
13744
|
+
console.warn("look-ahead refill after address allocation failed", e);
|
|
13745
|
+
}
|
|
13746
|
+
}
|
|
13747
|
+
return allocated;
|
|
13748
|
+
}
|
|
13749
|
+
/**
|
|
13750
|
+
* The wallet's existing display addresses, as persisted contract rows —
|
|
13751
|
+
* the honest answer for a wallet with no index to burn.
|
|
13752
|
+
*
|
|
13753
|
+
* Each type is minted from the descriptor that already owns its display
|
|
13754
|
+
* script ({@link displayDescriptor}), not from the identity key, so the
|
|
13755
|
+
* returned `signingDescriptor` is the one that signs for the returned
|
|
13756
|
+
* `address` even on a wallet that has rotated.
|
|
13757
|
+
*/
|
|
13758
|
+
async currentAddresses(manager, types) {
|
|
13759
|
+
const out = [];
|
|
13760
|
+
for (const type of types) {
|
|
13761
|
+
const descriptor = await this.displayDescriptor(manager, type);
|
|
13762
|
+
out.push(await this.mintAddress(manager, type, descriptor, false, false));
|
|
13763
|
+
}
|
|
13764
|
+
return out;
|
|
13765
|
+
}
|
|
13766
|
+
/**
|
|
13767
|
+
* The descriptor that owns the wallet's current display script for `type`,
|
|
13768
|
+
* read off the row the wallet persisted when it adopted that script.
|
|
13769
|
+
*
|
|
13770
|
+
* Deriving it from the identity instead is only correct for a wallet that
|
|
13771
|
+
* never rotates. On one that has — an HD wallet whose provider later
|
|
13772
|
+
* declines to allocate — the display script belongs to an HD child, and
|
|
13773
|
+
* pairing its address with the identity descriptor hands the caller a
|
|
13774
|
+
* {@link NewAddress} whose `signingDescriptor` resolves, via
|
|
13775
|
+
* {@link signerForDescriptor}, to a signer holding the wrong key.
|
|
13776
|
+
*
|
|
13777
|
+
* Falls back to the identity's pathless `tr(pubkey)` when no row carries a
|
|
13778
|
+
* descriptor: the static / `auto` case, where the identity key genuinely
|
|
13779
|
+
* owns the display script and this is what `getNextSigningDescriptor`
|
|
13780
|
+
* answers too. (The index-0 baselines registered at construction carry no
|
|
13781
|
+
* `signingDescriptor` metadata, so those wallets take this path.)
|
|
13782
|
+
*/
|
|
13783
|
+
async displayDescriptor(manager, type) {
|
|
13784
|
+
const display = type === "boarding" ? this._boardingTapscript : this.offchainTapscript;
|
|
13785
|
+
const [row] = await manager.getContracts({ script: hex.encode(display.pkScript) });
|
|
13786
|
+
const persisted = row?.metadata?.signingDescriptor;
|
|
13787
|
+
if (typeof persisted === "string") return persisted;
|
|
13788
|
+
return identityDescriptor(this.identity);
|
|
13789
|
+
}
|
|
13790
|
+
/**
|
|
13791
|
+
* Build, persist and shape one address of `type` owned by `descriptor` —
|
|
13792
|
+
* the single build-and-register path behind both {@link allocateAddresses}
|
|
13793
|
+
* and {@link currentAddresses}, so a freshly allocated address and a
|
|
13794
|
+
* re-registered display address cannot disagree on what gets written.
|
|
13795
|
+
*
|
|
13796
|
+
* The descriptor is the sole source of the script's owner key in both
|
|
13797
|
+
* branches. Deriving one flavour from the descriptor and the other from a
|
|
13798
|
+
* tapscript field is what lets `address` and `signingDescriptor` drift
|
|
13799
|
+
* apart.
|
|
13800
|
+
*/
|
|
13801
|
+
async mintAddress(manager, type, descriptor, tagSource, allocated) {
|
|
13802
|
+
if (type === "boarding") {
|
|
13803
|
+
const built2 = this.buildBoardingContract(
|
|
13804
|
+
deriveDescriptorLeafPubKey(descriptor),
|
|
13805
|
+
descriptor,
|
|
13806
|
+
tagSource
|
|
13807
|
+
);
|
|
13808
|
+
const contract2 = await manager.createContract(built2.params);
|
|
13809
|
+
return {
|
|
13810
|
+
type,
|
|
13811
|
+
// `built.tapscript` is a `DefaultVtxo.Script` here without a
|
|
13812
|
+
// cast — the branch, not a widened local, does the narrowing.
|
|
13813
|
+
tapscript: built2.tapscript,
|
|
13814
|
+
// A boarding row persists the *ark* encoding of its script, so
|
|
13815
|
+
// `contract.address` is unusable for an onchain sender: the
|
|
13816
|
+
// onchain form has to be re-derived.
|
|
13817
|
+
address: built2.tapscript.onchainAddress(this.network),
|
|
13818
|
+
signingDescriptor: descriptor,
|
|
13819
|
+
contract: contract2,
|
|
13820
|
+
allocated
|
|
13821
|
+
};
|
|
13822
|
+
}
|
|
13823
|
+
const built = buildReceiveContract(
|
|
13824
|
+
this.offchainTapscript,
|
|
13825
|
+
descriptor,
|
|
13826
|
+
this.network.hrp,
|
|
13827
|
+
tagSource
|
|
13828
|
+
);
|
|
13829
|
+
const contract = await manager.createContract(built.params);
|
|
13830
|
+
return {
|
|
13831
|
+
type,
|
|
13832
|
+
tapscript: built.tapscript,
|
|
13833
|
+
// Offchain rows already store the address they advertise, and
|
|
13834
|
+
// reading it back keeps a coalesced row (`createContract` is
|
|
13835
|
+
// first-wins on script) honest about what was actually persisted.
|
|
13836
|
+
address: contract.address,
|
|
13837
|
+
signingDescriptor: descriptor,
|
|
13838
|
+
contract,
|
|
13839
|
+
allocated
|
|
13840
|
+
};
|
|
13841
|
+
}
|
|
13842
|
+
/**
|
|
13843
|
+
* Build the boarding contract owned by `pubKey`, keeping every other option
|
|
13844
|
+
* of the wallet's current boarding tapscript (notably the boarding-exit
|
|
13845
|
+
* CSV, which is index-independent). The offchain analogue lives in
|
|
13846
|
+
* {@link buildReceiveContract}.
|
|
13847
|
+
*/
|
|
13848
|
+
buildBoardingContract(pubKey, descriptor, tagSource) {
|
|
13849
|
+
const tapscript = new DefaultVtxo.Script({
|
|
13539
13850
|
...this._boardingTapscript.options,
|
|
13540
13851
|
pubKey
|
|
13541
13852
|
});
|
|
13542
|
-
const csvTimelock =
|
|
13543
|
-
|
|
13544
|
-
|
|
13853
|
+
const csvTimelock = tapscript.options.csvTimelock ?? DefaultVtxo.Script.DEFAULT_TIMELOCK;
|
|
13854
|
+
return {
|
|
13855
|
+
tapscript,
|
|
13545
13856
|
params: {
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13857
|
+
type: "boarding",
|
|
13858
|
+
params: {
|
|
13859
|
+
pubKey: hex.encode(pubKey),
|
|
13860
|
+
serverPubKey: hex.encode(tapscript.options.serverPubKey),
|
|
13861
|
+
csvTimelock: timelockToSequence(csvTimelock).toString()
|
|
13862
|
+
},
|
|
13863
|
+
script: hex.encode(tapscript.pkScript),
|
|
13864
|
+
address: tapscript.address(this.network.hrp, this.arkServerPublicKey).encode(),
|
|
13865
|
+
state: "active",
|
|
13866
|
+
metadata: {
|
|
13867
|
+
...tagSource && { source: WALLET_RECEIVE_SOURCE },
|
|
13868
|
+
signingDescriptor: descriptor
|
|
13869
|
+
}
|
|
13556
13870
|
}
|
|
13557
|
-
}
|
|
13558
|
-
this.setBoardingTapscriptForRotation(newBoarding);
|
|
13559
|
-
try {
|
|
13560
|
-
await manager.refillLookAhead();
|
|
13561
|
-
} catch (e) {
|
|
13562
|
-
console.warn("look-ahead refill after boarding allocation failed", e);
|
|
13563
|
-
}
|
|
13564
|
-
return newBoarding.onchainAddress(this.network);
|
|
13871
|
+
};
|
|
13565
13872
|
}
|
|
13566
13873
|
/**
|
|
13567
13874
|
* @see HDWalletCapable.getCurrentSigningDescriptor
|
|
@@ -13946,7 +14253,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
13946
14253
|
await this._restoreInFlight?.catch(() => void 0);
|
|
13947
14254
|
this._serverInfoUnsub?.();
|
|
13948
14255
|
this._serverInfoUnsub = void 0;
|
|
13949
|
-
await this.
|
|
14256
|
+
await this.settleServerInfoChanges();
|
|
13950
14257
|
let rotatorError;
|
|
13951
14258
|
try {
|
|
13952
14259
|
await this._receiveRotator?.dispose();
|
|
@@ -14478,7 +14785,10 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
14478
14785
|
* `typeof` guard skips the arknote strings settle also accepts.
|
|
14479
14786
|
*
|
|
14480
14787
|
* No-ops for static / `auto` wallets (no descriptor provider — boarding
|
|
14481
|
-
* stays on its fixed index-0 address).
|
|
14788
|
+
* stays on its fixed index-0 address). Wallets on a custom
|
|
14789
|
+
* {@link DescriptorProvider} DO rotate here now, where they previously
|
|
14790
|
+
* no-opped — see the behaviour-change note on {@link
|
|
14791
|
+
* getNewBoardingAddress}. Best-effort and non-fatal: the
|
|
14482
14792
|
* settle has already committed and its txid must be returned, so a
|
|
14483
14793
|
* rotation failure is logged and swallowed rather than thrown. Funds at
|
|
14484
14794
|
* the retired boarding address remain discoverable — the old `boarding`
|
|
@@ -15136,6 +15446,8 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
15136
15446
|
for (const vtxo of vtxos) {
|
|
15137
15447
|
if (hasTerminalSpend(vtxo)) {
|
|
15138
15448
|
unclaimed.push(cashReport(vtxo, "already-spent"));
|
|
15449
|
+
} else if (vtxo.isUnrolled) {
|
|
15450
|
+
unclaimed.push(cashReport(vtxo, "exited"));
|
|
15139
15451
|
} else if (isSubdust(vtxo, this.dustAmount)) {
|
|
15140
15452
|
unclaimed.push(cashReport(vtxo, "subdust"));
|
|
15141
15453
|
} else if (vtxo.isSwept) {
|
|
@@ -16026,6 +16338,11 @@ var MessageBus = class {
|
|
|
16026
16338
|
buildServicesFn;
|
|
16027
16339
|
boundOnMessage = this.onMessage.bind(this);
|
|
16028
16340
|
intentRepository;
|
|
16341
|
+
/** Pending broadcasts, drained FIFO by a single {@link drain} loop. */
|
|
16342
|
+
broadcastQueue = [];
|
|
16343
|
+
draining = false;
|
|
16344
|
+
/** Bumped wherever the generation owning the queued broadcasts ends. */
|
|
16345
|
+
broadcastEpoch = 0;
|
|
16029
16346
|
/** Start the message bus and attach service-worker event listeners. */
|
|
16030
16347
|
async start() {
|
|
16031
16348
|
if (this.running) return;
|
|
@@ -16048,6 +16365,7 @@ var MessageBus = class {
|
|
|
16048
16365
|
this.running = false;
|
|
16049
16366
|
this.tickInProgress = false;
|
|
16050
16367
|
this.initialized = false;
|
|
16368
|
+
this.invalidateBroadcasts();
|
|
16051
16369
|
if (this.tickTimeout !== null) {
|
|
16052
16370
|
self.clearTimeout(this.tickTimeout);
|
|
16053
16371
|
this.tickTimeout = null;
|
|
@@ -16060,6 +16378,78 @@ var MessageBus = class {
|
|
|
16060
16378
|
self.removeEventListener("message", this.boundOnMessage);
|
|
16061
16379
|
await Promise.all(Array.from(this.handlers.values()).map((updater) => updater.stop()));
|
|
16062
16380
|
}
|
|
16381
|
+
/** Invalidate every broadcast belonging to the outgoing generation. */
|
|
16382
|
+
invalidateBroadcasts() {
|
|
16383
|
+
this.broadcastEpoch++;
|
|
16384
|
+
this.broadcastQueue.length = 0;
|
|
16385
|
+
}
|
|
16386
|
+
broadcastToClients(responses) {
|
|
16387
|
+
this.broadcastQueue.push(...responses);
|
|
16388
|
+
void this.drain();
|
|
16389
|
+
}
|
|
16390
|
+
/**
|
|
16391
|
+
* Single fan-out loop, so pushes and tick responses keep one FIFO order.
|
|
16392
|
+
* A helper posting per response would race: `clients.matchAll()` gives no
|
|
16393
|
+
* cross-call resolution order, and it would de-batch `runTick`.
|
|
16394
|
+
*/
|
|
16395
|
+
async drain() {
|
|
16396
|
+
if (this.draining) return;
|
|
16397
|
+
this.draining = true;
|
|
16398
|
+
try {
|
|
16399
|
+
while (this.broadcastQueue.length) {
|
|
16400
|
+
const epoch = this.broadcastEpoch;
|
|
16401
|
+
const batch = this.broadcastQueue.splice(0);
|
|
16402
|
+
if (!this.running) {
|
|
16403
|
+
this.logDroppedBroadcasts(batch, "bus stopped");
|
|
16404
|
+
return;
|
|
16405
|
+
}
|
|
16406
|
+
let clients;
|
|
16407
|
+
try {
|
|
16408
|
+
clients = await self.clients.matchAll({
|
|
16409
|
+
includeUncontrolled: true,
|
|
16410
|
+
type: "window"
|
|
16411
|
+
});
|
|
16412
|
+
} catch (err) {
|
|
16413
|
+
this.logDroppedBroadcasts(batch, "clients.matchAll failed", err);
|
|
16414
|
+
continue;
|
|
16415
|
+
}
|
|
16416
|
+
if (!this.running) {
|
|
16417
|
+
this.logDroppedBroadcasts(batch, "bus stopped during matchAll");
|
|
16418
|
+
return;
|
|
16419
|
+
}
|
|
16420
|
+
if (this.broadcastEpoch !== epoch) {
|
|
16421
|
+
this.logDroppedBroadcasts(batch, "re-init landed during matchAll");
|
|
16422
|
+
continue;
|
|
16423
|
+
}
|
|
16424
|
+
for (const message of batch) {
|
|
16425
|
+
for (const client of clients) {
|
|
16426
|
+
try {
|
|
16427
|
+
client.postMessage(message);
|
|
16428
|
+
} catch (err) {
|
|
16429
|
+
if (this.debug)
|
|
16430
|
+
console.warn(`[${message.tag}] broadcast to client failed`, err);
|
|
16431
|
+
}
|
|
16432
|
+
}
|
|
16433
|
+
}
|
|
16434
|
+
}
|
|
16435
|
+
} catch {
|
|
16436
|
+
} finally {
|
|
16437
|
+
this.draining = false;
|
|
16438
|
+
if (this.running && this.broadcastQueue.length) void this.drain();
|
|
16439
|
+
}
|
|
16440
|
+
}
|
|
16441
|
+
/**
|
|
16442
|
+
* A dropped batch has no periodic recovery to fall back on now that events
|
|
16443
|
+
* no longer ride the tick, so name the loss under {@link Options.debug}.
|
|
16444
|
+
*/
|
|
16445
|
+
logDroppedBroadcasts(batch, reason, ...error) {
|
|
16446
|
+
if (!this.debug) return;
|
|
16447
|
+
console.warn(
|
|
16448
|
+
`dropping ${batch.length} broadcast(s): ${reason}`,
|
|
16449
|
+
batch.map((response) => response.tag),
|
|
16450
|
+
...error
|
|
16451
|
+
);
|
|
16452
|
+
}
|
|
16063
16453
|
scheduleNextTick() {
|
|
16064
16454
|
if (!this.running) return;
|
|
16065
16455
|
if (this.tickTimeout !== null) return;
|
|
@@ -16088,16 +16478,7 @@ var MessageBus = class {
|
|
|
16088
16478
|
if (this.debug)
|
|
16089
16479
|
console.log(`[${updater.messageTag}] outgoing tick response:`, response);
|
|
16090
16480
|
if (response && response.length > 0) {
|
|
16091
|
-
|
|
16092
|
-
includeUncontrolled: true,
|
|
16093
|
-
type: "window"
|
|
16094
|
-
}).then((clients) => {
|
|
16095
|
-
for (const message of response) {
|
|
16096
|
-
clients.forEach((client) => {
|
|
16097
|
-
client.postMessage(message);
|
|
16098
|
-
});
|
|
16099
|
-
}
|
|
16100
|
-
});
|
|
16481
|
+
this.broadcastToClients(response);
|
|
16101
16482
|
}
|
|
16102
16483
|
} catch (err) {
|
|
16103
16484
|
if (this.debug) console.error(`[${updater.messageTag}] tick failed`, err);
|
|
@@ -16136,6 +16517,14 @@ var MessageBus = class {
|
|
|
16136
16517
|
self.clearTimeout(this.tickTimeout);
|
|
16137
16518
|
this.tickTimeout = null;
|
|
16138
16519
|
}
|
|
16520
|
+
this.invalidateBroadcasts();
|
|
16521
|
+
const epoch = this.broadcastEpoch;
|
|
16522
|
+
const channel = {
|
|
16523
|
+
broadcast: (response) => {
|
|
16524
|
+
if (epoch !== this.broadcastEpoch) return;
|
|
16525
|
+
this.broadcastToClients([response]);
|
|
16526
|
+
}
|
|
16527
|
+
};
|
|
16139
16528
|
if (this.initialized) {
|
|
16140
16529
|
this.initialized = false;
|
|
16141
16530
|
await Promise.all(
|
|
@@ -16152,9 +16541,7 @@ var MessageBus = class {
|
|
|
16152
16541
|
try {
|
|
16153
16542
|
for (const updater of this.handlers.values()) {
|
|
16154
16543
|
if (this.debug) console.log(`Starting updater: ${updater.messageTag}`);
|
|
16155
|
-
await updater.start(services, {
|
|
16156
|
-
walletRepository: this.walletRepository
|
|
16157
|
-
});
|
|
16544
|
+
await updater.start(services, { walletRepository: this.walletRepository }, channel);
|
|
16158
16545
|
started.push(updater);
|
|
16159
16546
|
}
|
|
16160
16547
|
} catch (err) {
|
|
@@ -16824,6 +17211,17 @@ var WalletMessageHandler = class {
|
|
|
16824
17211
|
incomingFundsSubscription;
|
|
16825
17212
|
contractEventsSubscription;
|
|
16826
17213
|
onNextTick = [];
|
|
17214
|
+
channel;
|
|
17215
|
+
// One counter per subscription field, bumped exactly where that field is
|
|
17216
|
+
// dropped — never where a neighbour's is. They cannot be merged:
|
|
17217
|
+
// `onWalletInitialized` re-subscribes incoming funds while
|
|
17218
|
+
// `ensureContractEventBroadcasting` deliberately keeps its subscription, so
|
|
17219
|
+
// a shared bump would leave the live contract-event emitter permanently
|
|
17220
|
+
// stale, and folding requests in would truncate an in-flight settle.
|
|
17221
|
+
incomingFundsEpoch = 0;
|
|
17222
|
+
contractEventsEpoch = 0;
|
|
17223
|
+
/** Per-request progress callbacks: ends with the handler, not with a re-init. */
|
|
17224
|
+
requestEpoch = 0;
|
|
16827
17225
|
/**
|
|
16828
17226
|
* Instantiate a new WalletUpdater.
|
|
16829
17227
|
* Can override the default `messageTag` allowing more than one updater to run in parallel.
|
|
@@ -16834,13 +17232,20 @@ var WalletMessageHandler = class {
|
|
|
16834
17232
|
}
|
|
16835
17233
|
// lifecycle methods
|
|
16836
17234
|
async start(...params) {
|
|
16837
|
-
const [services, repositories] = params;
|
|
17235
|
+
const [services, repositories, channel] = params;
|
|
16838
17236
|
this.readonlyWallet = services.readonlyWallet;
|
|
16839
17237
|
this.wallet = services.wallet;
|
|
16840
17238
|
this.arkProvider = services.arkProvider;
|
|
16841
17239
|
this.walletRepository = repositories.walletRepository;
|
|
17240
|
+
this.channel = channel;
|
|
17241
|
+
this.onNextTick = [];
|
|
16842
17242
|
}
|
|
16843
17243
|
async stop() {
|
|
17244
|
+
this.requestEpoch++;
|
|
17245
|
+
this.incomingFundsEpoch++;
|
|
17246
|
+
this.contractEventsEpoch++;
|
|
17247
|
+
this.channel = void 0;
|
|
17248
|
+
this.onNextTick = [];
|
|
16844
17249
|
if (this.incomingFundsSubscription) {
|
|
16845
17250
|
this.incomingFundsSubscription();
|
|
16846
17251
|
this.incomingFundsSubscription = void 0;
|
|
@@ -16863,8 +17268,8 @@ var WalletMessageHandler = class {
|
|
|
16863
17268
|
this.indexerProvider = void 0;
|
|
16864
17269
|
}
|
|
16865
17270
|
async tick(_now) {
|
|
16866
|
-
const
|
|
16867
|
-
|
|
17271
|
+
const pending = this.onNextTick.splice(0);
|
|
17272
|
+
const results = await Promise.allSettled(pending.map((fn) => fn()));
|
|
16868
17273
|
return results.map((result) => {
|
|
16869
17274
|
if (result.status === "fulfilled") {
|
|
16870
17275
|
return result.value;
|
|
@@ -16874,8 +17279,46 @@ var WalletMessageHandler = class {
|
|
|
16874
17279
|
}
|
|
16875
17280
|
}).filter((response) => response !== null);
|
|
16876
17281
|
}
|
|
16877
|
-
|
|
16878
|
-
|
|
17282
|
+
epochOf(scope) {
|
|
17283
|
+
switch (scope) {
|
|
17284
|
+
case "incomingFunds":
|
|
17285
|
+
return this.incomingFundsEpoch;
|
|
17286
|
+
case "contractEvents":
|
|
17287
|
+
return this.contractEventsEpoch;
|
|
17288
|
+
case "request":
|
|
17289
|
+
return this.requestEpoch;
|
|
17290
|
+
default: {
|
|
17291
|
+
const _exhaustive = scope;
|
|
17292
|
+
throw new Error(`Unknown scope: ${_exhaustive}`);
|
|
17293
|
+
}
|
|
17294
|
+
}
|
|
17295
|
+
}
|
|
17296
|
+
newGeneration(scope) {
|
|
17297
|
+
const born = this.epochOf(scope);
|
|
17298
|
+
const stale = () => born !== this.epochOf(scope);
|
|
17299
|
+
return {
|
|
17300
|
+
get stale() {
|
|
17301
|
+
return stale();
|
|
17302
|
+
}
|
|
17303
|
+
};
|
|
17304
|
+
}
|
|
17305
|
+
/**
|
|
17306
|
+
* A handle rather than a `broadcast(response, epoch)` call, because it can
|
|
17307
|
+
* only be written where the closure it guards is created — an epoch passed
|
|
17308
|
+
* at the call site reads identically whether it guards anything or not.
|
|
17309
|
+
*/
|
|
17310
|
+
newEmitter(scope) {
|
|
17311
|
+
const gen = this.newGeneration(scope);
|
|
17312
|
+
return {
|
|
17313
|
+
get stale() {
|
|
17314
|
+
return gen.stale;
|
|
17315
|
+
},
|
|
17316
|
+
emit: (response) => {
|
|
17317
|
+
if (!response || gen.stale) return;
|
|
17318
|
+
if (this.channel) return this.channel.broadcast(response);
|
|
17319
|
+
this.onNextTick.push(() => response);
|
|
17320
|
+
}
|
|
17321
|
+
};
|
|
16879
17322
|
}
|
|
16880
17323
|
requireWallet() {
|
|
16881
17324
|
if (!this.wallet) {
|
|
@@ -16904,6 +17347,7 @@ var WalletMessageHandler = class {
|
|
|
16904
17347
|
}
|
|
16905
17348
|
async handleMessage(message) {
|
|
16906
17349
|
const id = message.id;
|
|
17350
|
+
const emitter = this.newEmitter("request");
|
|
16907
17351
|
if (message.type === "INIT_WALLET") {
|
|
16908
17352
|
await this.handleInitWallet(message);
|
|
16909
17353
|
return this.tagged({
|
|
@@ -17172,6 +17616,18 @@ var WalletMessageHandler = class {
|
|
|
17172
17616
|
payload: { descriptor }
|
|
17173
17617
|
});
|
|
17174
17618
|
}
|
|
17619
|
+
case "GET_NEW_ADDRESSES": {
|
|
17620
|
+
const wallet = this.wallet;
|
|
17621
|
+
if (!wallet) throw new WalletNotInitializedError();
|
|
17622
|
+
const addresses = await wallet.getNewAddresses(
|
|
17623
|
+
message.payload
|
|
17624
|
+
);
|
|
17625
|
+
return this.tagged({
|
|
17626
|
+
id,
|
|
17627
|
+
type: "NEW_ADDRESSES",
|
|
17628
|
+
payload: { addresses }
|
|
17629
|
+
});
|
|
17630
|
+
}
|
|
17175
17631
|
case "GET_USED_SIGNING_DESCRIPTORS": {
|
|
17176
17632
|
const wallet = this.wallet;
|
|
17177
17633
|
const descriptors = isHDWalletCapable(wallet) ? await wallet.getUsedSigningDescriptors(
|
|
@@ -17262,8 +17718,8 @@ var WalletMessageHandler = class {
|
|
|
17262
17718
|
const wallet = this.requireWallet();
|
|
17263
17719
|
const vtxoManager = await wallet.getVtxoManager();
|
|
17264
17720
|
const txid = await vtxoManager.recoverVtxos((e) => {
|
|
17265
|
-
|
|
17266
|
-
|
|
17721
|
+
emitter.emit(
|
|
17722
|
+
this.tagged({
|
|
17267
17723
|
id,
|
|
17268
17724
|
type: "RECOVER_VTXOS_EVENT",
|
|
17269
17725
|
payload: e
|
|
@@ -17307,8 +17763,8 @@ var WalletMessageHandler = class {
|
|
|
17307
17763
|
const wallet = this.requireWallet();
|
|
17308
17764
|
const vtxoManager = await wallet.getVtxoManager();
|
|
17309
17765
|
const txid = await vtxoManager.renewVtxos((e) => {
|
|
17310
|
-
|
|
17311
|
-
|
|
17766
|
+
emitter.emit(
|
|
17767
|
+
this.tagged({
|
|
17312
17768
|
id,
|
|
17313
17769
|
type: "RENEW_VTXOS_EVENT",
|
|
17314
17770
|
payload: e
|
|
@@ -17346,8 +17802,8 @@ var WalletMessageHandler = class {
|
|
|
17346
17802
|
const vtxoManager = await wallet.getVtxoManager();
|
|
17347
17803
|
const report = await vtxoManager.migrateDeprecatedSignerVtxos({
|
|
17348
17804
|
eventCallback: (e) => {
|
|
17349
|
-
|
|
17350
|
-
|
|
17805
|
+
emitter.emit(
|
|
17806
|
+
this.tagged({
|
|
17351
17807
|
id,
|
|
17352
17808
|
type: "MIGRATE_DEPRECATED_SIGNER_VTXOS_EVENT",
|
|
17353
17809
|
payload: e
|
|
@@ -17450,6 +17906,7 @@ var WalletMessageHandler = class {
|
|
|
17450
17906
|
intentLocked: offchain.intentLocked,
|
|
17451
17907
|
recoverable: offchain.recoverable,
|
|
17452
17908
|
pendingRecovery: offchain.pendingRecovery,
|
|
17909
|
+
unrolled: offchain.unrolled,
|
|
17453
17910
|
total: totalBoarding + offchain.total,
|
|
17454
17911
|
assets: offchain.assets,
|
|
17455
17912
|
availableAssets: offchain.availableAssets
|
|
@@ -17460,11 +17917,15 @@ var WalletMessageHandler = class {
|
|
|
17460
17917
|
return this.readonlyWallet.getBoardingUtxos();
|
|
17461
17918
|
}
|
|
17462
17919
|
async onWalletInitialized() {
|
|
17463
|
-
|
|
17920
|
+
const wallet = this.readonlyWallet;
|
|
17921
|
+
if (!wallet || !this.arkProvider || !this.indexerProvider || !this.walletRepository) {
|
|
17464
17922
|
return;
|
|
17465
17923
|
}
|
|
17924
|
+
const init = this.newGeneration("incomingFunds");
|
|
17466
17925
|
await this.ensureContractEventBroadcasting();
|
|
17926
|
+
if (init.stale) return;
|
|
17467
17927
|
await this.refreshCachedData();
|
|
17928
|
+
if (init.stale) return;
|
|
17468
17929
|
if (this.wallet) {
|
|
17469
17930
|
try {
|
|
17470
17931
|
const vtxos = await this.getVtxosFromRepo();
|
|
@@ -17477,72 +17938,81 @@ var WalletMessageHandler = class {
|
|
|
17477
17938
|
} catch (error) {
|
|
17478
17939
|
console.error("Error recovering pending transactions:", error);
|
|
17479
17940
|
}
|
|
17941
|
+
if (init.stale) return;
|
|
17480
17942
|
}
|
|
17481
17943
|
if (this.incomingFundsSubscription) this.incomingFundsSubscription();
|
|
17482
|
-
|
|
17483
|
-
this.
|
|
17484
|
-
|
|
17485
|
-
|
|
17486
|
-
|
|
17487
|
-
|
|
17488
|
-
|
|
17489
|
-
|
|
17490
|
-
|
|
17491
|
-
|
|
17492
|
-
|
|
17493
|
-
|
|
17494
|
-
|
|
17495
|
-
|
|
17496
|
-
const arr = byScript.get(v.script) ?? [];
|
|
17497
|
-
arr.push(v);
|
|
17498
|
-
byScript.set(v.script, arr);
|
|
17499
|
-
}
|
|
17500
|
-
let walletScript;
|
|
17501
|
-
try {
|
|
17502
|
-
walletScript = scriptFromArkAddress(address);
|
|
17503
|
-
} catch {
|
|
17504
|
-
walletScript = void 0;
|
|
17505
|
-
}
|
|
17506
|
-
const cm = await this.readonlyWallet.getContractManager();
|
|
17507
|
-
const contracts = await cm.getContracts();
|
|
17508
|
-
const addrByScript = new Map(contracts.map((c) => [c.script, c.address]));
|
|
17509
|
-
for (const [script, vtxos] of byScript) {
|
|
17510
|
-
const filtered = warnAndFilterVtxosForScript(
|
|
17511
|
-
vtxos,
|
|
17512
|
-
script,
|
|
17513
|
-
"WalletMessageHandler.notifyIncomingFunds"
|
|
17944
|
+
this.incomingFundsSubscription = void 0;
|
|
17945
|
+
this.incomingFundsEpoch++;
|
|
17946
|
+
const emitter = this.newEmitter("incomingFunds");
|
|
17947
|
+
const address = await wallet.getAddress();
|
|
17948
|
+
const unsubscribe = await wallet.notifyIncomingFunds(async (funds) => {
|
|
17949
|
+
if (emitter.stale) return;
|
|
17950
|
+
if (funds.type === "vtxo") {
|
|
17951
|
+
const { newVtxos, spentVtxos } = funds;
|
|
17952
|
+
if (newVtxos.length + spentVtxos.length === 0) return;
|
|
17953
|
+
const byScript = /* @__PURE__ */ new Map();
|
|
17954
|
+
for (const v of [...newVtxos, ...spentVtxos]) {
|
|
17955
|
+
if (!v.script) {
|
|
17956
|
+
console.warn(
|
|
17957
|
+
`WalletMessageHandler.notifyIncomingFunds: dropping VTXO without script ${v.txid}:${v.vout}`
|
|
17514
17958
|
);
|
|
17515
|
-
|
|
17516
|
-
const targetAddress = script === walletScript ? address : addrByScript.get(script);
|
|
17517
|
-
if (!targetAddress) continue;
|
|
17518
|
-
if (this.walletRepository) {
|
|
17519
|
-
await saveVtxosForContract(
|
|
17520
|
-
this.walletRepository,
|
|
17521
|
-
{ script, address: targetAddress },
|
|
17522
|
-
filtered
|
|
17523
|
-
);
|
|
17524
|
-
}
|
|
17959
|
+
continue;
|
|
17525
17960
|
}
|
|
17526
|
-
|
|
17527
|
-
|
|
17528
|
-
|
|
17529
|
-
broadcast: true,
|
|
17530
|
-
payload: { newVtxos, spentVtxos }
|
|
17531
|
-
})
|
|
17532
|
-
);
|
|
17961
|
+
const arr = byScript.get(v.script) ?? [];
|
|
17962
|
+
arr.push(v);
|
|
17963
|
+
byScript.set(v.script, arr);
|
|
17533
17964
|
}
|
|
17534
|
-
|
|
17535
|
-
|
|
17536
|
-
|
|
17537
|
-
|
|
17538
|
-
|
|
17539
|
-
|
|
17540
|
-
|
|
17541
|
-
|
|
17965
|
+
let walletScript;
|
|
17966
|
+
try {
|
|
17967
|
+
walletScript = scriptFromArkAddress(address);
|
|
17968
|
+
} catch {
|
|
17969
|
+
walletScript = void 0;
|
|
17970
|
+
}
|
|
17971
|
+
const cm = await wallet.getContractManager();
|
|
17972
|
+
if (emitter.stale) return;
|
|
17973
|
+
const contracts = await cm.getContracts();
|
|
17974
|
+
if (emitter.stale) return;
|
|
17975
|
+
const addrByScript = new Map(contracts.map((c) => [c.script, c.address]));
|
|
17976
|
+
for (const [script, vtxos] of byScript) {
|
|
17977
|
+
const filtered = warnAndFilterVtxosForScript(
|
|
17978
|
+
vtxos,
|
|
17979
|
+
script,
|
|
17980
|
+
"WalletMessageHandler.notifyIncomingFunds"
|
|
17542
17981
|
);
|
|
17982
|
+
if (filtered.length === 0) continue;
|
|
17983
|
+
const targetAddress = script === walletScript ? address : addrByScript.get(script);
|
|
17984
|
+
if (!targetAddress) continue;
|
|
17985
|
+
if (this.walletRepository) {
|
|
17986
|
+
if (emitter.stale) return;
|
|
17987
|
+
await saveVtxosForContract(
|
|
17988
|
+
this.walletRepository,
|
|
17989
|
+
{ script, address: targetAddress },
|
|
17990
|
+
filtered
|
|
17991
|
+
);
|
|
17992
|
+
}
|
|
17543
17993
|
}
|
|
17994
|
+
emitter.emit(
|
|
17995
|
+
this.tagged({
|
|
17996
|
+
type: "VTXO_UPDATE",
|
|
17997
|
+
broadcast: true,
|
|
17998
|
+
payload: { newVtxos, spentVtxos }
|
|
17999
|
+
})
|
|
18000
|
+
);
|
|
17544
18001
|
}
|
|
17545
|
-
|
|
18002
|
+
if (funds.type === "utxo") {
|
|
18003
|
+
if (emitter.stale) return;
|
|
18004
|
+
const utxos = await wallet.getBoardingUtxos();
|
|
18005
|
+
emitter.emit(
|
|
18006
|
+
this.tagged({
|
|
18007
|
+
type: "UTXO_UPDATE",
|
|
18008
|
+
broadcast: true,
|
|
18009
|
+
payload: { coins: utxos }
|
|
18010
|
+
})
|
|
18011
|
+
);
|
|
18012
|
+
}
|
|
18013
|
+
});
|
|
18014
|
+
if (emitter.stale) return unsubscribe();
|
|
18015
|
+
this.incomingFundsSubscription = unsubscribe;
|
|
17546
18016
|
if (this.wallet) {
|
|
17547
18017
|
try {
|
|
17548
18018
|
await this.wallet.getVtxoManager();
|
|
@@ -17587,10 +18057,11 @@ var WalletMessageHandler = class {
|
|
|
17587
18057
|
await this.refreshCachedData();
|
|
17588
18058
|
}
|
|
17589
18059
|
async handleSettle(message) {
|
|
18060
|
+
const emitter = this.newEmitter("request");
|
|
17590
18061
|
const wallet = this.requireWallet();
|
|
17591
18062
|
const txid = await wallet.settle(message.payload.params, (e) => {
|
|
17592
|
-
|
|
17593
|
-
|
|
18063
|
+
emitter.emit(
|
|
18064
|
+
this.tagged({
|
|
17594
18065
|
id: message.id,
|
|
17595
18066
|
type: "SETTLE_EVENT",
|
|
17596
18067
|
payload: e
|
|
@@ -17667,10 +18138,19 @@ var WalletMessageHandler = class {
|
|
|
17667
18138
|
throw new WalletNotInitializedError();
|
|
17668
18139
|
}
|
|
17669
18140
|
const allVtxos = await this.getVtxosFromRepo();
|
|
17670
|
-
const vtxos = allVtxos.filter((v) => !hasTerminalSpend(v));
|
|
17671
18141
|
const dustAmount = this.readonlyWallet.dustAmount;
|
|
18142
|
+
const withUnrolled = message.payload.filter?.withUnrolled ?? false;
|
|
17672
18143
|
const includeRecoverable = message.payload.filter?.withRecoverable ?? false;
|
|
17673
|
-
|
|
18144
|
+
return allVtxos.filter((v) => {
|
|
18145
|
+
if (v.isUnrolled) {
|
|
18146
|
+
return withUnrolled;
|
|
18147
|
+
}
|
|
18148
|
+
if (hasTerminalSpend(v)) {
|
|
18149
|
+
return false;
|
|
18150
|
+
}
|
|
18151
|
+
if (includeRecoverable) {
|
|
18152
|
+
return true;
|
|
18153
|
+
}
|
|
17674
18154
|
if (dustAmount != null && isSubdust(v, dustAmount)) {
|
|
17675
18155
|
return false;
|
|
17676
18156
|
}
|
|
@@ -17682,15 +18162,15 @@ var WalletMessageHandler = class {
|
|
|
17682
18162
|
}
|
|
17683
18163
|
return true;
|
|
17684
18164
|
});
|
|
17685
|
-
if (!message.payload.filter?.withUnrolled) {
|
|
17686
|
-
return filteredVtxos;
|
|
17687
|
-
}
|
|
17688
|
-
return filteredVtxos.concat(allVtxos.filter((v) => hasTerminalSpend(v) && v.isUnrolled));
|
|
17689
18165
|
}
|
|
17690
18166
|
/** Tear down handler subscriptions, then delegate the full wipe to the wallet. */
|
|
17691
18167
|
async clear() {
|
|
17692
18168
|
const wallet = this.wallet ?? this.readonlyWallet;
|
|
17693
18169
|
if (!wallet) return;
|
|
18170
|
+
this.requestEpoch++;
|
|
18171
|
+
this.incomingFundsEpoch++;
|
|
18172
|
+
this.contractEventsEpoch++;
|
|
18173
|
+
this.onNextTick = [];
|
|
17694
18174
|
if (this.incomingFundsSubscription) {
|
|
17695
18175
|
this.incomingFundsSubscription();
|
|
17696
18176
|
this.incomingFundsSubscription = void 0;
|
|
@@ -17779,13 +18259,17 @@ var WalletMessageHandler = class {
|
|
|
17779
18259
|
return buildTransactionHistory(vtxos, boardingTxs, commitmentsToIgnore, resolveTxCreatedAt);
|
|
17780
18260
|
}
|
|
17781
18261
|
async ensureContractEventBroadcasting() {
|
|
17782
|
-
|
|
18262
|
+
const wallet = this.readonlyWallet;
|
|
18263
|
+
if (!wallet) return;
|
|
17783
18264
|
if (this.contractEventsSubscription) return;
|
|
18265
|
+
const gen = this.newGeneration("contractEvents");
|
|
17784
18266
|
try {
|
|
17785
|
-
const manager = await
|
|
18267
|
+
const manager = await wallet.getContractManager();
|
|
18268
|
+
if (gen.stale || this.contractEventsSubscription) return;
|
|
18269
|
+
const emitter = this.newEmitter("contractEvents");
|
|
17786
18270
|
this.contractEventsSubscription = manager.onContractEvent((event) => {
|
|
17787
|
-
|
|
17788
|
-
|
|
18271
|
+
emitter.emit(
|
|
18272
|
+
this.tagged({
|
|
17789
18273
|
type: "CONTRACT_EVENT",
|
|
17790
18274
|
broadcast: true,
|
|
17791
18275
|
payload: { event }
|
|
@@ -17816,6 +18300,9 @@ var DEFAULT_MESSAGE_TIMEOUTS = {
|
|
|
17816
18300
|
// Allocation is a local repository write plus a fire-and-forget band
|
|
17817
18301
|
// slide — no indexer round trip on the request path.
|
|
17818
18302
|
GET_NEXT_SIGNING_DESCRIPTOR: 1e4,
|
|
18303
|
+
// Same shape as the bare allocation above, plus one contract write per
|
|
18304
|
+
// requested type — still local, still no indexer round trip.
|
|
18305
|
+
GET_NEW_ADDRESSES: 1e4,
|
|
17819
18306
|
GET_USED_SIGNING_DESCRIPTORS: 2e4,
|
|
17820
18307
|
ADVANCE_SIGNING_DESCRIPTOR_WATERMARK: 1e4,
|
|
17821
18308
|
// Medium reads — may involve indexer queries
|
|
@@ -18961,6 +19448,35 @@ var ServiceWorkerWallet = class _ServiceWorkerWallet extends ServiceWorkerReadon
|
|
|
18961
19448
|
throw new Error(`Failed to allocate next signing descriptor: ${error}`);
|
|
18962
19449
|
}
|
|
18963
19450
|
}
|
|
19451
|
+
/**
|
|
19452
|
+
* @see Wallet.getNewAddresses
|
|
19453
|
+
*
|
|
19454
|
+
* Proxied as a single request rather than rebuilt page-side out of
|
|
19455
|
+
* {@link getNextSigningDescriptor}: the worker owns the HD watermark *and*
|
|
19456
|
+
* the contract repository, so splitting the operation would let a page burn
|
|
19457
|
+
* an index and then fail to register the script, leaving an address nothing
|
|
19458
|
+
* watches.
|
|
19459
|
+
*
|
|
19460
|
+
* Note the error shape — `WalletCannotAllocateAddressError` is thrown
|
|
19461
|
+
* worker-side and cannot cross the message boundary as a class, so a
|
|
19462
|
+
* `forceNew` refusal surfaces here as a plain `Error` carrying its message
|
|
19463
|
+
* (and the worker-side error as `cause`). Callers that must branch on the
|
|
19464
|
+
* refusal match the message rather than `instanceof`.
|
|
19465
|
+
*/
|
|
19466
|
+
async getNewAddresses(opts) {
|
|
19467
|
+
const message = {
|
|
19468
|
+
id: getRandomId(),
|
|
19469
|
+
tag: this.messageTag,
|
|
19470
|
+
type: "GET_NEW_ADDRESSES",
|
|
19471
|
+
...opts ? { payload: opts } : {}
|
|
19472
|
+
};
|
|
19473
|
+
try {
|
|
19474
|
+
const response = await this.sendMessage(message);
|
|
19475
|
+
return response.payload.addresses;
|
|
19476
|
+
} catch (error) {
|
|
19477
|
+
throw new Error(`Failed to allocate new addresses: ${error}`, { cause: error });
|
|
19478
|
+
}
|
|
19479
|
+
}
|
|
18964
19480
|
/** @see HDWalletCapable.getUsedSigningDescriptors */
|
|
18965
19481
|
async getUsedSigningDescriptors(opts) {
|
|
18966
19482
|
const message = {
|
|
@@ -19927,6 +20443,10 @@ var ElectrumOnchainProvider = class {
|
|
|
19927
20443
|
}
|
|
19928
20444
|
throw new Error("Only 1 or 1P1C package can be broadcast");
|
|
19929
20445
|
}
|
|
20446
|
+
async getRawTransaction(txid) {
|
|
20447
|
+
const [tx] = await this.chain.fetchTransactions([txid]);
|
|
20448
|
+
return hex.decode(tx.hex);
|
|
20449
|
+
}
|
|
19930
20450
|
async getTxOutspends(txid) {
|
|
19931
20451
|
const [txResult] = await this.chain.fetchTransactions([txid]);
|
|
19932
20452
|
const tx = Transaction$2.fromRaw(hex.decode(txResult.hex), {
|
|
@@ -20232,6 +20752,183 @@ function childTxidFromHex(txHex) {
|
|
|
20232
20752
|
});
|
|
20233
20753
|
return tx.id;
|
|
20234
20754
|
}
|
|
20755
|
+
|
|
20756
|
+
// src/providers/cachingArk.ts
|
|
20757
|
+
var DEFAULT_TTL_MS = 6e4;
|
|
20758
|
+
var CachingArkProvider = class {
|
|
20759
|
+
constructor(inner, ttlMs = DEFAULT_TTL_MS) {
|
|
20760
|
+
this.inner = inner;
|
|
20761
|
+
this.ttlMs = ttlMs;
|
|
20762
|
+
this.unsubscribe = inner.onServerInfoChanged?.((info) => {
|
|
20763
|
+
this.cached = info;
|
|
20764
|
+
this.expiresAt = Date.now() + this.ttlMs;
|
|
20765
|
+
this.generation++;
|
|
20766
|
+
}) ?? (() => {
|
|
20767
|
+
});
|
|
20768
|
+
}
|
|
20769
|
+
inner;
|
|
20770
|
+
ttlMs;
|
|
20771
|
+
cached;
|
|
20772
|
+
expiresAt = 0;
|
|
20773
|
+
inflight;
|
|
20774
|
+
/** Bumped on every event-driven cache write; see {@link getInfo}. */
|
|
20775
|
+
generation = 0;
|
|
20776
|
+
unsubscribe;
|
|
20777
|
+
/** Releases the inner provider's server-info subscription. */
|
|
20778
|
+
dispose() {
|
|
20779
|
+
this.unsubscribe();
|
|
20780
|
+
}
|
|
20781
|
+
get serverUrl() {
|
|
20782
|
+
const url = this.inner.serverUrl;
|
|
20783
|
+
return typeof url === "string" ? url : void 0;
|
|
20784
|
+
}
|
|
20785
|
+
async getInfo() {
|
|
20786
|
+
if (this.cached && Date.now() < this.expiresAt) return this.cached;
|
|
20787
|
+
if (!this.inflight) {
|
|
20788
|
+
const generation = this.generation;
|
|
20789
|
+
this.inflight = this.inner.getInfo().then((info) => {
|
|
20790
|
+
if (this.generation !== generation) return this.cached ?? info;
|
|
20791
|
+
this.cached = info;
|
|
20792
|
+
this.expiresAt = Date.now() + this.ttlMs;
|
|
20793
|
+
return info;
|
|
20794
|
+
}).finally(() => {
|
|
20795
|
+
this.inflight = void 0;
|
|
20796
|
+
});
|
|
20797
|
+
}
|
|
20798
|
+
return this.inflight;
|
|
20799
|
+
}
|
|
20800
|
+
submitTx(signedArkTx, checkpointTxs) {
|
|
20801
|
+
return this.inner.submitTx(signedArkTx, checkpointTxs);
|
|
20802
|
+
}
|
|
20803
|
+
finalizeTx(arkTxid, finalCheckpointTxs) {
|
|
20804
|
+
return this.inner.finalizeTx(arkTxid, finalCheckpointTxs);
|
|
20805
|
+
}
|
|
20806
|
+
registerIntent(intent) {
|
|
20807
|
+
return this.inner.registerIntent(intent);
|
|
20808
|
+
}
|
|
20809
|
+
deleteIntent(intent) {
|
|
20810
|
+
return this.inner.deleteIntent(intent);
|
|
20811
|
+
}
|
|
20812
|
+
confirmRegistration(intentId) {
|
|
20813
|
+
return this.inner.confirmRegistration(intentId);
|
|
20814
|
+
}
|
|
20815
|
+
submitTreeNonces(batchId, pubkey, nonces) {
|
|
20816
|
+
return this.inner.submitTreeNonces(batchId, pubkey, nonces);
|
|
20817
|
+
}
|
|
20818
|
+
submitTreeSignatures(batchId, pubkey, signatures) {
|
|
20819
|
+
return this.inner.submitTreeSignatures(batchId, pubkey, signatures);
|
|
20820
|
+
}
|
|
20821
|
+
submitSignedForfeitTxs(signedForfeitTxs, signedCommitmentTx) {
|
|
20822
|
+
return this.inner.submitSignedForfeitTxs(signedForfeitTxs, signedCommitmentTx);
|
|
20823
|
+
}
|
|
20824
|
+
getEventStream(signal, topics) {
|
|
20825
|
+
return this.inner.getEventStream(signal, topics);
|
|
20826
|
+
}
|
|
20827
|
+
getTransactionsStream(signal) {
|
|
20828
|
+
return this.inner.getTransactionsStream(signal);
|
|
20829
|
+
}
|
|
20830
|
+
getPendingTxs(intent) {
|
|
20831
|
+
return this.inner.getPendingTxs(intent);
|
|
20832
|
+
}
|
|
20833
|
+
onServerInfoChanged(listener) {
|
|
20834
|
+
return this.inner.onServerInfoChanged?.(listener) ?? (() => {
|
|
20835
|
+
});
|
|
20836
|
+
}
|
|
20837
|
+
};
|
|
20838
|
+
var PrevTxUnavailableError = class extends Error {
|
|
20839
|
+
constructor(message, txids = []) {
|
|
20840
|
+
super(message);
|
|
20841
|
+
this.txids = txids;
|
|
20842
|
+
this.name = "PrevTxUnavailableError";
|
|
20843
|
+
}
|
|
20844
|
+
txids;
|
|
20845
|
+
};
|
|
20846
|
+
async function resolvePrevTxs(txids, source, onchain) {
|
|
20847
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
20848
|
+
const wanted = [...new Set(txids)];
|
|
20849
|
+
if (wanted.length === 0) return resolved;
|
|
20850
|
+
try {
|
|
20851
|
+
const { txs } = await source.getVirtualTxs(wanted);
|
|
20852
|
+
for (const psbt of txs) {
|
|
20853
|
+
const tx = Transaction.fromPSBT(base64.decode(psbt));
|
|
20854
|
+
resolved.set(tx.id, tx.toBytes());
|
|
20855
|
+
}
|
|
20856
|
+
} catch (err) {
|
|
20857
|
+
if (!onchain) throw err;
|
|
20858
|
+
}
|
|
20859
|
+
let missing = wanted.filter((txid) => !resolved.has(txid));
|
|
20860
|
+
if (missing.length > 0 && onchain) {
|
|
20861
|
+
const raw = await Promise.all(
|
|
20862
|
+
missing.map(async (txid) => {
|
|
20863
|
+
try {
|
|
20864
|
+
return await onchain.getRawTransaction(txid);
|
|
20865
|
+
} catch {
|
|
20866
|
+
return void 0;
|
|
20867
|
+
}
|
|
20868
|
+
})
|
|
20869
|
+
);
|
|
20870
|
+
for (const [i, bytes] of raw.entries()) {
|
|
20871
|
+
if (bytes) resolved.set(missing[i], bytes);
|
|
20872
|
+
}
|
|
20873
|
+
missing = missing.filter((txid) => !resolved.has(txid));
|
|
20874
|
+
}
|
|
20875
|
+
if (missing.length > 0) {
|
|
20876
|
+
throw new PrevTxUnavailableError(
|
|
20877
|
+
`cannot resolve the previous transaction of ${missing.join(", ")}` + (onchain ? "" : " (no onchain source configured)"),
|
|
20878
|
+
missing
|
|
20879
|
+
);
|
|
20880
|
+
}
|
|
20881
|
+
return resolved;
|
|
20882
|
+
}
|
|
20883
|
+
async function attachPrevArkTxs(tx, txids, source, onchain) {
|
|
20884
|
+
const pending = [];
|
|
20885
|
+
for (let i = 0; i < tx.inputsLength; i++) {
|
|
20886
|
+
if (getArkPsbtFields(tx, i, PrevArkTxField).length === 0) pending.push(i);
|
|
20887
|
+
}
|
|
20888
|
+
if (pending.length === 0) return;
|
|
20889
|
+
const resolved = await resolvePrevTxs(
|
|
20890
|
+
pending.map((i) => txidAt(txids, i)),
|
|
20891
|
+
source,
|
|
20892
|
+
onchain
|
|
20893
|
+
);
|
|
20894
|
+
for (const i of pending) {
|
|
20895
|
+
setArkPsbtField(tx, i, PrevArkTxField, resolved.get(txidAt(txids, i)));
|
|
20896
|
+
}
|
|
20897
|
+
}
|
|
20898
|
+
async function attachPrevoutTxs(tx, source) {
|
|
20899
|
+
const pending = [];
|
|
20900
|
+
for (let i = 0; i < tx.inputsLength; i++) {
|
|
20901
|
+
if (getArkPsbtFields(tx, i, PrevoutTxField).length > 0) continue;
|
|
20902
|
+
const input = tx.getInput(i);
|
|
20903
|
+
if (!input?.txid) throw new PrevTxUnavailableError(`input ${i} has no outpoint`);
|
|
20904
|
+
pending.push({ index: i, txid: hex.encode(input.txid) });
|
|
20905
|
+
}
|
|
20906
|
+
if (pending.length === 0) return;
|
|
20907
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
20908
|
+
for (const txid of new Set(pending.map((p) => p.txid))) {
|
|
20909
|
+
resolved.set(txid, await source.getRawTransaction(txid));
|
|
20910
|
+
}
|
|
20911
|
+
for (const { index, txid } of pending) {
|
|
20912
|
+
setArkPsbtField(tx, index, PrevoutTxField, resolved.get(txid));
|
|
20913
|
+
}
|
|
20914
|
+
}
|
|
20915
|
+
async function withPrevTxs(coins, source, onchain) {
|
|
20916
|
+
const pending = coins.filter((c) => !c.prevTx);
|
|
20917
|
+
if (pending.length === 0) return coins;
|
|
20918
|
+
const resolved = await resolvePrevTxs(
|
|
20919
|
+
pending.map((c) => c.txid),
|
|
20920
|
+
source,
|
|
20921
|
+
onchain
|
|
20922
|
+
);
|
|
20923
|
+
return coins.map((c) => c.prevTx ? c : { ...c, prevTx: resolved.get(c.txid) });
|
|
20924
|
+
}
|
|
20925
|
+
function txidAt(txids, index) {
|
|
20926
|
+
const txid = txids[index];
|
|
20927
|
+
if (txid === void 0) {
|
|
20928
|
+
throw new PrevTxUnavailableError(`no source txid supplied for input ${index}`);
|
|
20929
|
+
}
|
|
20930
|
+
return txid;
|
|
20931
|
+
}
|
|
20235
20932
|
var TAG_BIP322 = "BIP0322-signed-message";
|
|
20236
20933
|
var BIP322;
|
|
20237
20934
|
((BIP3222) => {
|
|
@@ -20609,6 +21306,22 @@ async function resolveUnilateralPath(params) {
|
|
|
20609
21306
|
return { selection: best.selection, label: "default:exit" };
|
|
20610
21307
|
}
|
|
20611
21308
|
|
|
21309
|
+
// src/wallet/exitObserver.ts
|
|
21310
|
+
function exitObserverFor(manager) {
|
|
21311
|
+
return (outpoint) => manager.refreshOutpoints([outpoint]);
|
|
21312
|
+
}
|
|
21313
|
+
async function notifyExitObserved(onExitObserved, outpoint) {
|
|
21314
|
+
if (!onExitObserved) return;
|
|
21315
|
+
try {
|
|
21316
|
+
await onExitObserved(outpoint);
|
|
21317
|
+
} catch (e) {
|
|
21318
|
+
console.error(
|
|
21319
|
+
`exit observer failed for ${outpoint.txid}:${outpoint.vout} \u2014 the exit is unaffected`,
|
|
21320
|
+
e
|
|
21321
|
+
);
|
|
21322
|
+
}
|
|
21323
|
+
}
|
|
21324
|
+
|
|
20612
21325
|
// src/wallet/unroll.ts
|
|
20613
21326
|
function chainTxTypeToChainedExit2(t) {
|
|
20614
21327
|
switch (t) {
|
|
@@ -20633,27 +21346,30 @@ var Unroll;
|
|
|
20633
21346
|
})(Unroll2.StepType || (Unroll2.StepType = {}));
|
|
20634
21347
|
class Session2 {
|
|
20635
21348
|
/** Create an unroll session from a virtual output outpoint and its dependency chain. */
|
|
20636
|
-
constructor(toUnroll, bumper, explorer, indexer, virtualTxRepository) {
|
|
21349
|
+
constructor(toUnroll, bumper, explorer, indexer, virtualTxRepository, onExitObserved) {
|
|
20637
21350
|
this.toUnroll = toUnroll;
|
|
20638
21351
|
this.bumper = bumper;
|
|
20639
21352
|
this.explorer = explorer;
|
|
20640
21353
|
this.indexer = indexer;
|
|
20641
21354
|
this.virtualTxRepository = virtualTxRepository;
|
|
21355
|
+
this.onExitObserved = onExitObserved;
|
|
20642
21356
|
}
|
|
20643
21357
|
toUnroll;
|
|
20644
21358
|
bumper;
|
|
20645
21359
|
explorer;
|
|
20646
21360
|
indexer;
|
|
20647
21361
|
virtualTxRepository;
|
|
21362
|
+
onExitObserved;
|
|
20648
21363
|
/** Create an unroll session by loading the virtual output chain from the indexer. */
|
|
20649
|
-
static async create(toUnroll, bumper, explorer, indexer, virtualTxRepository) {
|
|
21364
|
+
static async create(toUnroll, bumper, explorer, indexer, virtualTxRepository, onExitObserved) {
|
|
20650
21365
|
const { chain } = await indexer.getVtxoChain(toUnroll);
|
|
20651
21366
|
return new Session2(
|
|
20652
21367
|
{ ...toUnroll, chain },
|
|
20653
21368
|
bumper,
|
|
20654
21369
|
explorer,
|
|
20655
21370
|
indexer,
|
|
20656
|
-
virtualTxRepository
|
|
21371
|
+
virtualTxRepository,
|
|
21372
|
+
onExitObserved
|
|
20657
21373
|
);
|
|
20658
21374
|
}
|
|
20659
21375
|
/**
|
|
@@ -20689,6 +21405,14 @@ var Unroll;
|
|
|
20689
21405
|
}
|
|
20690
21406
|
/**
|
|
20691
21407
|
* Get the next step to be executed
|
|
21408
|
+
*
|
|
21409
|
+
* @remarks
|
|
21410
|
+
* `do()` is the step, not a formality: every effect lives there, and at
|
|
21411
|
+
* `StepType.DONE` that includes firing {@link onExitObserved}. A caller
|
|
21412
|
+
* driving `next()` by hand must always await it — the async iterator
|
|
21413
|
+
* below does. Reading `type` and skipping `do()` leaves the exit
|
|
21414
|
+
* unobserved, and on the other step kinds unbroadcast.
|
|
21415
|
+
*
|
|
20692
21416
|
* @returns The next step to be executed + the function to execute it
|
|
20693
21417
|
*/
|
|
20694
21418
|
async next() {
|
|
@@ -20717,7 +21441,12 @@ var Unroll;
|
|
|
20717
21441
|
return {
|
|
20718
21442
|
type: 2 /* DONE */,
|
|
20719
21443
|
vtxoTxid: this.toUnroll.txid,
|
|
20720
|
-
do
|
|
21444
|
+
// The observation rides on `do` rather than the iterator so
|
|
21445
|
+
// a caller driving `next()` by hand fires it too.
|
|
21446
|
+
do: () => notifyExitObserved(this.onExitObserved, {
|
|
21447
|
+
txid: this.toUnroll.txid,
|
|
21448
|
+
vout: this.toUnroll.vout
|
|
21449
|
+
})
|
|
20721
21450
|
};
|
|
20722
21451
|
}
|
|
20723
21452
|
const virtualTxBase64 = await this.resolveVirtualTxBase64(nextTxToBroadcast);
|
|
@@ -20751,9 +21480,22 @@ var Unroll;
|
|
|
20751
21480
|
}
|
|
20752
21481
|
}
|
|
20753
21482
|
Unroll2.Session = Session2;
|
|
21483
|
+
async function sessionFor(wallet, toUnroll, bumper) {
|
|
21484
|
+
const manager = await wallet.getContractManager();
|
|
21485
|
+
return Session2.create(
|
|
21486
|
+
toUnroll,
|
|
21487
|
+
bumper,
|
|
21488
|
+
wallet.onchainProvider,
|
|
21489
|
+
wallet.indexerProvider,
|
|
21490
|
+
wallet.virtualTxRepository,
|
|
21491
|
+
exitObserverFor(manager)
|
|
21492
|
+
);
|
|
21493
|
+
}
|
|
21494
|
+
Unroll2.sessionFor = sessionFor;
|
|
20754
21495
|
async function completeUnroll(wallet, vtxoTxids, outputAddress) {
|
|
20755
21496
|
const signedTx = await prepareUnrollTransaction(wallet, vtxoTxids, outputAddress);
|
|
20756
21497
|
await wallet.onchainProvider.broadcastTransaction(signedTx.hex);
|
|
21498
|
+
await refreshSpentExitOutputs(wallet, signedTx);
|
|
20757
21499
|
return signedTx.id;
|
|
20758
21500
|
}
|
|
20759
21501
|
Unroll2.completeUnroll = completeUnroll;
|
|
@@ -20769,9 +21511,9 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
|
|
|
20769
21511
|
let totalAmount = 0n;
|
|
20770
21512
|
const txWeightEstimator = TxWeightEstimator.create();
|
|
20771
21513
|
for (const vtxo of vtxos) {
|
|
20772
|
-
if (!vtxo
|
|
21514
|
+
if (!canSweepOnchain(vtxo)) {
|
|
20773
21515
|
throw new Error(
|
|
20774
|
-
`Vtxo ${vtxo.txid}:${vtxo.vout} is not fully unrolled
|
|
21516
|
+
`Vtxo ${vtxo.txid}:${vtxo.vout} cannot be swept onchain: it is not fully unrolled (use unroll first), or its exit output was already spent`
|
|
20775
21517
|
);
|
|
20776
21518
|
}
|
|
20777
21519
|
const txStatus = await wallet.onchainProvider.getTxStatus(vtxo.txid);
|
|
@@ -20832,6 +21574,22 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
|
|
|
20832
21574
|
signedTx.finalize();
|
|
20833
21575
|
return signedTx;
|
|
20834
21576
|
}
|
|
21577
|
+
async function refreshSpentExitOutputs(wallet, signedTx) {
|
|
21578
|
+
const outpoints = [];
|
|
21579
|
+
for (let i = 0; i < signedTx.inputsLength; i++) {
|
|
21580
|
+
const input = signedTx.getInput(i);
|
|
21581
|
+
if (input.txid && input.index !== void 0) {
|
|
21582
|
+
outpoints.push({ txid: hex.encode(input.txid), vout: input.index });
|
|
21583
|
+
}
|
|
21584
|
+
}
|
|
21585
|
+
if (outpoints.length === 0) return;
|
|
21586
|
+
try {
|
|
21587
|
+
const manager = await wallet.getContractManager();
|
|
21588
|
+
await manager.refreshOutpoints(outpoints);
|
|
21589
|
+
} catch (e) {
|
|
21590
|
+
console.error("completeUnroll: failed to refresh the spent exit outputs", e);
|
|
21591
|
+
}
|
|
21592
|
+
}
|
|
20835
21593
|
function sleep2(ms) {
|
|
20836
21594
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
20837
21595
|
}
|
|
@@ -20910,7 +21668,7 @@ async function buildSignedSweep(params) {
|
|
|
20910
21668
|
}
|
|
20911
21669
|
|
|
20912
21670
|
// src/wallet/exit/estimate.ts
|
|
20913
|
-
var CHILD_OUTPUT_DUST =
|
|
21671
|
+
var CHILD_OUTPUT_DUST = CHILD_DUST_AMOUNT;
|
|
20914
21672
|
function stepFundingAmount(stepFee) {
|
|
20915
21673
|
return stepFee + CHILD_OUTPUT_DUST;
|
|
20916
21674
|
}
|
|
@@ -21071,10 +21829,18 @@ async function computeExitLayout(opts, feeRate) {
|
|
|
21071
21829
|
// splitter. funded: + 1 splitter tx and pre-signed children.
|
|
21072
21830
|
txCount: (graph ? 0 : steps.length > 0 ? 1 : 0) + steps.length * 2 + sweeps.length,
|
|
21073
21831
|
totalFeeSats: splitterFee + stepFees + sweepFees,
|
|
21074
|
-
// graph funding is what the executor sends to its own fee address:
|
|
21075
|
-
//
|
|
21076
|
-
//
|
|
21077
|
-
|
|
21832
|
+
// graph funding is what the executor sends to its own fee address: the
|
|
21833
|
+
// CPFP fees, plus one dust floor. Change recycles through that single
|
|
21834
|
+
// address, so each bump hands its remainder to the next and only the
|
|
21835
|
+
// *final* change has to clear `CHILD_DUST_AMOUNT` — but it does have to,
|
|
21836
|
+
// and `buildAnchorChild` throws rather than absorbing a short remainder
|
|
21837
|
+
// into the fee. Quoting bare fees quotes an amount that strands the last
|
|
21838
|
+
// bump and every sweep behind it.
|
|
21839
|
+
//
|
|
21840
|
+
// funded reserves the same floor per step instead of once overall (see
|
|
21841
|
+
// `stepFundingAmount`), because it pre-funds each child separately
|
|
21842
|
+
// through the splitter rather than recycling one output.
|
|
21843
|
+
fundingRequiredSats: graph ? steps.length > 0 ? stepFees + CHILD_OUTPUT_DUST : 0 : splitterFee + fundingTotal,
|
|
21078
21844
|
recoveredSats: sweeps.reduce((s, x) => s + (x.vtxo.value - x.sweepFee), 0)
|
|
21079
21845
|
};
|
|
21080
21846
|
const expiries = pendingNodes.map((n) => n.expiresAt).filter((x) => x !== void 0);
|
|
@@ -21134,12 +21900,32 @@ var Executor = class {
|
|
|
21134
21900
|
this.pollIntervalMs = opts?.pollIntervalMs ?? 5e3;
|
|
21135
21901
|
this.feeWallet = opts?.feeWallet;
|
|
21136
21902
|
this.signal = opts?.signal;
|
|
21903
|
+
this.onExitObserved = opts?.onExitObserved;
|
|
21137
21904
|
}
|
|
21138
21905
|
pkg;
|
|
21139
21906
|
provider;
|
|
21140
21907
|
pollIntervalMs;
|
|
21141
21908
|
feeWallet;
|
|
21142
21909
|
signal;
|
|
21910
|
+
onExitObserved;
|
|
21911
|
+
/**
|
|
21912
|
+
* Per-VTXO branch progress, which the executor otherwise does not track:
|
|
21913
|
+
* `dead` / `done` are per-step, and a VTXO is only onchain once EVERY
|
|
21914
|
+
* `package`/`bump` step naming it has confirmed. (`broadcast` — the funding
|
|
21915
|
+
* splitter — carries no `forVtxos` and serves no single VTXO.)
|
|
21916
|
+
*/
|
|
21917
|
+
branchSteps() {
|
|
21918
|
+
const byVtxo = /* @__PURE__ */ new Map();
|
|
21919
|
+
this.pkg.steps.forEach((step, i) => {
|
|
21920
|
+
if (step.kind !== "package" && step.kind !== "bump") return;
|
|
21921
|
+
for (const vtxo of step.forVtxos) {
|
|
21922
|
+
let steps = byVtxo.get(vtxo);
|
|
21923
|
+
if (!steps) byVtxo.set(vtxo, steps = /* @__PURE__ */ new Set());
|
|
21924
|
+
steps.add(i);
|
|
21925
|
+
}
|
|
21926
|
+
});
|
|
21927
|
+
return byVtxo;
|
|
21928
|
+
}
|
|
21143
21929
|
/**
|
|
21144
21930
|
* Poll delay. Nearly all wall-clock time is spent here, so it must be the
|
|
21145
21931
|
* thing that reacts to abort — checking only between polls would leave
|
|
@@ -21179,6 +21965,19 @@ var Executor = class {
|
|
|
21179
21965
|
async *[Symbol.asyncIterator]() {
|
|
21180
21966
|
throwIfAborted(this.signal);
|
|
21181
21967
|
const dead = /* @__PURE__ */ new Set();
|
|
21968
|
+
const branchSteps = this.branchSteps();
|
|
21969
|
+
const onchainSteps = /* @__PURE__ */ new Set();
|
|
21970
|
+
const branchObserved = /* @__PURE__ */ new Set();
|
|
21971
|
+
const observeBranch = async (stepIndex, forVtxos) => {
|
|
21972
|
+
onchainSteps.add(stepIndex);
|
|
21973
|
+
for (const vtxo of forVtxos ?? []) {
|
|
21974
|
+
if (branchObserved.has(vtxo)) continue;
|
|
21975
|
+
const steps = branchSteps.get(vtxo);
|
|
21976
|
+
if (!steps || ![...steps].every((i) => onchainSteps.has(i))) continue;
|
|
21977
|
+
branchObserved.add(vtxo);
|
|
21978
|
+
await this.observe(vtxo);
|
|
21979
|
+
}
|
|
21980
|
+
};
|
|
21182
21981
|
if (this.pkg.validUntil && Date.now() / 1e3 > this.pkg.validUntil) {
|
|
21183
21982
|
yield {
|
|
21184
21983
|
stepIndex: -1,
|
|
@@ -21208,6 +22007,7 @@ var Executor = class {
|
|
|
21208
22007
|
const anchorTxid = step.kind === "package" || step.kind === "bump" ? step.parentTxid : step.txid;
|
|
21209
22008
|
const existing = await this.status(anchorTxid);
|
|
21210
22009
|
if (existing?.confirmed) {
|
|
22010
|
+
await observeBranch(i, forVtxos);
|
|
21211
22011
|
yield {
|
|
21212
22012
|
stepIndex: i,
|
|
21213
22013
|
kind: step.kind,
|
|
@@ -21263,6 +22063,7 @@ var Executor = class {
|
|
|
21263
22063
|
}
|
|
21264
22064
|
}
|
|
21265
22065
|
await this.waitConfirmed(anchorTxid);
|
|
22066
|
+
await observeBranch(i, forVtxos);
|
|
21266
22067
|
yield {
|
|
21267
22068
|
stepIndex: i,
|
|
21268
22069
|
kind: step.kind,
|
|
@@ -21293,6 +22094,7 @@ var Executor = class {
|
|
|
21293
22094
|
const swept = await this.status(step.txid);
|
|
21294
22095
|
if (swept?.confirmed) {
|
|
21295
22096
|
done.add(index);
|
|
22097
|
+
await this.observe(step.vtxo);
|
|
21296
22098
|
yield {
|
|
21297
22099
|
stepIndex: index,
|
|
21298
22100
|
kind: "sweep",
|
|
@@ -21349,7 +22151,25 @@ var Executor = class {
|
|
|
21349
22151
|
if (done.size < pending.length) await this.sleep();
|
|
21350
22152
|
}
|
|
21351
22153
|
}
|
|
22154
|
+
/** `"txid:vout"` -> outpoint, then hand it to the hook. A malformed entry is skipped. */
|
|
22155
|
+
async observe(outpoint) {
|
|
22156
|
+
if (!this.onExitObserved) return;
|
|
22157
|
+
const sep = outpoint.lastIndexOf(":");
|
|
22158
|
+
const rest = outpoint.slice(sep + 1);
|
|
22159
|
+
const vout = Number(rest);
|
|
22160
|
+
if (sep <= 0 || rest === "" || !Number.isInteger(vout)) return;
|
|
22161
|
+
await notifyExitObserved(this.onExitObserved, { txid: outpoint.slice(0, sep), vout });
|
|
22162
|
+
}
|
|
21352
22163
|
};
|
|
22164
|
+
|
|
22165
|
+
// src/wallet/exit/execute.ts
|
|
22166
|
+
async function execute(wallet, pkg, opts) {
|
|
22167
|
+
const manager = await wallet.getContractManager();
|
|
22168
|
+
return new Executor(pkg, opts?.provider ?? wallet.onchainProvider, {
|
|
22169
|
+
...opts,
|
|
22170
|
+
onExitObserved: opts?.onExitObserved ?? exitObserverFor(manager)
|
|
22171
|
+
});
|
|
22172
|
+
}
|
|
21353
22173
|
async function prepare(opts) {
|
|
21354
22174
|
const { wallet, onchainWallet } = opts;
|
|
21355
22175
|
const feeRate = await resolveFeeRate(opts);
|
|
@@ -21424,7 +22244,10 @@ async function prepare(opts) {
|
|
|
21424
22244
|
totals: {
|
|
21425
22245
|
txCount: bumpSteps.length * 2 + sweepSteps.length,
|
|
21426
22246
|
totalFeeSats: stepFees2 + sweepFees2,
|
|
21427
|
-
|
|
22247
|
+
// Fees plus the single dust floor the recycling change output
|
|
22248
|
+
// must keep clear; see the note in `estimate.ts`. Must match
|
|
22249
|
+
// the quote `estimate` gives for the same package.
|
|
22250
|
+
fundingRequiredSats: bumpSteps.length > 0 ? stepFees2 + CHILD_OUTPUT_DUST : 0,
|
|
21428
22251
|
recoveredSats: recovered2
|
|
21429
22252
|
},
|
|
21430
22253
|
vtxos: layout.infos,
|
|
@@ -21593,6 +22416,7 @@ function isValidStep(step) {
|
|
|
21593
22416
|
var UnilateralExit = {
|
|
21594
22417
|
estimate,
|
|
21595
22418
|
prepare,
|
|
22419
|
+
execute,
|
|
21596
22420
|
Executor
|
|
21597
22421
|
};
|
|
21598
22422
|
|
|
@@ -22018,7 +22842,9 @@ var ArkadeContract = class _ArkadeContract {
|
|
|
22018
22842
|
const [registered] = await manager.getContracts({ script: scriptHex });
|
|
22019
22843
|
if (registered) {
|
|
22020
22844
|
const [withVtxos] = await manager.getContractsWithVtxos({ script: scriptHex });
|
|
22021
|
-
return (withVtxos?.vtxos ?? []).filter(
|
|
22845
|
+
return (withVtxos?.vtxos ?? []).filter(
|
|
22846
|
+
(v) => !hasTerminalSpend(v) && !v.isUnrolled
|
|
22847
|
+
);
|
|
22022
22848
|
}
|
|
22023
22849
|
}
|
|
22024
22850
|
if (!this.client.indexer) {
|
|
@@ -22128,6 +22954,19 @@ var ArkadeTransactionBuilder = class {
|
|
|
22128
22954
|
if (coin.sourceTx) {
|
|
22129
22955
|
setArkPsbtField(arkTx, 0, PrevArkTxField, coin.sourceTx);
|
|
22130
22956
|
}
|
|
22957
|
+
if (this.fn.arkadeScript) {
|
|
22958
|
+
const indexer = this.contract.client.indexer;
|
|
22959
|
+
if (!indexer) {
|
|
22960
|
+
throw new PrevTxUnavailableError(
|
|
22961
|
+
"covenant spends require an `indexer` on the Arkade client to resolve the previous ark tx of each input"
|
|
22962
|
+
);
|
|
22963
|
+
}
|
|
22964
|
+
await attachPrevArkTxs(
|
|
22965
|
+
arkTx,
|
|
22966
|
+
[coin.txid, ...this.fundingCoins.map((c) => c.txid)],
|
|
22967
|
+
indexer
|
|
22968
|
+
);
|
|
22969
|
+
}
|
|
22131
22970
|
const condition = (def.tapscript.witness ?? []).map((w) => this.witnessBytes(w));
|
|
22132
22971
|
if (condition.length > 0) {
|
|
22133
22972
|
setArkPsbtField(arkTx, 0, ConditionWitness, condition);
|
|
@@ -22633,6 +23472,6 @@ function createDefaultPaymentRouter(wallet) {
|
|
|
22633
23472
|
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
22634
23473
|
*/
|
|
22635
23474
|
|
|
22636
|
-
export { ARKADE_MAGIC, ARKADE_SALTED_PREIMAGE_TAG, ARKADE_SWAP_PREIMAGE_TAG, ActivityRegistry, AmbiguousRouteError, ArkNote, ArkadeCash, ArkadeCashCreateError, AssetManager, BIP21, BIP21Error, BIP322, BLOCKED_UPGRADE_TIMEOUT_MS, Batch, ChainedTxType, ConnectionDisposedError, ContractManager, ContractRepositoryImpl, ContractWatcher, DB_VERSION, DEFAULT_MESSAGE_TIMEOUTS, DEFAULT_MIN_BATCH_EXPIRY_SECONDS, DEFAULT_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, DatabaseUpgradeBlockedError, DelegateManagerImpl, DelegateNotConfiguredError, DelegatorManagerImpl, DelegatorNotConfiguredError, DescriptorIdentity, DescriptorSigningProviderMissingError, DustChangeError, ELECTRUM_TCP_HOST, ELECTRUM_WS_URL, ESPLORA_URL, ElectrumOnchainProvider, EmulatorPacket, EsploraProvider, Estimator, Extension, ExtensionNotFoundError, ForeignDescriptorError, HDDescriptorProvider, INTENT_TERMINAL_STATES, InMemoryContractRepository, InMemoryIntentRepository, InMemoryVirtualTxRepository, InMemoryWalletRepository, IndexedDBContractRepository, IndexedDBIntentRepository, IndexedDBVirtualTxRepository, IndexedDBWalletRepository, MAX_USED_SIGNING_DESCRIPTORS_LOOK_AHEAD, MESSAGE_BUS_INITIALIZING, MESSAGE_BUS_NOT_INITIALIZED, MIGRATION_KEY, MUTINYNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, MessageBus, MessageBusInitializingError, MessageBusNotInitializedError, MissingSigningDescriptorError, MnemonicIdentity, OnchainWallet, P2A, PaymentRouter, REGTEST_MIN_BATCH_EXPIRY_SECONDS, REGTEST_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, Ramps, ReadonlyAssetManager, ReadonlyDescriptorIdentity, ReadonlySingleKey, ReadonlyWallet, ReadonlyWalletError, RestDelegateProvider, RestDelegatorProvider, RestEmulatorProvider, SIGNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, SeedIdentity, ServiceWorkerReadonlyWallet, ServiceWorkerTimeoutError, ServiceWorkerWallet, SingleKey, TxTree, TxType, TxWeightEstimator, UnannotatableInputError, UnilateralExit, UnknownPacket, Unroll, VtxoManager, Wallet2 as Wallet, WalletCannotSignError, WalletMessageHandler, WalletNotInitializedError, WalletRepositoryImpl, WsElectrumChainSource, adoptContractDescriptor, arkRail, arkTarget, arkade_exports, assertFinalCommitmentMatchesValidated, assertIntentIdUnique, assertSendableAmount, assertSubmittedArkTxid, assertValidBatchExpiry, assertValidServerUnrollScript, assetMintResolver, awaitTransaction, boardingResolver, btcTarget, buildForfeitTx, buildOffchainTx, buildPreimageMessage, buildSaltedPreimageMessage, claimWithPreimageIdentity, classifyAgainstSignerSet, classifyContractSigner, closeDatabase, collabExitResolver, combineTapscriptSigs, contractFromArkContract, contractFromArkContractWithAddress, contractPreimage, contractSigner, createAssetPacket, createDefaultActivityRegistry, createDefaultPaymentRouter, createExitChainResolver, createManagedConnection, decodeArkContract, defaultBatchExpiryPolicy, defaultCheckpointExitDelayPolicy, deleteByIndex, deserializeAssets, deserializeExitPackage, deserializeUtxo, deserializeVtxo, encodeArkContract, extendVirtualCoinForContract, gateExclusion, gatedContracts, getAllByIndexValues, getMigrationStatus, getRandomId, hasBoardingTxExpired, hasCandidates, intentMatchesFilter, intentPageBounds, invoiceTarget, isArkContract, isBatchSignable, isBtcAddress, isContractGenericallySpendable, isCooperativelyMigratable, isDeterministicSigner, isDiscoverable, isHDAllocationCapable, isHDDeterministicSignCapable, isHDWalletCapable, isLightningInvoice, isLnurl, isMessageBusInitializingError, isMessageBusNotInitializedError, isPerArtifactDescriptor, isSigningIdentity, isSubdust, isTerminalIntentState, isValidArkAddress, isVtxoExpiringSoon, isVtxoForScript, isWatchedContract, logExcludedVtxos, makeHandle, matchServerCheckpoints, mergeChainedTxType, migrateWalletRepository, onchainRail, openDatabase, outpointExclusion, outpointReasons, promisifyRequest, provisionClaimSecret, provisionRefundKey, requiresMigration, resolveBatchExpiryPolicy, resolveCheckpointExitDelayPolicy, resolveDescriptorSigner, resolveSendAmount, rollbackMigration, saveVtxosForContract, scriptFromArkAddress, selectCoinsWithAsset, selectVirtualCoins, serializeAssets, serializeExitPackage, serializeUtxo, serializeVtxo, setupServiceWorker, signAndSubmitOffchainTx, signerSetFromInfo, signingDescriptorIndex, strictSigningDescriptorIndex, toXOnlySignerHex, tryResolveSendAmount, validateBatchRecipients, validateConnectorsTxGraph, validateVtxoTxGraph, verifyTapscriptSignatures, waitForIncomingFunds, warnAndFilterVtxosForScript };
|
|
22637
|
-
//# sourceMappingURL=chunk-
|
|
22638
|
-
//# sourceMappingURL=chunk-
|
|
23475
|
+
export { ARKADE_MAGIC, ARKADE_SALTED_PREIMAGE_TAG, ARKADE_SWAP_PREIMAGE_TAG, ActivityRegistry, AmbiguousRouteError, ArkNote, ArkadeCash, ArkadeCashCreateError, AssetManager, BIP21, BIP21Error, BIP322, BLOCKED_UPGRADE_TIMEOUT_MS, Batch, CachingArkProvider, ChainedTxType, ConnectionDisposedError, ContractManager, ContractRepositoryImpl, ContractWatcher, DB_VERSION, DEFAULT_MESSAGE_TIMEOUTS, DEFAULT_MIN_BATCH_EXPIRY_SECONDS, DEFAULT_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, DatabaseUpgradeBlockedError, DelegateManagerImpl, DelegateNotConfiguredError, DelegatorManagerImpl, DelegatorNotConfiguredError, DescriptorIdentity, DescriptorSigningProviderMissingError, DustChangeError, ELECTRUM_TCP_HOST, ELECTRUM_WS_URL, ESPLORA_URL, ElectrumOnchainProvider, EmulatorPacket, EsploraProvider, Estimator, Extension, ExtensionNotFoundError, ForeignDescriptorError, HDDescriptorProvider, INTENT_TERMINAL_STATES, InMemoryContractRepository, InMemoryIntentRepository, InMemoryVirtualTxRepository, InMemoryWalletRepository, IndexedDBContractRepository, IndexedDBIntentRepository, IndexedDBVirtualTxRepository, IndexedDBWalletRepository, MAX_USED_SIGNING_DESCRIPTORS_LOOK_AHEAD, MESSAGE_BUS_INITIALIZING, MESSAGE_BUS_NOT_INITIALIZED, MIGRATION_KEY, MUTINYNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, MessageBus, MessageBusInitializingError, MessageBusNotInitializedError, MissingSigningDescriptorError, MnemonicIdentity, OnchainWallet, P2A, PaymentRouter, PrevTxUnavailableError, REGTEST_MIN_BATCH_EXPIRY_SECONDS, REGTEST_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, Ramps, ReadonlyAssetManager, ReadonlyDescriptorIdentity, ReadonlySingleKey, ReadonlyWallet, ReadonlyWalletError, RestDelegateProvider, RestDelegatorProvider, RestEmulatorProvider, SIGNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, SeedIdentity, ServiceWorkerReadonlyWallet, ServiceWorkerTimeoutError, ServiceWorkerWallet, SingleKey, TxTree, TxType, TxWeightEstimator, UnannotatableInputError, UnilateralExit, UnknownPacket, Unroll, VtxoManager, Wallet2 as Wallet, WalletCannotAllocateAddressError, WalletCannotSignError, WalletMessageHandler, WalletNotInitializedError, WalletRepositoryImpl, WsElectrumChainSource, adoptContractDescriptor, arkRail, arkTarget, arkade_exports, assertFinalCommitmentMatchesValidated, assertIntentIdUnique, assertSendableAmount, assertSubmittedArkTxid, assertValidBatchExpiry, assertValidServerUnrollScript, assetMintResolver, attachPrevArkTxs, attachPrevoutTxs, awaitTransaction, boardingResolver, btcTarget, buildForfeitTx, buildOffchainTx, buildPreimageMessage, buildSaltedPreimageMessage, claimWithPreimageIdentity, classifyAgainstSignerSet, classifyContractSigner, closeDatabase, collabExitResolver, combineTapscriptSigs, contractFromArkContract, contractFromArkContractWithAddress, contractPreimage, contractSigner, createAssetPacket, createDefaultActivityRegistry, createDefaultPaymentRouter, createExitChainResolver, createManagedConnection, decodeArkContract, defaultBatchExpiryPolicy, defaultCheckpointExitDelayPolicy, deleteByIndex, deserializeAssets, deserializeExitPackage, deserializeUtxo, deserializeVtxo, encodeArkContract, exitObserverFor, extendVirtualCoinForContract, extractArkProviderUrl, gateExclusion, gatedContracts, getAllByIndexValues, getMigrationStatus, getRandomId, hasBoardingTxExpired, hasCandidates, intentMatchesFilter, intentPageBounds, invoiceTarget, isAddressAllocationCapable, isArkContract, isBatchSignable, isBtcAddress, isContractGenericallySpendable, isCooperativelyMigratable, isDeterministicSigner, isDiscoverable, isHDAllocationCapable, isHDDeterministicSignCapable, isHDWalletCapable, isLightningInvoice, isLnurl, isMessageBusInitializingError, isMessageBusNotInitializedError, isPerArtifactDescriptor, isSigningIdentity, isSubdust, isTerminalIntentState, isValidArkAddress, isVtxoExpiringSoon, isVtxoForScript, isWatchedContract, logExcludedVtxos, makeHandle, matchServerCheckpoints, mergeChainedTxType, migrateWalletRepository, notifyExitObserved, onchainRail, openDatabase, outpointExclusion, outpointReasons, promisifyRequest, provisionClaimSecret, provisionRefundKey, requiresMigration, resolveBatchExpiryPolicy, resolveCheckpointExitDelayPolicy, resolveDescriptorSigner, resolvePrevTxs, resolveSendAmount, rollbackMigration, saveVtxosForContract, scriptFromArkAddress, selectCoinsWithAsset, selectVirtualCoins, serializeAssets, serializeExitPackage, serializeUtxo, serializeVtxo, setupServiceWorker, signAndSubmitOffchainTx, signerSetFromInfo, signingDescriptorIndex, strictSigningDescriptorIndex, toXOnlySignerHex, tryResolveSendAmount, validateBatchRecipients, validateConnectorsTxGraph, validateVtxoTxGraph, verifyTapscriptSignatures, waitForIncomingFunds, warnAndFilterVtxosForScript, withPrevTxs };
|
|
23476
|
+
//# sourceMappingURL=chunk-AEWJU6NZ.js.map
|
|
23477
|
+
//# sourceMappingURL=chunk-AEWJU6NZ.js.map
|