@anywalletkit/wallet-near 0.1.9 → 0.3.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.d.cts CHANGED
@@ -266,7 +266,7 @@ declare const STORAGE_DEPOSIT_GAS: bigint;
266
266
  declare const IMPLICIT_ACCOUNT_MIN_DEPOSIT: bigint;
267
267
 
268
268
  /** Why a transaction was refused before signing. */
269
- type UnsafeTransactionCode = 'signer-mismatch' | 'public-key-mismatch' | 'dangerous-action' | 'invalid-account' | 'no-actions' | 'gas-limit' | 'fee-limit' | 'missing-block-hash' | 'missing-nonce' | 'unknown-action' | 'insufficient-balance' | 'implicit-account-min-deposit' | 'no-access-key' | 'storage-deposit';
269
+ type UnsafeTransactionCode = 'signer-mismatch' | 'public-key-mismatch' | 'dangerous-action' | 'invalid-account' | 'no-actions' | 'gas-limit' | 'fee-limit' | 'missing-block-hash' | 'missing-nonce' | 'unknown-action' | 'insufficient-balance' | 'implicit-account-min-deposit' | 'no-access-key' | 'storage-deposit' | 'non-canonical' | 'invalid-method' | 'malformed-action';
270
270
  /** A transaction failed a hard check and was not signed. */
271
271
  declare class UnsafeTransactionError extends Error {
272
272
  readonly code: UnsafeTransactionCode;
@@ -395,8 +395,11 @@ declare const ACTION_TAG: {
395
395
  readonly useGlobalContract: 10;
396
396
  };
397
397
  type NearActionKey = keyof typeof ACTION_TAG;
398
+ /** The one key an action object has. Two keys (a deleteAccount next to a functionCall) is no action: whichever a reader picks, another reader may pick the other (scan 2026-10-27 F6). */
398
399
  declare function actionKey(a: NearAction): NearActionKey;
399
- /** Function-call args as bytes: raw bytes pass through; objects / strings become UTF-8 JSON / UTF-8. */
400
+ /** A plain `{…}` object: not an array, not a class instance. */
401
+ declare function isPlainObject(v: unknown): v is Record<string, unknown>;
402
+ /** Function-call args as bytes: raw bytes pass through; plain objects / strings become UTF-8 JSON / UTF-8. Anything else throws. */
400
403
  declare function argsBytes(args: Uint8Array | Record<string, unknown> | string): Uint8Array;
401
404
  declare function writeAction(w: BorshWriter, a: NearAction): void;
402
405
  declare function readAction(r: BorshReader): NearAction;
@@ -618,6 +621,13 @@ declare class WalletAccountReadOnlyNear implements IWalletAccountReadOnly {
618
621
  }
619
622
  declare function receiptOf(hash: string, o: RawFinalOutcome): NearReceipt;
620
623
  declare function parseSignature(signature: string): Uint8Array;
624
+ /**
625
+ * An object transaction has exactly the shape the encoder writes, before it is built or signed (also
626
+ * `signBuilt`): every action one known key; a function call's `methodName` a string of the method
627
+ * grammar, `args` bytes, a string or a plain object, `gas` / `deposit` bigints; every account id and
628
+ * method name well formed. What the policies read is then what gets encoded (scan 2026-10-27 F6, F28).
629
+ */
630
+ declare function assertWellFormed(tx: Pick<NearBuiltTransaction, 'receiverId' | 'actions'>): void;
621
631
 
622
632
  interface NearTransferResult extends TransferResult {
623
633
  estimate?: NearFeeEstimate;
@@ -633,12 +643,13 @@ interface NearTransferResult extends TransferResult {
633
643
  * `accountId` for a named account whose full-access key this is.
634
644
  */
635
645
  declare class WalletAccountNear extends WalletAccountReadOnlyNear implements IWalletAccount {
646
+ #private;
636
647
  /** nonce / block hash come from the node, so building needs the network. */
637
648
  readonly needsNetwork = true;
638
649
  /** Derivation path, or `external` for an external signer. */
639
650
  readonly path: string;
640
- /** The signer that holds the key. */
641
- readonly signer: Signer;
651
+ /** What holds the key: `seed`, `key` (one imported key) or `external`. */
652
+ readonly signerKind: Signer['kind'];
642
653
  private _disposed;
643
654
  private _readOnly;
644
655
  constructor(signer: Signer, publicKey: Uint8Array, path: string, config?: NearConfig, accountId?: string);
@@ -649,7 +660,6 @@ declare class WalletAccountNear extends WalletAccountReadOnlyNear implements IWa
649
660
  /** The same key bound to a named account (`alice.near`) that lists it as a full-access key. */
650
661
  withAccountId(accountId: string): WalletAccountNear;
651
662
  private key;
652
- private signBytes;
653
663
  /**
654
664
  * Raw ed25519 signature over the message bytes, as NEAR tooling prints it: "ed25519:<base58>".
655
665
  * A 32-byte message — string or bytes — is refused with {@link MessageIsTransactionError}: a NEAR
@@ -709,4 +719,4 @@ declare class WalletManagerNear extends WalletManager<WalletAccountNear, NearCon
709
719
  getFeeRates(): Promise<FeeRates>;
710
720
  }
711
721
 
712
- export { ACTION_TAG, BorshReader, BorshWriter, BroadcastUnknownError, CAIP2, DANGEROUS_ACTIONS, type DescribeContext, FT_TRANSFER_GAS, IMPLICIT_ACCOUNT_MIN_DEPOSIT, MAX_GAS, MessageIsTransactionError, NEAR_BASE_PATH, NEP413_PREFIX, type NearAccessKey, type NearAccountView, type NearAction, type NearAddKeyAction, type NearBuiltTransaction, type NearConfig, type NearCreateAccountAction, type NearDelegateAction, type NearDeleteAccountAction, type NearDeleteKeyAction, type NearDeployContractAction, type NearDeployGlobalContractAction, type NearFeeEstimate, type NearFetch, type NearFunctionCallAction, type NearProvider, type NearPublicKey, type NearQuote, type NearReceipt, NearRpc, NearRpcError, type NearSignature, type NearSignedDelegateAction, type NearSignedTransaction, type NearSimulation, type NearStakeAction, type NearTransaction, type NearTransferAction, type NearTransferOptions, type NearTransferResult, type NearTxDescription, type NearTxKind, type NearTxWarning, type NearTxWarningCode, type NearUseGlobalContractAction, type Nep413Payload, type Nep413Signed, ONE_YOCTO, type RawAccessKeyView, type RawAccountView, type RawFinalOutcome, STORAGE_DEPOSIT_GAS, STORAGE_PRICE_PER_BYTE, SimulationError, TGAS, type UnsafeTransactionCode, UnsafeTransactionError, WalletAccountNear, WalletAccountReadOnlyNear, WalletManagerNear, YOCTO, actionKey, argsBytes, base58ToBytes, bytesToBase58, createClient, decodeAnyTransaction, decodeSignedTransaction, decodeTransaction, WalletManagerNear as default, describeTransaction, ed25519Key, encodeSignedTransaction, encodeTransaction, failureOf, fromBase64, implicitAccountId, isDangerous, isImplicitAccountId, isValidAccountId, nep413Bytes, nep413Hash, outcomeFailed, parsePublicKey, parseSignature, publicKeyOfImplicit, publicKeyToString, readAction, readPublicKey, readSignature, receiptOf, toBase64, writeAction, writePublicKey, writeSignature };
722
+ export { ACTION_TAG, BorshReader, BorshWriter, BroadcastUnknownError, CAIP2, DANGEROUS_ACTIONS, type DescribeContext, FT_TRANSFER_GAS, IMPLICIT_ACCOUNT_MIN_DEPOSIT, MAX_GAS, MessageIsTransactionError, NEAR_BASE_PATH, NEP413_PREFIX, type NearAccessKey, type NearAccountView, type NearAction, type NearAddKeyAction, type NearBuiltTransaction, type NearConfig, type NearCreateAccountAction, type NearDelegateAction, type NearDeleteAccountAction, type NearDeleteKeyAction, type NearDeployContractAction, type NearDeployGlobalContractAction, type NearFeeEstimate, type NearFetch, type NearFunctionCallAction, type NearProvider, type NearPublicKey, type NearQuote, type NearReceipt, NearRpc, NearRpcError, type NearSignature, type NearSignedDelegateAction, type NearSignedTransaction, type NearSimulation, type NearStakeAction, type NearTransaction, type NearTransferAction, type NearTransferOptions, type NearTransferResult, type NearTxDescription, type NearTxKind, type NearTxWarning, type NearTxWarningCode, type NearUseGlobalContractAction, type Nep413Payload, type Nep413Signed, ONE_YOCTO, type RawAccessKeyView, type RawAccountView, type RawFinalOutcome, STORAGE_DEPOSIT_GAS, STORAGE_PRICE_PER_BYTE, SimulationError, TGAS, type UnsafeTransactionCode, UnsafeTransactionError, WalletAccountNear, WalletAccountReadOnlyNear, WalletManagerNear, YOCTO, actionKey, argsBytes, assertWellFormed, base58ToBytes, bytesToBase58, createClient, decodeAnyTransaction, decodeSignedTransaction, decodeTransaction, WalletManagerNear as default, describeTransaction, ed25519Key, encodeSignedTransaction, encodeTransaction, failureOf, fromBase64, implicitAccountId, isDangerous, isImplicitAccountId, isPlainObject, isValidAccountId, nep413Bytes, nep413Hash, outcomeFailed, parsePublicKey, parseSignature, publicKeyOfImplicit, publicKeyToString, readAction, readPublicKey, readSignature, receiptOf, toBase64, writeAction, writePublicKey, writeSignature };
package/dist/index.d.ts CHANGED
@@ -266,7 +266,7 @@ declare const STORAGE_DEPOSIT_GAS: bigint;
266
266
  declare const IMPLICIT_ACCOUNT_MIN_DEPOSIT: bigint;
267
267
 
268
268
  /** Why a transaction was refused before signing. */
269
- type UnsafeTransactionCode = 'signer-mismatch' | 'public-key-mismatch' | 'dangerous-action' | 'invalid-account' | 'no-actions' | 'gas-limit' | 'fee-limit' | 'missing-block-hash' | 'missing-nonce' | 'unknown-action' | 'insufficient-balance' | 'implicit-account-min-deposit' | 'no-access-key' | 'storage-deposit';
269
+ type UnsafeTransactionCode = 'signer-mismatch' | 'public-key-mismatch' | 'dangerous-action' | 'invalid-account' | 'no-actions' | 'gas-limit' | 'fee-limit' | 'missing-block-hash' | 'missing-nonce' | 'unknown-action' | 'insufficient-balance' | 'implicit-account-min-deposit' | 'no-access-key' | 'storage-deposit' | 'non-canonical' | 'invalid-method' | 'malformed-action';
270
270
  /** A transaction failed a hard check and was not signed. */
271
271
  declare class UnsafeTransactionError extends Error {
272
272
  readonly code: UnsafeTransactionCode;
@@ -395,8 +395,11 @@ declare const ACTION_TAG: {
395
395
  readonly useGlobalContract: 10;
396
396
  };
397
397
  type NearActionKey = keyof typeof ACTION_TAG;
398
+ /** The one key an action object has. Two keys (a deleteAccount next to a functionCall) is no action: whichever a reader picks, another reader may pick the other (scan 2026-10-27 F6). */
398
399
  declare function actionKey(a: NearAction): NearActionKey;
399
- /** Function-call args as bytes: raw bytes pass through; objects / strings become UTF-8 JSON / UTF-8. */
400
+ /** A plain `{…}` object: not an array, not a class instance. */
401
+ declare function isPlainObject(v: unknown): v is Record<string, unknown>;
402
+ /** Function-call args as bytes: raw bytes pass through; plain objects / strings become UTF-8 JSON / UTF-8. Anything else throws. */
400
403
  declare function argsBytes(args: Uint8Array | Record<string, unknown> | string): Uint8Array;
401
404
  declare function writeAction(w: BorshWriter, a: NearAction): void;
402
405
  declare function readAction(r: BorshReader): NearAction;
@@ -618,6 +621,13 @@ declare class WalletAccountReadOnlyNear implements IWalletAccountReadOnly {
618
621
  }
619
622
  declare function receiptOf(hash: string, o: RawFinalOutcome): NearReceipt;
620
623
  declare function parseSignature(signature: string): Uint8Array;
624
+ /**
625
+ * An object transaction has exactly the shape the encoder writes, before it is built or signed (also
626
+ * `signBuilt`): every action one known key; a function call's `methodName` a string of the method
627
+ * grammar, `args` bytes, a string or a plain object, `gas` / `deposit` bigints; every account id and
628
+ * method name well formed. What the policies read is then what gets encoded (scan 2026-10-27 F6, F28).
629
+ */
630
+ declare function assertWellFormed(tx: Pick<NearBuiltTransaction, 'receiverId' | 'actions'>): void;
621
631
 
622
632
  interface NearTransferResult extends TransferResult {
623
633
  estimate?: NearFeeEstimate;
@@ -633,12 +643,13 @@ interface NearTransferResult extends TransferResult {
633
643
  * `accountId` for a named account whose full-access key this is.
634
644
  */
635
645
  declare class WalletAccountNear extends WalletAccountReadOnlyNear implements IWalletAccount {
646
+ #private;
636
647
  /** nonce / block hash come from the node, so building needs the network. */
637
648
  readonly needsNetwork = true;
638
649
  /** Derivation path, or `external` for an external signer. */
639
650
  readonly path: string;
640
- /** The signer that holds the key. */
641
- readonly signer: Signer;
651
+ /** What holds the key: `seed`, `key` (one imported key) or `external`. */
652
+ readonly signerKind: Signer['kind'];
642
653
  private _disposed;
643
654
  private _readOnly;
644
655
  constructor(signer: Signer, publicKey: Uint8Array, path: string, config?: NearConfig, accountId?: string);
@@ -649,7 +660,6 @@ declare class WalletAccountNear extends WalletAccountReadOnlyNear implements IWa
649
660
  /** The same key bound to a named account (`alice.near`) that lists it as a full-access key. */
650
661
  withAccountId(accountId: string): WalletAccountNear;
651
662
  private key;
652
- private signBytes;
653
663
  /**
654
664
  * Raw ed25519 signature over the message bytes, as NEAR tooling prints it: "ed25519:<base58>".
655
665
  * A 32-byte message — string or bytes — is refused with {@link MessageIsTransactionError}: a NEAR
@@ -709,4 +719,4 @@ declare class WalletManagerNear extends WalletManager<WalletAccountNear, NearCon
709
719
  getFeeRates(): Promise<FeeRates>;
710
720
  }
711
721
 
712
- export { ACTION_TAG, BorshReader, BorshWriter, BroadcastUnknownError, CAIP2, DANGEROUS_ACTIONS, type DescribeContext, FT_TRANSFER_GAS, IMPLICIT_ACCOUNT_MIN_DEPOSIT, MAX_GAS, MessageIsTransactionError, NEAR_BASE_PATH, NEP413_PREFIX, type NearAccessKey, type NearAccountView, type NearAction, type NearAddKeyAction, type NearBuiltTransaction, type NearConfig, type NearCreateAccountAction, type NearDelegateAction, type NearDeleteAccountAction, type NearDeleteKeyAction, type NearDeployContractAction, type NearDeployGlobalContractAction, type NearFeeEstimate, type NearFetch, type NearFunctionCallAction, type NearProvider, type NearPublicKey, type NearQuote, type NearReceipt, NearRpc, NearRpcError, type NearSignature, type NearSignedDelegateAction, type NearSignedTransaction, type NearSimulation, type NearStakeAction, type NearTransaction, type NearTransferAction, type NearTransferOptions, type NearTransferResult, type NearTxDescription, type NearTxKind, type NearTxWarning, type NearTxWarningCode, type NearUseGlobalContractAction, type Nep413Payload, type Nep413Signed, ONE_YOCTO, type RawAccessKeyView, type RawAccountView, type RawFinalOutcome, STORAGE_DEPOSIT_GAS, STORAGE_PRICE_PER_BYTE, SimulationError, TGAS, type UnsafeTransactionCode, UnsafeTransactionError, WalletAccountNear, WalletAccountReadOnlyNear, WalletManagerNear, YOCTO, actionKey, argsBytes, base58ToBytes, bytesToBase58, createClient, decodeAnyTransaction, decodeSignedTransaction, decodeTransaction, WalletManagerNear as default, describeTransaction, ed25519Key, encodeSignedTransaction, encodeTransaction, failureOf, fromBase64, implicitAccountId, isDangerous, isImplicitAccountId, isValidAccountId, nep413Bytes, nep413Hash, outcomeFailed, parsePublicKey, parseSignature, publicKeyOfImplicit, publicKeyToString, readAction, readPublicKey, readSignature, receiptOf, toBase64, writeAction, writePublicKey, writeSignature };
722
+ export { ACTION_TAG, BorshReader, BorshWriter, BroadcastUnknownError, CAIP2, DANGEROUS_ACTIONS, type DescribeContext, FT_TRANSFER_GAS, IMPLICIT_ACCOUNT_MIN_DEPOSIT, MAX_GAS, MessageIsTransactionError, NEAR_BASE_PATH, NEP413_PREFIX, type NearAccessKey, type NearAccountView, type NearAction, type NearAddKeyAction, type NearBuiltTransaction, type NearConfig, type NearCreateAccountAction, type NearDelegateAction, type NearDeleteAccountAction, type NearDeleteKeyAction, type NearDeployContractAction, type NearDeployGlobalContractAction, type NearFeeEstimate, type NearFetch, type NearFunctionCallAction, type NearProvider, type NearPublicKey, type NearQuote, type NearReceipt, NearRpc, NearRpcError, type NearSignature, type NearSignedDelegateAction, type NearSignedTransaction, type NearSimulation, type NearStakeAction, type NearTransaction, type NearTransferAction, type NearTransferOptions, type NearTransferResult, type NearTxDescription, type NearTxKind, type NearTxWarning, type NearTxWarningCode, type NearUseGlobalContractAction, type Nep413Payload, type Nep413Signed, ONE_YOCTO, type RawAccessKeyView, type RawAccountView, type RawFinalOutcome, STORAGE_DEPOSIT_GAS, STORAGE_PRICE_PER_BYTE, SimulationError, TGAS, type UnsafeTransactionCode, UnsafeTransactionError, WalletAccountNear, WalletAccountReadOnlyNear, WalletManagerNear, YOCTO, actionKey, argsBytes, assertWellFormed, base58ToBytes, bytesToBase58, createClient, decodeAnyTransaction, decodeSignedTransaction, decodeTransaction, WalletManagerNear as default, describeTransaction, ed25519Key, encodeSignedTransaction, encodeTransaction, failureOf, fromBase64, implicitAccountId, isDangerous, isImplicitAccountId, isPlainObject, isValidAccountId, nep413Bytes, nep413Hash, outcomeFailed, parsePublicKey, parseSignature, publicKeyOfImplicit, publicKeyToString, readAction, readPublicKey, readSignature, receiptOf, toBase64, writeAction, writePublicKey, writeSignature };
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  outcomeFailed,
31
31
  parseJsonPreservingBigInts,
32
32
  toBase64
33
- } from "./chunk-4FHO2WJN.js";
33
+ } from "./chunk-ZWMEZA5A.js";
34
34
 
35
35
  // src/address.ts
36
36
  import { base58 } from "@scure/base";
@@ -74,7 +74,7 @@ var bytesToBase58 = (b) => base58.encode(b);
74
74
 
75
75
  // src/borsh.ts
76
76
  var utf8 = new TextEncoder();
77
- var utf8d = new TextDecoder();
77
+ var utf8d = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
78
78
  var BorshWriter = class {
79
79
  _buf = new Uint8Array(256);
80
80
  _len = 0;
@@ -176,7 +176,10 @@ var BorshReader = class {
176
176
  return utf8d.decode(this.vecU8());
177
177
  }
178
178
  option(read) {
179
- return this.u8() === 0 ? void 0 : read();
179
+ const tag = this.u8();
180
+ if (tag === 0) return void 0;
181
+ if (tag !== 1) throw new RangeError(`borsh: option tag ${tag}`);
182
+ return read();
180
183
  }
181
184
  done() {
182
185
  if (this.remaining !== 0) throw new RangeError(`borsh: ${this.remaining} trailing bytes`);
@@ -219,13 +222,21 @@ var ACTION_TAG = {
219
222
  useGlobalContract: 10
220
223
  };
221
224
  function actionKey(a) {
222
- const k = Object.keys(a)[0];
223
- if (!k || !(k in ACTION_TAG)) throw new RangeError(`unknown action ${k}`);
225
+ const keys = typeof a === "object" && a !== null ? Object.keys(a) : [];
226
+ if (keys.length !== 1) throw new RangeError(`an action must have exactly one key (has: ${keys.join(", ") || "none"})`);
227
+ const k = keys[0];
228
+ if (!Object.prototype.hasOwnProperty.call(ACTION_TAG, k)) throw new RangeError(`unknown action ${k}`);
224
229
  return k;
225
230
  }
231
+ function isPlainObject(v) {
232
+ if (typeof v !== "object" || v === null || Array.isArray(v)) return false;
233
+ const proto = Object.getPrototypeOf(v);
234
+ return proto === Object.prototype || proto === null;
235
+ }
226
236
  function argsBytes(args) {
227
237
  if (args instanceof Uint8Array) return args;
228
238
  if (typeof args === "string") return utf8.encode(args);
239
+ if (!isPlainObject(args)) throw new TypeError("function-call args must be bytes, a string or a plain object");
229
240
  return utf8.encode(JSON.stringify(args));
230
241
  }
231
242
  function writeAccessKey(w, k) {
@@ -283,6 +294,8 @@ function writeAction(w, a) {
283
294
  return;
284
295
  case "functionCall": {
285
296
  const f = a.functionCall;
297
+ if (typeof f.methodName !== "string") throw new TypeError("functionCall.methodName must be a string");
298
+ if (f.gas !== void 0 && typeof f.gas !== "bigint" || f.deposit !== void 0 && typeof f.deposit !== "bigint") throw new TypeError("functionCall gas and deposit must be bigints");
286
299
  w.string(f.methodName).vecU8(argsBytes(f.args)).u64(f.gas ?? 30n * 10n ** 12n).u128(f.deposit ?? 0n);
287
300
  return;
288
301
  }
@@ -329,6 +342,11 @@ function writeAction(w, a) {
329
342
  }
330
343
  }
331
344
  }
345
+ function mode(r) {
346
+ const m = r.u8();
347
+ if (m !== 0 && m !== 1) throw new RangeError(`borsh: unknown global-contract mode ${m}`);
348
+ return m;
349
+ }
332
350
  function readAction(r) {
333
351
  const tag = r.u8();
334
352
  switch (tag) {
@@ -363,11 +381,11 @@ function readAction(r) {
363
381
  }
364
382
  case 9: {
365
383
  const code = r.vecU8();
366
- const m = r.u8();
384
+ const m = mode(r);
367
385
  return { deployGlobalContract: { code, deployMode: m === 0 ? "codeHash" : "accountId" } };
368
386
  }
369
387
  case 10: {
370
- const m = r.u8();
388
+ const m = mode(r);
371
389
  return { useGlobalContract: m === 0 ? { codeHash: r.bytes(32) } : { accountId: r.string() } };
372
390
  }
373
391
  default:
@@ -682,7 +700,8 @@ var WalletAccountReadOnlyNear = class _WalletAccountReadOnlyNear {
682
700
  }
683
701
  /** Fill `signerId` / `publicKey` / `nonce` / `blockHash` (the last two from the node when missing). */
684
702
  async buildTransaction(tx) {
685
- if (typeof tx === "string") return decodeAnyTransaction(fromBase64(tx)).transaction;
703
+ if (typeof tx === "string") return canonicalTransaction(tx);
704
+ assertWellFormed(tx);
686
705
  const signerId = tx.signerId ?? this.address;
687
706
  const publicKey = tx.publicKey ?? this.publicKey;
688
707
  let nonce = tx.nonce;
@@ -796,6 +815,7 @@ var WalletAccountReadOnlyNear = class _WalletAccountReadOnlyNear {
796
815
  if (tx.publicKey.keyType !== this.publicKey.keyType || !equalBytes(tx.publicKey.data, this.publicKey.data)) throw new UnsafeTransactionError("public-key-mismatch", "The transaction public key is not this account's key.");
797
816
  if (!tx.actions.length) throw new UnsafeTransactionError("no-actions", "The transaction has no actions.");
798
817
  if (!isValidAccountId(tx.receiverId)) throw new UnsafeTransactionError("invalid-account", `"${tx.receiverId}" is not a valid NEAR account id.`);
818
+ assertWellFormed(tx);
799
819
  if (tx.blockHash.length !== 32) throw new UnsafeTransactionError("missing-block-hash", "The transaction has no 32-byte block hash.");
800
820
  if (tx.nonce <= 0n) throw new UnsafeTransactionError("missing-nonce", "The transaction nonce must be positive.");
801
821
  if (!this._config.allowDangerousActions) {
@@ -851,6 +871,64 @@ function parseSignature(signature) {
851
871
  }
852
872
  return base58ToBytes(s, 64);
853
873
  }
874
+ var METHOD_NAME = /^[A-Za-z0-9_]{1,256}$/;
875
+ function assertWellFormed(tx) {
876
+ if (!Array.isArray(tx.actions)) throw new UnsafeTransactionError("malformed-action", "actions must be an array.");
877
+ assertShape(tx.actions);
878
+ assertNames(tx.actions);
879
+ }
880
+ function assertShape(actions, depth = 0) {
881
+ for (const a of actions) {
882
+ const keys = typeof a === "object" && a !== null ? Object.keys(a) : [];
883
+ if (keys.length !== 1 || !Object.prototype.hasOwnProperty.call(ACTION_TAG, keys[0])) {
884
+ throw new UnsafeTransactionError("malformed-action", `An action must have exactly one known key (has: ${keys.join(", ") || "none"}).`);
885
+ }
886
+ if ("functionCall" in a) {
887
+ const f = a.functionCall;
888
+ if (!(f.args instanceof Uint8Array) && typeof f.args !== "string" && !isPlainObject(f.args)) throw new UnsafeTransactionError("malformed-action", "Function-call args must be bytes, a string or a plain object.");
889
+ if (f.gas !== void 0 && typeof f.gas !== "bigint" || f.deposit !== void 0 && typeof f.deposit !== "bigint") throw new UnsafeTransactionError("malformed-action", "Function-call gas and deposit must be bigints.");
890
+ }
891
+ if ("signedDelegate" in a && depth === 0) assertShape(a.signedDelegate.delegateAction.actions, depth + 1);
892
+ }
893
+ }
894
+ function assertNames(actions, depth = 0) {
895
+ const account = (id) => {
896
+ if (typeof id !== "string" || !isValidAccountId(id)) throw new UnsafeTransactionError("invalid-account", `${JSON.stringify(id)} is not a valid NEAR account id.`);
897
+ };
898
+ const method = (name) => {
899
+ if (typeof name !== "string" || !METHOD_NAME.test(name)) throw new UnsafeTransactionError("invalid-method", `${JSON.stringify(name)} is not a method name this wallet signs (ASCII letters, digits, '_').`);
900
+ };
901
+ for (const a of actions) {
902
+ if ("functionCall" in a) method(a.functionCall.methodName);
903
+ else if ("deleteAccount" in a) account(a.deleteAccount.beneficiaryId);
904
+ else if ("addKey" in a && "functionCall" in a.addKey.accessKey.permission) {
905
+ const p = a.addKey.accessKey.permission.functionCall;
906
+ account(p.receiverId);
907
+ for (const m of p.methodNames) method(m);
908
+ } else if ("useGlobalContract" in a && "accountId" in a.useGlobalContract) account(a.useGlobalContract.accountId);
909
+ else if ("signedDelegate" in a) {
910
+ const d = a.signedDelegate.delegateAction;
911
+ account(d.senderId);
912
+ account(d.receiverId);
913
+ if (depth > 0) throw new UnsafeTransactionError("unknown-action", "A delegated action inside a delegated action is not signed.");
914
+ assertNames(d.actions, depth + 1);
915
+ }
916
+ }
917
+ }
918
+ function canonicalTransaction(b64) {
919
+ const bytes = fromBase64(b64);
920
+ let decoded;
921
+ try {
922
+ decoded = decodeAnyTransaction(bytes);
923
+ } catch (e) {
924
+ throw new UnsafeTransactionError("non-canonical", `Not a borsh NEAR transaction: ${e.message}`);
925
+ }
926
+ const again = decoded.signature ? encodeSignedTransaction({ transaction: decoded.transaction, signature: decoded.signature }) : encodeTransaction(decoded.transaction);
927
+ if (!equalBytes(again, bytes)) throw new UnsafeTransactionError("non-canonical", "This borsh transaction does not re-encode to the same bytes, so what was reviewed may not be what gets signed.");
928
+ if (!isValidAccountId(decoded.transaction.signerId) || !isValidAccountId(decoded.transaction.receiverId)) throw new UnsafeTransactionError("invalid-account", "The transaction names an invalid NEAR account id.");
929
+ assertWellFormed(decoded.transaction);
930
+ return decoded.transaction;
931
+ }
854
932
  function equalBytes(a, b) {
855
933
  if (a.length !== b.length) return false;
856
934
  let diff = 0;
@@ -872,13 +950,20 @@ var WalletAccountNear = class _WalletAccountNear extends WalletAccountReadOnlyNe
872
950
  needsNetwork = true;
873
951
  /** Derivation path, or `external` for an external signer. */
874
952
  path;
875
- /** The signer that holds the key. */
876
- signer;
953
+ /**
954
+ * The signer that holds the key, in a private field: not a property of the account, so no code
955
+ * the account is handed to (a protocol module, a logger) can reach it and sign around the
956
+ * account's checks (audit 2026-10-29 A1).
957
+ */
958
+ #signer;
959
+ /** What holds the key: `seed`, `key` (one imported key) or `external`. */
960
+ signerKind;
877
961
  _disposed = false;
878
962
  _readOnly;
879
963
  constructor(signer, publicKey, path, config = {}, accountId) {
880
964
  super(accountId ?? implicitAccountId(publicKey), config, ed25519Key(publicKey));
881
- this.signer = requireCurve(signer, "ed25519");
965
+ this.#signer = requireCurve(signer, "ed25519");
966
+ this.signerKind = this.#signer.kind;
882
967
  this.path = path;
883
968
  }
884
969
  /** Wrap a raw derived key (takes ownership; zeroized on dispose). */
@@ -892,14 +977,14 @@ var WalletAccountNear = class _WalletAccountNear extends WalletAccountReadOnlyNe
892
977
  }
893
978
  /** The same key bound to a named account (`alice.near`) that lists it as a full-access key. */
894
979
  withAccountId(accountId) {
895
- return new _WalletAccountNear(this.signer, this.publicKey.data, this.path, this._config, accountId);
980
+ return new _WalletAccountNear(this.#signer, this.publicKey.data, this.path, this._config, accountId);
896
981
  }
897
982
  key() {
898
983
  if (this._disposed) throw new SignerError("This account has been disposed.");
899
984
  }
900
- async signBytes(bytes, context) {
985
+ async #signBytes(bytes, context) {
901
986
  this.key();
902
- return this.signer.sign(bytes, { scheme: "ed25519", context });
987
+ return this.#signer.sign(bytes, { scheme: "ed25519", context });
903
988
  }
904
989
  /**
905
990
  * Raw ed25519 signature over the message bytes, as NEAR tooling prints it: "ed25519:<base58>".
@@ -912,16 +997,17 @@ var WalletAccountNear = class _WalletAccountNear extends WalletAccountReadOnlyNe
912
997
  async sign(message) {
913
998
  const bytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
914
999
  if (bytes.length === 32 || carriesKey(bytes, this.publicKey.data)) throw new MessageIsTransactionError();
915
- return `ed25519:${bytesToBase58(await this.signBytes(bytes, "near-message"))}`;
1000
+ return `ed25519:${bytesToBase58(await this.#signBytes(bytes, "near-message"))}`;
916
1001
  }
917
1002
  /** NEP-413 off-chain message (what NEAR Intents and dApps ask wallets to sign). */
918
1003
  async signNep413(payload) {
919
- const sig = await this.signBytes(nep413Hash(payload), "near-nep413");
1004
+ const sig = await this.#signBytes(nep413Hash(payload), "near-nep413");
920
1005
  return { signature: toBase64(sig), publicKey: publicKeyToString(this.publicKey), accountId: this.address };
921
1006
  }
922
1007
  /** Sign a fully built transaction. No checks — see `signTransaction`. */
923
1008
  async signBuilt(tx) {
924
- const sig = await this.signBytes(WalletAccountReadOnlyNear.hashOf(tx), "near-tx");
1009
+ assertWellFormed(tx);
1010
+ const sig = await this.#signBytes(WalletAccountReadOnlyNear.hashOf(tx), "near-tx");
925
1011
  return { transaction: tx, signature: { keyType: "ed25519", data: sig } };
926
1012
  }
927
1013
  /** Build → hard checks → preflight → fee cap. Shared by sign / send / transfer. */
@@ -985,7 +1071,7 @@ var WalletAccountNear = class _WalletAccountNear extends WalletAccountReadOnlyNe
985
1071
  /** Dispose the signer (zeroizes a local key). Idempotent. */
986
1072
  dispose() {
987
1073
  this._disposed = true;
988
- this.signer.dispose();
1074
+ this.#signer.dispose();
989
1075
  }
990
1076
  };
991
1077
  function decodeSigned(b64) {
@@ -1075,6 +1161,7 @@ export {
1075
1161
  YOCTO,
1076
1162
  actionKey,
1077
1163
  argsBytes,
1164
+ assertWellFormed,
1078
1165
  base58ToBytes,
1079
1166
  bytesToBase58,
1080
1167
  createClient,
@@ -1095,6 +1182,7 @@ export {
1095
1182
  implicitAccountId,
1096
1183
  isDangerous,
1097
1184
  isImplicitAccountId,
1185
+ isPlainObject,
1098
1186
  isValidAccountId,
1099
1187
  mapNearblocksGroup,
1100
1188
  mapNearblocksTxn,