@gasfree-kit/ton-gasless 0.1.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.
@@ -0,0 +1,101 @@
1
+ import * as _tetherto_wdk_wallet_ton_gasless from '@tetherto/wdk-wallet-ton-gasless';
2
+
3
+ declare const tonUsdtTokenRoot = "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs";
4
+ type TonGaslessNetworkConfig = {
5
+ tonClient: {
6
+ url: string;
7
+ secretKey: string;
8
+ };
9
+ transferMaxFee: number;
10
+ paymasterToken: {
11
+ address: string;
12
+ };
13
+ tonApiClient: {
14
+ url: string;
15
+ secretKey: string;
16
+ };
17
+ };
18
+ type TonGaslessClientConfig = {
19
+ tonCenterUrl: string;
20
+ tonCenterApiKey: string;
21
+ tonApiUrl: string;
22
+ tonApiSecretKey: string;
23
+ transferMaxFee?: number;
24
+ usdtAddress?: string;
25
+ };
26
+ declare function getTonGaslessConfig(config: TonGaslessClientConfig): TonGaslessNetworkConfig;
27
+
28
+ /**
29
+ * Set up a TON gasless wallet via WDK.
30
+ *
31
+ * Uses legacy derivation path (m/44'/607'/0'/0/{index}) for compatibility
32
+ * with wallets created by wdk-wallet-ton <= beta.5.
33
+ */
34
+ declare function setupTonGaslessWallet(seedPhrase: string, config: TonGaslessClientConfig, derivationPath?: string): Promise<{
35
+ wallet: _tetherto_wdk_wallet_ton_gasless.default;
36
+ account: _tetherto_wdk_wallet_ton_gasless.TonAccount;
37
+ address: string;
38
+ }>;
39
+
40
+ declare class TonGaslessTetherTransfer {
41
+ /**
42
+ * Get transaction fee estimate for a gasless USDT transfer on TON.
43
+ * The gasless commission is returned in USDT (paymaster token units).
44
+ */
45
+ static getTransactionEstimateFee(seedPhrase: string, config: TonGaslessClientConfig, amountInUsdt: string, recipientAddress: string): Promise<{
46
+ message: string;
47
+ success: boolean;
48
+ data: {
49
+ fee: string;
50
+ };
51
+ }>;
52
+ /**
53
+ * Check USDT balance on TON.
54
+ */
55
+ static checkBalance(seedPhrase: string, config: TonGaslessClientConfig, tokenAddress?: string): Promise<{
56
+ message: string;
57
+ success: boolean;
58
+ data: {
59
+ nativeBalance: number;
60
+ decimals: number;
61
+ usdBalance: string;
62
+ };
63
+ }>;
64
+ /**
65
+ * Execute a gasless USDT transfer on TON.
66
+ *
67
+ * The relay pays Toncoin gas and deducts a small USDT commission.
68
+ * User only needs USDT — balance must cover amount + gas commission.
69
+ */
70
+ static transferUSDT(seedPhrase: string, config: TonGaslessClientConfig, amountInUsdt: string, recipientAddress: string): Promise<{
71
+ message: string;
72
+ success: boolean;
73
+ data: {
74
+ transactionHash: string;
75
+ fee: unknown;
76
+ tonTransferContext: {
77
+ wdkHash: string;
78
+ walletAddress: string;
79
+ recipientAddress: string;
80
+ amountBaseUnits: string;
81
+ transferTimestamp: number;
82
+ };
83
+ };
84
+ }>;
85
+ }
86
+
87
+ /**
88
+ * Convert human-readable USDT amount to TON base units.
89
+ */
90
+ declare function usdtTonBaseUnits(amount: string | number): bigint;
91
+ /**
92
+ * Convert TON base units to human-readable USDT.
93
+ */
94
+ declare function fromTonBaseUnitsToUsdt(amount: bigint, dec?: number): string;
95
+ /**
96
+ * Convert fee in base units to USDT value using TON price.
97
+ * Uses BigInt arithmetic to avoid precision loss for large values.
98
+ */
99
+ declare function getTonUsdtValue(amountInBaseUnits: bigint, exchangeRate: number): number;
100
+
101
+ export { type TonGaslessClientConfig, type TonGaslessNetworkConfig, TonGaslessTetherTransfer, fromTonBaseUnitsToUsdt, getTonGaslessConfig, getTonUsdtValue, setupTonGaslessWallet, tonUsdtTokenRoot, usdtTonBaseUnits };
@@ -0,0 +1,101 @@
1
+ import * as _tetherto_wdk_wallet_ton_gasless from '@tetherto/wdk-wallet-ton-gasless';
2
+
3
+ declare const tonUsdtTokenRoot = "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs";
4
+ type TonGaslessNetworkConfig = {
5
+ tonClient: {
6
+ url: string;
7
+ secretKey: string;
8
+ };
9
+ transferMaxFee: number;
10
+ paymasterToken: {
11
+ address: string;
12
+ };
13
+ tonApiClient: {
14
+ url: string;
15
+ secretKey: string;
16
+ };
17
+ };
18
+ type TonGaslessClientConfig = {
19
+ tonCenterUrl: string;
20
+ tonCenterApiKey: string;
21
+ tonApiUrl: string;
22
+ tonApiSecretKey: string;
23
+ transferMaxFee?: number;
24
+ usdtAddress?: string;
25
+ };
26
+ declare function getTonGaslessConfig(config: TonGaslessClientConfig): TonGaslessNetworkConfig;
27
+
28
+ /**
29
+ * Set up a TON gasless wallet via WDK.
30
+ *
31
+ * Uses legacy derivation path (m/44'/607'/0'/0/{index}) for compatibility
32
+ * with wallets created by wdk-wallet-ton <= beta.5.
33
+ */
34
+ declare function setupTonGaslessWallet(seedPhrase: string, config: TonGaslessClientConfig, derivationPath?: string): Promise<{
35
+ wallet: _tetherto_wdk_wallet_ton_gasless.default;
36
+ account: _tetherto_wdk_wallet_ton_gasless.TonAccount;
37
+ address: string;
38
+ }>;
39
+
40
+ declare class TonGaslessTetherTransfer {
41
+ /**
42
+ * Get transaction fee estimate for a gasless USDT transfer on TON.
43
+ * The gasless commission is returned in USDT (paymaster token units).
44
+ */
45
+ static getTransactionEstimateFee(seedPhrase: string, config: TonGaslessClientConfig, amountInUsdt: string, recipientAddress: string): Promise<{
46
+ message: string;
47
+ success: boolean;
48
+ data: {
49
+ fee: string;
50
+ };
51
+ }>;
52
+ /**
53
+ * Check USDT balance on TON.
54
+ */
55
+ static checkBalance(seedPhrase: string, config: TonGaslessClientConfig, tokenAddress?: string): Promise<{
56
+ message: string;
57
+ success: boolean;
58
+ data: {
59
+ nativeBalance: number;
60
+ decimals: number;
61
+ usdBalance: string;
62
+ };
63
+ }>;
64
+ /**
65
+ * Execute a gasless USDT transfer on TON.
66
+ *
67
+ * The relay pays Toncoin gas and deducts a small USDT commission.
68
+ * User only needs USDT — balance must cover amount + gas commission.
69
+ */
70
+ static transferUSDT(seedPhrase: string, config: TonGaslessClientConfig, amountInUsdt: string, recipientAddress: string): Promise<{
71
+ message: string;
72
+ success: boolean;
73
+ data: {
74
+ transactionHash: string;
75
+ fee: unknown;
76
+ tonTransferContext: {
77
+ wdkHash: string;
78
+ walletAddress: string;
79
+ recipientAddress: string;
80
+ amountBaseUnits: string;
81
+ transferTimestamp: number;
82
+ };
83
+ };
84
+ }>;
85
+ }
86
+
87
+ /**
88
+ * Convert human-readable USDT amount to TON base units.
89
+ */
90
+ declare function usdtTonBaseUnits(amount: string | number): bigint;
91
+ /**
92
+ * Convert TON base units to human-readable USDT.
93
+ */
94
+ declare function fromTonBaseUnitsToUsdt(amount: bigint, dec?: number): string;
95
+ /**
96
+ * Convert fee in base units to USDT value using TON price.
97
+ * Uses BigInt arithmetic to avoid precision loss for large values.
98
+ */
99
+ declare function getTonUsdtValue(amountInBaseUnits: bigint, exchangeRate: number): number;
100
+
101
+ export { type TonGaslessClientConfig, type TonGaslessNetworkConfig, TonGaslessTetherTransfer, fromTonBaseUnitsToUsdt, getTonGaslessConfig, getTonUsdtValue, setupTonGaslessWallet, tonUsdtTokenRoot, usdtTonBaseUnits };
package/dist/index.js ADDED
@@ -0,0 +1,240 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ TonGaslessTetherTransfer: () => TonGaslessTetherTransfer,
34
+ fromTonBaseUnitsToUsdt: () => fromTonBaseUnitsToUsdt,
35
+ getTonGaslessConfig: () => getTonGaslessConfig,
36
+ getTonUsdtValue: () => getTonUsdtValue,
37
+ setupTonGaslessWallet: () => setupTonGaslessWallet,
38
+ tonUsdtTokenRoot: () => tonUsdtTokenRoot,
39
+ usdtTonBaseUnits: () => usdtTonBaseUnits
40
+ });
41
+ module.exports = __toCommonJS(index_exports);
42
+
43
+ // src/tonNetworkConfiguration.ts
44
+ var tonUsdtTokenRoot = "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs";
45
+ var MAX_TRANSFER_FEE = 5e7;
46
+ var DEFAULT_TRANSFER_FEE = 1e6;
47
+ function getTonGaslessConfig(config) {
48
+ const fee = config.transferMaxFee ?? DEFAULT_TRANSFER_FEE;
49
+ if (fee > MAX_TRANSFER_FEE) {
50
+ throw new Error(
51
+ `transferMaxFee (${fee}) exceeds maximum allowed value (${MAX_TRANSFER_FEE}). This protects against excessive fee deductions.`
52
+ );
53
+ }
54
+ return {
55
+ tonClient: {
56
+ url: config.tonCenterUrl,
57
+ secretKey: config.tonCenterApiKey
58
+ },
59
+ transferMaxFee: fee,
60
+ paymasterToken: {
61
+ address: config.usdtAddress ?? tonUsdtTokenRoot
62
+ },
63
+ tonApiClient: {
64
+ url: config.tonApiUrl,
65
+ secretKey: config.tonApiSecretKey
66
+ }
67
+ };
68
+ }
69
+
70
+ // src/tonGasless.ts
71
+ async function setupTonGaslessWallet(seedPhrase, config, derivationPath = "0'/0/0") {
72
+ const networkConfig = getTonGaslessConfig(config);
73
+ const WalletManagerTonGaslessModule = await import("@tetherto/wdk-wallet-ton-gasless");
74
+ const WalletManagerTonGasless = WalletManagerTonGaslessModule.default;
75
+ const wallet = new WalletManagerTonGasless(seedPhrase, networkConfig);
76
+ const account = await wallet.getAccountByPath(derivationPath);
77
+ const address = await account.getAddress();
78
+ return { wallet, account, address };
79
+ }
80
+
81
+ // src/tonGaslessTetherTransfer.ts
82
+ var import_core = require("@gasfree-kit/core");
83
+
84
+ // src/tonUtility.ts
85
+ var decimals = 6;
86
+ function usdtTonBaseUnits(amount) {
87
+ const str = amount.toString().trim();
88
+ if (!/^\d+(\.\d+)?$/.test(str)) {
89
+ throw new Error(`Invalid USDT amount: "${str}". Must be a non-negative decimal number.`);
90
+ }
91
+ const [integerPart, fractionPart = ""] = str.split(".");
92
+ if (fractionPart.length > decimals) {
93
+ throw new Error(
94
+ `USDT amount has too many decimal places (${fractionPart.length}). Maximum is ${decimals}.`
95
+ );
96
+ }
97
+ const normalizedFraction = (fractionPart + "0".repeat(decimals)).slice(0, decimals);
98
+ return BigInt(integerPart + normalizedFraction);
99
+ }
100
+ function fromTonBaseUnitsToUsdt(amount, dec = 6) {
101
+ const str = amount.toString().padStart(dec + 1, "0");
102
+ const integer = str.slice(0, -dec);
103
+ const fraction = str.slice(-dec).replace(/0+$/, "");
104
+ return fraction ? `${integer}.${fraction}` : integer;
105
+ }
106
+ function getTonUsdtValue(amountInBaseUnits, exchangeRate) {
107
+ const rateScale = 10n ** 12n;
108
+ const scaledRate = BigInt(Math.round(exchangeRate * Number(rateScale)));
109
+ const scaledResult = amountInBaseUnits * scaledRate;
110
+ const divisor = 10n ** BigInt(decimals) * rateScale;
111
+ return Number(scaledResult * 1000000n / divisor) / 1e6;
112
+ }
113
+
114
+ // src/tonGaslessTetherTransfer.ts
115
+ var TonGaslessTetherTransfer = class {
116
+ /**
117
+ * Get transaction fee estimate for a gasless USDT transfer on TON.
118
+ * The gasless commission is returned in USDT (paymaster token units).
119
+ */
120
+ static async getTransactionEstimateFee(seedPhrase, config, amountInUsdt, recipientAddress) {
121
+ (0, import_core.validateTonAddress)(recipientAddress, "recipient address");
122
+ const amount = usdtTonBaseUnits(amountInUsdt);
123
+ const { account, wallet } = await setupTonGaslessWallet(seedPhrase, config);
124
+ try {
125
+ const transferQuote = await account.quoteTransfer({
126
+ token: tonUsdtTokenRoot,
127
+ recipient: recipientAddress,
128
+ amount
129
+ });
130
+ const feeInUsdt = fromTonBaseUnitsToUsdt(transferQuote.fee);
131
+ return {
132
+ message: "Transaction fee estimate retrieved successfully",
133
+ success: true,
134
+ data: { fee: feeInUsdt }
135
+ };
136
+ } finally {
137
+ account.dispose();
138
+ wallet.dispose();
139
+ }
140
+ }
141
+ /**
142
+ * Check USDT balance on TON.
143
+ */
144
+ static async checkBalance(seedPhrase, config, tokenAddress = tonUsdtTokenRoot) {
145
+ const { account, wallet } = await setupTonGaslessWallet(seedPhrase, config);
146
+ try {
147
+ const balance = await account.getTokenBalance(tokenAddress);
148
+ const usdBalance = fromTonBaseUnitsToUsdt(balance);
149
+ return {
150
+ message: "TON balances retrieved successfully",
151
+ success: true,
152
+ data: {
153
+ nativeBalance: Number(balance),
154
+ decimals: 6,
155
+ usdBalance: String(usdBalance)
156
+ }
157
+ };
158
+ } finally {
159
+ account.dispose();
160
+ wallet.dispose();
161
+ }
162
+ }
163
+ /**
164
+ * Execute a gasless USDT transfer on TON.
165
+ *
166
+ * The relay pays Toncoin gas and deducts a small USDT commission.
167
+ * User only needs USDT — balance must cover amount + gas commission.
168
+ */
169
+ static async transferUSDT(seedPhrase, config, amountInUsdt, recipientAddress) {
170
+ const amount = usdtTonBaseUnits(amountInUsdt);
171
+ const {
172
+ account,
173
+ wallet,
174
+ address: walletAddress
175
+ } = await setupTonGaslessWallet(seedPhrase, config);
176
+ try {
177
+ (0, import_core.validateTonAddress)(recipientAddress, "recipient address");
178
+ if (recipientAddress.toLowerCase() === walletAddress.toLowerCase()) {
179
+ throw new import_core.TransactionFailedError("ton", "Cannot transfer to your own address");
180
+ }
181
+ const balance = await account.getTokenBalance(tonUsdtTokenRoot);
182
+ const quote = await account.quoteTransfer({
183
+ token: tonUsdtTokenRoot,
184
+ recipient: recipientAddress,
185
+ amount
186
+ });
187
+ if (balance < amount + quote.fee) {
188
+ throw new import_core.InsufficientBalanceError("ton", "USDT (amount + gas fee)");
189
+ }
190
+ const result = await account.transfer({
191
+ token: tonUsdtTokenRoot,
192
+ recipient: recipientAddress,
193
+ amount
194
+ });
195
+ return {
196
+ message: "USDT transfer on TON successful (gasless)",
197
+ success: true,
198
+ data: {
199
+ transactionHash: result.hash,
200
+ fee: result.fee,
201
+ tonTransferContext: {
202
+ wdkHash: result.hash,
203
+ walletAddress,
204
+ recipientAddress,
205
+ amountBaseUnits: amount.toString(),
206
+ transferTimestamp: Date.now()
207
+ }
208
+ }
209
+ };
210
+ } catch (error) {
211
+ if (error instanceof import_core.InsufficientBalanceError || error instanceof import_core.TransactionFailedError) {
212
+ throw error;
213
+ }
214
+ let message = "Failed to transfer USDT on TON";
215
+ if (error instanceof Error) {
216
+ if (error.message.includes("insufficient balance") || error.message.includes("Failed to unpack account state")) {
217
+ message = "Insufficient USDT balance for network fees";
218
+ } else if (error.message.includes("invalid address")) {
219
+ message = "The recipient TON address is invalid";
220
+ } else if (error.message.includes("timeout")) {
221
+ message = "Network timeout - please try again";
222
+ }
223
+ }
224
+ throw new import_core.TransactionFailedError("ton", message);
225
+ } finally {
226
+ account.dispose();
227
+ wallet.dispose();
228
+ }
229
+ }
230
+ };
231
+ // Annotate the CommonJS export names for ESM import in node:
232
+ 0 && (module.exports = {
233
+ TonGaslessTetherTransfer,
234
+ fromTonBaseUnitsToUsdt,
235
+ getTonGaslessConfig,
236
+ getTonUsdtValue,
237
+ setupTonGaslessWallet,
238
+ tonUsdtTokenRoot,
239
+ usdtTonBaseUnits
240
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,201 @@
1
+ // src/tonNetworkConfiguration.ts
2
+ var tonUsdtTokenRoot = "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs";
3
+ var MAX_TRANSFER_FEE = 5e7;
4
+ var DEFAULT_TRANSFER_FEE = 1e6;
5
+ function getTonGaslessConfig(config) {
6
+ const fee = config.transferMaxFee ?? DEFAULT_TRANSFER_FEE;
7
+ if (fee > MAX_TRANSFER_FEE) {
8
+ throw new Error(
9
+ `transferMaxFee (${fee}) exceeds maximum allowed value (${MAX_TRANSFER_FEE}). This protects against excessive fee deductions.`
10
+ );
11
+ }
12
+ return {
13
+ tonClient: {
14
+ url: config.tonCenterUrl,
15
+ secretKey: config.tonCenterApiKey
16
+ },
17
+ transferMaxFee: fee,
18
+ paymasterToken: {
19
+ address: config.usdtAddress ?? tonUsdtTokenRoot
20
+ },
21
+ tonApiClient: {
22
+ url: config.tonApiUrl,
23
+ secretKey: config.tonApiSecretKey
24
+ }
25
+ };
26
+ }
27
+
28
+ // src/tonGasless.ts
29
+ async function setupTonGaslessWallet(seedPhrase, config, derivationPath = "0'/0/0") {
30
+ const networkConfig = getTonGaslessConfig(config);
31
+ const WalletManagerTonGaslessModule = await import("@tetherto/wdk-wallet-ton-gasless");
32
+ const WalletManagerTonGasless = WalletManagerTonGaslessModule.default;
33
+ const wallet = new WalletManagerTonGasless(seedPhrase, networkConfig);
34
+ const account = await wallet.getAccountByPath(derivationPath);
35
+ const address = await account.getAddress();
36
+ return { wallet, account, address };
37
+ }
38
+
39
+ // src/tonGaslessTetherTransfer.ts
40
+ import {
41
+ InsufficientBalanceError,
42
+ TransactionFailedError,
43
+ validateTonAddress
44
+ } from "@gasfree-kit/core";
45
+
46
+ // src/tonUtility.ts
47
+ var decimals = 6;
48
+ function usdtTonBaseUnits(amount) {
49
+ const str = amount.toString().trim();
50
+ if (!/^\d+(\.\d+)?$/.test(str)) {
51
+ throw new Error(`Invalid USDT amount: "${str}". Must be a non-negative decimal number.`);
52
+ }
53
+ const [integerPart, fractionPart = ""] = str.split(".");
54
+ if (fractionPart.length > decimals) {
55
+ throw new Error(
56
+ `USDT amount has too many decimal places (${fractionPart.length}). Maximum is ${decimals}.`
57
+ );
58
+ }
59
+ const normalizedFraction = (fractionPart + "0".repeat(decimals)).slice(0, decimals);
60
+ return BigInt(integerPart + normalizedFraction);
61
+ }
62
+ function fromTonBaseUnitsToUsdt(amount, dec = 6) {
63
+ const str = amount.toString().padStart(dec + 1, "0");
64
+ const integer = str.slice(0, -dec);
65
+ const fraction = str.slice(-dec).replace(/0+$/, "");
66
+ return fraction ? `${integer}.${fraction}` : integer;
67
+ }
68
+ function getTonUsdtValue(amountInBaseUnits, exchangeRate) {
69
+ const rateScale = 10n ** 12n;
70
+ const scaledRate = BigInt(Math.round(exchangeRate * Number(rateScale)));
71
+ const scaledResult = amountInBaseUnits * scaledRate;
72
+ const divisor = 10n ** BigInt(decimals) * rateScale;
73
+ return Number(scaledResult * 1000000n / divisor) / 1e6;
74
+ }
75
+
76
+ // src/tonGaslessTetherTransfer.ts
77
+ var TonGaslessTetherTransfer = class {
78
+ /**
79
+ * Get transaction fee estimate for a gasless USDT transfer on TON.
80
+ * The gasless commission is returned in USDT (paymaster token units).
81
+ */
82
+ static async getTransactionEstimateFee(seedPhrase, config, amountInUsdt, recipientAddress) {
83
+ validateTonAddress(recipientAddress, "recipient address");
84
+ const amount = usdtTonBaseUnits(amountInUsdt);
85
+ const { account, wallet } = await setupTonGaslessWallet(seedPhrase, config);
86
+ try {
87
+ const transferQuote = await account.quoteTransfer({
88
+ token: tonUsdtTokenRoot,
89
+ recipient: recipientAddress,
90
+ amount
91
+ });
92
+ const feeInUsdt = fromTonBaseUnitsToUsdt(transferQuote.fee);
93
+ return {
94
+ message: "Transaction fee estimate retrieved successfully",
95
+ success: true,
96
+ data: { fee: feeInUsdt }
97
+ };
98
+ } finally {
99
+ account.dispose();
100
+ wallet.dispose();
101
+ }
102
+ }
103
+ /**
104
+ * Check USDT balance on TON.
105
+ */
106
+ static async checkBalance(seedPhrase, config, tokenAddress = tonUsdtTokenRoot) {
107
+ const { account, wallet } = await setupTonGaslessWallet(seedPhrase, config);
108
+ try {
109
+ const balance = await account.getTokenBalance(tokenAddress);
110
+ const usdBalance = fromTonBaseUnitsToUsdt(balance);
111
+ return {
112
+ message: "TON balances retrieved successfully",
113
+ success: true,
114
+ data: {
115
+ nativeBalance: Number(balance),
116
+ decimals: 6,
117
+ usdBalance: String(usdBalance)
118
+ }
119
+ };
120
+ } finally {
121
+ account.dispose();
122
+ wallet.dispose();
123
+ }
124
+ }
125
+ /**
126
+ * Execute a gasless USDT transfer on TON.
127
+ *
128
+ * The relay pays Toncoin gas and deducts a small USDT commission.
129
+ * User only needs USDT — balance must cover amount + gas commission.
130
+ */
131
+ static async transferUSDT(seedPhrase, config, amountInUsdt, recipientAddress) {
132
+ const amount = usdtTonBaseUnits(amountInUsdt);
133
+ const {
134
+ account,
135
+ wallet,
136
+ address: walletAddress
137
+ } = await setupTonGaslessWallet(seedPhrase, config);
138
+ try {
139
+ validateTonAddress(recipientAddress, "recipient address");
140
+ if (recipientAddress.toLowerCase() === walletAddress.toLowerCase()) {
141
+ throw new TransactionFailedError("ton", "Cannot transfer to your own address");
142
+ }
143
+ const balance = await account.getTokenBalance(tonUsdtTokenRoot);
144
+ const quote = await account.quoteTransfer({
145
+ token: tonUsdtTokenRoot,
146
+ recipient: recipientAddress,
147
+ amount
148
+ });
149
+ if (balance < amount + quote.fee) {
150
+ throw new InsufficientBalanceError("ton", "USDT (amount + gas fee)");
151
+ }
152
+ const result = await account.transfer({
153
+ token: tonUsdtTokenRoot,
154
+ recipient: recipientAddress,
155
+ amount
156
+ });
157
+ return {
158
+ message: "USDT transfer on TON successful (gasless)",
159
+ success: true,
160
+ data: {
161
+ transactionHash: result.hash,
162
+ fee: result.fee,
163
+ tonTransferContext: {
164
+ wdkHash: result.hash,
165
+ walletAddress,
166
+ recipientAddress,
167
+ amountBaseUnits: amount.toString(),
168
+ transferTimestamp: Date.now()
169
+ }
170
+ }
171
+ };
172
+ } catch (error) {
173
+ if (error instanceof InsufficientBalanceError || error instanceof TransactionFailedError) {
174
+ throw error;
175
+ }
176
+ let message = "Failed to transfer USDT on TON";
177
+ if (error instanceof Error) {
178
+ if (error.message.includes("insufficient balance") || error.message.includes("Failed to unpack account state")) {
179
+ message = "Insufficient USDT balance for network fees";
180
+ } else if (error.message.includes("invalid address")) {
181
+ message = "The recipient TON address is invalid";
182
+ } else if (error.message.includes("timeout")) {
183
+ message = "Network timeout - please try again";
184
+ }
185
+ }
186
+ throw new TransactionFailedError("ton", message);
187
+ } finally {
188
+ account.dispose();
189
+ wallet.dispose();
190
+ }
191
+ }
192
+ };
193
+ export {
194
+ TonGaslessTetherTransfer,
195
+ fromTonBaseUnitsToUsdt,
196
+ getTonGaslessConfig,
197
+ getTonUsdtValue,
198
+ setupTonGaslessWallet,
199
+ tonUsdtTokenRoot,
200
+ usdtTonBaseUnits
201
+ };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@gasfree-kit/ton-gasless",
3
+ "version": "0.1.0",
4
+ "description": "Gasless USDT transfers on TON via sponsored relay",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "@gasfree-kit/core": "0.1.0"
20
+ },
21
+ "peerDependencies": {
22
+ "@tetherto/wdk-wallet-ton-gasless": "^1.0.0-beta.4",
23
+ "tonweb": "^0.0.66"
24
+ },
25
+ "license": "MIT",
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "dev": "tsup --watch",
32
+ "test": "vitest run",
33
+ "typecheck": "tsc --noEmit",
34
+ "clean": "rm -rf dist"
35
+ }
36
+ }