@t402/ton 2.0.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/cjs/exact/client/index.d.ts +53 -0
- package/dist/cjs/exact/client/index.js +181 -0
- package/dist/cjs/exact/client/index.js.map +1 -0
- package/dist/cjs/exact/facilitator/index.d.ts +79 -0
- package/dist/cjs/exact/facilitator/index.js +331 -0
- package/dist/cjs/exact/facilitator/index.js.map +1 -0
- package/dist/cjs/exact/server/index.d.ts +135 -0
- package/dist/cjs/exact/server/index.js +318 -0
- package/dist/cjs/exact/server/index.js.map +1 -0
- package/dist/cjs/index.d.ts +293 -0
- package/dist/cjs/index.js +442 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/signer-CFiw2DST.d.ts +277 -0
- package/dist/esm/chunk-6LOUEHJT.mjs +192 -0
- package/dist/esm/chunk-6LOUEHJT.mjs.map +1 -0
- package/dist/esm/chunk-RST5PY7E.mjs +85 -0
- package/dist/esm/chunk-RST5PY7E.mjs.map +1 -0
- package/dist/esm/chunk-ZCMWKFVA.mjs +101 -0
- package/dist/esm/chunk-ZCMWKFVA.mjs.map +1 -0
- package/dist/esm/exact/client/index.d.mts +53 -0
- package/dist/esm/exact/client/index.mjs +8 -0
- package/dist/esm/exact/client/index.mjs.map +1 -0
- package/dist/esm/exact/facilitator/index.d.mts +79 -0
- package/dist/esm/exact/facilitator/index.mjs +258 -0
- package/dist/esm/exact/facilitator/index.mjs.map +1 -0
- package/dist/esm/exact/server/index.d.mts +135 -0
- package/dist/esm/exact/server/index.mjs +212 -0
- package/dist/esm/exact/server/index.mjs.map +1 -0
- package/dist/esm/index.d.mts +293 -0
- package/dist/esm/index.mjs +108 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/signer-CFiw2DST.d.mts +277 -0
- package/package.json +99 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { SchemeNetworkClient, PaymentRequirements, PaymentPayload } from '@t402/core/types';
|
|
2
|
+
import { C as ClientTonSigner } from '../../signer-CFiw2DST.js';
|
|
3
|
+
import '@ton/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* TON Client Scheme Implementation
|
|
7
|
+
*
|
|
8
|
+
* Creates payment payloads for TON Jetton transfers using the exact scheme.
|
|
9
|
+
* Builds and signs external messages for Jetton wallet interactions.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Configuration for ExactTonScheme client
|
|
14
|
+
*/
|
|
15
|
+
interface ExactTonSchemeConfig {
|
|
16
|
+
/** Override the TON amount attached for gas (in nanoTON) */
|
|
17
|
+
gasAmount?: bigint;
|
|
18
|
+
/** Override the forward TON amount (in nanoTON) */
|
|
19
|
+
forwardAmount?: bigint;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* TON client implementation for the Exact payment scheme.
|
|
23
|
+
*
|
|
24
|
+
* Creates signed Jetton transfer messages that can be broadcast
|
|
25
|
+
* by a facilitator to complete the payment.
|
|
26
|
+
*/
|
|
27
|
+
declare class ExactTonScheme implements SchemeNetworkClient {
|
|
28
|
+
private readonly signer;
|
|
29
|
+
private readonly getJettonWalletAddress;
|
|
30
|
+
private readonly config;
|
|
31
|
+
readonly scheme = "exact";
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new ExactTonScheme instance.
|
|
34
|
+
*
|
|
35
|
+
* @param signer - The TON signer for client operations
|
|
36
|
+
* @param getJettonWalletAddress - Function to derive Jetton wallet address
|
|
37
|
+
* @param config - Optional configuration overrides
|
|
38
|
+
*/
|
|
39
|
+
constructor(signer: ClientTonSigner, getJettonWalletAddress: (ownerAddress: string, jettonMasterAddress: string) => Promise<string>, config?: ExactTonSchemeConfig);
|
|
40
|
+
/**
|
|
41
|
+
* Creates a payment payload for the Exact scheme.
|
|
42
|
+
*
|
|
43
|
+
* The payload contains a pre-signed external message that performs
|
|
44
|
+
* a Jetton transfer from the client to the recipient.
|
|
45
|
+
*
|
|
46
|
+
* @param t402Version - The t402 protocol version
|
|
47
|
+
* @param paymentRequirements - The payment requirements
|
|
48
|
+
* @returns Promise resolving to a payment payload
|
|
49
|
+
*/
|
|
50
|
+
createPaymentPayload(t402Version: number, paymentRequirements: PaymentRequirements): Promise<Pick<PaymentPayload, "t402Version" | "payload">>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { ExactTonScheme, type ExactTonSchemeConfig };
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/exact/client/index.ts
|
|
21
|
+
var client_exports = {};
|
|
22
|
+
__export(client_exports, {
|
|
23
|
+
ExactTonScheme: () => ExactTonScheme
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(client_exports);
|
|
26
|
+
|
|
27
|
+
// src/exact/client/scheme.ts
|
|
28
|
+
var import_core2 = require("@ton/core");
|
|
29
|
+
|
|
30
|
+
// src/constants.ts
|
|
31
|
+
var TON_MAINNET_CAIP2 = "ton:mainnet";
|
|
32
|
+
var TON_TESTNET_CAIP2 = "ton:testnet";
|
|
33
|
+
var TON_NETWORKS = [TON_MAINNET_CAIP2, TON_TESTNET_CAIP2];
|
|
34
|
+
var TON_MAINNET_ENDPOINT = "https://toncenter.com/api/v2/jsonRPC";
|
|
35
|
+
var TON_TESTNET_ENDPOINT = "https://testnet.toncenter.com/api/v2/jsonRPC";
|
|
36
|
+
var TON_MAINNET_V4_ENDPOINT = "https://mainnet-v4.tonhubapi.com";
|
|
37
|
+
var TON_TESTNET_V4_ENDPOINT = "https://testnet-v4.tonhubapi.com";
|
|
38
|
+
var NETWORK_ENDPOINTS = {
|
|
39
|
+
[TON_MAINNET_CAIP2]: TON_MAINNET_ENDPOINT,
|
|
40
|
+
[TON_TESTNET_CAIP2]: TON_TESTNET_ENDPOINT
|
|
41
|
+
};
|
|
42
|
+
var NETWORK_V4_ENDPOINTS = {
|
|
43
|
+
[TON_MAINNET_CAIP2]: TON_MAINNET_V4_ENDPOINT,
|
|
44
|
+
[TON_TESTNET_CAIP2]: TON_TESTNET_V4_ENDPOINT
|
|
45
|
+
};
|
|
46
|
+
var JETTON_TRANSFER_OP = 260734629;
|
|
47
|
+
var DEFAULT_JETTON_TRANSFER_TON = 100000000n;
|
|
48
|
+
var DEFAULT_FORWARD_TON = 1n;
|
|
49
|
+
var SCHEME_EXACT = "exact";
|
|
50
|
+
|
|
51
|
+
// src/utils.ts
|
|
52
|
+
var import_core = require("@ton/core");
|
|
53
|
+
function normalizeNetwork(network) {
|
|
54
|
+
if (network.startsWith("ton:")) {
|
|
55
|
+
if (!TON_NETWORKS.includes(network)) {
|
|
56
|
+
throw new Error(`Unsupported TON network: ${network}`);
|
|
57
|
+
}
|
|
58
|
+
return network;
|
|
59
|
+
}
|
|
60
|
+
const mapping = {
|
|
61
|
+
ton: TON_MAINNET_CAIP2,
|
|
62
|
+
"ton-mainnet": TON_MAINNET_CAIP2,
|
|
63
|
+
mainnet: TON_MAINNET_CAIP2,
|
|
64
|
+
"ton-testnet": TON_TESTNET_CAIP2,
|
|
65
|
+
testnet: TON_TESTNET_CAIP2
|
|
66
|
+
};
|
|
67
|
+
const caip2 = mapping[network.toLowerCase()];
|
|
68
|
+
if (!caip2) {
|
|
69
|
+
throw new Error(`Unsupported TON network: ${network}`);
|
|
70
|
+
}
|
|
71
|
+
return caip2;
|
|
72
|
+
}
|
|
73
|
+
function parseTonAddress(address) {
|
|
74
|
+
return import_core.Address.parse(address);
|
|
75
|
+
}
|
|
76
|
+
function generateQueryId() {
|
|
77
|
+
const timestamp = BigInt(Date.now());
|
|
78
|
+
const random = BigInt(Math.floor(Math.random() * 1e6));
|
|
79
|
+
return timestamp * 1000000n + random;
|
|
80
|
+
}
|
|
81
|
+
function buildJettonTransferBody(params) {
|
|
82
|
+
const builder = (0, import_core.beginCell)().storeUint(JETTON_TRANSFER_OP, 32).storeUint(params.queryId, 64).storeCoins(params.amount).storeAddress(params.destination).storeAddress(params.responseDestination).storeBit(false);
|
|
83
|
+
builder.storeCoins(params.forwardAmount ?? 1n);
|
|
84
|
+
if (params.forwardPayload) {
|
|
85
|
+
builder.storeBit(true).storeRef(params.forwardPayload);
|
|
86
|
+
} else {
|
|
87
|
+
builder.storeBit(false);
|
|
88
|
+
}
|
|
89
|
+
return builder.endCell();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/exact/client/scheme.ts
|
|
93
|
+
var ExactTonScheme = class {
|
|
94
|
+
/**
|
|
95
|
+
* Creates a new ExactTonScheme instance.
|
|
96
|
+
*
|
|
97
|
+
* @param signer - The TON signer for client operations
|
|
98
|
+
* @param getJettonWalletAddress - Function to derive Jetton wallet address
|
|
99
|
+
* @param config - Optional configuration overrides
|
|
100
|
+
*/
|
|
101
|
+
constructor(signer, getJettonWalletAddress, config = {}) {
|
|
102
|
+
this.signer = signer;
|
|
103
|
+
this.getJettonWalletAddress = getJettonWalletAddress;
|
|
104
|
+
this.config = config;
|
|
105
|
+
this.scheme = SCHEME_EXACT;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Creates a payment payload for the Exact scheme.
|
|
109
|
+
*
|
|
110
|
+
* The payload contains a pre-signed external message that performs
|
|
111
|
+
* a Jetton transfer from the client to the recipient.
|
|
112
|
+
*
|
|
113
|
+
* @param t402Version - The t402 protocol version
|
|
114
|
+
* @param paymentRequirements - The payment requirements
|
|
115
|
+
* @returns Promise resolving to a payment payload
|
|
116
|
+
*/
|
|
117
|
+
async createPaymentPayload(t402Version, paymentRequirements) {
|
|
118
|
+
const network = normalizeNetwork(paymentRequirements.network);
|
|
119
|
+
if (!paymentRequirements.asset) {
|
|
120
|
+
throw new Error("Asset (Jetton master address) is required");
|
|
121
|
+
}
|
|
122
|
+
if (!paymentRequirements.payTo) {
|
|
123
|
+
throw new Error("PayTo address is required");
|
|
124
|
+
}
|
|
125
|
+
if (!paymentRequirements.amount) {
|
|
126
|
+
throw new Error("Amount is required");
|
|
127
|
+
}
|
|
128
|
+
const jettonMasterAddress = paymentRequirements.asset;
|
|
129
|
+
const destinationAddress = parseTonAddress(paymentRequirements.payTo);
|
|
130
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(
|
|
131
|
+
this.signer.address.toString(),
|
|
132
|
+
jettonMasterAddress
|
|
133
|
+
);
|
|
134
|
+
const senderJettonWallet = import_core2.Address.parse(senderJettonWalletAddress);
|
|
135
|
+
const seqno = await this.signer.getSeqno();
|
|
136
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
137
|
+
const validUntil = now + paymentRequirements.maxTimeoutSeconds;
|
|
138
|
+
const queryId = generateQueryId();
|
|
139
|
+
const jettonAmount = BigInt(paymentRequirements.amount);
|
|
140
|
+
const jettonTransferBody = buildJettonTransferBody({
|
|
141
|
+
queryId,
|
|
142
|
+
amount: jettonAmount,
|
|
143
|
+
destination: destinationAddress,
|
|
144
|
+
responseDestination: this.signer.address,
|
|
145
|
+
forwardAmount: this.config.forwardAmount ?? DEFAULT_FORWARD_TON
|
|
146
|
+
});
|
|
147
|
+
const tonAmount = this.config.gasAmount ?? DEFAULT_JETTON_TRANSFER_TON;
|
|
148
|
+
const signedMessage = await this.signer.signMessage({
|
|
149
|
+
to: senderJettonWallet,
|
|
150
|
+
value: tonAmount,
|
|
151
|
+
body: jettonTransferBody,
|
|
152
|
+
sendMode: import_core2.SendMode.PAY_GAS_SEPARATELY,
|
|
153
|
+
timeout: paymentRequirements.maxTimeoutSeconds
|
|
154
|
+
});
|
|
155
|
+
const signedBoc = signedMessage.toBoc().toString("base64");
|
|
156
|
+
const authorization = {
|
|
157
|
+
from: this.signer.address.toString({ bounceable: true }),
|
|
158
|
+
to: paymentRequirements.payTo,
|
|
159
|
+
jettonMaster: jettonMasterAddress,
|
|
160
|
+
jettonAmount: jettonAmount.toString(),
|
|
161
|
+
tonAmount: tonAmount.toString(),
|
|
162
|
+
validUntil,
|
|
163
|
+
seqno,
|
|
164
|
+
queryId: queryId.toString()
|
|
165
|
+
};
|
|
166
|
+
const payload = {
|
|
167
|
+
signedBoc,
|
|
168
|
+
authorization
|
|
169
|
+
};
|
|
170
|
+
void network;
|
|
171
|
+
return {
|
|
172
|
+
t402Version,
|
|
173
|
+
payload
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
178
|
+
0 && (module.exports = {
|
|
179
|
+
ExactTonScheme
|
|
180
|
+
});
|
|
181
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/exact/client/index.ts","../../../../src/exact/client/scheme.ts","../../../../src/constants.ts","../../../../src/utils.ts"],"sourcesContent":["export { ExactTonScheme } from \"./scheme.js\";\nexport type { ExactTonSchemeConfig } from \"./scheme.js\";\n","/**\n * TON Client Scheme Implementation\n *\n * Creates payment payloads for TON Jetton transfers using the exact scheme.\n * Builds and signs external messages for Jetton wallet interactions.\n */\n\nimport { Address, SendMode } from \"@ton/core\";\nimport type { PaymentPayload, PaymentRequirements, SchemeNetworkClient } from \"@t402/core/types\";\nimport type { ClientTonSigner } from \"../../signer.js\";\nimport type { ExactTonPayloadV2 } from \"../../types.js\";\nimport { SCHEME_EXACT, DEFAULT_JETTON_TRANSFER_TON, DEFAULT_FORWARD_TON } from \"../../constants.js\";\nimport {\n generateQueryId,\n buildJettonTransferBody,\n normalizeNetwork,\n parseTonAddress,\n} from \"../../utils.js\";\n\n/**\n * Configuration for ExactTonScheme client\n */\nexport interface ExactTonSchemeConfig {\n /** Override the TON amount attached for gas (in nanoTON) */\n gasAmount?: bigint;\n /** Override the forward TON amount (in nanoTON) */\n forwardAmount?: bigint;\n}\n\n/**\n * TON client implementation for the Exact payment scheme.\n *\n * Creates signed Jetton transfer messages that can be broadcast\n * by a facilitator to complete the payment.\n */\nexport class ExactTonScheme implements SchemeNetworkClient {\n readonly scheme = SCHEME_EXACT;\n\n /**\n * Creates a new ExactTonScheme instance.\n *\n * @param signer - The TON signer for client operations\n * @param getJettonWalletAddress - Function to derive Jetton wallet address\n * @param config - Optional configuration overrides\n */\n constructor(\n private readonly signer: ClientTonSigner,\n private readonly getJettonWalletAddress: (\n ownerAddress: string,\n jettonMasterAddress: string,\n ) => Promise<string>,\n private readonly config: ExactTonSchemeConfig = {},\n ) {}\n\n /**\n * Creates a payment payload for the Exact scheme.\n *\n * The payload contains a pre-signed external message that performs\n * a Jetton transfer from the client to the recipient.\n *\n * @param t402Version - The t402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload\n */\n async createPaymentPayload(\n t402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<Pick<PaymentPayload, \"t402Version\" | \"payload\">> {\n // Normalize and validate network\n const network = normalizeNetwork(paymentRequirements.network);\n\n // Validate required fields\n if (!paymentRequirements.asset) {\n throw new Error(\"Asset (Jetton master address) is required\");\n }\n if (!paymentRequirements.payTo) {\n throw new Error(\"PayTo address is required\");\n }\n if (!paymentRequirements.amount) {\n throw new Error(\"Amount is required\");\n }\n\n // Parse addresses\n const jettonMasterAddress = paymentRequirements.asset;\n const destinationAddress = parseTonAddress(paymentRequirements.payTo);\n\n // Get client's Jetton wallet address\n const senderJettonWalletAddress = await this.getJettonWalletAddress(\n this.signer.address.toString(),\n jettonMasterAddress,\n );\n const senderJettonWallet = Address.parse(senderJettonWalletAddress);\n\n // Get current seqno for replay protection\n const seqno = await this.signer.getSeqno();\n\n // Calculate validity period\n const now = Math.floor(Date.now() / 1000);\n const validUntil = now + paymentRequirements.maxTimeoutSeconds;\n\n // Generate unique query ID\n const queryId = generateQueryId();\n\n // Parse amount\n const jettonAmount = BigInt(paymentRequirements.amount);\n\n // Build Jetton transfer body\n const jettonTransferBody = buildJettonTransferBody({\n queryId,\n amount: jettonAmount,\n destination: destinationAddress,\n responseDestination: this.signer.address,\n forwardAmount: this.config.forwardAmount ?? DEFAULT_FORWARD_TON,\n });\n\n // Gas amount for the transfer\n const tonAmount = this.config.gasAmount ?? DEFAULT_JETTON_TRANSFER_TON;\n\n // Sign the message\n const signedMessage = await this.signer.signMessage({\n to: senderJettonWallet,\n value: tonAmount,\n body: jettonTransferBody,\n sendMode: SendMode.PAY_GAS_SEPARATELY,\n timeout: paymentRequirements.maxTimeoutSeconds,\n });\n\n // Encode to base64\n const signedBoc = signedMessage.toBoc().toString(\"base64\");\n\n // Build authorization metadata\n const authorization: ExactTonPayloadV2[\"authorization\"] = {\n from: this.signer.address.toString({ bounceable: true }),\n to: paymentRequirements.payTo,\n jettonMaster: jettonMasterAddress,\n jettonAmount: jettonAmount.toString(),\n tonAmount: tonAmount.toString(),\n validUntil,\n seqno,\n queryId: queryId.toString(),\n };\n\n // Create payload\n const payload: ExactTonPayloadV2 = {\n signedBoc,\n authorization,\n };\n\n // Mark network as used\n void network;\n\n return {\n t402Version,\n payload,\n };\n }\n}\n","/**\n * TON Network Constants\n *\n * This module provides constants for TON blockchain integration including:\n * - CAIP-2 network identifiers\n * - RPC endpoints\n * - Jetton transfer operation codes\n * - Default gas amounts\n */\n\n/**\n * CAIP-2 Network Identifiers for TON\n * Using simple identifiers for mainnet/testnet\n */\nexport const TON_MAINNET_CAIP2 = \"ton:mainnet\";\nexport const TON_TESTNET_CAIP2 = \"ton:testnet\";\n\n/**\n * Supported TON networks\n */\nexport const TON_NETWORKS = [TON_MAINNET_CAIP2, TON_TESTNET_CAIP2] as const;\n\nexport type TonNetwork = (typeof TON_NETWORKS)[number];\n\n/**\n * Default RPC endpoints (TonCenter API v2)\n */\nexport const TON_MAINNET_ENDPOINT = \"https://toncenter.com/api/v2/jsonRPC\";\nexport const TON_TESTNET_ENDPOINT = \"https://testnet.toncenter.com/api/v2/jsonRPC\";\n\n/**\n * TON API v4 endpoints (for @ton/ton TonClient4)\n */\nexport const TON_MAINNET_V4_ENDPOINT = \"https://mainnet-v4.tonhubapi.com\";\nexport const TON_TESTNET_V4_ENDPOINT = \"https://testnet-v4.tonhubapi.com\";\n\n/**\n * Network endpoint mapping\n */\nexport const NETWORK_ENDPOINTS: Record<string, string> = {\n [TON_MAINNET_CAIP2]: TON_MAINNET_ENDPOINT,\n [TON_TESTNET_CAIP2]: TON_TESTNET_ENDPOINT,\n};\n\nexport const NETWORK_V4_ENDPOINTS: Record<string, string> = {\n [TON_MAINNET_CAIP2]: TON_MAINNET_V4_ENDPOINT,\n [TON_TESTNET_CAIP2]: TON_TESTNET_V4_ENDPOINT,\n};\n\n/**\n * Jetton Transfer Operation Codes (TEP-74)\n * @see https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md\n */\nexport const JETTON_TRANSFER_OP = 0x0f8a7ea5; // transfer\nexport const JETTON_INTERNAL_TRANSFER_OP = 0x178d4519; // internal_transfer\nexport const JETTON_TRANSFER_NOTIFICATION_OP = 0x7362d09c; // transfer_notification\nexport const JETTON_BURN_OP = 0x595f07bc; // burn\n\n/**\n * Default gas amounts for Jetton transfers\n * TON requires attaching TON for gas to internal messages\n */\nexport const DEFAULT_JETTON_TRANSFER_TON = 100_000_000n; // 0.1 TON for gas\nexport const DEFAULT_FORWARD_TON = 1n; // Minimal forward amount (notification)\nexport const MIN_JETTON_TRANSFER_TON = 50_000_000n; // 0.05 TON minimum\n\n/**\n * Maximum gas amounts to prevent excessive fees\n */\nexport const MAX_JETTON_TRANSFER_TON = 500_000_000n; // 0.5 TON maximum\n\n/**\n * Scheme identifier for exact payments\n */\nexport const SCHEME_EXACT = \"exact\";\n\n/**\n * Default timeout for payment validity (in seconds)\n */\nexport const DEFAULT_VALIDITY_DURATION = 3600; // 1 hour\n\n/**\n * Address format constants\n */\nexport const TON_ADDRESS_LENGTH = 48; // Friendly format length (base64url)\nexport const TON_RAW_ADDRESS_LENGTH = 66; // Raw format: workchain:hash (0:64hex)\n","/**\n * TON Utility Functions\n *\n * Helper functions for TON address handling, message building,\n * and network operations.\n */\n\nimport { Address, beginCell, Cell } from \"@ton/core\";\nimport type { Network } from \"@t402/core/types\";\nimport {\n TON_MAINNET_CAIP2,\n TON_TESTNET_CAIP2,\n TON_NETWORKS,\n NETWORK_ENDPOINTS,\n JETTON_TRANSFER_OP,\n} from \"./constants.js\";\n\n/**\n * Normalize network identifier to CAIP-2 format\n *\n * @param network - Network identifier (may be legacy format)\n * @returns Normalized CAIP-2 network identifier\n * @throws Error if network is not supported\n */\nexport function normalizeNetwork(network: Network): Network {\n // Already in CAIP-2 format\n if (network.startsWith(\"ton:\")) {\n if (!TON_NETWORKS.includes(network as (typeof TON_NETWORKS)[number])) {\n throw new Error(`Unsupported TON network: ${network}`);\n }\n return network as Network;\n }\n\n // Handle legacy format conversions\n const mapping: Record<string, Network> = {\n ton: TON_MAINNET_CAIP2 as Network,\n \"ton-mainnet\": TON_MAINNET_CAIP2 as Network,\n mainnet: TON_MAINNET_CAIP2 as Network,\n \"ton-testnet\": TON_TESTNET_CAIP2 as Network,\n testnet: TON_TESTNET_CAIP2 as Network,\n };\n\n const caip2 = mapping[network.toLowerCase()];\n if (!caip2) {\n throw new Error(`Unsupported TON network: ${network}`);\n }\n return caip2;\n}\n\n/**\n * Get RPC endpoint for a network\n *\n * @param network - Network identifier\n * @returns RPC endpoint URL\n */\nexport function getEndpoint(network: Network): string {\n const caip2 = normalizeNetwork(network);\n const endpoint = NETWORK_ENDPOINTS[caip2];\n if (!endpoint) {\n throw new Error(`No endpoint configured for network: ${network}`);\n }\n return endpoint;\n}\n\n/**\n * Check if a network identifier is a supported TON network\n *\n * @param network - Network identifier to check\n * @returns true if supported\n */\nexport function isTonNetwork(network: string): boolean {\n try {\n normalizeNetwork(network as Network);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Validate TON address format\n *\n * @param address - Address to validate\n * @returns true if valid TON address\n */\nexport function validateTonAddress(address: string): boolean {\n try {\n Address.parse(address);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Parse TON address from string\n *\n * @param address - Address string (friendly or raw format)\n * @returns Parsed Address object\n * @throws Error if invalid format\n */\nexport function parseTonAddress(address: string): Address {\n return Address.parse(address);\n}\n\n/**\n * Compare two TON addresses for equality\n * Handles different address formats (friendly, raw, bounceable/non-bounceable)\n *\n * @param addr1 - First address\n * @param addr2 - Second address\n * @returns true if addresses are equal\n */\nexport function addressesEqual(addr1: string, addr2: string): boolean {\n try {\n const a1 = Address.parse(addr1);\n const a2 = Address.parse(addr2);\n return a1.equals(a2);\n } catch {\n return false;\n }\n}\n\n/**\n * Format address to friendly format\n *\n * @param address - Address to format\n * @param options - Formatting options\n * @returns Friendly format address string\n */\nexport function formatAddress(\n address: string | Address,\n options?: { bounceable?: boolean; testOnly?: boolean },\n): string {\n const addr = typeof address === \"string\" ? Address.parse(address) : address;\n return addr.toString({\n bounceable: options?.bounceable ?? true,\n testOnly: options?.testOnly ?? false,\n });\n}\n\n/**\n * Convert decimal amount to smallest units (e.g., nano-Jettons)\n *\n * @param decimalAmount - Amount in decimal format (e.g., \"1.50\")\n * @param decimals - Number of decimal places\n * @returns Amount in smallest units as string\n */\nexport function convertToJettonAmount(decimalAmount: string, decimals: number): string {\n const amount = parseFloat(decimalAmount);\n if (isNaN(amount)) {\n throw new Error(`Invalid amount: ${decimalAmount}`);\n }\n const jettonAmount = Math.floor(amount * Math.pow(10, decimals));\n return jettonAmount.toString();\n}\n\n/**\n * Convert smallest units to decimal amount\n *\n * @param jettonAmount - Amount in smallest units\n * @param decimals - Number of decimal places\n * @returns Amount in decimal format as string\n */\nexport function convertFromJettonAmount(jettonAmount: string | bigint, decimals: number): string {\n const amount = typeof jettonAmount === \"string\" ? BigInt(jettonAmount) : jettonAmount;\n const divisor = BigInt(Math.pow(10, decimals));\n const wholePart = amount / divisor;\n const fractionalPart = amount % divisor;\n\n if (fractionalPart === 0n) {\n return wholePart.toString();\n }\n\n const fractionalStr = fractionalPart.toString().padStart(decimals, \"0\");\n return `${wholePart}.${fractionalStr}`.replace(/\\.?0+$/, \"\");\n}\n\n/**\n * Generate a unique query ID for Jetton transfer\n * Uses timestamp + random component for uniqueness\n *\n * @returns BigInt query ID\n */\nexport function generateQueryId(): bigint {\n const timestamp = BigInt(Date.now());\n const random = BigInt(Math.floor(Math.random() * 1000000));\n return timestamp * 1000000n + random;\n}\n\n/**\n * Build Jetton transfer message body (TEP-74)\n *\n * @param params - Transfer parameters\n * @returns Cell containing the transfer message\n */\nexport function buildJettonTransferBody(params: {\n queryId: bigint;\n amount: bigint;\n destination: Address;\n responseDestination: Address;\n forwardAmount?: bigint;\n forwardPayload?: Cell;\n}): Cell {\n const builder = beginCell()\n .storeUint(JETTON_TRANSFER_OP, 32) // op: transfer\n .storeUint(params.queryId, 64) // query_id\n .storeCoins(params.amount) // amount\n .storeAddress(params.destination) // destination\n .storeAddress(params.responseDestination) // response_destination\n .storeBit(false); // no custom payload\n\n // Forward amount (for notification)\n builder.storeCoins(params.forwardAmount ?? 1n);\n\n // Forward payload (optional)\n if (params.forwardPayload) {\n builder.storeBit(true).storeRef(params.forwardPayload);\n } else {\n builder.storeBit(false);\n }\n\n return builder.endCell();\n}\n\n/**\n * Parse Jetton transfer message from Cell\n *\n * @param body - Cell containing the message\n * @returns Parsed transfer parameters\n * @throws Error if not a valid Jetton transfer message\n */\nexport function parseJettonTransferBody(body: Cell): {\n op: number;\n queryId: bigint;\n amount: bigint;\n destination: Address;\n responseDestination: Address;\n forwardAmount: bigint;\n forwardPayload?: Cell;\n} {\n const slice = body.beginParse();\n\n const op = slice.loadUint(32);\n if (op !== JETTON_TRANSFER_OP) {\n throw new Error(`Not a Jetton transfer message. Expected op ${JETTON_TRANSFER_OP}, got ${op}`);\n }\n\n const queryId = slice.loadUintBig(64);\n const amount = slice.loadCoins();\n const destination = slice.loadAddress();\n const responseDestination = slice.loadAddress();\n\n // Skip custom_payload bit\n const hasCustomPayload = slice.loadBit();\n if (hasCustomPayload) {\n slice.loadRef(); // Skip custom payload\n }\n\n const forwardAmount = slice.loadCoins();\n\n // Forward payload\n const hasForwardPayload = slice.loadBit();\n const forwardPayload = hasForwardPayload ? slice.loadRef() : undefined;\n\n return {\n op,\n queryId,\n amount,\n destination,\n responseDestination,\n forwardAmount,\n forwardPayload,\n };\n}\n\n/**\n * Calculate estimated gas for Jetton transfer\n * Based on typical TON network fees\n *\n * @param params - Optional parameters for estimation\n * @returns Estimated gas in nanoTON\n */\nexport function estimateJettonTransferGas(_params?: {\n hasForwardPayload?: boolean;\n}): bigint {\n // Base cost for Jetton transfer (typical)\n // Includes: external message, wallet internal message, Jetton wallet message\n return 100_000_000n; // 0.1 TON (conservative estimate)\n}\n"],"mappings":"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","names":["import_core"]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { SchemeNetworkFacilitator, PaymentPayload, PaymentRequirements, VerifyResponse, SettleResponse } from '@t402/core/types';
|
|
2
|
+
import { F as FacilitatorTonSigner } from '../../signer-CFiw2DST.js';
|
|
3
|
+
import '@ton/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* TON Facilitator Scheme Implementation
|
|
7
|
+
*
|
|
8
|
+
* Verifies and settles TON Jetton payments using the exact scheme.
|
|
9
|
+
* Validates signed messages and broadcasts transactions to the network.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Configuration options for ExactTonScheme facilitator
|
|
14
|
+
*/
|
|
15
|
+
interface ExactTonSchemeConfig {
|
|
16
|
+
/** Whether this facilitator can sponsor gas for transactions */
|
|
17
|
+
canSponsorGas?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* TON facilitator implementation for the Exact payment scheme.
|
|
21
|
+
*
|
|
22
|
+
* Verifies signed Jetton transfer messages and broadcasts them
|
|
23
|
+
* to the TON network to complete payments.
|
|
24
|
+
*/
|
|
25
|
+
declare class ExactTonScheme implements SchemeNetworkFacilitator {
|
|
26
|
+
private readonly signer;
|
|
27
|
+
readonly scheme = "exact";
|
|
28
|
+
readonly caipFamily = "ton:*";
|
|
29
|
+
private config;
|
|
30
|
+
/**
|
|
31
|
+
* Creates a new ExactTonScheme facilitator instance.
|
|
32
|
+
*
|
|
33
|
+
* @param signer - The TON signer for facilitator operations
|
|
34
|
+
* @param config - Optional configuration
|
|
35
|
+
*/
|
|
36
|
+
constructor(signer: FacilitatorTonSigner, config?: ExactTonSchemeConfig);
|
|
37
|
+
/**
|
|
38
|
+
* Get mechanism-specific extra data for the supported kinds endpoint.
|
|
39
|
+
* For TON, optionally returns gas sponsor address if configured.
|
|
40
|
+
*
|
|
41
|
+
* @param network - The network identifier
|
|
42
|
+
* @returns Extra data object or undefined
|
|
43
|
+
*/
|
|
44
|
+
getExtra(network: string): Record<string, unknown> | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Get signer addresses used by this facilitator.
|
|
47
|
+
* Returns all addresses this facilitator can use for operations.
|
|
48
|
+
*
|
|
49
|
+
* @param network - The network identifier
|
|
50
|
+
* @returns Array of facilitator addresses
|
|
51
|
+
*/
|
|
52
|
+
getSigners(network: string): string[];
|
|
53
|
+
/**
|
|
54
|
+
* Verifies a payment payload.
|
|
55
|
+
*
|
|
56
|
+
* Performs comprehensive validation:
|
|
57
|
+
* 1. Scheme and network matching
|
|
58
|
+
* 2. BOC format validation
|
|
59
|
+
* 3. Message structure verification
|
|
60
|
+
* 4. Authorization expiry check
|
|
61
|
+
* 5. Balance verification
|
|
62
|
+
* 6. Amount and recipient validation
|
|
63
|
+
*
|
|
64
|
+
* @param payload - The payment payload to verify
|
|
65
|
+
* @param requirements - The payment requirements
|
|
66
|
+
* @returns Promise resolving to verification response
|
|
67
|
+
*/
|
|
68
|
+
verify(payload: PaymentPayload, requirements: PaymentRequirements): Promise<VerifyResponse>;
|
|
69
|
+
/**
|
|
70
|
+
* Settles a payment by broadcasting the signed message.
|
|
71
|
+
*
|
|
72
|
+
* @param payload - The payment payload to settle
|
|
73
|
+
* @param requirements - The payment requirements
|
|
74
|
+
* @returns Promise resolving to settlement response
|
|
75
|
+
*/
|
|
76
|
+
settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export { ExactTonScheme, type ExactTonSchemeConfig };
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/exact/facilitator/index.ts
|
|
21
|
+
var facilitator_exports = {};
|
|
22
|
+
__export(facilitator_exports, {
|
|
23
|
+
ExactTonScheme: () => ExactTonScheme
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(facilitator_exports);
|
|
26
|
+
|
|
27
|
+
// src/exact/facilitator/scheme.ts
|
|
28
|
+
var import_core2 = require("@ton/core");
|
|
29
|
+
|
|
30
|
+
// src/constants.ts
|
|
31
|
+
var TON_MAINNET_CAIP2 = "ton:mainnet";
|
|
32
|
+
var TON_TESTNET_CAIP2 = "ton:testnet";
|
|
33
|
+
var TON_NETWORKS = [TON_MAINNET_CAIP2, TON_TESTNET_CAIP2];
|
|
34
|
+
var TON_MAINNET_ENDPOINT = "https://toncenter.com/api/v2/jsonRPC";
|
|
35
|
+
var TON_TESTNET_ENDPOINT = "https://testnet.toncenter.com/api/v2/jsonRPC";
|
|
36
|
+
var TON_MAINNET_V4_ENDPOINT = "https://mainnet-v4.tonhubapi.com";
|
|
37
|
+
var TON_TESTNET_V4_ENDPOINT = "https://testnet-v4.tonhubapi.com";
|
|
38
|
+
var NETWORK_ENDPOINTS = {
|
|
39
|
+
[TON_MAINNET_CAIP2]: TON_MAINNET_ENDPOINT,
|
|
40
|
+
[TON_TESTNET_CAIP2]: TON_TESTNET_ENDPOINT
|
|
41
|
+
};
|
|
42
|
+
var NETWORK_V4_ENDPOINTS = {
|
|
43
|
+
[TON_MAINNET_CAIP2]: TON_MAINNET_V4_ENDPOINT,
|
|
44
|
+
[TON_TESTNET_CAIP2]: TON_TESTNET_V4_ENDPOINT
|
|
45
|
+
};
|
|
46
|
+
var SCHEME_EXACT = "exact";
|
|
47
|
+
|
|
48
|
+
// src/utils.ts
|
|
49
|
+
var import_core = require("@ton/core");
|
|
50
|
+
function normalizeNetwork(network) {
|
|
51
|
+
if (network.startsWith("ton:")) {
|
|
52
|
+
if (!TON_NETWORKS.includes(network)) {
|
|
53
|
+
throw new Error(`Unsupported TON network: ${network}`);
|
|
54
|
+
}
|
|
55
|
+
return network;
|
|
56
|
+
}
|
|
57
|
+
const mapping = {
|
|
58
|
+
ton: TON_MAINNET_CAIP2,
|
|
59
|
+
"ton-mainnet": TON_MAINNET_CAIP2,
|
|
60
|
+
mainnet: TON_MAINNET_CAIP2,
|
|
61
|
+
"ton-testnet": TON_TESTNET_CAIP2,
|
|
62
|
+
testnet: TON_TESTNET_CAIP2
|
|
63
|
+
};
|
|
64
|
+
const caip2 = mapping[network.toLowerCase()];
|
|
65
|
+
if (!caip2) {
|
|
66
|
+
throw new Error(`Unsupported TON network: ${network}`);
|
|
67
|
+
}
|
|
68
|
+
return caip2;
|
|
69
|
+
}
|
|
70
|
+
function addressesEqual(addr1, addr2) {
|
|
71
|
+
try {
|
|
72
|
+
const a1 = import_core.Address.parse(addr1);
|
|
73
|
+
const a2 = import_core.Address.parse(addr2);
|
|
74
|
+
return a1.equals(a2);
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/exact/facilitator/scheme.ts
|
|
81
|
+
var ExactTonScheme = class {
|
|
82
|
+
/**
|
|
83
|
+
* Creates a new ExactTonScheme facilitator instance.
|
|
84
|
+
*
|
|
85
|
+
* @param signer - The TON signer for facilitator operations
|
|
86
|
+
* @param config - Optional configuration
|
|
87
|
+
*/
|
|
88
|
+
constructor(signer, config = {}) {
|
|
89
|
+
this.signer = signer;
|
|
90
|
+
this.scheme = SCHEME_EXACT;
|
|
91
|
+
this.caipFamily = "ton:*";
|
|
92
|
+
this.config = config;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get mechanism-specific extra data for the supported kinds endpoint.
|
|
96
|
+
* For TON, optionally returns gas sponsor address if configured.
|
|
97
|
+
*
|
|
98
|
+
* @param network - The network identifier
|
|
99
|
+
* @returns Extra data object or undefined
|
|
100
|
+
*/
|
|
101
|
+
getExtra(network) {
|
|
102
|
+
void network;
|
|
103
|
+
if (this.config.canSponsorGas) {
|
|
104
|
+
const addresses = this.signer.getAddresses();
|
|
105
|
+
if (addresses.length > 0) {
|
|
106
|
+
return {
|
|
107
|
+
gasSponsor: addresses[0]
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return void 0;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get signer addresses used by this facilitator.
|
|
115
|
+
* Returns all addresses this facilitator can use for operations.
|
|
116
|
+
*
|
|
117
|
+
* @param network - The network identifier
|
|
118
|
+
* @returns Array of facilitator addresses
|
|
119
|
+
*/
|
|
120
|
+
getSigners(network) {
|
|
121
|
+
void network;
|
|
122
|
+
return [...this.signer.getAddresses()];
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Verifies a payment payload.
|
|
126
|
+
*
|
|
127
|
+
* Performs comprehensive validation:
|
|
128
|
+
* 1. Scheme and network matching
|
|
129
|
+
* 2. BOC format validation
|
|
130
|
+
* 3. Message structure verification
|
|
131
|
+
* 4. Authorization expiry check
|
|
132
|
+
* 5. Balance verification
|
|
133
|
+
* 6. Amount and recipient validation
|
|
134
|
+
*
|
|
135
|
+
* @param payload - The payment payload to verify
|
|
136
|
+
* @param requirements - The payment requirements
|
|
137
|
+
* @returns Promise resolving to verification response
|
|
138
|
+
*/
|
|
139
|
+
async verify(payload, requirements) {
|
|
140
|
+
const tonPayload = payload.payload;
|
|
141
|
+
const authorization = tonPayload.authorization;
|
|
142
|
+
if (payload.accepted.scheme !== SCHEME_EXACT || requirements.scheme !== SCHEME_EXACT) {
|
|
143
|
+
return {
|
|
144
|
+
isValid: false,
|
|
145
|
+
invalidReason: "unsupported_scheme",
|
|
146
|
+
payer: authorization.from
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
const payloadNetwork = normalizeNetwork(payload.accepted.network);
|
|
151
|
+
const requirementsNetwork = normalizeNetwork(requirements.network);
|
|
152
|
+
if (payloadNetwork !== requirementsNetwork) {
|
|
153
|
+
return {
|
|
154
|
+
isValid: false,
|
|
155
|
+
invalidReason: "network_mismatch",
|
|
156
|
+
payer: authorization.from
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
} catch {
|
|
160
|
+
return {
|
|
161
|
+
isValid: false,
|
|
162
|
+
invalidReason: "invalid_network",
|
|
163
|
+
payer: authorization.from
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
import_core2.Cell.fromBase64(tonPayload.signedBoc);
|
|
168
|
+
} catch {
|
|
169
|
+
return {
|
|
170
|
+
isValid: false,
|
|
171
|
+
invalidReason: "invalid_boc_format",
|
|
172
|
+
payer: authorization.from
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const verifyResult = await this.signer.verifyMessage({
|
|
176
|
+
signedBoc: tonPayload.signedBoc,
|
|
177
|
+
expectedFrom: authorization.from,
|
|
178
|
+
expectedTransfer: {
|
|
179
|
+
jettonAmount: BigInt(authorization.jettonAmount),
|
|
180
|
+
destination: requirements.payTo,
|
|
181
|
+
jettonMaster: requirements.asset
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
if (!verifyResult.valid) {
|
|
185
|
+
return {
|
|
186
|
+
isValid: false,
|
|
187
|
+
invalidReason: verifyResult.reason || "message_verification_failed",
|
|
188
|
+
payer: authorization.from
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
192
|
+
if (authorization.validUntil < now + 30) {
|
|
193
|
+
return {
|
|
194
|
+
isValid: false,
|
|
195
|
+
invalidReason: "authorization_expired",
|
|
196
|
+
payer: authorization.from
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
const balance = await this.signer.getJettonBalance({
|
|
201
|
+
ownerAddress: authorization.from,
|
|
202
|
+
jettonMasterAddress: requirements.asset
|
|
203
|
+
});
|
|
204
|
+
if (balance < BigInt(requirements.amount)) {
|
|
205
|
+
return {
|
|
206
|
+
isValid: false,
|
|
207
|
+
invalidReason: "insufficient_jetton_balance",
|
|
208
|
+
payer: authorization.from
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.warn("Could not verify Jetton balance:", error);
|
|
213
|
+
}
|
|
214
|
+
if (BigInt(authorization.jettonAmount) < BigInt(requirements.amount)) {
|
|
215
|
+
return {
|
|
216
|
+
isValid: false,
|
|
217
|
+
invalidReason: "insufficient_amount",
|
|
218
|
+
payer: authorization.from
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (!addressesEqual(authorization.to, requirements.payTo)) {
|
|
222
|
+
return {
|
|
223
|
+
isValid: false,
|
|
224
|
+
invalidReason: "recipient_mismatch",
|
|
225
|
+
payer: authorization.from
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
if (!addressesEqual(authorization.jettonMaster, requirements.asset)) {
|
|
229
|
+
return {
|
|
230
|
+
isValid: false,
|
|
231
|
+
invalidReason: "asset_mismatch",
|
|
232
|
+
payer: authorization.from
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
const currentSeqno = await this.signer.getSeqno(authorization.from);
|
|
237
|
+
if (authorization.seqno < currentSeqno) {
|
|
238
|
+
return {
|
|
239
|
+
isValid: false,
|
|
240
|
+
invalidReason: "seqno_already_used",
|
|
241
|
+
payer: authorization.from
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
if (authorization.seqno > currentSeqno) {
|
|
245
|
+
return {
|
|
246
|
+
isValid: false,
|
|
247
|
+
invalidReason: "seqno_too_high",
|
|
248
|
+
payer: authorization.from
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.warn("Could not verify seqno:", error);
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const isDeployed = await this.signer.isDeployed(authorization.from);
|
|
256
|
+
if (!isDeployed) {
|
|
257
|
+
return {
|
|
258
|
+
isValid: false,
|
|
259
|
+
invalidReason: "wallet_not_deployed",
|
|
260
|
+
payer: authorization.from
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.warn("Could not verify wallet deployment:", error);
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
isValid: true,
|
|
268
|
+
invalidReason: void 0,
|
|
269
|
+
payer: authorization.from
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Settles a payment by broadcasting the signed message.
|
|
274
|
+
*
|
|
275
|
+
* @param payload - The payment payload to settle
|
|
276
|
+
* @param requirements - The payment requirements
|
|
277
|
+
* @returns Promise resolving to settlement response
|
|
278
|
+
*/
|
|
279
|
+
async settle(payload, requirements) {
|
|
280
|
+
const tonPayload = payload.payload;
|
|
281
|
+
const verifyResult = await this.verify(payload, requirements);
|
|
282
|
+
if (!verifyResult.isValid) {
|
|
283
|
+
return {
|
|
284
|
+
success: false,
|
|
285
|
+
network: payload.accepted.network,
|
|
286
|
+
transaction: "",
|
|
287
|
+
errorReason: verifyResult.invalidReason ?? "verification_failed",
|
|
288
|
+
payer: tonPayload.authorization.from
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
const txHash = await this.signer.sendExternalMessage(tonPayload.signedBoc);
|
|
293
|
+
const confirmation = await this.signer.waitForTransaction({
|
|
294
|
+
address: tonPayload.authorization.from,
|
|
295
|
+
seqno: tonPayload.authorization.seqno + 1,
|
|
296
|
+
// Wait for next seqno
|
|
297
|
+
timeout: 6e4
|
|
298
|
+
// 60 second timeout
|
|
299
|
+
});
|
|
300
|
+
if (!confirmation.success) {
|
|
301
|
+
return {
|
|
302
|
+
success: false,
|
|
303
|
+
errorReason: confirmation.error || "transaction_not_confirmed",
|
|
304
|
+
transaction: txHash,
|
|
305
|
+
network: payload.accepted.network,
|
|
306
|
+
payer: tonPayload.authorization.from
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
success: true,
|
|
311
|
+
transaction: confirmation.hash || txHash,
|
|
312
|
+
network: payload.accepted.network,
|
|
313
|
+
payer: tonPayload.authorization.from
|
|
314
|
+
};
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error("Failed to settle TON transaction:", error);
|
|
317
|
+
return {
|
|
318
|
+
success: false,
|
|
319
|
+
errorReason: "transaction_failed",
|
|
320
|
+
transaction: "",
|
|
321
|
+
network: payload.accepted.network,
|
|
322
|
+
payer: tonPayload.authorization.from
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
328
|
+
0 && (module.exports = {
|
|
329
|
+
ExactTonScheme
|
|
330
|
+
});
|
|
331
|
+
//# sourceMappingURL=index.js.map
|