@arkade-os/sdk 0.4.67 → 0.4.69
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 +38 -0
- package/dist/adapters/expo.cjs +5 -5
- package/dist/adapters/expo.d.cts +2 -2
- package/dist/adapters/expo.d.ts +2 -2
- package/dist/adapters/expo.js +3 -3
- package/dist/adapters/indexedDB.cjs +5 -5
- package/dist/adapters/indexedDB.js +4 -4
- package/dist/{asyncStorageTaskQueue-Za-e_zMk.d.ts → asyncStorageTaskQueue-BgUJN-3X.d.ts} +2 -2
- package/dist/{asyncStorageTaskQueue-LTpeXYaD.d.cts → asyncStorageTaskQueue-Cstx6hS7.d.cts} +2 -2
- package/dist/{chunk-6TAQF6EV.js → chunk-2PPL3O7Z.js} +72 -120
- package/dist/chunk-2PPL3O7Z.js.map +1 -0
- package/dist/{chunk-2JV4VQ7C.cjs → chunk-5MLC2HU3.cjs} +17 -3
- package/dist/chunk-5MLC2HU3.cjs.map +1 -0
- package/dist/{chunk-MJUTO3PY.cjs → chunk-EBYCTLET.cjs} +832 -488
- package/dist/chunk-EBYCTLET.cjs.map +1 -0
- package/dist/{chunk-CO3KKSWM.cjs → chunk-GVHUHTRH.cjs} +17 -17
- package/dist/{chunk-CO3KKSWM.cjs.map → chunk-GVHUHTRH.cjs.map} +1 -1
- package/dist/{chunk-YDRZDZPP.cjs → chunk-HQ4DMGA4.cjs} +10 -10
- package/dist/{chunk-YDRZDZPP.cjs.map → chunk-HQ4DMGA4.cjs.map} +1 -1
- package/dist/{chunk-3WIWNE4P.js → chunk-L5SCQYHF.js} +16 -4
- package/dist/chunk-L5SCQYHF.js.map +1 -0
- package/dist/{chunk-MZFUZUTQ.js → chunk-MNMPGEK2.js} +4 -4
- package/dist/{chunk-MZFUZUTQ.js.map → chunk-MNMPGEK2.js.map} +1 -1
- package/dist/{chunk-AEWJU6NZ.js → chunk-TA7XLEP2.js} +411 -68
- package/dist/chunk-TA7XLEP2.js.map +1 -0
- package/dist/{chunk-OIZ2V2VD.cjs → chunk-WIFL5QYZ.cjs} +118 -166
- package/dist/chunk-WIFL5QYZ.cjs.map +1 -0
- package/dist/{chunk-EALWOVHK.js → chunk-XLWDX7QZ.js} +4 -4
- package/dist/{chunk-EALWOVHK.js.map → chunk-XLWDX7QZ.js.map} +1 -1
- package/dist/{chunk-R2YAMONM.cjs → chunk-XQPN5YP2.cjs} +17 -17
- package/dist/{chunk-R2YAMONM.cjs.map → chunk-XQPN5YP2.cjs.map} +1 -1
- package/dist/{chunk-X3VEMUVV.js → chunk-YG7T6LI3.js} +3 -3
- package/dist/{chunk-X3VEMUVV.js.map → chunk-YG7T6LI3.js.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-cdmzb2f9.d.ts → delegate-BPdzTbwN.d.ts} +1 -1
- package/dist/{delegate-Bz2e2zXY.d.cts → delegate-DrwIar11.d.cts} +1 -1
- package/dist/{hdWalletCapable-Hi12xjCJ.d.ts → hdWalletCapable-D4WH35z0.d.cts} +49 -5
- package/dist/{hdWalletCapable-BSjuUYOO.d.cts → hdWalletCapable-DyxCiNVE.d.ts} +49 -5
- package/dist/{index-BiACuWaf.d.ts → index-BqhpAqqj.d.cts} +96 -119
- package/dist/{index-D2GjZxBr.d.cts → index-TZJvbIaA.d.ts} +96 -119
- package/dist/{index-DU5o_hz7.d.cts → index-dWRqYSdS.d.cts} +70 -2
- package/dist/{index-DU5o_hz7.d.ts → index-dWRqYSdS.d.ts} +70 -2
- package/dist/index.cjs +297 -289
- package/dist/index.d.cts +29 -8
- package/dist/index.d.ts +29 -8
- 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-BZJMLQ6g.d.cts → taskRunner-CzYKyJ9c.d.cts} +2 -2
- package/dist/{taskRunner-DATaRQus.d.ts → taskRunner-D2fnbqYw.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 +14 -14
- package/dist/wallet/expo/index.d.cts +4 -4
- package/dist/wallet/expo/index.d.ts +4 -4
- package/dist/wallet/expo/index.js +5 -5
- package/dist/worker/expo/index.cjs +9 -9
- package/dist/worker/expo/index.d.cts +4 -4
- package/dist/worker/expo/index.d.ts +4 -4
- package/dist/worker/expo/index.js +5 -5
- package/package.json +1 -1
- package/dist/chunk-2JV4VQ7C.cjs.map +0 -1
- package/dist/chunk-3WIWNE4P.js.map +0 -1
- package/dist/chunk-6TAQF6EV.js.map +0 -1
- package/dist/chunk-AEWJU6NZ.js.map +0 -1
- package/dist/chunk-MJUTO3PY.cjs.map +0 -1
- package/dist/chunk-OIZ2V2VD.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, identityDescriptor, DefaultVtxo, speculativeReceiveMetadata, DelegateVtxo, WALLET_RECEIVE_SOURCE, BoardingContractHandler } from './chunk-
|
|
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-
|
|
1
|
+
import { AssetId, AssetGroup, AssetInput, AssetOutput, Metadata, Packet, BufferReader, BufferWriter, AssetRef, RestIndexerProvider } from './chunk-YG7T6LI3.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-2PPL3O7Z.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, assertAllowedSighashTypes, baseFetch, Intent, rateGate, DEFAULT_NETWORK_NAME, formatSighash, 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-L5SCQYHF.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';
|
|
@@ -272,7 +272,7 @@ function getPrevOutput(finalKey, graph, sharedOutputAmount, tx) {
|
|
|
272
272
|
script: pkScript
|
|
273
273
|
};
|
|
274
274
|
}
|
|
275
|
-
var
|
|
275
|
+
var ALLOWED_SIGHASH = [SigHash.DEFAULT, SigHash.ALL, SigHash.ALL_ANYONECANPAY];
|
|
276
276
|
var SingleKey = class _SingleKey {
|
|
277
277
|
key;
|
|
278
278
|
constructor(key) {
|
|
@@ -301,8 +301,9 @@ var SingleKey = class _SingleKey {
|
|
|
301
301
|
async sign(tx, inputIndexes) {
|
|
302
302
|
const txCpy = tx.clone();
|
|
303
303
|
if (!inputIndexes) {
|
|
304
|
+
assertAllowedSighashTypes(txCpy, ALLOWED_SIGHASH);
|
|
304
305
|
try {
|
|
305
|
-
if (!txCpy.sign(this.key,
|
|
306
|
+
if (!txCpy.sign(this.key, ALLOWED_SIGHASH)) {
|
|
306
307
|
throw new Error("Failed to sign transaction");
|
|
307
308
|
}
|
|
308
309
|
} catch (e) {
|
|
@@ -313,7 +314,7 @@ var SingleKey = class _SingleKey {
|
|
|
313
314
|
return txCpy;
|
|
314
315
|
}
|
|
315
316
|
for (const inputIndex of inputIndexes) {
|
|
316
|
-
if (!txCpy.signIdx(this.key, inputIndex,
|
|
317
|
+
if (!txCpy.signIdx(this.key, inputIndex, ALLOWED_SIGHASH)) {
|
|
317
318
|
throw new Error(`Failed to sign input #${inputIndex}`);
|
|
318
319
|
}
|
|
319
320
|
}
|
|
@@ -378,7 +379,7 @@ var ReadonlySingleKey = class _ReadonlySingleKey {
|
|
|
378
379
|
return Promise.resolve(this.publicKey);
|
|
379
380
|
}
|
|
380
381
|
};
|
|
381
|
-
var
|
|
382
|
+
var ALLOWED_SIGHASH2 = [SigHash.DEFAULT, SigHash.ALL, SigHash.ALL_ANYONECANPAY];
|
|
382
383
|
var seedBytes = /* @__PURE__ */ new WeakMap();
|
|
383
384
|
var mnemonicMeta = /* @__PURE__ */ new WeakMap();
|
|
384
385
|
var SeedIdentity = class _SeedIdentity {
|
|
@@ -581,8 +582,9 @@ var SeedIdentity = class _SeedIdentity {
|
|
|
581
582
|
signTxWithKey(tx, key, inputIndexes) {
|
|
582
583
|
const txCpy = tx.clone();
|
|
583
584
|
if (!inputIndexes) {
|
|
585
|
+
assertAllowedSighashTypes(txCpy, ALLOWED_SIGHASH2);
|
|
584
586
|
try {
|
|
585
|
-
if (!txCpy.sign(key,
|
|
587
|
+
if (!txCpy.sign(key, ALLOWED_SIGHASH2)) {
|
|
586
588
|
throw new Error("Failed to sign transaction");
|
|
587
589
|
}
|
|
588
590
|
} catch (e) {
|
|
@@ -592,7 +594,7 @@ var SeedIdentity = class _SeedIdentity {
|
|
|
592
594
|
}
|
|
593
595
|
} else {
|
|
594
596
|
for (const idx of inputIndexes) {
|
|
595
|
-
if (!txCpy.signIdx(key, idx,
|
|
597
|
+
if (!txCpy.signIdx(key, idx, ALLOWED_SIGHASH2)) {
|
|
596
598
|
throw new Error(`Failed to sign input #${idx}`);
|
|
597
599
|
}
|
|
598
600
|
}
|
|
@@ -1647,6 +1649,16 @@ var EsploraProvider = class {
|
|
|
1647
1649
|
baseUrl;
|
|
1648
1650
|
pollingInterval;
|
|
1649
1651
|
forcePolling;
|
|
1652
|
+
/**
|
|
1653
|
+
* Live {@link watchAddresses} subscriptions, keyed by their address set.
|
|
1654
|
+
*
|
|
1655
|
+
* Concurrent watchers over the same addresses share one transport, so a
|
|
1656
|
+
* caller that opens watchers in a loop — or leaks them by abandoning
|
|
1657
|
+
* {@link waitForIncomingFunds} — costs one entry in a `Set` rather than
|
|
1658
|
+
* another WebSocket plus another full-history polling loop. Entries are
|
|
1659
|
+
* dropped once their last subscriber stops.
|
|
1660
|
+
*/
|
|
1661
|
+
addressWatches = /* @__PURE__ */ new Map();
|
|
1650
1662
|
async getCoins(address) {
|
|
1651
1663
|
const response = await baseFetch(`${this.baseUrl}/address/${address}/utxo`);
|
|
1652
1664
|
if (!response.ok) {
|
|
@@ -1691,6 +1703,18 @@ var EsploraProvider = class {
|
|
|
1691
1703
|
}
|
|
1692
1704
|
return response.json();
|
|
1693
1705
|
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Activity counts for an address, without its transactions — orders of
|
|
1708
|
+
* magnitude smaller than `/address/{addr}/txs`, which is what makes it
|
|
1709
|
+
* usable as a change probe for the polling fallback.
|
|
1710
|
+
*/
|
|
1711
|
+
async getAddressStats(address) {
|
|
1712
|
+
const response = await baseFetch(`${this.baseUrl}/address/${address}`);
|
|
1713
|
+
if (!response.ok) {
|
|
1714
|
+
throw new Error(`Failed to get address stats: ${response.statusText}`);
|
|
1715
|
+
}
|
|
1716
|
+
return response.json();
|
|
1717
|
+
}
|
|
1694
1718
|
async getRawTransaction(txid) {
|
|
1695
1719
|
const response = await baseFetch(`${this.baseUrl}/tx/${txid}/hex`);
|
|
1696
1720
|
if (!response.ok) {
|
|
@@ -1722,50 +1746,227 @@ var EsploraProvider = class {
|
|
|
1722
1746
|
blockHeight: data.block_height
|
|
1723
1747
|
};
|
|
1724
1748
|
}
|
|
1749
|
+
/**
|
|
1750
|
+
* Watch a set of addresses over the explorer's WebSocket, degrading to HTTP
|
|
1751
|
+
* polling whenever the socket is unavailable and returning to the socket as
|
|
1752
|
+
* soon as it can be re-established.
|
|
1753
|
+
*
|
|
1754
|
+
* Concurrent calls covering the same address set share one transport. The
|
|
1755
|
+
* returned function releases **this** subscription only; the transport is
|
|
1756
|
+
* torn down when the last subscriber releases it. Calling it more than once
|
|
1757
|
+
* is a no-op.
|
|
1758
|
+
*
|
|
1759
|
+
* @param addresses - Addresses to monitor; order is not significant
|
|
1760
|
+
* @param callback - Invoked with transactions seen after the watch started
|
|
1761
|
+
* @returns A function releasing this subscription
|
|
1762
|
+
* @remarks
|
|
1763
|
+
* The HTTP fallback fetches full address history per address per cycle,
|
|
1764
|
+
* which is dramatically more expensive than the socket — so callers should
|
|
1765
|
+
* release watches they no longer need rather than relying on sharing.
|
|
1766
|
+
* @see {@link waitForIncomingFunds} for the cancellation-aware wallet-level helper
|
|
1767
|
+
*/
|
|
1725
1768
|
async watchAddresses(addresses, callback) {
|
|
1726
|
-
|
|
1769
|
+
const key = [...addresses].sort().join("\0");
|
|
1770
|
+
let watch = this.addressWatches.get(key);
|
|
1771
|
+
if (!watch) {
|
|
1772
|
+
watch = this.createAddressWatch(addresses, () => this.addressWatches.delete(key));
|
|
1773
|
+
this.addressWatches.set(key, watch);
|
|
1774
|
+
}
|
|
1775
|
+
const subscriber = { callback };
|
|
1776
|
+
watch.subscribers.add(subscriber);
|
|
1777
|
+
const shared = watch;
|
|
1778
|
+
await shared.started;
|
|
1779
|
+
let released = false;
|
|
1780
|
+
return () => {
|
|
1781
|
+
if (released) return;
|
|
1782
|
+
released = true;
|
|
1783
|
+
shared.subscribers.delete(subscriber);
|
|
1784
|
+
if (shared.subscribers.size === 0) shared.teardown();
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
/**
|
|
1788
|
+
* Bring up one shared address watch: a WebSocket subscription where the
|
|
1789
|
+
* explorer supports it, degrading to HTTP polling when it doesn't.
|
|
1790
|
+
*
|
|
1791
|
+
* @param addresses - Addresses this watch covers
|
|
1792
|
+
* @param onTeardown - Invoked when the watch retires, to drop the registry entry
|
|
1793
|
+
*/
|
|
1794
|
+
createAddressWatch(addresses, onTeardown) {
|
|
1795
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
1727
1796
|
const wsUrl = this.baseUrl.replace(/^http(s)?:/, "ws$1:") + "/v1/ws";
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1797
|
+
let stopped = false;
|
|
1798
|
+
let timer = null;
|
|
1799
|
+
let pollStarted = false;
|
|
1800
|
+
let ws = null;
|
|
1801
|
+
let reconnectTimer = null;
|
|
1802
|
+
let reconnectFailures = 0;
|
|
1803
|
+
let pollSession = 0;
|
|
1804
|
+
const emit = (txs) => {
|
|
1805
|
+
if (stopped || txs.length === 0) return;
|
|
1806
|
+
for (const subscriber of [...subscribers]) {
|
|
1807
|
+
try {
|
|
1808
|
+
subscriber.callback(txs);
|
|
1809
|
+
} catch (error) {
|
|
1810
|
+
console.error("Address watch subscriber threw:", error);
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
};
|
|
1814
|
+
const txKey2 = (tx) => `${tx.txid}_${tx.status.block_time}`;
|
|
1815
|
+
const getAllTxs = async () => {
|
|
1816
|
+
const txArrays = await Promise.all(
|
|
1817
|
+
addresses.map((address) => this.getTransactions(address))
|
|
1818
|
+
);
|
|
1819
|
+
return txArrays.flat();
|
|
1820
|
+
};
|
|
1821
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1822
|
+
let baselined = false;
|
|
1823
|
+
let anchorHeight;
|
|
1824
|
+
const baseline = (async () => {
|
|
1825
|
+
const [history, tip] = await Promise.allSettled([getAllTxs(), this.getChainTip()]);
|
|
1826
|
+
if (history.status === "fulfilled") {
|
|
1827
|
+
for (const tx of history.value) seen.add(txKey2(tx));
|
|
1828
|
+
baselined = true;
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
console.warn(
|
|
1832
|
+
"Could not baseline watched addresses; the first poll pass will establish it instead:",
|
|
1833
|
+
history.reason
|
|
1834
|
+
);
|
|
1835
|
+
if (tip.status === "fulfilled") anchorHeight = tip.value.height;
|
|
1836
|
+
})();
|
|
1837
|
+
const report = (txs) => {
|
|
1838
|
+
const fresh = [];
|
|
1839
|
+
for (const tx of txs) {
|
|
1840
|
+
const key = txKey2(tx);
|
|
1841
|
+
if (seen.has(key)) continue;
|
|
1842
|
+
seen.add(key);
|
|
1843
|
+
fresh.push(tx);
|
|
1844
|
+
}
|
|
1845
|
+
if (fresh.length === 0) return;
|
|
1846
|
+
emit(fresh);
|
|
1847
|
+
};
|
|
1848
|
+
const startPolling = async () => {
|
|
1849
|
+
if (stopped || pollStarted) return;
|
|
1850
|
+
pollStarted = true;
|
|
1851
|
+
console.warn(
|
|
1852
|
+
`Esplora websocket unavailable (${wsUrl}); falling back to HTTP polling every ${this.pollingInterval}ms for ${addresses.length} address(es) while retrying the socket`
|
|
1853
|
+
);
|
|
1854
|
+
let failures = 0;
|
|
1855
|
+
const activityFingerprint = async () => {
|
|
1856
|
+
try {
|
|
1857
|
+
const stats = await Promise.all(
|
|
1858
|
+
addresses.map((address) => this.getAddressStats(address))
|
|
1859
|
+
);
|
|
1860
|
+
const counted = (activity) => typeof activity?.tx_count === "number" && typeof activity.funded_txo_count === "number" && typeof activity.spent_txo_count === "number";
|
|
1861
|
+
const usable = stats.every(
|
|
1862
|
+
(s) => counted(s?.chain_stats) && counted(s?.mempool_stats)
|
|
1863
|
+
);
|
|
1864
|
+
if (!usable) return void 0;
|
|
1865
|
+
if (stats.some((s) => s.mempool_stats.tx_count > 0)) return void 0;
|
|
1866
|
+
return stats.map(
|
|
1867
|
+
({ chain_stats: chain }) => `${chain.tx_count}:${chain.funded_txo_count}:${chain.spent_txo_count}`
|
|
1868
|
+
).join(",");
|
|
1869
|
+
} catch {
|
|
1870
|
+
return void 0;
|
|
1871
|
+
}
|
|
1872
|
+
};
|
|
1873
|
+
let lastFingerprint;
|
|
1874
|
+
const session = pollSession;
|
|
1875
|
+
const isCurrentLoop = () => !stopped && session === pollSession;
|
|
1876
|
+
const schedule = () => {
|
|
1877
|
+
if (!isCurrentLoop()) return;
|
|
1878
|
+
timer = setTimeout(tick, this.pollingInterval * 2 ** failures);
|
|
1734
1879
|
};
|
|
1735
|
-
const
|
|
1736
|
-
const txKey2 = (tx) => `${tx.txid}_${tx.status.block_time}`;
|
|
1737
|
-
const existingTxs = new Set(initialTxs.map(txKey2));
|
|
1738
|
-
intervalId = setInterval(async () => {
|
|
1880
|
+
const tick = async () => {
|
|
1739
1881
|
try {
|
|
1882
|
+
const fingerprint = await activityFingerprint();
|
|
1883
|
+
if (!isCurrentLoop()) return;
|
|
1884
|
+
if (fingerprint !== void 0 && fingerprint === lastFingerprint) {
|
|
1885
|
+
failures = 0;
|
|
1886
|
+
schedule();
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1740
1889
|
const currentTxs = await getAllTxs();
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1890
|
+
if (!isCurrentLoop()) return;
|
|
1891
|
+
lastFingerprint = fingerprint;
|
|
1892
|
+
if (baselined) {
|
|
1893
|
+
report(currentTxs);
|
|
1894
|
+
} else if (anchorHeight !== void 0) {
|
|
1895
|
+
const arrivedAfterStart = (tx) => !tx.status.confirmed || tx.status.block_height === void 0 || tx.status.block_height > anchorHeight;
|
|
1896
|
+
for (const tx of currentTxs) {
|
|
1897
|
+
if (!arrivedAfterStart(tx)) seen.add(txKey2(tx));
|
|
1898
|
+
}
|
|
1899
|
+
baselined = true;
|
|
1900
|
+
report(currentTxs);
|
|
1901
|
+
} else {
|
|
1902
|
+
console.warn(
|
|
1903
|
+
`Esplora address watch established its baseline late for ${addresses.length} address(es); deposits arriving before now may not have been reported`
|
|
1904
|
+
);
|
|
1905
|
+
for (const tx of currentTxs) seen.add(txKey2(tx));
|
|
1906
|
+
baselined = true;
|
|
1745
1907
|
}
|
|
1908
|
+
failures = 0;
|
|
1746
1909
|
} catch (error) {
|
|
1747
|
-
|
|
1910
|
+
failures = Math.min(failures + 1, MAX_POLL_BACKOFF_EXPONENT);
|
|
1911
|
+
console.error("Error polling watched addresses:", error);
|
|
1748
1912
|
}
|
|
1749
|
-
|
|
1913
|
+
schedule();
|
|
1914
|
+
};
|
|
1915
|
+
await baseline;
|
|
1916
|
+
if (!isCurrentLoop()) return;
|
|
1917
|
+
await tick();
|
|
1750
1918
|
};
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
if (
|
|
1754
|
-
|
|
1919
|
+
const stopPolling = () => {
|
|
1920
|
+
pollSession++;
|
|
1921
|
+
if (timer) {
|
|
1922
|
+
clearTimeout(timer);
|
|
1923
|
+
timer = null;
|
|
1924
|
+
}
|
|
1925
|
+
pollStarted = false;
|
|
1755
1926
|
};
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1927
|
+
const handleSocketFailure = () => {
|
|
1928
|
+
if (stopped) return Promise.resolve();
|
|
1929
|
+
scheduleReconnect();
|
|
1930
|
+
return startPolling();
|
|
1931
|
+
};
|
|
1932
|
+
const scheduleReconnect = () => {
|
|
1933
|
+
if (stopped || reconnectTimer !== null) return;
|
|
1934
|
+
const delay = RECONNECT_BASE_DELAY_MS * 2 ** Math.min(reconnectFailures, MAX_RECONNECT_BACKOFF_EXPONENT);
|
|
1935
|
+
reconnectFailures++;
|
|
1936
|
+
reconnectTimer = setTimeout(() => {
|
|
1937
|
+
reconnectTimer = null;
|
|
1938
|
+
connect();
|
|
1939
|
+
}, delay);
|
|
1940
|
+
};
|
|
1941
|
+
const connect = () => {
|
|
1942
|
+
if (stopped) return Promise.resolve();
|
|
1943
|
+
const previous = ws;
|
|
1944
|
+
ws = null;
|
|
1945
|
+
if (previous) {
|
|
1946
|
+
try {
|
|
1947
|
+
previous.close();
|
|
1948
|
+
} catch {
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
let socket;
|
|
1952
|
+
try {
|
|
1953
|
+
socket = new WebSocket(wsUrl);
|
|
1954
|
+
} catch {
|
|
1955
|
+
return handleSocketFailure();
|
|
1956
|
+
}
|
|
1957
|
+
ws = socket;
|
|
1958
|
+
const isCurrent = () => !stopped && ws === socket;
|
|
1959
|
+
socket.addEventListener("open", () => {
|
|
1960
|
+
if (!isCurrent()) return;
|
|
1961
|
+
reconnectFailures = 0;
|
|
1763
1962
|
const subscribeMsg = {
|
|
1764
1963
|
"track-addresses": addresses
|
|
1765
1964
|
};
|
|
1766
|
-
|
|
1965
|
+
socket.send(JSON.stringify(subscribeMsg));
|
|
1966
|
+
stopPolling();
|
|
1767
1967
|
});
|
|
1768
|
-
|
|
1968
|
+
socket.addEventListener("message", (event) => {
|
|
1969
|
+
if (!isCurrent()) return;
|
|
1769
1970
|
try {
|
|
1770
1971
|
const newTxs = [];
|
|
1771
1972
|
const message = JSON.parse(event.data.toString());
|
|
@@ -1777,19 +1978,42 @@ var EsploraProvider = class {
|
|
|
1777
1978
|
newTxs.push(...aux[address][type].filter(isExplorerTransaction));
|
|
1778
1979
|
}
|
|
1779
1980
|
}
|
|
1780
|
-
|
|
1981
|
+
report(newTxs);
|
|
1781
1982
|
} catch (error) {
|
|
1782
1983
|
console.error("Failed to process WebSocket message:", error);
|
|
1783
1984
|
}
|
|
1784
1985
|
});
|
|
1785
|
-
|
|
1786
|
-
|
|
1986
|
+
socket.addEventListener("error", () => {
|
|
1987
|
+
if (isCurrent()) void handleSocketFailure();
|
|
1787
1988
|
});
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1989
|
+
socket.addEventListener("close", () => {
|
|
1990
|
+
if (isCurrent()) void handleSocketFailure();
|
|
1991
|
+
});
|
|
1992
|
+
return Promise.resolve();
|
|
1993
|
+
};
|
|
1994
|
+
const teardown = () => {
|
|
1995
|
+
if (stopped) return;
|
|
1996
|
+
stopped = true;
|
|
1997
|
+
onTeardown();
|
|
1998
|
+
if (timer) {
|
|
1999
|
+
clearTimeout(timer);
|
|
2000
|
+
timer = null;
|
|
2001
|
+
}
|
|
2002
|
+
if (reconnectTimer !== null) {
|
|
2003
|
+
clearTimeout(reconnectTimer);
|
|
2004
|
+
reconnectTimer = null;
|
|
2005
|
+
}
|
|
2006
|
+
if (ws) {
|
|
2007
|
+
try {
|
|
2008
|
+
ws.close();
|
|
2009
|
+
} catch {
|
|
2010
|
+
}
|
|
2011
|
+
ws = null;
|
|
2012
|
+
}
|
|
2013
|
+
subscribers.clear();
|
|
2014
|
+
};
|
|
2015
|
+
const started = this.forcePolling ? startPolling() : connect().then(() => baseline);
|
|
2016
|
+
return { subscribers, teardown, started };
|
|
1793
2017
|
}
|
|
1794
2018
|
async getChainTip() {
|
|
1795
2019
|
const tipBlocks = await baseFetch(`${this.baseUrl}/blocks`);
|
|
@@ -1806,6 +2030,8 @@ var EsploraProvider = class {
|
|
|
1806
2030
|
const hash = tip[0].id;
|
|
1807
2031
|
return {
|
|
1808
2032
|
height: tip[0].height,
|
|
2033
|
+
// `mediantime`, never `timestamp`: the latter is the header's own
|
|
2034
|
+
// `nTime`, and this field is specified as MTP.
|
|
1809
2035
|
time: tip[0].mediantime,
|
|
1810
2036
|
hash
|
|
1811
2037
|
};
|
|
@@ -1871,6 +2097,9 @@ var isExplorerTransaction = (tx) => {
|
|
|
1871
2097
|
(vout) => typeof vout.scriptpubkey_address === "string" && typeof vout.value === "number"
|
|
1872
2098
|
) && typeof tx.status === "object" && typeof tx.status.confirmed === "boolean";
|
|
1873
2099
|
};
|
|
2100
|
+
var MAX_POLL_BACKOFF_EXPONENT = 4;
|
|
2101
|
+
var RECONNECT_BASE_DELAY_MS = 1e3;
|
|
2102
|
+
var MAX_RECONNECT_BACKOFF_EXPONENT = 5;
|
|
1874
2103
|
var getVarIntSize = (n) => {
|
|
1875
2104
|
if (n < 253) return 1;
|
|
1876
2105
|
if (n <= 65535) return 3;
|
|
@@ -3085,9 +3314,6 @@ function hasBoardingTxExpired(coin, boardingTimelock, chainTipHeight) {
|
|
|
3085
3314
|
const blockTime = BigInt(Math.floor(coin.status.block_time));
|
|
3086
3315
|
return blockTime + boardingTimelock.value <= now;
|
|
3087
3316
|
}
|
|
3088
|
-
function formatSighash(type) {
|
|
3089
|
-
return `0x${type.toString(16).padStart(2, "0")}`;
|
|
3090
|
-
}
|
|
3091
3317
|
function verifyTapscriptSignatures(tx, inputIndex, requiredSigners, excludePubkeys = [], allowedSighashTypes = [SigHash.DEFAULT], expectedLeafHash) {
|
|
3092
3318
|
const input = tx.getInput(inputIndex);
|
|
3093
3319
|
const prevoutScripts = [];
|
|
@@ -3305,6 +3531,15 @@ async function submitOffchainTx(provider, offchainTx, signer, hooks, options) {
|
|
|
3305
3531
|
assertSubmittedArkTxid(response, signedArkTx, "submitTx");
|
|
3306
3532
|
const { arkTxid, signedCheckpointTxs } = response;
|
|
3307
3533
|
const matched = matchServerCheckpoints(signedCheckpointTxs, offchainTx.checkpoints, "submitTx");
|
|
3534
|
+
matched.forEach(({ server }, index) => {
|
|
3535
|
+
try {
|
|
3536
|
+
assertAllowedSighashTypes(server);
|
|
3537
|
+
} catch (error) {
|
|
3538
|
+
throw new ServerResponseMismatchError(
|
|
3539
|
+
`submitTx checkpoint ${index}: ${error instanceof Error ? error.message : String(error)}`
|
|
3540
|
+
);
|
|
3541
|
+
}
|
|
3542
|
+
});
|
|
3308
3543
|
const verify = options?.verifyServerSignatures;
|
|
3309
3544
|
if (verify) {
|
|
3310
3545
|
if (response.finalArkTx === void 0) {
|
|
@@ -3906,6 +4141,7 @@ function getRecoverableWithSubdust(vtxos, dustAmount, now) {
|
|
|
3906
4141
|
};
|
|
3907
4142
|
}
|
|
3908
4143
|
function isVtxoExpiringSoon(vtxo, thresholdMs) {
|
|
4144
|
+
if (vtxo.isUnrolled) return false;
|
|
3909
4145
|
const realThresholdMs = thresholdMs <= 100 ? DEFAULT_THRESHOLD_MS : thresholdMs;
|
|
3910
4146
|
const expiresAt = normalizeVtxo(vtxo).expiresAt;
|
|
3911
4147
|
if (expiresAt === void 0) return false;
|
|
@@ -3916,7 +4152,9 @@ function isVtxoExpiringSoon(vtxo, thresholdMs) {
|
|
|
3916
4152
|
}
|
|
3917
4153
|
function getExpiringAndRecoverableVtxos(vtxos, thresholdMs, dustAmount, now) {
|
|
3918
4154
|
return vtxos.filter(
|
|
3919
|
-
|
|
4155
|
+
// The leading exclusion covers the `isSubdust` arm too, which is a value
|
|
4156
|
+
// property and would otherwise re-admit an exited coin on its own.
|
|
4157
|
+
(vtxo) => !vtxo.isUnrolled && (isVtxoExpiringSoon(vtxo, thresholdMs) || canRecoverOnchain(vtxo, now) || isSubdust(vtxo, dustAmount))
|
|
3920
4158
|
);
|
|
3921
4159
|
}
|
|
3922
4160
|
function isMigrationCapable(wallet) {
|
|
@@ -6448,6 +6686,13 @@ var TxTree = class {
|
|
|
6448
6686
|
if (nbOfInputs !== 1) {
|
|
6449
6687
|
throw new Error(`unexpected number of inputs: ${nbOfInputs}, expected 1`);
|
|
6450
6688
|
}
|
|
6689
|
+
if (this.root.lockTime !== 0) {
|
|
6690
|
+
throw new Error(`unexpected locktime: ${this.root.lockTime}, expected 0`);
|
|
6691
|
+
}
|
|
6692
|
+
const sequence = this.root.getInput(0).sequence;
|
|
6693
|
+
if (sequence !== void 0 && sequence !== DEFAULT_SEQUENCE) {
|
|
6694
|
+
throw new Error(`unexpected sequence: ${sequence}, expected ${DEFAULT_SEQUENCE}`);
|
|
6695
|
+
}
|
|
6451
6696
|
if (this.children.size > nbOfOutputs - 1) {
|
|
6452
6697
|
throw new Error(
|
|
6453
6698
|
`unexpected number of children: ${this.children.size}, expected maximum ${nbOfOutputs - 1}`
|
|
@@ -12079,6 +12324,7 @@ function filterSnapshotVtxos(snapshot, filter, pendingSpendOutpoints) {
|
|
|
12079
12324
|
});
|
|
12080
12325
|
}
|
|
12081
12326
|
var PENDING_RECOVERY_REASON = "is past its operator signer's rotation cutoff \u2014 the operator will not co-sign it until it recovers";
|
|
12327
|
+
var UNROLLED_REASON = "was unilaterally exited and lives onchain \u2014 `Unroll.completeUnroll` is the only spend that reaches it";
|
|
12082
12328
|
function omittedOutpoints(before, after) {
|
|
12083
12329
|
if (before.length === after.length) return /* @__PURE__ */ new Set();
|
|
12084
12330
|
const kept = new Set(after.map((vtxo) => `${vtxo.txid}:${vtxo.vout}`));
|
|
@@ -12651,6 +12897,13 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
12651
12897
|
"is locked by an in-flight settlement intent"
|
|
12652
12898
|
)
|
|
12653
12899
|
]);
|
|
12900
|
+
if (!filter?.withUnrolled) {
|
|
12901
|
+
logExcludedVtxos(
|
|
12902
|
+
"getSpendableVtxos",
|
|
12903
|
+
snapshot.flatMap((contract) => contract.vtxos).filter((vtxo) => vtxo.isUnrolled && !hasTerminalSpend(vtxo)),
|
|
12904
|
+
[() => UNROLLED_REASON]
|
|
12905
|
+
);
|
|
12906
|
+
}
|
|
12654
12907
|
return unlocked;
|
|
12655
12908
|
}
|
|
12656
12909
|
/**
|
|
@@ -15203,9 +15456,11 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
15203
15456
|
seen.add(pendingTx.arkTxid);
|
|
15204
15457
|
batchPending.push(pendingTx.arkTxid);
|
|
15205
15458
|
try {
|
|
15206
|
-
const checkpointTxs = pendingTx.signedCheckpointTxs.map(
|
|
15207
|
-
|
|
15208
|
-
|
|
15459
|
+
const checkpointTxs = pendingTx.signedCheckpointTxs.map((c) => {
|
|
15460
|
+
const tx = Transaction$2.fromPSBT(base64.decode(c));
|
|
15461
|
+
assertAllowedSighashTypes(tx);
|
|
15462
|
+
return tx;
|
|
15463
|
+
});
|
|
15209
15464
|
assertCheckpointsMatchInputs(
|
|
15210
15465
|
checkpointTxs,
|
|
15211
15466
|
checkpointInputs,
|
|
@@ -15373,7 +15628,9 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
15373
15628
|
const myPkScript = ArkAddress.decode(await this.getAddress()).pkScript;
|
|
15374
15629
|
let { spendable, unclaimed } = this.classifyCashVtxos(vtxos);
|
|
15375
15630
|
let swept = 0;
|
|
15376
|
-
const drainable = vtxos.filter(
|
|
15631
|
+
const drainable = vtxos.filter(
|
|
15632
|
+
(vtxo) => !isSubdust(vtxo, this.dustAmount) && !vtxo.isUnrolled
|
|
15633
|
+
);
|
|
15377
15634
|
if (drainable.length > 0) {
|
|
15378
15635
|
let drained = { count: 0, swept: 0, claimed: /* @__PURE__ */ new Set() };
|
|
15379
15636
|
try {
|
|
@@ -15533,9 +15790,11 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
15533
15790
|
const unrollCandidates = this.checkpointUnrollCandidates(await this.arkProvider.getInfo());
|
|
15534
15791
|
for (const pendingTx of pendingTxs) {
|
|
15535
15792
|
try {
|
|
15536
|
-
const checkpointTxs = pendingTx.signedCheckpointTxs.map(
|
|
15537
|
-
|
|
15538
|
-
|
|
15793
|
+
const checkpointTxs = pendingTx.signedCheckpointTxs.map((checkpoint) => {
|
|
15794
|
+
const tx = Transaction$2.fromPSBT(base64.decode(checkpoint));
|
|
15795
|
+
assertAllowedSighashTypes(tx);
|
|
15796
|
+
return tx;
|
|
15797
|
+
});
|
|
15539
15798
|
assertCheckpointsMatchInputs(
|
|
15540
15799
|
checkpointTxs,
|
|
15541
15800
|
inputs.map((input) => ({
|
|
@@ -16246,19 +16505,53 @@ function selectVirtualCoins(coins, targetAmount) {
|
|
|
16246
16505
|
changeAmount
|
|
16247
16506
|
};
|
|
16248
16507
|
}
|
|
16249
|
-
|
|
16508
|
+
var AbortError = class extends Error {
|
|
16509
|
+
constructor(message = "Operation aborted") {
|
|
16510
|
+
super(message);
|
|
16511
|
+
this.name = "AbortError";
|
|
16512
|
+
}
|
|
16513
|
+
};
|
|
16514
|
+
function abortReason(signal) {
|
|
16515
|
+
const { reason } = signal;
|
|
16516
|
+
if (reason instanceof Error) return reason;
|
|
16517
|
+
return new AbortError(typeof reason === "string" ? reason : void 0);
|
|
16518
|
+
}
|
|
16519
|
+
async function waitForIncomingFunds(wallet, options) {
|
|
16520
|
+
const { signal, timeoutMs } = options ?? {};
|
|
16521
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
16250
16522
|
let stopFunc;
|
|
16251
16523
|
let settled = false;
|
|
16252
|
-
|
|
16524
|
+
let timeoutId;
|
|
16525
|
+
let onAbort;
|
|
16526
|
+
return new Promise((resolve, reject) => {
|
|
16527
|
+
const settle = (deliver) => {
|
|
16528
|
+
if (settled) return;
|
|
16529
|
+
settled = true;
|
|
16530
|
+
if (timeoutId !== void 0) clearTimeout(timeoutId);
|
|
16531
|
+
if (onAbort) signal?.removeEventListener("abort", onAbort);
|
|
16532
|
+
stopFunc?.();
|
|
16533
|
+
deliver();
|
|
16534
|
+
};
|
|
16535
|
+
const cancel = (reason) => settle(() => reject(reason));
|
|
16536
|
+
if (signal) {
|
|
16537
|
+
onAbort = () => cancel(abortReason(signal));
|
|
16538
|
+
signal.addEventListener("abort", onAbort);
|
|
16539
|
+
}
|
|
16540
|
+
if (timeoutMs !== void 0) {
|
|
16541
|
+
timeoutId = setTimeout(
|
|
16542
|
+
() => cancel(new AbortError(`waitForIncomingFunds timed out after ${timeoutMs}ms`)),
|
|
16543
|
+
timeoutMs
|
|
16544
|
+
);
|
|
16545
|
+
}
|
|
16253
16546
|
wallet.notifyIncomingFunds((funds) => {
|
|
16254
16547
|
const hasFunds = funds.type === "utxo" ? funds.coins.length > 0 : funds.newVtxos.length > 0;
|
|
16255
16548
|
if (settled || !hasFunds) return;
|
|
16256
|
-
|
|
16257
|
-
resolve(funds);
|
|
16258
|
-
stopFunc?.();
|
|
16549
|
+
settle(() => resolve(funds));
|
|
16259
16550
|
}).then((stop) => {
|
|
16260
16551
|
stopFunc = stop;
|
|
16261
16552
|
if (settled) stop();
|
|
16553
|
+
}).catch((error) => {
|
|
16554
|
+
cancel(error);
|
|
16262
16555
|
});
|
|
16263
16556
|
});
|
|
16264
16557
|
}
|
|
@@ -20088,6 +20381,7 @@ var ListUnspentMethod = "blockchain.scripthash.listunspent";
|
|
|
20088
20381
|
var MISSING_TRANSACTION = "missingtransaction";
|
|
20089
20382
|
var MAX_FETCH_TRANSACTIONS_ATTEMPTS = 5;
|
|
20090
20383
|
var BLOCK_HEADER_SIZE = 80;
|
|
20384
|
+
var MTP_WINDOW = 11;
|
|
20091
20385
|
function parseBlockHeader(headerHex) {
|
|
20092
20386
|
const headerBytes = hex.decode(headerHex);
|
|
20093
20387
|
if (headerBytes.length !== BLOCK_HEADER_SIZE) {
|
|
@@ -20394,6 +20688,8 @@ var ElectrumOnchainProvider = class {
|
|
|
20394
20688
|
ws;
|
|
20395
20689
|
network;
|
|
20396
20690
|
chain;
|
|
20691
|
+
mtpCache;
|
|
20692
|
+
mtpInflight;
|
|
20397
20693
|
async getCoins(address) {
|
|
20398
20694
|
const script = this.encodeAddress(address);
|
|
20399
20695
|
const scriptHash = toScriptHash(script);
|
|
@@ -20649,15 +20945,58 @@ var ElectrumOnchainProvider = class {
|
|
|
20649
20945
|
blockTime
|
|
20650
20946
|
};
|
|
20651
20947
|
}
|
|
20948
|
+
/** `time` is median-time-past, per {@link OnchainProvider.getChainTip};
|
|
20949
|
+
* Electrum serves raw headers and no MTP, so it is computed here. */
|
|
20652
20950
|
async getChainTip() {
|
|
20653
20951
|
const tip = await this.chain.subscribeHeaders();
|
|
20654
20952
|
const { hash, timestamp } = parseBlockHeader(tip.hex);
|
|
20655
20953
|
return {
|
|
20656
20954
|
height: tip.height,
|
|
20657
|
-
time: timestamp,
|
|
20955
|
+
time: await this.medianTimePast(tip.height, timestamp, hash),
|
|
20658
20956
|
hash
|
|
20659
20957
|
};
|
|
20660
20958
|
}
|
|
20959
|
+
/**
|
|
20960
|
+
* Consensus's `GetMedianTimePast`, ending at and including `height`.
|
|
20961
|
+
*
|
|
20962
|
+
* Cached per tip HASH, not height: this runs on every balance read, and
|
|
20963
|
+
* hashing means a reorg at the same height recomputes rather than serving
|
|
20964
|
+
* the orphaned chain's median.
|
|
20965
|
+
*/
|
|
20966
|
+
async medianTimePast(height, tipTime, hash) {
|
|
20967
|
+
if (this.mtpCache?.hash === hash) return this.mtpCache.mtp;
|
|
20968
|
+
if (this.mtpInflight?.hash === hash) return this.mtpInflight.mtp;
|
|
20969
|
+
const mtp = this.readMedianTimePast(height, tipTime, hash).finally(() => {
|
|
20970
|
+
this.mtpInflight = void 0;
|
|
20971
|
+
});
|
|
20972
|
+
this.mtpInflight = { hash, mtp };
|
|
20973
|
+
return mtp;
|
|
20974
|
+
}
|
|
20975
|
+
/** Degrades to the tip's `nTime` rather than throwing — a caller that
|
|
20976
|
+
* cannot read the tip at all is worse off. */
|
|
20977
|
+
async readMedianTimePast(height, tipTime, hash) {
|
|
20978
|
+
const heights = [];
|
|
20979
|
+
for (let h = height - 1; h >= 0 && heights.length < MTP_WINDOW - 1; h--) heights.push(h);
|
|
20980
|
+
if (heights.length === 0) return tipTime;
|
|
20981
|
+
let timestamps;
|
|
20982
|
+
try {
|
|
20983
|
+
const headers = await this.chain.fetchBlockHeaders(heights);
|
|
20984
|
+
timestamps = [
|
|
20985
|
+
tipTime,
|
|
20986
|
+
...headers.map((header) => parseBlockHeader(header.hex).timestamp)
|
|
20987
|
+
];
|
|
20988
|
+
} catch (e) {
|
|
20989
|
+
console.warn(
|
|
20990
|
+
"Failed to fetch the median-time-past window; using the tip's own time",
|
|
20991
|
+
e
|
|
20992
|
+
);
|
|
20993
|
+
return tipTime;
|
|
20994
|
+
}
|
|
20995
|
+
timestamps.sort((a, b) => a - b);
|
|
20996
|
+
const mtp = timestamps[Math.floor(timestamps.length / 2)];
|
|
20997
|
+
this.mtpCache = { hash, mtp };
|
|
20998
|
+
return mtp;
|
|
20999
|
+
}
|
|
20661
21000
|
async watchAddresses(addresses, eventCallback) {
|
|
20662
21001
|
const scripts = addresses.map((addr) => this.encodeAddress(addr));
|
|
20663
21002
|
const scriptHashes = scripts.map(toScriptHash);
|
|
@@ -22834,6 +23173,10 @@ var ArkadeContract = class _ArkadeContract {
|
|
|
22834
23173
|
* When a `contractManager` is configured and this contract is registered,
|
|
22835
23174
|
* reads the repository-backed state (offline-first, kept fresh by the
|
|
22836
23175
|
* contract watcher). Otherwise falls back to a direct indexer query.
|
|
23176
|
+
*
|
|
23177
|
+
* Both branches refuse a spent or unilaterally exited output. They are not
|
|
23178
|
+
* otherwise interchangeable: the fallback asks `spendableOnly`, which also
|
|
23179
|
+
* drops swept coins — the manager branch keeps those.
|
|
22837
23180
|
*/
|
|
22838
23181
|
async getUtxos() {
|
|
22839
23182
|
const manager = this.client.contractManager;
|
|
@@ -22854,7 +23197,7 @@ var ArkadeContract = class _ArkadeContract {
|
|
|
22854
23197
|
scripts: [scriptHex],
|
|
22855
23198
|
spendableOnly: true
|
|
22856
23199
|
});
|
|
22857
|
-
return vtxos;
|
|
23200
|
+
return vtxos.filter((v) => !hasTerminalSpend(v) && !v.isUnrolled);
|
|
22858
23201
|
}
|
|
22859
23202
|
/** Total spendable balance (requires an indexer). */
|
|
22860
23203
|
async getBalance() {
|
|
@@ -23472,6 +23815,6 @@ function createDefaultPaymentRouter(wallet) {
|
|
|
23472
23815
|
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
23473
23816
|
*/
|
|
23474
23817
|
|
|
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-
|
|
23477
|
-
//# sourceMappingURL=chunk-
|
|
23818
|
+
export { ARKADE_MAGIC, ARKADE_SALTED_PREIMAGE_TAG, ARKADE_SWAP_PREIMAGE_TAG, AbortError, 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 };
|
|
23819
|
+
//# sourceMappingURL=chunk-TA7XLEP2.js.map
|
|
23820
|
+
//# sourceMappingURL=chunk-TA7XLEP2.js.map
|