@tonappchain/sdk 0.5.7 → 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 +399 -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,7 +208,7 @@ 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)
|
|
@@ -162,19 +216,43 @@ class TacSdk {
|
|
|
162
216
|
.storeAddress(null)
|
|
163
217
|
.storeRef((0, ton_1.beginCell)().endCell())
|
|
164
218
|
.storeRef(this.TONParams.jettonWalletCode)
|
|
165
|
-
.storeStringTail(
|
|
219
|
+
.storeStringTail(evmAddress)
|
|
166
220
|
.endCell());
|
|
167
221
|
if (!expectedMinterAddress.equals(givenMinter.address)) {
|
|
168
222
|
return InternalStruct_1.AssetOpType.JETTON_TRANSFER;
|
|
169
223
|
}
|
|
170
224
|
return InternalStruct_1.AssetOpType.JETTON_BURN;
|
|
171
225
|
}
|
|
172
|
-
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) {
|
|
173
249
|
const uniqueAssetsMap = new Map();
|
|
174
250
|
let crossChainTonAmount = 0n;
|
|
175
251
|
for await (const asset of assets ?? []) {
|
|
176
252
|
if (asset.rawAmount <= 0)
|
|
177
253
|
continue;
|
|
254
|
+
if (asset.type !== Struct_1.AssetType.FT)
|
|
255
|
+
continue;
|
|
178
256
|
if (asset.address) {
|
|
179
257
|
(0, Utils_1.validateTVMAddress)(asset.address);
|
|
180
258
|
uniqueAssetsMap.set(asset.address, (uniqueAssetsMap.get(asset.address) || 0n) + BigInt(asset.rawAmount));
|
|
@@ -186,53 +264,113 @@ class TacSdk {
|
|
|
186
264
|
const jettons = Array.from(uniqueAssetsMap.entries()).map(([address, rawAmount]) => ({
|
|
187
265
|
address,
|
|
188
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,
|
|
189
280
|
}));
|
|
190
281
|
return {
|
|
191
282
|
jettons,
|
|
283
|
+
nfts,
|
|
192
284
|
crossChainTonAmount,
|
|
193
285
|
};
|
|
194
286
|
}
|
|
195
|
-
async
|
|
287
|
+
async generateJettonPayload(jetton, caller, evmData, crossChainTonAmount, forwardFeeTonAmount, feeParams) {
|
|
196
288
|
const opType = await this.getJettonOpType(jetton);
|
|
197
289
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
198
290
|
console.log(`***** Jetton ${jetton.address} requires ${opType} operation`);
|
|
291
|
+
const feeData = this.generateFeeData(feeParams);
|
|
199
292
|
let payload;
|
|
200
293
|
switch (opType) {
|
|
201
294
|
case InternalStruct_1.AssetOpType.JETTON_BURN:
|
|
202
295
|
payload = this.getJettonBurnPayload({
|
|
203
296
|
notificationReceiverAddress: this.TONParams.crossChainLayerAddress,
|
|
204
297
|
...jetton,
|
|
205
|
-
}, evmData, crossChainTonAmount);
|
|
298
|
+
}, evmData, crossChainTonAmount, feeData);
|
|
206
299
|
break;
|
|
207
300
|
case InternalStruct_1.AssetOpType.JETTON_TRANSFER:
|
|
208
|
-
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);
|
|
209
331
|
break;
|
|
210
332
|
}
|
|
211
333
|
return payload;
|
|
212
334
|
}
|
|
213
|
-
async generateCrossChainMessages(caller, evmData, aggregatedData) {
|
|
335
|
+
async generateCrossChainMessages(caller, evmData, aggregatedData, feeParams) {
|
|
214
336
|
let crossChainTonAmount = aggregatedData.crossChainTonAmount;
|
|
215
|
-
|
|
337
|
+
let feeTonAmount = feeParams.protocolFee + feeParams.evmExecutorFee + feeParams.tvmExecutorFee;
|
|
338
|
+
if (aggregatedData.jettons.length == 0 && aggregatedData.nfts.length == 0) {
|
|
216
339
|
return [
|
|
217
340
|
{
|
|
218
341
|
address: this.TONParams.crossChainLayerAddress,
|
|
219
|
-
value: crossChainTonAmount + Consts_1.TRANSACTION_TON_AMOUNT,
|
|
220
|
-
payload: this.getTonTransferPayload(caller, evmData, crossChainTonAmount),
|
|
342
|
+
value: crossChainTonAmount + feeTonAmount + Consts_1.TRANSACTION_TON_AMOUNT,
|
|
343
|
+
payload: this.getTonTransferPayload(caller, evmData, crossChainTonAmount, feeParams),
|
|
221
344
|
},
|
|
222
345
|
];
|
|
223
346
|
}
|
|
224
347
|
const messages = [];
|
|
348
|
+
let currentFeeParams = feeParams;
|
|
225
349
|
for (const jetton of aggregatedData.jettons) {
|
|
226
|
-
const payload = await this.
|
|
350
|
+
const payload = await this.generateJettonPayload(jetton, caller, evmData, crossChainTonAmount, feeTonAmount, currentFeeParams);
|
|
227
351
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
228
352
|
const jettonWalletAddress = await this.getUserJettonWalletAddress(caller, jetton.address);
|
|
229
353
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
230
354
|
messages.push({
|
|
231
355
|
address: jettonWalletAddress,
|
|
232
|
-
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,
|
|
233
369
|
payload,
|
|
234
370
|
});
|
|
235
371
|
crossChainTonAmount = 0n;
|
|
372
|
+
feeTonAmount = 0n;
|
|
373
|
+
currentFeeParams = undefined;
|
|
236
374
|
}
|
|
237
375
|
return messages;
|
|
238
376
|
}
|
|
@@ -261,75 +399,243 @@ class TacSdk {
|
|
|
261
399
|
}
|
|
262
400
|
async convertAssetsToRawFormat(assets) {
|
|
263
401
|
return await Promise.all((assets ?? []).map(async (asset) => {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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;
|
|
271
431
|
}));
|
|
272
432
|
}
|
|
273
|
-
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();
|
|
274
436
|
const tacSimulationBody = {
|
|
275
437
|
tacCallParams: {
|
|
276
438
|
arguments: evmProxyMsg.encodedParameters ?? '0x',
|
|
277
439
|
methodName: (0, Utils_1.formatSolidityMethodName)(evmProxyMsg.methodName),
|
|
278
440
|
target: evmProxyMsg.evmTargetAddress,
|
|
279
441
|
},
|
|
442
|
+
evmValidExecutors: evmValidExecutors,
|
|
280
443
|
extraData: '0x',
|
|
281
444
|
feeAssetAddress: '',
|
|
282
445
|
shardsKey: transactionLinker.shardsKey,
|
|
283
446
|
tonAssets: rawAssets.map((asset) => ({
|
|
284
447
|
amount: asset.rawAmount.toString(),
|
|
285
448
|
tokenAddress: asset.address || '',
|
|
449
|
+
assetType: asset.type,
|
|
286
450
|
})),
|
|
287
451
|
tonCaller: transactionLinker.caller,
|
|
288
452
|
};
|
|
289
453
|
const tacSimulationResult = await this.simulateTACMessage(tacSimulationBody);
|
|
290
454
|
if (!tacSimulationResult.simulationStatus) {
|
|
291
455
|
if (forceSend) {
|
|
292
|
-
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
|
+
};
|
|
293
467
|
}
|
|
294
468
|
throw tacSimulationResult;
|
|
295
469
|
}
|
|
296
|
-
|
|
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 };
|
|
297
485
|
}
|
|
298
|
-
async
|
|
486
|
+
async getTransactionSimulationInfo(evmProxyMsg, sender, assets) {
|
|
299
487
|
const rawAssets = await this.convertAssetsToRawFormat(assets);
|
|
300
|
-
const aggregatedData = await this.
|
|
488
|
+
const aggregatedData = await this.aggregateTokens(rawAssets);
|
|
301
489
|
const transactionLinkerShardCount = aggregatedData.jettons.length == 0 ? 1 : aggregatedData.jettons.length;
|
|
302
|
-
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;
|
|
303
500
|
const transactionLinker = (0, Utils_1.generateTransactionLinker)(caller, transactionLinkerShardCount);
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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;
|
|
307
510
|
}
|
|
308
|
-
|
|
309
|
-
|
|
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);
|
|
310
526
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
311
527
|
const transaction = {
|
|
312
528
|
validUntil: +new Date() + 15 * 60 * 1000,
|
|
313
529
|
messages,
|
|
314
530
|
network: this.network,
|
|
315
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);
|
|
316
537
|
console.log('*****Sending transaction: ', transaction);
|
|
317
538
|
const sendTransactionResult = await sender.sendShardTransaction(transaction, this.delay, this.network, this.TONParams.contractOpener);
|
|
318
539
|
return { sendTransactionResult, ...transactionLinker };
|
|
319
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
|
+
}
|
|
320
625
|
async getEVMTokenAddress(tvmTokenAddress) {
|
|
321
626
|
if (tvmTokenAddress !== this.nativeTONAddress) {
|
|
322
627
|
(0, Utils_1.validateTVMAddress)(tvmTokenAddress);
|
|
628
|
+
tvmTokenAddress = ton_1.Address.parse(tvmTokenAddress).toString({ bounceable: true });
|
|
323
629
|
const { code: givenMinterCodeBOC } = await this.TONParams.contractOpener.getContractState((0, ton_1.address)(tvmTokenAddress));
|
|
324
630
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
325
631
|
if (givenMinterCodeBOC && this.TONParams.jettonMinterCode.equals(ton_1.Cell.fromBoc(givenMinterCodeBOC)[0])) {
|
|
326
632
|
const givenMinter = this.TONParams.contractOpener.open(new JettonMaster_1.JettonMaster((0, ton_1.address)(tvmTokenAddress)));
|
|
327
|
-
const
|
|
633
|
+
const evmAddress = await givenMinter.getEVMAddress();
|
|
328
634
|
await (0, Utils_1.sleep)(this.delay * 1000);
|
|
329
|
-
return
|
|
635
|
+
return evmAddress;
|
|
330
636
|
}
|
|
331
637
|
}
|
|
332
|
-
return
|
|
638
|
+
return this.TACParams.tokenUtils.computeAddress(tvmTokenAddress);
|
|
333
639
|
}
|
|
334
640
|
async getTVMTokenAddress(evmTokenAddress) {
|
|
335
641
|
(0, Utils_1.validateEVMAddress)(evmTokenAddress);
|
|
@@ -337,7 +643,7 @@ class TacSdk {
|
|
|
337
643
|
if (bytecode.includes(ethers_1.ethers.id('getInfo()').slice(2, 10))) {
|
|
338
644
|
const contract = new ethers_1.ethers.Contract(evmTokenAddress, this.TACParams.crossChainLayerTokenABI, this.TACParams.provider);
|
|
339
645
|
const info = await contract.getInfo.staticCall();
|
|
340
|
-
return info.
|
|
646
|
+
return info.tvmAddress;
|
|
341
647
|
}
|
|
342
648
|
const jettonMaster = JettonMaster_1.JettonMaster.createFromConfig({
|
|
343
649
|
evmTokenAddress,
|
|
@@ -347,6 +653,48 @@ class TacSdk {
|
|
|
347
653
|
});
|
|
348
654
|
return jettonMaster.address.toString();
|
|
349
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
|
+
}
|
|
350
698
|
async simulateTACMessage(req) {
|
|
351
699
|
for (const endpoint of this.liteSequencerEndpoints) {
|
|
352
700
|
try {
|