@evaafi/sdk 0.3.1 → 0.4.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.
@@ -1,387 +1,409 @@
1
- import {
2
- Address,
3
- beginCell,
4
- Cell,
5
- Contract,
6
- ContractProvider,
7
- OpenedContract,
8
- Sender,
9
- SendMode,
10
- storeStateInit,
11
- } from '@ton/core';
12
- import {
13
- EVAA_MASTER_MAINNET,
14
- EVAA_MASTER_TESTNET,
15
- FEES,
16
- LENDING_CODE,
17
- MAINNET_VERSION,
18
- OPCODES,
19
- TESTNET_VERSION,
20
- } from '../constants';
21
- import { Maybe } from '@ton/core/dist/utils/maybe';
22
- import { EvaaUser } from './UserContract';
23
- import { parseMasterData } from '../api/parser';
24
- import { MasterData } from '../types/Master';
25
- import { JettonWallet } from './JettonWallet';
26
- import { getUserJettonWallet } from '../utils/userJettonWallet';
27
-
28
- /**
29
- * Parameters for the Evaa contract
30
- * @property testnet - true for testnet, false for mainnet
31
- * @property debug - true to enable debug mode (optional)
32
- */
33
- export type EvaaParameters = {
34
- testnet: boolean;
35
- debug?: boolean;
36
- };
37
-
38
- /**
39
- * Parameters for the Jetton message
40
- * @property responseAddress - address to send excesses
41
- * @property forwardAmount - amount to forward to the destination address
42
- */
43
- export type JettonMessageParameters = {
44
- responseAddress?: Address;
45
- forwardAmount?: bigint;
46
- };
47
-
48
- /**
49
- * Base parameters for supply
50
- * @property queryID - unique query ID
51
- * @property includeUserCode - true to include user code for update (needed when user contract code version is outdated)
52
- * @property amount - amount to supply
53
- * @property userAddress - user address
54
- * @property assetID - asset ID
55
- */
56
- export type SupplyBaseParameters = {
57
- queryID: bigint;
58
- includeUserCode: boolean;
59
- amount: bigint;
60
- userAddress: Address;
61
- assetID: bigint;
62
- };
63
- /**
64
- * Parameters for the TON supply message
65
- * @property type - 'ton'
66
- */
67
- export type TonSupplyParameters = SupplyBaseParameters & {
68
- type: 'ton';
69
- };
70
- /**
71
- * Parameters for the jetton supply message
72
- * @property type - 'jetton'
73
- */
74
- export type JettonSupplyParameters = SupplyBaseParameters &
75
- JettonMessageParameters & {
76
- type: 'jetton';
77
- };
78
-
79
- /**
80
- * Parameters for the withdraw message
81
- * @property queryID - unique query ID
82
- * @property assetID - asset ID
83
- * @property amount - amount to withdraw
84
- * @property userAddress - user address
85
- * @property includeUserCode - true to include user code for update (needed when user contract code version is outdated)
86
- * @property priceData - price data cell. Can be obtained from the getPrices function
87
- */
88
- export type WithdrawParameters = {
89
- queryID: bigint;
90
- assetID: bigint;
91
- amount: bigint;
92
- userAddress: Address;
93
- includeUserCode: boolean;
94
- priceData: Cell;
95
- };
96
-
97
- /**
98
- * Base data for liquidation. Can be obtained from the user contract liquidationParameters getter
99
- * @property borrowerAddress - borrower address (user address that is being liquidated)
100
- * @property loanAsset - loan asset ID
101
- * @property collateralAsset - collateral asset ID
102
- * @property minCollateralAmount - minimal amount to receive from the liquidation
103
- * @property liquidationAmount - amount to liquidate
104
- * @property tonLiquidation - true if the loan asset is TON
105
- */
106
- export type LiquidationBaseData = {
107
- borrowerAddress: Address;
108
- loanAsset: bigint;
109
- collateralAsset: bigint;
110
- minCollateralAmount: bigint;
111
- liquidationAmount: bigint;
112
- tonLiquidation: boolean;
113
- };
114
-
115
- /**
116
- * Base parameters for liquidation
117
- * @property queryID - unique query ID
118
- * @property liquidatorAddress - liquidator address, where and collateral will be sent
119
- * @property includeUserCode - true to include user code for update (needed when user contract code version is outdated)
120
- * @property priceData - price data cell. Can be obtained from the getPrices function
121
- */
122
- export type LiquidationBaseParameters = LiquidationBaseData & {
123
- queryID: bigint;
124
- liquidatorAddress: Address;
125
- includeUserCode: boolean;
126
- priceData: Cell;
127
- };
128
-
129
- /**
130
- * Parameters for the TON liquidation message
131
- * @property type - 'ton'
132
- */
133
- export type TonLiquidationParameters = LiquidationBaseParameters & {
134
- type: 'ton';
135
- };
136
- /**
137
- * Parameters for the jetton liquidation message
138
- * @property type - 'jetton'
139
- */
140
- export type JettonLiquidationParameters = LiquidationBaseParameters &
141
- JettonMessageParameters & {
142
- type: 'jetton';
143
- };
144
-
145
- /**
146
- * Evaa master contract wrapper
147
- */
148
- export class Evaa implements Contract {
149
- readonly address: Address = EVAA_MASTER_MAINNET;
150
- readonly network: 'mainnet' | 'testnet' = 'mainnet';
151
- private readonly debug?: boolean;
152
- private _data?: MasterData;
153
- private lastSync = 0;
154
-
155
- /**
156
- * Create Evaa contract wrapper
157
- * @param parameters Evaa contract parameters
158
- */
159
- constructor(parameters?: EvaaParameters) {
160
- if (parameters?.testnet) {
161
- this.network = 'testnet';
162
- this.address = EVAA_MASTER_TESTNET;
163
- }
164
- this.debug = parameters?.debug;
165
- }
166
-
167
- /**
168
- * Create supply message
169
- * @returns supply message as a cell
170
- */
171
- createSupplyMessage(parameters: TonSupplyParameters | JettonSupplyParameters): Cell {
172
- if (parameters.type === 'jetton') {
173
- return beginCell()
174
- .storeUint(OPCODES.JETTON_TRANSFER, 32)
175
- .storeUint(parameters.queryID, 64)
176
- .storeCoins(parameters.amount)
177
- .storeAddress(this.address)
178
- .storeAddress(parameters.responseAddress ?? parameters.userAddress)
179
- .storeBit(0)
180
- .storeCoins(parameters.forwardAmount ?? FEES.SUPPLY_JETTON_FWD)
181
- .storeBit(1)
182
- .storeRef(
183
- beginCell()
184
- .storeUint(OPCODES.SUPPLY, 32)
185
- .storeInt(parameters.includeUserCode ? -1 : 0, 2)
186
- .storeAddress(parameters.userAddress)
187
- .endCell(),
188
- )
189
- .endCell();
190
- } else {
191
- return beginCell()
192
- .storeUint(OPCODES.SUPPLY, 32)
193
- .storeUint(parameters.queryID, 64)
194
- .storeInt(parameters.includeUserCode ? -1 : 0, 2)
195
- .storeUint(parameters.amount, 64)
196
- .storeAddress(parameters.userAddress)
197
- .endCell();
198
- }
199
- }
200
-
201
- /**
202
- * Create withdraw message
203
- * @returns withdraw message as a cell
204
- */
205
- createWithdrawMessage(parameters: WithdrawParameters): Cell {
206
- return beginCell()
207
- .storeUint(OPCODES.WITHDRAW, 32)
208
- .storeUint(parameters.queryID, 64)
209
- .storeUint(parameters.assetID, 256)
210
- .storeUint(parameters.amount, 64)
211
- .storeAddress(parameters.userAddress)
212
- .storeInt(parameters.includeUserCode ? -1 : 0, 2)
213
- .storeRef(parameters.priceData)
214
- .endCell();
215
- }
216
-
217
- /**
218
- * Create liquidation message
219
- * @returns liquidation message as a cell
220
- */
221
- createLiquidationMessage(parameters: TonLiquidationParameters | JettonLiquidationParameters): Cell {
222
- if (parameters.type === 'jetton') {
223
- return beginCell()
224
- .storeUint(OPCODES.JETTON_TRANSFER, 32)
225
- .storeUint(parameters.queryID, 64)
226
- .storeCoins(parameters.liquidationAmount)
227
- .storeAddress(this.address)
228
- .storeAddress(parameters.responseAddress ?? parameters.liquidatorAddress)
229
- .storeBit(0)
230
- .storeCoins(parameters.forwardAmount ?? FEES.LIQUIDATION_JETTON_FWD)
231
- .storeBit(1)
232
- .storeRef(
233
- beginCell()
234
- .storeUint(OPCODES.LIQUIDATE, 32)
235
- .storeAddress(parameters.borrowerAddress)
236
- .storeAddress(parameters.liquidatorAddress)
237
- .storeUint(parameters.collateralAsset, 256)
238
- .storeUint(parameters.minCollateralAmount, 64)
239
- .storeInt(parameters.includeUserCode ? -1 : 0, 2)
240
- // do not need liquidationAmount in case of jetton liquidation because
241
- // the exact amount of transferred jettons for liquidation is known
242
- .storeUint(0, 64)
243
- .storeRef(parameters.priceData)
244
- .endCell(),
245
- )
246
- .endCell();
247
- } else {
248
- return beginCell()
249
- .storeUint(OPCODES.LIQUIDATE, 32)
250
- .storeUint(parameters.queryID, 64)
251
- .storeAddress(parameters.borrowerAddress)
252
- .storeAddress(parameters.liquidatorAddress)
253
- .storeUint(parameters.collateralAsset, 256)
254
- .storeUint(parameters.minCollateralAmount, 64)
255
- .storeInt(parameters.includeUserCode ? -1 : 0, 2)
256
- .storeUint(parameters.liquidationAmount, 64)
257
- .storeRef(parameters.priceData)
258
- .endCell();
259
- }
260
- }
261
-
262
- /**
263
- * Calculate user contract address
264
- * @param userAddress
265
- * @returns user contract address
266
- */
267
- calculateUserSCAddr(userAddress: Address): Address {
268
- const lendingData = beginCell()
269
- .storeAddress(this.address)
270
- .storeAddress(userAddress)
271
- .storeUint(0, 8)
272
- .storeBit(0)
273
- .endCell();
274
-
275
- const stateInit = beginCell()
276
- .store(
277
- storeStateInit({
278
- code: LENDING_CODE,
279
- data: lendingData,
280
- }),
281
- )
282
- .endCell();
283
- return new Address(0, stateInit.hash());
284
- }
285
-
286
- /**
287
- * Open user contract wrapper
288
- * @param userAddress
289
- * @returns user contract
290
- */
291
- openUserContract(userAddress: Address): EvaaUser {
292
- return EvaaUser.createFromAddress(this.calculateUserSCAddr(userAddress));
293
- }
294
-
295
- getOpenedUserContract(provider: ContractProvider, userAddress: Address): OpenedContract<EvaaUser> {
296
- return provider.open(this.openUserContract(userAddress));
297
- }
298
-
299
- /**
300
- * Get master contract data
301
- */
302
- get data(): Maybe<MasterData> {
303
- return this._data;
304
- }
305
-
306
- async sendSupply(
307
- provider: ContractProvider,
308
- via: Sender,
309
- value: bigint,
310
- parameters: TonSupplyParameters | JettonSupplyParameters,
311
- ) {
312
- const message = this.createSupplyMessage(parameters);
313
-
314
- if (parameters.type === 'jetton') {
315
- if (!via.address) {
316
- throw Error('Via address is required for jetton supply');
317
- }
318
- const jettonWallet = provider.open(
319
- JettonWallet.createFromAddress(getUserJettonWallet(via.address, parameters.assetID, this.network)),
320
- );
321
- await jettonWallet.sendTransfer(via, value, message);
322
- } else {
323
- await provider.internal(via, {
324
- value,
325
- sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
326
- body: message,
327
- });
328
- }
329
- }
330
-
331
- async sendWithdraw(provider: ContractProvider, via: Sender, value: bigint, parameters: WithdrawParameters) {
332
- const message = this.createWithdrawMessage(parameters);
333
- await provider.internal(via, {
334
- value,
335
- sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
336
- body: message,
337
- });
338
- }
339
-
340
- async sendLiquidation(
341
- provider: ContractProvider,
342
- via: Sender,
343
- value: bigint,
344
- parameters: TonLiquidationParameters | JettonLiquidationParameters,
345
- ) {
346
- const message = this.createLiquidationMessage(parameters);
347
-
348
- if (parameters.type === 'jetton') {
349
- if (!via.address) {
350
- throw Error('Via address is required for jetton liquidation');
351
- }
352
- const jettonWallet = provider.open(
353
- JettonWallet.createFromAddress(getUserJettonWallet(via.address, parameters.loanAsset, this.network)),
354
- );
355
- await jettonWallet.sendTransfer(via, value, message);
356
- } else {
357
- await provider.internal(via, {
358
- value,
359
- sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
360
- body: message,
361
- });
362
- }
363
- }
364
-
365
- /**
366
- * Sync master contract data
367
- */
368
- async getSync(provider: ContractProvider) {
369
- const state = (await provider.getState()).state;
370
- if (state.type === 'active') {
371
- this._data = parseMasterData(state.data!.toString('base64url'));
372
- if (this.network === 'testnet' && this._data.upgradeConfig.masterCodeVersion !== TESTNET_VERSION) {
373
- throw Error(
374
- `Outdated SDK version. It supports only master code version ${TESTNET_VERSION} on testnet, but the current master code version is ${this._data.upgradeConfig.masterCodeVersion}`,
375
- );
376
- }
377
- if (this.network === 'mainnet' && this._data.upgradeConfig.masterCodeVersion !== MAINNET_VERSION) {
378
- throw Error(
379
- `Outdated SDK version. It supports only master code version ${MAINNET_VERSION} on mainnet, but the current master code version is ${this._data.upgradeConfig.masterCodeVersion}`,
380
- );
381
- }
382
- this.lastSync = Math.floor(Date.now() / 1000);
383
- } else {
384
- throw Error('Master contract is not active');
385
- }
386
- }
387
- }
1
+ import {
2
+ Address,
3
+ beginCell,
4
+ Cell,
5
+ Contract,
6
+ ContractProvider,
7
+ OpenedContract,
8
+ Sender,
9
+ SendMode,
10
+ storeStateInit,
11
+ } from '@ton/core';
12
+ import {
13
+ EVAA_MASTER_MAINNET,
14
+ EVAA_MASTER_TESTNET,
15
+ FEES,
16
+ LENDING_CODE,
17
+ MAINNET_VERSION,
18
+ OPCODES,
19
+ TESTNET_VERSION,
20
+ } from '../constants';
21
+ import { Maybe } from '@ton/core/dist/utils/maybe';
22
+ import { EvaaUser } from './UserContract';
23
+ import { parseMasterData } from '../api/parser';
24
+ import { MasterData } from '../types/Master';
25
+ import { JettonWallet } from './JettonWallet';
26
+ import { getUserJettonWallet } from '../utils/userJettonWallet';
27
+
28
+ /**
29
+ * Parameters for the Evaa contract
30
+ * @property testnet - true for testnet, false for mainnet
31
+ * @property debug - true to enable debug mode (optional)
32
+ */
33
+ export type EvaaParameters = {
34
+ testnet: boolean;
35
+ debug?: boolean;
36
+ };
37
+
38
+ /**
39
+ * Parameters for the Jetton message
40
+ * @property responseAddress - address to send excesses
41
+ * @property forwardAmount - amount to forward to the destination address
42
+ */
43
+ export type JettonMessageParameters = {
44
+ responseAddress?: Address;
45
+ forwardAmount?: bigint;
46
+ };
47
+
48
+ /**
49
+ * Base parameters for supply
50
+ * @property queryID - unique query ID
51
+ * @property includeUserCode - true to include user code for update (needed when user contract code version is outdated)
52
+ * @property amount - amount to supply
53
+ * @property userAddress - user address
54
+ * @property assetID - asset ID
55
+ */
56
+ export type SupplyBaseParameters = {
57
+ queryID: bigint;
58
+ includeUserCode: boolean;
59
+ amount: bigint;
60
+ userAddress: Address;
61
+ assetID: bigint;
62
+ };
63
+ /**
64
+ * Parameters for the TON supply message
65
+ * @property type - 'ton'
66
+ */
67
+ export type TonSupplyParameters = SupplyBaseParameters & {
68
+ type: 'ton';
69
+ };
70
+ /**
71
+ * Parameters for the jetton supply message
72
+ * @property type - 'jetton'
73
+ */
74
+ export type JettonSupplyParameters = SupplyBaseParameters &
75
+ JettonMessageParameters & {
76
+ type: 'jetton';
77
+ };
78
+
79
+ /**
80
+ * Parameters for the withdraw message
81
+ * @property queryID - unique query ID
82
+ * @property assetID - asset ID
83
+ * @property amount - amount to withdraw
84
+ * @property userAddress - user address
85
+ * @property includeUserCode - true to include user code for update (needed when user contract code version is outdated)
86
+ * @property priceData - price data cell. Can be obtained from the getPrices function
87
+ */
88
+ export type WithdrawParameters = {
89
+ queryID: bigint;
90
+ assetID: bigint;
91
+ amount: bigint;
92
+ userAddress: Address;
93
+ includeUserCode: boolean;
94
+ priceData: Cell;
95
+ };
96
+
97
+ /**
98
+ * Base data for liquidation. Can be obtained from the user contract liquidationParameters getter
99
+ * @property borrowerAddress - borrower address (user address that is being liquidated)
100
+ * @property loanAsset - loan asset ID
101
+ * @property collateralAsset - collateral asset ID
102
+ * @property minCollateralAmount - minimal amount to receive from the liquidation
103
+ * @property liquidationAmount - amount to liquidate
104
+ * @property tonLiquidation - true if the loan asset is TON
105
+ */
106
+ export type LiquidationBaseData = {
107
+ borrowerAddress: Address;
108
+ loanAsset: bigint;
109
+ collateralAsset: bigint;
110
+ minCollateralAmount: bigint;
111
+ liquidationAmount: bigint;
112
+ tonLiquidation: boolean;
113
+ };
114
+
115
+ /**
116
+ * Base parameters for liquidation
117
+ * @property queryID - unique query ID
118
+ * @property liquidatorAddress - liquidator address, where and collateral will be sent
119
+ * @property includeUserCode - true to include user code for update (needed when user contract code version is outdated)
120
+ * @property priceData - price data cell. Can be obtained from the getPrices function
121
+ */
122
+ export type LiquidationBaseParameters = LiquidationBaseData & {
123
+ queryID: bigint;
124
+ liquidatorAddress: Address;
125
+ includeUserCode: boolean;
126
+ priceData: Cell;
127
+ };
128
+
129
+ /**
130
+ * Parameters for the TON liquidation message
131
+ * @property type - 'ton'
132
+ */
133
+ export type TonLiquidationParameters = LiquidationBaseParameters & {
134
+ type: 'ton';
135
+ };
136
+ /**
137
+ * Parameters for the jetton liquidation message
138
+ * @property type - 'jetton'
139
+ */
140
+ export type JettonLiquidationParameters = LiquidationBaseParameters &
141
+ JettonMessageParameters & {
142
+ type: 'jetton';
143
+ };
144
+
145
+ /**
146
+ * Evaa master contract wrapper
147
+ */
148
+ export class Evaa implements Contract {
149
+ readonly address: Address = EVAA_MASTER_MAINNET;
150
+ readonly network: 'mainnet' | 'testnet' = 'mainnet';
151
+ private readonly debug?: boolean;
152
+ private _data?: MasterData;
153
+ private lastSync = 0;
154
+
155
+ /**
156
+ * Create Evaa contract wrapper
157
+ * @param parameters Evaa contract parameters
158
+ */
159
+ constructor(parameters?: EvaaParameters) {
160
+ if (parameters?.testnet) {
161
+ this.network = 'testnet';
162
+ this.address = EVAA_MASTER_TESTNET;
163
+ }
164
+ this.debug = parameters?.debug;
165
+ }
166
+
167
+ /**
168
+ * Create supply message
169
+ * @returns supply message as a cell
170
+ */
171
+ createSupplyMessage(parameters: TonSupplyParameters | JettonSupplyParameters): Cell {
172
+ if (parameters.type === 'jetton') {
173
+ return beginCell()
174
+ .storeUint(OPCODES.JETTON_TRANSFER, 32)
175
+ .storeUint(parameters.queryID, 64)
176
+ .storeCoins(parameters.amount)
177
+ .storeAddress(this.address)
178
+ .storeAddress(parameters.responseAddress ?? parameters.userAddress)
179
+ .storeBit(0)
180
+ .storeCoins(parameters.forwardAmount ?? FEES.SUPPLY_JETTON_FWD)
181
+ .storeBit(1)
182
+ .storeRef(
183
+ beginCell()
184
+ .storeUint(OPCODES.SUPPLY, 32)
185
+ .storeInt(parameters.includeUserCode ? -1 : 0, 2)
186
+ .storeAddress(parameters.userAddress)
187
+ .endCell(),
188
+ )
189
+ .endCell();
190
+ } else {
191
+ return beginCell()
192
+ .storeUint(OPCODES.SUPPLY, 32)
193
+ .storeUint(parameters.queryID, 64)
194
+ .storeInt(parameters.includeUserCode ? -1 : 0, 2)
195
+ .storeUint(parameters.amount, 64)
196
+ .storeAddress(parameters.userAddress)
197
+ .endCell();
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Create withdraw message
203
+ * @returns withdraw message as a cell
204
+ */
205
+ createWithdrawMessage(parameters: WithdrawParameters): Cell {
206
+ return beginCell()
207
+ .storeUint(OPCODES.WITHDRAW, 32)
208
+ .storeUint(parameters.queryID, 64)
209
+ .storeUint(parameters.assetID, 256)
210
+ .storeUint(parameters.amount, 64)
211
+ .storeAddress(parameters.userAddress)
212
+ .storeInt(parameters.includeUserCode ? -1 : 0, 2)
213
+ .storeRef(parameters.priceData)
214
+ .endCell();
215
+ }
216
+
217
+ /**
218
+ * Create liquidation message
219
+ * @returns liquidation message as a cell
220
+ */
221
+ createLiquidationMessage(parameters: TonLiquidationParameters | JettonLiquidationParameters): Cell {
222
+ if (parameters.type === 'jetton') {
223
+ return beginCell()
224
+ .storeUint(OPCODES.JETTON_TRANSFER, 32)
225
+ .storeUint(parameters.queryID, 64)
226
+ .storeCoins(parameters.liquidationAmount)
227
+ .storeAddress(this.address)
228
+ .storeAddress(parameters.responseAddress ?? parameters.liquidatorAddress)
229
+ .storeBit(0)
230
+ .storeCoins(parameters.forwardAmount ?? FEES.LIQUIDATION_JETTON_FWD)
231
+ .storeBit(1)
232
+ .storeRef(
233
+ beginCell()
234
+ .storeUint(OPCODES.LIQUIDATE, 32)
235
+ .storeAddress(parameters.borrowerAddress)
236
+ .storeAddress(parameters.liquidatorAddress)
237
+ .storeUint(parameters.collateralAsset, 256)
238
+ .storeUint(parameters.minCollateralAmount, 64)
239
+ .storeInt(parameters.includeUserCode ? -1 : 0, 2)
240
+ // do not need liquidationAmount in case of jetton liquidation because
241
+ // the exact amount of transferred jettons for liquidation is known
242
+ .storeUint(0, 64)
243
+ .storeRef(parameters.priceData)
244
+ .endCell(),
245
+ )
246
+ .endCell();
247
+ } else {
248
+ return beginCell()
249
+ .storeUint(OPCODES.LIQUIDATE, 32)
250
+ .storeUint(parameters.queryID, 64)
251
+ .storeAddress(parameters.borrowerAddress)
252
+ .storeAddress(parameters.liquidatorAddress)
253
+ .storeUint(parameters.collateralAsset, 256)
254
+ .storeUint(parameters.minCollateralAmount, 64)
255
+ .storeInt(parameters.includeUserCode ? -1 : 0, 2)
256
+ .storeUint(parameters.liquidationAmount, 64)
257
+ .storeRef(parameters.priceData)
258
+ .endCell();
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Calculate user contract address
264
+ * @param userAddress
265
+ * @returns user contract address
266
+ */
267
+ calculateUserSCAddr(userAddress: Address): Address {
268
+ const lendingData = beginCell()
269
+ .storeAddress(this.address)
270
+ .storeAddress(userAddress)
271
+ .storeUint(0, 8)
272
+ .storeBit(0)
273
+ .endCell();
274
+
275
+ const stateInit = beginCell()
276
+ .store(
277
+ storeStateInit({
278
+ code: LENDING_CODE,
279
+ data: lendingData,
280
+ }),
281
+ )
282
+ .endCell();
283
+ return new Address(0, stateInit.hash());
284
+ }
285
+
286
+ /**
287
+ * Open user contract wrapper
288
+ * @param userAddress
289
+ * @returns user contract
290
+ */
291
+ openUserContract(userAddress: Address): EvaaUser {
292
+ return EvaaUser.createFromAddress(this.calculateUserSCAddr(userAddress), this.network === 'testnet');
293
+ }
294
+
295
+ getOpenedUserContract(provider: ContractProvider, userAddress: Address): OpenedContract<EvaaUser> {
296
+ return provider.open(this.openUserContract(userAddress));
297
+ }
298
+
299
+ /**
300
+ * Get master contract data
301
+ */
302
+ get data(): Maybe<MasterData> {
303
+ return this._data;
304
+ }
305
+
306
+ async sendSupply(
307
+ provider: ContractProvider,
308
+ via: Sender,
309
+ value: bigint,
310
+ parameters: TonSupplyParameters | JettonSupplyParameters,
311
+ ) {
312
+ const message = this.createSupplyMessage(parameters);
313
+
314
+ if (parameters.type === 'jetton') {
315
+ if (!via.address) {
316
+ throw Error('Via address is required for jetton supply');
317
+ }
318
+ const jettonWallet = provider.open(
319
+ JettonWallet.createFromAddress(getUserJettonWallet(via.address, parameters.assetID, this.network)),
320
+ );
321
+ await jettonWallet.sendTransfer(via, value, message);
322
+ } else {
323
+ await provider.internal(via, {
324
+ value,
325
+ sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
326
+ body: message,
327
+ });
328
+ }
329
+ }
330
+
331
+ async sendWithdraw(provider: ContractProvider, via: Sender, value: bigint, parameters: WithdrawParameters) {
332
+ const message = this.createWithdrawMessage(parameters);
333
+ await provider.internal(via, {
334
+ value,
335
+ sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
336
+ body: message,
337
+ });
338
+ }
339
+
340
+ async sendLiquidation(
341
+ provider: ContractProvider,
342
+ via: Sender,
343
+ value: bigint,
344
+ parameters: TonLiquidationParameters | JettonLiquidationParameters,
345
+ ) {
346
+ const message = this.createLiquidationMessage(parameters);
347
+
348
+ if (parameters.type === 'jetton') {
349
+ if (!via.address) {
350
+ throw Error('Via address is required for jetton liquidation');
351
+ }
352
+ const jettonWallet = provider.open(
353
+ JettonWallet.createFromAddress(getUserJettonWallet(via.address, parameters.loanAsset, this.network)),
354
+ );
355
+ await jettonWallet.sendTransfer(via, value, message);
356
+ } else {
357
+ await provider.internal(via, {
358
+ value,
359
+ sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
360
+ body: message,
361
+ });
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Open user contract wrapper
367
+ * @param forwardPayload - payload that will be forwarded to the address which requested the data
368
+ */
369
+ async sendOnchainGetter(
370
+ provider: ContractProvider,
371
+ via: Sender,
372
+ value: bigint,
373
+ queryID: bigint,
374
+ forwardPayload: Cell,
375
+ ) {
376
+ await provider.internal(via, {
377
+ value,
378
+ sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
379
+ body: beginCell()
380
+ .storeUint(OPCODES.ONCHAIN_GETTER, 32)
381
+ .storeUint(queryID, 64)
382
+ .storeRef(forwardPayload)
383
+ .endCell(),
384
+ });
385
+ }
386
+
387
+ /**
388
+ * Sync master contract data
389
+ */
390
+ async getSync(provider: ContractProvider) {
391
+ const state = (await provider.getState()).state;
392
+ if (state.type === 'active') {
393
+ this._data = parseMasterData(state.data!.toString('base64url'), this.network === 'testnet');
394
+ if (this.network === 'testnet' && this._data.upgradeConfig.masterCodeVersion !== TESTNET_VERSION) {
395
+ throw Error(
396
+ `Outdated SDK version. It supports only master code version ${TESTNET_VERSION} on testnet, but the current master code version is ${this._data.upgradeConfig.masterCodeVersion}`,
397
+ );
398
+ }
399
+ if (this.network === 'mainnet' && this._data.upgradeConfig.masterCodeVersion !== MAINNET_VERSION) {
400
+ throw Error(
401
+ `Outdated SDK version. It supports only master code version ${MAINNET_VERSION} on mainnet, but the current master code version is ${this._data.upgradeConfig.masterCodeVersion}`,
402
+ );
403
+ }
404
+ this.lastSync = Math.floor(Date.now() / 1000);
405
+ } else {
406
+ throw Error('Master contract is not active');
407
+ }
408
+ }
409
+ }