@tonappchain/sdk 0.7.1-frost-test-1 → 0.7.2-alpha-1
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/dev/ton/internal/build/CrossChainLayer.compiled.json +1 -1
- package/dist/artifacts/dev/ton/internal/build/Executor.compiled.json +1 -1
- package/dist/artifacts/dev/ton/internal/build/JettonMinter.compiled.json +1 -1
- package/dist/artifacts/dev/ton/internal/build/JettonProxy.compiled.json +1 -1
- package/dist/artifacts/dev/ton/internal/build/JettonWallet.compiled.json +1 -1
- package/dist/artifacts/dev/ton/internal/build/NFTItem.compiled.json +1 -1
- package/dist/artifacts/dev/ton/internal/build/NFTProxy.compiled.json +1 -1
- package/dist/artifacts/dev/ton/internal/wrappers/CrossChainLayer.d.ts +1 -0
- package/dist/artifacts/dev/ton/internal/wrappers/CrossChainLayer.js +15 -5
- package/dist/artifacts/dev/ton/internal/wrappers/JettonMinter.d.ts +2 -2
- package/dist/artifacts/dev/ton/internal/wrappers/JettonMinter.js +2 -2
- 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 +36 -7
- package/dist/src/assets/AssetFactory.js +8 -2
- package/dist/src/assets/FT.d.ts +1 -1
- package/dist/src/assets/FT.js +1 -1
- package/dist/src/assets/NFT.d.ts +1 -1
- package/dist/src/assets/NFT.js +1 -1
- package/dist/src/assets/TON.d.ts +3 -2
- package/dist/src/assets/TON.js +2 -1
- package/dist/src/errors/instances.d.ts +2 -0
- package/dist/src/errors/instances.js +3 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +2 -4
- package/dist/src/interfaces/Asset.d.ts +4 -9
- package/dist/src/interfaces/ContractOpener.d.ts +5 -1
- package/dist/src/interfaces/ISimulator.d.ts +15 -1
- package/dist/src/interfaces/ITONTransactionManager.d.ts +20 -1
- package/dist/src/interfaces/ITacSDK.d.ts +10 -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/Consts.d.ts +50 -1
- package/dist/src/sdk/Consts.js +52 -2
- package/dist/src/sdk/Simulator.d.ts +11 -2
- package/dist/src/sdk/Simulator.js +190 -0
- package/dist/src/sdk/StartTracking.d.ts +5 -3
- package/dist/src/sdk/StartTracking.js +60 -40
- package/dist/src/sdk/TONTransactionManager.d.ts +8 -5
- package/dist/src/sdk/TONTransactionManager.js +49 -6
- package/dist/src/sdk/TacSdk.d.ts +2 -1
- package/dist/src/sdk/TacSdk.js +7 -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 +10 -1
- package/dist/src/sdk/Utils.js +48 -0
- package/dist/src/sender/BatchSender.js +19 -0
- package/dist/src/sender/MockSender.d.ts +2 -0
- package/dist/src/sender/MockSender.js +13 -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/sender/index.d.ts +1 -0
- package/dist/src/sender/index.js +1 -0
- package/dist/src/structs/InternalStruct.d.ts +45 -1
- package/dist/src/structs/Struct.d.ts +29 -2
- package/dist/src/wrappers/HighloadWalletV3.d.ts +5 -3
- package/dist/src/wrappers/HighloadWalletV3.js +14 -3
- package/package.json +3 -4
|
@@ -1,19 +1,22 @@
|
|
|
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");
|
|
8
|
+
const sender_1 = require("../sender");
|
|
7
9
|
const Consts_1 = require("./Consts");
|
|
8
10
|
const Logger_1 = require("./Logger");
|
|
9
11
|
const Utils_1 = require("./Utils");
|
|
10
12
|
const Validator_1 = require("./Validator");
|
|
11
13
|
class TONTransactionManager {
|
|
12
|
-
constructor(config, simulator, operationTracker, logger = new Logger_1.NoopLogger()) {
|
|
14
|
+
constructor(config, simulator, operationTracker, logger = new Logger_1.NoopLogger(), txFinalizer) {
|
|
13
15
|
this.config = config;
|
|
14
16
|
this.simulator = simulator;
|
|
15
17
|
this.operationTracker = operationTracker;
|
|
16
18
|
this.logger = logger;
|
|
19
|
+
this.txFinalizer = txFinalizer;
|
|
17
20
|
}
|
|
18
21
|
async buildFeeParams(options, evmProxyMsg, sender, tx) {
|
|
19
22
|
const { withoutSimulation, protocolFee, evmExecutorFee, tvmExecutorFee, isRoundTrip } = options;
|
|
@@ -46,6 +49,7 @@ class TONTransactionManager {
|
|
|
46
49
|
: simulationResult.feeParams.tvmExecutorFee,
|
|
47
50
|
gasLimit: evmProxyMsg.gasLimit ?? simulationResult.feeParams.gasLimit,
|
|
48
51
|
isRoundTrip: isRoundTrip ?? simulationResult.feeParams.isRoundTrip,
|
|
52
|
+
evmEstimatedGas: simulationResult.simulation?.estimatedGas,
|
|
49
53
|
};
|
|
50
54
|
}
|
|
51
55
|
async prepareCrossChainTransaction(evmProxyMsg, sender, assets, options, skipAssetsBalanceValidation = false) {
|
|
@@ -106,29 +110,45 @@ class TONTransactionManager {
|
|
|
106
110
|
let feeTonAmount = feeParams.protocolFee + feeParams.evmExecutorFee + feeParams.tvmExecutorFee;
|
|
107
111
|
this.logger.debug(`Crosschain ton amount: ${crossChainTonAmount}, Fee ton amount: ${feeTonAmount}`);
|
|
108
112
|
if (!totalAssets.length) {
|
|
113
|
+
const tonNetworkFee = this.simulator.estimateTONFee(ton, {
|
|
114
|
+
excessReceiver: caller,
|
|
115
|
+
evmData,
|
|
116
|
+
feeParams,
|
|
117
|
+
});
|
|
109
118
|
return [
|
|
110
119
|
{
|
|
111
120
|
address: this.config.TONParams.crossChainLayerAddress,
|
|
112
|
-
value: crossChainTonAmount + feeTonAmount +
|
|
121
|
+
value: crossChainTonAmount + feeTonAmount + tonNetworkFee,
|
|
113
122
|
payload: await ton.generatePayload({ excessReceiver: caller, evmData, feeParams }),
|
|
123
|
+
extra: {
|
|
124
|
+
tonNetworkFee,
|
|
125
|
+
tacEstimatedGas: feeParams.evmEstimatedGas,
|
|
126
|
+
},
|
|
114
127
|
},
|
|
115
128
|
];
|
|
116
129
|
}
|
|
117
130
|
const messages = [];
|
|
118
131
|
let currentFeeParams = feeParams;
|
|
119
132
|
for (const asset of totalAssets) {
|
|
120
|
-
const
|
|
133
|
+
const params = {
|
|
121
134
|
excessReceiver: caller,
|
|
122
135
|
evmData,
|
|
123
136
|
crossChainTonAmount,
|
|
124
137
|
forwardFeeTonAmount: feeTonAmount,
|
|
125
138
|
feeParams: currentFeeParams,
|
|
126
|
-
}
|
|
139
|
+
};
|
|
140
|
+
const payload = await asset.generatePayload(params);
|
|
127
141
|
const address = asset instanceof assets_1.FT ? await asset.getUserWalletAddress(caller) : asset.address;
|
|
142
|
+
const forwardAmount = asset instanceof assets_1.FT ? Consts_1.JETTON_TRANSFER_FORWARD_TON_AMOUNT : Consts_1.NFT_TRANSFER_FORWARD_TON_AMOUNT;
|
|
143
|
+
const tonNetworkFee = this.simulator.estimateTONFee(asset, params);
|
|
128
144
|
messages.push({
|
|
129
145
|
address,
|
|
130
|
-
value: crossChainTonAmount + feeTonAmount +
|
|
146
|
+
value: crossChainTonAmount + feeTonAmount + tonNetworkFee + forwardAmount,
|
|
131
147
|
payload,
|
|
148
|
+
extra: {
|
|
149
|
+
tonNetworkFee,
|
|
150
|
+
tacEstimatedGas: currentFeeParams?.evmEstimatedGas,
|
|
151
|
+
},
|
|
132
152
|
});
|
|
133
153
|
crossChainTonAmount = 0n;
|
|
134
154
|
feeTonAmount = 0n;
|
|
@@ -149,7 +169,17 @@ class TONTransactionManager {
|
|
|
149
169
|
if (!shouldWaitForOperationId) {
|
|
150
170
|
return { sendTransactionResult, ...transactionLinker };
|
|
151
171
|
}
|
|
152
|
-
const waitOptions = tx.options?.waitOptions ?? {
|
|
172
|
+
const waitOptions = tx.options?.waitOptions ?? {
|
|
173
|
+
ensureTxExecuted: true,
|
|
174
|
+
};
|
|
175
|
+
if (waitOptions.ensureTxExecuted && sendTransactionResult.boc) {
|
|
176
|
+
const hash = (0, Utils_1.getNormalizedExtMessageHash)((0, ton_1.loadMessage)(ton_1.Cell.fromBase64(sendTransactionResult.boc).beginParse()));
|
|
177
|
+
this.logger.info(`Tracking transaction tree for hash: ${hash}`);
|
|
178
|
+
await this.txFinalizer.trackTransactionTree(sender.getSenderAddress(), hash, {
|
|
179
|
+
maxDepth: 10,
|
|
180
|
+
});
|
|
181
|
+
this.logger.info(`Transaction tree successful`);
|
|
182
|
+
}
|
|
153
183
|
waitOptions.successCheck = waitOptions.successCheck ?? ((id) => !!id);
|
|
154
184
|
waitOptions.logger = waitOptions.logger ?? this.logger;
|
|
155
185
|
const operationId = await this.operationTracker
|
|
@@ -216,5 +246,18 @@ class TONTransactionManager {
|
|
|
216
246
|
return transactionLinkers;
|
|
217
247
|
}
|
|
218
248
|
}
|
|
249
|
+
async prepareCrossChainTransactionPayload(evmProxyMsg, senderAddress, assets = [], options) {
|
|
250
|
+
this.logger.debug('Preparing cross-chain transaction payload');
|
|
251
|
+
const mockSender = (0, sender_1.getMockSender)(senderAddress);
|
|
252
|
+
const result = await this.prepareCrossChainTransaction(evmProxyMsg, mockSender, assets, options, true);
|
|
253
|
+
return result.transaction.messages.map((r) => ({
|
|
254
|
+
body: r.payload,
|
|
255
|
+
destinationAddress: r.address,
|
|
256
|
+
tonAmount: r.value,
|
|
257
|
+
tonNetworkFee: r.extra.tonNetworkFee,
|
|
258
|
+
tacEstimatedGas: r.extra.tacEstimatedGas,
|
|
259
|
+
transactionLinker: result.transactionLinker,
|
|
260
|
+
}));
|
|
261
|
+
}
|
|
219
262
|
}
|
|
220
263
|
exports.TONTransactionManager = TONTransactionManager;
|
package/dist/src/sdk/TacSdk.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { JettonMinterData, NFTItemData } from '../../artifacts/tonTypes';
|
|
|
3
3
|
import { FT, NFT } from '../assets';
|
|
4
4
|
import { IConfiguration, ILogger, IOperationTracker, ITacSDK } from '../interfaces';
|
|
5
5
|
import type { SenderAbstraction } from '../sender';
|
|
6
|
-
import { AssetFromFTArg, AssetFromNFTCollectionArg, AssetFromNFTItemArg, AssetLike, BatchCrossChainTxWithAssetLike, CrossChainTransactionOptions, CrossChainTransactionsOptions, CrosschainTx, EVMAddress, EvmProxyMsg, ExecutionFeeEstimationResult, NFTAddressType, SDKParams, SuggestedTVMExecutorFee, TACSimulationParams, TACSimulationResult, TransactionLinkerWithOperationId, TVMAddress, UserWalletBalanceExtended } from '../structs/Struct';
|
|
6
|
+
import { AssetFromFTArg, AssetFromNFTCollectionArg, AssetFromNFTItemArg, AssetLike, BatchCrossChainTxWithAssetLike, CrossChainPayloadResult, CrossChainTransactionOptions, CrossChainTransactionsOptions, CrosschainTx, EVMAddress, EvmProxyMsg, ExecutionFeeEstimationResult, NFTAddressType, SDKParams, SuggestedTVMExecutorFee, TACSimulationParams, TACSimulationResult, TransactionLinkerWithOperationId, TVMAddress, UserWalletBalanceExtended } from '../structs/Struct';
|
|
7
7
|
export declare class TacSdk implements ITacSDK {
|
|
8
8
|
readonly config: IConfiguration;
|
|
9
9
|
readonly operationTracker: IOperationTracker;
|
|
@@ -41,4 +41,5 @@ export declare class TacSdk implements ITacSDK {
|
|
|
41
41
|
getTVMNFTAddress(evmNFTAddress: string, tokenId?: number | bigint): Promise<string>;
|
|
42
42
|
getEVMNFTAddress(tvmNFTAddress: string, addressType: NFTAddressType): Promise<string>;
|
|
43
43
|
getOperationTracker(): IOperationTracker;
|
|
44
|
+
prepareCrossChainTransactionPayload(evmProxyMsg: EvmProxyMsg, senderAddress: string, assets?: AssetLike[], options?: CrossChainTransactionOptions): Promise<CrossChainPayloadResult[]>;
|
|
44
45
|
}
|
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
|
}
|
|
@@ -177,5 +179,9 @@ class TacSdk {
|
|
|
177
179
|
getOperationTracker() {
|
|
178
180
|
return this.operationTracker;
|
|
179
181
|
}
|
|
182
|
+
async prepareCrossChainTransactionPayload(evmProxyMsg, senderAddress, assets = [], options) {
|
|
183
|
+
const normalizedAssets = await (0, Utils_1.normalizeAssets)(this.config, assets);
|
|
184
|
+
return this.tonTransactionManager.prepareCrossChainTransactionPayload(evmProxyMsg, senderAddress, normalizedAssets, options);
|
|
185
|
+
}
|
|
180
186
|
}
|
|
181
187
|
exports.TacSdk = TacSdk;
|
|
@@ -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 TonIndexerTxFinalizer 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.TonIndexerTxFinalizer = 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 TonIndexerTxFinalizer {
|
|
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.TonIndexerTxFinalizer = TonIndexerTxFinalizer;
|
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,12 @@ 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>;
|
|
40
|
+
export declare function recurisivelyCollectCellStats(cell: Cell): {
|
|
41
|
+
bits: number;
|
|
42
|
+
cells: number;
|
|
43
|
+
};
|
package/dist/src/sdk/Utils.js
CHANGED
|
@@ -19,6 +19,9 @@ 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;
|
|
24
|
+
exports.recurisivelyCollectCellStats = recurisivelyCollectCellStats;
|
|
22
25
|
const ton_1 = require("@ton/ton");
|
|
23
26
|
const ethers_1 = require("ethers");
|
|
24
27
|
const ton_crypto_1 = require("ton-crypto");
|
|
@@ -299,3 +302,48 @@ function getNumber(len, cell) {
|
|
|
299
302
|
function getString(cell) {
|
|
300
303
|
return cell?.beginParse().loadStringTail() ?? '';
|
|
301
304
|
}
|
|
305
|
+
function getNormalizedExtMessageHash(message) {
|
|
306
|
+
if (message.info.type !== 'external-in') {
|
|
307
|
+
throw new Error(`Message must be "external-in", got ${message.info.type}`);
|
|
308
|
+
}
|
|
309
|
+
const info = {
|
|
310
|
+
...message.info,
|
|
311
|
+
src: undefined,
|
|
312
|
+
importFee: 0n,
|
|
313
|
+
};
|
|
314
|
+
const normalizedMessage = {
|
|
315
|
+
...message,
|
|
316
|
+
init: null,
|
|
317
|
+
info: info,
|
|
318
|
+
};
|
|
319
|
+
return (0, ton_1.beginCell)()
|
|
320
|
+
.store((0, ton_1.storeMessage)(normalizedMessage, { forceRef: true }))
|
|
321
|
+
.endCell()
|
|
322
|
+
.hash()
|
|
323
|
+
.toString('base64');
|
|
324
|
+
}
|
|
325
|
+
async function retry(fn, options) {
|
|
326
|
+
let lastError;
|
|
327
|
+
for (let i = 0; i < options.retries; i++) {
|
|
328
|
+
try {
|
|
329
|
+
return await fn();
|
|
330
|
+
}
|
|
331
|
+
catch (e) {
|
|
332
|
+
if (e instanceof Error) {
|
|
333
|
+
lastError = e;
|
|
334
|
+
}
|
|
335
|
+
await new Promise((resolve) => setTimeout(resolve, options.delay));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
throw lastError;
|
|
339
|
+
}
|
|
340
|
+
function recurisivelyCollectCellStats(cell) {
|
|
341
|
+
let bits = 0;
|
|
342
|
+
let cells = 0;
|
|
343
|
+
for (const ref of cell.refs) {
|
|
344
|
+
const stats = recurisivelyCollectCellStats(ref);
|
|
345
|
+
bits += stats.bits;
|
|
346
|
+
cells += stats.cells;
|
|
347
|
+
}
|
|
348
|
+
return { bits: cell.bits.length + bits, cells: 1 + cells };
|
|
349
|
+
}
|
|
@@ -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,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMockSender = void 0;
|
|
4
|
+
const getMockSender = (senderAddress) => {
|
|
5
|
+
return {
|
|
6
|
+
getSenderAddress: () => senderAddress,
|
|
7
|
+
sendShardTransaction: async () => ({ success: true, boc: '' }),
|
|
8
|
+
sendShardTransactions: async () => [],
|
|
9
|
+
getBalance: async () => 0n,
|
|
10
|
+
getBalanceOf: async () => 0n,
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
exports.getMockSender = getMockSender;
|
|
@@ -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 result || boc;
|
|
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
|
});
|
package/dist/src/sender/index.js
CHANGED
|
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("../interfaces/SenderAbstraction"), exports);
|
|
18
18
|
__exportStar(require("./BatchSender"), exports);
|
|
19
|
+
__exportStar(require("./MockSender"), exports);
|
|
19
20
|
__exportStar(require("./SenderFactory"), exports);
|