@t402/ton 2.0.0 → 2.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.
Files changed (38) hide show
  1. package/dist/cjs/exact/client/index.d.ts +63 -4
  2. package/dist/cjs/exact/client/index.js +29 -3
  3. package/dist/cjs/exact/client/index.js.map +1 -1
  4. package/dist/cjs/exact/facilitator/index.d.ts +63 -3
  5. package/dist/cjs/exact/facilitator/index.js +31 -4
  6. package/dist/cjs/exact/facilitator/index.js.map +1 -1
  7. package/dist/cjs/exact/server/index.d.ts +42 -17
  8. package/dist/cjs/exact/server/index.js +22 -40
  9. package/dist/cjs/exact/server/index.js.map +1 -1
  10. package/dist/cjs/index.d.ts +7 -2
  11. package/dist/cjs/index.js +496 -13
  12. package/dist/cjs/index.js.map +1 -1
  13. package/dist/cjs/{signer-CFiw2DST.d.ts → signer-Bqn2K0b4.d.ts} +1 -1
  14. package/dist/esm/{chunk-6LOUEHJT.mjs → chunk-3BN2G4M7.mjs} +6 -1
  15. package/dist/esm/chunk-3BN2G4M7.mjs.map +1 -0
  16. package/dist/esm/{chunk-ZCMWKFVA.mjs → chunk-7OE2PWYP.mjs} +28 -4
  17. package/dist/esm/chunk-7OE2PWYP.mjs.map +1 -0
  18. package/dist/esm/chunk-NGYEU24R.mjs +271 -0
  19. package/dist/esm/chunk-NGYEU24R.mjs.map +1 -0
  20. package/dist/esm/chunk-ZJA7AWWH.mjs +284 -0
  21. package/dist/esm/chunk-ZJA7AWWH.mjs.map +1 -0
  22. package/dist/esm/exact/client/index.d.mts +63 -4
  23. package/dist/esm/exact/client/index.mjs +6 -4
  24. package/dist/esm/exact/facilitator/index.d.mts +63 -3
  25. package/dist/esm/exact/facilitator/index.mjs +6 -254
  26. package/dist/esm/exact/facilitator/index.mjs.map +1 -1
  27. package/dist/esm/exact/server/index.d.mts +42 -17
  28. package/dist/esm/exact/server/index.mjs +6 -208
  29. package/dist/esm/exact/server/index.mjs.map +1 -1
  30. package/dist/esm/index.d.mts +7 -2
  31. package/dist/esm/index.mjs +13 -5
  32. package/dist/esm/index.mjs.map +1 -1
  33. package/dist/esm/{signer-CFiw2DST.d.mts → signer-Bqn2K0b4.d.mts} +1 -1
  34. package/package.json +8 -7
  35. package/dist/esm/chunk-6LOUEHJT.mjs.map +0 -1
  36. package/dist/esm/chunk-RST5PY7E.mjs +0 -85
  37. package/dist/esm/chunk-RST5PY7E.mjs.map +0 -1
  38. package/dist/esm/chunk-ZCMWKFVA.mjs.map +0 -1
package/dist/cjs/index.js CHANGED
@@ -3,6 +3,7 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
7
  var __export = (target, all) => {
7
8
  for (var name in all)
8
9
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -16,6 +17,7 @@ var __copyProps = (to, from, except, desc) => {
16
17
  return to;
17
18
  };
18
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
19
21
 
20
22
  // src/index.ts
21
23
  var src_exports = {};
@@ -62,6 +64,9 @@ __export(src_exports, {
62
64
  normalizeNetwork: () => normalizeNetwork,
63
65
  parseJettonTransferBody: () => parseJettonTransferBody,
64
66
  parseTonAddress: () => parseTonAddress,
67
+ registerExactTonClientScheme: () => registerExactTonScheme,
68
+ registerExactTonFacilitatorScheme: () => registerExactTonScheme3,
69
+ registerExactTonServerScheme: () => registerExactTonScheme2,
65
70
  toClientTonSigner: () => toClientTonSigner,
66
71
  toFacilitatorTonSigner: () => toFacilitatorTonSigner,
67
72
  validateTonAddress: () => validateTonAddress
@@ -241,7 +246,7 @@ var ExactTonScheme = class {
241
246
  this.signer = signer;
242
247
  this.getJettonWalletAddress = getJettonWalletAddress;
243
248
  this.config = config;
244
- this.scheme = SCHEME_EXACT;
249
+ __publicField(this, "scheme", SCHEME_EXACT);
245
250
  }
246
251
  /**
247
252
  * Creates a payment payload for the Exact scheme.
@@ -314,15 +319,26 @@ var ExactTonScheme = class {
314
319
  }
315
320
  };
316
321
 
317
- // src/signer.ts
318
- function toClientTonSigner(signer) {
319
- return signer;
320
- }
321
- function toFacilitatorTonSigner(client) {
322
- return {
323
- ...client,
324
- getAddresses: () => [client.address]
325
- };
322
+ // src/exact/client/register.ts
323
+ function registerExactTonScheme(client, config) {
324
+ const scheme = new ExactTonScheme(
325
+ config.signer,
326
+ config.getJettonWalletAddress,
327
+ config.schemeConfig
328
+ );
329
+ if (config.networks && config.networks.length > 0) {
330
+ config.networks.forEach((network) => {
331
+ client.register(network, scheme);
332
+ });
333
+ } else {
334
+ client.register("ton:*", scheme);
335
+ }
336
+ if (config.policies) {
337
+ config.policies.forEach((policy) => {
338
+ client.registerPolicy(policy);
339
+ });
340
+ }
341
+ return client;
326
342
  }
327
343
 
328
344
  // src/tokens.ts
@@ -369,9 +385,7 @@ function getDefaultJetton(network) {
369
385
  function getJettonByAddress(network, address) {
370
386
  const jettons = JETTON_REGISTRY[network];
371
387
  if (!jettons) return void 0;
372
- return Object.values(jettons).find(
373
- (j) => j.masterAddress.toLowerCase() === address.toLowerCase()
374
- );
388
+ return Object.values(jettons).find((j) => j.masterAddress.toLowerCase() === address.toLowerCase());
375
389
  }
376
390
  function getNetworksForJetton(symbol) {
377
391
  const networks = [];
@@ -391,6 +405,472 @@ function isNetworkSupported(network) {
391
405
  function getSupportedNetworks() {
392
406
  return Object.keys(JETTON_REGISTRY);
393
407
  }
408
+
409
+ // src/exact/server/scheme.ts
410
+ var ExactTonScheme2 = class {
411
+ constructor(config = {}) {
412
+ __publicField(this, "scheme", SCHEME_EXACT);
413
+ __publicField(this, "moneyParsers", []);
414
+ __publicField(this, "config");
415
+ this.config = config;
416
+ }
417
+ /**
418
+ * Register a custom money parser in the parser chain.
419
+ * Multiple parsers can be registered - they will be tried in registration order.
420
+ * Each parser receives a decimal amount (e.g., 1.50 for $1.50).
421
+ * If a parser returns null, the next parser in the chain will be tried.
422
+ * The default parser is always the final fallback.
423
+ *
424
+ * @param parser - Custom function to convert amount to AssetAmount (or null to skip)
425
+ * @returns The server instance for chaining
426
+ *
427
+ * @example
428
+ * tonServer.registerMoneyParser(async (amount, network) => {
429
+ * // Use custom Jetton for large amounts
430
+ * if (amount > 1000) {
431
+ * return {
432
+ * amount: (amount * 1e9).toString(),
433
+ * asset: "EQCustomJettonAddress...",
434
+ * extra: { tier: "premium" }
435
+ * };
436
+ * }
437
+ * return null; // Use next parser
438
+ * });
439
+ */
440
+ registerMoneyParser(parser) {
441
+ this.moneyParsers.push(parser);
442
+ return this;
443
+ }
444
+ /**
445
+ * Parses a price into an asset amount.
446
+ * If price is already an AssetAmount, returns it directly.
447
+ * If price is Money (string | number), parses to decimal and tries custom parsers.
448
+ * Falls back to default conversion if all custom parsers return null.
449
+ *
450
+ * @param price - The price to parse
451
+ * @param network - The network to use
452
+ * @returns Promise that resolves to the parsed asset amount
453
+ */
454
+ async parsePrice(price, network) {
455
+ const normalizedNetwork = normalizeNetwork(network);
456
+ if (typeof price === "object" && price !== null && "amount" in price) {
457
+ if (!price.asset) {
458
+ throw new Error(`Asset address must be specified for AssetAmount on network ${network}`);
459
+ }
460
+ return {
461
+ amount: price.amount,
462
+ asset: price.asset,
463
+ extra: price.extra || {}
464
+ };
465
+ }
466
+ const amount = this.parseMoneyToDecimal(price);
467
+ for (const parser of this.moneyParsers) {
468
+ const result = await parser(amount, normalizedNetwork);
469
+ if (result !== null) {
470
+ return result;
471
+ }
472
+ }
473
+ return this.defaultMoneyConversion(amount, normalizedNetwork);
474
+ }
475
+ /**
476
+ * Build payment requirements for this scheme/network combination.
477
+ * Adds TON-specific fields like gas sponsor if provided by facilitator.
478
+ *
479
+ * @param paymentRequirements - Base payment requirements with amount/asset already set
480
+ * @param supportedKind - The supported kind from facilitator's /supported endpoint
481
+ * @param extensionKeys - Extensions supported by the facilitator (unused)
482
+ * @returns Enhanced payment requirements ready to be sent to clients
483
+ */
484
+ async enhancePaymentRequirements(paymentRequirements, supportedKind, extensionKeys) {
485
+ void extensionKeys;
486
+ const extra = { ...paymentRequirements.extra };
487
+ if (supportedKind.extra?.gasSponsor) {
488
+ extra.gasSponsor = supportedKind.extra.gasSponsor;
489
+ }
490
+ return {
491
+ ...paymentRequirements,
492
+ extra
493
+ };
494
+ }
495
+ /**
496
+ * Parse Money (string | number) to a decimal number.
497
+ * Handles formats like "$1.50", "1.50", 1.50, etc.
498
+ *
499
+ * @param money - The money value to parse
500
+ * @returns Decimal number
501
+ */
502
+ parseMoneyToDecimal(money) {
503
+ if (typeof money === "number") {
504
+ return money;
505
+ }
506
+ const cleanMoney = money.replace(/^\$/, "").trim();
507
+ const amount = parseFloat(cleanMoney);
508
+ if (isNaN(amount)) {
509
+ throw new Error(`Invalid money format: ${money}`);
510
+ }
511
+ return amount;
512
+ }
513
+ /**
514
+ * Default money conversion implementation.
515
+ * Converts decimal amount to the preferred Jetton on the specified network.
516
+ *
517
+ * @param amount - The decimal amount (e.g., 1.50)
518
+ * @param network - The network to use
519
+ * @returns The parsed asset amount
520
+ */
521
+ defaultMoneyConversion(amount, network) {
522
+ const jetton = this.getDefaultAsset(network);
523
+ const tokenAmount = this.convertToTokenAmount(amount.toString(), jetton.decimals);
524
+ return {
525
+ amount: tokenAmount,
526
+ asset: jetton.masterAddress,
527
+ extra: {
528
+ symbol: jetton.symbol,
529
+ name: jetton.name,
530
+ decimals: jetton.decimals
531
+ }
532
+ };
533
+ }
534
+ /**
535
+ * Convert decimal amount to token units (e.g., 0.10 -> 100000 for 6-decimal tokens)
536
+ *
537
+ * @param decimalAmount - The decimal amount to convert
538
+ * @param decimals - Number of decimals for the token
539
+ * @returns The token amount as a string
540
+ */
541
+ convertToTokenAmount(decimalAmount, decimals) {
542
+ const amount = parseFloat(decimalAmount);
543
+ if (isNaN(amount)) {
544
+ throw new Error(`Invalid amount: ${decimalAmount}`);
545
+ }
546
+ const tokenAmount = Math.floor(amount * Math.pow(10, decimals));
547
+ return tokenAmount.toString();
548
+ }
549
+ /**
550
+ * Get the default asset info for a network.
551
+ * Priority: configured preferredJetton > USDT > first available
552
+ *
553
+ * @param network - The network to get asset info for
554
+ * @returns The Jetton configuration
555
+ */
556
+ getDefaultAsset(network) {
557
+ if (this.config.preferredJetton) {
558
+ const preferred = getJettonConfig(network, this.config.preferredJetton);
559
+ if (preferred) return preferred;
560
+ }
561
+ const defaultJetton = getDefaultJetton(network);
562
+ if (defaultJetton) return defaultJetton;
563
+ throw new Error(`No Jettons configured for network ${network}`);
564
+ }
565
+ /**
566
+ * Get all supported networks
567
+ */
568
+ static getSupportedNetworks() {
569
+ return Object.keys(JETTON_REGISTRY);
570
+ }
571
+ /**
572
+ * Check if a network is supported
573
+ */
574
+ static isNetworkSupported(network) {
575
+ return network in JETTON_REGISTRY;
576
+ }
577
+ };
578
+
579
+ // src/exact/server/register.ts
580
+ function registerExactTonScheme2(server, config = {}) {
581
+ const scheme = new ExactTonScheme2(config.schemeConfig);
582
+ if (config.networks && config.networks.length > 0) {
583
+ config.networks.forEach((network) => {
584
+ server.register(network, scheme);
585
+ });
586
+ } else {
587
+ server.register("ton:*", scheme);
588
+ }
589
+ return server;
590
+ }
591
+
592
+ // src/exact/facilitator/scheme.ts
593
+ var import_core3 = require("@ton/core");
594
+ var ExactTonScheme3 = class {
595
+ /**
596
+ * Creates a new ExactTonScheme facilitator instance.
597
+ *
598
+ * @param signer - The TON signer for facilitator operations
599
+ * @param config - Optional configuration
600
+ */
601
+ constructor(signer, config = {}) {
602
+ this.signer = signer;
603
+ __publicField(this, "scheme", SCHEME_EXACT);
604
+ __publicField(this, "caipFamily", "ton:*");
605
+ __publicField(this, "config");
606
+ this.config = config;
607
+ }
608
+ /**
609
+ * Get mechanism-specific extra data for the supported kinds endpoint.
610
+ * For TON, optionally returns gas sponsor address if configured.
611
+ *
612
+ * @param network - The network identifier
613
+ * @returns Extra data object or undefined
614
+ */
615
+ getExtra(network) {
616
+ void network;
617
+ if (this.config.canSponsorGas) {
618
+ const addresses = this.signer.getAddresses();
619
+ if (addresses.length > 0) {
620
+ return {
621
+ gasSponsor: addresses[0]
622
+ };
623
+ }
624
+ }
625
+ return void 0;
626
+ }
627
+ /**
628
+ * Get signer addresses used by this facilitator.
629
+ * Returns all addresses this facilitator can use for operations.
630
+ *
631
+ * @param network - The network identifier
632
+ * @returns Array of facilitator addresses
633
+ */
634
+ getSigners(network) {
635
+ void network;
636
+ return [...this.signer.getAddresses()];
637
+ }
638
+ /**
639
+ * Verifies a payment payload.
640
+ *
641
+ * Performs comprehensive validation:
642
+ * 1. Scheme and network matching
643
+ * 2. BOC format validation
644
+ * 3. Message structure verification
645
+ * 4. Authorization expiry check
646
+ * 5. Balance verification
647
+ * 6. Amount and recipient validation
648
+ *
649
+ * @param payload - The payment payload to verify
650
+ * @param requirements - The payment requirements
651
+ * @returns Promise resolving to verification response
652
+ */
653
+ async verify(payload, requirements) {
654
+ const tonPayload = payload.payload;
655
+ if (!tonPayload?.authorization?.from || !tonPayload?.signedBoc) {
656
+ return {
657
+ isValid: false,
658
+ invalidReason: "invalid_payload_structure",
659
+ payer: ""
660
+ };
661
+ }
662
+ const authorization = tonPayload.authorization;
663
+ if (payload.accepted.scheme !== SCHEME_EXACT || requirements.scheme !== SCHEME_EXACT) {
664
+ return {
665
+ isValid: false,
666
+ invalidReason: "unsupported_scheme",
667
+ payer: authorization.from
668
+ };
669
+ }
670
+ try {
671
+ const payloadNetwork = normalizeNetwork(payload.accepted.network);
672
+ const requirementsNetwork = normalizeNetwork(requirements.network);
673
+ if (payloadNetwork !== requirementsNetwork) {
674
+ return {
675
+ isValid: false,
676
+ invalidReason: "network_mismatch",
677
+ payer: authorization.from
678
+ };
679
+ }
680
+ } catch {
681
+ return {
682
+ isValid: false,
683
+ invalidReason: "invalid_network",
684
+ payer: authorization.from
685
+ };
686
+ }
687
+ try {
688
+ import_core3.Cell.fromBase64(tonPayload.signedBoc);
689
+ } catch {
690
+ return {
691
+ isValid: false,
692
+ invalidReason: "invalid_boc_format",
693
+ payer: authorization.from
694
+ };
695
+ }
696
+ const verifyResult = await this.signer.verifyMessage({
697
+ signedBoc: tonPayload.signedBoc,
698
+ expectedFrom: authorization.from,
699
+ expectedTransfer: {
700
+ jettonAmount: BigInt(authorization.jettonAmount),
701
+ destination: requirements.payTo,
702
+ jettonMaster: requirements.asset
703
+ }
704
+ });
705
+ if (!verifyResult.valid) {
706
+ return {
707
+ isValid: false,
708
+ invalidReason: verifyResult.reason || "message_verification_failed",
709
+ payer: authorization.from
710
+ };
711
+ }
712
+ const now = Math.floor(Date.now() / 1e3);
713
+ if (authorization.validUntil < now + 30) {
714
+ return {
715
+ isValid: false,
716
+ invalidReason: "authorization_expired",
717
+ payer: authorization.from
718
+ };
719
+ }
720
+ try {
721
+ const balance = await this.signer.getJettonBalance({
722
+ ownerAddress: authorization.from,
723
+ jettonMasterAddress: requirements.asset
724
+ });
725
+ if (balance < BigInt(requirements.amount)) {
726
+ return {
727
+ isValid: false,
728
+ invalidReason: "insufficient_jetton_balance",
729
+ payer: authorization.from
730
+ };
731
+ }
732
+ } catch (error) {
733
+ console.warn("Could not verify Jetton balance:", error);
734
+ }
735
+ if (BigInt(authorization.jettonAmount) < BigInt(requirements.amount)) {
736
+ return {
737
+ isValid: false,
738
+ invalidReason: "insufficient_amount",
739
+ payer: authorization.from
740
+ };
741
+ }
742
+ if (!addressesEqual(authorization.to, requirements.payTo)) {
743
+ return {
744
+ isValid: false,
745
+ invalidReason: "recipient_mismatch",
746
+ payer: authorization.from
747
+ };
748
+ }
749
+ if (!addressesEqual(authorization.jettonMaster, requirements.asset)) {
750
+ return {
751
+ isValid: false,
752
+ invalidReason: "asset_mismatch",
753
+ payer: authorization.from
754
+ };
755
+ }
756
+ try {
757
+ const currentSeqno = await this.signer.getSeqno(authorization.from);
758
+ if (authorization.seqno < currentSeqno) {
759
+ return {
760
+ isValid: false,
761
+ invalidReason: "seqno_already_used",
762
+ payer: authorization.from
763
+ };
764
+ }
765
+ if (authorization.seqno > currentSeqno) {
766
+ return {
767
+ isValid: false,
768
+ invalidReason: "seqno_too_high",
769
+ payer: authorization.from
770
+ };
771
+ }
772
+ } catch (error) {
773
+ console.warn("Could not verify seqno:", error);
774
+ }
775
+ try {
776
+ const isDeployed = await this.signer.isDeployed(authorization.from);
777
+ if (!isDeployed) {
778
+ return {
779
+ isValid: false,
780
+ invalidReason: "wallet_not_deployed",
781
+ payer: authorization.from
782
+ };
783
+ }
784
+ } catch (error) {
785
+ console.warn("Could not verify wallet deployment:", error);
786
+ }
787
+ return {
788
+ isValid: true,
789
+ invalidReason: void 0,
790
+ payer: authorization.from
791
+ };
792
+ }
793
+ /**
794
+ * Settles a payment by broadcasting the signed message.
795
+ *
796
+ * @param payload - The payment payload to settle
797
+ * @param requirements - The payment requirements
798
+ * @returns Promise resolving to settlement response
799
+ */
800
+ async settle(payload, requirements) {
801
+ const tonPayload = payload.payload;
802
+ if (!tonPayload?.authorization?.from || !tonPayload?.signedBoc) {
803
+ return {
804
+ success: false,
805
+ network: payload.accepted.network,
806
+ transaction: "",
807
+ errorReason: "invalid_payload_structure",
808
+ payer: ""
809
+ };
810
+ }
811
+ const verifyResult = await this.verify(payload, requirements);
812
+ if (!verifyResult.isValid) {
813
+ return {
814
+ success: false,
815
+ network: payload.accepted.network,
816
+ transaction: "",
817
+ errorReason: verifyResult.invalidReason ?? "verification_failed",
818
+ payer: tonPayload.authorization.from
819
+ };
820
+ }
821
+ try {
822
+ const txHash = await this.signer.sendExternalMessage(tonPayload.signedBoc);
823
+ const confirmation = await this.signer.waitForTransaction({
824
+ address: tonPayload.authorization.from,
825
+ seqno: tonPayload.authorization.seqno + 1,
826
+ // Wait for next seqno
827
+ timeout: 6e4
828
+ // 60 second timeout
829
+ });
830
+ if (!confirmation.success) {
831
+ return {
832
+ success: false,
833
+ errorReason: confirmation.error || "transaction_not_confirmed",
834
+ transaction: txHash,
835
+ network: payload.accepted.network,
836
+ payer: tonPayload.authorization.from
837
+ };
838
+ }
839
+ return {
840
+ success: true,
841
+ transaction: confirmation.hash || txHash,
842
+ network: payload.accepted.network,
843
+ payer: tonPayload.authorization.from
844
+ };
845
+ } catch (error) {
846
+ console.error("Failed to settle TON transaction:", error);
847
+ return {
848
+ success: false,
849
+ errorReason: "transaction_failed",
850
+ transaction: "",
851
+ network: payload.accepted.network,
852
+ payer: tonPayload.authorization.from
853
+ };
854
+ }
855
+ }
856
+ };
857
+
858
+ // src/exact/facilitator/register.ts
859
+ function registerExactTonScheme3(facilitator, config) {
860
+ facilitator.register(config.networks, new ExactTonScheme3(config.signer, config.schemeConfig));
861
+ return facilitator;
862
+ }
863
+
864
+ // src/signer.ts
865
+ function toClientTonSigner(signer) {
866
+ return signer;
867
+ }
868
+ function toFacilitatorTonSigner(client) {
869
+ return {
870
+ ...client,
871
+ getAddresses: () => [client.address]
872
+ };
873
+ }
394
874
  // Annotate the CommonJS export names for ESM import in node:
395
875
  0 && (module.exports = {
396
876
  DEFAULT_FORWARD_TON,
@@ -435,6 +915,9 @@ function getSupportedNetworks() {
435
915
  normalizeNetwork,
436
916
  parseJettonTransferBody,
437
917
  parseTonAddress,
918
+ registerExactTonClientScheme,
919
+ registerExactTonFacilitatorScheme,
920
+ registerExactTonServerScheme,
438
921
  toClientTonSigner,
439
922
  toFacilitatorTonSigner,
440
923
  validateTonAddress