@arkade-os/sdk 0.4.75 → 0.4.77
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/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 +3 -5
- package/dist/adapters/indexedDB.cjs.map +1 -1
- package/dist/adapters/indexedDB.d.cts +1 -1
- package/dist/adapters/indexedDB.d.ts +1 -1
- package/dist/adapters/indexedDB.js +3 -5
- package/dist/adapters/indexedDB.js.map +1 -1
- package/dist/{asyncStorageTaskQueue-DjwCbb07.d.ts → asyncStorageTaskQueue-DTl0WM7E.d.ts} +1 -1
- package/dist/{asyncStorageTaskQueue-5k0H_cDM.d.cts → asyncStorageTaskQueue-MmJyAnu-.d.cts} +1 -1
- package/dist/{chunk-YA3L3WL4.cjs → chunk-4LP6XOMW.cjs} +17 -17
- package/dist/{chunk-YA3L3WL4.cjs.map → chunk-4LP6XOMW.cjs.map} +1 -1
- package/dist/{chunk-UKFA7NVE.js → chunk-52OA3UIC.js} +25 -12
- package/dist/chunk-52OA3UIC.js.map +1 -0
- package/dist/{chunk-4GLSOP6L.js → chunk-ACPANSOX.js} +43 -11
- package/dist/chunk-ACPANSOX.js.map +1 -0
- package/dist/{chunk-J5EX3OMM.cjs → chunk-CJN4CUEU.cjs} +25 -11
- package/dist/chunk-CJN4CUEU.cjs.map +1 -0
- package/dist/{chunk-SH23SRZE.cjs → chunk-H62OOAS4.cjs} +17 -17
- package/dist/{chunk-SH23SRZE.cjs.map → chunk-H62OOAS4.cjs.map} +1 -1
- package/dist/{chunk-PS564TAU.js → chunk-HKOFYHZP.js} +3 -3
- package/dist/{chunk-PS564TAU.js.map → chunk-HKOFYHZP.js.map} +1 -1
- package/dist/{chunk-YYWEBYFJ.cjs → chunk-LUWSY2QO.cjs} +89 -57
- package/dist/chunk-LUWSY2QO.cjs.map +1 -0
- package/dist/{chunk-FTLPTF3R.js → chunk-MLOZHTBN.js} +570 -114
- package/dist/chunk-MLOZHTBN.js.map +1 -0
- package/dist/{chunk-SKAL4MCW.js → chunk-T6MGH4V4.js} +4 -4
- package/dist/{chunk-SKAL4MCW.js.map → chunk-T6MGH4V4.js.map} +1 -1
- package/dist/{chunk-2Q2PYU3Y.cjs → chunk-Y4YK44IM.cjs} +10 -10
- package/dist/{chunk-2Q2PYU3Y.cjs.map → chunk-Y4YK44IM.cjs.map} +1 -1
- package/dist/{chunk-EHJYR4E5.cjs → chunk-YJEWWLOQ.cjs} +1005 -550
- package/dist/chunk-YJEWWLOQ.cjs.map +1 -0
- package/dist/{chunk-2ULUCL6A.js → chunk-YKNTUOUG.js} +4 -4
- package/dist/{chunk-2ULUCL6A.js.map → chunk-YKNTUOUG.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-D_sW61rj.d.ts → delegate-CjcysR7s.d.ts} +1 -1
- package/dist/{delegate-D0v8yT-a.d.cts → delegate-QPCGaD_z.d.cts} +1 -1
- package/dist/{hdWalletCapable-66hG5KQP.d.cts → hdWalletCapable--pMncWbC.d.ts} +6 -4
- package/dist/{hdWalletCapable-DHCNbAgl.d.ts → hdWalletCapable-Bp_p0WLj.d.cts} +6 -4
- package/dist/{index-B2JSxDi1.d.cts → index-BMY272ns.d.cts} +26 -8
- package/dist/{index-TZBbMNqA.d.ts → index-Ie_ak2zY.d.cts} +39 -9
- package/dist/{index-TZBbMNqA.d.cts → index-Ie_ak2zY.d.ts} +39 -9
- package/dist/{index-vUeTpifq.d.ts → index-m-EM-e8D.d.ts} +26 -8
- package/dist/index.cjs +307 -303
- package/dist/index.d.cts +75 -13
- package/dist/index.d.ts +75 -13
- package/dist/index.js +4 -4
- package/dist/repositories/realm/index.cjs +36 -19
- package/dist/repositories/realm/index.cjs.map +1 -1
- package/dist/repositories/realm/index.d.cts +6 -3
- package/dist/repositories/realm/index.d.ts +6 -3
- package/dist/repositories/realm/index.js +22 -5
- package/dist/repositories/realm/index.js.map +1 -1
- package/dist/repositories/sqlite/index.cjs +42 -18
- package/dist/repositories/sqlite/index.cjs.map +1 -1
- package/dist/repositories/sqlite/index.d.cts +5 -2
- package/dist/repositories/sqlite/index.d.ts +5 -2
- package/dist/repositories/sqlite/index.js +29 -5
- package/dist/repositories/sqlite/index.js.map +1 -1
- package/dist/{taskRunner-CAAPpdyi.d.cts → taskRunner-BgRowCqB.d.cts} +1 -1
- package/dist/{taskRunner-CairkunF.d.ts → taskRunner-CqrlrJEt.d.ts} +1 -1
- package/dist/wallet/expo/background.cjs +14 -14
- package/dist/wallet/expo/background.d.cts +3 -3
- package/dist/wallet/expo/background.d.ts +3 -3
- package/dist/wallet/expo/background.js +6 -6
- package/dist/wallet/expo/index.cjs +14 -14
- package/dist/wallet/expo/index.cjs.map +1 -1
- package/dist/wallet/expo/index.d.cts +5 -5
- package/dist/wallet/expo/index.d.ts +5 -5
- package/dist/wallet/expo/index.js +5 -5
- 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 +1 -1
- package/dist/chunk-4GLSOP6L.js.map +0 -1
- package/dist/chunk-EHJYR4E5.cjs.map +0 -1
- package/dist/chunk-FTLPTF3R.js.map +0 -1
- package/dist/chunk-J5EX3OMM.cjs.map +0 -1
- package/dist/chunk-UKFA7NVE.js.map +0 -1
- package/dist/chunk-YYWEBYFJ.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, networks, getNetwork, DEFAULT_NETWORK, resolveEmulatorPubkey,
|
|
1
|
+
import { AssetId, AssetGroup, AssetInput, AssetOutput, Metadata, Packet, BufferReader, BufferWriter, AssetRef, RestIndexerProvider } from './chunk-HKOFYHZP.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-ACPANSOX.js';
|
|
3
|
+
import { VtxoScript, Transaction, isRecoverable, CSVMultisigTapscript, networks, getNetwork, DEFAULT_NETWORK, resolveEmulatorPubkey, isVtxoSpent, 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, MultisigTapscript, isEventSourceError, isEventSourceUnavailableError, getAllNormalizedVtxos, isPastExpiry, isRetryableProviderError, DEFAULT_PAGE_SIZE, RestArkProvider, toVirtualStatus, ArkError, TapTreeCoder, resolveTimeHeight, canSpendOffchain, parseLegacyExpiry, isExpired, PrevoutTxField, fetchVtxoCreatedAtByTxid, DEFAULT_ARKADE_SERVER_URL, ProviderUnavailableError } from './chunk-52OA3UIC.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';
|
|
@@ -1334,7 +1334,7 @@ async function provisionClaimSecret(wallet, opts = {}) {
|
|
|
1334
1334
|
const descriptor = await provisionDescriptor(wallet);
|
|
1335
1335
|
const signer = await contractSigner(wallet, descriptor);
|
|
1336
1336
|
const pubkey = await signer.xOnlyPublicKey();
|
|
1337
|
-
const
|
|
1337
|
+
const claim2 = async () => {
|
|
1338
1338
|
if (opts.preimage) return { preimage: opts.preimage, mustPersistPreimage: true };
|
|
1339
1339
|
if (isPerArtifactDescriptor(descriptor)) {
|
|
1340
1340
|
return {
|
|
@@ -1356,7 +1356,7 @@ async function provisionClaimSecret(wallet, opts = {}) {
|
|
|
1356
1356
|
return { preimage: randomBytes(32), mustPersistPreimage: true };
|
|
1357
1357
|
}
|
|
1358
1358
|
};
|
|
1359
|
-
const { preimage, preimageSalt, mustPersistPreimage } = await
|
|
1359
|
+
const { preimage, preimageSalt, mustPersistPreimage } = await claim2();
|
|
1360
1360
|
return {
|
|
1361
1361
|
descriptor,
|
|
1362
1362
|
pubkey,
|
|
@@ -3918,7 +3918,7 @@ function parseProgram(text, env) {
|
|
|
3918
3918
|
var DUST_AMOUNT = 546;
|
|
3919
3919
|
var FALLBACK_WALLET_DUST_AMOUNT = 330n;
|
|
3920
3920
|
function getDustAmount(wallet) {
|
|
3921
|
-
return "dustAmount" in wallet ? wallet.dustAmount : FALLBACK_WALLET_DUST_AMOUNT;
|
|
3921
|
+
return wallet && "dustAmount" in wallet ? wallet.dustAmount : FALLBACK_WALLET_DUST_AMOUNT;
|
|
3922
3922
|
}
|
|
3923
3923
|
function extendCoinWithTapscript(boardingTapscript, utxo) {
|
|
3924
3924
|
return {
|
|
@@ -4128,7 +4128,7 @@ function selectPendingRecoveryOutpoints(contractsWithVtxos, signerSet, nowSecond
|
|
|
4128
4128
|
continue;
|
|
4129
4129
|
}
|
|
4130
4130
|
for (const v of vtxos) {
|
|
4131
|
-
if (!
|
|
4131
|
+
if (!isVtxoSpent(v) && !v.isSwept && !v.isUnrolled) {
|
|
4132
4132
|
out.add(`${v.txid}:${v.vout}`);
|
|
4133
4133
|
}
|
|
4134
4134
|
}
|
|
@@ -4655,7 +4655,10 @@ var VtxoManager = class _VtxoManager {
|
|
|
4655
4655
|
if (this.settlementConfig === false && thresholdMs === void 0) {
|
|
4656
4656
|
return [];
|
|
4657
4657
|
}
|
|
4658
|
-
const vtxos = await this.wallet.getSpendableVtxos({
|
|
4658
|
+
const vtxos = await this.wallet.getSpendableVtxos({
|
|
4659
|
+
withRecoverable: true,
|
|
4660
|
+
genericallySpendableOnly: true
|
|
4661
|
+
});
|
|
4659
4662
|
let threshold;
|
|
4660
4663
|
if (thresholdMs !== void 0) {
|
|
4661
4664
|
threshold = thresholdMs;
|
|
@@ -5152,8 +5155,8 @@ var VtxoManager = class _VtxoManager {
|
|
|
5152
5155
|
const cls = classifyAgainstSignerSet(serverPubKey, signerSet, nowSeconds);
|
|
5153
5156
|
if (cls.status === "CURRENT") continue;
|
|
5154
5157
|
const live = vtxos.filter((v) => !v.isUnrolled);
|
|
5155
|
-
const recoverable = live.filter((v) => v.isSwept && !
|
|
5156
|
-
const spendable = live.filter((v) => !
|
|
5158
|
+
const recoverable = live.filter((v) => v.isSwept && !isVtxoSpent(v));
|
|
5159
|
+
const spendable = live.filter((v) => !isVtxoSpent(v) && !v.isSwept);
|
|
5157
5160
|
const value = spendable.reduce((sum, v) => sum + v.value, 0);
|
|
5158
5161
|
let recoverableCount = 0;
|
|
5159
5162
|
let recoverableValue = 0;
|
|
@@ -7319,7 +7322,8 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
7319
7322
|
}
|
|
7320
7323
|
const metadata = castMetadata(params.metadata);
|
|
7321
7324
|
const virtualCoins = await this.wallet.getSpendableVtxos({
|
|
7322
|
-
withRecoverable: false
|
|
7325
|
+
withRecoverable: false,
|
|
7326
|
+
genericallySpendableOnly: true
|
|
7323
7327
|
});
|
|
7324
7328
|
const controlAssetRef = params.controlAssetId ? AssetRef.fromId(AssetId.fromString(params.controlAssetId)) : null;
|
|
7325
7329
|
const coinSelection = selectVirtualCoins(virtualCoins, Number(this.wallet.dustAmount));
|
|
@@ -7408,7 +7412,8 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
7408
7412
|
throw new Error(`Asset ${params.assetId} is not reissuable`);
|
|
7409
7413
|
}
|
|
7410
7414
|
const virtualCoins = await this.wallet.getSpendableVtxos({
|
|
7411
|
-
withRecoverable: false
|
|
7415
|
+
withRecoverable: false,
|
|
7416
|
+
genericallySpendableOnly: true
|
|
7412
7417
|
});
|
|
7413
7418
|
const assetChanges = /* @__PURE__ */ new Map();
|
|
7414
7419
|
const { selected: controlCoins } = selectCoinsWithAsset(virtualCoins, controlAssetId, 1n);
|
|
@@ -7514,7 +7519,8 @@ var AssetManager = class extends ReadonlyAssetManager {
|
|
|
7514
7519
|
throw new Error(`Burn amount must be greater than 0, got ${params.amount}`);
|
|
7515
7520
|
}
|
|
7516
7521
|
const virtualCoins = await this.wallet.getSpendableVtxos({
|
|
7517
|
-
withRecoverable: false
|
|
7522
|
+
withRecoverable: false,
|
|
7523
|
+
genericallySpendableOnly: true
|
|
7518
7524
|
});
|
|
7519
7525
|
const assetChanges = /* @__PURE__ */ new Map();
|
|
7520
7526
|
const { selected: assetCoins } = selectCoinsWithAsset(
|
|
@@ -8203,7 +8209,7 @@ var STORE_INTENTS = "intents";
|
|
|
8203
8209
|
var STORE_VIRTUAL_TXS = "virtualTxs";
|
|
8204
8210
|
var STORE_VTXO_BRANCHES = "vtxoBranches";
|
|
8205
8211
|
var LEGACY_STORE_CONTRACT_COLLECTIONS = "contractsCollections";
|
|
8206
|
-
var DB_VERSION =
|
|
8212
|
+
var DB_VERSION = 4;
|
|
8207
8213
|
var INTENT_DB_VERSION = 5;
|
|
8208
8214
|
function initDatabase(db, oldVersion, transaction) {
|
|
8209
8215
|
if (!db.objectStoreNames.contains(STORE_VTXOS)) {
|
|
@@ -8266,6 +8272,7 @@ function initDatabase(db, oldVersion, transaction) {
|
|
|
8266
8272
|
unique: false
|
|
8267
8273
|
});
|
|
8268
8274
|
}
|
|
8275
|
+
vtxosStore.createIndex("scriptUnspent", ["script", "unspent"], { unique: false });
|
|
8269
8276
|
}
|
|
8270
8277
|
if (!db.objectStoreNames.contains(STORE_UTXOS)) {
|
|
8271
8278
|
const utxosStore = db.createObjectStore(STORE_UTXOS, {
|
|
@@ -8348,14 +8355,18 @@ function initDatabase(db, oldVersion, transaction) {
|
|
|
8348
8355
|
keyPath: "key"
|
|
8349
8356
|
});
|
|
8350
8357
|
}
|
|
8351
|
-
if (oldVersion >= 1 && oldVersion <
|
|
8358
|
+
if (oldVersion >= 1 && oldVersion < 4 && transaction) {
|
|
8352
8359
|
const vtxosStore = transaction.objectStore(STORE_VTXOS);
|
|
8353
8360
|
if (!vtxosStore.indexNames.contains("script")) {
|
|
8354
8361
|
vtxosStore.createIndex("script", "script", { unique: false });
|
|
8355
8362
|
}
|
|
8356
|
-
|
|
8363
|
+
if (!vtxosStore.indexNames.contains("scriptUnspent")) {
|
|
8364
|
+
vtxosStore.createIndex("scriptUnspent", ["script", "unspent"], { unique: false });
|
|
8365
|
+
}
|
|
8366
|
+
backfillVtxoIndexFields(transaction);
|
|
8357
8367
|
}
|
|
8358
8368
|
}
|
|
8369
|
+
var unspentFlag = (vtxo) => isVtxoSpent(vtxo) ? {} : { unspent: 1 };
|
|
8359
8370
|
function initDatabaseWithIntents(db, oldVersion, transaction) {
|
|
8360
8371
|
initDatabase(db, oldVersion, transaction);
|
|
8361
8372
|
if (!db.objectStoreNames.contains(STORE_INTENTS)) {
|
|
@@ -8405,19 +8416,28 @@ function dedupeIntentIds(store, onComplete) {
|
|
|
8405
8416
|
cursor.continue();
|
|
8406
8417
|
};
|
|
8407
8418
|
}
|
|
8408
|
-
function
|
|
8419
|
+
function backfillVtxoIndexFields(transaction) {
|
|
8409
8420
|
const store = transaction.objectStore(STORE_VTXOS);
|
|
8410
|
-
const
|
|
8411
|
-
|
|
8412
|
-
const
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8421
|
+
const pageSize = 1e3;
|
|
8422
|
+
const readPage = (after) => {
|
|
8423
|
+
const request = store.getAll(after && IDBKeyRange.lowerBound(after, true), pageSize);
|
|
8424
|
+
request.onsuccess = () => {
|
|
8425
|
+
const rows = request.result;
|
|
8426
|
+
for (const value of rows) {
|
|
8427
|
+
const next = {
|
|
8428
|
+
...value,
|
|
8429
|
+
script: value.script || scriptFromArkAddress(value.address),
|
|
8430
|
+
...unspentFlag(value)
|
|
8431
|
+
};
|
|
8432
|
+
if (next.script !== value.script || next.unspent !== value.unspent) {
|
|
8433
|
+
store.put(next);
|
|
8434
|
+
}
|
|
8435
|
+
}
|
|
8436
|
+
const last = rows.at(-1);
|
|
8437
|
+
if (rows.length === pageSize && last) readPage([last.address, last.txid, last.vout]);
|
|
8438
|
+
};
|
|
8420
8439
|
};
|
|
8440
|
+
readPage();
|
|
8421
8441
|
}
|
|
8422
8442
|
|
|
8423
8443
|
// src/worker/browser/utils.ts
|
|
@@ -8776,15 +8796,21 @@ var InMemoryWalletRepository = class {
|
|
|
8776
8796
|
this.vtxosByAddress.delete(address);
|
|
8777
8797
|
}
|
|
8778
8798
|
async getVtxosForScript(script) {
|
|
8779
|
-
|
|
8799
|
+
return this.getVtxosForScripts([script]);
|
|
8800
|
+
}
|
|
8801
|
+
async getVtxosForScripts(scripts, options) {
|
|
8802
|
+
if (scripts.length === 0) return [];
|
|
8803
|
+
const selected = new Set(scripts);
|
|
8804
|
+
const byOutpoint = /* @__PURE__ */ new Map();
|
|
8780
8805
|
for (const bucket of this.vtxosByAddress.values()) {
|
|
8781
8806
|
for (const vtxo of bucket) {
|
|
8782
|
-
if (
|
|
8783
|
-
|
|
8807
|
+
if (vtxo.script && selected.has(vtxo.script)) {
|
|
8808
|
+
byOutpoint.set(`${vtxo.script}:${vtxo.txid}:${vtxo.vout}`, vtxo);
|
|
8784
8809
|
}
|
|
8785
8810
|
}
|
|
8786
8811
|
}
|
|
8787
|
-
|
|
8812
|
+
const rows = [...byOutpoint.values()];
|
|
8813
|
+
return options?.unspentOnly ? rows.filter((vtxo) => !isVtxoSpent(vtxo)) : rows;
|
|
8788
8814
|
}
|
|
8789
8815
|
async saveVtxosForScript(key, vtxos) {
|
|
8790
8816
|
if (!key.address) {
|
|
@@ -9565,7 +9591,7 @@ var ContractWatcher = class {
|
|
|
9565
9591
|
}
|
|
9566
9592
|
if (target === byWatchedScript && eventType === "vtxo_received") {
|
|
9567
9593
|
const n = normalizeVtxo(vtxo);
|
|
9568
|
-
if (
|
|
9594
|
+
if (isVtxoSpent(n) || n.isSwept || isPastExpiry(n, now)) continue;
|
|
9569
9595
|
}
|
|
9570
9596
|
let bucket = target.get(vtxo.script);
|
|
9571
9597
|
if (!bucket) {
|
|
@@ -9664,7 +9690,7 @@ var NON_TERMINAL_INTENT_STATES = ALL_INTENT_STATES.filter(
|
|
|
9664
9690
|
(s) => !isTerminalIntentState(s)
|
|
9665
9691
|
);
|
|
9666
9692
|
function isConsumed(vtxo) {
|
|
9667
|
-
return vtxo !== void 0 &&
|
|
9693
|
+
return vtxo !== void 0 && isVtxoSpent(vtxo);
|
|
9668
9694
|
}
|
|
9669
9695
|
async function classifyIntent(intent, vtxosByOutpoint, now) {
|
|
9670
9696
|
if (isTerminalIntentState(intent.state)) return void 0;
|
|
@@ -9754,7 +9780,8 @@ function areCoalescibleContractTypes(a, b) {
|
|
|
9754
9780
|
function toWatchOnlyContract(params) {
|
|
9755
9781
|
return { ...params, state: params.state ?? "active", createdAt: Date.now() };
|
|
9756
9782
|
}
|
|
9757
|
-
|
|
9783
|
+
var TAPSCRIPT_MEMO_MAX_ENTRIES = 1024;
|
|
9784
|
+
function annotatableIn(scriptToContract, vtxos, memo) {
|
|
9758
9785
|
const scripts = /* @__PURE__ */ new Set();
|
|
9759
9786
|
const cache = /* @__PURE__ */ new Map();
|
|
9760
9787
|
const failures = /* @__PURE__ */ new Map();
|
|
@@ -9762,7 +9789,25 @@ function annotatableIn(scriptToContract, vtxos) {
|
|
|
9762
9789
|
const contract = scriptToContract.get(script);
|
|
9763
9790
|
if (!contract) continue;
|
|
9764
9791
|
try {
|
|
9765
|
-
|
|
9792
|
+
const key = `${contract.type}\0${script}\0${JSON.stringify(contract.params)}`;
|
|
9793
|
+
const handler = contractHandlers.get(contract.type);
|
|
9794
|
+
const hit = memo?.get(script);
|
|
9795
|
+
let tapscripts;
|
|
9796
|
+
if (hit && hit.key === key && hit.handler === handler) {
|
|
9797
|
+
tapscripts = hit.tapscripts;
|
|
9798
|
+
memo.delete(script);
|
|
9799
|
+
memo.set(script, hit);
|
|
9800
|
+
} else {
|
|
9801
|
+
memo?.delete(script);
|
|
9802
|
+
tapscripts = deriveContractTapscripts(contract);
|
|
9803
|
+
if (handler && memo) {
|
|
9804
|
+
memo.set(script, { key, handler, tapscripts });
|
|
9805
|
+
if (memo.size > TAPSCRIPT_MEMO_MAX_ENTRIES) {
|
|
9806
|
+
memo.delete(memo.keys().next().value);
|
|
9807
|
+
}
|
|
9808
|
+
}
|
|
9809
|
+
}
|
|
9810
|
+
cache.set(script, tapscripts);
|
|
9766
9811
|
scripts.add(script);
|
|
9767
9812
|
} catch (err) {
|
|
9768
9813
|
failures.set(
|
|
@@ -9780,6 +9825,8 @@ var CHAIN_TIP_TIMEOUT_MS = 5e3;
|
|
|
9780
9825
|
var ContractManager = class _ContractManager {
|
|
9781
9826
|
config;
|
|
9782
9827
|
watcher;
|
|
9828
|
+
/** Per-sync tapscript caches start empty; this outlives them. Consumers only ever see clones. */
|
|
9829
|
+
tapscriptMemo = /* @__PURE__ */ new Map();
|
|
9783
9830
|
initialized = false;
|
|
9784
9831
|
eventCallbacks = /* @__PURE__ */ new Set();
|
|
9785
9832
|
stopWatcherFn;
|
|
@@ -10462,9 +10509,15 @@ var ContractManager = class _ContractManager {
|
|
|
10462
10509
|
const dbFilter = this.buildContractsDbFilter(filter ?? {});
|
|
10463
10510
|
return await this.config.contractRepository.getContracts(dbFilter);
|
|
10464
10511
|
}
|
|
10465
|
-
async getContractsWithVtxos(filter, pageSize) {
|
|
10512
|
+
async getContractsWithVtxos(filter, pageSize, options) {
|
|
10513
|
+
if (options?.maxSyncAgeMs !== void 0 && (!Number.isSafeInteger(options.maxSyncAgeMs) || options.maxSyncAgeMs < 0)) {
|
|
10514
|
+
throw new Error("maxSyncAgeMs must be a non-negative safe integer");
|
|
10515
|
+
}
|
|
10466
10516
|
const contracts = await this.getContracts(filter);
|
|
10467
|
-
if (this.syncedWithin(
|
|
10517
|
+
if (this.syncedWithin(
|
|
10518
|
+
contracts,
|
|
10519
|
+
options?.maxSyncAgeMs ?? (options?.requireSynced ? 0 : this.config.vtxoSyncMaxAgeMs ?? 0)
|
|
10520
|
+
)) {
|
|
10468
10521
|
await this.demoteFundedAwaitingContracts(contracts);
|
|
10469
10522
|
} else {
|
|
10470
10523
|
try {
|
|
@@ -10473,12 +10526,23 @@ var ContractManager = class _ContractManager {
|
|
|
10473
10526
|
} catch (err) {
|
|
10474
10527
|
if (!isRetryableProviderError(err)) throw err;
|
|
10475
10528
|
this.markSyncDegraded(err);
|
|
10529
|
+
if (options?.requireSynced) {
|
|
10530
|
+
throw new Error("Spendable VTXO read requires an online contract sync", {
|
|
10531
|
+
cause: err
|
|
10532
|
+
});
|
|
10533
|
+
}
|
|
10476
10534
|
}
|
|
10477
10535
|
}
|
|
10478
|
-
const vtxos = await this.getVtxosForContracts(contracts);
|
|
10536
|
+
const vtxos = await this.getVtxosForContracts(contracts, options);
|
|
10537
|
+
const vtxosByScript = /* @__PURE__ */ new Map();
|
|
10538
|
+
for (const vtxo of vtxos) {
|
|
10539
|
+
const group = vtxosByScript.get(vtxo.contractScript) ?? [];
|
|
10540
|
+
group.push(vtxo);
|
|
10541
|
+
vtxosByScript.set(vtxo.contractScript, group);
|
|
10542
|
+
}
|
|
10479
10543
|
return contracts.map((contract) => ({
|
|
10480
10544
|
contract,
|
|
10481
|
-
vtxos:
|
|
10545
|
+
vtxos: vtxosByScript.get(contract.script)?.slice() ?? []
|
|
10482
10546
|
}));
|
|
10483
10547
|
}
|
|
10484
10548
|
async annotateVtxos(vtxos, tapscripts) {
|
|
@@ -10504,7 +10568,8 @@ var ContractManager = class _ContractManager {
|
|
|
10504
10568
|
});
|
|
10505
10569
|
const { scripts, failures } = annotatableIn(
|
|
10506
10570
|
new Map(contracts.map((contract) => [contract.script, contract])),
|
|
10507
|
-
vtxos
|
|
10571
|
+
vtxos,
|
|
10572
|
+
this.tapscriptMemo
|
|
10508
10573
|
);
|
|
10509
10574
|
const orphans = vtxos.filter(
|
|
10510
10575
|
(vtxo) => !scripts.has(vtxo.script) && !failures.has(vtxo.script)
|
|
@@ -10655,6 +10720,7 @@ var ContractManager = class _ContractManager {
|
|
|
10655
10720
|
*/
|
|
10656
10721
|
async deleteContract(script) {
|
|
10657
10722
|
await this.config.contractRepository.deleteContract(script);
|
|
10723
|
+
this.tapscriptMemo.delete(script);
|
|
10658
10724
|
await this.watcher.removeContract(script);
|
|
10659
10725
|
}
|
|
10660
10726
|
/**
|
|
@@ -10906,20 +10972,28 @@ var ContractManager = class _ContractManager {
|
|
|
10906
10972
|
}
|
|
10907
10973
|
this.emitEvent(event);
|
|
10908
10974
|
}
|
|
10909
|
-
async getVtxosForContracts(contracts) {
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10975
|
+
async getVtxosForContracts(contracts, options) {
|
|
10976
|
+
if (contracts.length === 0) return [];
|
|
10977
|
+
let rows;
|
|
10978
|
+
if (this.config.walletRepository.getVtxosForScripts) {
|
|
10979
|
+
const byScript = new Set(contracts.map((contract) => contract.script));
|
|
10980
|
+
rows = (await this.config.walletRepository.getVtxosForScripts([...byScript], options)).filter((vtxo) => vtxo.script !== void 0 && byScript.has(vtxo.script)).map((vtxo) => ({ ...normalizeVtxo(vtxo), contractScript: vtxo.script }));
|
|
10981
|
+
} else {
|
|
10982
|
+
const res = await Promise.all(
|
|
10983
|
+
contracts.map(
|
|
10984
|
+
(contract) => getVtxosForContract(this.config.walletRepository, contract).then(
|
|
10985
|
+
(vtxos) => vtxos.map(
|
|
10986
|
+
(vtxo) => ({
|
|
10987
|
+
...vtxo,
|
|
10988
|
+
contractScript: contract.script
|
|
10989
|
+
})
|
|
10990
|
+
)
|
|
10918
10991
|
)
|
|
10919
10992
|
)
|
|
10920
|
-
)
|
|
10921
|
-
|
|
10922
|
-
|
|
10993
|
+
);
|
|
10994
|
+
rows = res.flat();
|
|
10995
|
+
}
|
|
10996
|
+
return options?.unspentOnly ? rows.filter((vtxo) => !isVtxoSpent(vtxo)) : rows;
|
|
10923
10997
|
}
|
|
10924
10998
|
/**
|
|
10925
10999
|
* Sync virtual outputs for the given contracts against the indexer.
|
|
@@ -11000,7 +11074,11 @@ var ContractManager = class _ContractManager {
|
|
|
11000
11074
|
for (const [script, contract] of await this.promoteLookAheadHits(vtxos)) {
|
|
11001
11075
|
scriptToContract.set(script, contract);
|
|
11002
11076
|
}
|
|
11003
|
-
const {
|
|
11077
|
+
const {
|
|
11078
|
+
scripts: annotatable,
|
|
11079
|
+
cache,
|
|
11080
|
+
failures
|
|
11081
|
+
} = annotatableIn(scriptToContract, vtxos, this.tapscriptMemo);
|
|
11004
11082
|
this.recordAnnotationFailures(annotatable, failures);
|
|
11005
11083
|
const owned = vtxos.filter((v) => annotatable.has(v.script));
|
|
11006
11084
|
const annotated = await this.annotateVtxos(owned, cache);
|
|
@@ -11100,7 +11178,11 @@ var ContractManager = class _ContractManager {
|
|
|
11100
11178
|
for (const [script, contract] of promoted) {
|
|
11101
11179
|
scriptToContract.set(script, contract);
|
|
11102
11180
|
}
|
|
11103
|
-
const {
|
|
11181
|
+
const {
|
|
11182
|
+
scripts: annotatable,
|
|
11183
|
+
cache,
|
|
11184
|
+
failures
|
|
11185
|
+
} = annotatableIn(scriptToContract, vtxos, this.tapscriptMemo);
|
|
11104
11186
|
this.recordAnnotationFailures(annotatable, failures);
|
|
11105
11187
|
const owned = vtxos.filter((v) => annotatable.has(v.script));
|
|
11106
11188
|
const annotated = await this.annotateVtxos(owned, cache);
|
|
@@ -11412,7 +11494,7 @@ var IndexedDBWalletRepository = class {
|
|
|
11412
11494
|
const store = transaction.objectStore(STORE_VTXOS);
|
|
11413
11495
|
for (const vtxo of vtxos) {
|
|
11414
11496
|
const serialized = serializeVtxo(vtxo);
|
|
11415
|
-
store.put({ address, ...serialized });
|
|
11497
|
+
store.put({ address, ...serialized, ...unspentFlag(vtxo) });
|
|
11416
11498
|
}
|
|
11417
11499
|
await awaitTransaction(transaction);
|
|
11418
11500
|
} catch (error) {
|
|
@@ -11432,31 +11514,52 @@ var IndexedDBWalletRepository = class {
|
|
|
11432
11514
|
}
|
|
11433
11515
|
}
|
|
11434
11516
|
async getVtxosForScript(script) {
|
|
11517
|
+
return this.getVtxosForScripts([script]);
|
|
11518
|
+
}
|
|
11519
|
+
async getVtxosForScripts(scripts, options) {
|
|
11520
|
+
const unique = [...new Set(scripts)];
|
|
11521
|
+
if (unique.length === 0) return [];
|
|
11435
11522
|
try {
|
|
11436
11523
|
const db = await this.getDB();
|
|
11437
|
-
const
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11441
|
-
|
|
11524
|
+
const rows = options?.unspentOnly ? await getAllByIndexValues(
|
|
11525
|
+
this.vtxoStore(db),
|
|
11526
|
+
"scriptUnspent",
|
|
11527
|
+
unique.map((script) => [script, 1])
|
|
11528
|
+
) : await getAllByIndexValues(this.vtxoStore(db), "script", unique);
|
|
11529
|
+
const selected = new Set(unique);
|
|
11442
11530
|
const byOutpoint = /* @__PURE__ */ new Map();
|
|
11443
|
-
for (const row of
|
|
11444
|
-
|
|
11445
|
-
const
|
|
11446
|
-
|
|
11447
|
-
|
|
11531
|
+
for (const row of rows) {
|
|
11532
|
+
if (!selected.has(row.script)) continue;
|
|
11533
|
+
const key = `${row.script}:${row.txid}:${row.vout}`;
|
|
11534
|
+
const existing = byOutpoint.get(key);
|
|
11535
|
+
if (!existing || shouldReplaceVtxo(existing, row)) byOutpoint.set(key, row);
|
|
11536
|
+
}
|
|
11537
|
+
if (options?.unspentOnly && byOutpoint.size > 0) {
|
|
11538
|
+
const txids = [...new Set([...byOutpoint.values()].map((row) => row.txid))];
|
|
11539
|
+
const store = this.vtxoStore(db);
|
|
11540
|
+
for (const row of await getAllByIndexValues(store, "txid", txids)) {
|
|
11541
|
+
const key = `${row.script}:${row.txid}:${row.vout}`;
|
|
11542
|
+
const existing = byOutpoint.get(key);
|
|
11543
|
+
if (existing && shouldReplaceVtxo(existing, row)) byOutpoint.set(key, row);
|
|
11544
|
+
}
|
|
11545
|
+
}
|
|
11546
|
+
const result = [];
|
|
11547
|
+
for (const row of byOutpoint.values()) {
|
|
11548
|
+
if (options?.unspentOnly && (row.isSpent || row.spentBy || row.settledBy)) {
|
|
11448
11549
|
continue;
|
|
11449
11550
|
}
|
|
11450
|
-
|
|
11451
|
-
|
|
11452
|
-
}
|
|
11551
|
+
const vtxo = deserializeVtxoWithBackfill(row);
|
|
11552
|
+
if (!options?.unspentOnly || !isVtxoSpent(vtxo)) result.push(vtxo);
|
|
11453
11553
|
}
|
|
11454
|
-
return
|
|
11554
|
+
return result;
|
|
11455
11555
|
} catch (error) {
|
|
11456
|
-
console.error(
|
|
11556
|
+
console.error("Failed to get VTXOs for scripts:", error);
|
|
11457
11557
|
throw error;
|
|
11458
11558
|
}
|
|
11459
11559
|
}
|
|
11560
|
+
vtxoStore(db) {
|
|
11561
|
+
return db.transaction([STORE_VTXOS], "readonly").objectStore(STORE_VTXOS);
|
|
11562
|
+
}
|
|
11460
11563
|
async saveVtxosForScript(key, vtxos) {
|
|
11461
11564
|
if (!key.address) {
|
|
11462
11565
|
throw new Error("IndexedDBWalletRepository requires an address");
|
|
@@ -11587,7 +11690,7 @@ var IndexedDBWalletRepository = class {
|
|
|
11587
11690
|
return this.connection.get();
|
|
11588
11691
|
}
|
|
11589
11692
|
};
|
|
11590
|
-
function deserializeVtxoWithBackfill(o) {
|
|
11693
|
+
function deserializeVtxoWithBackfill({ unspent: _unspent, ...o }) {
|
|
11591
11694
|
if (!o.script) {
|
|
11592
11695
|
o = { ...o, script: scriptFromArkAddress(o.address) };
|
|
11593
11696
|
}
|
|
@@ -12507,7 +12610,7 @@ async function resolveDescriptorProvider(config, walletRepository) {
|
|
|
12507
12610
|
|
|
12508
12611
|
// src/wallet/balance.ts
|
|
12509
12612
|
function computeOffchainBalance(vtxos, caps) {
|
|
12510
|
-
const { now, isPendingRecovery, isGenericallySpendable, isUnlocked } = caps;
|
|
12613
|
+
const { now, isPendingRecovery, isGenericallySpendable, isUnlocked, dustCarrier } = caps;
|
|
12511
12614
|
let settled = 0;
|
|
12512
12615
|
let preconfirmed = 0;
|
|
12513
12616
|
let available = 0;
|
|
@@ -12524,7 +12627,7 @@ function computeOffchainBalance(vtxos, caps) {
|
|
|
12524
12627
|
}
|
|
12525
12628
|
};
|
|
12526
12629
|
for (const vtxo of vtxos) {
|
|
12527
|
-
if (
|
|
12630
|
+
if (isVtxoSpent(vtxo)) continue;
|
|
12528
12631
|
addAssets(owned, vtxo);
|
|
12529
12632
|
if (vtxo.isUnrolled) {
|
|
12530
12633
|
unrolled += vtxo.value;
|
|
@@ -12553,6 +12656,9 @@ function computeOffchainBalance(vtxos, caps) {
|
|
|
12553
12656
|
addAssets(spendable, vtxo);
|
|
12554
12657
|
}
|
|
12555
12658
|
}
|
|
12659
|
+
if (available > 0 && spendable.size > 0) {
|
|
12660
|
+
available = Math.max(0, available - Number(dustCarrier));
|
|
12661
|
+
}
|
|
12556
12662
|
const toAssets = (from) => Array.from(from.entries()).map(([assetId, amount]) => ({ assetId, amount }));
|
|
12557
12663
|
return {
|
|
12558
12664
|
settled,
|
|
@@ -12793,7 +12899,7 @@ function filterSnapshotVtxos(snapshot, filter, pendingSpendOutpoints) {
|
|
|
12793
12899
|
if (vtxo.isUnrolled) {
|
|
12794
12900
|
return !!f.withUnrolled;
|
|
12795
12901
|
}
|
|
12796
|
-
if (
|
|
12902
|
+
if (isVtxoSpent(vtxo)) {
|
|
12797
12903
|
return false;
|
|
12798
12904
|
}
|
|
12799
12905
|
if (!f.withRecoverable && canRecoverOnchain(vtxo, now)) {
|
|
@@ -13361,7 +13467,9 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
13361
13467
|
}
|
|
13362
13468
|
/** @inheritdoc */
|
|
13363
13469
|
async getSpendableVtxos(filter) {
|
|
13364
|
-
const snapshot = await this.contractSnapshot(
|
|
13470
|
+
const snapshot = await this.contractSnapshot(filter, {
|
|
13471
|
+
unspentOnly: !filter?.withUnrolled
|
|
13472
|
+
});
|
|
13365
13473
|
const vtxos = filterSnapshotVtxos(snapshot, filter, this._pendingSpendOutpoints);
|
|
13366
13474
|
const { gated, pendingRecovery } = this.spendabilityView(snapshot);
|
|
13367
13475
|
const selectable = vtxos.filter(
|
|
@@ -13379,7 +13487,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
13379
13487
|
if (!filter?.withUnrolled) {
|
|
13380
13488
|
logExcludedVtxos(
|
|
13381
13489
|
"getSpendableVtxos",
|
|
13382
|
-
snapshot.flatMap((contract) => contract.vtxos).filter((vtxo) => vtxo.isUnrolled && !
|
|
13490
|
+
snapshot.flatMap((contract) => contract.vtxos).filter((vtxo) => vtxo.isUnrolled && !isVtxoSpent(vtxo)),
|
|
13383
13491
|
[() => UNROLLED_REASON]
|
|
13384
13492
|
);
|
|
13385
13493
|
}
|
|
@@ -13453,9 +13561,25 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
13453
13561
|
* otherwise the gate and the pending-recovery set answer about two different
|
|
13454
13562
|
* points in time, and each read costs another sync.
|
|
13455
13563
|
*/
|
|
13456
|
-
async contractSnapshot() {
|
|
13564
|
+
async contractSnapshot(filter, options) {
|
|
13457
13565
|
const contractManager = await this.getContractManager();
|
|
13458
|
-
|
|
13566
|
+
const scope = filter?.watchedOnly ? { watch: ["watched", "awaiting-funds"] } : void 0;
|
|
13567
|
+
let query = scope;
|
|
13568
|
+
if (filter?.genericallySpendableOnly) {
|
|
13569
|
+
const scripts = (await contractManager.getContracts(scope)).filter(isContractGenericallySpendable).map((contract) => contract.script);
|
|
13570
|
+
if (scripts.length === 0) {
|
|
13571
|
+
if (filter.requireSynced) {
|
|
13572
|
+
throw new Error("No generically spendable contracts to sync");
|
|
13573
|
+
}
|
|
13574
|
+
return [];
|
|
13575
|
+
}
|
|
13576
|
+
query = { ...scope, script: scripts };
|
|
13577
|
+
}
|
|
13578
|
+
return contractManager.getContractsWithVtxos(query, void 0, {
|
|
13579
|
+
maxSyncAgeMs: filter?.maxSyncAgeMs,
|
|
13580
|
+
unspentOnly: options?.unspentOnly,
|
|
13581
|
+
requireSynced: filter?.requireSynced
|
|
13582
|
+
});
|
|
13459
13583
|
}
|
|
13460
13584
|
/**
|
|
13461
13585
|
* The two exclusion sets the gate is made of, derived from one snapshot so
|
|
@@ -13479,7 +13603,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
|
|
|
13479
13603
|
now: { timestamp: /* @__PURE__ */ new Date() },
|
|
13480
13604
|
isPendingRecovery: (vtxo) => pendingRecovery.has(`${vtxo.txid}:${vtxo.vout}`),
|
|
13481
13605
|
isGenericallySpendable: (vtxo) => !isGatedVtxo(vtxo, gated),
|
|
13482
|
-
isUnlocked: (vtxo) => unlocked.has(`${vtxo.txid}:${vtxo.vout}`)
|
|
13606
|
+
isUnlocked: (vtxo) => unlocked.has(`${vtxo.txid}:${vtxo.vout}`),
|
|
13607
|
+
dustCarrier: getDustAmount(this)
|
|
13483
13608
|
};
|
|
13484
13609
|
}
|
|
13485
13610
|
/**
|
|
@@ -15283,7 +15408,10 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
15283
15408
|
filteredBoardingUtxos.push(utxo);
|
|
15284
15409
|
amount += utxo.value - inputFee.satoshis;
|
|
15285
15410
|
}
|
|
15286
|
-
const vtxos = await this.getSpendableVtxos({
|
|
15411
|
+
const vtxos = await this.getSpendableVtxos({
|
|
15412
|
+
withRecoverable: true,
|
|
15413
|
+
genericallySpendableOnly: true
|
|
15414
|
+
});
|
|
15287
15415
|
const filteredVtxos = [];
|
|
15288
15416
|
for (const vtxo of byValueDescending(vtxos)) {
|
|
15289
15417
|
if (filteredVtxos.length >= MAX_VTXOS_PER_SETTLEMENT) {
|
|
@@ -16196,7 +16324,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
16196
16324
|
const spendable = [];
|
|
16197
16325
|
const unclaimed = [];
|
|
16198
16326
|
for (const vtxo of vtxos) {
|
|
16199
|
-
if (
|
|
16327
|
+
if (isVtxoSpent(vtxo)) {
|
|
16200
16328
|
unclaimed.push(cashReport(vtxo, "already-spent"));
|
|
16201
16329
|
} else if (vtxo.isUnrolled) {
|
|
16202
16330
|
unclaimed.push(cashReport(vtxo, "exited"));
|
|
@@ -16387,7 +16515,8 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
16387
16515
|
let virtualCoins = [];
|
|
16388
16516
|
if (!selectedVtxos) {
|
|
16389
16517
|
virtualCoins = await this.getSpendableVtxos({
|
|
16390
|
-
withRecoverable: false
|
|
16518
|
+
withRecoverable: false,
|
|
16519
|
+
genericallySpendableOnly: true
|
|
16391
16520
|
});
|
|
16392
16521
|
}
|
|
16393
16522
|
const assetChanges = /* @__PURE__ */ new Map();
|
|
@@ -16419,6 +16548,15 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
16419
16548
|
}
|
|
16420
16549
|
}
|
|
16421
16550
|
} else {
|
|
16551
|
+
const coinsByAsset = /* @__PURE__ */ new Map();
|
|
16552
|
+
for (const coin of virtualCoins) {
|
|
16553
|
+
for (const assetId of new Set(coin.assets?.map((asset) => asset.assetId))) {
|
|
16554
|
+
const coins = coinsByAsset.get(assetId) ?? [];
|
|
16555
|
+
coins.push(coin);
|
|
16556
|
+
coinsByAsset.set(assetId, coins);
|
|
16557
|
+
}
|
|
16558
|
+
}
|
|
16559
|
+
const selectedOutpoints2 = /* @__PURE__ */ new Set();
|
|
16422
16560
|
for (const recipient of recipients) {
|
|
16423
16561
|
if (!recipient.assets) {
|
|
16424
16562
|
continue;
|
|
@@ -16437,8 +16575,8 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
16437
16575
|
amountToSelect -= existingChange;
|
|
16438
16576
|
assetChanges.delete(receiverAsset.assetId);
|
|
16439
16577
|
}
|
|
16440
|
-
const availableCoins =
|
|
16441
|
-
(
|
|
16578
|
+
const availableCoins = (coinsByAsset.get(receiverAsset.assetId) ?? []).filter(
|
|
16579
|
+
(coin) => !selectedOutpoints2.has(vtxoOutpoint(coin))
|
|
16442
16580
|
);
|
|
16443
16581
|
const { selected, totalAssetAmount } = selectCoinsWithAsset(
|
|
16444
16582
|
availableCoins,
|
|
@@ -16447,6 +16585,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
16447
16585
|
);
|
|
16448
16586
|
for (const coin of selected) {
|
|
16449
16587
|
selectedCoins.push(coin);
|
|
16588
|
+
selectedOutpoints2.add(vtxoOutpoint(coin));
|
|
16450
16589
|
btcAmountToSelect -= coin.value;
|
|
16451
16590
|
if (coin.assets) {
|
|
16452
16591
|
for (const a of coin.assets) {
|
|
@@ -16467,7 +16606,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
16467
16606
|
}
|
|
16468
16607
|
if (btcAmountToSelect > 0) {
|
|
16469
16608
|
const availableCoins = virtualCoins.filter(
|
|
16470
|
-
(
|
|
16609
|
+
(coin) => !selectedOutpoints2.has(vtxoOutpoint(coin))
|
|
16471
16610
|
);
|
|
16472
16611
|
const { inputs: btcCoins } = selectVirtualCoins(availableCoins, btcAmountToSelect);
|
|
16473
16612
|
for (const coin of btcCoins) {
|
|
@@ -16479,6 +16618,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
16479
16618
|
}
|
|
16480
16619
|
}
|
|
16481
16620
|
selectedCoins = [...selectedCoins, ...btcCoins];
|
|
16621
|
+
for (const coin of btcCoins) selectedOutpoints2.add(vtxoOutpoint(coin));
|
|
16482
16622
|
}
|
|
16483
16623
|
}
|
|
16484
16624
|
let totalBtcSelected = selectedCoins.reduce((sum, c) => sum + c.value, 0);
|
|
@@ -16495,19 +16635,58 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
16495
16635
|
`send({ selectedVtxos }): inputs total ${totalBtcSelected} sats, outputs need ${totalBtcOutput}`
|
|
16496
16636
|
);
|
|
16497
16637
|
}
|
|
16498
|
-
if (assetChanges.size > 0 && changeAmount < Number(this.dustAmount)) {
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16505
|
-
|
|
16638
|
+
if (selectedVtxos && assetChanges.size > 0 && changeAmount < Number(this.dustAmount)) {
|
|
16639
|
+
throw new Error(
|
|
16640
|
+
`send({ selectedVtxos }): ${changeAmount} sats of change cannot carry ${assetChanges.size} asset change(s), needs ${this.dustAmount}`
|
|
16641
|
+
);
|
|
16642
|
+
}
|
|
16643
|
+
const vtxoMinAmount = changeAmount > 0 || assetChanges.size > 0 ? (await this.arkProvider.getInfo()).vtxoMinAmount ?? 0n : 0n;
|
|
16644
|
+
if (selectedVtxos && changeAmount > 0 && BigInt(changeAmount) < vtxoMinAmount) {
|
|
16645
|
+
throw new Error(
|
|
16646
|
+
`send({ selectedVtxos }): ${changeAmount} sats of change is below the operator minimum of ${vtxoMinAmount} sats`
|
|
16506
16647
|
);
|
|
16507
|
-
|
|
16508
|
-
|
|
16509
|
-
|
|
16648
|
+
}
|
|
16649
|
+
const selectedOutpoints = new Set(selectedCoins.map(vtxoOutpoint));
|
|
16650
|
+
while (!selectedVtxos && (changeAmount > 0 && BigInt(changeAmount) < vtxoMinAmount || assetChanges.size > 0 && BigInt(changeAmount) < this.dustAmount)) {
|
|
16651
|
+
const minimumChange = assetChanges.size > 0 && this.dustAmount > vtxoMinAmount ? this.dustAmount : vtxoMinAmount;
|
|
16652
|
+
const availableCoins = virtualCoins.filter(
|
|
16653
|
+
(coin) => !selectedOutpoints.has(vtxoOutpoint(coin))
|
|
16510
16654
|
);
|
|
16655
|
+
let extraCoins;
|
|
16656
|
+
try {
|
|
16657
|
+
({ inputs: extraCoins } = selectVirtualCoins(
|
|
16658
|
+
availableCoins,
|
|
16659
|
+
Number(minimumChange) - changeAmount
|
|
16660
|
+
));
|
|
16661
|
+
} catch (error) {
|
|
16662
|
+
if (!(error instanceof Error) || error.message !== "Insufficient funds") {
|
|
16663
|
+
throw error;
|
|
16664
|
+
}
|
|
16665
|
+
if (recipients.every((r) => r.assets.length === 0)) {
|
|
16666
|
+
const plainCoins = virtualCoins.filter((coin) => !coin.assets?.length);
|
|
16667
|
+
const exact = plainCoins.find((coin) => coin.value === totalBtcOutput);
|
|
16668
|
+
let exactCoins = exact ? [exact] : void 0;
|
|
16669
|
+
if (!exactCoins) {
|
|
16670
|
+
const byAmount = /* @__PURE__ */ new Map();
|
|
16671
|
+
for (const coin of plainCoins) {
|
|
16672
|
+
const partner = byAmount.get(totalBtcOutput - coin.value);
|
|
16673
|
+
if (partner) {
|
|
16674
|
+
exactCoins = [partner, coin];
|
|
16675
|
+
break;
|
|
16676
|
+
}
|
|
16677
|
+
byAmount.set(coin.value, coin);
|
|
16678
|
+
}
|
|
16679
|
+
}
|
|
16680
|
+
if (exactCoins) {
|
|
16681
|
+
selectedCoins = exactCoins;
|
|
16682
|
+
assetChanges.clear();
|
|
16683
|
+
totalBtcSelected = totalBtcOutput;
|
|
16684
|
+
changeAmount = 0;
|
|
16685
|
+
break;
|
|
16686
|
+
}
|
|
16687
|
+
}
|
|
16688
|
+
throw new Error(`Cannot form minimum change amount of ${minimumChange} sats`);
|
|
16689
|
+
}
|
|
16511
16690
|
for (const coin of extraCoins) {
|
|
16512
16691
|
if (coin.assets) {
|
|
16513
16692
|
for (const asset of coin.assets) {
|
|
@@ -16517,6 +16696,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
|
|
|
16517
16696
|
}
|
|
16518
16697
|
}
|
|
16519
16698
|
selectedCoins = [...selectedCoins, ...extraCoins];
|
|
16699
|
+
for (const coin of extraCoins) selectedOutpoints.add(vtxoOutpoint(coin));
|
|
16520
16700
|
totalBtcSelected += extraCoins.reduce((sum, c) => sum + c.value, 0);
|
|
16521
16701
|
changeAmount = totalBtcSelected - totalBtcOutput;
|
|
16522
16702
|
}
|
|
@@ -17903,7 +18083,8 @@ var Ramps = class {
|
|
|
17903
18083
|
if (vtxos) reportUngatedInputs(this.wallet, vtxos);
|
|
17904
18084
|
const spendable = vtxos ?? await this.wallet.getSpendableVtxos({
|
|
17905
18085
|
withRecoverable: true,
|
|
17906
|
-
withUnrolled: false
|
|
18086
|
+
withUnrolled: false,
|
|
18087
|
+
genericallySpendableOnly: true
|
|
17907
18088
|
});
|
|
17908
18089
|
const estimator = new Estimator(feeInfo?.intentFee ?? {});
|
|
17909
18090
|
const { inputs, subtotal } = filterOffboardInputs(spendable, feeInfo, named);
|
|
@@ -17945,7 +18126,8 @@ var Ramps = class {
|
|
|
17945
18126
|
if (vtxos) reportUngatedInputs(this.wallet, vtxos);
|
|
17946
18127
|
const spendable = vtxos ?? await this.wallet.getSpendableVtxos({
|
|
17947
18128
|
withRecoverable: true,
|
|
17948
|
-
withUnrolled: false
|
|
18129
|
+
withUnrolled: false,
|
|
18130
|
+
genericallySpendableOnly: true
|
|
17949
18131
|
});
|
|
17950
18132
|
const estimator = new Estimator(feeInfo?.intentFee ?? {});
|
|
17951
18133
|
const { inputs, subtotal } = filterOffboardInputs(spendable, feeInfo, named);
|
|
@@ -18332,7 +18514,7 @@ var WalletMessageHandler = class {
|
|
|
18332
18514
|
return this.tagged({
|
|
18333
18515
|
id,
|
|
18334
18516
|
type: "SPENDABLE_VTXOS",
|
|
18335
|
-
payload: { vtxos }
|
|
18517
|
+
payload: { vtxos, filterApplied: true }
|
|
18336
18518
|
});
|
|
18337
18519
|
}
|
|
18338
18520
|
case "GET_BOARDING_UTXOS": {
|
|
@@ -18413,11 +18595,15 @@ var WalletMessageHandler = class {
|
|
|
18413
18595
|
}
|
|
18414
18596
|
case "GET_CONTRACTS_WITH_VTXOS": {
|
|
18415
18597
|
const manager = await this.readonlyWallet.getContractManager();
|
|
18416
|
-
const contracts = await manager.getContractsWithVtxos(
|
|
18598
|
+
const contracts = await manager.getContractsWithVtxos(
|
|
18599
|
+
message.payload.filter,
|
|
18600
|
+
void 0,
|
|
18601
|
+
message.payload.options
|
|
18602
|
+
);
|
|
18417
18603
|
return this.tagged({
|
|
18418
18604
|
id,
|
|
18419
18605
|
type: "CONTRACTS_WITH_VTXOS",
|
|
18420
|
-
payload: { contracts }
|
|
18606
|
+
payload: { contracts, filterApplied: true }
|
|
18421
18607
|
});
|
|
18422
18608
|
}
|
|
18423
18609
|
case "WATCH_SCRIPT": {
|
|
@@ -18835,7 +19021,8 @@ var WalletMessageHandler = class {
|
|
|
18835
19021
|
now: { timestamp: /* @__PURE__ */ new Date() },
|
|
18836
19022
|
isPendingRecovery: (vtxo) => pendingOutpoints.has(`${vtxo.txid}:${vtxo.vout}`),
|
|
18837
19023
|
isGenericallySpendable: (vtxo) => !isGatedVtxo(vtxo, gated),
|
|
18838
|
-
isUnlocked: (vtxo) => unlocked.has(`${vtxo.txid}:${vtxo.vout}`)
|
|
19024
|
+
isUnlocked: (vtxo) => unlocked.has(`${vtxo.txid}:${vtxo.vout}`),
|
|
19025
|
+
dustCarrier: getDustAmount(this.readonlyWallet)
|
|
18839
19026
|
});
|
|
18840
19027
|
return {
|
|
18841
19028
|
boarding: {
|
|
@@ -19088,7 +19275,7 @@ var WalletMessageHandler = class {
|
|
|
19088
19275
|
if (v.isUnrolled) {
|
|
19089
19276
|
return withUnrolled;
|
|
19090
19277
|
}
|
|
19091
|
-
if (
|
|
19278
|
+
if (isVtxoSpent(v)) {
|
|
19092
19279
|
return false;
|
|
19093
19280
|
}
|
|
19094
19281
|
if (includeRecoverable) {
|
|
@@ -19941,7 +20128,13 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
19941
20128
|
};
|
|
19942
20129
|
try {
|
|
19943
20130
|
const response = await this.sendMessage(message);
|
|
19944
|
-
|
|
20131
|
+
const payload = response.payload;
|
|
20132
|
+
if ((filter?.watchedOnly || filter?.genericallySpendableOnly || filter?.requireSynced) && payload.filterApplied !== true) {
|
|
20133
|
+
throw new Error(
|
|
20134
|
+
"Service worker does not support the requested contract scope or freshness check"
|
|
20135
|
+
);
|
|
20136
|
+
}
|
|
20137
|
+
return payload.vtxos.map(normalizeVtxo);
|
|
19945
20138
|
} catch (error) {
|
|
19946
20139
|
throw new Error(`Failed to get spendable vtxos: ${error}`);
|
|
19947
20140
|
}
|
|
@@ -20026,15 +20219,20 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
|
|
|
20026
20219
|
throw new Error("Failed to get contracts");
|
|
20027
20220
|
}
|
|
20028
20221
|
},
|
|
20029
|
-
async getContractsWithVtxos(filter) {
|
|
20222
|
+
async getContractsWithVtxos(filter, _pageSize, options) {
|
|
20030
20223
|
const message = {
|
|
20031
20224
|
type: "GET_CONTRACTS_WITH_VTXOS",
|
|
20032
20225
|
id: getRandomId(),
|
|
20033
20226
|
tag: messageTag,
|
|
20034
|
-
payload: { filter }
|
|
20227
|
+
payload: { filter, options }
|
|
20035
20228
|
};
|
|
20036
20229
|
try {
|
|
20037
20230
|
const response = await sendContractMessage(message);
|
|
20231
|
+
if (options?.requireSynced && response.payload.filterApplied !== true) {
|
|
20232
|
+
throw new Error(
|
|
20233
|
+
"Service worker does not support the requested freshness check"
|
|
20234
|
+
);
|
|
20235
|
+
}
|
|
20038
20236
|
await refreshSyncState();
|
|
20039
20237
|
return response.payload.contracts;
|
|
20040
20238
|
} catch (e) {
|
|
@@ -23512,7 +23710,9 @@ __export(arkade_exports, {
|
|
|
23512
23710
|
fromASM: () => fromASM,
|
|
23513
23711
|
getOpcodeName: () => getOpcodeName,
|
|
23514
23712
|
getOpcodeValue: () => getOpcodeValue,
|
|
23713
|
+
isContractArtifact: () => isContractArtifact,
|
|
23515
23714
|
parseArtifact: () => parseArtifact,
|
|
23715
|
+
programFromArtifact: () => programFromArtifact,
|
|
23516
23716
|
resolveAsm: () => resolveAsm,
|
|
23517
23717
|
serializeArkadeContractParams: () => serializeArkadeContractParams,
|
|
23518
23718
|
stringifyArtifact: () => stringifyArtifact,
|
|
@@ -23710,6 +23910,263 @@ function createArkadeBatchHandler(intentId, inputs, signer, signedProof, message
|
|
|
23710
23910
|
}
|
|
23711
23911
|
};
|
|
23712
23912
|
}
|
|
23913
|
+
var NATIVE_STRUCTS = {
|
|
23914
|
+
AssetId: [
|
|
23915
|
+
["txid", "bytes32"],
|
|
23916
|
+
["gidx", "int"]
|
|
23917
|
+
],
|
|
23918
|
+
Outpoint: [
|
|
23919
|
+
["txid", "bytes32"],
|
|
23920
|
+
["vout", "int"]
|
|
23921
|
+
],
|
|
23922
|
+
ECPoint: [
|
|
23923
|
+
["x", "int"],
|
|
23924
|
+
["y", "int"]
|
|
23925
|
+
]
|
|
23926
|
+
};
|
|
23927
|
+
var HASH_OPCODES = /* @__PURE__ */ new Set(["OP_SHA256", "OP_HASH160", "OP_HASH256", "OP_RIPEMD160"]);
|
|
23928
|
+
function isRecord(value) {
|
|
23929
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23930
|
+
}
|
|
23931
|
+
function isNamed(value) {
|
|
23932
|
+
return isRecord(value) && typeof value.name === "string" && typeof value.type === "string" && value.type.length > 0;
|
|
23933
|
+
}
|
|
23934
|
+
function isContractArtifact(value) {
|
|
23935
|
+
if (!isRecord(value) || typeof value.contractName !== "string") return false;
|
|
23936
|
+
if (!Array.isArray(value.constructorInputs)) return false;
|
|
23937
|
+
if (value.structs !== void 0 && !Array.isArray(value.structs)) return false;
|
|
23938
|
+
if (!Array.isArray(value.functions) || value.functions.length === 0) return false;
|
|
23939
|
+
return value.functions.every(
|
|
23940
|
+
(group) => isRecord(group) && typeof group.name === "string" && Array.isArray(group.leaves) && group.leaves.length > 0
|
|
23941
|
+
);
|
|
23942
|
+
}
|
|
23943
|
+
function fail(detail) {
|
|
23944
|
+
throw new Error(`programFromArtifact: ${detail}`);
|
|
23945
|
+
}
|
|
23946
|
+
function claim(seen, name, kind) {
|
|
23947
|
+
if (seen.has(name)) fail(`duplicate ${kind} '${name}'`);
|
|
23948
|
+
seen.add(name);
|
|
23949
|
+
}
|
|
23950
|
+
var SCALAR_TYPES = {
|
|
23951
|
+
pubkey: "pubkey",
|
|
23952
|
+
signature: "sig",
|
|
23953
|
+
bytes: "bytes",
|
|
23954
|
+
bytes20: "hash",
|
|
23955
|
+
bytes32: "hash",
|
|
23956
|
+
asset: "hash",
|
|
23957
|
+
int: "int",
|
|
23958
|
+
bool: "int"
|
|
23959
|
+
};
|
|
23960
|
+
function argType(arkType) {
|
|
23961
|
+
if (!Object.hasOwn(SCALAR_TYPES, arkType)) fail(`unknown type '${arkType}'`);
|
|
23962
|
+
return SCALAR_TYPES[arkType];
|
|
23963
|
+
}
|
|
23964
|
+
function arrayParts(type) {
|
|
23965
|
+
const open = type.indexOf("[");
|
|
23966
|
+
if (open < 0 || !type.endsWith("]")) return [type, 0];
|
|
23967
|
+
const length = Number(type.slice(open + 1, -1));
|
|
23968
|
+
return Number.isInteger(length) && length > 0 ? [type.slice(0, open), length] : [type, 0];
|
|
23969
|
+
}
|
|
23970
|
+
function flatten(param, structs, stack = []) {
|
|
23971
|
+
if (!isNamed(param)) fail("parameter needs a name and a type");
|
|
23972
|
+
if (Object.hasOwn(NATIVE_STRUCTS, param.type)) {
|
|
23973
|
+
return NATIVE_STRUCTS[param.type].map(([field, type]) => ({
|
|
23974
|
+
name: `${param.name}.${field}`,
|
|
23975
|
+
type: argType(type)
|
|
23976
|
+
}));
|
|
23977
|
+
}
|
|
23978
|
+
const declared = structs.find((struct) => struct?.name === param.type);
|
|
23979
|
+
if (declared) {
|
|
23980
|
+
if (stack.includes(param.type)) fail(`recursive struct layout '${param.type}'`);
|
|
23981
|
+
return declared.fields.flatMap(
|
|
23982
|
+
(field) => flatten({ name: `${param.name}.${field.name}`, type: field.type }, structs, [
|
|
23983
|
+
...stack,
|
|
23984
|
+
param.type
|
|
23985
|
+
])
|
|
23986
|
+
);
|
|
23987
|
+
}
|
|
23988
|
+
const [element, length] = arrayParts(param.type);
|
|
23989
|
+
if (length === 0) {
|
|
23990
|
+
if (param.type.includes("[") || param.type.includes("]")) {
|
|
23991
|
+
fail(`invalid array type '${param.type}'`);
|
|
23992
|
+
}
|
|
23993
|
+
return [{ name: param.name, type: argType(param.type) }];
|
|
23994
|
+
}
|
|
23995
|
+
if (Object.hasOwn(NATIVE_STRUCTS, element) || structs.some((struct) => struct.name === element)) {
|
|
23996
|
+
fail(`arrays of structs are not supported: '${param.type}'`);
|
|
23997
|
+
}
|
|
23998
|
+
return Array.from({ length }, (_, index) => ({
|
|
23999
|
+
name: `${param.name}.${index}`,
|
|
24000
|
+
type: argType(element)
|
|
24001
|
+
}));
|
|
24002
|
+
}
|
|
24003
|
+
function opcodeToken(token) {
|
|
24004
|
+
const base = token.slice(3);
|
|
24005
|
+
const name = base === "0" || /^([1-9]|1[0-6])$/.test(base) ? token : base;
|
|
24006
|
+
if (!Object.hasOwn(ARKADE_OPS, name)) {
|
|
24007
|
+
fail(`opcode '${token}' is not in this SDK's table`);
|
|
24008
|
+
}
|
|
24009
|
+
return name;
|
|
24010
|
+
}
|
|
24011
|
+
function instantiationParam(body) {
|
|
24012
|
+
return `contract_${body.replace(/[^A-Za-z0-9]+/g, "_")}`.replace(/_+$/, "");
|
|
24013
|
+
}
|
|
24014
|
+
function asmToken(token, instantiations) {
|
|
24015
|
+
if (token.startsWith("OP_")) return opcodeToken(token);
|
|
24016
|
+
if (token.startsWith("<") && token.endsWith(">")) {
|
|
24017
|
+
const inner = token.slice(1, -1);
|
|
24018
|
+
if (inner.startsWith("CONTRACT:")) {
|
|
24019
|
+
const body = inner.slice("CONTRACT:".length);
|
|
24020
|
+
const name = instantiationParam(body);
|
|
24021
|
+
const seen = instantiations.get(name);
|
|
24022
|
+
if (seen !== void 0 && seen !== body) {
|
|
24023
|
+
fail(`instantiations '${seen}' and '${body}' both map to parameter '${name}'`);
|
|
24024
|
+
}
|
|
24025
|
+
instantiations.set(name, body);
|
|
24026
|
+
return `$${name}`;
|
|
24027
|
+
}
|
|
24028
|
+
if (inner.startsWith("VTXO:")) {
|
|
24029
|
+
fail(`'${token}' is not a placeholder; the compiler emits <CONTRACT:\u2026>`);
|
|
24030
|
+
}
|
|
24031
|
+
if (inner === "SERVER_KEY" || inner.startsWith("EMULATOR_KEY:")) {
|
|
24032
|
+
fail(`${token} is a signer role and cannot appear in a covenant`);
|
|
24033
|
+
}
|
|
24034
|
+
return `$${inner}`;
|
|
24035
|
+
}
|
|
24036
|
+
if (token.startsWith("0x")) return hex.decode(token.slice(2));
|
|
24037
|
+
try {
|
|
24038
|
+
return BigInt(token);
|
|
24039
|
+
} catch {
|
|
24040
|
+
fail(`unrecognized assembly token '${token}'`);
|
|
24041
|
+
}
|
|
24042
|
+
}
|
|
24043
|
+
function providedWitness(witness) {
|
|
24044
|
+
if (witness === void 0) return [];
|
|
24045
|
+
if (!Array.isArray(witness)) fail("leaf witness must be an array");
|
|
24046
|
+
return witness.filter((item) => {
|
|
24047
|
+
if (!isNamed(item)) fail("witness item needs a name and a type");
|
|
24048
|
+
return !item.injected && item.type !== "signature";
|
|
24049
|
+
});
|
|
24050
|
+
}
|
|
24051
|
+
function parseLeaf(leaf, hasCovenant, instantiations, extras) {
|
|
24052
|
+
const asm = leaf.asm;
|
|
24053
|
+
let index = 0;
|
|
24054
|
+
let condition;
|
|
24055
|
+
if (asm.length >= 4 && HASH_OPCODES.has(asm[0]) && asm[2] === "OP_EQUAL") {
|
|
24056
|
+
if (asm[3] !== "OP_VERIFY")
|
|
24057
|
+
fail(`leaf '${leaf.name}': hash condition must end in OP_VERIFY`);
|
|
24058
|
+
condition = asm.slice(0, 3).map((token) => asmToken(token, instantiations));
|
|
24059
|
+
index = 4;
|
|
24060
|
+
}
|
|
24061
|
+
let csv;
|
|
24062
|
+
let cltv;
|
|
24063
|
+
if (asm.length >= index + 3 && asm[index + 2] === "OP_DROP") {
|
|
24064
|
+
const operand = asm[index].startsWith("<") && asm[index].endsWith(">") ? `$${asm[index].slice(1, -1)}` : BigInt(asm[index]);
|
|
24065
|
+
if (asm[index + 1] === "OP_CHECKSEQUENCEVERIFY") csv = { type: "blocks", value: operand };
|
|
24066
|
+
else if (asm[index + 1] === "OP_CHECKLOCKTIMEVERIFY") cltv = operand;
|
|
24067
|
+
else fail(`leaf '${leaf.name}': unexpected timelock opcode ${asm[index + 1]}`);
|
|
24068
|
+
index += 3;
|
|
24069
|
+
}
|
|
24070
|
+
const signers = [];
|
|
24071
|
+
let emulator;
|
|
24072
|
+
while (index < asm.length) {
|
|
24073
|
+
const key = asm[index];
|
|
24074
|
+
const terminator = asm[index + 1];
|
|
24075
|
+
const last = terminator === "OP_CHECKSIG";
|
|
24076
|
+
if (!last && terminator !== "OP_CHECKSIGVERIFY") {
|
|
24077
|
+
fail(`leaf '${leaf.name}': expected CHECKSIG after '${key}', found '${terminator}'`);
|
|
24078
|
+
}
|
|
24079
|
+
if (!key.startsWith("<") || !key.endsWith(">")) {
|
|
24080
|
+
fail(`leaf '${leaf.name}': unsupported key operand '${key}'`);
|
|
24081
|
+
}
|
|
24082
|
+
const inner = key.slice(1, -1);
|
|
24083
|
+
if (inner === "SERVER_KEY") signers.push("$server");
|
|
24084
|
+
else if (inner.startsWith("TWEAK:")) {
|
|
24085
|
+
const [, base, fn] = inner.match(/^TWEAK:([^:]+):([^:]+)$/) ?? [];
|
|
24086
|
+
if (!base || !fn) fail(`leaf '${leaf.name}': malformed tweak '${key}'`);
|
|
24087
|
+
signers.push({ tweak: `$${base}`, fn });
|
|
24088
|
+
} else if (inner.startsWith("EMULATOR_KEY:")) {
|
|
24089
|
+
if (!hasCovenant) fail(`leaf '${leaf.name}': ${key} needs a covenant`);
|
|
24090
|
+
if (!last) fail(`leaf '${leaf.name}': ${key} must be the last signer`);
|
|
24091
|
+
emulator = inner.slice("EMULATOR_KEY:".length);
|
|
24092
|
+
} else signers.push(`$${inner}`);
|
|
24093
|
+
index += 2;
|
|
24094
|
+
}
|
|
24095
|
+
const constructorTweak = signers.some((signer) => typeof signer !== "string");
|
|
24096
|
+
if (hasCovenant && emulator === void 0 && !constructorTweak) {
|
|
24097
|
+
fail(
|
|
24098
|
+
`leaf '${leaf.name}': covenant leaf must sign with the emulator or a tweaked constructor key`
|
|
24099
|
+
);
|
|
24100
|
+
}
|
|
24101
|
+
if (signers.length === 0) fail(`leaf '${leaf.name}': at least one named signer is required`);
|
|
24102
|
+
return {
|
|
24103
|
+
signers,
|
|
24104
|
+
...emulator !== void 0 ? { emulator } : hasCovenant ? { emulator: null } : {},
|
|
24105
|
+
...condition ? { asm: condition } : {},
|
|
24106
|
+
...csv ? { csv } : {},
|
|
24107
|
+
...cltv !== void 0 ? { cltv } : {},
|
|
24108
|
+
...extras.length > 0 ? { witness: extras.map((item) => item.name) } : {}
|
|
24109
|
+
};
|
|
24110
|
+
}
|
|
24111
|
+
function programFromArtifact(artifact) {
|
|
24112
|
+
if (!isContractArtifact(artifact)) {
|
|
24113
|
+
fail(
|
|
24114
|
+
"expected a complete arkadec artifact with contractName, constructorInputs, and non-empty functions"
|
|
24115
|
+
);
|
|
24116
|
+
}
|
|
24117
|
+
const structs = artifact.structs ?? [];
|
|
24118
|
+
const structNames = /* @__PURE__ */ new Set();
|
|
24119
|
+
for (const struct of structs) {
|
|
24120
|
+
if (!isRecord(struct) || typeof struct.name !== "string") continue;
|
|
24121
|
+
if (Object.hasOwn(SCALAR_TYPES, struct.name) || Object.hasOwn(NATIVE_STRUCTS, struct.name)) {
|
|
24122
|
+
fail(`struct name '${struct.name}' shadows a built-in type`);
|
|
24123
|
+
}
|
|
24124
|
+
claim(structNames, struct.name, "struct");
|
|
24125
|
+
}
|
|
24126
|
+
const instantiations = /* @__PURE__ */ new Map();
|
|
24127
|
+
const functions = {};
|
|
24128
|
+
const groups = /* @__PURE__ */ new Set();
|
|
24129
|
+
const leafNames = /* @__PURE__ */ new Set();
|
|
24130
|
+
for (const group of artifact.functions) {
|
|
24131
|
+
claim(groups, group.name, "spend group");
|
|
24132
|
+
const covenantInputs = (group.arkade?.inputs ?? []).flatMap(
|
|
24133
|
+
(input) => flatten(input, structs)
|
|
24134
|
+
);
|
|
24135
|
+
const arkadeScript = group.arkade ? {
|
|
24136
|
+
asm: group.arkade.asm.map((token) => asmToken(token, instantiations)),
|
|
24137
|
+
// Covenant witness is reverse declaration order.
|
|
24138
|
+
witness: covenantInputs.map((field) => field.name).reverse()
|
|
24139
|
+
} : void 0;
|
|
24140
|
+
for (const [index, leaf] of group.leaves.entries()) {
|
|
24141
|
+
const name = index === 0 ? group.name : `${group.name}/${index}:${leaf.name}`;
|
|
24142
|
+
claim(leafNames, name, "function name");
|
|
24143
|
+
const extras = providedWitness(leaf.witness);
|
|
24144
|
+
const tapscript = parseLeaf(leaf, group.arkade !== void 0, instantiations, extras);
|
|
24145
|
+
const inputs = [
|
|
24146
|
+
...covenantInputs,
|
|
24147
|
+
...extras.map((item) => ({ name: item.name, type: argType(item.type) }))
|
|
24148
|
+
];
|
|
24149
|
+
functions[name] = {
|
|
24150
|
+
...inputs.length > 0 ? { inputs } : {},
|
|
24151
|
+
tapscript,
|
|
24152
|
+
...arkadeScript ? { arkadeScript } : {}
|
|
24153
|
+
};
|
|
24154
|
+
}
|
|
24155
|
+
}
|
|
24156
|
+
const params = [
|
|
24157
|
+
...artifact.constructorInputs.flatMap((input) => flatten(input, structs)),
|
|
24158
|
+
{ name: "server", type: "pubkey" },
|
|
24159
|
+
...[...instantiations.keys()].map((name) => ({ name, type: "hash" }))
|
|
24160
|
+
];
|
|
24161
|
+
const paramNames = /* @__PURE__ */ new Set();
|
|
24162
|
+
for (const param of params) claim(paramNames, param.name, "program parameter");
|
|
24163
|
+
return {
|
|
24164
|
+
version: SUPPORTED_PROGRAM_VERSION,
|
|
24165
|
+
name: artifact.contractName,
|
|
24166
|
+
params,
|
|
24167
|
+
functions
|
|
24168
|
+
};
|
|
24169
|
+
}
|
|
23713
24170
|
var Arkade = class _Arkade {
|
|
23714
24171
|
arkProvider;
|
|
23715
24172
|
/** The co-signing service, or undefined for emulator-less (pure tapscript) usage. */
|
|
@@ -23922,9 +24379,7 @@ var ArkadeContract = class _ArkadeContract {
|
|
|
23922
24379
|
const [registered] = await manager.getContracts({ script: scriptHex });
|
|
23923
24380
|
if (registered) {
|
|
23924
24381
|
const [withVtxos] = await manager.getContractsWithVtxos({ script: scriptHex });
|
|
23925
|
-
return (withVtxos?.vtxos ?? []).filter(
|
|
23926
|
-
(v) => !hasTerminalSpend(v) && !v.isUnrolled
|
|
23927
|
-
);
|
|
24382
|
+
return (withVtxos?.vtxos ?? []).filter((v) => !isVtxoSpent(v) && !v.isUnrolled);
|
|
23928
24383
|
}
|
|
23929
24384
|
}
|
|
23930
24385
|
if (!this.client.indexer) {
|
|
@@ -23934,7 +24389,7 @@ var ArkadeContract = class _ArkadeContract {
|
|
|
23934
24389
|
scripts: [scriptHex],
|
|
23935
24390
|
spendableOnly: true
|
|
23936
24391
|
});
|
|
23937
|
-
return vtxos.filter((v) => !
|
|
24392
|
+
return vtxos.filter((v) => !isVtxoSpent(v) && !v.isUnrolled);
|
|
23938
24393
|
}
|
|
23939
24394
|
/** Total spendable balance (requires an indexer). */
|
|
23940
24395
|
async getBalance() {
|
|
@@ -24199,6 +24654,7 @@ var BIP21Error = /* @__PURE__ */ ((BIP21Error2) => {
|
|
|
24199
24654
|
BIP21Error2["INVALID_ADDRESS"] = "Invalid address";
|
|
24200
24655
|
return BIP21Error2;
|
|
24201
24656
|
})(BIP21Error || {});
|
|
24657
|
+
var formatAmount = (btc) => btc.toFixed(8).replace(/\.?0+$/, "");
|
|
24202
24658
|
var BIP21 = class _BIP21 {
|
|
24203
24659
|
/**
|
|
24204
24660
|
* Create a BIP21 URI from the provided parameters.
|
|
@@ -24220,7 +24676,7 @@ var BIP21 = class _BIP21 {
|
|
|
24220
24676
|
if (amount < 0) {
|
|
24221
24677
|
continue;
|
|
24222
24678
|
}
|
|
24223
|
-
queryParams[key] =
|
|
24679
|
+
queryParams[key] = formatAmount(amount);
|
|
24224
24680
|
} else if (key === "ark") {
|
|
24225
24681
|
if (typeof value === "string" && (value.startsWith("ark") || value.startsWith("tark"))) {
|
|
24226
24682
|
queryParams[key] = value;
|
|
@@ -24657,6 +25113,6 @@ function createDefaultPaymentRouter(wallet) {
|
|
|
24657
25113
|
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
24658
25114
|
*/
|
|
24659
25115
|
|
|
24660
|
-
export { ARKADE_MAGIC, ARKADE_SALTED_PREIMAGE_TAG, ARKADE_SWAP_PREIMAGE_TAG, ASSET_CARRIER_SATS, AbortError, ActivityRegistry, AmbiguousRouteError, ArkNote, ArkadeCash, ArkadeCashCreateError, AssetManager, BIP21, BIP21Error, BIP322, BLOCKED_UPGRADE_TIMEOUT_MS, Batch, CachingArkProvider, ChainedTxType, ConnectionDisposedError, ContractManager, ContractRepositoryImpl, ContractWatcher,
|
|
24661
|
-
//# sourceMappingURL=chunk-
|
|
24662
|
-
//# sourceMappingURL=chunk-
|
|
25116
|
+
export { ARKADE_MAGIC, ARKADE_SALTED_PREIMAGE_TAG, ARKADE_SWAP_PREIMAGE_TAG, ASSET_CARRIER_SATS, AbortError, ActivityRegistry, AmbiguousRouteError, ArkNote, ArkadeCash, ArkadeCashCreateError, AssetManager, BIP21, BIP21Error, BIP322, BLOCKED_UPGRADE_TIMEOUT_MS, Batch, CachingArkProvider, ChainedTxType, ConnectionDisposedError, ContractManager, ContractRepositoryImpl, ContractWatcher, 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, OversizedChangeError, 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, arkAssetRail, arkRail, arkTarget, arkade_exports, assertFinalCommitmentMatchesValidated, assertIntentIdUnique, assertNoAssets, assertNoSelection, assertSendableAmount, assertSubmittedArkTxid, assertValidBatchExpiry, assertValidServerUnrollScript, assetMintResolver, assetsOf, 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, isContractVtxoEvent, 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, registerWalletRestoreHook, requiresMigration, resolveAssetAmount, resolveBatchExpiryPolicy, resolveCheckpointExitDelayPolicy, resolveDescriptorSigner, resolvePrevTxs, resolveSendAmount, rollbackMigration, saveVtxosForContract, scriptFromArkAddress, selectCoinsWithAsset, selectVirtualCoins, selectionOf, serializeAssets, serializeExitPackage, serializeUtxo, serializeVtxo, setupServiceWorker, signAndSubmitOffchainTx, signerSetFromInfo, signingDescriptorIndex, strictSigningDescriptorIndex, toXOnlySignerHex, tryResolveSendAmount, validateBatchRecipients, validateConnectorsTxGraph, validateVtxoTxGraph, verifyTapscriptSignatures, waitForIncomingFunds, walletFeeSource, warnAndFilterVtxosForScript, withPrevTxs };
|
|
25117
|
+
//# sourceMappingURL=chunk-MLOZHTBN.js.map
|
|
25118
|
+
//# sourceMappingURL=chunk-MLOZHTBN.js.map
|