@tonappchain/sdk 0.7.2-payload-builder-0.2 → 0.7.2-payload-builder-0.3
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/artifacts/testnet/ton/internal/build/CrossChainLayer.compiled.json +1 -1
- package/dist/artifacts/testnet/ton/internal/build/Executor.compiled.json +1 -1
- package/dist/artifacts/testnet/ton/internal/build/JettonMinter.compiled.json +1 -1
- package/dist/artifacts/testnet/ton/internal/build/JettonProxy.compiled.json +1 -1
- package/dist/artifacts/testnet/ton/internal/build/JettonWallet.compiled.json +1 -1
- package/dist/artifacts/testnet/ton/internal/build/NFTItem.compiled.json +1 -1
- package/dist/artifacts/testnet/ton/internal/build/NFTProxy.compiled.json +1 -1
- package/dist/artifacts/testnet/ton/internal/wrappers/CrossChainLayer.d.ts +13 -1
- package/dist/artifacts/testnet/ton/internal/wrappers/CrossChainLayer.js +45 -7
- package/dist/artifacts/testnet/ton/internal/wrappers/JettonMinter.d.ts +2 -2
- package/dist/artifacts/testnet/ton/internal/wrappers/JettonMinter.js +2 -2
- package/dist/src/adapters/contractOpener.d.ts +4 -0
- package/dist/src/adapters/contractOpener.js +165 -1
- package/dist/src/adapters/retryableContractOpener.d.ts +5 -1
- package/dist/src/adapters/retryableContractOpener.js +22 -4
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.js +1 -4
- package/dist/src/interfaces/ContractOpener.d.ts +5 -1
- package/dist/src/interfaces/ITxFinalizer.d.ts +5 -0
- package/dist/src/interfaces/ITxFinalizer.js +2 -0
- package/dist/src/interfaces/WalletInstanse.d.ts +4 -8
- package/dist/src/sdk/StartTracking.d.ts +4 -3
- package/dist/src/sdk/StartTracking.js +5 -7
- package/dist/src/sdk/TONTransactionManager.d.ts +3 -1
- package/dist/src/sdk/TONTransactionManager.js +16 -3
- package/dist/src/sdk/TacSdk.js +3 -1
- package/dist/src/sdk/TxFinalizer.d.ts +15 -4
- package/dist/src/sdk/TxFinalizer.js +102 -23
- package/dist/src/sdk/Utils.d.ts +6 -1
- package/dist/src/sdk/Utils.js +37 -0
- package/dist/src/sender/BatchSender.js +19 -0
- package/dist/src/sender/RawSender.js +34 -1
- package/dist/src/sender/SenderFactory.js +1 -1
- package/dist/src/sender/TonConnectSender.js +2 -0
- package/dist/src/structs/InternalStruct.d.ts +19 -1
- package/dist/src/structs/Struct.d.ts +13 -1
- package/dist/src/wrappers/HighloadWalletV3.d.ts +5 -3
- package/dist/src/wrappers/HighloadWalletV3.js +14 -3
- package/package.json +2 -2
package/dist/src/index.d.ts
CHANGED
|
@@ -10,7 +10,6 @@ export { LiteSequencerClient } from './sdk/LiteSequencerClient';
|
|
|
10
10
|
export { ConsoleLogger, NoopLogger } from './sdk/Logger';
|
|
11
11
|
export { OperationTracker } from './sdk/OperationTracker';
|
|
12
12
|
export { Simulator } from './sdk/Simulator';
|
|
13
|
-
export { startTracking, startTrackingMultiple } from './sdk/StartTracking';
|
|
14
13
|
export { TacSdk } from './sdk/TacSdk';
|
|
15
14
|
export { TACTransactionManager } from './sdk/TACTransactionManager';
|
|
16
15
|
export { TONTransactionManager } from './sdk/TONTransactionManager';
|
package/dist/src/index.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
36
36
|
};
|
|
37
37
|
})();
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.TONTransactionManager = exports.TACTransactionManager = exports.TacSdk = exports.
|
|
39
|
+
exports.TONTransactionManager = exports.TACTransactionManager = exports.TacSdk = exports.Simulator = exports.OperationTracker = exports.NoopLogger = exports.ConsoleLogger = exports.LiteSequencerClient = exports.Configuration = exports.AxiosHttpClient = exports.AgnosticStructs = exports.AgnosticProxySDK = void 0;
|
|
40
40
|
__exportStar(require("./adapters"), exports);
|
|
41
41
|
var AgnosticSdk_1 = require("./agnosticSdk/AgnosticSdk");
|
|
42
42
|
Object.defineProperty(exports, "AgnosticProxySDK", { enumerable: true, get: function () { return AgnosticSdk_1.AgnosticProxySDK; } });
|
|
@@ -57,9 +57,6 @@ var OperationTracker_1 = require("./sdk/OperationTracker");
|
|
|
57
57
|
Object.defineProperty(exports, "OperationTracker", { enumerable: true, get: function () { return OperationTracker_1.OperationTracker; } });
|
|
58
58
|
var Simulator_1 = require("./sdk/Simulator");
|
|
59
59
|
Object.defineProperty(exports, "Simulator", { enumerable: true, get: function () { return Simulator_1.Simulator; } });
|
|
60
|
-
var StartTracking_1 = require("./sdk/StartTracking");
|
|
61
|
-
Object.defineProperty(exports, "startTracking", { enumerable: true, get: function () { return StartTracking_1.startTracking; } });
|
|
62
|
-
Object.defineProperty(exports, "startTrackingMultiple", { enumerable: true, get: function () { return StartTracking_1.startTrackingMultiple; } });
|
|
63
60
|
var TacSdk_1 = require("./sdk/TacSdk");
|
|
64
61
|
Object.defineProperty(exports, "TacSdk", { enumerable: true, get: function () { return TacSdk_1.TacSdk; } });
|
|
65
62
|
var TACTransactionManager_1 = require("./sdk/TACTransactionManager");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SandboxContract } from '@ton/sandbox';
|
|
2
|
-
import type { Address, Contract, OpenedContract } from '@ton/ton';
|
|
2
|
+
import type { Address, Contract, OpenedContract, Transaction } from '@ton/ton';
|
|
3
|
+
import { AddressInformation, GetTransactionsOptions } from '../structs/InternalStruct';
|
|
3
4
|
import { ContractState } from '../structs/Struct';
|
|
4
5
|
export interface ContractOpener {
|
|
5
6
|
/**
|
|
@@ -18,4 +19,7 @@ export interface ContractOpener {
|
|
|
18
19
|
* Closes any underlying connections if supported by the implementation.
|
|
19
20
|
*/
|
|
20
21
|
closeConnections?: () => unknown;
|
|
22
|
+
getTransactionByHash(address: Address, hash: string, opts?: GetTransactionsOptions): Promise<Transaction | null>;
|
|
23
|
+
getAdjacentTransactions(address: Address, hash: string, opts?: GetTransactionsOptions): Promise<Transaction[]>;
|
|
24
|
+
getAddressInformation(address: Address): Promise<AddressInformation>;
|
|
21
25
|
}
|
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
import type { Contract, ContractProvider, MessageRelaxed, SendMode } from '@ton/ton';
|
|
1
|
+
import type { Cell, Contract, ContractProvider, MessageRelaxed, SendMode } from '@ton/ton';
|
|
2
2
|
export interface WalletInstanse extends Contract {
|
|
3
3
|
/**
|
|
4
4
|
* Returns current wallet seqno, used for nonce/ordering.
|
|
5
5
|
* @param provider Contract provider to query the wallet.
|
|
6
6
|
*/
|
|
7
7
|
getSeqno(provider: ContractProvider): Promise<number>;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* @param provider Contract provider used to send the transfer.
|
|
11
|
-
* @param args Transfer arguments including seqno, secretKey, messages and sendMode.
|
|
12
|
-
*/
|
|
13
|
-
sendTransfer(provider: ContractProvider, args: {
|
|
8
|
+
send(provider: ContractProvider, msg: Cell): Promise<string | void>;
|
|
9
|
+
createTransfer(args: {
|
|
14
10
|
seqno: number;
|
|
15
11
|
secretKey: Buffer;
|
|
16
12
|
messages: MessageRelaxed[];
|
|
17
13
|
sendMode: SendMode;
|
|
18
14
|
timeout?: number;
|
|
19
|
-
}):
|
|
15
|
+
}): Cell;
|
|
20
16
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ILogger } from '../interfaces';
|
|
2
|
-
import {
|
|
2
|
+
import { ITxFinalizer } from '../interfaces/ITxFinalizer';
|
|
3
3
|
import { ExecutionStages, Network, TransactionLinker } from '../structs/Struct';
|
|
4
4
|
export declare function startTracking(transactionLinker: TransactionLinker, network: Network, options?: {
|
|
5
5
|
customLiteSequencerEndpoints?: string[];
|
|
@@ -7,8 +7,9 @@ export declare function startTracking(transactionLinker: TransactionLinker, netw
|
|
|
7
7
|
maxIterationCount?: number;
|
|
8
8
|
returnValue?: boolean;
|
|
9
9
|
tableView?: boolean;
|
|
10
|
-
txFinalizerConfig?: TxFinalizerConfig;
|
|
11
10
|
logger?: ILogger;
|
|
11
|
+
txFinalizer?: ITxFinalizer;
|
|
12
|
+
cclAddress?: string;
|
|
12
13
|
}): Promise<void | ExecutionStages>;
|
|
13
14
|
export declare function startTrackingMultiple(transactionLinkers: TransactionLinker[], network: Network, options?: {
|
|
14
15
|
customLiteSequencerEndpoints?: string[];
|
|
@@ -16,7 +17,7 @@ export declare function startTrackingMultiple(transactionLinkers: TransactionLin
|
|
|
16
17
|
maxIterationCount?: number;
|
|
17
18
|
returnValue?: boolean;
|
|
18
19
|
tableView?: boolean;
|
|
19
|
-
txFinalizerConfig?: TxFinalizerConfig;
|
|
20
20
|
logger?: ILogger;
|
|
21
|
+
txFinalizer?: ITxFinalizer;
|
|
21
22
|
}): Promise<void | ExecutionStages[]>;
|
|
22
23
|
export declare function printExecutionStagesTable(stages: ExecutionStages, logger: ILogger): void;
|
|
@@ -7,10 +7,9 @@ const Struct_1 = require("../structs/Struct");
|
|
|
7
7
|
const Consts_1 = require("./Consts");
|
|
8
8
|
const Logger_1 = require("./Logger");
|
|
9
9
|
const OperationTracker_1 = require("./OperationTracker");
|
|
10
|
-
const TxFinalizer_1 = require("./TxFinalizer");
|
|
11
10
|
const Utils_1 = require("./Utils");
|
|
12
11
|
async function startTracking(transactionLinker, network, options) {
|
|
13
|
-
const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true,
|
|
12
|
+
const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true, logger = new Logger_1.NoopLogger(), txFinalizer, cclAddress, } = options || {};
|
|
14
13
|
const tracker = new OperationTracker_1.OperationTracker(network, customLiteSequencerEndpoints, logger);
|
|
15
14
|
logger.debug('Start tracking operation');
|
|
16
15
|
logger.debug('caller: ' + transactionLinker.caller);
|
|
@@ -67,13 +66,12 @@ async function startTracking(transactionLinker, network, options) {
|
|
|
67
66
|
// Check if EXECUTED_IN_TON stage exists and use TxFinalizer to verify transaction success
|
|
68
67
|
if (profilingData.executedInTON.exists && profilingData.executedInTON.stageData?.transactions) {
|
|
69
68
|
logger.debug('EXECUTED_IN_TON stage found, verifying transaction success in TON...');
|
|
70
|
-
if (
|
|
71
|
-
const txFinalizer = new TxFinalizer_1.TonTxFinalizer(txFinalizerConfig, logger);
|
|
69
|
+
if (txFinalizer && cclAddress) {
|
|
72
70
|
const transactions = profilingData.executedInTON.stageData.transactions;
|
|
73
71
|
for (const tx of transactions) {
|
|
74
72
|
try {
|
|
75
73
|
logger.debug(`Verifying transaction: ${tx.hash}`);
|
|
76
|
-
await txFinalizer.trackTransactionTree(tx.hash);
|
|
74
|
+
await txFinalizer.trackTransactionTree(cclAddress, tx.hash, { maxDepth: 10 });
|
|
77
75
|
logger.debug(`Transaction ${tx.hash} verified successfully in TON`);
|
|
78
76
|
}
|
|
79
77
|
catch (error) {
|
|
@@ -101,7 +99,7 @@ async function startTracking(transactionLinker, network, options) {
|
|
|
101
99
|
}
|
|
102
100
|
}
|
|
103
101
|
async function startTrackingMultiple(transactionLinkers, network, options) {
|
|
104
|
-
const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true,
|
|
102
|
+
const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true, txFinalizer, logger = new Logger_1.NoopLogger(), } = options || {};
|
|
105
103
|
logger.debug(`Start tracking ${transactionLinkers.length} operations`);
|
|
106
104
|
const results = await Promise.all(transactionLinkers.map((linker, index) => {
|
|
107
105
|
logger.debug(`\nProcessing operation ${index + 1}/${transactionLinkers.length}`);
|
|
@@ -111,7 +109,7 @@ async function startTrackingMultiple(transactionLinkers, network, options) {
|
|
|
111
109
|
maxIterationCount,
|
|
112
110
|
returnValue: true,
|
|
113
111
|
tableView: false,
|
|
114
|
-
|
|
112
|
+
txFinalizer,
|
|
115
113
|
logger,
|
|
116
114
|
});
|
|
117
115
|
}));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Asset, IConfiguration, ILogger, IOperationTracker, ISimulator, ITONTransactionManager } from '../interfaces';
|
|
2
|
+
import { ITxFinalizer } from '../interfaces/ITxFinalizer';
|
|
2
3
|
import type { SenderAbstraction } from '../sender';
|
|
3
4
|
import { BatchCrossChainTx, CrossChainPayloadResult, CrossChainTransactionOptions, CrossChainTransactionsOptions, CrosschainTx, EvmProxyMsg, FeeParams, TransactionLinkerWithOperationId } from '../structs/Struct';
|
|
4
5
|
export declare class TONTransactionManager implements ITONTransactionManager {
|
|
@@ -6,7 +7,8 @@ export declare class TONTransactionManager implements ITONTransactionManager {
|
|
|
6
7
|
private readonly simulator;
|
|
7
8
|
private readonly operationTracker;
|
|
8
9
|
private readonly logger;
|
|
9
|
-
|
|
10
|
+
private readonly txFinalizer;
|
|
11
|
+
constructor(config: IConfiguration, simulator: ISimulator, operationTracker: IOperationTracker, logger: ILogger | undefined, txFinalizer: ITxFinalizer);
|
|
10
12
|
buildFeeParams(options: CrossChainTransactionOptions, evmProxyMsg: EvmProxyMsg, sender: SenderAbstraction, tx: CrosschainTx): Promise<FeeParams>;
|
|
11
13
|
private prepareCrossChainTransaction;
|
|
12
14
|
private generateCrossChainMessages;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TONTransactionManager = void 0;
|
|
4
|
+
const ton_1 = require("@ton/ton");
|
|
4
5
|
const assets_1 = require("../assets");
|
|
5
6
|
const errors_1 = require("../errors");
|
|
6
7
|
const instances_1 = require("../errors/instances");
|
|
@@ -9,11 +10,12 @@ const Logger_1 = require("./Logger");
|
|
|
9
10
|
const Utils_1 = require("./Utils");
|
|
10
11
|
const Validator_1 = require("./Validator");
|
|
11
12
|
class TONTransactionManager {
|
|
12
|
-
constructor(config, simulator, operationTracker, logger = new Logger_1.NoopLogger()) {
|
|
13
|
+
constructor(config, simulator, operationTracker, logger = new Logger_1.NoopLogger(), txFinalizer) {
|
|
13
14
|
this.config = config;
|
|
14
15
|
this.simulator = simulator;
|
|
15
16
|
this.operationTracker = operationTracker;
|
|
16
17
|
this.logger = logger;
|
|
18
|
+
this.txFinalizer = txFinalizer;
|
|
17
19
|
}
|
|
18
20
|
async buildFeeParams(options, evmProxyMsg, sender, tx) {
|
|
19
21
|
const { withoutSimulation, protocolFee, evmExecutorFee, tvmExecutorFee, isRoundTrip } = options;
|
|
@@ -155,7 +157,17 @@ class TONTransactionManager {
|
|
|
155
157
|
if (!shouldWaitForOperationId) {
|
|
156
158
|
return { sendTransactionResult, ...transactionLinker };
|
|
157
159
|
}
|
|
158
|
-
const waitOptions = tx.options?.waitOptions ?? {
|
|
160
|
+
const waitOptions = tx.options?.waitOptions ?? {
|
|
161
|
+
ensureTxExecuted: true,
|
|
162
|
+
};
|
|
163
|
+
if (waitOptions.ensureTxExecuted && sendTransactionResult.boc) {
|
|
164
|
+
const hash = (0, Utils_1.getNormalizedExtMessageHash)((0, ton_1.loadMessage)(ton_1.Cell.fromBase64(sendTransactionResult.boc).beginParse()));
|
|
165
|
+
this.logger.info(`Tracking transaction tree for hash: ${hash}`);
|
|
166
|
+
await this.txFinalizer.trackTransactionTree(sender.getSenderAddress(), hash, {
|
|
167
|
+
maxDepth: 10,
|
|
168
|
+
});
|
|
169
|
+
this.logger.info(`Transaction tree successful`);
|
|
170
|
+
}
|
|
159
171
|
waitOptions.successCheck = waitOptions.successCheck ?? ((id) => !!id);
|
|
160
172
|
waitOptions.logger = waitOptions.logger ?? this.logger;
|
|
161
173
|
const operationId = await this.operationTracker
|
|
@@ -226,7 +238,7 @@ class TONTransactionManager {
|
|
|
226
238
|
this.logger.debug('Preparing cross-chain transaction payload');
|
|
227
239
|
const mockSender = {
|
|
228
240
|
getSenderAddress: () => senderAddress,
|
|
229
|
-
sendShardTransaction: async () => ({ success: true }),
|
|
241
|
+
sendShardTransaction: async () => ({ success: true, boc: '' }),
|
|
230
242
|
sendShardTransactions: async () => [],
|
|
231
243
|
getBalance: async () => 0n,
|
|
232
244
|
getBalanceOf: async () => 0n,
|
|
@@ -237,6 +249,7 @@ class TONTransactionManager {
|
|
|
237
249
|
destinationAddress: r.address,
|
|
238
250
|
tonAmount: r.value,
|
|
239
251
|
networkFee: r.extra.networkFeeIncluded,
|
|
252
|
+
transactionLinker: result.transactionLinker,
|
|
240
253
|
}));
|
|
241
254
|
}
|
|
242
255
|
}
|
package/dist/src/sdk/TacSdk.js
CHANGED
|
@@ -11,6 +11,7 @@ const OperationTracker_1 = require("./OperationTracker");
|
|
|
11
11
|
const Simulator_1 = require("./Simulator");
|
|
12
12
|
const TACTransactionManager_1 = require("./TACTransactionManager");
|
|
13
13
|
const TONTransactionManager_1 = require("./TONTransactionManager");
|
|
14
|
+
const TxFinalizer_1 = require("./TxFinalizer");
|
|
14
15
|
const Utils_1 = require("./Utils");
|
|
15
16
|
class TacSdk {
|
|
16
17
|
constructor(config, simulator, tonTransactionManager, tacTransactionManager, operationTracker) {
|
|
@@ -40,7 +41,8 @@ class TacSdk {
|
|
|
40
41
|
const config = await Configuration_1.Configuration.create(network, artifacts, sdkParams.TONParams, sdkParams.TACParams, sdkParams.customLiteSequencerEndpoints, delay);
|
|
41
42
|
const operationTracker = new OperationTracker_1.OperationTracker(network, config.liteSequencerEndpoints);
|
|
42
43
|
const simulator = new Simulator_1.Simulator(config, operationTracker, logger);
|
|
43
|
-
const
|
|
44
|
+
const txFinalizer = sdkParams.TONParams?.txFinalizer ?? new TxFinalizer_1.TonTxFinalizer(config.TONParams.contractOpener, logger);
|
|
45
|
+
const tonTransactionManager = new TONTransactionManager_1.TONTransactionManager(config, simulator, operationTracker, logger, txFinalizer);
|
|
44
46
|
const tacTransactionManager = new TACTransactionManager_1.TACTransactionManager(config, operationTracker, logger);
|
|
45
47
|
return new TacSdk(config, simulator, tonTransactionManager, tacTransactionManager, operationTracker);
|
|
46
48
|
}
|
|
@@ -1,11 +1,22 @@
|
|
|
1
|
-
import { IHttpClient, ILogger } from '../interfaces';
|
|
1
|
+
import { ContractOpener, IHttpClient, ILogger } from '../interfaces';
|
|
2
|
+
import { ITxFinalizer } from '../interfaces/ITxFinalizer';
|
|
2
3
|
import { TxFinalizerConfig } from '../structs/InternalStruct';
|
|
3
|
-
export declare class TonTxFinalizer {
|
|
4
|
+
export declare class TonTxFinalizer implements ITxFinalizer {
|
|
5
|
+
private logger;
|
|
6
|
+
private contractOpener;
|
|
7
|
+
constructor(contractOpener: ContractOpener, logger?: ILogger);
|
|
8
|
+
private fetchAdjacentTransactions;
|
|
9
|
+
trackTransactionTree(address: string, hash: string, params: {
|
|
10
|
+
maxDepth?: number;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export declare class TonTxFinalizerV3 implements ITxFinalizer {
|
|
4
14
|
private logger;
|
|
5
15
|
private apiConfig;
|
|
6
16
|
private readonly httpClient;
|
|
7
17
|
constructor(apiConfig: TxFinalizerConfig, logger?: ILogger, httpClient?: IHttpClient);
|
|
8
|
-
private logHashFormats;
|
|
9
18
|
private fetchAdjacentTransactions;
|
|
10
|
-
trackTransactionTree(hash: string,
|
|
19
|
+
trackTransactionTree(_: string, hash: string, params?: {
|
|
20
|
+
maxDepth?: number;
|
|
21
|
+
}): Promise<void>;
|
|
11
22
|
}
|
|
@@ -1,33 +1,111 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TonTxFinalizer = void 0;
|
|
3
|
+
exports.TonTxFinalizerV3 = exports.TonTxFinalizer = void 0;
|
|
4
|
+
const ton_1 = require("@ton/ton");
|
|
4
5
|
const AxiosHttpClient_1 = require("./AxiosHttpClient");
|
|
5
6
|
const Logger_1 = require("./Logger");
|
|
6
7
|
const Utils_1 = require("./Utils");
|
|
7
8
|
const IGNORE_OPCODE = [
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
0xd53276db, // Excess
|
|
10
|
+
0x7362d09c, // Jetton Notify
|
|
10
11
|
];
|
|
11
12
|
class TonTxFinalizer {
|
|
12
|
-
constructor(
|
|
13
|
-
this.
|
|
13
|
+
constructor(contractOpener, logger = new Logger_1.NoopLogger()) {
|
|
14
|
+
this.contractOpener = contractOpener;
|
|
14
15
|
this.logger = logger;
|
|
15
|
-
this.httpClient = httpClient;
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
// Fetches adjacent transactions from toncenter
|
|
18
|
+
async fetchAdjacentTransactions(address, hash, retries = 5, delay = 1000, opts) {
|
|
19
|
+
for (let i = retries; i >= 0; i--) {
|
|
20
|
+
try {
|
|
21
|
+
const txs = await this.contractOpener.getAdjacentTransactions(address, hash, opts);
|
|
22
|
+
return txs;
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
const errorMessage = error.message;
|
|
26
|
+
// Rate limit error (429) - retry
|
|
27
|
+
if (errorMessage.includes('429')) {
|
|
28
|
+
if (i > 0) {
|
|
29
|
+
await (0, Utils_1.sleep)(delay);
|
|
30
|
+
}
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
// Log all errors except 404 Not Found
|
|
34
|
+
if (!errorMessage.includes('404')) {
|
|
35
|
+
const logMessage = error instanceof Error ? error.message : error;
|
|
36
|
+
this.logger.warn(`Failed to fetch adjacent transactions for ${hash}:`, logMessage);
|
|
37
|
+
}
|
|
38
|
+
if (i > 0) {
|
|
39
|
+
await (0, Utils_1.sleep)(delay);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
24
42
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
// Checks if all transactions in the tree are successful
|
|
46
|
+
async trackTransactionTree(address, hash, params) {
|
|
47
|
+
const { maxDepth = 10 } = params;
|
|
48
|
+
const parsedAddress = ton_1.Address.parse(address);
|
|
49
|
+
const visitedHashes = new Set();
|
|
50
|
+
const queue = [{ address: parsedAddress, hash, depth: 0 }];
|
|
51
|
+
while (queue.length > 0) {
|
|
52
|
+
const { hash: currentHash, depth: currentDepth, address: currentAddress } = queue.shift();
|
|
53
|
+
if (visitedHashes.has(currentHash)) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
visitedHashes.add(currentHash);
|
|
57
|
+
this.logger.debug(`Checking hash (depth ${currentDepth}): ${currentHash}`);
|
|
58
|
+
const transactions = await this.fetchAdjacentTransactions(currentAddress, currentHash, 5, 1000, {
|
|
59
|
+
limit: 10,
|
|
60
|
+
archival: true,
|
|
61
|
+
});
|
|
62
|
+
console.log(`Found ${transactions.length} adjacent transactions for ${currentHash}`);
|
|
63
|
+
if (transactions.length === 0)
|
|
64
|
+
continue;
|
|
65
|
+
for (const tx of transactions) {
|
|
66
|
+
if (tx.description.type !== 'generic' || !tx.inMessage)
|
|
67
|
+
continue;
|
|
68
|
+
const bodySlice = tx.inMessage.body.beginParse();
|
|
69
|
+
if (bodySlice.remainingBits < 32)
|
|
70
|
+
continue;
|
|
71
|
+
const opcode = bodySlice.loadUint(32);
|
|
72
|
+
if (!IGNORE_OPCODE.includes(opcode)) {
|
|
73
|
+
const { aborted, computePhase, actionPhase } = tx.description;
|
|
74
|
+
if (aborted ||
|
|
75
|
+
computePhase.type == 'skipped' ||
|
|
76
|
+
!computePhase.success ||
|
|
77
|
+
computePhase.exitCode !== 0 ||
|
|
78
|
+
(actionPhase && (!actionPhase.success || actionPhase.resultCode !== 0))) {
|
|
79
|
+
throw new Error(`Transaction failed:\n` +
|
|
80
|
+
`hash = ${currentHash}, ` +
|
|
81
|
+
`aborted = ${aborted}, ` +
|
|
82
|
+
`compute phase: ${computePhase.type === 'skipped' ? 'skipped' : `success = ${computePhase.success}, exit code = ${computePhase.exitCode}`}, ` +
|
|
83
|
+
`action phase: ${!actionPhase ? 'skipped' : `success = ${actionPhase.success}, result code = ${actionPhase.resultCode}`} `);
|
|
84
|
+
}
|
|
85
|
+
if (currentDepth + 1 < maxDepth) {
|
|
86
|
+
if (tx.outMessages.size > 0) {
|
|
87
|
+
queue.push({
|
|
88
|
+
hash: tx.hash().toString('base64'),
|
|
89
|
+
address: tx.inMessage.info.dest,
|
|
90
|
+
depth: currentDepth + 1,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this.logger.debug(`Skipping hash (depth ${currentDepth}): ${tx.hash().toString('base64')}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
this.logger.debug(`Finished checking hash (depth ${currentDepth}): ${currentHash}`);
|
|
29
100
|
}
|
|
30
|
-
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.TonTxFinalizer = TonTxFinalizer;
|
|
104
|
+
class TonTxFinalizerV3 {
|
|
105
|
+
constructor(apiConfig, logger = new Logger_1.NoopLogger(), httpClient = new AxiosHttpClient_1.AxiosHttpClient()) {
|
|
106
|
+
this.apiConfig = apiConfig;
|
|
107
|
+
this.logger = logger;
|
|
108
|
+
this.httpClient = httpClient;
|
|
31
109
|
}
|
|
32
110
|
// Fetches adjacent transactions from toncenter
|
|
33
111
|
async fetchAdjacentTransactions(hash, retries = 5, delay = 1000) {
|
|
@@ -64,7 +142,8 @@ class TonTxFinalizer {
|
|
|
64
142
|
return [];
|
|
65
143
|
}
|
|
66
144
|
// Checks if all transactions in the tree are successful
|
|
67
|
-
async trackTransactionTree(hash,
|
|
145
|
+
async trackTransactionTree(_, hash, params = { maxDepth: 10 }) {
|
|
146
|
+
const { maxDepth = 10 } = params;
|
|
68
147
|
const visitedHashes = new Set();
|
|
69
148
|
const queue = [{ hash, depth: 0 }];
|
|
70
149
|
while (queue.length > 0) {
|
|
@@ -73,12 +152,12 @@ class TonTxFinalizer {
|
|
|
73
152
|
continue;
|
|
74
153
|
}
|
|
75
154
|
visitedHashes.add(currentHash);
|
|
76
|
-
this.logger.debug(`Checking hash (depth ${currentDepth})
|
|
155
|
+
this.logger.debug(`Checking hash (depth ${currentDepth}): ${currentHash}`);
|
|
77
156
|
const transactions = await this.fetchAdjacentTransactions(currentHash);
|
|
78
157
|
if (transactions.length === 0)
|
|
79
158
|
continue;
|
|
80
159
|
for (const tx of transactions) {
|
|
81
|
-
if (!IGNORE_OPCODE.includes(tx.inMsg.opcode) && tx.inMsg.opcode !== null) {
|
|
160
|
+
if (!IGNORE_OPCODE.includes(Number(tx.inMsg.opcode)) && tx.inMsg.opcode !== null) {
|
|
82
161
|
const { aborted, computePh: compute_ph, action } = tx.description;
|
|
83
162
|
if (aborted ||
|
|
84
163
|
!compute_ph.success ||
|
|
@@ -100,10 +179,10 @@ class TonTxFinalizer {
|
|
|
100
179
|
}
|
|
101
180
|
}
|
|
102
181
|
else {
|
|
103
|
-
this.logger.debug(`Skipping hash (depth ${currentDepth})
|
|
182
|
+
this.logger.debug(`Skipping hash (depth ${currentDepth}): ${tx.hash}`);
|
|
104
183
|
}
|
|
105
184
|
}
|
|
106
185
|
}
|
|
107
186
|
}
|
|
108
187
|
}
|
|
109
|
-
exports.
|
|
188
|
+
exports.TonTxFinalizerV3 = TonTxFinalizerV3;
|
package/dist/src/sdk/Utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Address, Cell } from '@ton/ton';
|
|
1
|
+
import { Address, Cell, Message } from '@ton/ton';
|
|
2
2
|
import { AbiCoder } from 'ethers';
|
|
3
3
|
import type { FT, NFT, TON } from '../assets';
|
|
4
4
|
import { Asset, IConfiguration } from '../interfaces';
|
|
@@ -32,3 +32,8 @@ export declare function normalizeAssets(config: IConfiguration, assets?: AssetLi
|
|
|
32
32
|
export declare function getAddressString(cell?: Cell): string;
|
|
33
33
|
export declare function getNumber(len: number, cell?: Cell): number;
|
|
34
34
|
export declare function getString(cell?: Cell): string;
|
|
35
|
+
export declare function getNormalizedExtMessageHash(message: Message): string;
|
|
36
|
+
export declare function retry<T>(fn: () => Promise<T>, options: {
|
|
37
|
+
retries: number;
|
|
38
|
+
delay: number;
|
|
39
|
+
}): Promise<T>;
|
package/dist/src/sdk/Utils.js
CHANGED
|
@@ -19,6 +19,8 @@ exports.normalizeAssets = normalizeAssets;
|
|
|
19
19
|
exports.getAddressString = getAddressString;
|
|
20
20
|
exports.getNumber = getNumber;
|
|
21
21
|
exports.getString = getString;
|
|
22
|
+
exports.getNormalizedExtMessageHash = getNormalizedExtMessageHash;
|
|
23
|
+
exports.retry = retry;
|
|
22
24
|
const ton_1 = require("@ton/ton");
|
|
23
25
|
const ethers_1 = require("ethers");
|
|
24
26
|
const ton_crypto_1 = require("ton-crypto");
|
|
@@ -299,3 +301,38 @@ function getNumber(len, cell) {
|
|
|
299
301
|
function getString(cell) {
|
|
300
302
|
return cell?.beginParse().loadStringTail() ?? '';
|
|
301
303
|
}
|
|
304
|
+
function getNormalizedExtMessageHash(message) {
|
|
305
|
+
if (message.info.type !== 'external-in') {
|
|
306
|
+
throw new Error(`Message must be "external-in", got ${message.info.type}`);
|
|
307
|
+
}
|
|
308
|
+
const info = {
|
|
309
|
+
...message.info,
|
|
310
|
+
src: undefined,
|
|
311
|
+
importFee: 0n,
|
|
312
|
+
};
|
|
313
|
+
const normalizedMessage = {
|
|
314
|
+
...message,
|
|
315
|
+
init: null,
|
|
316
|
+
info: info,
|
|
317
|
+
};
|
|
318
|
+
return (0, ton_1.beginCell)()
|
|
319
|
+
.store((0, ton_1.storeMessage)(normalizedMessage, { forceRef: true }))
|
|
320
|
+
.endCell()
|
|
321
|
+
.hash()
|
|
322
|
+
.toString('base64');
|
|
323
|
+
}
|
|
324
|
+
async function retry(fn, options) {
|
|
325
|
+
let lastError;
|
|
326
|
+
for (let i = 0; i < options.retries; i++) {
|
|
327
|
+
try {
|
|
328
|
+
return await fn();
|
|
329
|
+
}
|
|
330
|
+
catch (e) {
|
|
331
|
+
if (e instanceof Error) {
|
|
332
|
+
lastError = e;
|
|
333
|
+
}
|
|
334
|
+
await new Promise((resolve) => setTimeout(resolve, options.delay));
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
throw lastError;
|
|
338
|
+
}
|
|
@@ -38,7 +38,16 @@ class BatchSender {
|
|
|
38
38
|
for (const group of groups) {
|
|
39
39
|
try {
|
|
40
40
|
const result = await this.sendGroup(group, contractOpener);
|
|
41
|
+
// Extract BoC if it's a string, or from sandbox result
|
|
42
|
+
let externalMsgBoc = '';
|
|
43
|
+
if (typeof result === 'string') {
|
|
44
|
+
externalMsgBoc = result;
|
|
45
|
+
}
|
|
46
|
+
else if (result?.result) {
|
|
47
|
+
externalMsgBoc = result.result;
|
|
48
|
+
}
|
|
41
49
|
results.push({
|
|
50
|
+
boc: externalMsgBoc,
|
|
42
51
|
success: true,
|
|
43
52
|
result,
|
|
44
53
|
lastMessageIndex: currentMessageIndex + group.length - 1,
|
|
@@ -46,6 +55,7 @@ class BatchSender {
|
|
|
46
55
|
}
|
|
47
56
|
catch (error) {
|
|
48
57
|
results.push({
|
|
58
|
+
boc: '',
|
|
49
59
|
success: false,
|
|
50
60
|
error: error,
|
|
51
61
|
lastMessageIndex: currentMessageIndex - 1,
|
|
@@ -118,7 +128,16 @@ class BatchSender {
|
|
|
118
128
|
}));
|
|
119
129
|
}
|
|
120
130
|
const result = await this.sendGroup(messages, contractOpener);
|
|
131
|
+
// Extract BoC if it's a string, or from sandbox result
|
|
132
|
+
let externalMsgBoc = '';
|
|
133
|
+
if (typeof result === 'string') {
|
|
134
|
+
externalMsgBoc = result;
|
|
135
|
+
}
|
|
136
|
+
else if (result?.result) {
|
|
137
|
+
externalMsgBoc = result.result;
|
|
138
|
+
}
|
|
121
139
|
return {
|
|
140
|
+
boc: externalMsgBoc,
|
|
122
141
|
success: true,
|
|
123
142
|
result,
|
|
124
143
|
lastMessageIndex: shardTransaction.messages.length - 1,
|
|
@@ -34,7 +34,16 @@ class RawSender {
|
|
|
34
34
|
for (const batch of batches) {
|
|
35
35
|
try {
|
|
36
36
|
const result = await this.sendBatch(batch, contractOpener);
|
|
37
|
+
// Extract BoC if it's a string, or from sandbox result
|
|
38
|
+
let externalMsgBoc = '';
|
|
39
|
+
if (typeof result === 'string') {
|
|
40
|
+
externalMsgBoc = result;
|
|
41
|
+
}
|
|
42
|
+
else if (result?.result) {
|
|
43
|
+
externalMsgBoc = result.result;
|
|
44
|
+
}
|
|
37
45
|
results.push({
|
|
46
|
+
boc: externalMsgBoc,
|
|
38
47
|
success: true,
|
|
39
48
|
result,
|
|
40
49
|
lastMessageIndex: currentMessageIndex + batch.length - 1,
|
|
@@ -42,6 +51,7 @@ class RawSender {
|
|
|
42
51
|
}
|
|
43
52
|
catch (error) {
|
|
44
53
|
results.push({
|
|
54
|
+
boc: '',
|
|
45
55
|
success: false,
|
|
46
56
|
error: error,
|
|
47
57
|
lastMessageIndex: currentMessageIndex - 1,
|
|
@@ -63,12 +73,26 @@ class RawSender {
|
|
|
63
73
|
async sendBatch(messages, contractOpener) {
|
|
64
74
|
const walletContract = contractOpener.open(this.wallet);
|
|
65
75
|
const seqno = await walletContract.getSeqno();
|
|
66
|
-
|
|
76
|
+
// Try to create BoC locally for standard wallets
|
|
77
|
+
const msg = this.wallet.createTransfer({
|
|
67
78
|
seqno,
|
|
68
79
|
secretKey: this.secretKey,
|
|
69
80
|
messages,
|
|
70
81
|
sendMode: ton_2.SendMode.PAY_GAS_SEPARATELY,
|
|
71
82
|
});
|
|
83
|
+
let neededInit = null;
|
|
84
|
+
if (this.wallet.init && (await contractOpener.getContractState(this.wallet.address)).state !== 'active') {
|
|
85
|
+
neededInit = this.wallet.init;
|
|
86
|
+
}
|
|
87
|
+
const ext = (0, ton_1.external)({
|
|
88
|
+
to: this.wallet.address,
|
|
89
|
+
init: neededInit,
|
|
90
|
+
body: msg,
|
|
91
|
+
});
|
|
92
|
+
const boc = (0, ton_1.beginCell)().store((0, ton_1.storeMessage)(ext)).endCell().toBoc().toString('base64');
|
|
93
|
+
// Send the transaction
|
|
94
|
+
const result = await walletContract.send(msg);
|
|
95
|
+
return boc || result;
|
|
72
96
|
}
|
|
73
97
|
getSenderAddress() {
|
|
74
98
|
return this.wallet.address.toString();
|
|
@@ -84,7 +108,16 @@ class RawSender {
|
|
|
84
108
|
}));
|
|
85
109
|
}
|
|
86
110
|
const result = await this.sendBatch(messages, contractOpener);
|
|
111
|
+
// Extract BoC if it's a string, or from sandbox result
|
|
112
|
+
let externalMsgBoc = '';
|
|
113
|
+
if (typeof result === 'string') {
|
|
114
|
+
externalMsgBoc = result;
|
|
115
|
+
}
|
|
116
|
+
else if (result?.result) {
|
|
117
|
+
externalMsgBoc = result.result;
|
|
118
|
+
}
|
|
87
119
|
return {
|
|
120
|
+
boc: externalMsgBoc,
|
|
88
121
|
success: true,
|
|
89
122
|
result,
|
|
90
123
|
lastMessageIndex: shardTransaction.messages.length - 1,
|
|
@@ -51,7 +51,7 @@ class SenderFactory {
|
|
|
51
51
|
config.timeout = params.options?.highloadV3?.timeout ?? HighloadWalletV3_1.DEFAULT_TIMEOUT;
|
|
52
52
|
}
|
|
53
53
|
const wallet = exports.wallets[params.version].create(config);
|
|
54
|
-
if (
|
|
54
|
+
if (wallet instanceof HighloadWalletV3_1.HighloadWalletV3) {
|
|
55
55
|
return new BatchSender_1.BatchSender(wallet, keypair.secretKey);
|
|
56
56
|
}
|
|
57
57
|
return new RawSender_1.RawSender(wallet, keypair.secretKey, params.version === 'V5R1' ? 254 : 4);
|
|
@@ -35,6 +35,7 @@ class TonConnectSender {
|
|
|
35
35
|
responses.push({
|
|
36
36
|
success: true,
|
|
37
37
|
result: response,
|
|
38
|
+
boc: response.boc,
|
|
38
39
|
lastMessageIndex: currentMessageIndex + chunk.length - 1,
|
|
39
40
|
});
|
|
40
41
|
currentMessageIndex += chunk.length;
|
|
@@ -42,6 +43,7 @@ class TonConnectSender {
|
|
|
42
43
|
catch (error) {
|
|
43
44
|
responses.push({
|
|
44
45
|
success: false,
|
|
46
|
+
boc: '',
|
|
45
47
|
error: error,
|
|
46
48
|
lastMessageIndex: currentMessageIndex - 1,
|
|
47
49
|
});
|