@anywalletkit/wallet-btc 0.2.1 → 0.2.3

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/index.cjs CHANGED
@@ -588,6 +588,7 @@ var DUST_LIMIT_P2TR = dustLimit("tr");
588
588
  var kindOfType = (type) => type === "p2tr" ? "tr" : "wpkh";
589
589
 
590
590
  // src/describe.ts
591
+ var import_core7 = require("@anywalletkit/core");
591
592
  var DEFAULT_MAX_FEE_RATE = 500;
592
593
  var RBF_SEQUENCE = 4294967293;
593
594
  var FINAL_SEQUENCE = 4294967294;
@@ -622,7 +623,7 @@ function describeTransaction(tx, inputValues, ctx) {
622
623
  const fee = inputSum - outputSum;
623
624
  const amount = outputs.filter((o) => o.role !== "change").reduce((s, o) => s + o.value, 0n);
624
625
  const vsize = vsizeOf(tx);
625
- const feeRate = vsize > 0 ? Math.round(Number(fee) / vsize * 100) / 100 : 0;
626
+ const feeRate = vsize > 0 ? Math.round((0, import_core7.bigintToNumber)(fee) / vsize * 100) / 100 : 0;
626
627
  if (feeRate > (ctx.maxFeeRate ?? DEFAULT_MAX_FEE_RATE)) warnings.add("high-fee-rate");
627
628
  if (amount > 0n && fee * 10n > amount) warnings.add("fee-over-10pct-of-amount");
628
629
  if (!outputs.some((o) => o.role === "change")) warnings.add("no-change");
@@ -668,7 +669,7 @@ var coinType = (network) => network === "bitcoin" ? 0 : 1;
668
669
  var purposeFor = (type) => type === "p2tr" ? 86 : 84;
669
670
 
670
671
  // src/read-only-account.ts
671
- var import_core7 = require("@anywalletkit/core");
672
+ var import_core8 = require("@anywalletkit/core");
672
673
  var toBig = (v) => typeof v === "bigint" ? v : BigInt(Math.round(Number(v)));
673
674
  var WalletAccountReadOnlyBtc = class {
674
675
  /** The address. */
@@ -700,7 +701,7 @@ var WalletAccountReadOnlyBtc = class {
700
701
  this._client = createClient(config);
701
702
  }
702
703
  requireClient(what) {
703
- if (!this._client) throw new import_core7.NetworkError(`The wallet must be connected to a client to ${what}.`);
704
+ if (!this._client) throw new import_core8.NetworkError(`The wallet must be connected to a client to ${what}.`);
704
705
  return this._client;
705
706
  }
706
707
  /** Fee-rate ceiling in sat/vB: `BtcConfig.maxFeeRate` or {@link DEFAULT_MAX_FEE_RATE}. */
@@ -742,7 +743,7 @@ var WalletAccountReadOnlyBtc = class {
742
743
  const inputWeight = this.inputWeight();
743
744
  const feeRate = await this.resolveFeeRate(spend);
744
745
  const utxos = await this.requireClient("plan a spend").listUnspent(this.address);
745
- if (utxos.length === 0) throw new import_core7.InsufficientFundsError(amount, 0n, "BTC");
746
+ if (utxos.length === 0) throw new import_core8.InsufficientFundsError(amount, 0n, "BTC");
746
747
  const own = kindOfType(this.addressType);
747
748
  const selection = selectCoins({
748
749
  utxos,
@@ -817,7 +818,7 @@ var WalletAccountReadOnlyBtc = class {
817
818
  };
818
819
 
819
820
  // src/account.ts
820
- var import_core8 = require("@anywalletkit/core");
821
+ var import_core9 = require("@anywalletkit/core");
821
822
  var import_btc_signer4 = require("@scure/btc-signer");
822
823
  var import_secp256k12 = require("@noble/curves/secp256k1.js");
823
824
  var import_base3 = require("@scure/base");
@@ -841,15 +842,15 @@ var WalletAccountBtc = class _WalletAccountBtc extends WalletAccountReadOnlyBtc
841
842
  const type = config.addressType ?? "p2wpkh";
842
843
  super(addressFromPublicKey(publicKey, networkParams(config.network ?? "bitcoin"), type), config);
843
844
  this.addressType = type;
844
- this.signer = (0, import_core8.requireCurve)(signer, "secp256k1");
845
+ this.signer = (0, import_core9.requireCurve)(signer, "secp256k1");
845
846
  const needed = type === "p2tr" ? "schnorr" : "ecdsa";
846
- if (!this.signer.schemes.includes(needed)) throw new import_core8.SignerError(`A ${type} account needs a signer with the '${needed}' scheme (has: ${this.signer.schemes.join(", ")}).`);
847
+ if (!this.signer.schemes.includes(needed)) throw new import_core9.SignerError(`A ${type} account needs a signer with the '${needed}' scheme (has: ${this.signer.schemes.join(", ")}).`);
847
848
  this.publicKey = publicKey;
848
849
  this.path = path;
849
850
  }
850
851
  /** Back-compat: wrap a raw derived key in a {@link LocalSigner} (the account takes ownership; it cannot derive). */
851
852
  static fromPrivateKey(privateKey, publicKey, path, config = {}) {
852
- return new _WalletAccountBtc(import_core8.LocalSigner.fromPrivateKey("secp256k1", privateKey, publicKey, path), publicKey, path, config);
853
+ return new _WalletAccountBtc(import_core9.LocalSigner.fromPrivateKey("secp256k1", privateKey, publicKey, path), publicKey, path, config);
853
854
  }
854
855
  /** Account index for the standard m/{84|86}'/{0|1}'/0'/0/i path. */
855
856
  get index() {
@@ -857,7 +858,7 @@ var WalletAccountBtc = class _WalletAccountBtc extends WalletAccountReadOnlyBtc
857
858
  return m ? Number(m[1]) : void 0;
858
859
  }
859
860
  live() {
860
- if (this._disposed) throw new import_core8.SignerError("This account has been disposed.");
861
+ if (this._disposed) throw new import_core9.SignerError("This account has been disposed.");
861
862
  }
862
863
  /** BIP-137 p2wpkh signature, base64 (Electrum / Bitcoin Core encoding). Not available for taproot accounts. */
863
864
  async sign(message) {
@@ -932,7 +933,7 @@ var WalletAccountBtc = class _WalletAccountBtc extends WalletAccountReadOnlyBtc
932
933
  const delta = required - fee;
933
934
  if (change === 0n) {
934
935
  const have = plan.utxos.reduce((s, u) => s + u.value, 0n);
935
- throw new import_core8.InsufficientFundsError(plan.amount + required, have, "BTC");
936
+ throw new import_core9.InsufficientFundsError(plan.amount + required, have, "BTC");
936
937
  }
937
938
  change = change - delta;
938
939
  if (change < this.dustLimit) {
@@ -1013,18 +1014,18 @@ var WalletAccountBtc = class _WalletAccountBtc extends WalletAccountReadOnlyBtc
1013
1014
  return (await this.buildSignedTransaction(tx)).desc;
1014
1015
  }
1015
1016
  /** Sign without broadcasting. Returns the raw transaction hex. Raw hex input is returned unchanged. */
1016
- async signTransaction(tx) {
1017
+ async signTransaction(tx, options = {}) {
1017
1018
  this.live();
1018
1019
  if (typeof tx === "string") return tx;
1019
1020
  const { tx: built, fee } = await this.buildSignedTransaction(tx);
1020
- this.checkMax(fee, this._config.transactionMaxFee, "transaction");
1021
+ this.checkMax(fee, (0, import_core9.feeLimit)(this._config.transactionMaxFee, options), "transaction");
1021
1022
  return built.hex;
1022
1023
  }
1023
1024
  async quoteSendTransaction(tx) {
1024
1025
  if (typeof tx === "string") return { fee: (await this.describeRaw(tx)).desc.fee };
1025
1026
  return super.quoteSendTransaction(tx);
1026
1027
  }
1027
- async sendTransaction(tx) {
1028
+ async sendTransaction(tx, options = {}) {
1028
1029
  this.live();
1029
1030
  const client = this.requireClient("send transactions");
1030
1031
  let rawHex, hash, fee;
@@ -1039,17 +1040,17 @@ var WalletAccountBtc = class _WalletAccountBtc extends WalletAccountReadOnlyBtc
1039
1040
  hash = built.tx.id;
1040
1041
  fee = built.fee;
1041
1042
  }
1042
- this.checkMax(fee, this._config.transactionMaxFee, "transaction");
1043
+ this.checkMax(fee, (0, import_core9.feeLimit)(this._config.transactionMaxFee, options), "transaction");
1043
1044
  const txid = await client.broadcast(rawHex);
1044
1045
  return { hash: txid || hash, fee };
1045
1046
  }
1046
1047
  /** Native BTC only (`token` is rejected). Subject to `transferMaxFee`. */
1047
- async transfer(o) {
1048
+ async transfer(o, writeOptions = {}) {
1048
1049
  if (o.token) throw new Error("Tokens are not supported on the bitcoin blockchain.");
1049
1050
  this.live();
1050
1051
  const client = this.requireClient("transfer");
1051
1052
  const built = await this.buildSignedTransaction({ to: o.recipient, value: o.amount });
1052
- this.checkMax(built.fee, this._config.transferMaxFee, "transfer");
1053
+ this.checkMax(built.fee, (0, import_core9.feeLimit)(this._config.transferMaxFee, writeOptions), "transfer");
1053
1054
  const txid = await client.broadcast(built.tx.hex);
1054
1055
  return { hash: txid || built.tx.id, fee: built.fee };
1055
1056
  }
@@ -1065,8 +1066,8 @@ var WalletAccountBtc = class _WalletAccountBtc extends WalletAccountReadOnlyBtc
1065
1066
  };
1066
1067
 
1067
1068
  // src/manager.ts
1068
- var import_core9 = require("@anywalletkit/core");
1069
- var WalletManagerBtc = class extends import_core9.WalletManager {
1069
+ var import_core10 = require("@anywalletkit/core");
1070
+ var WalletManagerBtc = class extends import_core10.WalletManager {
1070
1071
  constructor(seedOrSigner, config = {}) {
1071
1072
  super(seedOrSigner, config);
1072
1073
  }
@@ -1086,30 +1087,26 @@ var WalletManagerBtc = class extends import_core9.WalletManager {
1086
1087
  if (cached) return cached;
1087
1088
  const external = this.externalSigner();
1088
1089
  if (external) return this.fromSigner(external, full);
1089
- const signer = import_core9.LocalSigner.leafFromSeed(this.seedBytes(), "secp256k1", full);
1090
- const account = new WalletAccountBtc(signer, signer.publicKey, full, this._config);
1091
- this._accounts.set(full, account);
1092
- return account;
1090
+ return this.cachedAccount(full, () => {
1091
+ const signer = import_core10.LocalSigner.leafFromSeed(this.seedBytes(), "secp256k1", full);
1092
+ return new WalletAccountBtc(signer, signer.publicKey, full, this._config);
1093
+ });
1093
1094
  }
1094
1095
  /** Resolve `path` against an injected signer: the signer itself, or a child when it can derive there. */
1095
1096
  async fromSigner(signer, path) {
1096
1097
  this.requireSigner("secp256k1");
1097
- let leaf = signer;
1098
+ let rel;
1098
1099
  let key = "external";
1099
- if ((0, import_core9.isSeedSigner)(signer)) {
1100
+ if ((0, import_core10.isSeedSigner)(signer)) {
1100
1101
  if (path === signer.path) key = path;
1101
1102
  else if (path.startsWith(`${signer.path}/`)) {
1102
- leaf = await (signer.deriveLeaf ?? signer.derive).call(signer, path.slice(signer.path.length + 1));
1103
+ rel = path.slice(signer.path.length + 1);
1103
1104
  key = path;
1104
- } else throw new import_core9.SignerError(`The injected signer sits at ${signer.path}; it cannot provide ${path}.`);
1105
+ } else throw new import_core10.SignerError(`The injected signer sits at ${signer.path}; it cannot provide ${path}.`);
1105
1106
  } else if (path !== `${this.basePath}/0'/0/0` && path !== "external") {
1106
- throw new import_core9.SignerError(`An external signer has one account; ${path} is not derivable from it.`);
1107
+ throw new import_core10.SignerError(`An external signer has one account; ${path} is not derivable from it.`);
1107
1108
  }
1108
- const cached = this._accounts.get(key);
1109
- if (cached) return cached;
1110
- const account = new WalletAccountBtc(leaf, await leaf.getPublicKey(), key, this._config);
1111
- this._accounts.set(key, account);
1112
- return account;
1109
+ return this.signerAccount(key, signer, rel, (leaf, publicKey) => new WalletAccountBtc(leaf, publicKey, key, this._config));
1113
1110
  }
1114
1111
  /** A read-only account for any address, with this manager's config. */
1115
1112
  getReadOnlyAccount(address) {
@@ -1251,7 +1248,7 @@ function createBtcHistory(options = {}) {
1251
1248
  const pageNo = cursor?.p ?? 1;
1252
1249
  const data = await failover((c) => c.getAddressPage(address, pageNo, pageSize));
1253
1250
  let items = (data.transactions ?? []).map((tx) => mapBlockbookTx(chain, address, tx));
1254
- items.sort((a, b) => (b.block === void 0 ? 1 : a.block === void 0 ? -1 : Number(b.block - a.block)) || b.time - a.time);
1251
+ items.sort((a, b) => (b.block === void 0 ? 1 : a.block === void 0 ? -1 : b.block > a.block ? 1 : b.block < a.block ? -1 : 0) || b.time - a.time);
1255
1252
  const totalPages = data.totalPages ?? 1;
1256
1253
  let more = pageNo < totalPages;
1257
1254
  if (query.since !== void 0) {