@arkade-os/sdk 0.4.60 → 0.4.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/adapters/expo.cjs +5 -5
  2. package/dist/adapters/expo.d.cts +4 -4
  3. package/dist/adapters/expo.d.ts +4 -4
  4. package/dist/adapters/expo.js +3 -3
  5. package/dist/adapters/indexedDB.cjs +5 -5
  6. package/dist/adapters/indexedDB.js +4 -4
  7. package/dist/{asyncStorageTaskQueue-CqijAAPG.d.cts → asyncStorageTaskQueue-B53mOTCw.d.cts} +2 -2
  8. package/dist/{asyncStorageTaskQueue-Vsp6uk8e.d.ts → asyncStorageTaskQueue-Df-CTfTE.d.ts} +2 -2
  9. package/dist/{chunk-Y54MUBT7.js → chunk-2IZW6AEK.js} +879 -146
  10. package/dist/chunk-2IZW6AEK.js.map +1 -0
  11. package/dist/{chunk-MZNLCMUP.cjs → chunk-G53HASDV.cjs} +113 -79
  12. package/dist/chunk-G53HASDV.cjs.map +1 -0
  13. package/dist/{chunk-3Q7BBUWO.js → chunk-H2ZAJOQA.js} +4 -4
  14. package/dist/{chunk-3Q7BBUWO.js.map → chunk-H2ZAJOQA.js.map} +1 -1
  15. package/dist/{chunk-PRFL62ID.cjs → chunk-I6EDUE75.cjs} +17 -17
  16. package/dist/{chunk-PRFL62ID.cjs.map → chunk-I6EDUE75.cjs.map} +1 -1
  17. package/dist/{chunk-B66RYHTB.js → chunk-I7RLG6VX.js} +4 -4
  18. package/dist/{chunk-B66RYHTB.js.map → chunk-I7RLG6VX.js.map} +1 -1
  19. package/dist/{chunk-2DINXHGQ.js → chunk-L7S5KC5B.js} +66 -35
  20. package/dist/chunk-L7S5KC5B.js.map +1 -0
  21. package/dist/{chunk-4A4GRSTB.cjs → chunk-OH2XLTXE.cjs} +3 -3
  22. package/dist/{chunk-4A4GRSTB.cjs.map → chunk-OH2XLTXE.cjs.map} +1 -1
  23. package/dist/{chunk-2XLNQHG4.cjs → chunk-PWWA4DBL.cjs} +10 -10
  24. package/dist/{chunk-2XLNQHG4.cjs.map → chunk-PWWA4DBL.cjs.map} +1 -1
  25. package/dist/{chunk-H7JCHFM6.cjs → chunk-QRSR4HV4.cjs} +17 -17
  26. package/dist/{chunk-H7JCHFM6.cjs.map → chunk-QRSR4HV4.cjs.map} +1 -1
  27. package/dist/{chunk-FSKANUV4.js → chunk-RMBI6P4N.js} +3 -3
  28. package/dist/{chunk-FSKANUV4.js.map → chunk-RMBI6P4N.js.map} +1 -1
  29. package/dist/{chunk-JBULXTCC.js → chunk-URT2RVGB.js} +3 -3
  30. package/dist/{chunk-JBULXTCC.js.map → chunk-URT2RVGB.js.map} +1 -1
  31. package/dist/{chunk-KNS5MTTI.cjs → chunk-Z2OZMKFV.cjs} +1272 -523
  32. package/dist/chunk-Z2OZMKFV.cjs.map +1 -0
  33. package/dist/contracts/handlers/index.cjs +9 -9
  34. package/dist/contracts/handlers/index.d.cts +5 -5
  35. package/dist/contracts/handlers/index.d.ts +5 -5
  36. package/dist/contracts/handlers/index.js +2 -2
  37. package/dist/{delegate-DNEuM_nK.d.cts → delegate-BjYJJsml.d.ts} +1 -1
  38. package/dist/{delegate-DidNTsKm.d.ts → delegate-CC1gcvuC.d.cts} +1 -1
  39. package/dist/{index-BP8-zniX.d.cts → index-C888wFEV.d.ts} +102 -102
  40. package/dist/{ark-D2_yNhfz.d.cts → index-CwBr7qzV.d.cts} +3941 -3812
  41. package/dist/{ark-D2_yNhfz.d.ts → index-CwBr7qzV.d.ts} +3941 -3812
  42. package/dist/{index-DzQbNQUG.d.ts → index-Cz5_WaQP.d.cts} +102 -102
  43. package/dist/index.cjs +328 -248
  44. package/dist/index.d.cts +340 -52
  45. package/dist/index.d.ts +340 -52
  46. package/dist/index.js +4 -4
  47. package/dist/repositories/realm/index.cjs +19 -19
  48. package/dist/repositories/realm/index.d.cts +4 -4
  49. package/dist/repositories/realm/index.d.ts +4 -4
  50. package/dist/repositories/realm/index.js +5 -5
  51. package/dist/repositories/sqlite/index.cjs +18 -18
  52. package/dist/repositories/sqlite/index.d.cts +4 -4
  53. package/dist/repositories/sqlite/index.d.ts +4 -4
  54. package/dist/repositories/sqlite/index.js +5 -5
  55. package/dist/{taskRunner-9gnlYEpb.d.ts → taskRunner-BMUndClz.d.cts} +2 -2
  56. package/dist/{taskRunner-BEQNFEa4.d.cts → taskRunner-DZWUsSzA.d.ts} +2 -2
  57. package/dist/wallet/expo/background.cjs +14 -14
  58. package/dist/wallet/expo/background.d.cts +5 -5
  59. package/dist/wallet/expo/background.d.ts +5 -5
  60. package/dist/wallet/expo/background.js +6 -6
  61. package/dist/wallet/expo/index.cjs +36 -16
  62. package/dist/wallet/expo/index.cjs.map +1 -1
  63. package/dist/wallet/expo/index.d.cts +13 -6
  64. package/dist/wallet/expo/index.d.ts +13 -6
  65. package/dist/wallet/expo/index.js +27 -7
  66. package/dist/wallet/expo/index.js.map +1 -1
  67. package/dist/{wallet-ipUA1XCp.d.cts → wallet-Dpjx6CJ7.d.ts} +91 -17
  68. package/dist/{wallet-C_MYHyOj.d.ts → wallet-H3f14est.d.cts} +91 -17
  69. package/dist/worker/expo/index.cjs +9 -9
  70. package/dist/worker/expo/index.d.cts +6 -6
  71. package/dist/worker/expo/index.d.ts +6 -6
  72. package/dist/worker/expo/index.js +5 -5
  73. package/package.json +1 -1
  74. package/dist/chunk-2DINXHGQ.js.map +0 -1
  75. package/dist/chunk-KNS5MTTI.cjs.map +0 -1
  76. package/dist/chunk-MZNLCMUP.cjs.map +0 -1
  77. package/dist/chunk-Y54MUBT7.js.map +0 -1
@@ -1,8 +1,8 @@
1
- import { AssetId, AssetGroup, AssetInput, AssetOutput, Metadata, Packet, BufferReader, BufferWriter, AssetRef, RestIndexerProvider } from './chunk-FSKANUV4.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, inputName, contractHandlers, isMainnetDescriptor, descriptorIsOurs, deriveDescriptorLeafPubKey, deriveDescriptorLeafCompressedPubKey, DefaultVtxo, speculativeReceiveMetadata, DelegateVtxo, WALLET_RECEIVE_SOURCE, BoardingContractHandler } from './chunk-2DINXHGQ.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, 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, resolveTimeHeight, canSpendOffchain, parseLegacyExpiry, isExpired, DEFAULT_ARKADE_SERVER_URL, ProviderUnavailableError, networks as networks$1, isPastExpiry, fetchVtxoCreatedAtByTxid } from './chunk-JBULXTCC.js';
1
+ import { AssetId, AssetGroup, AssetInput, AssetOutput, Metadata, Packet, BufferReader, BufferWriter, AssetRef, RestIndexerProvider } from './chunk-RMBI6P4N.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, inputName, contractHandlers, isMainnetDescriptor, descriptorIsOurs, deriveDescriptorLeafPubKey, deriveDescriptorLeafCompressedPubKey, parseHDDescriptor, DefaultVtxo, speculativeReceiveMetadata, DelegateVtxo, WALLET_RECEIVE_SOURCE, BoardingContractHandler, identityDescriptor } from './chunk-L7S5KC5B.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, sequenceToTimelock, decodeTapscript, scriptFromTapLeafScript, CLTVMultisigTapscript, VtxoTaprootTree, timelockToSequence, baseFetch, Intent, rateGate, DEFAULT_NETWORK_NAME, normalizeVtxo, getSequence, toBatchExpiry, maybeArkError, isArkError, ArkErrorName, toOffchainInputFeeParams, canRecoverOnchain, getNetwork, MultisigTapscript, isEventSourceError, isEventSourceUnavailableError, isRetryableProviderError, getAllNormalizedVtxos, DEFAULT_PAGE_SIZE, RestArkProvider, toVirtualStatus, ArkError, TapTreeCoder, resolveTimeHeight, canSpendOffchain, parseLegacyExpiry, isExpired, DEFAULT_ARKADE_SERVER_URL, ProviderUnavailableError, networks as networks$1, isPastExpiry, fetchVtxoCreatedAtByTxid } from './chunk-URT2RVGB.js';
4
4
  import { __export } from './chunk-NSBPE2FW.js';
5
- import { sha256, equalBytes, hash160, sha256x2, concatBytes, randomPrivateKeyBytes, pubECDSA, pubSchnorr } from '@scure/btc-signer/utils.js';
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';
7
7
  import { hex, base58, base64, bech32m } from '@scure/base';
8
8
  import * as musig2 from '@scure/btc-signer/musig2.js';
@@ -332,6 +332,18 @@ var SingleKey = class _SingleKey {
332
332
  if (signatureType === "ecdsa") return signAsync(message, this.key, { prehash: false });
333
333
  return schnorr$1.signAsync(message, this.key);
334
334
  }
335
+ /**
336
+ * BIP-340 sign `messageHash` with aux_rand = 0, so the signature — and
337
+ * anything derived from it — is reproducible from the key alone.
338
+ *
339
+ * What lets a static wallet derive a swap preimage instead of storing one
340
+ * (see `wallet/contractSecrets.ts`). Deliberately NOT `signMessage`, whose
341
+ * schnorr branch draws a random aux_rand: a preimage derived from that is
342
+ * unrecoverable, and the loss would only surface at claim time.
343
+ */
344
+ async signSchnorrDeterministic(messageHash) {
345
+ return schnorr$1.signAsync(messageHash, this.key, new Uint8Array(32));
346
+ }
335
347
  async toReadonly() {
336
348
  return new ReadonlySingleKey(await this.compressedPublicKey());
337
349
  }
@@ -461,6 +473,19 @@ var SeedIdentity = class _SeedIdentity {
461
473
  async signMessage(message, signatureType = "schnorr") {
462
474
  return this.signMessageWithKey(this.derivedKey, message, signatureType);
463
475
  }
476
+ /**
477
+ * BIP-340 sign `messageHash` with this identity's own key, aux_rand = 0.
478
+ *
479
+ * The descriptor-less sibling of
480
+ * {@link signSchnorrDeterministicWithDescriptor}, for an `auto`-mode wallet
481
+ * whose bare `tr(pubkey)` resolves to the identity itself rather than to a
482
+ * {@link DescriptorIdentity}. Deliberately NOT routed through
483
+ * `signMessage`, whose schnorr branch draws a random aux_rand and would
484
+ * make the "deterministic" signature unreproducible.
485
+ */
486
+ async signSchnorrDeterministic(messageHash) {
487
+ return schnorr$1.signAsync(messageHash, this.derivedKey, new Uint8Array(32));
488
+ }
464
489
  signerSession() {
465
490
  return TreeSignerSession.random();
466
491
  }
@@ -879,8 +904,33 @@ function isHDCapableIdentity(value) {
879
904
  function isBatchSignable(identity) {
880
905
  return "signMultiple" in identity && typeof identity.signMultiple === "function";
881
906
  }
882
-
883
- // src/wallet/hdWalletCapable.ts
907
+ function isSigningIdentity(value) {
908
+ if (typeof value !== "object" || value === null) return false;
909
+ const v = value;
910
+ return typeof v.sign === "function" && typeof v.signMessage === "function" && typeof v.signerSession === "function" && typeof v.xOnlyPublicKey === "function";
911
+ }
912
+ var ForeignDescriptorError = class extends Error {
913
+ constructor(descriptor, options) {
914
+ super(`this wallet holds no key for descriptor: ${descriptor}`, options);
915
+ this.descriptor = descriptor;
916
+ }
917
+ descriptor;
918
+ name = "ForeignDescriptorError";
919
+ };
920
+ async function resolveDescriptorSigner(descriptor, identity, provider) {
921
+ const owner = provider?.isOurs(descriptor) ? provider : isHDCapableIdentity(identity) && identity.isOurs(descriptor) ? identity : void 0;
922
+ if (owner && parseHDDescriptor(descriptor)) {
923
+ return new DescriptorIdentity({ descriptor, signer: owner, base: identity });
924
+ }
925
+ let key;
926
+ try {
927
+ key = deriveDescriptorLeafPubKey(descriptor);
928
+ } catch {
929
+ throw new ForeignDescriptorError(descriptor);
930
+ }
931
+ if (equalBytes(await identity.xOnlyPublicKey(), key)) return identity;
932
+ throw new ForeignDescriptorError(descriptor);
933
+ }
884
934
  function isHDWalletCapable(value) {
885
935
  if (typeof value !== "object" || value === null) return false;
886
936
  const v = value;
@@ -892,6 +942,478 @@ function isHDAllocationCapable(value) {
892
942
  return typeof v.getNextSigningDescriptor === "function" && typeof v.advanceSigningDescriptorWatermark === "function";
893
943
  }
894
944
 
945
+ // ../../node_modules/@noble/hashes/utils.js
946
+ function isBytes(a) {
947
+ return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
948
+ }
949
+ function abytes(value, length, title = "") {
950
+ const bytes = isBytes(value);
951
+ const len = value?.length;
952
+ const needsLen = length !== void 0;
953
+ if (!bytes || needsLen) {
954
+ const prefix = title && `"${title}" `;
955
+ const ofLen = "";
956
+ const got = bytes ? `length=${len}` : `type=${typeof value}`;
957
+ throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
958
+ }
959
+ return value;
960
+ }
961
+ function aexists(instance, checkFinished = true) {
962
+ if (instance.destroyed)
963
+ throw new Error("Hash instance has been destroyed");
964
+ if (checkFinished && instance.finished)
965
+ throw new Error("Hash#digest() has already been called");
966
+ }
967
+ function aoutput(out, instance) {
968
+ abytes(out, void 0, "digestInto() output");
969
+ const min = instance.outputLen;
970
+ if (out.length < min) {
971
+ throw new Error('"digestInto() output" expected to be of length >=' + min);
972
+ }
973
+ }
974
+ function clean(...arrays) {
975
+ for (let i = 0; i < arrays.length; i++) {
976
+ arrays[i].fill(0);
977
+ }
978
+ }
979
+ function createView(arr) {
980
+ return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
981
+ }
982
+ function rotr(word, shift) {
983
+ return word << 32 - shift | word >>> shift;
984
+ }
985
+ function createHasher(hashCons, info = {}) {
986
+ const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
987
+ const tmp = hashCons(void 0);
988
+ hashC.outputLen = tmp.outputLen;
989
+ hashC.blockLen = tmp.blockLen;
990
+ hashC.create = (opts) => hashCons(opts);
991
+ Object.assign(hashC, info);
992
+ return Object.freeze(hashC);
993
+ }
994
+ function randomBytes(bytesLength = 32) {
995
+ const cr = typeof globalThis === "object" ? globalThis.crypto : null;
996
+ if (typeof cr?.getRandomValues !== "function")
997
+ throw new Error("crypto.getRandomValues must be defined");
998
+ return cr.getRandomValues(new Uint8Array(bytesLength));
999
+ }
1000
+ var oidNist = (suffix) => ({
1001
+ oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
1002
+ });
1003
+
1004
+ // ../../node_modules/@noble/hashes/_md.js
1005
+ function Chi(a, b, c) {
1006
+ return a & b ^ ~a & c;
1007
+ }
1008
+ function Maj(a, b, c) {
1009
+ return a & b ^ a & c ^ b & c;
1010
+ }
1011
+ var HashMD = class {
1012
+ blockLen;
1013
+ outputLen;
1014
+ padOffset;
1015
+ isLE;
1016
+ // For partial updates less than block size
1017
+ buffer;
1018
+ view;
1019
+ finished = false;
1020
+ length = 0;
1021
+ pos = 0;
1022
+ destroyed = false;
1023
+ constructor(blockLen, outputLen, padOffset, isLE) {
1024
+ this.blockLen = blockLen;
1025
+ this.outputLen = outputLen;
1026
+ this.padOffset = padOffset;
1027
+ this.isLE = isLE;
1028
+ this.buffer = new Uint8Array(blockLen);
1029
+ this.view = createView(this.buffer);
1030
+ }
1031
+ update(data) {
1032
+ aexists(this);
1033
+ abytes(data);
1034
+ const { view, buffer, blockLen } = this;
1035
+ const len = data.length;
1036
+ for (let pos = 0; pos < len; ) {
1037
+ const take = Math.min(blockLen - this.pos, len - pos);
1038
+ if (take === blockLen) {
1039
+ const dataView = createView(data);
1040
+ for (; blockLen <= len - pos; pos += blockLen)
1041
+ this.process(dataView, pos);
1042
+ continue;
1043
+ }
1044
+ buffer.set(data.subarray(pos, pos + take), this.pos);
1045
+ this.pos += take;
1046
+ pos += take;
1047
+ if (this.pos === blockLen) {
1048
+ this.process(view, 0);
1049
+ this.pos = 0;
1050
+ }
1051
+ }
1052
+ this.length += data.length;
1053
+ this.roundClean();
1054
+ return this;
1055
+ }
1056
+ digestInto(out) {
1057
+ aexists(this);
1058
+ aoutput(out, this);
1059
+ this.finished = true;
1060
+ const { buffer, view, blockLen, isLE } = this;
1061
+ let { pos } = this;
1062
+ buffer[pos++] = 128;
1063
+ clean(this.buffer.subarray(pos));
1064
+ if (this.padOffset > blockLen - pos) {
1065
+ this.process(view, 0);
1066
+ pos = 0;
1067
+ }
1068
+ for (let i = pos; i < blockLen; i++)
1069
+ buffer[i] = 0;
1070
+ view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
1071
+ this.process(view, 0);
1072
+ const oview = createView(out);
1073
+ const len = this.outputLen;
1074
+ if (len % 4)
1075
+ throw new Error("_sha2: outputLen must be aligned to 32bit");
1076
+ const outLen = len / 4;
1077
+ const state = this.get();
1078
+ if (outLen > state.length)
1079
+ throw new Error("_sha2: outputLen bigger than state");
1080
+ for (let i = 0; i < outLen; i++)
1081
+ oview.setUint32(4 * i, state[i], isLE);
1082
+ }
1083
+ digest() {
1084
+ const { buffer, outputLen } = this;
1085
+ this.digestInto(buffer);
1086
+ const res = buffer.slice(0, outputLen);
1087
+ this.destroy();
1088
+ return res;
1089
+ }
1090
+ _cloneInto(to) {
1091
+ to ||= new this.constructor();
1092
+ to.set(...this.get());
1093
+ const { blockLen, buffer, length, finished, destroyed, pos } = this;
1094
+ to.destroyed = destroyed;
1095
+ to.finished = finished;
1096
+ to.length = length;
1097
+ to.pos = pos;
1098
+ if (length % blockLen)
1099
+ to.buffer.set(buffer);
1100
+ return to;
1101
+ }
1102
+ clone() {
1103
+ return this._cloneInto();
1104
+ }
1105
+ };
1106
+ var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
1107
+ 1779033703,
1108
+ 3144134277,
1109
+ 1013904242,
1110
+ 2773480762,
1111
+ 1359893119,
1112
+ 2600822924,
1113
+ 528734635,
1114
+ 1541459225
1115
+ ]);
1116
+
1117
+ // ../../node_modules/@noble/hashes/sha2.js
1118
+ var SHA256_K = /* @__PURE__ */ Uint32Array.from([
1119
+ 1116352408,
1120
+ 1899447441,
1121
+ 3049323471,
1122
+ 3921009573,
1123
+ 961987163,
1124
+ 1508970993,
1125
+ 2453635748,
1126
+ 2870763221,
1127
+ 3624381080,
1128
+ 310598401,
1129
+ 607225278,
1130
+ 1426881987,
1131
+ 1925078388,
1132
+ 2162078206,
1133
+ 2614888103,
1134
+ 3248222580,
1135
+ 3835390401,
1136
+ 4022224774,
1137
+ 264347078,
1138
+ 604807628,
1139
+ 770255983,
1140
+ 1249150122,
1141
+ 1555081692,
1142
+ 1996064986,
1143
+ 2554220882,
1144
+ 2821834349,
1145
+ 2952996808,
1146
+ 3210313671,
1147
+ 3336571891,
1148
+ 3584528711,
1149
+ 113926993,
1150
+ 338241895,
1151
+ 666307205,
1152
+ 773529912,
1153
+ 1294757372,
1154
+ 1396182291,
1155
+ 1695183700,
1156
+ 1986661051,
1157
+ 2177026350,
1158
+ 2456956037,
1159
+ 2730485921,
1160
+ 2820302411,
1161
+ 3259730800,
1162
+ 3345764771,
1163
+ 3516065817,
1164
+ 3600352804,
1165
+ 4094571909,
1166
+ 275423344,
1167
+ 430227734,
1168
+ 506948616,
1169
+ 659060556,
1170
+ 883997877,
1171
+ 958139571,
1172
+ 1322822218,
1173
+ 1537002063,
1174
+ 1747873779,
1175
+ 1955562222,
1176
+ 2024104815,
1177
+ 2227730452,
1178
+ 2361852424,
1179
+ 2428436474,
1180
+ 2756734187,
1181
+ 3204031479,
1182
+ 3329325298
1183
+ ]);
1184
+ var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
1185
+ var SHA2_32B = class extends HashMD {
1186
+ constructor(outputLen) {
1187
+ super(64, outputLen, 8, false);
1188
+ }
1189
+ get() {
1190
+ const { A, B, C, D, E, F, G, H } = this;
1191
+ return [A, B, C, D, E, F, G, H];
1192
+ }
1193
+ // prettier-ignore
1194
+ set(A, B, C, D, E, F, G, H) {
1195
+ this.A = A | 0;
1196
+ this.B = B | 0;
1197
+ this.C = C | 0;
1198
+ this.D = D | 0;
1199
+ this.E = E | 0;
1200
+ this.F = F | 0;
1201
+ this.G = G | 0;
1202
+ this.H = H | 0;
1203
+ }
1204
+ process(view, offset) {
1205
+ for (let i = 0; i < 16; i++, offset += 4)
1206
+ SHA256_W[i] = view.getUint32(offset, false);
1207
+ for (let i = 16; i < 64; i++) {
1208
+ const W15 = SHA256_W[i - 15];
1209
+ const W2 = SHA256_W[i - 2];
1210
+ const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
1211
+ const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
1212
+ SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
1213
+ }
1214
+ let { A, B, C, D, E, F, G, H } = this;
1215
+ for (let i = 0; i < 64; i++) {
1216
+ const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
1217
+ const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
1218
+ const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
1219
+ const T2 = sigma0 + Maj(A, B, C) | 0;
1220
+ H = G;
1221
+ G = F;
1222
+ F = E;
1223
+ E = D + T1 | 0;
1224
+ D = C;
1225
+ C = B;
1226
+ B = A;
1227
+ A = T1 + T2 | 0;
1228
+ }
1229
+ A = A + this.A | 0;
1230
+ B = B + this.B | 0;
1231
+ C = C + this.C | 0;
1232
+ D = D + this.D | 0;
1233
+ E = E + this.E | 0;
1234
+ F = F + this.F | 0;
1235
+ G = G + this.G | 0;
1236
+ H = H + this.H | 0;
1237
+ this.set(A, B, C, D, E, F, G, H);
1238
+ }
1239
+ roundClean() {
1240
+ clean(SHA256_W);
1241
+ }
1242
+ destroy() {
1243
+ this.set(0, 0, 0, 0, 0, 0, 0, 0);
1244
+ clean(this.buffer);
1245
+ }
1246
+ };
1247
+ var _SHA256 = class extends SHA2_32B {
1248
+ // We cannot use array here since array allows indexing by variable
1249
+ // which means optimizer/compiler cannot use registers.
1250
+ A = SHA256_IV[0] | 0;
1251
+ B = SHA256_IV[1] | 0;
1252
+ C = SHA256_IV[2] | 0;
1253
+ D = SHA256_IV[3] | 0;
1254
+ E = SHA256_IV[4] | 0;
1255
+ F = SHA256_IV[5] | 0;
1256
+ G = SHA256_IV[6] | 0;
1257
+ H = SHA256_IV[7] | 0;
1258
+ constructor() {
1259
+ super(32);
1260
+ }
1261
+ };
1262
+ var sha256 = /* @__PURE__ */ createHasher(
1263
+ () => new _SHA256(),
1264
+ /* @__PURE__ */ oidNist(1)
1265
+ );
1266
+ var ARKADE_SWAP_PREIMAGE_TAG = "Arkade-RFQ-Preimage-v1";
1267
+ var ARKADE_SALTED_PREIMAGE_TAG = "Arkade-Contract-Preimage-Salted-v1";
1268
+ function buildPreimageMessage(xonly, index) {
1269
+ if (xonly.length !== 32) {
1270
+ throw new Error(`x-only pubkey must be 32 bytes, got ${xonly.length}`);
1271
+ }
1272
+ if (!Number.isInteger(index) || index < 0 || index > 4294967295) {
1273
+ throw new Error(`index must be a u32, got ${index}`);
1274
+ }
1275
+ const tag = new TextEncoder().encode(ARKADE_SWAP_PREIMAGE_TAG);
1276
+ const message = new Uint8Array(tag.length + 32 + 4);
1277
+ message.set(tag, 0);
1278
+ message.set(xonly, tag.length);
1279
+ new DataView(message.buffer).setUint32(tag.length + 32, index, true);
1280
+ return message;
1281
+ }
1282
+ function buildSaltedPreimageMessage(xonly, salt) {
1283
+ if (xonly.length !== 32) {
1284
+ throw new Error(`x-only pubkey must be 32 bytes, got ${xonly.length}`);
1285
+ }
1286
+ if (salt.length !== 32) {
1287
+ throw new Error(`preimage salt must be 32 bytes, got ${salt.length}`);
1288
+ }
1289
+ const tag = new TextEncoder().encode(ARKADE_SALTED_PREIMAGE_TAG);
1290
+ const message = new Uint8Array(tag.length + 32 + 32);
1291
+ message.set(tag, 0);
1292
+ message.set(xonly, tag.length);
1293
+ message.set(salt, tag.length + 32);
1294
+ return message;
1295
+ }
1296
+ var PREIMAGE_INDEX = 0;
1297
+ function isPerArtifactDescriptor(descriptor) {
1298
+ return parseHDDescriptor(descriptor) !== null;
1299
+ }
1300
+ async function provisionDescriptor(wallet) {
1301
+ const allocated = isHDAllocationCapable(wallet) ? await wallet.getNextSigningDescriptor() : void 0;
1302
+ return allocated ?? await identityDescriptor(wallet.identity);
1303
+ }
1304
+ async function provisionRefundKey(wallet) {
1305
+ const descriptor = await provisionDescriptor(wallet);
1306
+ const signer = await contractSigner(wallet, descriptor);
1307
+ return { descriptor, pubkey: await signer.xOnlyPublicKey() };
1308
+ }
1309
+ async function provisionClaimSecret(wallet, opts = {}) {
1310
+ if (opts.preimage && opts.preimage.length !== 32) {
1311
+ throw new Error(`preimage must be 32 bytes, got ${opts.preimage.length}`);
1312
+ }
1313
+ const { descriptor, pubkey } = await provisionRefundKey(wallet);
1314
+ const claim = async () => {
1315
+ if (opts.preimage) return { preimage: opts.preimage, mustPersistPreimage: true };
1316
+ if (isPerArtifactDescriptor(descriptor)) {
1317
+ return {
1318
+ preimage: await derivePreimage(wallet, descriptor),
1319
+ mustPersistPreimage: false
1320
+ };
1321
+ }
1322
+ const preimageSalt2 = randomBytes(32);
1323
+ try {
1324
+ return {
1325
+ preimage: await derivePreimage(wallet, descriptor, preimageSalt2),
1326
+ preimageSalt: preimageSalt2,
1327
+ mustPersistPreimage: false
1328
+ };
1329
+ } catch (cause) {
1330
+ if (cause instanceof ForeignDescriptorError || cause instanceof WalletCannotSignError) {
1331
+ throw cause;
1332
+ }
1333
+ return { preimage: randomBytes(32), mustPersistPreimage: true };
1334
+ }
1335
+ };
1336
+ const { preimage, preimageSalt, mustPersistPreimage } = await claim();
1337
+ return {
1338
+ descriptor,
1339
+ pubkey,
1340
+ preimage,
1341
+ paymentHash: sha256(preimage),
1342
+ ...preimageSalt ? { preimageSalt } : {},
1343
+ mustPersistPreimage
1344
+ };
1345
+ }
1346
+ async function contractSigner(wallet, descriptor) {
1347
+ const signer = isHDWalletCapable(wallet) ? await wallet.signerForDescriptor(descriptor) : wallet.identity;
1348
+ let expected;
1349
+ try {
1350
+ expected = deriveDescriptorLeafPubKey(descriptor);
1351
+ } catch (cause) {
1352
+ throw new ForeignDescriptorError(descriptor, { cause });
1353
+ }
1354
+ const actual = await signer.xOnlyPublicKey();
1355
+ if (!equalBytes(actual, expected)) throw new ForeignDescriptorError(descriptor);
1356
+ if (!isSigningIdentity(signer)) throw new WalletCannotSignError(descriptor);
1357
+ return signer;
1358
+ }
1359
+ var WalletCannotSignError = class extends Error {
1360
+ constructor(descriptor) {
1361
+ super(`this wallet holds the key for ${descriptor} but cannot sign with it`);
1362
+ this.descriptor = descriptor;
1363
+ }
1364
+ descriptor;
1365
+ name = "WalletCannotSignError";
1366
+ };
1367
+ async function contractPreimage(wallet, descriptor, opts = {}) {
1368
+ if (opts.stored) {
1369
+ if (opts.stored.length !== 32) {
1370
+ throw new Error(`stored preimage must be 32 bytes, got ${opts.stored.length}`);
1371
+ }
1372
+ return opts.stored;
1373
+ }
1374
+ if (isPerArtifactDescriptor(descriptor)) return derivePreimage(wallet, descriptor);
1375
+ if (opts.salt) return derivePreimage(wallet, descriptor, opts.salt);
1376
+ throw new Error(
1377
+ `descriptor ${descriptor} names no single artifact, so its preimage cannot be derived; no salt and no stored preimage were given`
1378
+ );
1379
+ }
1380
+ function isDeterministicSigner(value) {
1381
+ if (typeof value !== "object" || value === null) return false;
1382
+ const v = value;
1383
+ return typeof v.signSchnorrDeterministic === "function" && typeof v.xOnlyPublicKey === "function";
1384
+ }
1385
+ async function derivePreimage(wallet, descriptor, salt) {
1386
+ const signer = await contractSigner(wallet, descriptor);
1387
+ if (!isDeterministicSigner(signer)) {
1388
+ throw new Error(
1389
+ `wallet cannot sign deterministically for ${descriptor}; its preimage is not derivable`
1390
+ );
1391
+ }
1392
+ const xonly = await signer.xOnlyPublicKey();
1393
+ const message = salt ? buildSaltedPreimageMessage(xonly, salt) : buildPreimageMessage(xonly, PREIMAGE_INDEX);
1394
+ try {
1395
+ return sha256(await signer.signSchnorrDeterministic(sha256(message)));
1396
+ } catch (cause) {
1397
+ throw new Error(
1398
+ `wallet cannot sign deterministically for ${descriptor}; its preimage is not derivable`,
1399
+ { cause }
1400
+ );
1401
+ }
1402
+ }
1403
+ async function adoptContractDescriptor(wallet, descriptor) {
1404
+ if (!isHDAllocationCapable(wallet)) return;
1405
+ if (!isPerArtifactDescriptor(descriptor)) return;
1406
+ if (isHDWalletCapable(wallet)) {
1407
+ try {
1408
+ await wallet.signerForDescriptor(descriptor);
1409
+ } catch (error) {
1410
+ if (error instanceof ForeignDescriptorError) return;
1411
+ throw error;
1412
+ }
1413
+ }
1414
+ await wallet.advanceSigningDescriptorWatermark(descriptor);
1415
+ }
1416
+
895
1417
  // src/worker/browser/service-worker-manager.ts
896
1418
  var registrations = /* @__PURE__ */ new Map();
897
1419
  var handshakes = /* @__PURE__ */ new WeakSet();
@@ -3094,6 +3616,21 @@ function assertRecipientArkAddress(encoded, address, context) {
3094
3616
  );
3095
3617
  }
3096
3618
  }
3619
+ function assertTapTreeDerivesAddress(encoded, tapTree, address) {
3620
+ let derived;
3621
+ try {
3622
+ derived = VtxoScript.decode(tapTree).pkScript;
3623
+ } catch (e) {
3624
+ throw new Error(
3625
+ `Invalid tapTree for ${encoded}: ${e instanceof Error ? e.message : String(e)}`
3626
+ );
3627
+ }
3628
+ if (hex.encode(derived) !== hex.encode(address.pkScript)) {
3629
+ throw new Error(
3630
+ `Invalid tapTree for ${encoded}: derives ${hex.encode(derived)}, address is ${hex.encode(address.pkScript)}. Expected VtxoScript.encode() form: leaf depths are ignored and the tree is rebuilt in arkd's canonical shape.`
3631
+ );
3632
+ }
3633
+ }
3097
3634
  function validateRecipients(recipients, dustAmount, context) {
3098
3635
  const validatedRecipients = [];
3099
3636
  for (const recipient of recipients) {
@@ -3108,16 +3645,58 @@ function validateRecipients(recipients, dustAmount, context) {
3108
3645
  if (amount <= 0) {
3109
3646
  throw new Error("Amount must be positive");
3110
3647
  }
3648
+ if (recipient.tapTree) {
3649
+ assertTapTreeDerivesAddress(recipient.address, recipient.tapTree, address);
3650
+ }
3111
3651
  validatedRecipients.push({
3112
3652
  address: recipient.address,
3113
3653
  assets: recipient.assets ?? [],
3114
3654
  amount,
3115
- script: amount < dustAmount ? address.subdustPkScript : address.pkScript
3655
+ script: amount < dustAmount ? address.subdustPkScript : address.pkScript,
3656
+ tapTree: recipient.tapTree
3116
3657
  });
3117
3658
  }
3118
3659
  return validatedRecipients;
3119
3660
  }
3120
3661
 
3662
+ // src/contracts/spendability.ts
3663
+ function isContractGenericallySpendable(contract) {
3664
+ return contractHandlers.get(contract.type)?.isGenericallySpendable?.(contract) === true;
3665
+ }
3666
+ function gatedContracts(contracts) {
3667
+ const gated = /* @__PURE__ */ new Map();
3668
+ for (const contract of contracts) {
3669
+ if (!isContractGenericallySpendable(contract)) gated.set(contract.script, contract.type);
3670
+ }
3671
+ return gated;
3672
+ }
3673
+ function gateExclusion(gated) {
3674
+ return (vtxo) => {
3675
+ const type = vtxo.script === void 0 ? void 0 : gated.get(vtxo.script);
3676
+ if (type === void 0) return void 0;
3677
+ return `at ${vtxo.script} (contract type '${type}') is not generically spendable`;
3678
+ };
3679
+ }
3680
+ function outpointExclusion(outpoints, reason) {
3681
+ return (vtxo) => outpoints.has(`${vtxo.txid}:${vtxo.vout}`) ? reason : void 0;
3682
+ }
3683
+ function outpointReasons(reasons) {
3684
+ return (vtxo) => reasons.get(`${vtxo.txid}:${vtxo.vout}`);
3685
+ }
3686
+ function logExcludedVtxos(source, vtxos, exclusions) {
3687
+ if (exclusions.length === 0) return;
3688
+ for (const vtxo of vtxos) {
3689
+ for (const exclusion of exclusions) {
3690
+ const reason = exclusion(vtxo);
3691
+ if (reason === void 0) continue;
3692
+ console.debug(`[spendability] ${source}: ${vtxo.txid}:${vtxo.vout} ${reason}`);
3693
+ }
3694
+ }
3695
+ }
3696
+ var UnannotatableInputError = class extends Error {
3697
+ name = "UnannotatableInputError";
3698
+ };
3699
+
3121
3700
  // src/wallet/vtxo-manager.ts
3122
3701
  function selectPendingRecoveryOutpoints(contractsWithVtxos, signerSet, nowSeconds = Math.floor(Date.now() / 1e3)) {
3123
3702
  const out = /* @__PURE__ */ new Set();
@@ -3400,6 +3979,27 @@ var VtxoManager = class _VtxoManager {
3400
3979
  static MIGRATION_COOLDOWN_MS = 3e4;
3401
3980
  static MIGRATION_MAX_BACKOFF_MS = 5 * 60 * 1e3;
3402
3981
  // ========== Recovery Methods ==========
3982
+ /**
3983
+ * Outpoints recovery must not name yet, with the reason each was refused.
3984
+ * Empty when the manager offers no opinion — an embedder's may not implement
3985
+ * the predicate, and every contract type but VHTLC never answers.
3986
+ *
3987
+ * Reaches only a lockup whose `sender` is this wallet's own key: role
3988
+ * resolution matches that key against the contract's params, so a
3989
+ * descriptor-derived sender (every RFQ lockup) is not matched and such a row
3990
+ * still fails its batch at submit.
3991
+ *
3992
+ * The key stays a thunk so an ordinary recovery never touches the identity,
3993
+ * and the full coins are passed rather than bare outpoints because only they
3994
+ * carry the confirmation a relative timelock is measured from.
3995
+ */
3996
+ async unspendableNow(vtxos) {
3997
+ const contractManager = await this.wallet.getContractManager();
3998
+ return await contractManager.unspendableNowReasons?.(
3999
+ vtxos,
4000
+ async () => hex.encode(await this.wallet.identity.xOnlyPublicKey())
4001
+ ) ?? /* @__PURE__ */ new Map();
4002
+ }
3403
4003
  /**
3404
4004
  * Recover swept/expired virtual outputs by settling them back to the wallet's Arkade address.
3405
4005
  *
@@ -3412,6 +4012,11 @@ var VtxoManager = class _VtxoManager {
3412
4012
  * Note: Settled virtual outputs with long expiry are NOT recovered to avoid locking liquidity unnecessarily.
3413
4013
  * Only preconfirmed subdust is recovered to consolidate small amounts.
3414
4014
  *
4015
+ * Inputs whose contract refuses a spend right now — an immature VHTLC refund
4016
+ * path — are skipped rather than failing the batch that holds them, and
4017
+ * {@link getRecoverableBalance} skips the same set. See
4018
+ * {@link unspendableNow} for which rows that reaches.
4019
+ *
3415
4020
  * @param eventCallback - Optional callback to receive settlement events
3416
4021
  * @returns Settlement transaction ID
3417
4022
  * @throws Error if no recoverable virtual outputs found
@@ -3440,6 +4045,26 @@ var VtxoManager = class _VtxoManager {
3440
4045
  if (vtxosToRecover.length === 0) {
3441
4046
  throw new Error("No recoverable VTXOs found");
3442
4047
  }
4048
+ const refused = await this.unspendableNow(vtxosToRecover);
4049
+ if (refused.size > 0) {
4050
+ logExcludedVtxos("recoverVtxos", vtxosToRecover, [outpointReasons(refused)]);
4051
+ const held = vtxosToRecover.length;
4052
+ vtxosToRecover = vtxosToRecover.filter(
4053
+ (vtxo) => !refused.has(`${vtxo.txid}:${vtxo.vout}`)
4054
+ );
4055
+ if (vtxosToRecover.length === 0) {
4056
+ const why = refused.size === 1 ? [...refused.values()][0] : [...refused].map(([outpoint, reason]) => `${outpoint}: ${reason}`).join("; ");
4057
+ throw new Error(
4058
+ `All ${held} recoverable VTXO(s) are held by a contract that refuses a spend right now: ${why}`
4059
+ );
4060
+ }
4061
+ ({ vtxosToRecover } = getRecoverableWithSubdust(vtxosToRecover, dustAmount, now));
4062
+ if (vtxosToRecover.length === 0) {
4063
+ throw new Error(
4064
+ `Excluding ${refused.size} VTXO(s) not yet spendable, the remaining recoverable amount is below the dust threshold ${dustAmount}`
4065
+ );
4066
+ }
4067
+ }
3443
4068
  const info = await this.getInfoProvider()?.getInfo();
3444
4069
  const vtxoMaxAmount = info?.vtxoMaxAmount ?? -1n;
3445
4070
  const estimator = new Estimator(info?.fees.intentFee ?? {});
@@ -3503,6 +4128,11 @@ var VtxoManager = class _VtxoManager {
3503
4128
  * The batch size caps are not applied here: they defer the overflow to the
3504
4129
  * next cycle rather than reducing what is recoverable.
3505
4130
  *
4131
+ * Inputs a contract refuses right now are excluded, so this and
4132
+ * {@link recoverVtxos} answer over the same set. `Balance.recoverable` still
4133
+ * counts them: that field reports what the wallet owns, this one what a
4134
+ * batch would hand back today.
4135
+ *
3506
4136
  * @returns Object containing recoverable amounts and subdust information
3507
4137
  *
3508
4138
  * @example
@@ -3524,11 +4154,24 @@ var VtxoManager = class _VtxoManager {
3524
4154
  withUnrolled: false
3525
4155
  });
3526
4156
  const dustAmount = getDustAmount(this.wallet);
3527
- const { vtxosToRecover, includesSubdust } = getRecoverableWithSubdust(
4157
+ const now = await fetchTimeHeight(this.wallet);
4158
+ let { vtxosToRecover, includesSubdust } = getRecoverableWithSubdust(
3528
4159
  allVtxos,
3529
4160
  dustAmount,
3530
- await fetchTimeHeight(this.wallet)
4161
+ now
3531
4162
  );
4163
+ const refused = await this.unspendableNow(vtxosToRecover);
4164
+ if (refused.size > 0) {
4165
+ logExcludedVtxos("getRecoverableBalance", vtxosToRecover, [outpointReasons(refused)]);
4166
+ const remaining = vtxosToRecover.filter(
4167
+ (vtxo) => !refused.has(`${vtxo.txid}:${vtxo.vout}`)
4168
+ );
4169
+ ({ vtxosToRecover, includesSubdust } = getRecoverableWithSubdust(
4170
+ remaining,
4171
+ dustAmount,
4172
+ now
4173
+ ));
4174
+ }
3532
4175
  const info = await this.getInfoProvider()?.getInfo();
3533
4176
  const estimator = new Estimator(info?.fees.intentFee ?? {});
3534
4177
  const { payable, net } = priceSettlementInputs(vtxosToRecover, estimator);
@@ -4770,7 +5413,7 @@ var ArkNote = class _ArkNote {
4770
5413
  this.preimage = preimage;
4771
5414
  this.value = value;
4772
5415
  this.HRP = HRP;
4773
- const preimageHash = sha256(this.preimage);
5416
+ const preimageHash = sha256$1(this.preimage);
4774
5417
  this.vtxoScript = new VtxoScript([noteTapscript(preimageHash)]);
4775
5418
  const leaf = this.vtxoScript.leaves[0];
4776
5419
  this.txid = hex.encode(new Uint8Array(preimageHash).reverse());
@@ -7590,41 +8233,6 @@ function mergeByKey(existing, incoming, toKey) {
7590
8233
  });
7591
8234
  return Array.from(next.values());
7592
8235
  }
7593
-
7594
- // src/contracts/spendability.ts
7595
- function isContractGenericallySpendable(contract) {
7596
- return contractHandlers.get(contract.type)?.isGenericallySpendable?.(contract) === true;
7597
- }
7598
- function gatedContracts(contracts) {
7599
- const gated = /* @__PURE__ */ new Map();
7600
- for (const contract of contracts) {
7601
- if (!isContractGenericallySpendable(contract)) gated.set(contract.script, contract.type);
7602
- }
7603
- return gated;
7604
- }
7605
- function gateExclusion(gated) {
7606
- return (vtxo) => {
7607
- const type = vtxo.script === void 0 ? void 0 : gated.get(vtxo.script);
7608
- if (type === void 0) return void 0;
7609
- return `at ${vtxo.script} (contract type '${type}') is not generically spendable`;
7610
- };
7611
- }
7612
- function outpointExclusion(outpoints, reason) {
7613
- return (vtxo) => outpoints.has(`${vtxo.txid}:${vtxo.vout}`) ? reason : void 0;
7614
- }
7615
- function logExcludedVtxos(source, vtxos, exclusions) {
7616
- if (exclusions.length === 0) return;
7617
- for (const vtxo of vtxos) {
7618
- for (const exclusion of exclusions) {
7619
- const reason = exclusion(vtxo);
7620
- if (reason === void 0) continue;
7621
- console.debug(`[spendability] ${source}: ${vtxo.txid}:${vtxo.vout} ${reason}`);
7622
- }
7623
- }
7624
- }
7625
- var UnannotatableInputError = class extends Error {
7626
- name = "UnannotatableInputError";
7627
- };
7628
8236
  var ARKCONTRACT_PREFIX = "arkcontract";
7629
8237
  function encodeArkContract(contract) {
7630
8238
  const params = new URLSearchParams();
@@ -9065,7 +9673,17 @@ var ContractManager = class _ContractManager {
9065
9673
  }
9066
9674
  /** @inheritdoc */
9067
9675
  async assertSpendableNow(vtxos, walletPubKey) {
9068
- if (vtxos.length === 0) return;
9676
+ const refused = await this.unspendableNowReasons(vtxos, walletPubKey);
9677
+ if (refused.size === 0) return;
9678
+ if (refused.size === 1) throw new Error([...refused.values()][0]);
9679
+ throw new Error(
9680
+ `refusing to spend ${refused.size} vtxo(s) that cannot be spent yet: ` + [...refused].map(([outpoint, why]) => `${outpoint}: ${why}`).join("; ")
9681
+ );
9682
+ }
9683
+ /** @inheritdoc */
9684
+ async unspendableNowReasons(vtxos, walletPubKey) {
9685
+ const refused = /* @__PURE__ */ new Map();
9686
+ if (vtxos.length === 0) return refused;
9069
9687
  const contracts = await this.config.contractRepository.getContracts({
9070
9688
  script: Array.from(new Set(vtxos.map((vtxo) => vtxo.script)))
9071
9689
  });
@@ -9074,7 +9692,7 @@ var ContractManager = class _ContractManager {
9074
9692
  const contract = byScript.get(vtxo.script);
9075
9693
  return contract !== void 0 && contractHandlers.get(contract.type)?.assertSpendableNow !== void 0;
9076
9694
  });
9077
- if (asking.length === 0) return;
9695
+ if (asking.length === 0) return refused;
9078
9696
  const tip = await this.currentChainTip();
9079
9697
  const walletKey = await walletPubKey?.();
9080
9698
  for (const vtxo of asking) {
@@ -9096,12 +9714,20 @@ var ContractManager = class _ContractManager {
9096
9714
  // really is one.
9097
9715
  vtxo: isVirtualCoin(vtxo) && "status" in vtxo ? vtxo : void 0
9098
9716
  };
9099
- await handler.assertSpendableNow(
9100
- handler.createScript(contract.params),
9101
- contract,
9102
- context
9103
- );
9717
+ try {
9718
+ await handler.assertSpendableNow(
9719
+ handler.createScript(contract.params),
9720
+ contract,
9721
+ context
9722
+ );
9723
+ } catch (err) {
9724
+ refused.set(
9725
+ `${vtxo.txid}:${vtxo.vout}`,
9726
+ err instanceof Error ? err.message : String(err)
9727
+ );
9728
+ }
9104
9729
  }
9730
+ return refused;
9105
9731
  }
9106
9732
  // Field-by-field, so every filter a caller can express reaches the
9107
9733
  // repository. A field missing here is not a narrower query — it is an
@@ -11219,6 +11845,8 @@ function computeOffchainBalance(vtxos, caps) {
11219
11845
  let settled = 0;
11220
11846
  let preconfirmed = 0;
11221
11847
  let available = 0;
11848
+ let gated = 0;
11849
+ let intentLocked = 0;
11222
11850
  let recoverable = 0;
11223
11851
  let pendingRecovery = 0;
11224
11852
  const owned = /* @__PURE__ */ new Map();
@@ -11245,7 +11873,11 @@ function computeOffchainBalance(vtxos, caps) {
11245
11873
  } else {
11246
11874
  settled += vtxo.value;
11247
11875
  }
11248
- if (isGenericallySpendable(vtxo) && isUnlocked(vtxo)) {
11876
+ if (!isGenericallySpendable(vtxo)) {
11877
+ gated += vtxo.value;
11878
+ } else if (!isUnlocked(vtxo)) {
11879
+ intentLocked += vtxo.value;
11880
+ } else {
11249
11881
  available += vtxo.value;
11250
11882
  addAssets(spendable, vtxo);
11251
11883
  }
@@ -11255,6 +11887,8 @@ function computeOffchainBalance(vtxos, caps) {
11255
11887
  settled,
11256
11888
  preconfirmed,
11257
11889
  available,
11890
+ gated,
11891
+ intentLocked,
11258
11892
  recoverable,
11259
11893
  pendingRecovery,
11260
11894
  total: settled + preconfirmed + recoverable + pendingRecovery,
@@ -11411,6 +12045,17 @@ function intentProofJobs(coins) {
11411
12045
  }));
11412
12046
  return [{ index: 0, lookupScript: coinJobs[0].lookupScript }, ...coinJobs];
11413
12047
  }
12048
+ function asSendParams(args) {
12049
+ const [first] = args;
12050
+ if (args.length === 1 && first && "recipients" in first) {
12051
+ const params = first;
12052
+ if (params.recipients.length === 0) {
12053
+ throw new Error("At least one receiver is required");
12054
+ }
12055
+ return params;
12056
+ }
12057
+ return { recipients: args };
12058
+ }
11414
12059
  function extractArkProviderUrl(provider) {
11415
12060
  const serverUrl = provider.serverUrl;
11416
12061
  return typeof serverUrl === "string" && serverUrl.length > 0 ? serverUrl : void 0;
@@ -12007,6 +12652,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
12007
12652
  settled: offchain.settled,
12008
12653
  preconfirmed: offchain.preconfirmed,
12009
12654
  available: offchain.available,
12655
+ gated: offchain.gated,
12656
+ intentLocked: offchain.intentLocked,
12010
12657
  recoverable: offchain.recoverable,
12011
12658
  pendingRecovery: offchain.pendingRecovery,
12012
12659
  total: totalBoarding + offchain.total,
@@ -13049,15 +13696,24 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13049
13696
  return provider.getCurrentSigningDescriptor();
13050
13697
  }
13051
13698
  /**
13052
- * @see HDWalletCapable.getNextSigningDescriptor
13699
+ * @see HDAllocationCapable.getNextSigningDescriptor
13700
+ *
13701
+ * Every `Wallet` answers — this is where the wallet's key-provisioning
13702
+ * policy lives, so consumers never have to branch on wallet shape:
13703
+ * - HD: allocate a fresh index through the contract manager (which owns
13704
+ * cross-context serialization and the look-ahead band).
13705
+ * - custom provider: whatever the provider allocates.
13706
+ * - static / `auto`: the identity key as a bare `tr(pubkey)` descriptor —
13707
+ * the same answer every call, because that IS the static policy.
13053
13708
  */
13054
13709
  async getNextSigningDescriptor() {
13055
- const provider = this._descriptorProvider;
13056
- if (!(provider instanceof HDDescriptorProvider)) return void 0;
13057
- return (await this.getContractManager()).getNextSigningDescriptor();
13710
+ if (this._descriptorProvider instanceof HDDescriptorProvider) {
13711
+ return (await this.getContractManager()).getNextSigningDescriptor();
13712
+ }
13713
+ return identityDescriptor(this.identity);
13058
13714
  }
13059
13715
  /**
13060
- * @see HDWalletCapable.advanceSigningDescriptorWatermark
13716
+ * @see HDAllocationCapable.advanceSigningDescriptorWatermark
13061
13717
  */
13062
13718
  async advanceSigningDescriptorWatermark(descriptor) {
13063
13719
  const provider = this._descriptorProvider;
@@ -13110,13 +13766,16 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13110
13766
  }
13111
13767
  /**
13112
13768
  * @see HDWalletCapable.signerForDescriptor
13769
+ *
13770
+ * Fail-loud contract: the returned identity is always the descriptor's
13771
+ * own key. A descriptor this wallet cannot sign for throws
13772
+ * {@link ForeignDescriptorError} instead of silently substituting the
13773
+ * baseline identity — that identity would sign happily with the wrong
13774
+ * key, and the failure would only surface as a rejected transaction or a
13775
+ * dead script, far from the call that caused it.
13113
13776
  */
13114
13777
  async signerForDescriptor(descriptor) {
13115
- const provider = this._descriptorProvider;
13116
- if (!(provider instanceof HDDescriptorProvider) || !provider.isOurs(descriptor)) {
13117
- return this.identity;
13118
- }
13119
- return new DescriptorIdentity({ descriptor, signer: provider, base: this.identity });
13778
+ return resolveDescriptorSigner(descriptor, this.identity, this._descriptorProvider);
13120
13779
  }
13121
13780
  /**
13122
13781
  * Mid-session server-signer rotation (plan §4). When arkd rotates its
@@ -13322,7 +13981,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13322
13981
  const manager = await this.getContractManager();
13323
13982
  const provider = this._descriptorProvider;
13324
13983
  const hd = provider instanceof HDDescriptorProvider;
13325
- const staticDescriptor = hd ? void 0 : `tr(${hex.encode(await this.identity.xOnlyPublicKey())})`;
13984
+ const staticDescriptor = hd ? void 0 : await identityDescriptor(this.identity);
13326
13985
  const materialize = (index) => hd ? provider.materializeDescriptorAt(index) : staticDescriptor;
13327
13986
  const delegatePubKey = this.offchainTapscript instanceof DelegateVtxo.Script ? this.offchainTapscript.options.delegatePubKey : void 0;
13328
13987
  const arkInfo = await this.arkProvider.getInfo();
@@ -14099,7 +14758,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14099
14758
  return {
14100
14759
  onBatchStarted: async (event) => {
14101
14760
  const utf8IntentId = new TextEncoder().encode(intentId);
14102
- const intentIdHash = sha256(utf8IntentId);
14761
+ const intentIdHash = sha256$1(utf8IntentId);
14103
14762
  const intentIdHashStr = hex.encode(intentIdHash);
14104
14763
  const skip = !event.intentIdHashes.includes(intentIdHashStr);
14105
14764
  if (skip) {
@@ -14734,10 +15393,13 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14734
15393
  return total;
14735
15394
  }
14736
15395
  /**
14737
- * Send BTC and/or assets to one or more recipients.
15396
+ * Send BTC and/or assets to one or more recipients, passed either as
15397
+ * variadic `Recipient`s or as a single `SendParams` object — the latter
15398
+ * also carries the virtual outputs to spend.
14738
15399
  *
14739
- * @param args - Recipients with their addresses, BTC amounts, and assets
15400
+ * @param args - Recipients, or a `SendParams` object
14740
15401
  * @returns Promise resolving to the Arkade transaction ID
15402
+ * @see SendParams
14741
15403
  *
14742
15404
  * @example
14743
15405
  * ```typescript
@@ -14746,15 +15408,28 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14746
15408
  * amount: 1000, // (optional, default to dust) btc amount to send to the output
14747
15409
  * assets: [{ assetId: 'abc123...', amount: 50n }] // (optional) list of assets to send
14748
15410
  * });
15411
+ *
15412
+ * // choosing the inputs as well as the outputs
15413
+ * const txid = await wallet.send({
15414
+ * recipients: [{ address: 'ark1q...', amount: 1000 }],
15415
+ * selectedVtxos: mine, // spent as given, nothing added
15416
+ * });
14749
15417
  * ```
14750
15418
  */
14751
15419
  async send(...args) {
14752
- return this._withTxLock(() => this._sendImpl(...args));
15420
+ const params = asSendParams(args);
15421
+ return this._withTxLock(() => this._sendImpl(params));
14753
15422
  }
14754
- async _sendImpl(...args) {
15423
+ async _sendImpl({ recipients: args, selectedVtxos }) {
14755
15424
  if (args.length === 0) {
14756
15425
  throw new Error("At least one receiver is required");
14757
15426
  }
15427
+ if (selectedVtxos && selectedVtxos.length === 0) {
15428
+ throw new Error("send({ selectedVtxos }): no inputs");
15429
+ }
15430
+ if (selectedVtxos) {
15431
+ void this.logUngatedInputs("send({ selectedVtxos })", selectedVtxos);
15432
+ }
14758
15433
  const offchainTapscript = this.offchainTapscript;
14759
15434
  const serverPubKey = this.arkServerPublicKey;
14760
15435
  const serverUnrollScript = this.serverUnrollScript;
@@ -14765,84 +15440,123 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14765
15440
  Number(this.dustAmount),
14766
15441
  this.recipientAddressContext(serverPubKey)
14767
15442
  );
14768
- const virtualCoins = await this.getSpendableVtxos({
14769
- withRecoverable: false
14770
- });
15443
+ let virtualCoins = [];
15444
+ if (!selectedVtxos) {
15445
+ virtualCoins = await this.getSpendableVtxos({
15446
+ withRecoverable: false
15447
+ });
15448
+ }
14771
15449
  const assetChanges = /* @__PURE__ */ new Map();
14772
- let selectedCoins = [];
15450
+ let selectedCoins = selectedVtxos ? [...selectedVtxos] : [];
14773
15451
  let btcAmountToSelect = 0;
14774
15452
  for (const recipient of recipients) {
14775
15453
  btcAmountToSelect += Math.max(recipient.amount, Number(this.dustAmount));
14776
15454
  }
14777
- for (const recipient of recipients) {
14778
- if (!recipient.assets) {
14779
- continue;
15455
+ if (selectedVtxos) {
15456
+ for (const coin of selectedCoins) {
15457
+ for (const asset of coin.assets ?? []) {
15458
+ const existing = assetChanges.get(asset.assetId) ?? 0n;
15459
+ assetChanges.set(asset.assetId, existing + asset.amount);
15460
+ }
14780
15461
  }
14781
- for (const receiverAsset of recipient.assets) {
14782
- let amountToSelect = receiverAsset.amount;
14783
- const existingChange = assetChanges.get(receiverAsset.assetId) ?? 0n;
14784
- if (existingChange >= amountToSelect) {
14785
- assetChanges.set(receiverAsset.assetId, existingChange - amountToSelect);
14786
- if (assetChanges.get(receiverAsset.assetId) === 0n) {
14787
- assetChanges.delete(receiverAsset.assetId);
15462
+ for (const recipient of recipients) {
15463
+ for (const asset of recipient.assets) {
15464
+ const remaining = (assetChanges.get(asset.assetId) ?? 0n) - asset.amount;
15465
+ if (remaining < 0n) {
15466
+ throw new Error(
15467
+ `send({ selectedVtxos }): inputs are short ${-remaining} of asset ${asset.assetId}`
15468
+ );
15469
+ }
15470
+ if (remaining === 0n) {
15471
+ assetChanges.delete(asset.assetId);
15472
+ } else {
15473
+ assetChanges.set(asset.assetId, remaining);
14788
15474
  }
15475
+ }
15476
+ }
15477
+ } else {
15478
+ for (const recipient of recipients) {
15479
+ if (!recipient.assets) {
14789
15480
  continue;
14790
15481
  }
14791
- if (existingChange > 0n) {
14792
- amountToSelect -= existingChange;
14793
- assetChanges.delete(receiverAsset.assetId);
15482
+ for (const receiverAsset of recipient.assets) {
15483
+ let amountToSelect = receiverAsset.amount;
15484
+ const existingChange = assetChanges.get(receiverAsset.assetId) ?? 0n;
15485
+ if (existingChange >= amountToSelect) {
15486
+ assetChanges.set(receiverAsset.assetId, existingChange - amountToSelect);
15487
+ if (assetChanges.get(receiverAsset.assetId) === 0n) {
15488
+ assetChanges.delete(receiverAsset.assetId);
15489
+ }
15490
+ continue;
15491
+ }
15492
+ if (existingChange > 0n) {
15493
+ amountToSelect -= existingChange;
15494
+ assetChanges.delete(receiverAsset.assetId);
15495
+ }
15496
+ const availableCoins = virtualCoins.filter(
15497
+ (c) => !selectedCoins.find((sc) => sc.txid === c.txid && sc.vout === c.vout)
15498
+ );
15499
+ const { selected, totalAssetAmount } = selectCoinsWithAsset(
15500
+ availableCoins,
15501
+ receiverAsset.assetId,
15502
+ amountToSelect
15503
+ );
15504
+ for (const coin of selected) {
15505
+ selectedCoins.push(coin);
15506
+ btcAmountToSelect -= coin.value;
15507
+ if (coin.assets) {
15508
+ for (const a of coin.assets) {
15509
+ if (a.assetId === receiverAsset.assetId) {
15510
+ continue;
15511
+ }
15512
+ const existing = assetChanges.get(a.assetId) ?? 0n;
15513
+ assetChanges.set(a.assetId, existing + a.amount);
15514
+ }
15515
+ }
15516
+ }
15517
+ const assetChangeAmount = totalAssetAmount - amountToSelect;
15518
+ if (assetChangeAmount > 0n) {
15519
+ const existing = assetChanges.get(receiverAsset.assetId) ?? 0n;
15520
+ assetChanges.set(receiverAsset.assetId, existing + assetChangeAmount);
15521
+ }
14794
15522
  }
15523
+ }
15524
+ if (btcAmountToSelect > 0) {
14795
15525
  const availableCoins = virtualCoins.filter(
14796
15526
  (c) => !selectedCoins.find((sc) => sc.txid === c.txid && sc.vout === c.vout)
14797
15527
  );
14798
- const { selected, totalAssetAmount } = selectCoinsWithAsset(
14799
- availableCoins,
14800
- receiverAsset.assetId,
14801
- amountToSelect
14802
- );
14803
- for (const coin of selected) {
14804
- selectedCoins.push(coin);
14805
- btcAmountToSelect -= coin.value;
15528
+ const { inputs: btcCoins } = selectVirtualCoins(availableCoins, btcAmountToSelect);
15529
+ for (const coin of btcCoins) {
14806
15530
  if (coin.assets) {
14807
- for (const a of coin.assets) {
14808
- if (a.assetId === receiverAsset.assetId) {
14809
- continue;
14810
- }
14811
- const existing = assetChanges.get(a.assetId) ?? 0n;
14812
- assetChanges.set(a.assetId, existing + a.amount);
15531
+ for (const asset of coin.assets) {
15532
+ const existing = assetChanges.get(asset.assetId) ?? 0n;
15533
+ assetChanges.set(asset.assetId, existing + asset.amount);
14813
15534
  }
14814
15535
  }
14815
15536
  }
14816
- const assetChangeAmount = totalAssetAmount - amountToSelect;
14817
- if (assetChangeAmount > 0n) {
14818
- const existing = assetChanges.get(receiverAsset.assetId) ?? 0n;
14819
- assetChanges.set(receiverAsset.assetId, existing + assetChangeAmount);
14820
- }
14821
- }
14822
- }
14823
- if (btcAmountToSelect > 0) {
14824
- const availableCoins = virtualCoins.filter(
14825
- (c) => !selectedCoins.find((sc) => sc.txid === c.txid && sc.vout === c.vout)
14826
- );
14827
- const { inputs: btcCoins } = selectVirtualCoins(availableCoins, btcAmountToSelect);
14828
- for (const coin of btcCoins) {
14829
- if (coin.assets) {
14830
- for (const asset of coin.assets) {
14831
- const existing = assetChanges.get(asset.assetId) ?? 0n;
14832
- assetChanges.set(asset.assetId, existing + asset.amount);
14833
- }
14834
- }
15537
+ selectedCoins = [...selectedCoins, ...btcCoins];
14835
15538
  }
14836
- selectedCoins = [...selectedCoins, ...btcCoins];
14837
15539
  }
14838
15540
  let totalBtcSelected = selectedCoins.reduce((sum, c) => sum + c.value, 0);
14839
15541
  const outputs = recipients.map((recipient) => ({
14840
15542
  script: recipient.script,
14841
- amount: BigInt(recipient.amount)
15543
+ amount: BigInt(recipient.amount),
15544
+ // Already checked against the recipient address in `validateRecipients`.
15545
+ ...recipient.tapTree ? { tapTree: TapTreeCoder.decode(recipient.tapTree) } : {}
14842
15546
  }));
14843
15547
  const totalBtcOutput = outputs.reduce((sum, o) => sum + Number(o.amount), 0);
14844
15548
  let changeAmount = totalBtcSelected - totalBtcOutput;
15549
+ if (changeAmount < 0) {
15550
+ throw new Error(
15551
+ `send({ selectedVtxos }): inputs total ${totalBtcSelected} sats, outputs need ${totalBtcOutput}`
15552
+ );
15553
+ }
14845
15554
  if (assetChanges.size > 0 && changeAmount < Number(this.dustAmount)) {
15555
+ if (selectedVtxos) {
15556
+ throw new Error(
15557
+ `send({ selectedVtxos }): ${changeAmount} sats of change cannot carry ${assetChanges.size} asset change(s), needs ${this.dustAmount}`
15558
+ );
15559
+ }
14846
15560
  const availableCoins = virtualCoins.filter(
14847
15561
  (c) => !selectedCoins.find((sc) => sc.txid === c.txid && sc.vout === c.vout)
14848
15562
  );
@@ -16605,8 +17319,8 @@ var WalletMessageHandler = class {
16605
17319
  });
16606
17320
  }
16607
17321
  case "SEND": {
16608
- const { recipients } = message.payload;
16609
- const txid = await this.wallet.send(...recipients);
17322
+ const { recipients, selectedVtxos } = message.payload;
17323
+ const txid = await (selectedVtxos ? this.wallet.send({ recipients, selectedVtxos }) : this.wallet.send(...recipients));
16610
17324
  return this.tagged({
16611
17325
  id,
16612
17326
  type: "SEND_SUCCESS",
@@ -16854,6 +17568,8 @@ var WalletMessageHandler = class {
16854
17568
  settled: offchain.settled,
16855
17569
  preconfirmed: offchain.preconfirmed,
16856
17570
  available: offchain.available,
17571
+ gated: offchain.gated,
17572
+ intentLocked: offchain.intentLocked,
16857
17573
  recoverable: offchain.recoverable,
16858
17574
  pendingRecovery: offchain.pendingRecovery,
16859
17575
  total: totalBoarding + offchain.total,
@@ -17298,10 +18014,6 @@ function getRequestDedupKey(request) {
17298
18014
  const { id, tag, ...rest } = request;
17299
18015
  return JSON.stringify(rest);
17300
18016
  }
17301
- function isSigningCapable(identity) {
17302
- const candidate = identity;
17303
- return typeof candidate.signMessage === "function" && typeof candidate.sign === "function" && typeof candidate.signerSession === "function";
17304
- }
17305
18017
  var ServiceWorkerReadonlyAssetManager = class {
17306
18018
  constructor(sendMessage, messageTag) {
17307
18019
  this.sendMessage = sendMessage;
@@ -18009,7 +18721,15 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
18009
18721
  */
18010
18722
  async assertAnnotatable() {
18011
18723
  },
18012
- /** Same reasoning as {@link assertAnnotatable}: the worker checks it. */
18724
+ /**
18725
+ * Same reasoning as {@link assertAnnotatable}: the worker checks it.
18726
+ *
18727
+ * `unspendableNowReasons` is deliberately absent rather than stubbed
18728
+ * alongside it. A stub returning an empty map reads as "nothing
18729
+ * refused", and a filter acting on that silently drops its decision;
18730
+ * absent, the optional call is skipped. Recovery — the only caller —
18731
+ * runs inside the worker against the real manager anyway.
18732
+ */
18013
18733
  async assertSpendableNow() {
18014
18734
  },
18015
18735
  async annotateVtxos(vtxos) {
@@ -18235,7 +18955,7 @@ var ServiceWorkerWallet = class _ServiceWorkerWallet extends ServiceWorkerReadon
18235
18955
  }
18236
18956
  const walletRepository = options.storage?.walletRepository ?? new IndexedDBWalletRepository();
18237
18957
  const contractRepository = options.storage?.contractRepository ?? new IndexedDBContractRepository();
18238
- if (!isSigningCapable(options.identity)) {
18958
+ if (!isSigningIdentity(options.identity)) {
18239
18959
  throw new Error(
18240
18960
  "ServiceWorkerWallet.create() requires a signing Identity; got a ReadonlyIdentity"
18241
18961
  );
@@ -18395,17 +19115,21 @@ var ServiceWorkerWallet = class _ServiceWorkerWallet extends ServiceWorkerReadon
18395
19115
  /**
18396
19116
  * @see HDWalletCapable.signerForDescriptor
18397
19117
  *
18398
- * Runs page-side: an Identity cannot cross the message bus, and it does
18399
- * not need to — the page owns the signing identity, and derivation reads
18400
- * no allocation state. Mirrors {@link Wallet.signerForDescriptor}'s
18401
- * fallback: the wallet identity itself for a non-HD identity or a foreign
19118
+ * Runs page-side: an `Identity` cannot cross the message bus, and it does
19119
+ * not need to — the page owns the signing identity, and resolving a
19120
+ * descriptor reads no allocation state. Shares
19121
+ * {@link resolveDescriptorSigner} with {@link Wallet.signerForDescriptor}
19122
+ * so the two sides of the bus cannot answer differently for one
18402
19123
  * descriptor.
19124
+ *
19125
+ * No provider is passed, and none is needed: `HDDescriptorProvider`'s
19126
+ * `isOurs` and signing members all delegate to the identity, which the
19127
+ * page holds. Building one here would only add a page-side read of the
19128
+ * wallet state the worker allocates from — shared mutable state on a path
19129
+ * that has no business touching it.
18403
19130
  */
18404
19131
  async signerForDescriptor(descriptor) {
18405
- if (!isHDCapableIdentity(this.identity)) return this.identity;
18406
- const provider = await HDDescriptorProvider.create(this.identity, this.walletRepository);
18407
- if (!provider.isOurs(descriptor)) return this.identity;
18408
- return new DescriptorIdentity({ descriptor, signer: provider, base: this.identity });
19132
+ return resolveDescriptorSigner(descriptor, this.identity);
18409
19133
  }
18410
19134
  async sendBitcoin(params) {
18411
19135
  const message = {
@@ -18469,12 +19193,16 @@ var ServiceWorkerWallet = class _ServiceWorkerWallet extends ServiceWorkerReadon
18469
19193
  throw error;
18470
19194
  }
18471
19195
  }
18472
- async send(...recipients) {
19196
+ async send(...args) {
19197
+ const [first] = args;
19198
+ const { recipients, selectedVtxos } = args.length === 1 && first && "recipients" in first ? first : { recipients: args, selectedVtxos: void 0 };
18473
19199
  const message = {
18474
19200
  tag: this.messageTag,
18475
19201
  type: "SEND",
18476
19202
  id: getRandomId(),
18477
- payload: { recipients }
19203
+ // Omitted rather than sent as `undefined`, so an older worker sees
19204
+ // exactly the payload it saw before.
19205
+ payload: selectedVtxos ? { recipients, selectedVtxos } : { recipients }
18478
19206
  };
18479
19207
  try {
18480
19208
  const response = await this.sendMessage(message);
@@ -18975,8 +19703,8 @@ function parseBlockHeader(headerHex) {
18975
19703
  }
18976
19704
  const view = new DataView(headerBytes.buffer, headerBytes.byteOffset);
18977
19705
  const timestamp = view.getUint32(68, true);
18978
- const hash1 = sha256(headerBytes);
18979
- const hash2 = sha256(hash1);
19706
+ const hash1 = sha256$1(headerBytes);
19707
+ const hash2 = sha256$1(hash1);
18980
19708
  const hashStr = hex.encode(new Uint8Array(hash2).reverse());
18981
19709
  return { hash: hashStr, timestamp };
18982
19710
  }
@@ -19594,7 +20322,7 @@ var ElectrumOnchainProvider = class {
19594
20322
  }
19595
20323
  };
19596
20324
  function toScriptHash(script) {
19597
- return hex.encode(sha256(script).reverse());
20325
+ return hex.encode(sha256$1(script).reverse());
19598
20326
  }
19599
20327
  function isHeaderSubscribeResult(v) {
19600
20328
  if (typeof v !== "object" || v === null) return false;
@@ -21035,7 +21763,7 @@ function createArkadeBatchHandler(intentId, inputs, signer, signedProof, message
21035
21763
  return {
21036
21764
  onBatchStarted: async (event) => {
21037
21765
  const utf8IntentId = new TextEncoder().encode(intentId);
21038
- const intentIdHash = sha256(utf8IntentId);
21766
+ const intentIdHash = sha256$1(utf8IntentId);
21039
21767
  const intentIdHashStr = hex.encode(intentIdHash);
21040
21768
  if (!event.intentIdHashes.includes(intentIdHashStr)) return { skip: true };
21041
21769
  const info = await arkProvider.getInfo();
@@ -22020,7 +22748,12 @@ function createDefaultPaymentRouter(wallet) {
22020
22748
  prefs: { priority: ["ark", "lightning", "onchain"] }
22021
22749
  }).use(arkRail()).use(onchainRail());
22022
22750
  }
22751
+ /*! Bundled license information:
22752
+
22753
+ @noble/hashes/utils.js:
22754
+ (*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
22755
+ */
22023
22756
 
22024
- export { ARKADE_MAGIC, ActivityRegistry, AmbiguousRouteError, ArkNote, ArkadeCash, ArkadeCashCreateError, AssetManager, BIP21, BIP21Error, BIP322, Batch, ChainedTxType, ContractManager, ContractRepositoryImpl, ContractWatcher, DB_VERSION, DEFAULT_MESSAGE_TIMEOUTS, DEFAULT_MIN_BATCH_EXPIRY_SECONDS, DEFAULT_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, DelegateManagerImpl, DelegateNotConfiguredError, DelegatorManagerImpl, DelegatorNotConfiguredError, DescriptorIdentity, DescriptorSigningProviderMissingError, DustChangeError, ELECTRUM_TCP_HOST, ELECTRUM_WS_URL, ESPLORA_URL, ElectrumOnchainProvider, EmulatorPacket, EsploraProvider, Estimator, Extension, ExtensionNotFoundError, HDDescriptorProvider, INTENT_TERMINAL_STATES, InMemoryContractRepository, InMemoryIntentRepository, InMemoryVirtualTxRepository, InMemoryWalletRepository, IndexedDBContractRepository, IndexedDBIntentRepository, IndexedDBVirtualTxRepository, IndexedDBWalletRepository, MAX_USED_SIGNING_DESCRIPTORS_LOOK_AHEAD, MESSAGE_BUS_INITIALIZING, MESSAGE_BUS_NOT_INITIALIZED, MIGRATION_KEY, MUTINYNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, MessageBus, MessageBusInitializingError, MessageBusNotInitializedError, MissingSigningDescriptorError, MnemonicIdentity, OnchainWallet, P2A, PaymentRouter, REGTEST_MIN_BATCH_EXPIRY_SECONDS, REGTEST_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, Ramps, ReadonlyAssetManager, ReadonlyDescriptorIdentity, ReadonlySingleKey, ReadonlyWallet, ReadonlyWalletError, RestDelegateProvider, RestDelegatorProvider, RestEmulatorProvider, SIGNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, SeedIdentity, ServiceWorkerReadonlyWallet, ServiceWorkerTimeoutError, ServiceWorkerWallet, SingleKey, TxTree, TxType, TxWeightEstimator, UnannotatableInputError, UnilateralExit, UnknownPacket, Unroll, VtxoManager, Wallet2 as Wallet, WalletMessageHandler, WalletNotInitializedError, WalletRepositoryImpl, WsElectrumChainSource, arkRail, arkTarget, arkade_exports, assertFinalCommitmentMatchesValidated, assertIntentIdUnique, assertSendableAmount, assertSubmittedArkTxid, assertValidBatchExpiry, assertValidServerUnrollScript, assetMintResolver, boardingResolver, btcTarget, buildForfeitTx, buildOffchainTx, claimWithPreimageIdentity, classifyAgainstSignerSet, classifyContractSigner, closeDatabase, collabExitResolver, combineTapscriptSigs, contractFromArkContract, contractFromArkContractWithAddress, createAssetPacket, createDefaultActivityRegistry, createDefaultPaymentRouter, createExitChainResolver, decodeArkContract, defaultBatchExpiryPolicy, defaultCheckpointExitDelayPolicy, deserializeAssets, deserializeExitPackage, deserializeUtxo, deserializeVtxo, encodeArkContract, extendVirtualCoinForContract, gateExclusion, gatedContracts, getMigrationStatus, getRandomId, hasBoardingTxExpired, hasCandidates, intentMatchesFilter, intentPageBounds, invoiceTarget, isArkContract, isBatchSignable, isBtcAddress, isContractGenericallySpendable, isCooperativelyMigratable, isDiscoverable, isHDAllocationCapable, isHDDeterministicSignCapable, isHDWalletCapable, isLightningInvoice, isLnurl, isMessageBusInitializingError, isMessageBusNotInitializedError, isSubdust, isTerminalIntentState, isValidArkAddress, isVtxoExpiringSoon, isVtxoForScript, isWatchedContract, logExcludedVtxos, makeHandle, matchServerCheckpoints, mergeChainedTxType, migrateWalletRepository, onchainRail, openDatabase, outpointExclusion, requiresMigration, resolveBatchExpiryPolicy, resolveCheckpointExitDelayPolicy, resolveSendAmount, rollbackMigration, saveVtxosForContract, scriptFromArkAddress, selectCoinsWithAsset, selectVirtualCoins, serializeAssets, serializeExitPackage, serializeUtxo, serializeVtxo, setupServiceWorker, signAndSubmitOffchainTx, signerSetFromInfo, signingDescriptorIndex, strictSigningDescriptorIndex, toXOnlySignerHex, tryResolveSendAmount, validateBatchRecipients, validateConnectorsTxGraph, validateVtxoTxGraph, verifyTapscriptSignatures, waitForIncomingFunds, warnAndFilterVtxosForScript };
22025
- //# sourceMappingURL=chunk-Y54MUBT7.js.map
22026
- //# sourceMappingURL=chunk-Y54MUBT7.js.map
22757
+ export { ARKADE_MAGIC, ARKADE_SALTED_PREIMAGE_TAG, ARKADE_SWAP_PREIMAGE_TAG, ActivityRegistry, AmbiguousRouteError, ArkNote, ArkadeCash, ArkadeCashCreateError, AssetManager, BIP21, BIP21Error, BIP322, Batch, ChainedTxType, ContractManager, ContractRepositoryImpl, ContractWatcher, DB_VERSION, DEFAULT_MESSAGE_TIMEOUTS, DEFAULT_MIN_BATCH_EXPIRY_SECONDS, DEFAULT_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, DelegateManagerImpl, DelegateNotConfiguredError, DelegatorManagerImpl, DelegatorNotConfiguredError, DescriptorIdentity, DescriptorSigningProviderMissingError, DustChangeError, ELECTRUM_TCP_HOST, ELECTRUM_WS_URL, ESPLORA_URL, ElectrumOnchainProvider, EmulatorPacket, EsploraProvider, Estimator, Extension, ExtensionNotFoundError, ForeignDescriptorError, HDDescriptorProvider, INTENT_TERMINAL_STATES, InMemoryContractRepository, InMemoryIntentRepository, InMemoryVirtualTxRepository, InMemoryWalletRepository, IndexedDBContractRepository, IndexedDBIntentRepository, IndexedDBVirtualTxRepository, IndexedDBWalletRepository, MAX_USED_SIGNING_DESCRIPTORS_LOOK_AHEAD, MESSAGE_BUS_INITIALIZING, MESSAGE_BUS_NOT_INITIALIZED, MIGRATION_KEY, MUTINYNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, MessageBus, MessageBusInitializingError, MessageBusNotInitializedError, MissingSigningDescriptorError, MnemonicIdentity, OnchainWallet, P2A, PaymentRouter, REGTEST_MIN_BATCH_EXPIRY_SECONDS, REGTEST_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, Ramps, ReadonlyAssetManager, ReadonlyDescriptorIdentity, ReadonlySingleKey, ReadonlyWallet, ReadonlyWalletError, RestDelegateProvider, RestDelegatorProvider, RestEmulatorProvider, SIGNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS, SeedIdentity, ServiceWorkerReadonlyWallet, ServiceWorkerTimeoutError, ServiceWorkerWallet, SingleKey, TxTree, TxType, TxWeightEstimator, UnannotatableInputError, UnilateralExit, UnknownPacket, Unroll, VtxoManager, Wallet2 as Wallet, WalletCannotSignError, WalletMessageHandler, WalletNotInitializedError, WalletRepositoryImpl, WsElectrumChainSource, adoptContractDescriptor, arkRail, arkTarget, arkade_exports, assertFinalCommitmentMatchesValidated, assertIntentIdUnique, assertSendableAmount, assertSubmittedArkTxid, assertValidBatchExpiry, assertValidServerUnrollScript, assetMintResolver, boardingResolver, btcTarget, buildForfeitTx, buildOffchainTx, buildPreimageMessage, buildSaltedPreimageMessage, claimWithPreimageIdentity, classifyAgainstSignerSet, classifyContractSigner, closeDatabase, collabExitResolver, combineTapscriptSigs, contractFromArkContract, contractFromArkContractWithAddress, contractPreimage, contractSigner, createAssetPacket, createDefaultActivityRegistry, createDefaultPaymentRouter, createExitChainResolver, decodeArkContract, defaultBatchExpiryPolicy, defaultCheckpointExitDelayPolicy, deserializeAssets, deserializeExitPackage, deserializeUtxo, deserializeVtxo, encodeArkContract, extendVirtualCoinForContract, gateExclusion, gatedContracts, getMigrationStatus, getRandomId, hasBoardingTxExpired, hasCandidates, intentMatchesFilter, intentPageBounds, invoiceTarget, isArkContract, isBatchSignable, isBtcAddress, isContractGenericallySpendable, isCooperativelyMigratable, isDeterministicSigner, isDiscoverable, isHDAllocationCapable, isHDDeterministicSignCapable, isHDWalletCapable, isLightningInvoice, isLnurl, isMessageBusInitializingError, isMessageBusNotInitializedError, isPerArtifactDescriptor, isSigningIdentity, isSubdust, isTerminalIntentState, isValidArkAddress, isVtxoExpiringSoon, isVtxoForScript, isWatchedContract, logExcludedVtxos, makeHandle, matchServerCheckpoints, mergeChainedTxType, migrateWalletRepository, onchainRail, openDatabase, outpointExclusion, outpointReasons, provisionClaimSecret, provisionRefundKey, requiresMigration, resolveBatchExpiryPolicy, resolveCheckpointExitDelayPolicy, resolveDescriptorSigner, resolveSendAmount, rollbackMigration, saveVtxosForContract, scriptFromArkAddress, selectCoinsWithAsset, selectVirtualCoins, serializeAssets, serializeExitPackage, serializeUtxo, serializeVtxo, setupServiceWorker, signAndSubmitOffchainTx, signerSetFromInfo, signingDescriptorIndex, strictSigningDescriptorIndex, toXOnlySignerHex, tryResolveSendAmount, validateBatchRecipients, validateConnectorsTxGraph, validateVtxoTxGraph, verifyTapscriptSignatures, waitForIncomingFunds, warnAndFilterVtxosForScript };
22758
+ //# sourceMappingURL=chunk-2IZW6AEK.js.map
22759
+ //# sourceMappingURL=chunk-2IZW6AEK.js.map