@anywalletkit/wallet-ton 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.d.cts CHANGED
@@ -67,6 +67,12 @@ interface TonConfig {
67
67
  validUntilSeconds?: number;
68
68
  /** Nanotons attached to a jetton transfer on top of `forwardTonAmount` (default 0.05 TON). */
69
69
  jettonAttachedValue?: bigint | number | string;
70
+ /**
71
+ * Most nanotons a jetton `transfer()` may attach to the jetton-wallet call, `forwardTonAmount`
72
+ * included (default 1 TON). The contract that receives them is the one the jetton master names,
73
+ * so a fake master gets all of it: the cap bounds what such a call can cost.
74
+ */
75
+ maxJettonAttachedValue?: bigint | number | string;
70
76
  /**
71
77
  * 'mainnet' (ton:-239, default) or 'testnet' (ton:-3). Sets the CAIP-2 id, the address flags and the
72
78
  * wallet_id network (-239 / -3), so a testnet wallet has its own address and its signed messages are
@@ -122,8 +128,14 @@ interface TonTransferOptions {
122
128
  memo?: string;
123
129
  /** Jetton only: custom payload cell (rarely needed; e.g. mintless jettons). */
124
130
  customPayload?: Cell;
125
- /** Jetton only: where excess TON returns (default: this wallet). */
131
+ /**
132
+ * Jetton only: where excess TON returns (default: this wallet). Another address is refused
133
+ * unless `allowForeignResponseDestination` is set: it receives TON the policies' recipient
134
+ * check never sees.
135
+ */
126
136
  responseDestination?: string;
137
+ /** Jetton only: let `responseDestination` be another address than this wallet. Off by default. */
138
+ allowForeignResponseDestination?: boolean;
127
139
  /** Jetton only: query id (default random). */
128
140
  queryId?: bigint | number;
129
141
  /** Jetton only: nanotons attached to the jetton-wallet call (default config.jettonAttachedValue + forwardTonAmount). */
@@ -469,12 +481,6 @@ interface ParsedV5R1Body {
469
481
  /** Parse a signed (or zero-signed) V5R1 external body back into its messages. Returns null for anything else. */
470
482
  declare function parseV5R1Body(body: Cell): ParsedV5R1Body | null;
471
483
 
472
- /**
473
- * "What am I signing" for TON — offline. Decodes the messages of a
474
- * {@link TonSendable} (or a prebuilt V5R1 body) into human-checkable items and
475
- * flags the classic mistakes before any key is touched.
476
- */
477
-
478
484
  /** TEP-74 `transfer` op code of a jetton wallet. */
479
485
  declare const JETTON_TRANSFER_OP = 260734629;
480
486
  /** What one outgoing message does. */
@@ -553,6 +559,21 @@ type DecodedBody = {
553
559
  };
554
560
  /** Decode a message body cell. */
555
561
  declare function decodeBody(body: Cell): DecodedBody;
562
+ /**
563
+ * A base64 BoC as its single root Cell, refused when its layout is one other readers may parse
564
+ * differently from @ton/core: a magic other than the generic one, more than one root, absent cells,
565
+ * or any cell that stores its hashes (with_hashes: @ton/core skips a hash area another reader takes
566
+ * for data), has a level mask, or is exotic. What remains is read the same by every reader, the
567
+ * kit's policy reader included, whatever order the serializer put the cells in (scan 2026-10-27
568
+ * F2, F4). Real provider BoCs order cells differently from @ton/core, so the bytes are not required
569
+ * to round-trip.
570
+ */
571
+ declare function canonicalBocCell(b64: string, what?: string): Cell;
572
+ /**
573
+ * The body a message is built with: a Cell, a text comment, or a canonical `bodyBoc`. A `body` that is
574
+ * neither a string nor a Cell is refused rather than replaced by `bodyBoc` (scan 2026-10-27 F4).
575
+ */
576
+ declare function messageBody(tx: TonTransaction): Cell | undefined;
556
577
  /** A text comment body (op 0 plus the text), as wallets show it. */
557
578
  declare function commentCell(text: string): Cell;
558
579
  /** Describe one outgoing message and push its warnings into `warnings`. */
@@ -723,12 +744,13 @@ declare function tonSignDataDigest(address: TonAddressParts, request: TonSignDat
723
744
  * once the transaction has passed.
724
745
  */
725
746
  declare class WalletAccountTon extends WalletAccountReadOnlyTon implements IWalletAccount {
747
+ #private;
726
748
  /** seqno and fees come from the network before signing. */
727
749
  readonly needsNetwork = true;
728
750
  /** Derivation path, `ton-mnemonic`, or `external`. */
729
751
  readonly path: string;
730
- /** The signer that holds the key. */
731
- readonly signer: Signer;
752
+ /** What holds the key: `seed`, `key` (one imported key) or `external`. */
753
+ readonly signerKind: Signer['kind'];
732
754
  private _readOnly;
733
755
  /** `publicKey` is the signer's 32-byte ed25519 key; the V5R1 address derives from it synchronously. */
734
756
  constructor(signer: Signer, publicKey: Uint8Array, path: string, config?: TonConfig);
@@ -766,7 +788,6 @@ declare class WalletAccountTon extends WalletAccountReadOnlyTon implements IWall
766
788
  private assertNoDrain;
767
789
  /** The send modes of a prebuilt V5R1 body; an unreadable body is left to the emulation and the node. */
768
790
  private bodyModes;
769
- private signMessages;
770
791
  private preflight;
771
792
  /** Sign without broadcasting. Returns the external-message BODY as base64 BoC (pass it back to sendTransaction as a Cell). */
772
793
  signTransaction(tx: TonSendable, options?: WriteOptions): Promise<string>;
@@ -818,4 +839,4 @@ declare class WalletManagerTon extends WalletManager<WalletAccountTon, TonConfig
818
839
  getFeeRates(): Promise<FeeRates>;
819
840
  }
820
841
 
821
- export { BroadcastUnknownError, CAIP2, DEFAULT_SEND_MODE, DEFAULT_TONAPI, type DecodedBody, type EmulateOptions, type EmulationOutcome, type EmulationSource, type EmulationVerdict, type GetMethodResult, JETTON_TRANSFER_OP, MAINNET_GLOBAL_ID, MAX_ACTIONS, MessageIsTransactionError, type ParsedV5R1Body, SEND_MODE, SimulationError, TESTNET_GLOBAL_ID, TON_BASE_PATH, TON_MNEMONIC_PATH, type TonAccountState, type TonAccountStatus, type TonAddressParts, TonCenter, type TonConfig, type TonDescribedKind, type TonDescribedMessage, type TonDescription, type TonEmulateConfig, type TonEndpoint, type TonFees, type TonJettonDetails, type TonProof, type TonProofRequest, type TonProvider, type TonReceipt, type TonRisk, type TonRpc, type TonSendable, type TonSignDataPayload, type TonSignDataRequest, type TonSignedData, type TonSimulation, type TonSimulationSource, type TonTransaction, type TonTransferOptions, type TonWarning, type TonWarningCode, UnsafeTransactionError, type V5R1Message, type V5R1SigningParams, type V5R1WalletIdParts, V5R1_CODE_HEX, V5R1_OP, WalletAccountReadOnlyTon, WalletAccountTon, WalletManagerTon, commentCell, createTonRpc as createTonClient, createTonRpc, decodeBody, WalletManagerTon as default, describeMessageRelaxed, describeTransaction, emulateExternal, emulateViaTonapi, installBufferGlobal, isAnsweredRefusal, parseEmulation, parseTonapiConsequences, parseTonapiRisk, parseTonapiTrace, parseV5R1Body, resolveEmulate, runEmulation, tonCenterEndpoint, tonProofDigest, tonSignDataDigest, v5r1Address, v5r1Code, v5r1ExternalMessage, v5r1PackSigned, v5r1PackUnsigned, v5r1SigningMessage, v5r1StateInit, v5r1WalletId };
842
+ export { BroadcastUnknownError, CAIP2, DEFAULT_SEND_MODE, DEFAULT_TONAPI, type DecodedBody, type EmulateOptions, type EmulationOutcome, type EmulationSource, type EmulationVerdict, type GetMethodResult, JETTON_TRANSFER_OP, MAINNET_GLOBAL_ID, MAX_ACTIONS, MessageIsTransactionError, type ParsedV5R1Body, SEND_MODE, SimulationError, TESTNET_GLOBAL_ID, TON_BASE_PATH, TON_MNEMONIC_PATH, type TonAccountState, type TonAccountStatus, type TonAddressParts, TonCenter, type TonConfig, type TonDescribedKind, type TonDescribedMessage, type TonDescription, type TonEmulateConfig, type TonEndpoint, type TonFees, type TonJettonDetails, type TonProof, type TonProofRequest, type TonProvider, type TonReceipt, type TonRisk, type TonRpc, type TonSendable, type TonSignDataPayload, type TonSignDataRequest, type TonSignedData, type TonSimulation, type TonSimulationSource, type TonTransaction, type TonTransferOptions, type TonWarning, type TonWarningCode, UnsafeTransactionError, type V5R1Message, type V5R1SigningParams, type V5R1WalletIdParts, V5R1_CODE_HEX, V5R1_OP, WalletAccountReadOnlyTon, WalletAccountTon, WalletManagerTon, canonicalBocCell, commentCell, createTonRpc as createTonClient, createTonRpc, decodeBody, WalletManagerTon as default, describeMessageRelaxed, describeTransaction, emulateExternal, emulateViaTonapi, installBufferGlobal, isAnsweredRefusal, messageBody, parseEmulation, parseTonapiConsequences, parseTonapiRisk, parseTonapiTrace, parseV5R1Body, resolveEmulate, runEmulation, tonCenterEndpoint, tonProofDigest, tonSignDataDigest, v5r1Address, v5r1Code, v5r1ExternalMessage, v5r1PackSigned, v5r1PackUnsigned, v5r1SigningMessage, v5r1StateInit, v5r1WalletId };
package/dist/index.d.ts CHANGED
@@ -67,6 +67,12 @@ interface TonConfig {
67
67
  validUntilSeconds?: number;
68
68
  /** Nanotons attached to a jetton transfer on top of `forwardTonAmount` (default 0.05 TON). */
69
69
  jettonAttachedValue?: bigint | number | string;
70
+ /**
71
+ * Most nanotons a jetton `transfer()` may attach to the jetton-wallet call, `forwardTonAmount`
72
+ * included (default 1 TON). The contract that receives them is the one the jetton master names,
73
+ * so a fake master gets all of it: the cap bounds what such a call can cost.
74
+ */
75
+ maxJettonAttachedValue?: bigint | number | string;
70
76
  /**
71
77
  * 'mainnet' (ton:-239, default) or 'testnet' (ton:-3). Sets the CAIP-2 id, the address flags and the
72
78
  * wallet_id network (-239 / -3), so a testnet wallet has its own address and its signed messages are
@@ -122,8 +128,14 @@ interface TonTransferOptions {
122
128
  memo?: string;
123
129
  /** Jetton only: custom payload cell (rarely needed; e.g. mintless jettons). */
124
130
  customPayload?: Cell;
125
- /** Jetton only: where excess TON returns (default: this wallet). */
131
+ /**
132
+ * Jetton only: where excess TON returns (default: this wallet). Another address is refused
133
+ * unless `allowForeignResponseDestination` is set: it receives TON the policies' recipient
134
+ * check never sees.
135
+ */
126
136
  responseDestination?: string;
137
+ /** Jetton only: let `responseDestination` be another address than this wallet. Off by default. */
138
+ allowForeignResponseDestination?: boolean;
127
139
  /** Jetton only: query id (default random). */
128
140
  queryId?: bigint | number;
129
141
  /** Jetton only: nanotons attached to the jetton-wallet call (default config.jettonAttachedValue + forwardTonAmount). */
@@ -469,12 +481,6 @@ interface ParsedV5R1Body {
469
481
  /** Parse a signed (or zero-signed) V5R1 external body back into its messages. Returns null for anything else. */
470
482
  declare function parseV5R1Body(body: Cell): ParsedV5R1Body | null;
471
483
 
472
- /**
473
- * "What am I signing" for TON — offline. Decodes the messages of a
474
- * {@link TonSendable} (or a prebuilt V5R1 body) into human-checkable items and
475
- * flags the classic mistakes before any key is touched.
476
- */
477
-
478
484
  /** TEP-74 `transfer` op code of a jetton wallet. */
479
485
  declare const JETTON_TRANSFER_OP = 260734629;
480
486
  /** What one outgoing message does. */
@@ -553,6 +559,21 @@ type DecodedBody = {
553
559
  };
554
560
  /** Decode a message body cell. */
555
561
  declare function decodeBody(body: Cell): DecodedBody;
562
+ /**
563
+ * A base64 BoC as its single root Cell, refused when its layout is one other readers may parse
564
+ * differently from @ton/core: a magic other than the generic one, more than one root, absent cells,
565
+ * or any cell that stores its hashes (with_hashes: @ton/core skips a hash area another reader takes
566
+ * for data), has a level mask, or is exotic. What remains is read the same by every reader, the
567
+ * kit's policy reader included, whatever order the serializer put the cells in (scan 2026-10-27
568
+ * F2, F4). Real provider BoCs order cells differently from @ton/core, so the bytes are not required
569
+ * to round-trip.
570
+ */
571
+ declare function canonicalBocCell(b64: string, what?: string): Cell;
572
+ /**
573
+ * The body a message is built with: a Cell, a text comment, or a canonical `bodyBoc`. A `body` that is
574
+ * neither a string nor a Cell is refused rather than replaced by `bodyBoc` (scan 2026-10-27 F4).
575
+ */
576
+ declare function messageBody(tx: TonTransaction): Cell | undefined;
556
577
  /** A text comment body (op 0 plus the text), as wallets show it. */
557
578
  declare function commentCell(text: string): Cell;
558
579
  /** Describe one outgoing message and push its warnings into `warnings`. */
@@ -723,12 +744,13 @@ declare function tonSignDataDigest(address: TonAddressParts, request: TonSignDat
723
744
  * once the transaction has passed.
724
745
  */
725
746
  declare class WalletAccountTon extends WalletAccountReadOnlyTon implements IWalletAccount {
747
+ #private;
726
748
  /** seqno and fees come from the network before signing. */
727
749
  readonly needsNetwork = true;
728
750
  /** Derivation path, `ton-mnemonic`, or `external`. */
729
751
  readonly path: string;
730
- /** The signer that holds the key. */
731
- readonly signer: Signer;
752
+ /** What holds the key: `seed`, `key` (one imported key) or `external`. */
753
+ readonly signerKind: Signer['kind'];
732
754
  private _readOnly;
733
755
  /** `publicKey` is the signer's 32-byte ed25519 key; the V5R1 address derives from it synchronously. */
734
756
  constructor(signer: Signer, publicKey: Uint8Array, path: string, config?: TonConfig);
@@ -766,7 +788,6 @@ declare class WalletAccountTon extends WalletAccountReadOnlyTon implements IWall
766
788
  private assertNoDrain;
767
789
  /** The send modes of a prebuilt V5R1 body; an unreadable body is left to the emulation and the node. */
768
790
  private bodyModes;
769
- private signMessages;
770
791
  private preflight;
771
792
  /** Sign without broadcasting. Returns the external-message BODY as base64 BoC (pass it back to sendTransaction as a Cell). */
772
793
  signTransaction(tx: TonSendable, options?: WriteOptions): Promise<string>;
@@ -818,4 +839,4 @@ declare class WalletManagerTon extends WalletManager<WalletAccountTon, TonConfig
818
839
  getFeeRates(): Promise<FeeRates>;
819
840
  }
820
841
 
821
- export { BroadcastUnknownError, CAIP2, DEFAULT_SEND_MODE, DEFAULT_TONAPI, type DecodedBody, type EmulateOptions, type EmulationOutcome, type EmulationSource, type EmulationVerdict, type GetMethodResult, JETTON_TRANSFER_OP, MAINNET_GLOBAL_ID, MAX_ACTIONS, MessageIsTransactionError, type ParsedV5R1Body, SEND_MODE, SimulationError, TESTNET_GLOBAL_ID, TON_BASE_PATH, TON_MNEMONIC_PATH, type TonAccountState, type TonAccountStatus, type TonAddressParts, TonCenter, type TonConfig, type TonDescribedKind, type TonDescribedMessage, type TonDescription, type TonEmulateConfig, type TonEndpoint, type TonFees, type TonJettonDetails, type TonProof, type TonProofRequest, type TonProvider, type TonReceipt, type TonRisk, type TonRpc, type TonSendable, type TonSignDataPayload, type TonSignDataRequest, type TonSignedData, type TonSimulation, type TonSimulationSource, type TonTransaction, type TonTransferOptions, type TonWarning, type TonWarningCode, UnsafeTransactionError, type V5R1Message, type V5R1SigningParams, type V5R1WalletIdParts, V5R1_CODE_HEX, V5R1_OP, WalletAccountReadOnlyTon, WalletAccountTon, WalletManagerTon, commentCell, createTonRpc as createTonClient, createTonRpc, decodeBody, WalletManagerTon as default, describeMessageRelaxed, describeTransaction, emulateExternal, emulateViaTonapi, installBufferGlobal, isAnsweredRefusal, parseEmulation, parseTonapiConsequences, parseTonapiRisk, parseTonapiTrace, parseV5R1Body, resolveEmulate, runEmulation, tonCenterEndpoint, tonProofDigest, tonSignDataDigest, v5r1Address, v5r1Code, v5r1ExternalMessage, v5r1PackSigned, v5r1PackUnsigned, v5r1SigningMessage, v5r1StateInit, v5r1WalletId };
842
+ export { BroadcastUnknownError, CAIP2, DEFAULT_SEND_MODE, DEFAULT_TONAPI, type DecodedBody, type EmulateOptions, type EmulationOutcome, type EmulationSource, type EmulationVerdict, type GetMethodResult, JETTON_TRANSFER_OP, MAINNET_GLOBAL_ID, MAX_ACTIONS, MessageIsTransactionError, type ParsedV5R1Body, SEND_MODE, SimulationError, TESTNET_GLOBAL_ID, TON_BASE_PATH, TON_MNEMONIC_PATH, type TonAccountState, type TonAccountStatus, type TonAddressParts, TonCenter, type TonConfig, type TonDescribedKind, type TonDescribedMessage, type TonDescription, type TonEmulateConfig, type TonEndpoint, type TonFees, type TonJettonDetails, type TonProof, type TonProofRequest, type TonProvider, type TonReceipt, type TonRisk, type TonRpc, type TonSendable, type TonSignDataPayload, type TonSignDataRequest, type TonSignedData, type TonSimulation, type TonSimulationSource, type TonTransaction, type TonTransferOptions, type TonWarning, type TonWarningCode, UnsafeTransactionError, type V5R1Message, type V5R1SigningParams, type V5R1WalletIdParts, V5R1_CODE_HEX, V5R1_OP, WalletAccountReadOnlyTon, WalletAccountTon, WalletManagerTon, canonicalBocCell, commentCell, createTonRpc as createTonClient, createTonRpc, decodeBody, WalletManagerTon as default, describeMessageRelaxed, describeTransaction, emulateExternal, emulateViaTonapi, installBufferGlobal, isAnsweredRefusal, messageBody, parseEmulation, parseTonapiConsequences, parseTonapiRisk, parseTonapiTrace, parseV5R1Body, resolveEmulate, runEmulation, tonCenterEndpoint, tonProofDigest, tonSignDataDigest, v5r1Address, v5r1Code, v5r1ExternalMessage, v5r1PackSigned, v5r1PackUnsigned, v5r1SigningMessage, v5r1StateInit, v5r1WalletId };
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  rawTonAddress,
11
11
  tonExplorerTxUrl,
12
12
  valueFlowTransfers
13
- } from "./chunk-RCL4PSJZ.js";
13
+ } from "./chunk-ZFENRKRW.js";
14
14
 
15
15
  // src/buffer-global.ts
16
16
  import { Buffer } from "buffer";
@@ -559,6 +559,7 @@ function parseV5R1Body(body) {
559
559
  }
560
560
 
561
561
  // src/describe.ts
562
+ import { Buffer as Buffer4 } from "buffer";
562
563
  import { Address as Address3, Cell as Cell3, beginCell as beginCell2 } from "@ton/core";
563
564
  var JETTON_TRANSFER_OP = 260734629;
564
565
  var LARGE_FORWARD_NANOTON = 500000000n;
@@ -618,11 +619,67 @@ function parseTo(to) {
618
619
  const a = Address3.parse(to);
619
620
  return { to: a.toRawString(), bounceable: true, workchain: a.workChain };
620
621
  }
621
- function bodyOf(tx) {
622
+ function canonicalBocCell(b64, what = "bodyBoc") {
623
+ if (!/^[A-Za-z0-9+/_-]+={0,2}$/.test(b64)) throw new UnsafeTransactionError("non-canonical-boc", `${what} is not a base64 string.`);
624
+ const bytes = Buffer4.from(b64, "base64");
625
+ const layout = plainBocLayout(bytes);
626
+ if (layout !== null) throw new UnsafeTransactionError("non-canonical-boc", `${what} is not a plain single-root BoC (${layout}), so what was reviewed may not be what is signed.`);
627
+ let roots;
628
+ try {
629
+ roots = Cell3.fromBoc(bytes);
630
+ } catch {
631
+ throw new UnsafeTransactionError("non-canonical-boc", `${what} is not a valid BoC.`);
632
+ }
633
+ if (roots.length !== 1) throw new UnsafeTransactionError("non-canonical-boc", `${what} has ${roots.length} roots.`);
634
+ return roots[0];
635
+ }
636
+ function plainBocLayout(b) {
637
+ if (b.length < 6 || b[0] !== 181 || b[1] !== 238 || b[2] !== 156 || b[3] !== 114) return "not the generic BoC magic";
638
+ const flags = b[4];
639
+ const size = flags & 7;
640
+ const offBytes = b[5];
641
+ if (size < 1 || size > 4 || offBytes < 1 || offBytes > 8) return "bad size fields";
642
+ let i = 6;
643
+ const int = (n) => {
644
+ if (i + n > b.length) throw new RangeError("truncated");
645
+ let v = 0;
646
+ for (let k = 0; k < n; k++) v = v * 256 + b[i++];
647
+ return v;
648
+ };
649
+ try {
650
+ const cells = int(size);
651
+ const roots = int(size);
652
+ const absent = int(size);
653
+ int(offBytes);
654
+ if (roots !== 1) return `${roots} roots`;
655
+ if (absent !== 0) return "absent cells";
656
+ i += roots * size;
657
+ if (flags & 128) i += cells * offBytes;
658
+ for (let c = 0; c < cells; c++) {
659
+ if (i + 2 > b.length) return "truncated";
660
+ const d1 = b[i++];
661
+ const d2 = b[i++];
662
+ if (d1 & 16) return "a cell stores its hashes";
663
+ if (d1 >> 5 !== 0) return "a cell has a level mask";
664
+ if (d1 & 8) return "an exotic cell";
665
+ if ((d1 & 7) > 4) return "a cell with more than 4 refs";
666
+ i += Math.ceil(d2 / 2) + (d1 & 7) * size;
667
+ }
668
+ if (i + (flags & 64 ? 4 : 0) !== b.length) return "trailing or missing bytes";
669
+ } catch {
670
+ return "truncated";
671
+ }
672
+ return null;
673
+ }
674
+ function messageBody(tx) {
622
675
  if (tx.body instanceof Cell3) return tx.body;
623
676
  if (typeof tx.body === "string") return tx.body === "" ? void 0 : commentCell(tx.body);
624
- if (tx.bodyBoc) return Cell3.fromBase64(tx.bodyBoc);
625
- return void 0;
677
+ if (tx.body !== void 0) throw new UnsafeTransactionError("body", "A message body must be a Cell or a string (a text comment).");
678
+ if (tx.bodyBoc !== void 0 && typeof tx.bodyBoc !== "string") throw new UnsafeTransactionError("body", "bodyBoc must be a base64 string.");
679
+ return tx.bodyBoc ? canonicalBocCell(tx.bodyBoc) : void 0;
680
+ }
681
+ function bodyOf(tx) {
682
+ return messageBody(tx);
626
683
  }
627
684
  function commentCell(text) {
628
685
  return beginCell2().storeUint(0, 32).storeStringTail(text).endCell();
@@ -728,6 +785,8 @@ import { ed25519 } from "@noble/curves/ed25519.js";
728
785
  import { Address as Address4, Cell as Cell4, beginCell as beginCell3, internal, loadStateInit } from "@ton/core";
729
786
  var JETTON_TRANSFER_OP2 = 260734629;
730
787
  var DEFAULT_JETTON_ATTACHED = 50000000n;
788
+ var DEFAULT_MAX_JETTON_ATTACHED = 1000000000n;
789
+ var RAW_ADDRESS = /^-?\d+:[0-9a-fA-F]{64}$/;
731
790
  var DEFAULT_INDEXER = "https://toncenter.com/api/v3";
732
791
  var DEFAULT_VALID_SECONDS = 60;
733
792
  var MAX_VALID_SECONDS = 600;
@@ -829,13 +888,15 @@ var WalletAccountReadOnlyTon = class {
829
888
  let address;
830
889
  let bounceable = true;
831
890
  let testOnly;
832
- if (Address4.isFriendly(to)) {
891
+ if (typeof to === "string" && Address4.isFriendly(to)) {
833
892
  const f = Address4.parseFriendly(to);
834
893
  address = f.address;
835
894
  bounceable = f.isBounceable;
836
895
  testOnly = f.isTestOnly;
837
- } else {
896
+ } else if (typeof to === "string" && RAW_ADDRESS.test(to)) {
838
897
  address = Address4.parse(to);
898
+ } else {
899
+ throw new UnsafeTransactionError("address", `${JSON.stringify(to)} is not a TON address in a strict form (raw wc:hex, or a friendly address with its checksum).`);
839
900
  }
840
901
  if (address.workChain !== 0 && address.workChain !== -1) throw new UnsafeTransactionError("exotic-workchain", `Refusing to send to workchain ${address.workChain}.`);
841
902
  const testnet = this._config.network === "testnet";
@@ -848,7 +909,7 @@ var WalletAccountReadOnlyTon = class {
848
909
  const value = big(tx.value);
849
910
  if (value <= 0n) throw new UnsafeTransactionError("zero-value", "TON message value must be positive.");
850
911
  const { address, bounceable } = this.checkedAddress(tx.to);
851
- const body = tx.body instanceof Cell4 ? tx.body : typeof tx.body === "string" ? tx.body === "" ? void 0 : commentCell(tx.body) : tx.bodyBoc ? Cell4.fromBase64(tx.bodyBoc) : void 0;
912
+ const body = messageBody(tx);
852
913
  const init = this.stateInitOf(tx.stateInit);
853
914
  const message = internal({ to: address, value, bounce: tx.bounceable ?? bounceable, ...body ? { body } : {}, ...init ? { init } : {} });
854
915
  return { message, ...tx.sendMode !== void 0 ? { mode: tx.sendMode } : {} };
@@ -858,14 +919,22 @@ var WalletAccountReadOnlyTon = class {
858
919
  if (amount <= 0n) throw new UnsafeTransactionError("zero-value", "Jetton amount must be positive.");
859
920
  const recipient = this.checkedAddress(o.recipient).address;
860
921
  const response = o.responseDestination ? this.checkedAddress(o.responseDestination).address : void 0;
922
+ if (response && !response.equals(this._address) && o.allowForeignResponseDestination !== true) {
923
+ throw new UnsafeTransactionError("foreign-response-destination", `The excess TON of this jetton transfer would go to ${response.toString()}, not to this wallet; pass allowForeignResponseDestination to allow it.`);
924
+ }
925
+ const forwardTon = o.forwardTonAmount !== void 0 ? big(o.forwardTonAmount) : 1n;
926
+ const attached = o.attachedValue !== void 0 ? big(o.attachedValue) : (this._config.jettonAttachedValue !== void 0 ? big(this._config.jettonAttachedValue) : DEFAULT_JETTON_ATTACHED) + forwardTon;
927
+ const maxAttached = this._config.maxJettonAttachedValue !== void 0 ? big(this._config.maxJettonAttachedValue) : DEFAULT_MAX_JETTON_ATTACHED;
928
+ if (attached > maxAttached || forwardTon > attached) {
929
+ throw new UnsafeTransactionError("attached-value", `A jetton transfer may attach at most ${maxAttached} nanotons, forwardTonAmount included (asked: ${attached}, forward ${forwardTon}); raise config.maxJettonAttachedValue if this is intended.`);
930
+ }
861
931
  const jw = await this.getJettonWalletAddress(o.token);
862
932
  await this.jettonWalletData(o.token, jw);
863
- const forwardTonAmount = o.forwardTonAmount !== void 0 ? big(o.forwardTonAmount) : 1n;
933
+ const forwardTonAmount = forwardTon;
864
934
  if (o.memo !== void 0 && o.forwardPayload !== void 0) throw new UnsafeTransactionError("memo-and-payload", "Pass either memo or forwardPayload, not both: a jetton transfer carries one forward payload.");
865
935
  const payload = o.forwardPayload ?? o.memo;
866
936
  const forwardPayload = payload === void 0 ? null : typeof payload === "string" ? commentCell(payload) : payload;
867
937
  const body = beginCell3().storeUint(JETTON_TRANSFER_OP2, 32).storeUint(o.queryId !== void 0 ? BigInt(o.queryId) : randomQueryId(), 64).storeCoins(amount).storeAddress(recipient).storeAddress(response ?? this._address).storeMaybeRef(o.customPayload ?? null).storeCoins(forwardTonAmount).storeMaybeRef(forwardPayload).endCell();
868
- const attached = o.attachedValue !== void 0 ? big(o.attachedValue) : (this._config.jettonAttachedValue !== void 0 ? big(this._config.jettonAttachedValue) : DEFAULT_JETTON_ATTACHED) + forwardTonAmount;
869
938
  return { message: internal({ to: jw, value: attached, bounce: true, body }) };
870
939
  }
871
940
  toMessages(tx) {
@@ -982,12 +1051,12 @@ function randomQueryId() {
982
1051
 
983
1052
  // src/account.ts
984
1053
  import { LocalSigner, feeLimit, requireCurve } from "@anywalletkit/core";
985
- import { Buffer as Buffer5 } from "buffer";
1054
+ import { Buffer as Buffer6 } from "buffer";
986
1055
  import { Cell as Cell5 } from "@ton/core";
987
1056
 
988
1057
  // src/tonconnect.ts
989
1058
  import { sha256 } from "@noble/hashes/sha2.js";
990
- import { Buffer as Buffer4 } from "buffer";
1059
+ import { Buffer as Buffer5 } from "buffer";
991
1060
  var utf82 = (s) => new TextEncoder().encode(s);
992
1061
  var int32BE = (n) => {
993
1062
  const b = new Uint8Array(4);
@@ -1022,7 +1091,7 @@ function checkCommon(address, domain, timestamp) {
1022
1091
  function base64Bytes(raw) {
1023
1092
  const s = raw.replace(/[\t\n\f\r ]/g, "");
1024
1093
  if (!/^[A-Za-z0-9+/]*={0,2}$/.test(s) || s.replace(/=+$/, "").length % 4 === 1) throw new TypeError("signData binary payload must be base64.");
1025
- return new Uint8Array(Buffer4.from(s, "base64"));
1094
+ return new Uint8Array(Buffer5.from(s, "base64"));
1026
1095
  }
1027
1096
  function tonProofDigest(address, request) {
1028
1097
  checkCommon(address, request.domain, request.timestamp);
@@ -1056,13 +1125,20 @@ var WalletAccountTon = class _WalletAccountTon extends WalletAccountReadOnlyTon
1056
1125
  needsNetwork = true;
1057
1126
  /** Derivation path, `ton-mnemonic`, or `external`. */
1058
1127
  path;
1059
- /** The signer that holds the key. */
1060
- signer;
1128
+ /**
1129
+ * The signer that holds the key, in a private field: not a property of the account, so no code
1130
+ * the account is handed to (a protocol module, a logger) can reach it and sign around the
1131
+ * account's checks (audit 2026-10-29 A1).
1132
+ */
1133
+ #signer;
1134
+ /** What holds the key: `seed`, `key` (one imported key) or `external`. */
1135
+ signerKind;
1061
1136
  _readOnly;
1062
1137
  /** `publicKey` is the signer's 32-byte ed25519 key; the V5R1 address derives from it synchronously. */
1063
1138
  constructor(signer, publicKey, path, config = {}) {
1064
1139
  super(publicKey, config);
1065
- this.signer = requireCurve(signer, "ed25519");
1140
+ this.#signer = requireCurve(signer, "ed25519");
1141
+ this.signerKind = this.#signer.kind;
1066
1142
  this.path = path;
1067
1143
  }
1068
1144
  /** Back-compat: wrap a raw derived key in a {@link LocalSigner} (the account takes ownership; it cannot derive). */
@@ -1085,7 +1161,7 @@ var WalletAccountTon = class _WalletAccountTon extends WalletAccountReadOnlyTon
1085
1161
  async sign(message) {
1086
1162
  const bytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
1087
1163
  if (bytes.length === 32 || carriesKey(bytes, this.publicKey)) throw new MessageIsTransactionError();
1088
- return toHex(await this.signer.sign(bytes, { scheme: "ed25519", context: "ton-message" }));
1164
+ return toHex(await this.#signer.sign(bytes, { scheme: "ed25519", context: "ton-message" }));
1089
1165
  }
1090
1166
  /**
1091
1167
  * TON Connect `ton_proof` for this wallet's address: the `proof` object of the connect reply. The
@@ -1094,20 +1170,20 @@ var WalletAccountTon = class _WalletAccountTon extends WalletAccountReadOnlyTon
1094
1170
  */
1095
1171
  async signTonProof(request) {
1096
1172
  const digest = tonProofDigest(this._address, request);
1097
- const signature = await this.signer.sign(digest, { scheme: "ed25519", context: "ton-proof" });
1173
+ const signature = await this.#signer.sign(digest, { scheme: "ed25519", context: "ton-proof" });
1098
1174
  return {
1099
1175
  timestamp: request.timestamp,
1100
1176
  domain: { lengthBytes: new TextEncoder().encode(request.domain).length, value: request.domain },
1101
1177
  payload: request.payload,
1102
- signature: Buffer5.from(signature).toString("base64")
1178
+ signature: Buffer6.from(signature).toString("base64")
1103
1179
  };
1104
1180
  }
1105
1181
  /** TON Connect `signData` (text / binary) for this wallet's address: the reply the dApp gets. */
1106
1182
  async signTonConnectData(request) {
1107
1183
  const digest = tonSignDataDigest(this._address, request);
1108
- const signature = await this.signer.sign(digest, { scheme: "ed25519", context: "ton-sign-data" });
1184
+ const signature = await this.#signer.sign(digest, { scheme: "ed25519", context: "ton-sign-data" });
1109
1185
  return {
1110
- signature: Buffer5.from(signature).toString("base64"),
1186
+ signature: Buffer6.from(signature).toString("base64"),
1111
1187
  address: this._address.toRawString(),
1112
1188
  timestamp: request.timestamp,
1113
1189
  domain: request.domain,
@@ -1135,7 +1211,7 @@ var WalletAccountTon = class _WalletAccountTon extends WalletAccountReadOnlyTon
1135
1211
  bodyModes(body) {
1136
1212
  return parseV5R1Body(body)?.messages.map((m) => m.mode) ?? [];
1137
1213
  }
1138
- async signMessages(messages, limit, op) {
1214
+ async #signMessages(messages, limit, op) {
1139
1215
  this.assertNoDrain(messages.map((m) => sendModeOf(m.mode)));
1140
1216
  const want = messages.reduce((sum, m) => sum + (m.message.info.type === "internal" ? m.message.info.value.coins : 0n), 0n);
1141
1217
  if (want > 0n) {
@@ -1144,7 +1220,7 @@ var WalletAccountTon = class _WalletAccountTon extends WalletAccountReadOnlyTon
1144
1220
  }
1145
1221
  const { signing } = await this.signingCell(messages);
1146
1222
  const fee = await this.preflight(v5r1PackUnsigned(signing), limit, op, want);
1147
- const signature = await this.signer.sign(new Uint8Array(signing.hash()), { scheme: "ed25519", context: "ton-external" });
1223
+ const signature = await this.#signer.sign(new Uint8Array(signing.hash()), { scheme: "ed25519", context: "ton-external" });
1148
1224
  return { body: v5r1PackSigned(signing, signature), fee };
1149
1225
  }
1150
1226
  async preflight(body, limit, op, expectedTonOut) {
@@ -1172,7 +1248,7 @@ var WalletAccountTon = class _WalletAccountTon extends WalletAccountReadOnlyTon
1172
1248
  await this.preflight(tx, feeLimit(this._config.transactionMaxFee, options), "transaction");
1173
1249
  return tx.toBoc().toString("base64");
1174
1250
  }
1175
- const { body } = await this.signMessages(this.toMessages(tx), feeLimit(this._config.transactionMaxFee, options), "transaction");
1251
+ const { body } = await this.#signMessages(this.toMessages(tx), feeLimit(this._config.transactionMaxFee, options), "transaction");
1176
1252
  return body.toBoc().toString("base64");
1177
1253
  }
1178
1254
  async broadcast(body) {
@@ -1191,14 +1267,14 @@ var WalletAccountTon = class _WalletAccountTon extends WalletAccountReadOnlyTon
1191
1267
  async sendTransaction(tx, options = {}) {
1192
1268
  this.requireRpc("send transactions");
1193
1269
  if (tx instanceof Cell5) this.assertNoDrain(this.bodyModes(tx));
1194
- const { body, fee } = tx instanceof Cell5 ? { body: tx, fee: await this.preflight(tx, feeLimit(this._config.transactionMaxFee, options), "transaction") } : await this.signMessages(this.toMessages(tx), feeLimit(this._config.transactionMaxFee, options), "transaction");
1270
+ const { body, fee } = tx instanceof Cell5 ? { body: tx, fee: await this.preflight(tx, feeLimit(this._config.transactionMaxFee, options), "transaction") } : await this.#signMessages(this.toMessages(tx), feeLimit(this._config.transactionMaxFee, options), "transaction");
1195
1271
  return { hash: await this.broadcast(body), fee };
1196
1272
  }
1197
1273
  /** TON (no `token`) or jetton transfer. */
1198
1274
  async transfer(o, writeOptions = {}) {
1199
1275
  this.requireRpc("transfer tokens");
1200
1276
  const message = o.token ? await this.jettonTransferMessage(o) : this.transactionMessage({ to: o.recipient, value: o.amount, ...o.memo !== void 0 ? { body: o.memo } : {} });
1201
- const { body, fee } = await this.signMessages([message], feeLimit(this._config.transferMaxFee, writeOptions), "transfer");
1277
+ const { body, fee } = await this.#signMessages([message], feeLimit(this._config.transferMaxFee, writeOptions), "transfer");
1202
1278
  return { hash: await this.broadcast(body), fee };
1203
1279
  }
1204
1280
  /** The same wallet as a {@link WalletAccountReadOnlyTon}. */
@@ -1208,7 +1284,7 @@ var WalletAccountTon = class _WalletAccountTon extends WalletAccountReadOnlyTon
1208
1284
  }
1209
1285
  /** Disposes the signer: a local key is zeroized, an external one is released. */
1210
1286
  dispose() {
1211
- this.signer.dispose();
1287
+ this.#signer.dispose();
1212
1288
  }
1213
1289
  };
1214
1290
 
@@ -1317,6 +1393,7 @@ export {
1317
1393
  WalletAccountReadOnlyTon,
1318
1394
  WalletAccountTon,
1319
1395
  WalletManagerTon,
1396
+ canonicalBocCell,
1320
1397
  commentCell,
1321
1398
  createTonRpc as createTonClient,
1322
1399
  createTonHistory,
@@ -1334,6 +1411,7 @@ export {
1334
1411
  mapActions as mapTonapiActions,
1335
1412
  mapTonapiEvent,
1336
1413
  mapToncenterTransaction,
1414
+ messageBody,
1337
1415
  parseEmulation,
1338
1416
  parseTonapiConsequences,
1339
1417
  parseTonapiRisk,