@tonappchain/sdk 0.6.1-v3.0.4 → 0.6.1-v3.0.5
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/errors/errors.d.ts +6 -0
- package/dist/errors/errors.js +15 -1
- package/dist/errors/instances.d.ts +3 -1
- package/dist/errors/instances.js +4 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -1
- package/dist/sdk/Consts.d.ts +5 -0
- package/dist/sdk/Consts.js +6 -1
- package/dist/sdk/LiteSequencerClient.d.ts +12 -0
- package/dist/sdk/LiteSequencerClient.js +127 -0
- package/dist/sdk/OperationTracker.d.ts +5 -6
- package/dist/sdk/OperationTracker.js +55 -89
- package/dist/sdk/TacSdk.d.ts +3 -3
- package/dist/sdk/TacSdk.js +63 -38
- package/dist/sdk/Utils.d.ts +2 -1
- package/dist/sdk/Utils.js +17 -1
- package/dist/sender/BatchSender.d.ts +15 -0
- package/dist/sender/BatchSender.js +116 -0
- package/dist/sender/RawSender.d.ts +3 -5
- package/dist/sender/RawSender.js +25 -29
- package/dist/sender/SenderAbstraction.d.ts +3 -3
- package/dist/sender/SenderFactory.js +4 -0
- package/dist/sender/TonConnectSender.d.ts +4 -4
- package/dist/sender/TonConnectSender.js +43 -15
- package/dist/sender/index.d.ts +1 -0
- package/dist/sender/index.js +1 -0
- package/dist/structs/InternalStruct.d.ts +8 -1
- package/dist/structs/Struct.d.ts +8 -4
- package/dist/wrappers/HighloadWalletV3.d.ts +3 -0
- package/dist/wrappers/HighloadWalletV3.js +12 -2
- package/package.json +2 -2
package/dist/sdk/TacSdk.js
CHANGED
|
@@ -20,7 +20,6 @@ const Consts_1 = require("./Consts");
|
|
|
20
20
|
const Utils_1 = require("./Utils");
|
|
21
21
|
const artifacts_1 = require("@tonappchain/artifacts");
|
|
22
22
|
const errors_1 = require("../errors");
|
|
23
|
-
const contractOpener_1 = require("../adapters/contractOpener");
|
|
24
23
|
const wrappers_1 = require("@tonappchain/artifacts/dist/src/ton/wrappers");
|
|
25
24
|
const instances_1 = require("../errors/instances");
|
|
26
25
|
class TacSdk {
|
|
@@ -45,7 +44,12 @@ class TacSdk {
|
|
|
45
44
|
return new TacSdk(network, delay, artifacts, TONParams, TACParams, liteSequencerEndpoints);
|
|
46
45
|
}
|
|
47
46
|
static async prepareTONParams(network, delay, artifacts, TONParams) {
|
|
48
|
-
const contractOpener = TONParams?.contractOpener ??
|
|
47
|
+
const contractOpener = TONParams?.contractOpener ??
|
|
48
|
+
new ton_1.TonClient({
|
|
49
|
+
endpoint: network == Struct_1.Network.TESTNET
|
|
50
|
+
? new URL('api/v2/jsonRPC', artifacts_1.testnet.TON_RPC_ENDPOINT_BY_TAC).toString()
|
|
51
|
+
: artifacts_1.mainnet.TON_PUBLIC_RPC_ENDPOINT,
|
|
52
|
+
});
|
|
49
53
|
const settingsAddress = TONParams?.settingsAddress ?? artifacts.ton.addresses.TON_SETTINGS_ADDRESS;
|
|
50
54
|
const settings = contractOpener.open(new Settings_1.Settings(ton_1.Address.parse(settingsAddress)));
|
|
51
55
|
const jettonProxyAddress = await settings.getAddressSetting('JettonProxyAddress');
|
|
@@ -169,24 +173,9 @@ class TacSdk {
|
|
|
169
173
|
.endCell();
|
|
170
174
|
return wrappers_1.NFTItem.transferMessage(queryId, (0, ton_1.address)(transferData.to ?? this.TONParams.nftProxyAddress), (0, ton_1.address)(transferData.responseAddress), Number((0, ton_1.fromNano)(Consts_1.NFT_TRANSFER_FORWARD_TON_AMOUNT + forwardFeeAmount + crossChainTonAmount)), forwardPayload);
|
|
171
175
|
}
|
|
172
|
-
generateFeeData(feeParams) {
|
|
173
|
-
if (feeParams) {
|
|
174
|
-
let feeDataBuilder = (0, ton_1.beginCell)()
|
|
175
|
-
.storeBit(feeParams.isRoundTrip)
|
|
176
|
-
.storeCoins(feeParams.protocolFee)
|
|
177
|
-
.storeCoins(feeParams.evmExecutorFee);
|
|
178
|
-
if (feeParams.isRoundTrip) {
|
|
179
|
-
feeDataBuilder.storeCoins(feeParams.tvmExecutorFee);
|
|
180
|
-
}
|
|
181
|
-
return feeDataBuilder.endCell();
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
return undefined;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
176
|
getTonTransferPayload(responseAddress, evmData, crossChainTonAmount, feeParams) {
|
|
188
177
|
const queryId = (0, Utils_1.generateRandomNumberByTimestamp)().randomNumber;
|
|
189
|
-
const feeData =
|
|
178
|
+
const feeData = (0, Utils_1.generateFeeData)(feeParams);
|
|
190
179
|
return (0, ton_1.beginCell)()
|
|
191
180
|
.storeUint(this.artifacts.ton.wrappers.CrossChainLayerOpCodes.anyone_tvmMsgToEVM, 32)
|
|
192
181
|
.storeUint(queryId, 64)
|
|
@@ -288,7 +277,7 @@ class TacSdk {
|
|
|
288
277
|
const opType = await this.getJettonOpType(jetton);
|
|
289
278
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
290
279
|
console.log(`***** Jetton ${jetton.address} requires ${opType} operation`);
|
|
291
|
-
const feeData =
|
|
280
|
+
const feeData = (0, Utils_1.generateFeeData)(feeParams);
|
|
292
281
|
let payload;
|
|
293
282
|
switch (opType) {
|
|
294
283
|
case InternalStruct_1.AssetOpType.JETTON_BURN:
|
|
@@ -307,7 +296,7 @@ class TacSdk {
|
|
|
307
296
|
const opType = await this.getNFTOpType(nft);
|
|
308
297
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
309
298
|
console.log(`***** NFT ${nft.address} requires ${opType} operation`);
|
|
310
|
-
const feeData =
|
|
299
|
+
const feeData = (0, Utils_1.generateFeeData)(feeParams);
|
|
311
300
|
let payload;
|
|
312
301
|
switch (opType) {
|
|
313
302
|
case InternalStruct_1.AssetOpType.NFT_BURN:
|
|
@@ -391,6 +380,7 @@ class TacSdk {
|
|
|
391
380
|
(0, Utils_1.validateTVMAddress)(precalculatedAddress);
|
|
392
381
|
const contract = this.TONParams.contractOpener.open(new JettonMaster_1.JettonMaster((0, ton_1.address)(precalculatedAddress)));
|
|
393
382
|
const { content } = await contract.getJettonData();
|
|
383
|
+
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
394
384
|
if (!content.metadata.decimals) {
|
|
395
385
|
// if decimals not specified use default value 9
|
|
396
386
|
return (0, ton_1.toNano)(asset.amount);
|
|
@@ -414,6 +404,7 @@ class TacSdk {
|
|
|
414
404
|
const address = (0, ethers_1.isAddress)(asset.collectionAddress)
|
|
415
405
|
? await this.getTVMNFTAddress(asset.collectionAddress, asset.itemIndex)
|
|
416
406
|
: await this.getNFTItemAddressTON(asset.collectionAddress, asset.itemIndex);
|
|
407
|
+
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
417
408
|
return {
|
|
418
409
|
address,
|
|
419
410
|
rawAmount: 1n,
|
|
@@ -491,6 +482,27 @@ class TacSdk {
|
|
|
491
482
|
const evmValidExecutors = this.TACParams.trustedTACExecutors;
|
|
492
483
|
return await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, evmValidExecutors, false, undefined);
|
|
493
484
|
}
|
|
485
|
+
async getTVMExecutorFeeInfo(assets, feeSymbol) {
|
|
486
|
+
const rawAssets = await this.convertAssetsToRawFormat(assets);
|
|
487
|
+
const requestBody = {
|
|
488
|
+
tonAssets: rawAssets.map((asset) => ({
|
|
489
|
+
amount: asset.rawAmount.toString(),
|
|
490
|
+
tokenAddress: asset.address || '',
|
|
491
|
+
assetType: asset.type,
|
|
492
|
+
})),
|
|
493
|
+
feeSymbol: feeSymbol,
|
|
494
|
+
};
|
|
495
|
+
for (const endpoint of this.liteSequencerEndpoints) {
|
|
496
|
+
try {
|
|
497
|
+
const response = await axios_1.default.post(`${endpoint}/ton/calculator/ton-executor-fee`, requestBody);
|
|
498
|
+
return response.data.response;
|
|
499
|
+
}
|
|
500
|
+
catch (error) {
|
|
501
|
+
console.error(`Error while calulating tvm executor fee ${endpoint}:`, error);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
throw errors_1.simulationError;
|
|
505
|
+
}
|
|
494
506
|
async prepareCrossChainTransaction(evmProxyMsg, caller, assets, options) {
|
|
495
507
|
let { forceSend = false, isRoundTrip = undefined, protocolFee = undefined, evmValidExecutors = [], evmExecutorFee = undefined, tvmValidExecutors = [], tvmExecutorFee = undefined, } = options || {};
|
|
496
508
|
const rawAssets = await this.convertAssetsToRawFormat(assets);
|
|
@@ -556,6 +568,34 @@ class TacSdk {
|
|
|
556
568
|
if (assets == undefined) {
|
|
557
569
|
assets = [];
|
|
558
570
|
}
|
|
571
|
+
let tonAssets = [];
|
|
572
|
+
for (const asset of assets) {
|
|
573
|
+
if (asset.type == Struct_1.AssetType.FT) {
|
|
574
|
+
const tvmAddress = await this.getTVMTokenAddress(asset.address);
|
|
575
|
+
tonAssets.push({
|
|
576
|
+
address: tvmAddress,
|
|
577
|
+
rawAmount: asset.rawAmount,
|
|
578
|
+
type: Struct_1.AssetType.FT,
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
const nftItemAddress = await this.getTVMNFTAddress(asset.collectionAddress, asset.itemIndex);
|
|
583
|
+
tonAssets.push({
|
|
584
|
+
address: nftItemAddress,
|
|
585
|
+
amount: 1,
|
|
586
|
+
type: Struct_1.AssetType.NFT,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
if (value > 0) {
|
|
591
|
+
const tvmAddress = await this.getTVMTokenAddress(await this.nativeTACAddress());
|
|
592
|
+
tonAssets.push({
|
|
593
|
+
address: tvmAddress,
|
|
594
|
+
rawAmount: value,
|
|
595
|
+
type: Struct_1.AssetType.FT,
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
const suggestedTONExecutorFee = await this.getTVMExecutorFeeInfo(tonAssets, Consts_1.TAC_SYMBOL);
|
|
559
599
|
const crossChainLayerAddress = await this.TACParams.crossChainLayer.getAddress();
|
|
560
600
|
for (const asset of assets) {
|
|
561
601
|
if (asset.type == Struct_1.AssetType.FT) {
|
|
@@ -571,27 +611,12 @@ class TacSdk {
|
|
|
571
611
|
}
|
|
572
612
|
const shardsKey = BigInt(Math.round(Math.random() * 1e18));
|
|
573
613
|
const protocolFee = await this.TACParams.crossChainLayer.getProtocolFee();
|
|
574
|
-
let tvmExecutorFeeInTON = 0n;
|
|
575
|
-
if (tvmExecutorFee != undefined) {
|
|
576
|
-
tvmExecutorFeeInTON = tvmExecutorFee;
|
|
577
|
-
}
|
|
578
|
-
else {
|
|
579
|
-
tvmExecutorFeeInTON =
|
|
580
|
-
((((0, ton_1.toNano)('0.065') + (0, ton_1.toNano)('0.05')) * BigInt(assets.length + 1 + Number(value != 0n)) +
|
|
581
|
-
(0, ton_1.toNano)('0.2')) *
|
|
582
|
-
120n) /
|
|
583
|
-
100n; // TODO calc that
|
|
584
|
-
}
|
|
585
|
-
const tonToTacRate = 100n;
|
|
586
|
-
const scale = 10n ** 9n;
|
|
587
|
-
const tonToTacRateScaled = tonToTacRate * scale;
|
|
588
|
-
const tvmExecutorFeeInTAC = tonToTacRateScaled * tvmExecutorFeeInTON;
|
|
589
614
|
const outMessage = {
|
|
590
615
|
shardsKey: shardsKey,
|
|
591
616
|
tvmTarget: tonTarget,
|
|
592
617
|
tvmPayload: '',
|
|
593
618
|
tvmProtocolFee: protocolFee,
|
|
594
|
-
tvmExecutorFee:
|
|
619
|
+
tvmExecutorFee: tvmExecutorFee ?? BigInt(suggestedTONExecutorFee.inTAC),
|
|
595
620
|
tvmValidExecutors: this.TACParams.trustedTONExecutors,
|
|
596
621
|
toBridge: assets
|
|
597
622
|
.filter((asset) => asset.type === Struct_1.AssetType.FT)
|
|
@@ -690,7 +715,7 @@ class TacSdk {
|
|
|
690
715
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
691
716
|
return evmAddress.toString();
|
|
692
717
|
}
|
|
693
|
-
return this.TACParams.tokenUtils.
|
|
718
|
+
return this.TACParams.tokenUtils.computeAddressERC721(tvmNFTAddress);
|
|
694
719
|
}
|
|
695
720
|
async isContractDeployedOnTVM(address) {
|
|
696
721
|
return (await this.TONParams.contractOpener.getContractState(ton_1.Address.parse(address))).state === 'active';
|
|
@@ -698,7 +723,7 @@ class TacSdk {
|
|
|
698
723
|
async simulateTACMessage(req) {
|
|
699
724
|
for (const endpoint of this.liteSequencerEndpoints) {
|
|
700
725
|
try {
|
|
701
|
-
const response = await axios_1.default.post(
|
|
726
|
+
const response = await axios_1.default.post(new URL('tac/simulator/simulate-message', endpoint).toString(), req, {
|
|
702
727
|
transformResponse: [Utils_1.toCamelCaseTransformer],
|
|
703
728
|
});
|
|
704
729
|
return response.data.response;
|
package/dist/sdk/Utils.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Address, Cell } from '@ton/ton';
|
|
2
2
|
import { AbiCoder } from 'ethers';
|
|
3
|
-
import { EvmProxyMsg, TransactionLinker, ValidExecutors } from '../structs/Struct';
|
|
3
|
+
import { EvmProxyMsg, FeeParams, TransactionLinker, ValidExecutors } from '../structs/Struct';
|
|
4
4
|
import { RandomNumberByTimestamp } from '../structs/InternalStruct';
|
|
5
5
|
export declare const sleep: (ms: number) => Promise<unknown>;
|
|
6
6
|
export declare function generateRandomNumber(interval: number): number;
|
|
@@ -16,3 +16,4 @@ export declare const convertKeysToCamelCase: <T>(data: T) => T;
|
|
|
16
16
|
export declare const calculateRawAmount: (amount: number, decimals: number) => bigint;
|
|
17
17
|
export declare const calculateAmount: (rawAmount: bigint, decimals: number) => number;
|
|
18
18
|
export declare const toCamelCaseTransformer: (data: any) => any;
|
|
19
|
+
export declare const generateFeeData: (feeParams?: FeeParams) => Cell | undefined;
|
package/dist/sdk/Utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toCamelCaseTransformer = exports.calculateAmount = exports.calculateRawAmount = exports.convertKeysToCamelCase = exports.sleep = void 0;
|
|
3
|
+
exports.generateFeeData = exports.toCamelCaseTransformer = exports.calculateAmount = exports.calculateRawAmount = exports.convertKeysToCamelCase = exports.sleep = void 0;
|
|
4
4
|
exports.generateRandomNumber = generateRandomNumber;
|
|
5
5
|
exports.generateRandomNumberByTimestamp = generateRandomNumberByTimestamp;
|
|
6
6
|
exports.calculateContractAddress = calculateContractAddress;
|
|
@@ -126,3 +126,19 @@ const toCamelCaseTransformer = (data) => {
|
|
|
126
126
|
}
|
|
127
127
|
};
|
|
128
128
|
exports.toCamelCaseTransformer = toCamelCaseTransformer;
|
|
129
|
+
const generateFeeData = (feeParams) => {
|
|
130
|
+
if (feeParams) {
|
|
131
|
+
let feeDataBuilder = (0, ton_1.beginCell)()
|
|
132
|
+
.storeBit(feeParams.isRoundTrip)
|
|
133
|
+
.storeCoins(feeParams.protocolFee)
|
|
134
|
+
.storeCoins(feeParams.evmExecutorFee);
|
|
135
|
+
if (feeParams.isRoundTrip) {
|
|
136
|
+
feeDataBuilder.storeCoins(feeParams.tvmExecutorFee);
|
|
137
|
+
}
|
|
138
|
+
return feeDataBuilder.endCell();
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
exports.generateFeeData = generateFeeData;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ContractOpener } from '../structs/Struct';
|
|
2
|
+
import type { SendResult, ShardTransaction } from '../structs/InternalStruct';
|
|
3
|
+
import { Network } from '../structs/Struct';
|
|
4
|
+
import { SenderAbstraction } from './SenderAbstraction';
|
|
5
|
+
import { HighloadWalletV3 } from '../wrappers/HighloadWalletV3';
|
|
6
|
+
export declare class BatchSender implements SenderAbstraction {
|
|
7
|
+
private wallet;
|
|
8
|
+
private secretKey;
|
|
9
|
+
constructor(wallet: HighloadWalletV3, secretKey: Buffer);
|
|
10
|
+
sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, _chain: Network, contractOpener: ContractOpener): Promise<SendResult[]>;
|
|
11
|
+
private prepareGroups;
|
|
12
|
+
private sendGroup;
|
|
13
|
+
getSenderAddress(): string;
|
|
14
|
+
sendShardTransaction(shardTransaction: ShardTransaction, delay: number, _chain: Network, contractOpener: ContractOpener): Promise<SendResult>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BatchSender = void 0;
|
|
4
|
+
const ton_1 = require("@ton/ton");
|
|
5
|
+
const SenderAbstraction_1 = require("./SenderAbstraction");
|
|
6
|
+
const Consts_1 = require("../sdk/Consts");
|
|
7
|
+
const instances_1 = require("../errors/instances");
|
|
8
|
+
class BatchSender {
|
|
9
|
+
constructor(wallet, secretKey) {
|
|
10
|
+
this.wallet = wallet;
|
|
11
|
+
this.secretKey = secretKey;
|
|
12
|
+
}
|
|
13
|
+
async sendShardTransactions(shardTransactions, delay, _chain, contractOpener) {
|
|
14
|
+
const allMessages = [];
|
|
15
|
+
let minValidUntil = Number.MAX_SAFE_INTEGER;
|
|
16
|
+
for (const transaction of shardTransactions) {
|
|
17
|
+
for (const message of transaction.messages) {
|
|
18
|
+
allMessages.push((0, ton_1.internal)({
|
|
19
|
+
to: message.address,
|
|
20
|
+
value: (0, ton_1.fromNano)(message.value),
|
|
21
|
+
bounce: true,
|
|
22
|
+
body: message.payload,
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
minValidUntil = Math.min(minValidUntil, transaction.validUntil);
|
|
26
|
+
}
|
|
27
|
+
const groups = await this.prepareGroups(allMessages);
|
|
28
|
+
const results = [];
|
|
29
|
+
let currentMessageIndex = 0;
|
|
30
|
+
for (const group of groups) {
|
|
31
|
+
await (0, SenderAbstraction_1.sleep)(delay * 1000);
|
|
32
|
+
try {
|
|
33
|
+
const result = await this.sendGroup(group, contractOpener);
|
|
34
|
+
results.push({
|
|
35
|
+
success: true,
|
|
36
|
+
result,
|
|
37
|
+
lastMessageIndex: currentMessageIndex + group.length - 1,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
results.push({
|
|
42
|
+
success: false,
|
|
43
|
+
error: error,
|
|
44
|
+
lastMessageIndex: currentMessageIndex - 1,
|
|
45
|
+
});
|
|
46
|
+
break; // Stop sending after first error
|
|
47
|
+
}
|
|
48
|
+
currentMessageIndex += group.length;
|
|
49
|
+
}
|
|
50
|
+
return results;
|
|
51
|
+
}
|
|
52
|
+
async prepareGroups(messages) {
|
|
53
|
+
const total = messages.length;
|
|
54
|
+
let left = 0;
|
|
55
|
+
const groups = [];
|
|
56
|
+
while (left < total) {
|
|
57
|
+
let groupSize = total - left;
|
|
58
|
+
if (groupSize > Consts_1.MAX_HIGHLOAD_GROUP_MSG_NUM) {
|
|
59
|
+
groupSize = Consts_1.MAX_HIGHLOAD_GROUP_MSG_NUM;
|
|
60
|
+
}
|
|
61
|
+
let validGroupFound = false;
|
|
62
|
+
while (groupSize > 0) {
|
|
63
|
+
const group = messages.slice(left, left + groupSize);
|
|
64
|
+
const createdAt = Math.floor(Date.now() / 1000) - 40;
|
|
65
|
+
const queryId = this.wallet.getQueryIdFromCreatedAt(createdAt);
|
|
66
|
+
const externalMsg = this.wallet.getExternalMessage(group, ton_1.SendMode.PAY_GAS_SEPARATELY, 0n, queryId);
|
|
67
|
+
const isBocSizeValid = externalMsg.body.toBoc().length <= Consts_1.MAX_EXT_MSG_SIZE;
|
|
68
|
+
const isDepthValid = externalMsg.body.depth() <= Consts_1.MAX_MSG_DEPTH;
|
|
69
|
+
if (isBocSizeValid && isDepthValid) {
|
|
70
|
+
groups.push(group);
|
|
71
|
+
left += groupSize;
|
|
72
|
+
validGroupFound = true;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
if (groupSize <= 1) {
|
|
76
|
+
throw (0, instances_1.prepareMessageGroupError)(isBocSizeValid, isDepthValid);
|
|
77
|
+
}
|
|
78
|
+
groupSize = Math.floor(groupSize / 2);
|
|
79
|
+
}
|
|
80
|
+
if (!validGroupFound) {
|
|
81
|
+
throw instances_1.noValidGroupFoundError;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return groups;
|
|
85
|
+
}
|
|
86
|
+
async sendGroup(messages, contractOpener) {
|
|
87
|
+
const walletContract = contractOpener.open(this.wallet);
|
|
88
|
+
return walletContract.sendTransfer({
|
|
89
|
+
secretKey: this.secretKey,
|
|
90
|
+
messages,
|
|
91
|
+
sendMode: ton_1.SendMode.PAY_GAS_SEPARATELY,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
getSenderAddress() {
|
|
95
|
+
return this.wallet.address.toString();
|
|
96
|
+
}
|
|
97
|
+
async sendShardTransaction(shardTransaction, delay, _chain, contractOpener) {
|
|
98
|
+
const messages = [];
|
|
99
|
+
for (const message of shardTransaction.messages) {
|
|
100
|
+
messages.push((0, ton_1.internal)({
|
|
101
|
+
to: message.address,
|
|
102
|
+
value: (0, ton_1.fromNano)(message.value),
|
|
103
|
+
bounce: true,
|
|
104
|
+
body: message.payload,
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
await (0, SenderAbstraction_1.sleep)(delay * 1000);
|
|
108
|
+
const result = await this.sendGroup(messages, contractOpener);
|
|
109
|
+
return {
|
|
110
|
+
success: true,
|
|
111
|
+
result,
|
|
112
|
+
lastMessageIndex: shardTransaction.messages.length - 1,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.BatchSender = BatchSender;
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import type { ContractOpener } from '../structs/Struct';
|
|
2
|
-
import type { ShardTransaction } from '../structs/InternalStruct';
|
|
2
|
+
import type { SendResult, ShardTransaction } from '../structs/InternalStruct';
|
|
3
3
|
import { Network } from '../structs/Struct';
|
|
4
4
|
import { SenderAbstraction, WalletInstance } from './SenderAbstraction';
|
|
5
5
|
export declare class RawSender implements SenderAbstraction {
|
|
6
6
|
private wallet;
|
|
7
7
|
private secretKey;
|
|
8
8
|
constructor(wallet: WalletInstance, secretKey: Buffer);
|
|
9
|
-
sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain: Network, contractOpener: ContractOpener): Promise<
|
|
9
|
+
sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain: Network, contractOpener: ContractOpener): Promise<SendResult[]>;
|
|
10
10
|
getSenderAddress(): string;
|
|
11
|
-
sendShardTransaction(shardTransaction: ShardTransaction, delay: number, _chain: Network, contractOpener: ContractOpener): Promise<
|
|
12
|
-
result: void;
|
|
13
|
-
})>;
|
|
11
|
+
sendShardTransaction(shardTransaction: ShardTransaction, delay: number, _chain: Network, contractOpener: ContractOpener): Promise<SendResult>;
|
|
14
12
|
}
|
package/dist/sender/RawSender.js
CHANGED
|
@@ -4,43 +4,34 @@ exports.RawSender = void 0;
|
|
|
4
4
|
const ton_1 = require("@ton/ton");
|
|
5
5
|
const ton_2 = require("@ton/ton");
|
|
6
6
|
const SenderAbstraction_1 = require("./SenderAbstraction");
|
|
7
|
-
const HighloadWalletV3_1 = require("../wrappers/HighloadWalletV3");
|
|
8
7
|
class RawSender {
|
|
9
8
|
constructor(wallet, secretKey) {
|
|
10
9
|
this.wallet = wallet;
|
|
11
10
|
this.secretKey = secretKey;
|
|
12
11
|
}
|
|
13
12
|
async sendShardTransactions(shardTransactions, delay, chain, contractOpener) {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}));
|
|
26
|
-
}
|
|
13
|
+
const results = [];
|
|
14
|
+
let currentMessageIndex = 0;
|
|
15
|
+
for (const shardTx of shardTransactions) {
|
|
16
|
+
try {
|
|
17
|
+
const result = await this.sendShardTransaction(shardTx, delay, chain, contractOpener);
|
|
18
|
+
results.push({
|
|
19
|
+
success: true,
|
|
20
|
+
result,
|
|
21
|
+
lastMessageIndex: currentMessageIndex + shardTx.messages.length - 1,
|
|
22
|
+
});
|
|
23
|
+
currentMessageIndex += shardTx.messages.length;
|
|
27
24
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
const results = [];
|
|
39
|
-
for (const shardTx of shardTransactions) {
|
|
40
|
-
results.push(await this.sendShardTransaction(shardTx, delay, chain, contractOpener));
|
|
25
|
+
catch (error) {
|
|
26
|
+
results.push({
|
|
27
|
+
success: false,
|
|
28
|
+
error: error,
|
|
29
|
+
lastMessageIndex: currentMessageIndex - 1,
|
|
30
|
+
});
|
|
31
|
+
break; // Stop sending after first error
|
|
41
32
|
}
|
|
42
|
-
return results;
|
|
43
33
|
}
|
|
34
|
+
return results;
|
|
44
35
|
}
|
|
45
36
|
getSenderAddress() {
|
|
46
37
|
return this.wallet.address.toString();
|
|
@@ -59,12 +50,17 @@ class RawSender {
|
|
|
59
50
|
}));
|
|
60
51
|
}
|
|
61
52
|
await (0, SenderAbstraction_1.sleep)(delay * 1000);
|
|
62
|
-
|
|
53
|
+
const result = await walletContract.sendTransfer({
|
|
63
54
|
seqno,
|
|
64
55
|
secretKey: this.secretKey,
|
|
65
56
|
messages,
|
|
66
57
|
sendMode: ton_2.SendMode.PAY_GAS_SEPARATELY,
|
|
67
58
|
});
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
result,
|
|
62
|
+
lastMessageIndex: shardTransaction.messages.length - 1,
|
|
63
|
+
};
|
|
68
64
|
}
|
|
69
65
|
}
|
|
70
66
|
exports.RawSender = RawSender;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Contract, ContractProvider, MessageRelaxed, SendMode } from '@ton/ton';
|
|
2
2
|
import type { ContractOpener } from '../structs/Struct';
|
|
3
|
-
import type { ShardTransaction } from '../structs/InternalStruct';
|
|
3
|
+
import type { SendResult, ShardTransaction } from '../structs/InternalStruct';
|
|
4
4
|
import { Network } from '../structs/Struct';
|
|
5
5
|
export declare const sleep: (ms: number) => Promise<unknown>;
|
|
6
6
|
export interface WalletInstance extends Contract {
|
|
@@ -14,7 +14,7 @@ export interface WalletInstance extends Contract {
|
|
|
14
14
|
}): Promise<void>;
|
|
15
15
|
}
|
|
16
16
|
export interface SenderAbstraction {
|
|
17
|
-
sendShardTransaction(shardTransaction: ShardTransaction, delay: number, chain?: Network, contractOpener?: ContractOpener): Promise<
|
|
18
|
-
sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain?: Network, contractOpener?: ContractOpener): Promise<
|
|
17
|
+
sendShardTransaction(shardTransaction: ShardTransaction, delay: number, chain?: Network, contractOpener?: ContractOpener): Promise<SendResult>;
|
|
18
|
+
sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain?: Network, contractOpener?: ContractOpener): Promise<SendResult[]>;
|
|
19
19
|
getSenderAddress(): string;
|
|
20
20
|
}
|
|
@@ -5,6 +5,7 @@ const ton_1 = require("@ton/ton");
|
|
|
5
5
|
const ton_crypto_1 = require("ton-crypto");
|
|
6
6
|
const RawSender_1 = require("./RawSender");
|
|
7
7
|
const TonConnectSender_1 = require("./TonConnectSender");
|
|
8
|
+
const BatchSender_1 = require("./BatchSender");
|
|
8
9
|
const errors_1 = require("../errors");
|
|
9
10
|
const Struct_1 = require("../structs/Struct");
|
|
10
11
|
const HighloadWalletV3_1 = require("../wrappers/HighloadWalletV3");
|
|
@@ -49,6 +50,9 @@ class SenderFactory {
|
|
|
49
50
|
config.timeout = params.options?.highloadV3?.timeout ?? HighloadWalletV3_1.DEFAULT_TIMEOUT;
|
|
50
51
|
}
|
|
51
52
|
const wallet = exports.wallets[params.version].create(config);
|
|
53
|
+
if (params.version === 'HIGHLOAD_V3') {
|
|
54
|
+
return new BatchSender_1.BatchSender(wallet, keypair.secretKey);
|
|
55
|
+
}
|
|
52
56
|
return new RawSender_1.RawSender(wallet, keypair.secretKey);
|
|
53
57
|
}
|
|
54
58
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { TonConnectUI } from '@tonconnect/ui';
|
|
2
|
-
import type { ShardTransaction } from '../structs/InternalStruct';
|
|
2
|
+
import type { SendResult, ShardTransaction } from '../structs/InternalStruct';
|
|
3
3
|
import { ContractOpener, Network } from '../structs/Struct';
|
|
4
4
|
import { SenderAbstraction } from './SenderAbstraction';
|
|
5
|
-
import { SendTransactionResponse } from '@tonconnect/sdk';
|
|
6
5
|
export declare class TonConnectSender implements SenderAbstraction {
|
|
7
6
|
readonly tonConnect: TonConnectUI;
|
|
8
7
|
constructor(tonConnect: TonConnectUI);
|
|
9
|
-
|
|
8
|
+
private sendChunkedMessages;
|
|
9
|
+
sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain: Network, _contractOpener?: ContractOpener): Promise<SendResult[]>;
|
|
10
10
|
getSenderAddress(): string;
|
|
11
|
-
sendShardTransaction(shardTransaction: ShardTransaction, delay: number, chain: Network): Promise<
|
|
11
|
+
sendShardTransaction(shardTransaction: ShardTransaction, delay: number, chain: Network): Promise<SendResult>;
|
|
12
12
|
}
|
|
@@ -5,13 +5,51 @@ const protocol_1 = require("@tonconnect/protocol");
|
|
|
5
5
|
const ui_1 = require("@tonconnect/ui");
|
|
6
6
|
const Struct_1 = require("../structs/Struct");
|
|
7
7
|
const SenderAbstraction_1 = require("./SenderAbstraction");
|
|
8
|
+
const CHUNK_SIZE = 4;
|
|
8
9
|
class TonConnectSender {
|
|
9
10
|
constructor(tonConnect) {
|
|
10
11
|
this.tonConnect = tonConnect;
|
|
11
12
|
}
|
|
12
|
-
async
|
|
13
|
+
async sendChunkedMessages(messages, validUntil, chain) {
|
|
14
|
+
const responses = [];
|
|
15
|
+
let currentMessageIndex = 0;
|
|
16
|
+
const chunkSize =
|
|
17
|
+
//@ts-ignore // 'find' checks that maxMessages is a property of the feature
|
|
18
|
+
this.tonConnect.wallet?.device.features.find((feat) => feat.hasOwnProperty('maxMessages'))?.maxMessages ||
|
|
19
|
+
CHUNK_SIZE;
|
|
20
|
+
for (let i = 0; i < messages.length; i += chunkSize) {
|
|
21
|
+
const chunk = messages.slice(i, i + chunkSize);
|
|
22
|
+
const transaction = {
|
|
23
|
+
validUntil,
|
|
24
|
+
messages: chunk,
|
|
25
|
+
network: chain == Struct_1.Network.TESTNET ? ui_1.CHAIN.TESTNET : ui_1.CHAIN.MAINNET,
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
const response = await this.tonConnect.sendTransaction(transaction);
|
|
29
|
+
responses.push({
|
|
30
|
+
success: true,
|
|
31
|
+
result: response,
|
|
32
|
+
lastMessageIndex: currentMessageIndex + chunk.length - 1,
|
|
33
|
+
});
|
|
34
|
+
currentMessageIndex += chunk.length;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
responses.push({
|
|
38
|
+
success: false,
|
|
39
|
+
error: error,
|
|
40
|
+
lastMessageIndex: currentMessageIndex - 1,
|
|
41
|
+
});
|
|
42
|
+
break; // Stop sending after first error
|
|
43
|
+
}
|
|
44
|
+
if (i + chunkSize < messages.length) {
|
|
45
|
+
await (0, SenderAbstraction_1.sleep)(1000);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return responses;
|
|
49
|
+
}
|
|
50
|
+
async sendShardTransactions(shardTransactions, delay, chain, _contractOpener) {
|
|
13
51
|
const allMessages = [];
|
|
14
|
-
let minValidUntil =
|
|
52
|
+
let minValidUntil = Number.MAX_SAFE_INTEGER;
|
|
15
53
|
for (const transaction of shardTransactions) {
|
|
16
54
|
for (const message of transaction.messages) {
|
|
17
55
|
allMessages.push({
|
|
@@ -22,14 +60,8 @@ class TonConnectSender {
|
|
|
22
60
|
}
|
|
23
61
|
minValidUntil = Math.min(minValidUntil, transaction.validUntil);
|
|
24
62
|
}
|
|
25
|
-
const transaction = {
|
|
26
|
-
validUntil: minValidUntil,
|
|
27
|
-
messages: allMessages,
|
|
28
|
-
network: chain == Struct_1.Network.TESTNET ? ui_1.CHAIN.TESTNET : ui_1.CHAIN.MAINNET,
|
|
29
|
-
};
|
|
30
63
|
await (0, SenderAbstraction_1.sleep)(delay * 1000);
|
|
31
|
-
|
|
32
|
-
return [response];
|
|
64
|
+
return this.sendChunkedMessages(allMessages, minValidUntil, chain);
|
|
33
65
|
}
|
|
34
66
|
getSenderAddress() {
|
|
35
67
|
return this.tonConnect.account?.address?.toString() || '';
|
|
@@ -43,13 +75,9 @@ class TonConnectSender {
|
|
|
43
75
|
payload: protocol_1.Base64.encode(message.payload.toBoc()).toString(),
|
|
44
76
|
});
|
|
45
77
|
}
|
|
46
|
-
const transaction = {
|
|
47
|
-
validUntil: shardTransaction.validUntil,
|
|
48
|
-
messages,
|
|
49
|
-
network: chain == Struct_1.Network.TESTNET ? ui_1.CHAIN.TESTNET : ui_1.CHAIN.MAINNET,
|
|
50
|
-
};
|
|
51
78
|
await (0, SenderAbstraction_1.sleep)(delay * 1000);
|
|
52
|
-
|
|
79
|
+
const responses = await this.sendChunkedMessages(messages, shardTransaction.validUntil, chain);
|
|
80
|
+
return responses[0];
|
|
53
81
|
}
|
|
54
82
|
}
|
|
55
83
|
exports.TonConnectSender = TonConnectSender;
|
package/dist/sender/index.d.ts
CHANGED
package/dist/sender/index.js
CHANGED
|
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./SenderAbstraction"), exports);
|
|
18
18
|
__exportStar(require("./SenderFactory"), exports);
|
|
19
|
+
__exportStar(require("./BatchSender"), exports);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Cell } from '@ton/ton';
|
|
2
|
-
import { ContractOpener, TACSimulationResult, ExecutionStagesByOperationId, Network, OperationIdsByShardsKey, RawAssetBridgingData, StatusInfosByOperationId, OperationType, AssetType } from './Struct';
|
|
2
|
+
import { ContractOpener, TACSimulationResult, ExecutionStagesByOperationId, Network, OperationIdsByShardsKey, RawAssetBridgingData, StatusInfosByOperationId, OperationType, AssetType, SuggestedTONExecutorFee } from './Struct';
|
|
3
3
|
import { AbstractProvider, ethers, Interface, InterfaceAbi } from 'ethers';
|
|
4
4
|
import { mainnet, testnet } from '@tonappchain/artifacts';
|
|
5
5
|
export type ShardMessage = {
|
|
@@ -80,3 +80,10 @@ export type StatusesResponse = ResponseBase<StatusInfosByOperationId>;
|
|
|
80
80
|
export type OperationIdsByShardsKeyResponse = ResponseBase<OperationIdsByShardsKey>;
|
|
81
81
|
export type StageProfilingResponse = ResponseBase<ExecutionStagesByOperationId>;
|
|
82
82
|
export type TACSimulationResponse = ResponseBase<TACSimulationResult>;
|
|
83
|
+
export type SuggestedTONExecutorFeeResponse = ResponseBase<SuggestedTONExecutorFee>;
|
|
84
|
+
export interface SendResult {
|
|
85
|
+
success: boolean;
|
|
86
|
+
result?: unknown;
|
|
87
|
+
error?: Error;
|
|
88
|
+
lastMessageIndex?: number;
|
|
89
|
+
}
|