@tonappchain/sdk 0.5.6 → 0.6.1-spb.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -20
- package/README.md +189 -1276
- package/dist/errors/instances.d.ts +1 -0
- package/dist/errors/instances.js +2 -1
- package/dist/sdk/Consts.d.ts +1 -0
- package/dist/sdk/Consts.js +3 -2
- package/dist/sdk/StartTracking.js +7 -6
- package/dist/sdk/TacSdk.d.ts +24 -7
- package/dist/sdk/TacSdk.js +400 -51
- package/dist/sdk/Utils.d.ts +3 -3
- package/dist/sdk/Utils.js +5 -3
- package/dist/sender/RawSender.d.ts +1 -0
- package/dist/sender/RawSender.js +33 -0
- package/dist/sender/SenderAbstraction.d.ts +1 -0
- package/dist/sender/TonConnectSender.d.ts +2 -1
- package/dist/sender/TonConnectSender.js +22 -0
- package/dist/structs/InternalStruct.d.ts +34 -6
- package/dist/structs/InternalStruct.js +2 -0
- package/dist/structs/Struct.d.ts +113 -6
- package/dist/structs/Struct.js +16 -1
- package/dist/wrappers/HighloadWalletV3.d.ts +1 -1
- package/dist/wrappers/HighloadWalletV3.js +4 -4
- package/dist/wrappers/JettonMaster.d.ts +1 -1
- package/dist/wrappers/JettonMaster.js +2 -2
- package/dist/wrappers/JettonWallet.d.ts +3 -2
- package/dist/wrappers/JettonWallet.js +8 -4
- package/package.json +67 -67
package/dist/sdk/TacSdk.js
CHANGED
|
@@ -21,6 +21,8 @@ const Utils_1 = require("./Utils");
|
|
|
21
21
|
const artifacts_1 = require("@tonappchain/artifacts");
|
|
22
22
|
const errors_1 = require("../errors");
|
|
23
23
|
const contractOpener_1 = require("../adapters/contractOpener");
|
|
24
|
+
const wrappers_1 = require("@tonappchain/artifacts/dist/src/ton/wrappers");
|
|
25
|
+
const instances_1 = require("../errors/instances");
|
|
24
26
|
class TacSdk {
|
|
25
27
|
constructor(network, delay, artifacts, TONParams, TACParams, liteSequencerEndpoints) {
|
|
26
28
|
this.network = network;
|
|
@@ -35,7 +37,7 @@ class TacSdk {
|
|
|
35
37
|
const delay = sdkParams.delay ?? Consts_1.DEFAULT_DELAY;
|
|
36
38
|
const artifacts = network === Struct_1.Network.TESTNET ? artifacts_1.testnet : artifacts_1.mainnet;
|
|
37
39
|
const TONParams = await this.prepareTONParams(network, delay, artifacts, sdkParams.TONParams);
|
|
38
|
-
const TACParams = await this.prepareTACParams(artifacts, sdkParams.TACParams);
|
|
40
|
+
const TACParams = await this.prepareTACParams(artifacts, delay, sdkParams.TACParams);
|
|
39
41
|
const liteSequencerEndpoints = sdkParams.customLiteSequencerEndpoints ??
|
|
40
42
|
(network === Struct_1.Network.TESTNET
|
|
41
43
|
? artifacts_1.testnet.PUBLIC_LITE_SEQUENCER_ENDPOINTS
|
|
@@ -50,9 +52,15 @@ class TacSdk {
|
|
|
50
52
|
await (0, Utils_1.sleep)(delay * 1000);
|
|
51
53
|
const crossChainLayerAddress = await settings.getAddressSetting('CrossChainLayerAddress');
|
|
52
54
|
await (0, Utils_1.sleep)(delay * 1000);
|
|
53
|
-
const jettonMinterCode = await settings.getCellSetting('
|
|
55
|
+
const jettonMinterCode = await settings.getCellSetting('JettonMinterCode');
|
|
54
56
|
await (0, Utils_1.sleep)(delay * 1000);
|
|
55
|
-
const jettonWalletCode = await settings.getCellSetting('
|
|
57
|
+
const jettonWalletCode = await settings.getCellSetting('JettonWalletCode');
|
|
58
|
+
await (0, Utils_1.sleep)(delay * 1000);
|
|
59
|
+
const nftProxyAddress = await settings.getAddressSetting('NFTProxyAddress');
|
|
60
|
+
await (0, Utils_1.sleep)(delay * 1000);
|
|
61
|
+
const nftItemCode = await settings.getCellSetting('NFTItemCode');
|
|
62
|
+
await (0, Utils_1.sleep)(delay * 1000);
|
|
63
|
+
const nftCollectionCode = await settings.getCellSetting('NFTCollectionCode');
|
|
56
64
|
await (0, Utils_1.sleep)(delay * 1000);
|
|
57
65
|
return {
|
|
58
66
|
contractOpener,
|
|
@@ -60,26 +68,42 @@ class TacSdk {
|
|
|
60
68
|
crossChainLayerAddress,
|
|
61
69
|
jettonMinterCode,
|
|
62
70
|
jettonWalletCode,
|
|
71
|
+
nftProxyAddress,
|
|
72
|
+
nftItemCode,
|
|
73
|
+
nftCollectionCode,
|
|
63
74
|
};
|
|
64
75
|
}
|
|
65
|
-
static async prepareTACParams(artifacts, TACParams) {
|
|
76
|
+
static async prepareTACParams(artifacts, delay, TACParams) {
|
|
66
77
|
const provider = TACParams?.provider ?? ethers_1.ethers.getDefaultProvider(artifacts.TAC_RPC_ENDPOINT);
|
|
67
78
|
const settingsAddress = TACParams?.settingsAddress?.toString() ?? artifacts.tac.addresses.TAC_SETTINGS_ADDRESS;
|
|
68
|
-
const settings =
|
|
79
|
+
const settings = artifacts.tac.wrappers.SettingsFactoryTAC.connect(settingsAddress, provider);
|
|
69
80
|
const crossChainLayerABI = TACParams?.crossChainLayerABI ?? artifacts.tac.compilationArtifacts.CrossChainLayer.abi;
|
|
70
81
|
const crossChainLayerAddress = await settings.getAddressSetting((0, ethers_1.keccak256)((0, ethers_1.toUtf8Bytes)('CrossChainLayerAddress')));
|
|
82
|
+
const crossChainLayer = artifacts.tac.wrappers.CrossChainLayerFactoryTAC.connect(crossChainLayerAddress, provider);
|
|
83
|
+
await (0, Utils_1.sleep)(delay * 1000);
|
|
71
84
|
const tokenUtilsAddress = await settings.getAddressSetting((0, ethers_1.keccak256)((0, ethers_1.toUtf8Bytes)('TokenUtilsAddress')));
|
|
85
|
+
const tokenUtils = artifacts.tac.wrappers.TokenUtilsFactoryTAC.connect(tokenUtilsAddress, provider);
|
|
86
|
+
await (0, Utils_1.sleep)(delay * 1000);
|
|
87
|
+
const trustedTACExecutors = await settings.getTrustedEVMExecutors();
|
|
88
|
+
await (0, Utils_1.sleep)(delay * 1000);
|
|
89
|
+
const trustedTONExecutors = await settings.getTrustedTVMExecutors();
|
|
72
90
|
const crossChainLayerTokenABI = TACParams?.crossChainLayerTokenABI ?? artifacts.tac.compilationArtifacts.CrossChainLayerToken.abi;
|
|
73
91
|
const crossChainLayerTokenBytecode = TACParams?.crossChainLayerTokenBytecode ?? artifacts.tac.compilationArtifacts.CrossChainLayerToken.bytecode;
|
|
92
|
+
const crossChainLayerNFTABI = TACParams?.crossChainLayerNFTABI ?? artifacts.tac.compilationArtifacts.CrossChainLayerNFT.abi;
|
|
93
|
+
const crossChainLayerNFTBytecode = TACParams?.crossChainLayerNFTBytecode ?? artifacts.tac.compilationArtifacts.CrossChainLayerNFT.bytecode;
|
|
74
94
|
return {
|
|
75
95
|
provider,
|
|
76
|
-
|
|
77
|
-
|
|
96
|
+
settings,
|
|
97
|
+
tokenUtils,
|
|
98
|
+
crossChainLayer,
|
|
99
|
+
trustedTACExecutors,
|
|
100
|
+
trustedTONExecutors,
|
|
78
101
|
abiCoder: new ethers_1.ethers.AbiCoder(),
|
|
79
102
|
crossChainLayerABI,
|
|
80
|
-
crossChainLayerAddress,
|
|
81
103
|
crossChainLayerTokenABI,
|
|
82
104
|
crossChainLayerTokenBytecode,
|
|
105
|
+
crossChainLayerNFTABI,
|
|
106
|
+
crossChainLayerNFTBytecode,
|
|
83
107
|
};
|
|
84
108
|
}
|
|
85
109
|
closeConnections() {
|
|
@@ -88,9 +112,8 @@ class TacSdk {
|
|
|
88
112
|
get nativeTONAddress() {
|
|
89
113
|
return 'NONE';
|
|
90
114
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return crossChainLayer.NATIVE_TOKEN_ADDRESS.staticCall();
|
|
115
|
+
async nativeTACAddress() {
|
|
116
|
+
return this.TACParams.crossChainLayer.NATIVE_TOKEN_ADDRESS.staticCall();
|
|
94
117
|
}
|
|
95
118
|
async getUserJettonWalletAddress(userAddress, tokenAddress) {
|
|
96
119
|
const jettonMaster = this.TONParams.contractOpener.open(new JettonMaster_1.JettonMaster(ton_1.Address.parse(tokenAddress)));
|
|
@@ -124,21 +147,52 @@ class TacSdk {
|
|
|
124
147
|
exists: true,
|
|
125
148
|
};
|
|
126
149
|
}
|
|
127
|
-
getJettonTransferPayload(jettonData, responseAddress, evmData, crossChainTonAmount) {
|
|
150
|
+
getJettonTransferPayload(jettonData, responseAddress, evmData, crossChainTonAmount, forwardFeeAmount, feeData) {
|
|
151
|
+
const queryId = (0, Utils_1.generateRandomNumberByTimestamp)().randomNumber;
|
|
152
|
+
return JettonWallet_1.JettonWallet.transferMessage(jettonData.rawAmount, this.TONParams.jettonProxyAddress, responseAddress, Consts_1.JETTON_TRANSFER_FORWARD_TON_AMOUNT + forwardFeeAmount + crossChainTonAmount, crossChainTonAmount, feeData, evmData, queryId);
|
|
153
|
+
}
|
|
154
|
+
getJettonBurnPayload(jettonData, evmData, crossChainTonAmount, feeData) {
|
|
128
155
|
const queryId = (0, Utils_1.generateRandomNumberByTimestamp)().randomNumber;
|
|
129
|
-
return JettonWallet_1.JettonWallet.
|
|
156
|
+
return JettonWallet_1.JettonWallet.burnMessage(jettonData.rawAmount, jettonData.notificationReceiverAddress, crossChainTonAmount, feeData, evmData, queryId);
|
|
130
157
|
}
|
|
131
|
-
|
|
158
|
+
getNFTBurnPayload(burnData) {
|
|
132
159
|
const queryId = (0, Utils_1.generateRandomNumberByTimestamp)().randomNumber;
|
|
133
|
-
return
|
|
160
|
+
return wrappers_1.NFTItem.burnMessage(queryId, (0, ton_1.address)(burnData.notificationReceiverAddress), burnData.crossChainTonAmount ?? 0, burnData.evmData, burnData.feeData);
|
|
134
161
|
}
|
|
135
|
-
|
|
162
|
+
getNFTTransferPayload(transferData, forwardFeeAmount) {
|
|
136
163
|
const queryId = (0, Utils_1.generateRandomNumberByTimestamp)().randomNumber;
|
|
164
|
+
const crossChainTonAmount = transferData.crossChainTonAmount ?? 0n;
|
|
165
|
+
const forwardPayload = (0, ton_1.beginCell)()
|
|
166
|
+
.storeCoins(crossChainTonAmount)
|
|
167
|
+
.storeMaybeRef(transferData.feeData)
|
|
168
|
+
.storeMaybeRef(transferData.evmData)
|
|
169
|
+
.endCell();
|
|
170
|
+
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
|
+
}
|
|
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
|
+
getTonTransferPayload(responseAddress, evmData, crossChainTonAmount, feeParams) {
|
|
188
|
+
const queryId = (0, Utils_1.generateRandomNumberByTimestamp)().randomNumber;
|
|
189
|
+
const feeData = this.generateFeeData(feeParams);
|
|
137
190
|
return (0, ton_1.beginCell)()
|
|
138
|
-
.storeUint(this.artifacts.ton.wrappers.CrossChainLayerOpCodes.
|
|
191
|
+
.storeUint(this.artifacts.ton.wrappers.CrossChainLayerOpCodes.anyone_tvmMsgToEVM, 32)
|
|
139
192
|
.storeUint(queryId, 64)
|
|
140
193
|
.storeUint(this.artifacts.ton.wrappers.OperationType.tonTransfer, 32)
|
|
141
194
|
.storeCoins(crossChainTonAmount)
|
|
195
|
+
.storeMaybeRef(feeData)
|
|
142
196
|
.storeAddress(ton_1.Address.parse(responseAddress))
|
|
143
197
|
.storeMaybeRef(evmData)
|
|
144
198
|
.endCell();
|
|
@@ -154,26 +208,51 @@ class TacSdk {
|
|
|
154
208
|
return InternalStruct_1.AssetOpType.JETTON_TRANSFER;
|
|
155
209
|
}
|
|
156
210
|
const givenMinter = this.TONParams.contractOpener.open(new JettonMaster_1.JettonMaster((0, ton_1.address)(asset.address)));
|
|
157
|
-
const
|
|
211
|
+
const evmAddress = await givenMinter.getEVMAddress();
|
|
158
212
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
159
213
|
const expectedMinterAddress = await (0, Utils_1.calculateContractAddress)(this.TONParams.jettonMinterCode, (0, ton_1.beginCell)()
|
|
160
214
|
.storeCoins(0)
|
|
161
215
|
.storeAddress((0, ton_1.address)(this.TONParams.crossChainLayerAddress))
|
|
216
|
+
.storeAddress(null)
|
|
162
217
|
.storeRef((0, ton_1.beginCell)().endCell())
|
|
163
218
|
.storeRef(this.TONParams.jettonWalletCode)
|
|
164
|
-
.storeStringTail(
|
|
219
|
+
.storeStringTail(evmAddress)
|
|
165
220
|
.endCell());
|
|
166
221
|
if (!expectedMinterAddress.equals(givenMinter.address)) {
|
|
167
222
|
return InternalStruct_1.AssetOpType.JETTON_TRANSFER;
|
|
168
223
|
}
|
|
169
224
|
return InternalStruct_1.AssetOpType.JETTON_BURN;
|
|
170
225
|
}
|
|
171
|
-
async
|
|
226
|
+
async getNFTOpType(asset) {
|
|
227
|
+
const { code: itemCodeBOC } = await this.TONParams.contractOpener.getContractState((0, ton_1.address)(asset.address));
|
|
228
|
+
if (!itemCodeBOC) {
|
|
229
|
+
throw errors_1.emptyContractError;
|
|
230
|
+
}
|
|
231
|
+
const givenNFTItemCode = ton_1.Cell.fromBoc(itemCodeBOC)[0];
|
|
232
|
+
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
233
|
+
if (!this.TONParams.nftItemCode.equals(givenNFTItemCode)) {
|
|
234
|
+
return InternalStruct_1.AssetOpType.NFT_TRANSFER;
|
|
235
|
+
}
|
|
236
|
+
return InternalStruct_1.AssetOpType.NFT_BURN;
|
|
237
|
+
}
|
|
238
|
+
async getNFTItemAddressTON(collectionAddress, itemIndex) {
|
|
239
|
+
(0, Utils_1.validateTVMAddress)(collectionAddress);
|
|
240
|
+
const nftCollection = this.TONParams.contractOpener.open(wrappers_1.NFTCollection.createFromAddress((0, ton_1.address)(collectionAddress)));
|
|
241
|
+
return (await nftCollection.getNFTAddressByIndex(itemIndex)).toString();
|
|
242
|
+
}
|
|
243
|
+
async getNFTItemData(itemAddress) {
|
|
244
|
+
(0, Utils_1.validateTVMAddress)(itemAddress);
|
|
245
|
+
const nftItem = this.TONParams.contractOpener.open(wrappers_1.NFTItem.createFromAddress((0, ton_1.address)(itemAddress)));
|
|
246
|
+
return await nftItem.getNFTData();
|
|
247
|
+
}
|
|
248
|
+
async aggregateTokens(assets) {
|
|
172
249
|
const uniqueAssetsMap = new Map();
|
|
173
250
|
let crossChainTonAmount = 0n;
|
|
174
251
|
for await (const asset of assets ?? []) {
|
|
175
252
|
if (asset.rawAmount <= 0)
|
|
176
253
|
continue;
|
|
254
|
+
if (asset.type !== Struct_1.AssetType.FT)
|
|
255
|
+
continue;
|
|
177
256
|
if (asset.address) {
|
|
178
257
|
(0, Utils_1.validateTVMAddress)(asset.address);
|
|
179
258
|
uniqueAssetsMap.set(asset.address, (uniqueAssetsMap.get(asset.address) || 0n) + BigInt(asset.rawAmount));
|
|
@@ -185,53 +264,113 @@ class TacSdk {
|
|
|
185
264
|
const jettons = Array.from(uniqueAssetsMap.entries()).map(([address, rawAmount]) => ({
|
|
186
265
|
address,
|
|
187
266
|
rawAmount,
|
|
267
|
+
type: Struct_1.AssetType.FT,
|
|
268
|
+
}));
|
|
269
|
+
uniqueAssetsMap.clear();
|
|
270
|
+
for await (const asset of assets ?? []) {
|
|
271
|
+
if (asset.type !== Struct_1.AssetType.NFT)
|
|
272
|
+
continue;
|
|
273
|
+
(0, Utils_1.validateTVMAddress)(asset.address);
|
|
274
|
+
uniqueAssetsMap.set(asset.address, 1n);
|
|
275
|
+
}
|
|
276
|
+
const nfts = Array.from(uniqueAssetsMap.entries()).map(([address, rawAmount]) => ({
|
|
277
|
+
address,
|
|
278
|
+
rawAmount,
|
|
279
|
+
type: Struct_1.AssetType.NFT,
|
|
188
280
|
}));
|
|
189
281
|
return {
|
|
190
282
|
jettons,
|
|
283
|
+
nfts,
|
|
191
284
|
crossChainTonAmount,
|
|
192
285
|
};
|
|
193
286
|
}
|
|
194
|
-
async
|
|
287
|
+
async generateJettonPayload(jetton, caller, evmData, crossChainTonAmount, forwardFeeTonAmount, feeParams) {
|
|
195
288
|
const opType = await this.getJettonOpType(jetton);
|
|
196
289
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
197
290
|
console.log(`***** Jetton ${jetton.address} requires ${opType} operation`);
|
|
291
|
+
const feeData = this.generateFeeData(feeParams);
|
|
198
292
|
let payload;
|
|
199
293
|
switch (opType) {
|
|
200
294
|
case InternalStruct_1.AssetOpType.JETTON_BURN:
|
|
201
295
|
payload = this.getJettonBurnPayload({
|
|
202
296
|
notificationReceiverAddress: this.TONParams.crossChainLayerAddress,
|
|
203
297
|
...jetton,
|
|
204
|
-
}, evmData, crossChainTonAmount);
|
|
298
|
+
}, evmData, crossChainTonAmount, feeData);
|
|
205
299
|
break;
|
|
206
300
|
case InternalStruct_1.AssetOpType.JETTON_TRANSFER:
|
|
207
|
-
payload = this.getJettonTransferPayload(jetton, caller, evmData, crossChainTonAmount);
|
|
301
|
+
payload = this.getJettonTransferPayload(jetton, caller, evmData, crossChainTonAmount, forwardFeeTonAmount, feeData);
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
return payload;
|
|
305
|
+
}
|
|
306
|
+
async generateNFTPayload(nft, caller, evmData, crossChainTonAmount, forwardFeeTonAmount, feeParams) {
|
|
307
|
+
const opType = await this.getNFTOpType(nft);
|
|
308
|
+
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
309
|
+
console.log(`***** NFT ${nft.address} requires ${opType} operation`);
|
|
310
|
+
const feeData = this.generateFeeData(feeParams);
|
|
311
|
+
let payload;
|
|
312
|
+
switch (opType) {
|
|
313
|
+
case InternalStruct_1.AssetOpType.NFT_BURN:
|
|
314
|
+
payload = this.getNFTBurnPayload({
|
|
315
|
+
notificationReceiverAddress: this.TONParams.crossChainLayerAddress,
|
|
316
|
+
...nft,
|
|
317
|
+
evmData,
|
|
318
|
+
crossChainTonAmount,
|
|
319
|
+
feeData,
|
|
320
|
+
});
|
|
321
|
+
break;
|
|
322
|
+
case InternalStruct_1.AssetOpType.NFT_TRANSFER:
|
|
323
|
+
payload = this.getNFTTransferPayload({
|
|
324
|
+
to: this.TONParams.nftProxyAddress,
|
|
325
|
+
responseAddress: caller,
|
|
326
|
+
evmData,
|
|
327
|
+
crossChainTonAmount,
|
|
328
|
+
feeData,
|
|
329
|
+
...nft,
|
|
330
|
+
}, forwardFeeTonAmount);
|
|
208
331
|
break;
|
|
209
332
|
}
|
|
210
333
|
return payload;
|
|
211
334
|
}
|
|
212
|
-
async generateCrossChainMessages(caller, evmData, aggregatedData) {
|
|
335
|
+
async generateCrossChainMessages(caller, evmData, aggregatedData, feeParams) {
|
|
213
336
|
let crossChainTonAmount = aggregatedData.crossChainTonAmount;
|
|
214
|
-
|
|
337
|
+
let feeTonAmount = feeParams.protocolFee + feeParams.evmExecutorFee + feeParams.tvmExecutorFee;
|
|
338
|
+
if (aggregatedData.jettons.length == 0 && aggregatedData.nfts.length == 0) {
|
|
215
339
|
return [
|
|
216
340
|
{
|
|
217
341
|
address: this.TONParams.crossChainLayerAddress,
|
|
218
|
-
value: crossChainTonAmount + Consts_1.TRANSACTION_TON_AMOUNT,
|
|
219
|
-
payload: this.getTonTransferPayload(caller, evmData, crossChainTonAmount),
|
|
342
|
+
value: crossChainTonAmount + feeTonAmount + Consts_1.TRANSACTION_TON_AMOUNT,
|
|
343
|
+
payload: this.getTonTransferPayload(caller, evmData, crossChainTonAmount, feeParams),
|
|
220
344
|
},
|
|
221
345
|
];
|
|
222
346
|
}
|
|
223
347
|
const messages = [];
|
|
348
|
+
let currentFeeParams = feeParams;
|
|
224
349
|
for (const jetton of aggregatedData.jettons) {
|
|
225
|
-
const payload = await this.
|
|
350
|
+
const payload = await this.generateJettonPayload(jetton, caller, evmData, crossChainTonAmount, feeTonAmount, currentFeeParams);
|
|
226
351
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
227
352
|
const jettonWalletAddress = await this.getUserJettonWalletAddress(caller, jetton.address);
|
|
228
353
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
229
354
|
messages.push({
|
|
230
355
|
address: jettonWalletAddress,
|
|
231
|
-
value: crossChainTonAmount + Consts_1.TRANSACTION_TON_AMOUNT,
|
|
356
|
+
value: crossChainTonAmount + feeTonAmount + Consts_1.TRANSACTION_TON_AMOUNT,
|
|
357
|
+
payload,
|
|
358
|
+
});
|
|
359
|
+
crossChainTonAmount = 0n;
|
|
360
|
+
feeTonAmount = 0n;
|
|
361
|
+
currentFeeParams = undefined;
|
|
362
|
+
}
|
|
363
|
+
for (const nft of aggregatedData.nfts) {
|
|
364
|
+
const payload = await this.generateNFTPayload(nft, caller, evmData, crossChainTonAmount, feeTonAmount, currentFeeParams);
|
|
365
|
+
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
366
|
+
messages.push({
|
|
367
|
+
address: nft.address,
|
|
368
|
+
value: crossChainTonAmount + feeTonAmount + Consts_1.TRANSACTION_TON_AMOUNT,
|
|
232
369
|
payload,
|
|
233
370
|
});
|
|
234
371
|
crossChainTonAmount = 0n;
|
|
372
|
+
feeTonAmount = 0n;
|
|
373
|
+
currentFeeParams = undefined;
|
|
235
374
|
}
|
|
236
375
|
return messages;
|
|
237
376
|
}
|
|
@@ -260,75 +399,243 @@ class TacSdk {
|
|
|
260
399
|
}
|
|
261
400
|
async convertAssetsToRawFormat(assets) {
|
|
262
401
|
return await Promise.all((assets ?? []).map(async (asset) => {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
402
|
+
if (asset.type === Struct_1.AssetType.FT) {
|
|
403
|
+
const address = (0, ethers_1.isAddress)(asset.address)
|
|
404
|
+
? await this.getTVMTokenAddress(asset.address)
|
|
405
|
+
: asset.address;
|
|
406
|
+
return {
|
|
407
|
+
address,
|
|
408
|
+
rawAmount: await this.getRawAmount(asset, address),
|
|
409
|
+
type: asset.type,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
if (asset.type === Struct_1.AssetType.NFT) {
|
|
413
|
+
if ('collectionAddress' in asset) {
|
|
414
|
+
const address = (0, ethers_1.isAddress)(asset.collectionAddress)
|
|
415
|
+
? await this.getTVMNFTAddress(asset.collectionAddress, asset.itemIndex)
|
|
416
|
+
: await this.getNFTItemAddressTON(asset.collectionAddress, asset.itemIndex);
|
|
417
|
+
return {
|
|
418
|
+
address,
|
|
419
|
+
rawAmount: 1n,
|
|
420
|
+
type: asset.type,
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
(0, Utils_1.validateTVMAddress)(asset.address);
|
|
424
|
+
return {
|
|
425
|
+
address: asset.address,
|
|
426
|
+
rawAmount: 1n,
|
|
427
|
+
type: asset.type,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
throw instances_1.invalidAssetType;
|
|
270
431
|
}));
|
|
271
432
|
}
|
|
272
|
-
async
|
|
433
|
+
async getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, evmValidExecutors, forceSend = false, isRoundTrip) {
|
|
434
|
+
const crossChainLayer = this.TONParams.contractOpener.open(this.artifacts.ton.wrappers.CrossChainLayer.createFromAddress(ton_1.Address.parse(this.TONParams.crossChainLayerAddress)));
|
|
435
|
+
const fullStateCCL = await crossChainLayer.getFullData();
|
|
273
436
|
const tacSimulationBody = {
|
|
274
437
|
tacCallParams: {
|
|
275
438
|
arguments: evmProxyMsg.encodedParameters ?? '0x',
|
|
276
439
|
methodName: (0, Utils_1.formatSolidityMethodName)(evmProxyMsg.methodName),
|
|
277
440
|
target: evmProxyMsg.evmTargetAddress,
|
|
278
441
|
},
|
|
442
|
+
evmValidExecutors: evmValidExecutors,
|
|
279
443
|
extraData: '0x',
|
|
280
444
|
feeAssetAddress: '',
|
|
281
445
|
shardsKey: transactionLinker.shardsKey,
|
|
282
446
|
tonAssets: rawAssets.map((asset) => ({
|
|
283
447
|
amount: asset.rawAmount.toString(),
|
|
284
448
|
tokenAddress: asset.address || '',
|
|
449
|
+
assetType: asset.type,
|
|
285
450
|
})),
|
|
286
451
|
tonCaller: transactionLinker.caller,
|
|
287
452
|
};
|
|
288
453
|
const tacSimulationResult = await this.simulateTACMessage(tacSimulationBody);
|
|
289
454
|
if (!tacSimulationResult.simulationStatus) {
|
|
290
455
|
if (forceSend) {
|
|
291
|
-
return
|
|
456
|
+
return {
|
|
457
|
+
feeParams: {
|
|
458
|
+
isRoundTrip: isRoundTrip ?? false,
|
|
459
|
+
gasLimit: 0n,
|
|
460
|
+
protocolFee: BigInt((0, ton_1.toNano)(fullStateCCL.tacProtocolFee)) +
|
|
461
|
+
BigInt(isRoundTrip ?? false) * BigInt((0, ton_1.toNano)(fullStateCCL.tonProtocolFee)),
|
|
462
|
+
evmExecutorFee: 0n,
|
|
463
|
+
tvmExecutorFee: 0n,
|
|
464
|
+
},
|
|
465
|
+
simulation: tacSimulationResult,
|
|
466
|
+
};
|
|
292
467
|
}
|
|
293
468
|
throw tacSimulationResult;
|
|
294
469
|
}
|
|
295
|
-
|
|
470
|
+
isRoundTrip = isRoundTrip ?? tacSimulationResult.outMessages != null;
|
|
471
|
+
let tonExecutorFeeInTON = 0n;
|
|
472
|
+
if (isRoundTrip) {
|
|
473
|
+
tonExecutorFeeInTON = BigInt(tacSimulationResult.suggestedTonExecutionFee);
|
|
474
|
+
}
|
|
475
|
+
const protocolFee = BigInt((0, ton_1.toNano)(fullStateCCL.tacProtocolFee)) +
|
|
476
|
+
BigInt(isRoundTrip) * BigInt((0, ton_1.toNano)(fullStateCCL.tonProtocolFee));
|
|
477
|
+
const feeParams = {
|
|
478
|
+
isRoundTrip: isRoundTrip,
|
|
479
|
+
gasLimit: tacSimulationResult.estimatedGas,
|
|
480
|
+
protocolFee: protocolFee,
|
|
481
|
+
evmExecutorFee: BigInt(tacSimulationResult.suggestedTacExecutionFee),
|
|
482
|
+
tvmExecutorFee: tonExecutorFeeInTON,
|
|
483
|
+
};
|
|
484
|
+
return { feeParams: feeParams, simulation: tacSimulationResult };
|
|
296
485
|
}
|
|
297
|
-
async
|
|
486
|
+
async getTransactionSimulationInfo(evmProxyMsg, sender, assets) {
|
|
298
487
|
const rawAssets = await this.convertAssetsToRawFormat(assets);
|
|
299
|
-
const aggregatedData = await this.
|
|
488
|
+
const aggregatedData = await this.aggregateTokens(rawAssets);
|
|
300
489
|
const transactionLinkerShardCount = aggregatedData.jettons.length == 0 ? 1 : aggregatedData.jettons.length;
|
|
301
|
-
const
|
|
490
|
+
const transactionLinker = (0, Utils_1.generateTransactionLinker)(sender.getSenderAddress(), transactionLinkerShardCount);
|
|
491
|
+
const evmValidExecutors = this.TACParams.trustedTACExecutors;
|
|
492
|
+
return await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, evmValidExecutors, false, undefined);
|
|
493
|
+
}
|
|
494
|
+
async prepareCrossChainTransaction(evmProxyMsg, caller, assets, options) {
|
|
495
|
+
let { forceSend = false, isRoundTrip = undefined, protocolFee = undefined, evmValidExecutors = [], evmExecutorFee = undefined, tvmValidExecutors = [], tvmExecutorFee = undefined, } = options || {};
|
|
496
|
+
const rawAssets = await this.convertAssetsToRawFormat(assets);
|
|
497
|
+
const aggregatedData = await this.aggregateTokens(rawAssets);
|
|
498
|
+
const tokensLength = aggregatedData.jettons.length + aggregatedData.nfts.length;
|
|
499
|
+
let transactionLinkerShardCount = tokensLength == 0 ? 1 : tokensLength;
|
|
302
500
|
const transactionLinker = (0, Utils_1.generateTransactionLinker)(caller, transactionLinkerShardCount);
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
501
|
+
if (evmValidExecutors.length == 0) {
|
|
502
|
+
evmValidExecutors = this.TACParams.trustedTACExecutors;
|
|
503
|
+
}
|
|
504
|
+
if (tvmValidExecutors.length == 0) {
|
|
505
|
+
tvmValidExecutors = this.TACParams.trustedTONExecutors;
|
|
506
|
+
}
|
|
507
|
+
const { feeParams } = await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, evmValidExecutors, forceSend, isRoundTrip);
|
|
508
|
+
if (evmProxyMsg.gasLimit == undefined) {
|
|
509
|
+
evmProxyMsg.gasLimit = feeParams.gasLimit;
|
|
306
510
|
}
|
|
307
|
-
|
|
308
|
-
|
|
511
|
+
if (evmExecutorFee != undefined) {
|
|
512
|
+
feeParams.evmExecutorFee = evmExecutorFee;
|
|
513
|
+
}
|
|
514
|
+
if (feeParams.isRoundTrip && tvmExecutorFee != undefined) {
|
|
515
|
+
feeParams.tvmExecutorFee = tvmExecutorFee;
|
|
516
|
+
}
|
|
517
|
+
if (protocolFee != undefined) {
|
|
518
|
+
feeParams.protocolFee = protocolFee;
|
|
519
|
+
}
|
|
520
|
+
const validExecutors = {
|
|
521
|
+
tac: evmValidExecutors,
|
|
522
|
+
ton: tvmValidExecutors,
|
|
523
|
+
};
|
|
524
|
+
const evmData = (0, Utils_1.buildEvmDataCell)(transactionLinker, evmProxyMsg, validExecutors);
|
|
525
|
+
const messages = await this.generateCrossChainMessages(caller, evmData, aggregatedData, feeParams);
|
|
309
526
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
310
527
|
const transaction = {
|
|
311
528
|
validUntil: +new Date() + 15 * 60 * 1000,
|
|
312
529
|
messages,
|
|
313
530
|
network: this.network,
|
|
314
531
|
};
|
|
532
|
+
return { transaction, transactionLinker };
|
|
533
|
+
}
|
|
534
|
+
async sendCrossChainTransaction(evmProxyMsg, sender, assets, options) {
|
|
535
|
+
const caller = sender.getSenderAddress();
|
|
536
|
+
const { transaction, transactionLinker } = await this.prepareCrossChainTransaction(evmProxyMsg, caller, assets, options);
|
|
315
537
|
console.log('*****Sending transaction: ', transaction);
|
|
316
538
|
const sendTransactionResult = await sender.sendShardTransaction(transaction, this.delay, this.network, this.TONParams.contractOpener);
|
|
317
539
|
return { sendTransactionResult, ...transactionLinker };
|
|
318
540
|
}
|
|
541
|
+
async sendCrossChainTransactions(sender, txs) {
|
|
542
|
+
const transactions = [];
|
|
543
|
+
const transactionLinkers = [];
|
|
544
|
+
const caller = sender.getSenderAddress();
|
|
545
|
+
for (const { options, assets, evmProxyMsg } of txs) {
|
|
546
|
+
const { transaction, transactionLinker } = await this.prepareCrossChainTransaction(evmProxyMsg, caller, assets, options);
|
|
547
|
+
transactions.push(transaction);
|
|
548
|
+
transactionLinkers.push(transactionLinker);
|
|
549
|
+
}
|
|
550
|
+
console.log('*****Sending transactions: ', transactions);
|
|
551
|
+
await sender.sendShardTransactions(transactions, this.delay, this.network, this.TONParams.contractOpener);
|
|
552
|
+
return transactionLinkers;
|
|
553
|
+
}
|
|
554
|
+
// TODO move to sdk.TAC, sdk.TON
|
|
555
|
+
async bridgeTokensToTON(signer, value, tonTarget, assets, tvmExecutorFee) {
|
|
556
|
+
if (assets == undefined) {
|
|
557
|
+
assets = [];
|
|
558
|
+
}
|
|
559
|
+
const crossChainLayerAddress = await this.TACParams.crossChainLayer.getAddress();
|
|
560
|
+
for (const asset of assets) {
|
|
561
|
+
if (asset.type == Struct_1.AssetType.FT) {
|
|
562
|
+
const tokenContract = this.artifacts.tac.wrappers.ERC20FactoryTAC.connect(asset.address, this.TACParams.provider);
|
|
563
|
+
const tx = await tokenContract.connect(signer).approve(crossChainLayerAddress, asset.rawAmount);
|
|
564
|
+
await tx.wait();
|
|
565
|
+
}
|
|
566
|
+
if (asset.type == Struct_1.AssetType.NFT) {
|
|
567
|
+
const tokenContract = this.artifacts.tac.wrappers.ERC721FactoryTAC.connect(asset.collectionAddress, this.TACParams.provider);
|
|
568
|
+
const tx = await tokenContract.connect(signer).approve(crossChainLayerAddress, asset.itemIndex);
|
|
569
|
+
await tx.wait();
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
const shardsKey = BigInt(Math.round(Math.random() * 1e18));
|
|
573
|
+
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
|
+
const outMessage = {
|
|
590
|
+
shardsKey: shardsKey,
|
|
591
|
+
tvmTarget: tonTarget,
|
|
592
|
+
tvmPayload: '',
|
|
593
|
+
tvmProtocolFee: protocolFee,
|
|
594
|
+
tvmExecutorFee: tvmExecutorFeeInTAC,
|
|
595
|
+
tvmValidExecutors: this.TACParams.trustedTONExecutors,
|
|
596
|
+
toBridge: assets
|
|
597
|
+
.filter((asset) => asset.type === Struct_1.AssetType.FT)
|
|
598
|
+
.map((asset) => ({
|
|
599
|
+
evmAddress: asset.address,
|
|
600
|
+
amount: asset.rawAmount,
|
|
601
|
+
})),
|
|
602
|
+
toBridgeNFT: assets
|
|
603
|
+
.filter((asset) => asset.type === Struct_1.AssetType.NFT)
|
|
604
|
+
.map((asset) => ({
|
|
605
|
+
evmAddress: asset.collectionAddress,
|
|
606
|
+
amount: 1n,
|
|
607
|
+
tokenId: asset.itemIndex,
|
|
608
|
+
})),
|
|
609
|
+
};
|
|
610
|
+
const encodedOutMessage = this.artifacts.tac.utils.encodeOutMessageV1(outMessage);
|
|
611
|
+
const outMsgVersion = 1n;
|
|
612
|
+
const totalValue = value + BigInt(outMessage.tvmProtocolFee) + BigInt(outMessage.tvmExecutorFee);
|
|
613
|
+
const tx = await this.TACParams.crossChainLayer
|
|
614
|
+
.connect(signer)
|
|
615
|
+
.sendMessage(outMsgVersion, encodedOutMessage, { value: totalValue });
|
|
616
|
+
await tx.wait();
|
|
617
|
+
return tx.hash;
|
|
618
|
+
}
|
|
619
|
+
get getTrustedTACExecutors() {
|
|
620
|
+
return this.TACParams.trustedTACExecutors;
|
|
621
|
+
}
|
|
622
|
+
get getTrustedTONExecutors() {
|
|
623
|
+
return this.TACParams.trustedTONExecutors;
|
|
624
|
+
}
|
|
319
625
|
async getEVMTokenAddress(tvmTokenAddress) {
|
|
320
626
|
if (tvmTokenAddress !== this.nativeTONAddress) {
|
|
321
627
|
(0, Utils_1.validateTVMAddress)(tvmTokenAddress);
|
|
628
|
+
tvmTokenAddress = ton_1.Address.parse(tvmTokenAddress).toString({ bounceable: true });
|
|
322
629
|
const { code: givenMinterCodeBOC } = await this.TONParams.contractOpener.getContractState((0, ton_1.address)(tvmTokenAddress));
|
|
323
630
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
324
631
|
if (givenMinterCodeBOC && this.TONParams.jettonMinterCode.equals(ton_1.Cell.fromBoc(givenMinterCodeBOC)[0])) {
|
|
325
632
|
const givenMinter = this.TONParams.contractOpener.open(new JettonMaster_1.JettonMaster((0, ton_1.address)(tvmTokenAddress)));
|
|
326
|
-
const
|
|
633
|
+
const evmAddress = await givenMinter.getEVMAddress();
|
|
327
634
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
328
|
-
return
|
|
635
|
+
return evmAddress;
|
|
329
636
|
}
|
|
330
637
|
}
|
|
331
|
-
return
|
|
638
|
+
return this.TACParams.tokenUtils.computeAddress(tvmTokenAddress);
|
|
332
639
|
}
|
|
333
640
|
async getTVMTokenAddress(evmTokenAddress) {
|
|
334
641
|
(0, Utils_1.validateEVMAddress)(evmTokenAddress);
|
|
@@ -336,7 +643,7 @@ class TacSdk {
|
|
|
336
643
|
if (bytecode.includes(ethers_1.ethers.id('getInfo()').slice(2, 10))) {
|
|
337
644
|
const contract = new ethers_1.ethers.Contract(evmTokenAddress, this.TACParams.crossChainLayerTokenABI, this.TACParams.provider);
|
|
338
645
|
const info = await contract.getInfo.staticCall();
|
|
339
|
-
return info.
|
|
646
|
+
return info.tvmAddress;
|
|
340
647
|
}
|
|
341
648
|
const jettonMaster = JettonMaster_1.JettonMaster.createFromConfig({
|
|
342
649
|
evmTokenAddress,
|
|
@@ -346,6 +653,48 @@ class TacSdk {
|
|
|
346
653
|
});
|
|
347
654
|
return jettonMaster.address.toString();
|
|
348
655
|
}
|
|
656
|
+
async getTVMNFTAddress(evmNFTAddress, tokenId) {
|
|
657
|
+
(0, Utils_1.validateEVMAddress)(evmNFTAddress);
|
|
658
|
+
let nftCollection;
|
|
659
|
+
const bytecode = await this.TACParams.provider.getCode(evmNFTAddress);
|
|
660
|
+
if (bytecode.includes(ethers_1.ethers.id('getInfo()').slice(2, 10))) {
|
|
661
|
+
const contract = new ethers_1.ethers.Contract(evmNFTAddress, this.TACParams.crossChainLayerNFTABI, this.TACParams.provider);
|
|
662
|
+
const info = await contract.getInfo.staticCall();
|
|
663
|
+
nftCollection = this.TONParams.contractOpener.open(wrappers_1.NFTCollection.createFromAddress(info.tvmAddress));
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
nftCollection = this.TONParams.contractOpener.open(wrappers_1.NFTCollection.createFromConfig({
|
|
667
|
+
ownerAddress: (0, ton_1.address)(this.TONParams.crossChainLayerAddress),
|
|
668
|
+
content: (0, ton_1.beginCell)().endCell(),
|
|
669
|
+
nftItemCode: this.TONParams.nftItemCode,
|
|
670
|
+
originalAddress: evmNFTAddress,
|
|
671
|
+
}, this.TONParams.nftCollectionCode));
|
|
672
|
+
}
|
|
673
|
+
return tokenId == undefined
|
|
674
|
+
? nftCollection.address.toString()
|
|
675
|
+
: (await nftCollection.getNFTAddressByIndex(tokenId)).toString();
|
|
676
|
+
}
|
|
677
|
+
async getEVMNFTAddress(tvmNFTAddress, addressType) {
|
|
678
|
+
(0, Utils_1.validateTVMAddress)(tvmNFTAddress);
|
|
679
|
+
tvmNFTAddress = ton_1.Address.parse(tvmNFTAddress).toString({ bounceable: true });
|
|
680
|
+
if (addressType == Struct_1.NFTAddressType.ITEM) {
|
|
681
|
+
tvmNFTAddress = (await this.getNFTItemData(tvmNFTAddress)).collectionAddress.toString();
|
|
682
|
+
addressType = Struct_1.NFTAddressType.COLLECTION;
|
|
683
|
+
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
684
|
+
}
|
|
685
|
+
const { code: givenNFTCollection } = await this.TONParams.contractOpener.getContractState((0, ton_1.address)(tvmNFTAddress));
|
|
686
|
+
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
687
|
+
if (givenNFTCollection && this.TONParams.nftCollectionCode.equals(ton_1.Cell.fromBoc(givenNFTCollection)[0])) {
|
|
688
|
+
const nftCollection = this.TONParams.contractOpener.open(wrappers_1.NFTCollection.createFromAddress((0, ton_1.address)(tvmNFTAddress)));
|
|
689
|
+
const evmAddress = await nftCollection.getOriginalAddress();
|
|
690
|
+
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
691
|
+
return evmAddress.toString();
|
|
692
|
+
}
|
|
693
|
+
return this.TACParams.tokenUtils.computeAddress(tvmNFTAddress);
|
|
694
|
+
}
|
|
695
|
+
async isContractDeployedOnTVM(address) {
|
|
696
|
+
return (await this.TONParams.contractOpener.getContractState(ton_1.Address.parse(address))).state === 'active';
|
|
697
|
+
}
|
|
349
698
|
async simulateTACMessage(req) {
|
|
350
699
|
for (const endpoint of this.liteSequencerEndpoints) {
|
|
351
700
|
try {
|