@anywalletkit/wallet-zcash 0.3.1 → 0.5.0

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
@@ -128,7 +128,8 @@ function encodeAddress(kind, hash, network) {
128
128
  return b58.encode(Uint8Array.of(a, b, ...hash));
129
129
  }
130
130
  function decodeAddress(address, network) {
131
- const a = address.trim();
131
+ if (typeof address !== "string" || /\s/.test(address)) throw new Error(`Invalid Zcash address: it carries whitespace or an invisible character (${JSON.stringify(address)}).`);
132
+ const a = address;
132
133
  if (/^u1|^utest/i.test(a)) throw new Error(`Unified address (${a.slice(0, 6)}\u2026) \u2014 shielded receivers are not supported; use a transparent t-address.`);
133
134
  if (/^zs1|^ztestsapling/i.test(a)) throw new Error("Sapling shielded address (zs1\u2026) \u2014 this wallet sends to transparent t-addresses only.");
134
135
  if (/^zc/i.test(a) && a.length > 90) throw new Error("Sprout address (zc\u2026) \u2014 the Sprout pool is deprecated; use a transparent t-address.");
@@ -1103,15 +1104,22 @@ var WalletAccountZcash = class _WalletAccountZcash extends WalletAccountReadOnly
1103
1104
  path;
1104
1105
  /** Compressed secp256k1 public key. */
1105
1106
  publicKey;
1106
- /** The signer that holds the key. */
1107
- signer;
1107
+ /**
1108
+ * The signer that holds the key, in a private field: not a property of the account, so no code
1109
+ * the account is handed to (a protocol module, a logger) can reach it and sign around the
1110
+ * account's checks (audit 2026-10-29 A1).
1111
+ */
1112
+ #signer;
1113
+ /** What holds the key: `seed`, `key` (one imported key) or `external`. */
1114
+ signerKind;
1108
1115
  _disposed = false;
1109
1116
  _readOnly;
1110
1117
  /** `publicKey` is the signer's compressed secp256k1 key (33 bytes); it is needed synchronously for the address. */
1111
1118
  constructor(signer, publicKey, path, config = {}) {
1112
1119
  super(addressFromPublicKey(publicKey, config.network ?? "mainnet"), config);
1113
- this.signer = (0, import_core7.requireCurve)(signer, "secp256k1");
1114
- if (!this.signer.schemes.includes("ecdsa")) throw new import_core7.SignerError(`A Zcash account needs a signer with the 'ecdsa' scheme (has: ${this.signer.schemes.join(", ")}).`);
1120
+ this.#signer = (0, import_core7.requireCurve)(signer, "secp256k1");
1121
+ this.signerKind = this.#signer.kind;
1122
+ if (!this.#signer.schemes.includes("ecdsa")) throw new import_core7.SignerError(`A Zcash account needs a signer with the 'ecdsa' scheme (has: ${this.#signer.schemes.join(", ")}).`);
1115
1123
  this.publicKey = publicKey;
1116
1124
  this.path = path;
1117
1125
  }
@@ -1130,7 +1138,7 @@ var WalletAccountZcash = class _WalletAccountZcash extends WalletAccountReadOnly
1130
1138
  /** Zcash message signature (zcashd `signmessage` encoding), base64. */
1131
1139
  async sign(message) {
1132
1140
  this.live();
1133
- return signMessageWith(message, this.signer);
1141
+ return signMessageWith(message, this.#signer);
1134
1142
  }
1135
1143
  ctx(intended) {
1136
1144
  return { network: this._network, ownAddress: this.address, intended, maxFee: this.maxFee };
@@ -1159,15 +1167,15 @@ var WalletAccountZcash = class _WalletAccountZcash extends WalletAccountReadOnly
1159
1167
  return { lockTime, expiryHeight, consensusBranchId };
1160
1168
  }
1161
1169
  /** Sign every input through the signer; the scriptSig is `<DER ‖ 0x01> <pubkey>`. */
1162
- async signInputs(tx, spent) {
1170
+ async #signInputs(tx, spent) {
1163
1171
  for (let i = 0; i < tx.inputs.length; i++) {
1164
1172
  const digest = sighashAll(tx, i, spent);
1165
- const rs = await this.signer.sign(digest, { scheme: "ecdsa", context: "zcash-sighash" });
1173
+ const rs = await this.#signer.sign(digest, { scheme: "ecdsa", context: "zcash-sighash" });
1166
1174
  const der = import_secp256k12.secp256k1.Signature.fromBytes(rs, "compact").toBytes("der");
1167
1175
  tx.inputs[i].scriptSig = p2pkhScriptSig(der, this.publicKey);
1168
1176
  }
1169
1177
  }
1170
- async signSpend(spend) {
1178
+ async #signSpend(spend) {
1171
1179
  this.live();
1172
1180
  const plan = await this.planSpend(spend);
1173
1181
  const params = await this.chainParams();
@@ -1179,7 +1187,7 @@ var WalletAccountZcash = class _WalletAccountZcash extends WalletAccountReadOnly
1179
1187
  const spent = plan.utxos.map((u) => ({ value: u.value, script: this.scriptPubKey }));
1180
1188
  const have = plan.utxos.reduce((s, u) => s + u.value, 0n);
1181
1189
  if (have < plan.amount + plan.fee) throw new import_core7.InsufficientFundsError(plan.amount + plan.fee, have, "ZEC");
1182
- await this.signInputs(tx, spent);
1190
+ await this.#signInputs(tx, spent);
1183
1191
  const ctx = this.ctx({ to: spend.to, value: plan.amount });
1184
1192
  const desc = describeTransaction(tx, spent, ctx);
1185
1193
  assertSafe(desc, ctx);
@@ -1211,7 +1219,7 @@ var WalletAccountZcash = class _WalletAccountZcash extends WalletAccountReadOnly
1211
1219
  /** "What you sign": the fully resolved spend (signed, NOT broadcast) or a caller's raw hex. */
1212
1220
  async describeTransaction(tx) {
1213
1221
  if (typeof tx === "string") return (await this.describeRaw(tx)).desc;
1214
- return (await this.signSpend(tx)).desc;
1222
+ return (await this.#signSpend(tx)).desc;
1215
1223
  }
1216
1224
  /** Sign without broadcasting. Returns the raw transaction hex. Raw hex input gets the checks `sendTransaction` runs (prevouts through the client) and is returned unchanged, never re-signed. */
1217
1225
  async signTransaction(tx, options = {}) {
@@ -1221,7 +1229,7 @@ var WalletAccountZcash = class _WalletAccountZcash extends WalletAccountReadOnly
1221
1229
  this.checkMax(desc.fee, (0, import_core7.feeLimit)(this._config.transactionMaxFee, options), "transaction");
1222
1230
  return tx;
1223
1231
  }
1224
- const built = await this.signSpend(tx);
1232
+ const built = await this.#signSpend(tx);
1225
1233
  this.checkMax(built.fee, (0, import_core7.feeLimit)(this._config.transactionMaxFee, options), "transaction");
1226
1234
  return built.hex;
1227
1235
  }
@@ -1239,7 +1247,7 @@ var WalletAccountZcash = class _WalletAccountZcash extends WalletAccountReadOnly
1239
1247
  hash = txid(parsed);
1240
1248
  fee = desc.fee;
1241
1249
  } else {
1242
- const built = await this.signSpend(tx);
1250
+ const built = await this.#signSpend(tx);
1243
1251
  rawHex = built.hex;
1244
1252
  hash = built.txid;
1245
1253
  fee = built.fee;
@@ -1252,7 +1260,7 @@ var WalletAccountZcash = class _WalletAccountZcash extends WalletAccountReadOnly
1252
1260
  if (o.token) throw new Error("Tokens are not supported on the zcash blockchain.");
1253
1261
  this.live();
1254
1262
  const client = this.requireClient("transfer");
1255
- const built = await this.signSpend({ to: o.recipient, value: o.amount });
1263
+ const built = await this.#signSpend({ to: o.recipient, value: o.amount });
1256
1264
  this.checkMax(built.fee, (0, import_core7.feeLimit)(this._config.transferMaxFee, writeOptions), "transfer");
1257
1265
  return { hash: await this.broadcast(client, built.hex, built.txid), fee: built.fee };
1258
1266
  }
@@ -1277,7 +1285,7 @@ var WalletAccountZcash = class _WalletAccountZcash extends WalletAccountReadOnly
1277
1285
  }
1278
1286
  dispose() {
1279
1287
  this._disposed = true;
1280
- this.signer.dispose();
1288
+ this.#signer.dispose();
1281
1289
  }
1282
1290
  };
1283
1291