@affluent-org/sdk 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/Account.compiled.json +1 -0
- package/dist/build/Receipt.compiled.json +1 -0
- package/dist/build/WTONWallet.compiled.json +1 -0
- package/dist/common/cache.d.ts +16 -0
- package/dist/common/cache.js +96 -0
- package/dist/common/service.d.ts +20 -0
- package/dist/common/service.js +69 -0
- package/dist/common/type.d.ts +14 -0
- package/dist/common/type.js +2 -0
- package/dist/common/unknown-contract.d.ts +14 -0
- package/dist/common/unknown-contract.js +18 -0
- package/dist/common/versions.d.ts +14 -0
- package/dist/common/versions.js +22 -0
- package/dist/constants/pool.d.ts +1 -0
- package/dist/constants/pool.js +2 -0
- package/dist/contracts/_mock/simple-oracle.d.ts +34 -0
- package/dist/contracts/_mock/simple-oracle.js +73 -0
- package/dist/contracts/vault/share-vault/type.d.ts +30 -0
- package/dist/contracts/vault/share-vault/type.js +2 -0
- package/dist/contracts/vault/strategy-vault/utils.d.ts +6 -0
- package/dist/contracts/vault/strategy-vault/utils.js +32 -0
- package/dist/factorial.d.ts +14 -0
- package/dist/factorial.js +20 -0
- package/dist/farm.d.ts +92 -0
- package/dist/farm.js +209 -0
- package/dist/monitor.d.ts +57 -0
- package/dist/monitor.js +527 -0
- package/dist/monitorCacheV1.d.ts +52 -0
- package/dist/monitorCacheV1.js +504 -0
- package/dist/oracle/oracle-v2.d.ts +39 -0
- package/dist/oracle/oracle-v2.js +151 -0
- package/dist/oracle/oracle.d.ts +107 -0
- package/dist/oracle/oracle.js +392 -0
- package/dist/periphery.d.ts +259 -0
- package/dist/periphery.js +1087 -0
- package/dist/pool.d.ts +216 -0
- package/dist/pool.js +2298 -0
- package/dist/poolCacheV1.d.ts +139 -0
- package/dist/poolCacheV1.js +1841 -0
- package/dist/rfq-auction.d.ts +75 -0
- package/dist/rfq-auction.js +220 -0
- package/dist/rfq-batch.d.ts +112 -0
- package/dist/rfq-batch.js +284 -0
- package/dist/services/share-vault/computation.d.ts +14 -17
- package/dist/services/share-vault/computation.js +39 -0
- package/dist/services/share-vault/index.js +6 -3
- package/dist/services/share-vault/query.d.ts +38 -8
- package/dist/services/share-vault/query.js +20 -27
- package/dist/services/share-vault/type.d.ts +19 -0
- package/dist/services/share-vault/type.js +2 -0
- package/dist/services/share-vault/user/index.js +3 -1
- package/dist/services/strategy-vault/computation.d.ts +1 -0
- package/dist/services/strategy-vault/computation.js +15 -0
- package/dist/services/strategy-vault/query.d.ts +147 -0
- package/dist/services/strategy-vault/query.js +67 -0
- package/dist/services/strategy-vault/type.d.ts +2 -0
- package/dist/services/strategy-vault/type.js +2 -0
- package/dist/share-vault.d.ts +91 -0
- package/dist/share-vault.js +747 -0
- package/dist/stonfi.d.ts +18 -0
- package/dist/stonfi.js +76 -0
- package/dist/strategy_vault/base.d.ts +399 -0
- package/dist/strategy_vault/base.js +1199 -0
- package/dist/strategy_vault/index.d.ts +3 -0
- package/dist/strategy_vault/index.js +7 -0
- package/dist/strategy_vault/steps.d.ts +49 -0
- package/dist/strategy_vault/steps.js +170 -0
- package/dist/types/action.d.ts +55 -0
- package/dist/types/action.js +2 -0
- package/dist/types/messages.d.ts +7 -0
- package/dist/types/messages.js +2 -0
- package/dist/types/params.d.ts +19 -0
- package/dist/types/params.js +2 -0
- package/dist/types/pool.d.ts +83 -0
- package/dist/types/pool.js +2 -0
- package/dist/types/transaction.d.ts +40 -0
- package/dist/types/transaction.js +2 -0
- package/dist/utils/_parse_temp/JumpIRM.d.ts +37 -0
- package/dist/utils/_parse_temp/JumpIRM.js +71 -0
- package/dist/utils/_parse_temp/Pool.d.ts +559 -0
- package/dist/utils/_parse_temp/Pool.js +1023 -0
- package/dist/utils/_parse_temp/ShareVault.d.ts +264 -0
- package/dist/utils/_parse_temp/ShareVault.js +479 -0
- package/dist/utils/_parse_temp/StrategyVault.d.ts +729 -0
- package/dist/utils/_parse_temp/StrategyVault.js +1865 -0
- package/dist/utils/_parse_temp/parseMsgBody.d.ts +13 -0
- package/dist/utils/_parse_temp/parseMsgBody.js +313 -0
- package/dist/utils/assert.d.ts +1 -0
- package/dist/utils/assert.js +9 -0
- package/dist/utils/client-for-parameter.d.ts +12 -0
- package/dist/utils/client-for-parameter.js +97 -0
- package/dist/utils/oracle/index.d.ts +4 -0
- package/dist/utils/oracle/index.js +19 -0
- package/dist/utils/oracle/redstone/helper.d.ts +22 -0
- package/dist/utils/oracle/redstone/helper.js +186 -0
- package/dist/utils/tracer.d.ts +13 -0
- package/dist/utils/tracer.js +137 -0
- package/dist/utils/tracker/index.d.ts +5 -0
- package/dist/utils/tracker/index.js +118 -0
- package/dist/utils/tracker/query-id-generactor.d.ts +2 -0
- package/dist/utils/tracker/query-id-generactor.js +12 -0
- package/dist/utils/tracker/type.d.ts +34 -0
- package/dist/utils/tracker/type.js +2 -0
- package/package.json +1 -1
package/dist/pool.js
ADDED
|
@@ -0,0 +1,2298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PoolV1 = void 0;
|
|
4
|
+
const ton_1 = require("@ton/ton");
|
|
5
|
+
const pool_1 = require("./contracts/core/pool");
|
|
6
|
+
const type_1 = require("./contracts/oracle/redstone-onchain-oracle/type");
|
|
7
|
+
const account_1 = require("./contracts/core/account");
|
|
8
|
+
const jetton_minter_1 = require("./contracts/jetton/jetton-minter");
|
|
9
|
+
const jetton_wallet_1 = require("./contracts/jetton/jetton-wallet");
|
|
10
|
+
const tracker_1 = require("./utils/tracker");
|
|
11
|
+
const query_id_generactor_1 = require("./utils/tracker/query-id-generactor");
|
|
12
|
+
const parser_1 = require("./utils/parser");
|
|
13
|
+
const jetton_wallet_2 = require("./contracts/wton/jetton-wallet");
|
|
14
|
+
const redstone_onchain_oracle_1 = require("./contracts/oracle/redstone-onchain-oracle");
|
|
15
|
+
const redstoneHelper_1 = require("./utils/oracle/redstone/redstoneHelper");
|
|
16
|
+
const jetton_minter_2 = require("./contracts/wton/jetton-minter");
|
|
17
|
+
const strategy_vault_1 = require("./contracts/vault/strategy-vault");
|
|
18
|
+
const share_vault_1 = require("./contracts/vault/share-vault");
|
|
19
|
+
const service_1 = require("./common/service");
|
|
20
|
+
const readonlyCachedRedstone_1 = require("./utils/oracle/redstone/readonlyCachedRedstone");
|
|
21
|
+
const unknown_contract_1 = require("./common/unknown-contract");
|
|
22
|
+
const utils_1 = require("./utils/utils");
|
|
23
|
+
const risk_calculator_1 = require("./utils/risk_calculator/risk_calculator");
|
|
24
|
+
const toAddress = (value) => {
|
|
25
|
+
if (value instanceof ton_1.Address) {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
return ton_1.Address.parse(value);
|
|
29
|
+
};
|
|
30
|
+
const toString = (value) => {
|
|
31
|
+
if (value instanceof ton_1.Address) {
|
|
32
|
+
return value.toString();
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
};
|
|
36
|
+
class PoolV1 extends service_1.ServiceBaseV1 {
|
|
37
|
+
// user -> asset -> wallet
|
|
38
|
+
walletAddresses = {};
|
|
39
|
+
// user -> pool -> account
|
|
40
|
+
accountAddresses = {};
|
|
41
|
+
async getJettonWalletAddress(owner, jetton) {
|
|
42
|
+
this.walletAddresses[owner] ||= {};
|
|
43
|
+
if (!this.walletAddresses[owner][jetton]) {
|
|
44
|
+
const jettonMinter = this.open(jetton_minter_1.JettonMinter.createFromAddress(toAddress(jetton)));
|
|
45
|
+
this.walletAddresses[owner][jetton] = await jettonMinter.getWalletAddress(toAddress(owner));
|
|
46
|
+
}
|
|
47
|
+
return this.walletAddresses[owner][jetton];
|
|
48
|
+
}
|
|
49
|
+
async getAccountAddress(owner, pool) {
|
|
50
|
+
this.accountAddresses[owner] ||= {};
|
|
51
|
+
if (!this.accountAddresses[owner][pool]) {
|
|
52
|
+
const poolContract = this.open(pool_1.Pool.createFromAddress(toAddress(pool)));
|
|
53
|
+
this.accountAddresses[owner][pool] = await poolContract.getAccountAddress(toAddress(owner));
|
|
54
|
+
}
|
|
55
|
+
return this.accountAddresses[owner][pool];
|
|
56
|
+
}
|
|
57
|
+
async findAndCallback(target, step, createdLt, callbackFn) {
|
|
58
|
+
const matchedTx = await (0, tracker_1.findTx)(this.client, toAddress(target), createdLt.toString(), step);
|
|
59
|
+
step.matchedTx = matchedTx;
|
|
60
|
+
if (matchedTx.inMessage?.body) {
|
|
61
|
+
const parsed = (0, parser_1.parseActionNotification)(matchedTx.inMessage.body);
|
|
62
|
+
if (parsed) {
|
|
63
|
+
step.actionNotificationResult = parsed;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (callbackFn)
|
|
67
|
+
callbackFn(step);
|
|
68
|
+
return matchedTx;
|
|
69
|
+
}
|
|
70
|
+
async supply(sender, params) {
|
|
71
|
+
const isWTON = toString(params.asset) == this.contracts.WTON;
|
|
72
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
73
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
74
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
75
|
+
const poolData = await pool.getPoolData();
|
|
76
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Supply, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, false, poolData.minimumGasFee);
|
|
77
|
+
if (toString(params.asset) == this.contracts.WTON) {
|
|
78
|
+
const poolWTONWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
79
|
+
const poolWTONWallet = this.open(jetton_wallet_2.WTONWallet.createFromAddress(poolWTONWalletAddress));
|
|
80
|
+
await poolWTONWallet.sendExternalTransfer(sender, jetton_wallet_2.WTONWallet.Gas.ExternalTransfer, {
|
|
81
|
+
recipient: toAddress(params.pool),
|
|
82
|
+
response: toAddress(params.response),
|
|
83
|
+
amount: params.amount,
|
|
84
|
+
forwardTonAmount: gas,
|
|
85
|
+
forwardPayload: pool_1.Pool.createSupplyPayload({
|
|
86
|
+
asset: toAddress(params.asset),
|
|
87
|
+
recipient: toAddress(params.recipient),
|
|
88
|
+
response: toAddress(params.response),
|
|
89
|
+
jettonForwardTonAmount,
|
|
90
|
+
jettonForwardPayload,
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(toString(params.sender), toString(params.asset));
|
|
96
|
+
const senderJettonWallet = this.open(jetton_wallet_1.JettonWallet.createFromAddress(senderJettonWalletAddress));
|
|
97
|
+
await senderJettonWallet.sendTransfer(sender, gas + jetton_wallet_1.JettonWallet.Gas.Transfer, {
|
|
98
|
+
recipient: toAddress(params.pool),
|
|
99
|
+
response: toAddress(params.response),
|
|
100
|
+
amount: params.amount,
|
|
101
|
+
forwardTonAmount: gas,
|
|
102
|
+
forwardPayload: pool_1.Pool.createSupplyPayload({
|
|
103
|
+
asset: toAddress(params.asset),
|
|
104
|
+
recipient: toAddress(params.recipient),
|
|
105
|
+
response: toAddress(params.response),
|
|
106
|
+
jettonForwardTonAmount,
|
|
107
|
+
jettonForwardPayload,
|
|
108
|
+
}),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async supplyAndWaitTx(sender, params, callbackFn) {
|
|
113
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(toString(params.sender), toString(params.asset));
|
|
114
|
+
const senderJettonWallet = this.open(jetton_wallet_1.JettonWallet.createFromAddress(senderJettonWalletAddress));
|
|
115
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
116
|
+
const poolJettonWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
117
|
+
const recipientAccountAddress = await this.getAccountAddress(toString(params.recipient), toString(params.pool));
|
|
118
|
+
const isWTON = toString(params.asset) == this.contracts.WTON;
|
|
119
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
120
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
121
|
+
const poolData = await pool.getPoolData();
|
|
122
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Supply, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, false, poolData.minimumGasFee);
|
|
123
|
+
const opts = {
|
|
124
|
+
recipient: toAddress(params.pool),
|
|
125
|
+
response: toAddress(params.response),
|
|
126
|
+
amount: params.amount,
|
|
127
|
+
forwardTonAmount: gas,
|
|
128
|
+
forwardPayload: pool_1.Pool.createSupplyPayload({
|
|
129
|
+
asset: toAddress(params.asset),
|
|
130
|
+
recipient: toAddress(params.recipient),
|
|
131
|
+
response: toAddress(params.response),
|
|
132
|
+
jettonForwardTonAmount,
|
|
133
|
+
jettonForwardPayload,
|
|
134
|
+
}),
|
|
135
|
+
};
|
|
136
|
+
const body = senderJettonWallet.createTransferBody(opts);
|
|
137
|
+
const queryId = (0, query_id_generactor_1.generateQueryId)(toAddress(params.sender), body);
|
|
138
|
+
const steps = [];
|
|
139
|
+
if (toString(params.asset) == this.contracts.WTON) {
|
|
140
|
+
const poolWTONWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
141
|
+
const poolWTONWallet = this.open(jetton_wallet_2.WTONWallet.createFromAddress(poolWTONWalletAddress));
|
|
142
|
+
await poolWTONWallet.sendExternalTransfer(sender, jetton_wallet_2.WTONWallet.Gas.ExternalTransfer, {
|
|
143
|
+
queryId: queryId,
|
|
144
|
+
...opts,
|
|
145
|
+
});
|
|
146
|
+
steps.push(...[
|
|
147
|
+
{
|
|
148
|
+
queryId,
|
|
149
|
+
description: "Sending the tx",
|
|
150
|
+
from: toAddress(params.sender),
|
|
151
|
+
to: poolWTONWalletAddress,
|
|
152
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
queryId,
|
|
156
|
+
description: "Supplying jetton to the pool",
|
|
157
|
+
from: toAddress(params.sender),
|
|
158
|
+
to: poolWTONWalletAddress,
|
|
159
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
160
|
+
},
|
|
161
|
+
]);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
await senderJettonWallet.sendTransfer(sender, gas + jetton_wallet_1.JettonWallet.Gas.Transfer, {
|
|
165
|
+
queryId: queryId,
|
|
166
|
+
...opts,
|
|
167
|
+
});
|
|
168
|
+
steps.push({
|
|
169
|
+
queryId,
|
|
170
|
+
description: "Sending the tx",
|
|
171
|
+
from: toAddress(params.sender),
|
|
172
|
+
to: senderJettonWalletAddress,
|
|
173
|
+
opcode: jetton_wallet_1.JettonWallet.Op.Transfer,
|
|
174
|
+
});
|
|
175
|
+
steps.push({
|
|
176
|
+
queryId,
|
|
177
|
+
description: "Supplying jetton to the pool",
|
|
178
|
+
from: senderJettonWalletAddress,
|
|
179
|
+
to: poolJettonWalletAddress,
|
|
180
|
+
opcode: jetton_wallet_1.JettonWallet.Op.InternalTransfer,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
steps.push(...[
|
|
184
|
+
{
|
|
185
|
+
queryId,
|
|
186
|
+
description: "Pool notification",
|
|
187
|
+
from: poolJettonWalletAddress,
|
|
188
|
+
to: pool.address,
|
|
189
|
+
opcode: jetton_wallet_1.JettonWallet.Op.TransferNotification,
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
queryId,
|
|
193
|
+
description: "Action notification",
|
|
194
|
+
from: pool.address,
|
|
195
|
+
to: toAddress(params.sender),
|
|
196
|
+
opcode: pool_1.Pool.Op.ActionNotification,
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
queryId,
|
|
200
|
+
description: "Updating the account",
|
|
201
|
+
from: pool.address,
|
|
202
|
+
to: recipientAccountAddress,
|
|
203
|
+
opcode: pool_1.Pool.Op.UpdateAccountStatus,
|
|
204
|
+
},
|
|
205
|
+
]);
|
|
206
|
+
(async () => {
|
|
207
|
+
const matchedTx0 = await this.findAndCallback(toAddress(params.sender), steps[0], "0", callbackFn);
|
|
208
|
+
const matchedTx1 = await this.findAndCallback(poolJettonWalletAddress, steps[1], matchedTx0.lt.toString(), callbackFn);
|
|
209
|
+
const matchedTx2 = await this.findAndCallback(pool.address, steps[2], matchedTx1.lt.toString(), callbackFn);
|
|
210
|
+
const matchedTx3 = await this.findAndCallback(toAddress(params.sender), steps[3], matchedTx2.lt.toString(), callbackFn);
|
|
211
|
+
const matchedTx4 = await this.findAndCallback(recipientAccountAddress, steps[4], matchedTx2.lt.toString(), callbackFn);
|
|
212
|
+
})();
|
|
213
|
+
return {
|
|
214
|
+
action: {
|
|
215
|
+
type: "pool-supply",
|
|
216
|
+
params,
|
|
217
|
+
queryId,
|
|
218
|
+
},
|
|
219
|
+
steps,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
async findTx(action, callbackFn) {
|
|
223
|
+
if (action.type == "pool-supply") {
|
|
224
|
+
return this.findSupplyTx(BigInt(action.queryId), action.params, callbackFn);
|
|
225
|
+
}
|
|
226
|
+
else if (action.type == "pool-withdraw") {
|
|
227
|
+
return this.findWithdrawTx(BigInt(action.queryId), action.params, callbackFn);
|
|
228
|
+
}
|
|
229
|
+
else if (action.type == "pool-borrow") {
|
|
230
|
+
return this.findBorrowTx(BigInt(action.queryId), action.params, callbackFn);
|
|
231
|
+
}
|
|
232
|
+
else if (action.type == "pool-repay") {
|
|
233
|
+
return this.findRepayTx(BigInt(action.queryId), action.params, callbackFn);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
async findSupplyTx(queryId, params, callbackFn) {
|
|
237
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(toString(params.sender), toString(params.asset));
|
|
238
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
239
|
+
const poolJettonWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
240
|
+
const recipientAccountAddress = await this.getAccountAddress(toString(params.recipient), toString(params.pool));
|
|
241
|
+
const steps = [];
|
|
242
|
+
if (toString(params.asset) == this.contracts.WTON) {
|
|
243
|
+
const poolWTONWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
244
|
+
const poolWTONWallet = this.open(jetton_wallet_2.WTONWallet.createFromAddress(poolWTONWalletAddress));
|
|
245
|
+
steps.push(...[
|
|
246
|
+
{
|
|
247
|
+
queryId,
|
|
248
|
+
description: "Sending the tx",
|
|
249
|
+
from: toAddress(params.sender),
|
|
250
|
+
to: poolWTONWalletAddress,
|
|
251
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
queryId,
|
|
255
|
+
description: "Supplying jetton to the pool",
|
|
256
|
+
from: toAddress(params.sender),
|
|
257
|
+
to: poolWTONWalletAddress,
|
|
258
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
259
|
+
},
|
|
260
|
+
]);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
steps.push({
|
|
264
|
+
queryId,
|
|
265
|
+
description: "Sending the tx",
|
|
266
|
+
from: toAddress(params.sender),
|
|
267
|
+
to: senderJettonWalletAddress,
|
|
268
|
+
opcode: jetton_wallet_1.JettonWallet.Op.Transfer,
|
|
269
|
+
});
|
|
270
|
+
steps.push({
|
|
271
|
+
queryId,
|
|
272
|
+
description: "Supplying jetton to the pool",
|
|
273
|
+
from: senderJettonWalletAddress,
|
|
274
|
+
to: poolJettonWalletAddress,
|
|
275
|
+
opcode: jetton_wallet_1.JettonWallet.Op.InternalTransfer,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
steps.push(...[
|
|
279
|
+
{
|
|
280
|
+
queryId,
|
|
281
|
+
description: "Pool notification",
|
|
282
|
+
from: poolJettonWalletAddress,
|
|
283
|
+
to: pool.address,
|
|
284
|
+
opcode: jetton_wallet_1.JettonWallet.Op.TransferNotification,
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
queryId,
|
|
288
|
+
description: "Action notification",
|
|
289
|
+
from: pool.address,
|
|
290
|
+
to: toAddress(params.sender),
|
|
291
|
+
opcode: pool_1.Pool.Op.ActionNotification,
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
queryId,
|
|
295
|
+
description: "Updating the account",
|
|
296
|
+
from: pool.address,
|
|
297
|
+
to: recipientAccountAddress,
|
|
298
|
+
opcode: pool_1.Pool.Op.UpdateAccountStatus,
|
|
299
|
+
},
|
|
300
|
+
]);
|
|
301
|
+
(async () => {
|
|
302
|
+
const matchedTx0 = await this.findAndCallback(toAddress(params.sender), steps[0], "0", callbackFn);
|
|
303
|
+
const matchedTx1 = await this.findAndCallback(poolJettonWalletAddress, steps[1], matchedTx0.lt.toString(), callbackFn);
|
|
304
|
+
const matchedTx2 = await this.findAndCallback(pool.address, steps[2], matchedTx1.lt.toString(), callbackFn);
|
|
305
|
+
const matchedTx3 = await this.findAndCallback(toAddress(params.sender), steps[3], matchedTx2.lt.toString(), callbackFn);
|
|
306
|
+
const matchedTx4 = await this.findAndCallback(recipientAccountAddress, steps[4], matchedTx3.lt.toString(), callbackFn);
|
|
307
|
+
})();
|
|
308
|
+
return {
|
|
309
|
+
action: {
|
|
310
|
+
type: "pool-supply",
|
|
311
|
+
params,
|
|
312
|
+
queryId,
|
|
313
|
+
},
|
|
314
|
+
steps,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
async withdraw(sender, params) {
|
|
318
|
+
const senderAccountAddress = await this.getAccountAddress(toString(params.sender), toString(params.pool));
|
|
319
|
+
const senderAccount = this.open(account_1.Account.createFromAddress(senderAccountAddress));
|
|
320
|
+
const accountData = await senderAccount.getAccountData();
|
|
321
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
322
|
+
const poolData = (await pool.getPoolData());
|
|
323
|
+
let oracleParams = null;
|
|
324
|
+
if (account_1.Account.haveBorrow(accountData)) {
|
|
325
|
+
const assets = [...new Set([...account_1.Account.haveAssets(accountData)])];
|
|
326
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
327
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
328
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
329
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
330
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
331
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
332
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
333
|
+
oracleParams = (0, ton_1.beginCell)()
|
|
334
|
+
.storeRef(feedIdCell)
|
|
335
|
+
.storeRef(payload)
|
|
336
|
+
.storeRef(requestAssetCell)
|
|
337
|
+
.endCell();
|
|
338
|
+
}
|
|
339
|
+
const isWTON = toString(params.asset) == this.contracts.WTON;
|
|
340
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
341
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
342
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Withdraw, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, !!oracleParams, poolData.minimumGasFee);
|
|
343
|
+
await pool.sendWithdraw(sender, gas, {
|
|
344
|
+
asset: toAddress(params.asset),
|
|
345
|
+
isShare: params.isShare,
|
|
346
|
+
amount: params.amount,
|
|
347
|
+
recipient: toAddress(params.recipient),
|
|
348
|
+
response: toAddress(params.response),
|
|
349
|
+
jettonForwardTonAmount,
|
|
350
|
+
jettonForwardPayload,
|
|
351
|
+
oracleParams: oracleParams,
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
async withdrawAndWaitTx(sender, params, callbackFn) {
|
|
355
|
+
const senderAccountAddress = await this.getAccountAddress(toString(params.sender), toString(params.pool));
|
|
356
|
+
const senderAccount = this.open(account_1.Account.createFromAddress(senderAccountAddress));
|
|
357
|
+
const accountData = await senderAccount.getAccountData();
|
|
358
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
359
|
+
const poolData = (await pool.getPoolData());
|
|
360
|
+
const poolJettonWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
361
|
+
const recipeintJettonWalletAddress = await this.getJettonWalletAddress(toString(params.recipient), toString(params.asset));
|
|
362
|
+
let oracleParams = null;
|
|
363
|
+
if (account_1.Account.haveBorrow(accountData)) {
|
|
364
|
+
const userAssets = [
|
|
365
|
+
...new Set([
|
|
366
|
+
...account_1.Account.haveAssets(accountData),
|
|
367
|
+
toString(params.asset),
|
|
368
|
+
]),
|
|
369
|
+
];
|
|
370
|
+
let { assets, vaultAssets } = await this.separateAssets(userAssets, poolData.oracleConfig);
|
|
371
|
+
const vaultPositions = await this.getParsedVaults(vaultAssets);
|
|
372
|
+
const exposures = await this.getExposures(vaultPositions);
|
|
373
|
+
const exposurePools = exposures.pools;
|
|
374
|
+
assets = [...new Set([...assets, ...exposures.assets])];
|
|
375
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
376
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
377
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
378
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
379
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
380
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
381
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
382
|
+
let requestFactorialPoolsCell = exposurePools.length > 0
|
|
383
|
+
? redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(exposurePools.map((pool) => ton_1.Address.parse(pool)))
|
|
384
|
+
: null;
|
|
385
|
+
let requestFactorialVaultsCell = vaultAssets.length > 0
|
|
386
|
+
? redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(vaultAssets.map((vault) => ton_1.Address.parse(vault)))
|
|
387
|
+
: null;
|
|
388
|
+
let requestFactorialCell = (0, ton_1.beginCell)()
|
|
389
|
+
.storeMaybeRef(requestFactorialPoolsCell)
|
|
390
|
+
.storeMaybeRef(requestFactorialVaultsCell)
|
|
391
|
+
.endCell();
|
|
392
|
+
oracleParams = (0, ton_1.beginCell)()
|
|
393
|
+
.storeRef(feedIdCell)
|
|
394
|
+
.storeRef(payload)
|
|
395
|
+
.storeRef(requestAssetCell)
|
|
396
|
+
.storeRef(requestFactorialCell)
|
|
397
|
+
.endCell();
|
|
398
|
+
}
|
|
399
|
+
const isWTON = toString(params.asset) == this.contracts.WTON;
|
|
400
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
401
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
402
|
+
const opts = {
|
|
403
|
+
asset: toAddress(params.asset),
|
|
404
|
+
isShare: params.isShare,
|
|
405
|
+
amount: params.amount,
|
|
406
|
+
recipient: toAddress(params.recipient),
|
|
407
|
+
response: toAddress(params.response),
|
|
408
|
+
jettonForwardTonAmount,
|
|
409
|
+
jettonForwardPayload,
|
|
410
|
+
oracleParams: oracleParams,
|
|
411
|
+
};
|
|
412
|
+
const body = pool_1.Pool.createWithdrawMsgBody(opts);
|
|
413
|
+
const queryId = (0, query_id_generactor_1.generateQueryId)(toAddress(params.sender), body);
|
|
414
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Withdraw, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, !!oracleParams, poolData.minimumGasFee);
|
|
415
|
+
await pool.sendWithdraw(sender, gas + (0, ton_1.toNano)(0.4), {
|
|
416
|
+
...opts,
|
|
417
|
+
queryId,
|
|
418
|
+
});
|
|
419
|
+
const steps = [
|
|
420
|
+
{
|
|
421
|
+
queryId,
|
|
422
|
+
description: "Sending the tx",
|
|
423
|
+
from: toAddress(params.sender),
|
|
424
|
+
to: toAddress(params.pool),
|
|
425
|
+
opcode: pool_1.Pool.Op.Withdraw,
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
queryId,
|
|
429
|
+
description: "Calculating oracle data",
|
|
430
|
+
from: toAddress(poolData.oracle ? poolData.oracle : params.pool),
|
|
431
|
+
to: toAddress(params.pool),
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
queryId,
|
|
435
|
+
description: "Updating the account",
|
|
436
|
+
from: toAddress(params.pool),
|
|
437
|
+
to: senderAccountAddress,
|
|
438
|
+
opcode: pool_1.Pool.Op.ExecuteAction,
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
queryId,
|
|
442
|
+
description: "Action notification",
|
|
443
|
+
from: toAddress(params.pool),
|
|
444
|
+
to: toAddress(params.sender),
|
|
445
|
+
opcode: pool_1.Pool.Op.ActionNotification,
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
queryId,
|
|
449
|
+
description: "Withdrawing jetton from the pool",
|
|
450
|
+
from: poolJettonWalletAddress,
|
|
451
|
+
to: recipeintJettonWalletAddress,
|
|
452
|
+
opcode: jetton_wallet_1.JettonWallet.Op.InternalTransfer,
|
|
453
|
+
},
|
|
454
|
+
];
|
|
455
|
+
(async () => {
|
|
456
|
+
const matchedTx0 = await this.findAndCallback(toAddress(params.sender), steps[0], "0", callbackFn);
|
|
457
|
+
if (poolData.oracle && oracleParams) {
|
|
458
|
+
const matchedTx1 = await this.findAndCallback(toAddress(params.pool), steps[1], matchedTx0.lt.toString(), callbackFn);
|
|
459
|
+
}
|
|
460
|
+
const matchedTx2 = await this.findAndCallback(toAddress(senderAccountAddress), steps[2], matchedTx0.lt.toString(), callbackFn);
|
|
461
|
+
const matchedTx3 = await this.findAndCallback(toAddress(params.sender), steps[3], matchedTx2.lt.toString(), callbackFn);
|
|
462
|
+
const matchedTx4 = await this.findAndCallback(toAddress(recipeintJettonWalletAddress), steps[4], matchedTx2.lt.toString(), callbackFn);
|
|
463
|
+
})();
|
|
464
|
+
return {
|
|
465
|
+
action: {
|
|
466
|
+
type: "pool-withdraw",
|
|
467
|
+
params,
|
|
468
|
+
queryId,
|
|
469
|
+
},
|
|
470
|
+
steps,
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
async findWithdrawTx(queryId, params, callbackFn) {
|
|
474
|
+
const senderAccountAddress = await this.getAccountAddress(toString(params.sender), toString(params.pool));
|
|
475
|
+
const senderAccount = this.open(account_1.Account.createFromAddress(senderAccountAddress));
|
|
476
|
+
const accountData = await senderAccount.getAccountData();
|
|
477
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
478
|
+
const poolData = (await pool.getPoolData());
|
|
479
|
+
const poolJettonWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
480
|
+
const recipeintJettonWalletAddress = await this.getJettonWalletAddress(toString(params.recipient), toString(params.asset));
|
|
481
|
+
let oracleParams = null;
|
|
482
|
+
if (account_1.Account.haveBorrow(accountData)) {
|
|
483
|
+
const assets = [...new Set([...account_1.Account.haveAssets(accountData)])];
|
|
484
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
485
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
486
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
487
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
488
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
489
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
490
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
491
|
+
oracleParams = (0, ton_1.beginCell)()
|
|
492
|
+
.storeRef(feedIdCell)
|
|
493
|
+
.storeRef(payload)
|
|
494
|
+
.storeRef(requestAssetCell)
|
|
495
|
+
.endCell();
|
|
496
|
+
}
|
|
497
|
+
const steps = [
|
|
498
|
+
{
|
|
499
|
+
queryId,
|
|
500
|
+
description: "Sending the tx",
|
|
501
|
+
from: toAddress(params.sender),
|
|
502
|
+
to: toAddress(params.pool),
|
|
503
|
+
opcode: pool_1.Pool.Op.Withdraw,
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
queryId,
|
|
507
|
+
description: "Calculating oracle data",
|
|
508
|
+
from: toAddress(poolData.oracle ? poolData.oracle : params.pool),
|
|
509
|
+
to: toAddress(params.pool),
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
queryId,
|
|
513
|
+
description: "Updating the account",
|
|
514
|
+
from: toAddress(params.pool),
|
|
515
|
+
to: senderAccountAddress,
|
|
516
|
+
opcode: pool_1.Pool.Op.ExecuteAction,
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
queryId,
|
|
520
|
+
description: "Action notification",
|
|
521
|
+
from: toAddress(params.pool),
|
|
522
|
+
to: toAddress(params.sender),
|
|
523
|
+
opcode: pool_1.Pool.Op.ActionNotification,
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
queryId,
|
|
527
|
+
description: "Withdrawing jetton from the pool",
|
|
528
|
+
from: poolJettonWalletAddress,
|
|
529
|
+
to: recipeintJettonWalletAddress,
|
|
530
|
+
opcode: jetton_wallet_1.JettonWallet.Op.InternalTransfer,
|
|
531
|
+
},
|
|
532
|
+
];
|
|
533
|
+
(async () => {
|
|
534
|
+
const matchedTx0 = await this.findAndCallback(toAddress(params.sender), steps[0], "0", callbackFn);
|
|
535
|
+
if (poolData.oracle && oracleParams) {
|
|
536
|
+
const matchedTx1 = await this.findAndCallback(toAddress(params.pool), steps[1], matchedTx0.lt.toString(), callbackFn);
|
|
537
|
+
}
|
|
538
|
+
const matchedTx2 = await this.findAndCallback(toAddress(senderAccountAddress), steps[2], matchedTx0.lt.toString(), callbackFn);
|
|
539
|
+
const matchedTx3 = await this.findAndCallback(toAddress(params.sender), steps[3], matchedTx2.lt.toString(), callbackFn);
|
|
540
|
+
const matchedTx4 = await this.findAndCallback(toAddress(recipeintJettonWalletAddress), steps[4], matchedTx3.lt.toString(), callbackFn);
|
|
541
|
+
})();
|
|
542
|
+
return {
|
|
543
|
+
action: {
|
|
544
|
+
type: "pool-withdraw",
|
|
545
|
+
params,
|
|
546
|
+
queryId,
|
|
547
|
+
},
|
|
548
|
+
steps,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
async borrow(sender, params) {
|
|
552
|
+
const senderAccountAddress = await this.getAccountAddress(toString(params.sender), toString(params.pool));
|
|
553
|
+
const senderAccount = this.open(account_1.Account.createFromAddress(senderAccountAddress));
|
|
554
|
+
const accountData = await senderAccount.getAccountData();
|
|
555
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
556
|
+
const poolData = (await pool.getPoolData());
|
|
557
|
+
const assets = [
|
|
558
|
+
...new Set([...account_1.Account.haveAssets(accountData), toString(params.asset)]),
|
|
559
|
+
];
|
|
560
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
561
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
562
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
563
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
564
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
565
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
566
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
567
|
+
const oracleParams = (0, ton_1.beginCell)()
|
|
568
|
+
.storeRef(feedIdCell)
|
|
569
|
+
.storeRef(payload)
|
|
570
|
+
.storeRef(requestAssetCell)
|
|
571
|
+
.endCell();
|
|
572
|
+
const isWTON = toString(params.asset) == this.contracts.WTON;
|
|
573
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
574
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
575
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Borrow, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, !!oracleParams, poolData.minimumGasFee);
|
|
576
|
+
await pool.sendBorrow(sender, gas, {
|
|
577
|
+
asset: toAddress(params.asset),
|
|
578
|
+
isShare: params.isShare,
|
|
579
|
+
amount: params.amount,
|
|
580
|
+
recipient: toAddress(params.recipient),
|
|
581
|
+
response: toAddress(params.response),
|
|
582
|
+
jettonForwardTonAmount,
|
|
583
|
+
jettonForwardPayload,
|
|
584
|
+
oracleParams: oracleParams,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
async borrowAndWaitTx(sender, params, callbackFn) {
|
|
588
|
+
const senderAccountAddress = await this.getAccountAddress(toString(params.sender), toString(params.pool));
|
|
589
|
+
const senderAccount = this.open(account_1.Account.createFromAddress(senderAccountAddress));
|
|
590
|
+
const accountData = await senderAccount.getAccountData();
|
|
591
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
592
|
+
const poolData = (await pool.getPoolData());
|
|
593
|
+
const poolJettonWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
594
|
+
const recipeintJettonWalletAddress = await this.getJettonWalletAddress(toString(params.recipient), toString(params.asset));
|
|
595
|
+
const userAssets = [
|
|
596
|
+
...new Set([...account_1.Account.haveAssets(accountData), toString(params.asset)]),
|
|
597
|
+
];
|
|
598
|
+
let { assets, vaultAssets } = await this.separateAssets(userAssets, poolData.oracleConfig);
|
|
599
|
+
const vaultPositions = await this.getParsedVaults(vaultAssets);
|
|
600
|
+
const exposures = await this.getExposures(vaultPositions);
|
|
601
|
+
const exposurePools = exposures.pools;
|
|
602
|
+
assets = [...new Set([...assets, ...exposures.assets])];
|
|
603
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
604
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
605
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
606
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
607
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
608
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
609
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
610
|
+
let requestFactorialPoolsCell = exposurePools.length > 0
|
|
611
|
+
? redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(exposurePools.map((pool) => ton_1.Address.parse(pool)))
|
|
612
|
+
: null;
|
|
613
|
+
let requestFactorialVaultsCell = vaultAssets.length > 0
|
|
614
|
+
? redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(vaultAssets.map((vault) => ton_1.Address.parse(vault)))
|
|
615
|
+
: null;
|
|
616
|
+
let requestFactorialCell = (0, ton_1.beginCell)()
|
|
617
|
+
.storeMaybeRef(requestFactorialPoolsCell)
|
|
618
|
+
.storeMaybeRef(requestFactorialVaultsCell)
|
|
619
|
+
.endCell();
|
|
620
|
+
const oracleParams = (0, ton_1.beginCell)()
|
|
621
|
+
.storeRef(feedIdCell)
|
|
622
|
+
.storeRef(payload)
|
|
623
|
+
.storeRef(requestAssetCell)
|
|
624
|
+
.storeRef(requestFactorialCell)
|
|
625
|
+
.endCell();
|
|
626
|
+
const isWTON = toString(params.asset) == this.contracts.WTON;
|
|
627
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
628
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
629
|
+
const opts = {
|
|
630
|
+
asset: toAddress(params.asset),
|
|
631
|
+
isShare: params.isShare,
|
|
632
|
+
amount: params.amount,
|
|
633
|
+
recipient: toAddress(params.recipient),
|
|
634
|
+
response: toAddress(params.response),
|
|
635
|
+
jettonForwardTonAmount,
|
|
636
|
+
jettonForwardPayload,
|
|
637
|
+
oracleParams: oracleParams,
|
|
638
|
+
};
|
|
639
|
+
const body = pool_1.Pool.createWithdrawMsgBody(opts);
|
|
640
|
+
const queryId = (0, query_id_generactor_1.generateQueryId)(toAddress(params.sender), body);
|
|
641
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Borrow, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, !!oracleParams, poolData.minimumGasFee);
|
|
642
|
+
await pool.sendBorrow(sender, gas, {
|
|
643
|
+
...opts,
|
|
644
|
+
queryId,
|
|
645
|
+
});
|
|
646
|
+
const steps = [
|
|
647
|
+
{
|
|
648
|
+
queryId,
|
|
649
|
+
description: "Sending the tx",
|
|
650
|
+
from: toAddress(params.sender),
|
|
651
|
+
to: toAddress(params.pool),
|
|
652
|
+
opcode: pool_1.Pool.Op.Borrow,
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
queryId,
|
|
656
|
+
description: "Calculating oracle data",
|
|
657
|
+
from: toAddress(poolData.oracle ? poolData.oracle : params.pool),
|
|
658
|
+
to: toAddress(params.pool),
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
queryId,
|
|
662
|
+
description: "Action notification",
|
|
663
|
+
from: toAddress(params.pool),
|
|
664
|
+
to: toAddress(params.sender),
|
|
665
|
+
opcode: pool_1.Pool.Op.ActionNotification,
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
queryId,
|
|
669
|
+
description: "Updating the account",
|
|
670
|
+
from: toAddress(params.pool),
|
|
671
|
+
to: senderAccountAddress,
|
|
672
|
+
opcode: pool_1.Pool.Op.ProcessBorrowActionResult,
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
queryId,
|
|
676
|
+
description: "Withdrawing jetton from the pool",
|
|
677
|
+
from: poolJettonWalletAddress,
|
|
678
|
+
to: recipeintJettonWalletAddress,
|
|
679
|
+
opcode: jetton_wallet_1.JettonWallet.Op.InternalTransfer,
|
|
680
|
+
},
|
|
681
|
+
];
|
|
682
|
+
(async () => {
|
|
683
|
+
const matchedTx0 = await this.findAndCallback(toAddress(params.sender), steps[0], "0", callbackFn);
|
|
684
|
+
if (poolData.oracle && oracleParams) {
|
|
685
|
+
const matchedTx1 = await this.findAndCallback(toAddress(params.pool), steps[1], matchedTx0.lt.toString(), callbackFn);
|
|
686
|
+
}
|
|
687
|
+
const matchedTx2 = await this.findAndCallback(toAddress(params.sender), steps[2], matchedTx0.lt.toString(), callbackFn);
|
|
688
|
+
const matchedTx4 = await this.findAndCallback(toAddress(senderAccountAddress), steps[3], matchedTx0.lt.toString(), callbackFn);
|
|
689
|
+
const matchedTx3 = await this.findAndCallback(toAddress(recipeintJettonWalletAddress), steps[4], matchedTx0.lt.toString(), callbackFn);
|
|
690
|
+
})();
|
|
691
|
+
return {
|
|
692
|
+
action: {
|
|
693
|
+
type: "pool-borrow",
|
|
694
|
+
params,
|
|
695
|
+
queryId,
|
|
696
|
+
},
|
|
697
|
+
steps,
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
async findBorrowTx(queryId, params, callbackFn) {
|
|
701
|
+
const senderAccountAddress = await this.getAccountAddress(toString(params.sender), toString(params.pool));
|
|
702
|
+
const senderAccount = this.open(account_1.Account.createFromAddress(senderAccountAddress));
|
|
703
|
+
const accountData = await senderAccount.getAccountData();
|
|
704
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
705
|
+
const poolData = (await pool.getPoolData());
|
|
706
|
+
const poolJettonWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
707
|
+
const recipeintJettonWalletAddress = await this.getJettonWalletAddress(toString(params.recipient), toString(params.asset));
|
|
708
|
+
const assets = [
|
|
709
|
+
...new Set([...account_1.Account.haveAssets(accountData), toString(params.asset)]),
|
|
710
|
+
];
|
|
711
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
712
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
713
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
714
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
715
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
716
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
717
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
718
|
+
const oracleParams = (0, ton_1.beginCell)()
|
|
719
|
+
.storeRef(feedIdCell)
|
|
720
|
+
.storeRef(payload)
|
|
721
|
+
.storeRef(requestAssetCell)
|
|
722
|
+
.endCell();
|
|
723
|
+
const steps = [
|
|
724
|
+
{
|
|
725
|
+
queryId,
|
|
726
|
+
description: "Sending the tx",
|
|
727
|
+
from: toAddress(params.sender),
|
|
728
|
+
to: toAddress(params.pool),
|
|
729
|
+
opcode: pool_1.Pool.Op.Borrow,
|
|
730
|
+
},
|
|
731
|
+
{
|
|
732
|
+
queryId,
|
|
733
|
+
description: "Calculating oracle data",
|
|
734
|
+
from: toAddress(poolData.oracle ? poolData.oracle : params.pool),
|
|
735
|
+
to: toAddress(params.pool),
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
queryId,
|
|
739
|
+
description: "Action notification",
|
|
740
|
+
from: toAddress(params.pool),
|
|
741
|
+
to: toAddress(params.sender),
|
|
742
|
+
opcode: pool_1.Pool.Op.ActionNotification,
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
queryId,
|
|
746
|
+
description: "Updating the account",
|
|
747
|
+
from: toAddress(params.pool),
|
|
748
|
+
to: senderAccountAddress,
|
|
749
|
+
opcode: pool_1.Pool.Op.ProcessBorrowActionResult,
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
queryId,
|
|
753
|
+
description: "Withdrawing jetton from the pool",
|
|
754
|
+
from: poolJettonWalletAddress,
|
|
755
|
+
to: recipeintJettonWalletAddress,
|
|
756
|
+
opcode: jetton_wallet_1.JettonWallet.Op.InternalTransfer,
|
|
757
|
+
},
|
|
758
|
+
];
|
|
759
|
+
(async () => {
|
|
760
|
+
const matchedTx0 = await this.findAndCallback(toAddress(params.sender), steps[0], "0", callbackFn);
|
|
761
|
+
if (poolData.oracle && oracleParams) {
|
|
762
|
+
const matchedTx1 = await this.findAndCallback(toAddress(params.pool), steps[1], matchedTx0.lt.toString(), callbackFn);
|
|
763
|
+
}
|
|
764
|
+
const matchedTx2 = await this.findAndCallback(toAddress(params.sender), steps[2], matchedTx0.lt.toString(), callbackFn);
|
|
765
|
+
const matchedTx4 = await this.findAndCallback(toAddress(senderAccountAddress), steps[3], matchedTx0.lt.toString(), callbackFn);
|
|
766
|
+
const matchedTx3 = await this.findAndCallback(toAddress(recipeintJettonWalletAddress), steps[4], matchedTx0.lt.toString(), callbackFn);
|
|
767
|
+
})();
|
|
768
|
+
return {
|
|
769
|
+
action: {
|
|
770
|
+
type: "pool-borrow",
|
|
771
|
+
params,
|
|
772
|
+
queryId,
|
|
773
|
+
},
|
|
774
|
+
steps,
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
async repay(sender, params) {
|
|
778
|
+
const isWTON = toString(params.asset) == this.contracts.WTON;
|
|
779
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
780
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
781
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
782
|
+
const poolData = await pool.getPoolData();
|
|
783
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Repay, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, false, poolData.minimumGasFee);
|
|
784
|
+
if (toString(params.asset) == this.contracts.WTON) {
|
|
785
|
+
const poolWTONWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
786
|
+
const poolWTONWallet = this.open(jetton_wallet_2.WTONWallet.createFromAddress(poolWTONWalletAddress));
|
|
787
|
+
await poolWTONWallet.sendExternalTransfer(sender, jetton_wallet_2.WTONWallet.Gas.ExternalTransfer, {
|
|
788
|
+
recipient: toAddress(params.pool),
|
|
789
|
+
response: toAddress(params.response),
|
|
790
|
+
amount: params.amount,
|
|
791
|
+
forwardTonAmount: gas,
|
|
792
|
+
forwardPayload: pool_1.Pool.createRepayPayload({
|
|
793
|
+
asset: toAddress(params.asset),
|
|
794
|
+
recipient: toAddress(params.recipient),
|
|
795
|
+
response: toAddress(params.response),
|
|
796
|
+
jettonForwardTonAmount,
|
|
797
|
+
jettonForwardPayload,
|
|
798
|
+
}),
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
else {
|
|
802
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(toString(params.sender), toString(params.asset));
|
|
803
|
+
const senderJettonWallet = this.open(jetton_wallet_1.JettonWallet.createFromAddress(senderJettonWalletAddress));
|
|
804
|
+
await senderJettonWallet.sendTransfer(sender, gas + jetton_wallet_1.JettonWallet.Gas.Transfer, {
|
|
805
|
+
recipient: toAddress(params.pool),
|
|
806
|
+
response: toAddress(params.response),
|
|
807
|
+
amount: params.amount,
|
|
808
|
+
forwardTonAmount: gas,
|
|
809
|
+
forwardPayload: pool_1.Pool.createRepayPayload({
|
|
810
|
+
asset: toAddress(params.asset),
|
|
811
|
+
recipient: toAddress(params.recipient),
|
|
812
|
+
response: toAddress(params.response),
|
|
813
|
+
jettonForwardTonAmount,
|
|
814
|
+
jettonForwardPayload,
|
|
815
|
+
}),
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
async repayAndWaitTx(sender, params, callbackFn) {
|
|
820
|
+
const isWTON = toString(params.asset) == this.contracts.WTON;
|
|
821
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
822
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
823
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(toString(params.sender), toString(params.asset));
|
|
824
|
+
const senderJettonWallet = this.open(jetton_wallet_1.JettonWallet.createFromAddress(senderJettonWalletAddress));
|
|
825
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
826
|
+
const poolJettonWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
827
|
+
const poolData = await pool.getPoolData();
|
|
828
|
+
const recipientAccountAddress = await this.getAccountAddress(toString(params.recipient), toString(params.pool));
|
|
829
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Repay, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, false, poolData.minimumGasFee);
|
|
830
|
+
const opts = {
|
|
831
|
+
recipient: toAddress(params.pool),
|
|
832
|
+
response: toAddress(params.response),
|
|
833
|
+
amount: params.amount,
|
|
834
|
+
forwardTonAmount: gas,
|
|
835
|
+
forwardPayload: pool_1.Pool.createRepayPayload({
|
|
836
|
+
asset: toAddress(params.asset),
|
|
837
|
+
recipient: toAddress(params.recipient),
|
|
838
|
+
response: toAddress(params.response),
|
|
839
|
+
jettonForwardTonAmount,
|
|
840
|
+
jettonForwardPayload,
|
|
841
|
+
}),
|
|
842
|
+
};
|
|
843
|
+
const body = senderJettonWallet.createTransferBody(opts);
|
|
844
|
+
const queryId = (0, query_id_generactor_1.generateQueryId)(toAddress(params.sender), body);
|
|
845
|
+
const steps = [];
|
|
846
|
+
if (toString(params.asset) == this.contracts.WTON) {
|
|
847
|
+
const poolWTONWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
848
|
+
const poolWTONWallet = this.open(jetton_wallet_2.WTONWallet.createFromAddress(poolWTONWalletAddress));
|
|
849
|
+
await poolWTONWallet.sendExternalTransfer(sender, jetton_wallet_2.WTONWallet.Gas.ExternalTransfer, {
|
|
850
|
+
queryId: queryId,
|
|
851
|
+
...opts,
|
|
852
|
+
});
|
|
853
|
+
steps.push(...[
|
|
854
|
+
{
|
|
855
|
+
queryId,
|
|
856
|
+
description: "Sending the tx",
|
|
857
|
+
from: toAddress(params.sender),
|
|
858
|
+
to: poolWTONWalletAddress,
|
|
859
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
860
|
+
},
|
|
861
|
+
{
|
|
862
|
+
queryId,
|
|
863
|
+
description: "Repaying jetton to the pool",
|
|
864
|
+
from: toAddress(params.sender),
|
|
865
|
+
to: poolWTONWalletAddress,
|
|
866
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
867
|
+
},
|
|
868
|
+
]);
|
|
869
|
+
}
|
|
870
|
+
else {
|
|
871
|
+
await senderJettonWallet.sendTransfer(sender, gas + jetton_wallet_1.JettonWallet.Gas.Transfer, {
|
|
872
|
+
...opts,
|
|
873
|
+
queryId,
|
|
874
|
+
});
|
|
875
|
+
steps.push(...[
|
|
876
|
+
{
|
|
877
|
+
queryId,
|
|
878
|
+
description: "Sending the tx",
|
|
879
|
+
from: toAddress(params.sender),
|
|
880
|
+
to: senderJettonWalletAddress,
|
|
881
|
+
opcode: jetton_wallet_1.JettonWallet.Op.Transfer,
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
queryId,
|
|
885
|
+
description: "Repaying jetton to the pool",
|
|
886
|
+
from: senderJettonWalletAddress,
|
|
887
|
+
to: poolJettonWalletAddress,
|
|
888
|
+
opcode: jetton_wallet_1.JettonWallet.Op.InternalTransfer,
|
|
889
|
+
},
|
|
890
|
+
]);
|
|
891
|
+
}
|
|
892
|
+
steps.push(...[
|
|
893
|
+
{
|
|
894
|
+
queryId,
|
|
895
|
+
description: "Pool notification",
|
|
896
|
+
from: poolJettonWalletAddress,
|
|
897
|
+
to: pool.address,
|
|
898
|
+
opcode: jetton_wallet_1.JettonWallet.Op.TransferNotification,
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
queryId,
|
|
902
|
+
description: "Updating the account",
|
|
903
|
+
from: pool.address,
|
|
904
|
+
to: recipientAccountAddress,
|
|
905
|
+
opcode: pool_1.Pool.Op.ExecuteAction,
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
queryId,
|
|
909
|
+
description: "Action notification",
|
|
910
|
+
from: pool.address,
|
|
911
|
+
to: toAddress(params.sender),
|
|
912
|
+
opcode: pool_1.Pool.Op.ActionNotification,
|
|
913
|
+
},
|
|
914
|
+
]);
|
|
915
|
+
(async () => {
|
|
916
|
+
const matchedTx0 = await this.findAndCallback(toAddress(params.sender), steps[0], "0", callbackFn);
|
|
917
|
+
const matchedTx1 = await this.findAndCallback(poolJettonWalletAddress, steps[1], matchedTx0.lt.toString(), callbackFn);
|
|
918
|
+
const matchedTx2 = await this.findAndCallback(pool.address, steps[2], matchedTx1.lt.toString(), callbackFn);
|
|
919
|
+
const matchedTx3 = await this.findAndCallback(recipientAccountAddress, steps[3], matchedTx2.lt.toString(), callbackFn);
|
|
920
|
+
const matchedTx4 = await this.findAndCallback(toAddress(params.sender), steps[4], matchedTx3.lt.toString(), callbackFn);
|
|
921
|
+
})();
|
|
922
|
+
return {
|
|
923
|
+
action: {
|
|
924
|
+
type: "pool-repay",
|
|
925
|
+
params,
|
|
926
|
+
queryId,
|
|
927
|
+
},
|
|
928
|
+
steps,
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
async findRepayTx(queryId, params, callbackFn) {
|
|
932
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(toString(params.sender), toString(params.asset));
|
|
933
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
934
|
+
const poolJettonWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
935
|
+
const recipientAccountAddress = await this.getAccountAddress(toString(params.recipient), toString(params.pool));
|
|
936
|
+
const steps = [];
|
|
937
|
+
if (toString(params.asset) == this.contracts.WTON) {
|
|
938
|
+
const poolWTONWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.asset));
|
|
939
|
+
steps.push(...[
|
|
940
|
+
{
|
|
941
|
+
queryId,
|
|
942
|
+
description: "Sending the tx",
|
|
943
|
+
from: toAddress(params.sender),
|
|
944
|
+
to: poolWTONWalletAddress,
|
|
945
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
queryId,
|
|
949
|
+
description: "Repaying jetton to the pool",
|
|
950
|
+
from: toAddress(params.sender),
|
|
951
|
+
to: poolWTONWalletAddress,
|
|
952
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
953
|
+
},
|
|
954
|
+
]);
|
|
955
|
+
}
|
|
956
|
+
else {
|
|
957
|
+
steps.push(...[
|
|
958
|
+
{
|
|
959
|
+
queryId,
|
|
960
|
+
description: "Sending the tx",
|
|
961
|
+
from: toAddress(params.sender),
|
|
962
|
+
to: senderJettonWalletAddress,
|
|
963
|
+
opcode: jetton_wallet_1.JettonWallet.Op.Transfer,
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
queryId,
|
|
967
|
+
description: "Repaying jetton to the pool",
|
|
968
|
+
from: senderJettonWalletAddress,
|
|
969
|
+
to: poolJettonWalletAddress,
|
|
970
|
+
opcode: jetton_wallet_1.JettonWallet.Op.InternalTransfer,
|
|
971
|
+
},
|
|
972
|
+
]);
|
|
973
|
+
}
|
|
974
|
+
steps.push(...[
|
|
975
|
+
{
|
|
976
|
+
queryId,
|
|
977
|
+
description: "Pool notification",
|
|
978
|
+
from: poolJettonWalletAddress,
|
|
979
|
+
to: pool.address,
|
|
980
|
+
opcode: jetton_wallet_1.JettonWallet.Op.TransferNotification,
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
queryId,
|
|
984
|
+
description: "Updating the account",
|
|
985
|
+
from: pool.address,
|
|
986
|
+
to: recipientAccountAddress,
|
|
987
|
+
opcode: pool_1.Pool.Op.ExecuteAction,
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
queryId,
|
|
991
|
+
description: "Action notification",
|
|
992
|
+
from: pool.address,
|
|
993
|
+
to: toAddress(params.sender),
|
|
994
|
+
opcode: pool_1.Pool.Op.ActionNotification,
|
|
995
|
+
},
|
|
996
|
+
]);
|
|
997
|
+
(async () => {
|
|
998
|
+
const matchedTx0 = await this.findAndCallback(toAddress(params.sender), steps[0], "0", callbackFn);
|
|
999
|
+
const matchedTx1 = await this.findAndCallback(poolJettonWalletAddress, steps[1], matchedTx0.lt.toString(), callbackFn);
|
|
1000
|
+
const matchedTx2 = await this.findAndCallback(pool.address, steps[2], matchedTx1.lt.toString(), callbackFn);
|
|
1001
|
+
const matchedTx3 = await this.findAndCallback(recipientAccountAddress, steps[3], matchedTx2.lt.toString(), callbackFn);
|
|
1002
|
+
const matchedTx4 = await this.findAndCallback(toAddress(params.sender), steps[4], matchedTx3.lt.toString(), callbackFn);
|
|
1003
|
+
})();
|
|
1004
|
+
return {
|
|
1005
|
+
action: {
|
|
1006
|
+
type: "pool-repay",
|
|
1007
|
+
params,
|
|
1008
|
+
queryId,
|
|
1009
|
+
},
|
|
1010
|
+
steps,
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
async liquidateSimulate(params) {
|
|
1014
|
+
const isWTON = toString(params.repayAsset) == this.contracts.WTON;
|
|
1015
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
1016
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
1017
|
+
const borrowerAccountAddress = await this.getAccountAddress(toString(params.borrower), toString(params.pool));
|
|
1018
|
+
const borrowerAccount = this.open(account_1.Account.createFromAddress(toAddress(borrowerAccountAddress)));
|
|
1019
|
+
const accountData = await borrowerAccount.getAccountData();
|
|
1020
|
+
const assets = [...new Set([...account_1.Account.haveAssets(accountData)])];
|
|
1021
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
1022
|
+
const poolData = (await pool.getPoolData());
|
|
1023
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
1024
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
1025
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
1026
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
1027
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
1028
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
1029
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
1030
|
+
const oracleParams = (0, ton_1.beginCell)()
|
|
1031
|
+
.storeRef(feedIdCell)
|
|
1032
|
+
.storeRef(payload)
|
|
1033
|
+
.storeRef(requestAssetCell)
|
|
1034
|
+
.endCell();
|
|
1035
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Liquidate, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, false, poolData.minimumGasFee);
|
|
1036
|
+
if (toString(params.repayAsset) == this.contracts.WTON) {
|
|
1037
|
+
const poolWTONWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.repayAsset));
|
|
1038
|
+
const poolWTONWallet = this.open(jetton_wallet_2.WTONWallet.createFromAddress(poolWTONWalletAddress));
|
|
1039
|
+
// await poolWTONWallet.sendExternalTransfer(sender, WTONWallet.Gas.ExternalTransfer, {
|
|
1040
|
+
// recipient: toAddress(params.pool),
|
|
1041
|
+
// response: toAddress(params.response),
|
|
1042
|
+
// amount: params.amount,
|
|
1043
|
+
// forwardTonAmount: gas,
|
|
1044
|
+
// forwardPayload: Pool.createLiquidatePayload({
|
|
1045
|
+
// repayAsset: toAddress(params.repayAsset),
|
|
1046
|
+
// seizeAsset: toAddress(params.seizeAsset),
|
|
1047
|
+
// borrower: toAddress(params.borrower),
|
|
1048
|
+
// response: toAddress(params.response),
|
|
1049
|
+
// jettonForwardTonAmount,
|
|
1050
|
+
// jettonForwardPayload,
|
|
1051
|
+
// oracleParams,
|
|
1052
|
+
// }),
|
|
1053
|
+
// });
|
|
1054
|
+
}
|
|
1055
|
+
else {
|
|
1056
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(toString(params.sender), toString(params.repayAsset));
|
|
1057
|
+
const senderJettonWallet = this.open(jetton_wallet_1.JettonWallet.createFromAddress(senderJettonWalletAddress));
|
|
1058
|
+
// await senderJettonWallet.sendTransfer(sender, gas + JettonWallet.Gas.Transfer, {
|
|
1059
|
+
// recipient: toAddress(params.pool),
|
|
1060
|
+
// response: toAddress(params.response),
|
|
1061
|
+
// amount: params.amount,
|
|
1062
|
+
// forwardTonAmount: gas,
|
|
1063
|
+
// forwardPayload: Pool.createLiquidatePayload({
|
|
1064
|
+
// repayAsset: toAddress(params.repayAsset),
|
|
1065
|
+
// seizeAsset: toAddress(params.seizeAsset),
|
|
1066
|
+
// borrower: toAddress(params.borrower),
|
|
1067
|
+
// response: toAddress(params.response),
|
|
1068
|
+
// jettonForwardTonAmount,
|
|
1069
|
+
// jettonForwardPayload,
|
|
1070
|
+
// oracleParams,
|
|
1071
|
+
// }),
|
|
1072
|
+
// });
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
async liquidateAndWaitTxSimulate(queryId, params, callbackFn) {
|
|
1076
|
+
const isWTON = toString(params.repayAsset) == this.contracts.WTON;
|
|
1077
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
1078
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
1079
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(toString(params.sender), toString(params.repayAsset));
|
|
1080
|
+
const senderJettonWallet = this.open(jetton_wallet_1.JettonWallet.createFromAddress(senderJettonWalletAddress));
|
|
1081
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
1082
|
+
const poolJettonWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.repayAsset));
|
|
1083
|
+
const senderAccountAddress = await this.getAccountAddress(toString(params.sender), toString(params.pool));
|
|
1084
|
+
const borrowerAccountAddress = await this.getAccountAddress(toString(params.borrower), toString(params.pool));
|
|
1085
|
+
const borrowerAccount = this.open(account_1.Account.createFromAddress(toAddress(borrowerAccountAddress)));
|
|
1086
|
+
const accountData = await borrowerAccount.getAccountData();
|
|
1087
|
+
const assets = [...new Set([...account_1.Account.haveAssets(accountData)])];
|
|
1088
|
+
const poolData = (await pool.getPoolData());
|
|
1089
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
1090
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
1091
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
1092
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
1093
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
1094
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
1095
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
1096
|
+
const oracleParams = (0, ton_1.beginCell)()
|
|
1097
|
+
.storeRef(feedIdCell)
|
|
1098
|
+
.storeRef(payload)
|
|
1099
|
+
.storeRef(requestAssetCell)
|
|
1100
|
+
.endCell();
|
|
1101
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Liquidate, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, false, poolData.minimumGasFee);
|
|
1102
|
+
const opts = {
|
|
1103
|
+
recipient: toAddress(params.pool),
|
|
1104
|
+
response: toAddress(params.response),
|
|
1105
|
+
amount: params.amount,
|
|
1106
|
+
forwardTonAmount: gas,
|
|
1107
|
+
forwardPayload: pool_1.Pool.createLiquidatePayload({
|
|
1108
|
+
repayAsset: toAddress(params.repayAsset),
|
|
1109
|
+
seizeAsset: toAddress(params.seizeAsset),
|
|
1110
|
+
borrower: toAddress(params.borrower),
|
|
1111
|
+
response: toAddress(params.response),
|
|
1112
|
+
jettonForwardTonAmount,
|
|
1113
|
+
jettonForwardPayload,
|
|
1114
|
+
oracleParams,
|
|
1115
|
+
}),
|
|
1116
|
+
};
|
|
1117
|
+
const body = senderJettonWallet.createTransferBody(opts);
|
|
1118
|
+
const steps = [];
|
|
1119
|
+
if (toString(params.repayAsset) == this.contracts.WTON) {
|
|
1120
|
+
const poolWTONWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.repayAsset));
|
|
1121
|
+
const poolWTONWallet = this.open(jetton_wallet_2.WTONWallet.createFromAddress(poolWTONWalletAddress));
|
|
1122
|
+
// await poolWTONWallet.sendExternalTransfer(sender, WTONWallet.Gas.ExternalTransfer, {
|
|
1123
|
+
// queryId: queryId,
|
|
1124
|
+
// ...opts,
|
|
1125
|
+
// });
|
|
1126
|
+
steps.push(...[
|
|
1127
|
+
{
|
|
1128
|
+
queryId,
|
|
1129
|
+
description: "tx send",
|
|
1130
|
+
from: toAddress(params.sender),
|
|
1131
|
+
to: poolWTONWalletAddress,
|
|
1132
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
1133
|
+
},
|
|
1134
|
+
{
|
|
1135
|
+
queryId,
|
|
1136
|
+
description: "send wton transfer to pool",
|
|
1137
|
+
from: toAddress(params.sender),
|
|
1138
|
+
to: poolWTONWalletAddress,
|
|
1139
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
1140
|
+
},
|
|
1141
|
+
]);
|
|
1142
|
+
}
|
|
1143
|
+
else {
|
|
1144
|
+
// await senderJettonWallet.sendTransfer(sender, gas + JettonWallet.Gas.Transfer, {
|
|
1145
|
+
// ...opts,
|
|
1146
|
+
// queryId,
|
|
1147
|
+
// });
|
|
1148
|
+
steps.push(...[
|
|
1149
|
+
{
|
|
1150
|
+
queryId,
|
|
1151
|
+
description: "tx send",
|
|
1152
|
+
from: toAddress(params.sender),
|
|
1153
|
+
to: senderJettonWalletAddress,
|
|
1154
|
+
opcode: jetton_wallet_1.JettonWallet.Op.Transfer,
|
|
1155
|
+
},
|
|
1156
|
+
{
|
|
1157
|
+
queryId,
|
|
1158
|
+
description: "send jetton transfer to pool",
|
|
1159
|
+
from: senderJettonWalletAddress,
|
|
1160
|
+
to: poolJettonWalletAddress,
|
|
1161
|
+
opcode: jetton_wallet_1.JettonWallet.Op.InternalTransfer,
|
|
1162
|
+
},
|
|
1163
|
+
]);
|
|
1164
|
+
}
|
|
1165
|
+
steps.push(...[
|
|
1166
|
+
{
|
|
1167
|
+
queryId,
|
|
1168
|
+
description: "pool notification",
|
|
1169
|
+
from: poolJettonWalletAddress,
|
|
1170
|
+
to: pool.address,
|
|
1171
|
+
opcode: jetton_wallet_1.JettonWallet.Op.TransferNotification,
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
queryId,
|
|
1175
|
+
description: "unlock & update account",
|
|
1176
|
+
from: pool.address,
|
|
1177
|
+
to: borrowerAccountAddress,
|
|
1178
|
+
opcode: pool_1.Pool.Op.ExecuteAction,
|
|
1179
|
+
},
|
|
1180
|
+
{
|
|
1181
|
+
queryId,
|
|
1182
|
+
description: "send seize collateral token",
|
|
1183
|
+
from: pool.address,
|
|
1184
|
+
to: senderAccountAddress,
|
|
1185
|
+
},
|
|
1186
|
+
{
|
|
1187
|
+
queryId,
|
|
1188
|
+
description: "action notification",
|
|
1189
|
+
from: pool.address,
|
|
1190
|
+
to: toAddress(params.sender),
|
|
1191
|
+
},
|
|
1192
|
+
]);
|
|
1193
|
+
(async () => {
|
|
1194
|
+
const matchedTx0 = await this.findAndCallback(toAddress(params.sender), steps[0], "0", callbackFn);
|
|
1195
|
+
const matchedTx1 = await this.findAndCallback(poolJettonWalletAddress, steps[1], matchedTx0.lt.toString(), callbackFn);
|
|
1196
|
+
const matchedTx2 = await this.findAndCallback(pool.address, steps[2], matchedTx1.lt.toString(), callbackFn);
|
|
1197
|
+
const matchedTx3 = await this.findAndCallback(borrowerAccountAddress, steps[3], matchedTx2.lt.toString(), callbackFn);
|
|
1198
|
+
const matchedTx4 = await this.findAndCallback(senderAccountAddress, steps[4], matchedTx3.lt.toString(), callbackFn);
|
|
1199
|
+
const matchedTx5 = await this.findAndCallback(toAddress(params.sender), steps[5], matchedTx4.lt.toString(), callbackFn);
|
|
1200
|
+
})();
|
|
1201
|
+
return steps;
|
|
1202
|
+
}
|
|
1203
|
+
async liquidate(sender, params) {
|
|
1204
|
+
const isWTON = toString(params.repayAsset) == this.contracts.WTON;
|
|
1205
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
1206
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
1207
|
+
const borrowerAccountAddress = await this.getAccountAddress(toString(params.borrower), toString(params.pool));
|
|
1208
|
+
const borrowerAccount = this.open(account_1.Account.createFromAddress(toAddress(borrowerAccountAddress)));
|
|
1209
|
+
const accountData = await borrowerAccount.getAccountData();
|
|
1210
|
+
const assets = [...new Set([...account_1.Account.haveAssets(accountData)])];
|
|
1211
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
1212
|
+
const poolData = (await pool.getPoolData());
|
|
1213
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
1214
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
1215
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
1216
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
1217
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
1218
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
1219
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
1220
|
+
const oracleParams = (0, ton_1.beginCell)()
|
|
1221
|
+
.storeRef(feedIdCell)
|
|
1222
|
+
.storeRef(payload)
|
|
1223
|
+
.storeRef(requestAssetCell)
|
|
1224
|
+
.endCell();
|
|
1225
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Liquidate, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, false, poolData.minimumGasFee);
|
|
1226
|
+
if (toString(params.repayAsset) == this.contracts.WTON) {
|
|
1227
|
+
const poolWTONWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.repayAsset));
|
|
1228
|
+
const poolWTONWallet = this.open(jetton_wallet_2.WTONWallet.createFromAddress(poolWTONWalletAddress));
|
|
1229
|
+
await poolWTONWallet.sendExternalTransfer(sender, jetton_wallet_2.WTONWallet.Gas.ExternalTransfer, {
|
|
1230
|
+
recipient: toAddress(params.pool),
|
|
1231
|
+
response: toAddress(params.response),
|
|
1232
|
+
amount: params.amount,
|
|
1233
|
+
forwardTonAmount: gas,
|
|
1234
|
+
forwardPayload: pool_1.Pool.createLiquidatePayload({
|
|
1235
|
+
repayAsset: toAddress(params.repayAsset),
|
|
1236
|
+
seizeAsset: toAddress(params.seizeAsset),
|
|
1237
|
+
borrower: toAddress(params.borrower),
|
|
1238
|
+
response: toAddress(params.response),
|
|
1239
|
+
jettonForwardTonAmount,
|
|
1240
|
+
jettonForwardPayload,
|
|
1241
|
+
oracleParams,
|
|
1242
|
+
}),
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
else {
|
|
1246
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(toString(params.sender), toString(params.repayAsset));
|
|
1247
|
+
const senderJettonWallet = this.open(jetton_wallet_1.JettonWallet.createFromAddress(senderJettonWalletAddress));
|
|
1248
|
+
await senderJettonWallet.sendTransfer(sender, gas + jetton_wallet_1.JettonWallet.Gas.Transfer, {
|
|
1249
|
+
recipient: toAddress(params.pool),
|
|
1250
|
+
response: toAddress(params.response),
|
|
1251
|
+
amount: params.amount,
|
|
1252
|
+
forwardTonAmount: gas,
|
|
1253
|
+
forwardPayload: pool_1.Pool.createLiquidatePayload({
|
|
1254
|
+
repayAsset: toAddress(params.repayAsset),
|
|
1255
|
+
seizeAsset: toAddress(params.seizeAsset),
|
|
1256
|
+
borrower: toAddress(params.borrower),
|
|
1257
|
+
response: toAddress(params.response),
|
|
1258
|
+
jettonForwardTonAmount,
|
|
1259
|
+
jettonForwardPayload,
|
|
1260
|
+
oracleParams,
|
|
1261
|
+
}),
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
async liquidateAndWaitTx(sender, params, callbackFn) {
|
|
1266
|
+
const isWTON = toString(params.repayAsset) == this.contracts.WTON;
|
|
1267
|
+
const jettonForwardTonAmount = isWTON ? (0, ton_1.toNano)(0.02) : 0n;
|
|
1268
|
+
const jettonForwardPayload = isWTON ? jetton_minter_2.WTON_UNWRAP_CELL : null;
|
|
1269
|
+
const senderJettonWalletAddress = await this.getJettonWalletAddress(toString(params.sender), toString(params.repayAsset));
|
|
1270
|
+
const senderJettonWallet = this.open(jetton_wallet_1.JettonWallet.createFromAddress(senderJettonWalletAddress));
|
|
1271
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(params.pool)));
|
|
1272
|
+
const poolJettonWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.repayAsset));
|
|
1273
|
+
const senderAccountAddress = await this.getAccountAddress(toString(params.sender), toString(params.pool));
|
|
1274
|
+
const borrowerAccountAddress = await this.getAccountAddress(toString(params.borrower), toString(params.pool));
|
|
1275
|
+
const borrowerAccount = this.open(account_1.Account.createFromAddress(toAddress(borrowerAccountAddress)));
|
|
1276
|
+
const poolData = (await pool.getPoolData());
|
|
1277
|
+
const accountData = await borrowerAccount.getAccountData();
|
|
1278
|
+
const userAssets = [...new Set([...account_1.Account.haveAssets(accountData)])];
|
|
1279
|
+
let { assets, vaultAssets } = await this.separateAssets(userAssets, poolData.oracleConfig);
|
|
1280
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
1281
|
+
const vaultPositions = await this.getParsedVaults(vaultAssets);
|
|
1282
|
+
const exposures = await this.getExposures(vaultPositions);
|
|
1283
|
+
const exposurePools = exposures.pools;
|
|
1284
|
+
assets = [...new Set([...assets, ...exposures.assets])];
|
|
1285
|
+
let requestFactorialPoolsCell = exposurePools.length > 0
|
|
1286
|
+
? redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(exposurePools.map((pool) => ton_1.Address.parse(pool)))
|
|
1287
|
+
: null;
|
|
1288
|
+
let requestFactorialVaultsCell = vaultAssets.length > 0
|
|
1289
|
+
? redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(vaultAssets.map((vault) => ton_1.Address.parse(vault)))
|
|
1290
|
+
: null;
|
|
1291
|
+
let requestFactorialCell = (0, ton_1.beginCell)()
|
|
1292
|
+
.storeMaybeRef(requestFactorialPoolsCell)
|
|
1293
|
+
.storeMaybeRef(requestFactorialVaultsCell)
|
|
1294
|
+
.endCell();
|
|
1295
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
1296
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
1297
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
1298
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
1299
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
1300
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
1301
|
+
const oracleParams = (0, ton_1.beginCell)()
|
|
1302
|
+
.storeRef(feedIdCell)
|
|
1303
|
+
.storeRef(payload)
|
|
1304
|
+
.storeRef(requestAssetCell)
|
|
1305
|
+
.storeRef(requestFactorialCell)
|
|
1306
|
+
.endCell();
|
|
1307
|
+
const gas = pool_1.Pool.calculateGasFee(pool_1.Pool.Op.Liquidate, pool_1.Pool.Gas.baseFee, pool_1.Pool.Gas.forwardFee, jettonForwardTonAmount, !poolData.oracle, false, poolData.minimumGasFee);
|
|
1308
|
+
const opts = {
|
|
1309
|
+
recipient: toAddress(params.pool),
|
|
1310
|
+
response: toAddress(params.response),
|
|
1311
|
+
amount: params.amount,
|
|
1312
|
+
forwardTonAmount: gas,
|
|
1313
|
+
forwardPayload: pool_1.Pool.createLiquidatePayload({
|
|
1314
|
+
repayAsset: toAddress(params.repayAsset),
|
|
1315
|
+
seizeAsset: toAddress(params.seizeAsset),
|
|
1316
|
+
borrower: toAddress(params.borrower),
|
|
1317
|
+
response: toAddress(params.response),
|
|
1318
|
+
jettonForwardTonAmount,
|
|
1319
|
+
jettonForwardPayload,
|
|
1320
|
+
oracleParams,
|
|
1321
|
+
}),
|
|
1322
|
+
};
|
|
1323
|
+
const body = senderJettonWallet.createTransferBody(opts);
|
|
1324
|
+
const queryId = (0, query_id_generactor_1.generateQueryId)(toAddress(params.sender), body);
|
|
1325
|
+
const steps = [];
|
|
1326
|
+
if (toString(params.repayAsset) == this.contracts.WTON) {
|
|
1327
|
+
const poolWTONWalletAddress = await this.getJettonWalletAddress(toString(params.pool), toString(params.repayAsset));
|
|
1328
|
+
const poolWTONWallet = this.open(jetton_wallet_2.WTONWallet.createFromAddress(poolWTONWalletAddress));
|
|
1329
|
+
await poolWTONWallet.sendExternalTransfer(sender, jetton_wallet_2.WTONWallet.Gas.ExternalTransfer, {
|
|
1330
|
+
queryId: queryId,
|
|
1331
|
+
...opts,
|
|
1332
|
+
});
|
|
1333
|
+
steps.push(...[
|
|
1334
|
+
{
|
|
1335
|
+
queryId,
|
|
1336
|
+
description: "tx send",
|
|
1337
|
+
from: toAddress(params.sender),
|
|
1338
|
+
to: poolWTONWalletAddress,
|
|
1339
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
queryId,
|
|
1343
|
+
description: "send wton transfer to pool",
|
|
1344
|
+
from: toAddress(params.sender),
|
|
1345
|
+
to: poolWTONWalletAddress,
|
|
1346
|
+
opcode: jetton_wallet_2.WTONWallet.Op.ExternalTransfer,
|
|
1347
|
+
},
|
|
1348
|
+
]);
|
|
1349
|
+
}
|
|
1350
|
+
else {
|
|
1351
|
+
await senderJettonWallet.sendTransfer(sender, gas + jetton_wallet_1.JettonWallet.Gas.Transfer, {
|
|
1352
|
+
...opts,
|
|
1353
|
+
queryId,
|
|
1354
|
+
});
|
|
1355
|
+
steps.push(...[
|
|
1356
|
+
{
|
|
1357
|
+
queryId,
|
|
1358
|
+
description: "tx send",
|
|
1359
|
+
from: toAddress(params.sender),
|
|
1360
|
+
to: senderJettonWalletAddress,
|
|
1361
|
+
opcode: jetton_wallet_1.JettonWallet.Op.Transfer,
|
|
1362
|
+
},
|
|
1363
|
+
{
|
|
1364
|
+
queryId,
|
|
1365
|
+
description: "send jetton transfer to pool",
|
|
1366
|
+
from: senderJettonWalletAddress,
|
|
1367
|
+
to: poolJettonWalletAddress,
|
|
1368
|
+
opcode: jetton_wallet_1.JettonWallet.Op.InternalTransfer,
|
|
1369
|
+
},
|
|
1370
|
+
]);
|
|
1371
|
+
}
|
|
1372
|
+
steps.push(...[
|
|
1373
|
+
{
|
|
1374
|
+
queryId,
|
|
1375
|
+
description: "pool notification",
|
|
1376
|
+
from: poolJettonWalletAddress,
|
|
1377
|
+
to: pool.address,
|
|
1378
|
+
opcode: jetton_wallet_1.JettonWallet.Op.TransferNotification,
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
queryId,
|
|
1382
|
+
description: "unlock & update account",
|
|
1383
|
+
from: pool.address,
|
|
1384
|
+
to: borrowerAccountAddress,
|
|
1385
|
+
opcode: pool_1.Pool.Op.ExecuteAction,
|
|
1386
|
+
},
|
|
1387
|
+
{
|
|
1388
|
+
queryId,
|
|
1389
|
+
description: "send seize collateral token",
|
|
1390
|
+
from: pool.address,
|
|
1391
|
+
to: senderAccountAddress,
|
|
1392
|
+
},
|
|
1393
|
+
{
|
|
1394
|
+
queryId,
|
|
1395
|
+
description: "action notification",
|
|
1396
|
+
from: pool.address,
|
|
1397
|
+
to: toAddress(params.sender),
|
|
1398
|
+
},
|
|
1399
|
+
]);
|
|
1400
|
+
(async () => {
|
|
1401
|
+
const matchedTx0 = await this.findAndCallback(toAddress(params.sender), steps[0], "0", callbackFn);
|
|
1402
|
+
const matchedTx1 = await this.findAndCallback(poolJettonWalletAddress, steps[1], matchedTx0.lt.toString(), callbackFn);
|
|
1403
|
+
const matchedTx2 = await this.findAndCallback(pool.address, steps[2], matchedTx1.lt.toString(), callbackFn);
|
|
1404
|
+
const matchedTx3 = await this.findAndCallback(borrowerAccountAddress, steps[3], matchedTx2.lt.toString(), callbackFn);
|
|
1405
|
+
const matchedTx4 = await this.findAndCallback(senderAccountAddress, steps[4], matchedTx3.lt.toString(), callbackFn);
|
|
1406
|
+
const matchedTx5 = await this.findAndCallback(toAddress(params.sender), steps[5], matchedTx4.lt.toString(), callbackFn);
|
|
1407
|
+
})();
|
|
1408
|
+
return {
|
|
1409
|
+
action: {
|
|
1410
|
+
type: "pool-liquidate",
|
|
1411
|
+
params,
|
|
1412
|
+
queryId,
|
|
1413
|
+
},
|
|
1414
|
+
steps,
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
async updateOnchainData(onchainDataInfo) {
|
|
1418
|
+
for (let [asset, data] of Object.entries(onchainDataInfo)) {
|
|
1419
|
+
if (data.sourceType === redstone_onchain_oracle_1.RedstoneOnchainOracle.SourceType.tonstakers &&
|
|
1420
|
+
"underlyingAddress" in data) {
|
|
1421
|
+
const result = await this.client
|
|
1422
|
+
.provider(ton_1.Address.parse(data.sourceAddress.toString()))
|
|
1423
|
+
.get("get_pool_state", []);
|
|
1424
|
+
result.stack.readBigNumber();
|
|
1425
|
+
data.underlyingReserve = result.stack.readBigNumber();
|
|
1426
|
+
data.totalSupply = result.stack.readBigNumber();
|
|
1427
|
+
}
|
|
1428
|
+
else if (data.sourceType === redstone_onchain_oracle_1.RedstoneOnchainOracle.SourceType.dedust &&
|
|
1429
|
+
data.assetType === type_1.AssetType.MultiAsset) {
|
|
1430
|
+
if (this.network === "mainnet") {
|
|
1431
|
+
const results = await Promise.all([
|
|
1432
|
+
this.client
|
|
1433
|
+
.provider(ton_1.Address.parse(data.sourceAddress.toString()))
|
|
1434
|
+
.get("get_reserves", []),
|
|
1435
|
+
this.client
|
|
1436
|
+
.provider(ton_1.Address.parse(data.sourceAddress.toString()))
|
|
1437
|
+
.get("get_jetton_data", []),
|
|
1438
|
+
]);
|
|
1439
|
+
data.underlying0Reserve = results[0].stack.readBigNumber();
|
|
1440
|
+
data.underlying1Reserve = results[0].stack.readBigNumber();
|
|
1441
|
+
data.totalSupply = results[1].stack.readBigNumber();
|
|
1442
|
+
}
|
|
1443
|
+
else {
|
|
1444
|
+
const result = await this.client
|
|
1445
|
+
.provider(ton_1.Address.parse(data.sourceAddress.toString()))
|
|
1446
|
+
.get("get_pool_state", []);
|
|
1447
|
+
result.stack.readBigNumber();
|
|
1448
|
+
data.underlying0Reserve = result.stack.readBigNumber();
|
|
1449
|
+
data.underlying1Reserve = result.stack.readBigNumber();
|
|
1450
|
+
data.totalSupply = result.stack.readBigNumber();
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
else if (data.sourceType === redstone_onchain_oracle_1.RedstoneOnchainOracle.SourceType.stonfi &&
|
|
1454
|
+
data.assetType === type_1.AssetType.MultiAsset) {
|
|
1455
|
+
if (this.network === "mainnet") {
|
|
1456
|
+
const result = await this.client
|
|
1457
|
+
.provider(ton_1.Address.parse(data.sourceAddress.toString()))
|
|
1458
|
+
.get("get_pool_data", []);
|
|
1459
|
+
result.stack.readNumber();
|
|
1460
|
+
result.stack.readAddress();
|
|
1461
|
+
data.totalSupply = result.stack.readBigNumber();
|
|
1462
|
+
data.underlying0Reserve = result.stack.readBigNumber();
|
|
1463
|
+
data.underlying1Reserve = result.stack.readBigNumber();
|
|
1464
|
+
}
|
|
1465
|
+
else {
|
|
1466
|
+
const result = await this.client
|
|
1467
|
+
.provider(ton_1.Address.parse(data.sourceAddress.toString()))
|
|
1468
|
+
.get("get_pool_state", []);
|
|
1469
|
+
result.stack.readBigNumber();
|
|
1470
|
+
data.underlying0Reserve = result.stack.readBigNumber();
|
|
1471
|
+
data.underlying1Reserve = result.stack.readBigNumber();
|
|
1472
|
+
data.totalSupply = result.stack.readBigNumber();
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
else if (data.sourceType === redstone_onchain_oracle_1.RedstoneOnchainOracle.SourceType.storm &&
|
|
1476
|
+
data.assetType === type_1.AssetType.SingleAsset) {
|
|
1477
|
+
if (this.network === "mainnet") {
|
|
1478
|
+
const results = await this.client
|
|
1479
|
+
.provider(ton_1.Address.parse(data.sourceAddress.toString()))
|
|
1480
|
+
.get("get_vault_data", []);
|
|
1481
|
+
const jettonWalletAddress = results.stack.readAddress();
|
|
1482
|
+
const lpRate = results.stack.readBigNumber();
|
|
1483
|
+
const lpTotalSupply = results.stack.readBigNumber();
|
|
1484
|
+
const freeBalance = results.stack.readBigNumber();
|
|
1485
|
+
const lockedBalance = results.stack.readBigNumber();
|
|
1486
|
+
const withdrawLockedBalance = results.stack.readBigNumber();
|
|
1487
|
+
const stakersBalance = results.stack.readBigNumber();
|
|
1488
|
+
const executorsBalance = results.stack.readBigNumber();
|
|
1489
|
+
data.underlyingReserve = lpRate;
|
|
1490
|
+
if (!data.totalSupply) {
|
|
1491
|
+
data.totalSupply = BigInt(1e9);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
else {
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
else if (data.sourceType === redstone_onchain_oracle_1.RedstoneOnchainOracle.SourceType.tradoor &&
|
|
1498
|
+
data.assetType === type_1.AssetType.SingleAsset) {
|
|
1499
|
+
if (this.network === "mainnet") {
|
|
1500
|
+
const results = await this.client
|
|
1501
|
+
.provider(ton_1.Address.parse(data.sourceAddress.toString()))
|
|
1502
|
+
.get("tlpPrice", []);
|
|
1503
|
+
const lpRate = results.stack.readBigNumber();
|
|
1504
|
+
data.underlyingReserve = lpRate;
|
|
1505
|
+
if (!data.totalSupply) {
|
|
1506
|
+
data.totalSupply = BigInt(18e9);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
return onchainDataInfo;
|
|
1512
|
+
}
|
|
1513
|
+
async getRedstonePrices(assets, poolData) {
|
|
1514
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
1515
|
+
const redstonePrices = await readonlyCachedRedstone_1.ReadonlyCachedRedstone.getPrices(result.redstoneAssetNames);
|
|
1516
|
+
const prices = {};
|
|
1517
|
+
const onchainData = {};
|
|
1518
|
+
redstonePrices.forEach((item) => {
|
|
1519
|
+
try {
|
|
1520
|
+
const rainfo = poolData.oracleConfig.redstoneAssetInfo[item.feedId.toString()];
|
|
1521
|
+
if (rainfo.assetType === 0) {
|
|
1522
|
+
prices[rainfo.address.toString()] = {
|
|
1523
|
+
type: type_1.AssetType.Native,
|
|
1524
|
+
timestamp: item.timestamp,
|
|
1525
|
+
price: (item.price * BigInt(1e8)) / rainfo.precision,
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
else if (rainfo.assetType === 1) {
|
|
1529
|
+
onchainData[rainfo.address.toString()] = {
|
|
1530
|
+
assetType: type_1.AssetType.SingleAsset,
|
|
1531
|
+
underlyingAddress: rainfo.underlyingAddress,
|
|
1532
|
+
underlyingReserve: item.price,
|
|
1533
|
+
totalSupply: rainfo.precision,
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
catch (e) { }
|
|
1538
|
+
});
|
|
1539
|
+
return { redstonePrices: prices, onchainData };
|
|
1540
|
+
}
|
|
1541
|
+
calculatePrices(_prices, oracleData) {
|
|
1542
|
+
const prices = { ..._prices };
|
|
1543
|
+
let oracles = Object.entries(oracleData);
|
|
1544
|
+
while (oracles.length !== 0) {
|
|
1545
|
+
const restOracles = [];
|
|
1546
|
+
for (let [asset, onchainDataInfo] of oracles) {
|
|
1547
|
+
if (!onchainDataInfo)
|
|
1548
|
+
throw "not found onchain data info1";
|
|
1549
|
+
if (onchainDataInfo.assetType === type_1.AssetType.SingleAsset) {
|
|
1550
|
+
if (prices[onchainDataInfo.underlyingAddress.toString()]) {
|
|
1551
|
+
const underlyingPriceInfo = prices[onchainDataInfo.underlyingAddress.toString()];
|
|
1552
|
+
prices[asset.toString()] = {
|
|
1553
|
+
type: type_1.AssetType.SingleAsset,
|
|
1554
|
+
price: (underlyingPriceInfo.price *
|
|
1555
|
+
onchainDataInfo.underlyingReserve) /
|
|
1556
|
+
onchainDataInfo.totalSupply,
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
else {
|
|
1560
|
+
restOracles.push([asset, onchainDataInfo]);
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
else if (onchainDataInfo.assetType === type_1.AssetType.MultiAsset) {
|
|
1564
|
+
if (prices[onchainDataInfo.underlying0Address.toString()] &&
|
|
1565
|
+
prices[onchainDataInfo.underlying1Address.toString()]) {
|
|
1566
|
+
const underlying0PriceInfo = prices[onchainDataInfo.underlying0Address.toString()];
|
|
1567
|
+
const underlying1PriceInfo = prices[onchainDataInfo.underlying1Address.toString()];
|
|
1568
|
+
const price0 = (underlying0PriceInfo.price *
|
|
1569
|
+
onchainDataInfo.underlying0Reserve) /
|
|
1570
|
+
onchainDataInfo.totalSupply;
|
|
1571
|
+
const price1 = (underlying1PriceInfo.price *
|
|
1572
|
+
onchainDataInfo.underlying1Reserve) /
|
|
1573
|
+
onchainDataInfo.totalSupply;
|
|
1574
|
+
prices[asset.toString()] = {
|
|
1575
|
+
type: type_1.AssetType.MultiAsset,
|
|
1576
|
+
price: price0 + price1,
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
else {
|
|
1580
|
+
restOracles.push([asset, onchainDataInfo]);
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
else if (onchainDataInfo.assetType === type_1.AssetType.Native) {
|
|
1584
|
+
}
|
|
1585
|
+
else {
|
|
1586
|
+
throw `invalid asset type ${onchainDataInfo.assetType}`;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
oracles = restOracles;
|
|
1590
|
+
}
|
|
1591
|
+
return prices;
|
|
1592
|
+
}
|
|
1593
|
+
decomposeAccountStatus(accountStatus, prices, onchainData) {
|
|
1594
|
+
const accumStatus = {};
|
|
1595
|
+
let userAssets = Object.values(accountStatus);
|
|
1596
|
+
while (userAssets.length !== 0) {
|
|
1597
|
+
const restUserAssets = [];
|
|
1598
|
+
for (let i = 0; i < userAssets.length; i++) {
|
|
1599
|
+
const state = userAssets[i];
|
|
1600
|
+
if (state.supply > 0n || state.borrow > 0n) {
|
|
1601
|
+
accumStatus[userAssets[i].address.toString()] ??= {
|
|
1602
|
+
supply: 0n,
|
|
1603
|
+
borrow: 0n,
|
|
1604
|
+
};
|
|
1605
|
+
if (state.supply > 0n) {
|
|
1606
|
+
accumStatus[userAssets[i].address.toString()].supply +=
|
|
1607
|
+
state.supply;
|
|
1608
|
+
}
|
|
1609
|
+
if (state.borrow > 0n) {
|
|
1610
|
+
accumStatus[userAssets[i].address.toString()].borrow +=
|
|
1611
|
+
state.borrow;
|
|
1612
|
+
}
|
|
1613
|
+
const onchainDataInfo = onchainData[state.address.toString()];
|
|
1614
|
+
if (!onchainDataInfo && !prices[state.address.toString()]) {
|
|
1615
|
+
throw "not found onchain data info2";
|
|
1616
|
+
}
|
|
1617
|
+
if (onchainDataInfo) {
|
|
1618
|
+
if (onchainDataInfo.assetType === type_1.AssetType.SingleAsset &&
|
|
1619
|
+
onchainDataInfo.underlyingReserve &&
|
|
1620
|
+
onchainDataInfo.totalSupply) {
|
|
1621
|
+
const underlyingSupply = (state.supply * onchainDataInfo.underlyingReserve) /
|
|
1622
|
+
onchainDataInfo.totalSupply;
|
|
1623
|
+
const underlyingBorrow = (state.borrow * onchainDataInfo.underlyingReserve) /
|
|
1624
|
+
onchainDataInfo.totalSupply;
|
|
1625
|
+
restUserAssets.push({
|
|
1626
|
+
address: onchainDataInfo.underlyingAddress,
|
|
1627
|
+
supply: underlyingSupply,
|
|
1628
|
+
borrow: underlyingBorrow,
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
else if (onchainDataInfo.assetType === type_1.AssetType.MultiAsset &&
|
|
1632
|
+
onchainDataInfo.underlying0Reserve &&
|
|
1633
|
+
onchainDataInfo.underlying1Reserve &&
|
|
1634
|
+
onchainDataInfo.totalSupply) {
|
|
1635
|
+
const underlying0Supply = (state.supply * onchainDataInfo.underlying0Reserve) /
|
|
1636
|
+
onchainDataInfo.totalSupply;
|
|
1637
|
+
const underlying0Borrow = (state.borrow * onchainDataInfo.underlying0Reserve) /
|
|
1638
|
+
onchainDataInfo.totalSupply;
|
|
1639
|
+
restUserAssets.push({
|
|
1640
|
+
address: onchainDataInfo.underlying0Address,
|
|
1641
|
+
supply: underlying0Supply,
|
|
1642
|
+
borrow: underlying0Borrow,
|
|
1643
|
+
});
|
|
1644
|
+
const underlying1Supply = (state.supply * onchainDataInfo.underlying1Reserve) /
|
|
1645
|
+
onchainDataInfo.totalSupply;
|
|
1646
|
+
const underlying1Borrow = (state.borrow * onchainDataInfo.underlying1Reserve) /
|
|
1647
|
+
onchainDataInfo.totalSupply;
|
|
1648
|
+
restUserAssets.push({
|
|
1649
|
+
address: onchainDataInfo.underlying1Address,
|
|
1650
|
+
supply: underlying1Supply,
|
|
1651
|
+
borrow: underlying1Borrow,
|
|
1652
|
+
});
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
else if (prices[state.address.toString()]?.type === type_1.AssetType.VaultAsset) {
|
|
1656
|
+
const priceData = prices[state.address.toString()];
|
|
1657
|
+
const decomposed = priceData.additionalData.decomposed;
|
|
1658
|
+
const totalSupply = priceData.additionalData.totalSupply;
|
|
1659
|
+
for (const asset of Object.keys(decomposed)) {
|
|
1660
|
+
const underlyingSupply = (state.supply * decomposed[asset].supply) / totalSupply +
|
|
1661
|
+
(state.borrow * decomposed[asset].borrow) / totalSupply;
|
|
1662
|
+
const underlyingBorrow = (state.supply * decomposed[asset].borrow) / totalSupply +
|
|
1663
|
+
(state.borrow * decomposed[asset].supply) / totalSupply;
|
|
1664
|
+
restUserAssets.push({
|
|
1665
|
+
address: ton_1.Address.parse(asset),
|
|
1666
|
+
supply: underlyingSupply,
|
|
1667
|
+
borrow: underlyingBorrow,
|
|
1668
|
+
});
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
userAssets = restUserAssets;
|
|
1674
|
+
}
|
|
1675
|
+
return accumStatus;
|
|
1676
|
+
}
|
|
1677
|
+
calculateRisk(decomposedAccountStatus, prices, poolData) {
|
|
1678
|
+
let collateral = 0n;
|
|
1679
|
+
let debt = 0n;
|
|
1680
|
+
let risk = 0n;
|
|
1681
|
+
Object.entries(decomposedAccountStatus).forEach(([asset, status]) => {
|
|
1682
|
+
const price = prices[asset];
|
|
1683
|
+
const suppliedValue = (BigInt(status.supply) * price.price) / BigInt(1e8);
|
|
1684
|
+
const borrowedValue = (BigInt(status.borrow) * price.price) / BigInt(1e8);
|
|
1685
|
+
const isCollateral = poolData.assets[asset].isCollateral;
|
|
1686
|
+
if (price.type === type_1.AssetType.Native) {
|
|
1687
|
+
if (isCollateral) {
|
|
1688
|
+
collateral += suppliedValue;
|
|
1689
|
+
}
|
|
1690
|
+
debt += borrowedValue;
|
|
1691
|
+
}
|
|
1692
|
+
if (isCollateral) {
|
|
1693
|
+
const delta = suppliedValue > borrowedValue
|
|
1694
|
+
? suppliedValue - borrowedValue
|
|
1695
|
+
: borrowedValue - suppliedValue;
|
|
1696
|
+
risk += (delta * poolData.assets[asset].riskFactor) / BigInt(1e4);
|
|
1697
|
+
}
|
|
1698
|
+
else {
|
|
1699
|
+
risk +=
|
|
1700
|
+
(borrowedValue * poolData.assets[asset].riskFactor) / BigInt(1e4);
|
|
1701
|
+
}
|
|
1702
|
+
});
|
|
1703
|
+
if (collateral === 0n && debt === 0n) {
|
|
1704
|
+
return {
|
|
1705
|
+
result: true,
|
|
1706
|
+
healthy: true,
|
|
1707
|
+
unhealthy: false,
|
|
1708
|
+
collateral,
|
|
1709
|
+
debt,
|
|
1710
|
+
risk,
|
|
1711
|
+
riskRatio: 0n,
|
|
1712
|
+
leverageRatio: 0n,
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1715
|
+
const netValue = collateral - debt;
|
|
1716
|
+
if (netValue <= 0n) {
|
|
1717
|
+
return {
|
|
1718
|
+
result: false,
|
|
1719
|
+
healthy: false,
|
|
1720
|
+
unhealthy: true,
|
|
1721
|
+
collateral,
|
|
1722
|
+
debt,
|
|
1723
|
+
risk,
|
|
1724
|
+
riskRatio: 2n ** 128n - 1n,
|
|
1725
|
+
leverageRatio: 2n ** 128n - 1n,
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
const leverageRatio = (collateral * BigInt(1e4)) / netValue;
|
|
1729
|
+
const riskRatio = (risk * BigInt(1e4)) / netValue;
|
|
1730
|
+
const unhealthy = poolData.liquidateLeverageRatio === 0n
|
|
1731
|
+
? riskRatio > poolData.liquidateVarRatio
|
|
1732
|
+
: leverageRatio > poolData.liquidateLeverageRatio ||
|
|
1733
|
+
riskRatio > poolData.liquidateVarRatio;
|
|
1734
|
+
return {
|
|
1735
|
+
result: !unhealthy,
|
|
1736
|
+
healthy: !unhealthy,
|
|
1737
|
+
unhealthy: unhealthy,
|
|
1738
|
+
collateral,
|
|
1739
|
+
debt,
|
|
1740
|
+
risk,
|
|
1741
|
+
riskRatio,
|
|
1742
|
+
leverageRatio,
|
|
1743
|
+
};
|
|
1744
|
+
}
|
|
1745
|
+
async getOracleRequestParams(assets, oracleConfig) {
|
|
1746
|
+
return redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, oracleConfig);
|
|
1747
|
+
}
|
|
1748
|
+
async isHealthy(poolAddress, ownerAddress, delta) {
|
|
1749
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(poolAddress)));
|
|
1750
|
+
const borrowerAccountAddress = await this.getAccountAddress(toString(ownerAddress), toString(poolAddress));
|
|
1751
|
+
const borrowerAccount = this.open(account_1.Account.createFromAddress(toAddress(borrowerAccountAddress)));
|
|
1752
|
+
// const poolData = await pool.getPoolData() as any;
|
|
1753
|
+
const poolData = pool_1.Pool.simulateAccrueInterest(await pool.getPoolData());
|
|
1754
|
+
let accountData = null;
|
|
1755
|
+
try {
|
|
1756
|
+
accountData = account_1.Account.convertShareToAmount(await borrowerAccount.getAccountData(), poolData);
|
|
1757
|
+
if (delta) {
|
|
1758
|
+
accountData = account_1.Account.applyDelta(accountData, delta);
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
catch (e) {
|
|
1762
|
+
console.log(e);
|
|
1763
|
+
return {
|
|
1764
|
+
result: true,
|
|
1765
|
+
healthy: true,
|
|
1766
|
+
unhealthy: false,
|
|
1767
|
+
collateral: 0n,
|
|
1768
|
+
debt: 0n,
|
|
1769
|
+
risk: 0n,
|
|
1770
|
+
riskRatio: 0n,
|
|
1771
|
+
leverageRatio: 0n,
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
const __assets = account_1.Account.haveAssets(accountData);
|
|
1775
|
+
if (__assets.length === 0) {
|
|
1776
|
+
return {
|
|
1777
|
+
result: true,
|
|
1778
|
+
healthy: true,
|
|
1779
|
+
unhealthy: false,
|
|
1780
|
+
collateral: 0n,
|
|
1781
|
+
debt: 0n,
|
|
1782
|
+
risk: 0n,
|
|
1783
|
+
riskRatio: 0n,
|
|
1784
|
+
leverageRatio: 0n,
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
const oracleConfig = poolData.oracleConfig;
|
|
1788
|
+
let { assets, vaultAssets } = await this.separateAssets(Object.keys(poolData.assets), oracleConfig);
|
|
1789
|
+
const { redstonePrices, onchainData: od } = await this.getRedstonePrices(assets, poolData);
|
|
1790
|
+
const onchainData2 = await this.updateOnchainData(oracleConfig.assetOnchainDataInfo);
|
|
1791
|
+
const onchainData = { ...od, ...onchainData2 };
|
|
1792
|
+
const assetPrices = this.calculatePrices(redstonePrices, onchainData);
|
|
1793
|
+
const vaultPositions = await this.getParsedVaults([...vaultAssets]);
|
|
1794
|
+
const exposures = await this.getExposures(vaultPositions);
|
|
1795
|
+
const exposurePools = exposures.pools;
|
|
1796
|
+
assets = [...new Set([...assets, ...exposures.assets])];
|
|
1797
|
+
const exposurePoolsData = {};
|
|
1798
|
+
for (let exposurePool of exposurePools) {
|
|
1799
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(exposurePool)));
|
|
1800
|
+
const poolData = await pool.getPoolData();
|
|
1801
|
+
exposurePoolsData[exposurePool] = poolData;
|
|
1802
|
+
}
|
|
1803
|
+
const vaultPrices = await this.calculateVaultPrices(assetPrices, exposurePoolsData, vaultPositions);
|
|
1804
|
+
const prices = {
|
|
1805
|
+
...assetPrices,
|
|
1806
|
+
...vaultPrices,
|
|
1807
|
+
};
|
|
1808
|
+
const decomposedAccountStatus = this.decomposeAccountStatus(accountData.status, prices, onchainData);
|
|
1809
|
+
return this.calculateRisk(decomposedAccountStatus, prices, poolData);
|
|
1810
|
+
}
|
|
1811
|
+
isHealthyV2(_poolData, _accountData, prices) {
|
|
1812
|
+
const poolData = pool_1.Pool.simulateAccrueInterest(_poolData);
|
|
1813
|
+
const decomposedAccountStatus = this.decomposeAccountStatus(_accountData, prices, poolData.oracleConfig.assetOnchainDataInfo);
|
|
1814
|
+
return this.calculateRisk(decomposedAccountStatus, prices, poolData);
|
|
1815
|
+
}
|
|
1816
|
+
// async getPrices(poolAddress: Address | string) {
|
|
1817
|
+
// const pool = this.open(Pool.createFromAddress(toAddress(poolAddress)));
|
|
1818
|
+
// const poolData = (await pool.getPoolData()) as any;
|
|
1819
|
+
// const assets = Object.keys(poolData.assets);
|
|
1820
|
+
// const { redstonePrices, onchainData: od } = await this.getRedstonePrices(
|
|
1821
|
+
// assets,
|
|
1822
|
+
// poolData
|
|
1823
|
+
// );
|
|
1824
|
+
// const onchainData2 = await this.updateOnchainData(
|
|
1825
|
+
// poolData.oracleConfig.assetOnchainDataInfo
|
|
1826
|
+
// );
|
|
1827
|
+
// const onchainData = { ...od, ...onchainData2 };
|
|
1828
|
+
// const prices = this.calculatePrices(redstonePrices, onchainData);
|
|
1829
|
+
// return prices;
|
|
1830
|
+
// }
|
|
1831
|
+
async getPrices(poolAddress) {
|
|
1832
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(poolAddress)));
|
|
1833
|
+
const poolData = await pool.getPoolData();
|
|
1834
|
+
const _assets = Object.keys(poolData.assets);
|
|
1835
|
+
const oracleConfig = poolData.oracleConfig;
|
|
1836
|
+
let { assets, vaultAssets } = await this.separateAssets(_assets, oracleConfig);
|
|
1837
|
+
const { redstonePrices, onchainData: od } = await this.getRedstonePrices(assets, poolData);
|
|
1838
|
+
const onchainData2 = await this.updateOnchainData(oracleConfig.assetOnchainDataInfo);
|
|
1839
|
+
const onchainData = { ...od, ...onchainData2 };
|
|
1840
|
+
const prices = this.calculatePrices(redstonePrices, onchainData);
|
|
1841
|
+
const vaultPositions = await this.getParsedVaults([...vaultAssets]);
|
|
1842
|
+
const exposures = await this.getExposures(vaultPositions);
|
|
1843
|
+
const exposurePools = exposures.pools;
|
|
1844
|
+
assets = [...new Set([...assets, ...exposures.assets])];
|
|
1845
|
+
const exposurePoolsData = {};
|
|
1846
|
+
for (let exposurePool of exposurePools) {
|
|
1847
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(exposurePool)));
|
|
1848
|
+
const poolData = await pool.getPoolData();
|
|
1849
|
+
exposurePoolsData[exposurePool] = poolData;
|
|
1850
|
+
}
|
|
1851
|
+
const vaultPrices = await this.calculateVaultPrices(prices, exposurePoolsData, vaultPositions);
|
|
1852
|
+
return {
|
|
1853
|
+
...prices,
|
|
1854
|
+
...vaultPrices,
|
|
1855
|
+
};
|
|
1856
|
+
}
|
|
1857
|
+
async getPricesV2(poolAddress) {
|
|
1858
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(poolAddress)));
|
|
1859
|
+
const poolData = await pool.getPoolData();
|
|
1860
|
+
const _assets = Object.keys(poolData.assets);
|
|
1861
|
+
const oracleConfig = poolData.oracleConfig;
|
|
1862
|
+
let { assets, vaultAssets } = await this.separateAssets(_assets, oracleConfig);
|
|
1863
|
+
const { redstonePrices, onchainData: od } = await this.getRedstonePrices(assets, poolData);
|
|
1864
|
+
const onchainData2 = await this.updateOnchainData(oracleConfig.assetOnchainDataInfo);
|
|
1865
|
+
const onchainData = { ...od, ...onchainData2 };
|
|
1866
|
+
const prices = this.calculatePrices(redstonePrices, onchainData);
|
|
1867
|
+
const vaultPositions = await this.getParsedVaults([...vaultAssets]);
|
|
1868
|
+
const exposures = await this.getExposures(vaultPositions);
|
|
1869
|
+
const exposurePools = exposures.pools;
|
|
1870
|
+
assets = [...new Set([...assets, ...exposures.assets])];
|
|
1871
|
+
const exposurePoolsData = {};
|
|
1872
|
+
for (let exposurePool of exposurePools) {
|
|
1873
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(exposurePool)));
|
|
1874
|
+
const poolData = await pool.getPoolData();
|
|
1875
|
+
exposurePoolsData[exposurePool] = poolData;
|
|
1876
|
+
}
|
|
1877
|
+
const vaultPrices = await this.calculateVaultPrices(prices, exposurePoolsData, vaultPositions);
|
|
1878
|
+
return {
|
|
1879
|
+
...prices,
|
|
1880
|
+
...vaultPrices,
|
|
1881
|
+
};
|
|
1882
|
+
}
|
|
1883
|
+
async calculateVaultPrices(price, poolInfos, vaults) {
|
|
1884
|
+
const vaultPrices = {};
|
|
1885
|
+
while (Object.keys(vaults).length > 0) {
|
|
1886
|
+
const vaultAddresses = Object.keys(vaults);
|
|
1887
|
+
for (let vaultAddress of vaultAddresses) {
|
|
1888
|
+
try {
|
|
1889
|
+
const amountVaultPosition = shareToAmount(vaults[vaultAddress], poolInfos);
|
|
1890
|
+
let totalValue = 0n;
|
|
1891
|
+
for (const assetAddress of Object.keys(amountVaultPosition.assetAmounts)) {
|
|
1892
|
+
const assetPrice = price[assetAddress]?.price || vaultPrices[assetAddress].price;
|
|
1893
|
+
if (!assetPrice)
|
|
1894
|
+
throw "error";
|
|
1895
|
+
totalValue +=
|
|
1896
|
+
amountVaultPosition.assetAmounts[assetAddress] * assetPrice;
|
|
1897
|
+
}
|
|
1898
|
+
if (totalValue === 0n || amountVaultPosition.totalSupply === 0n) {
|
|
1899
|
+
vaultPrices[vaultAddress] = {
|
|
1900
|
+
type: 10,
|
|
1901
|
+
price: 0n,
|
|
1902
|
+
additionalData: {
|
|
1903
|
+
decomposed: {},
|
|
1904
|
+
totalSupply: 0n,
|
|
1905
|
+
},
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
else {
|
|
1909
|
+
vaultPrices[vaultAddress] = {
|
|
1910
|
+
type: 10,
|
|
1911
|
+
price: totalValue / amountVaultPosition.totalSupply,
|
|
1912
|
+
additionalData: amountVaultPosition.additionalData,
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
delete vaults[vaultAddress];
|
|
1916
|
+
}
|
|
1917
|
+
catch (e) { }
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
return vaultPrices;
|
|
1921
|
+
}
|
|
1922
|
+
async getParsedVaults(vaultAddresses) {
|
|
1923
|
+
const decomposedVault = {};
|
|
1924
|
+
for (let vaultAddress of vaultAddresses) {
|
|
1925
|
+
const state = await this.getByContract(unknown_contract_1.UnknownContract, vaultAddress).getState();
|
|
1926
|
+
if (state.state.type === "active" && state.state.data) {
|
|
1927
|
+
const data = ton_1.Cell.fromBoc(state.state.data)[0];
|
|
1928
|
+
try {
|
|
1929
|
+
const vaultData = strategy_vault_1.StrategyVault.parseVaultData(data);
|
|
1930
|
+
const vaultDataa = {
|
|
1931
|
+
totalSupply: vaultData.totalSupply,
|
|
1932
|
+
assets: Object.keys(vaultData.assets).reduce((acc, asset) => {
|
|
1933
|
+
acc[asset] = vaultData.assets[asset].cash;
|
|
1934
|
+
return acc;
|
|
1935
|
+
}, {}),
|
|
1936
|
+
poolPositions: Object.keys(vaultData.factorialPools).reduce((acc, pool) => {
|
|
1937
|
+
acc[pool] = Object.keys(vaultData.factorialPools[pool]).reduce((acc, asset) => {
|
|
1938
|
+
acc[asset] = {
|
|
1939
|
+
supply: vaultData.factorialPools[pool][asset].supply,
|
|
1940
|
+
borrow: vaultData.factorialPools[pool][asset].borrow,
|
|
1941
|
+
};
|
|
1942
|
+
return acc;
|
|
1943
|
+
}, {});
|
|
1944
|
+
return acc;
|
|
1945
|
+
}, {}),
|
|
1946
|
+
};
|
|
1947
|
+
decomposedVault[vaultAddress.toString()] = vaultDataa;
|
|
1948
|
+
}
|
|
1949
|
+
catch (e) {
|
|
1950
|
+
const vaultData = share_vault_1.ShareVault.parseVaultData(data);
|
|
1951
|
+
const vaultDataa = {
|
|
1952
|
+
totalSupply: vaultData.totalSupply,
|
|
1953
|
+
assets: {
|
|
1954
|
+
[vaultData.asset.toString()]: vaultData.cash,
|
|
1955
|
+
},
|
|
1956
|
+
poolPositions: Object.values(vaultData.whitelistedPools).reduce((acc, pool) => {
|
|
1957
|
+
acc[pool.address.toString()] = {
|
|
1958
|
+
[vaultData.asset.toString()]: {
|
|
1959
|
+
supply: pool.supply,
|
|
1960
|
+
borrow: 0n,
|
|
1961
|
+
},
|
|
1962
|
+
};
|
|
1963
|
+
return acc;
|
|
1964
|
+
}, {}),
|
|
1965
|
+
};
|
|
1966
|
+
decomposedVault[vaultAddress.toString()] = vaultDataa;
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
return decomposedVault;
|
|
1971
|
+
}
|
|
1972
|
+
async getExposures(vaults) {
|
|
1973
|
+
const assets = new Set();
|
|
1974
|
+
const pools = new Set();
|
|
1975
|
+
for (let vault of Object.values(vaults)) {
|
|
1976
|
+
const _assets = vault.assets;
|
|
1977
|
+
for (let asset of Object.keys(_assets)) {
|
|
1978
|
+
const position = vault.assets[asset];
|
|
1979
|
+
if (position > 0n) {
|
|
1980
|
+
assets.add(asset);
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
for (let pool of Object.keys(vault.poolPositions)) {
|
|
1984
|
+
const _assets = vault.poolPositions[pool];
|
|
1985
|
+
for (let asset of Object.keys(_assets)) {
|
|
1986
|
+
const position = vault.poolPositions[pool][asset];
|
|
1987
|
+
if (position.supply > 0n || position.borrow > 0n) {
|
|
1988
|
+
pools.add(pool);
|
|
1989
|
+
assets.add(asset);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
const result = { pools: [...pools], assets: [...assets] };
|
|
1995
|
+
return result;
|
|
1996
|
+
}
|
|
1997
|
+
async calculateMaxBorrowableAmount({ borrowerAddress, poolAddress, tokenAddress, BUFFER = 100n, }) {
|
|
1998
|
+
if (!poolAddress || !borrowerAddress)
|
|
1999
|
+
throw new Error("Pool address or borrower address is required");
|
|
2000
|
+
const poolContract = this.open(pool_1.Pool.createFromAddress(toAddress(poolAddress)));
|
|
2001
|
+
const pool = pool_1.Pool.simulateAccrueInterest(await poolContract.getPoolData());
|
|
2002
|
+
const accountContract = this.open(account_1.Account.createFromAddress(await poolContract.getAccountAddress(borrowerAddress)));
|
|
2003
|
+
const accountState = account_1.Account.convertShareToAmount(await accountContract.getAccountData(), pool);
|
|
2004
|
+
const cash = pool.assets[tokenAddress].cash;
|
|
2005
|
+
const { onchainData: od } = await this.getRedstonePrices([tokenAddress], pool);
|
|
2006
|
+
const pricesData = await this.getPricesV2(poolAddress.toString());
|
|
2007
|
+
const onchainData2 = await this.updateOnchainData(pool.oracleConfig.assetOnchainDataInfo);
|
|
2008
|
+
const onchainData = { ...od, ...onchainData2 };
|
|
2009
|
+
// @ts-ignore
|
|
2010
|
+
pool.oracleConfig.assetOnchainDataInfo = onchainData;
|
|
2011
|
+
const beforeHealth = this.isHealthyV2(pool, accountState.status, pricesData);
|
|
2012
|
+
const riskCalculator = new risk_calculator_1.RiskCalculator(accountState.status, pricesData, onchainData, pool);
|
|
2013
|
+
const deltaSolutionsForTargetRatio = riskCalculator.calculateDeltaForTargetRiskRatio(pool.maxLoanVarRatio - BUFFER, tokenAddress);
|
|
2014
|
+
const deltaSolutionForLeverage = riskCalculator.calculateDeltaForTargetLeverage(pool.maxLoanLeverageRatio - BUFFER, tokenAddress, "borrow");
|
|
2015
|
+
const solutionsForTargetRatio = deltaSolutionsForTargetRatio.map((solution) => (0, utils_1.bigIntMin)([solution.delta, 0n]) * -1n);
|
|
2016
|
+
const hasAnswer = solutionsForTargetRatio.length > 0;
|
|
2017
|
+
const solutionForTargetRatio = hasAnswer
|
|
2018
|
+
? (0, utils_1.bigIntMin)(solutionsForTargetRatio)
|
|
2019
|
+
: utils_1.MAX256;
|
|
2020
|
+
const solutionForLeverage = deltaSolutionForLeverage.delta >= 0n ? deltaSolutionForLeverage.delta : 0n;
|
|
2021
|
+
const maxBorrowableAmount = (0, utils_1.bigIntMin)([
|
|
2022
|
+
solutionForTargetRatio,
|
|
2023
|
+
solutionForLeverage,
|
|
2024
|
+
cash,
|
|
2025
|
+
]);
|
|
2026
|
+
let reason;
|
|
2027
|
+
if (maxBorrowableAmount === solutionForTargetRatio) {
|
|
2028
|
+
reason = "RISK_RATIO_CONSTRAINT";
|
|
2029
|
+
}
|
|
2030
|
+
else if (maxBorrowableAmount === solutionForLeverage) {
|
|
2031
|
+
reason = "LEVERAGE_CONSTRAINT";
|
|
2032
|
+
}
|
|
2033
|
+
else if (maxBorrowableAmount === cash) {
|
|
2034
|
+
reason = "POOL_CASH_CONSTRAINT";
|
|
2035
|
+
}
|
|
2036
|
+
else {
|
|
2037
|
+
throw new Error("Unknown reason for max borrowable amount");
|
|
2038
|
+
}
|
|
2039
|
+
const accountState2 = account_1.Account.applyDelta(accountState, {
|
|
2040
|
+
[tokenAddress]: {
|
|
2041
|
+
address: ton_1.Address.parse(tokenAddress),
|
|
2042
|
+
supply: 0n,
|
|
2043
|
+
borrow: maxBorrowableAmount,
|
|
2044
|
+
},
|
|
2045
|
+
});
|
|
2046
|
+
const afterHealth = this.isHealthyV2(pool, accountState2.status, pricesData);
|
|
2047
|
+
return {
|
|
2048
|
+
amount: maxBorrowableAmount,
|
|
2049
|
+
reason,
|
|
2050
|
+
beforeAccountHealth: beforeHealth,
|
|
2051
|
+
afterAccountHealth: afterHealth,
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2054
|
+
;
|
|
2055
|
+
async calculateMaxWithdrawableAmount({ withdrawerAddress, poolAddress, tokenAddress, BUFFER = 100n, }) {
|
|
2056
|
+
if (!poolAddress || !withdrawerAddress)
|
|
2057
|
+
throw new Error("Pool address or withdrawer address is required");
|
|
2058
|
+
const poolContract = this.open(pool_1.Pool.createFromAddress(toAddress(poolAddress)));
|
|
2059
|
+
const pool = pool_1.Pool.simulateAccrueInterest(await poolContract.getPoolData());
|
|
2060
|
+
const accountContract = this.open(account_1.Account.createFromAddress(await poolContract.getAccountAddress(withdrawerAddress)));
|
|
2061
|
+
const accountState = account_1.Account.convertShareToAmount(await accountContract.getAccountData(), pool);
|
|
2062
|
+
const cash = pool.assets[tokenAddress]?.cash;
|
|
2063
|
+
const hasNoPosition = Object.values(accountState.status).every((value) => value.borrow === 0n && value.supply === 0n);
|
|
2064
|
+
if (hasNoPosition) {
|
|
2065
|
+
return { amount: 0n, reason: "USER_SUPPLY_CONSTRAINT" };
|
|
2066
|
+
}
|
|
2067
|
+
const hasNoBorrowedAmount = Object.values(accountState.status).every((value) => value.borrow === 0n);
|
|
2068
|
+
if (hasNoBorrowedAmount) {
|
|
2069
|
+
const supplyAmount = accountState.status[tokenAddress]?.supply;
|
|
2070
|
+
if (supplyAmount > cash) {
|
|
2071
|
+
return { amount: cash, reason: "POOL_CASH_CONSTRAINT" };
|
|
2072
|
+
}
|
|
2073
|
+
else {
|
|
2074
|
+
return { amount: supplyAmount, reason: "USER_SUPPLY_CONSTRAINT" };
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
const { onchainData: od } = await this.getRedstonePrices([tokenAddress], pool);
|
|
2078
|
+
const pricesData = await this.getPricesV2(poolAddress.toString());
|
|
2079
|
+
const onchainData2 = await this.updateOnchainData(pool.oracleConfig.assetOnchainDataInfo);
|
|
2080
|
+
const onchainData = { ...od, ...onchainData2 };
|
|
2081
|
+
// @ts-ignore
|
|
2082
|
+
pool.oracleConfig.assetOnchainDataInfo = onchainData;
|
|
2083
|
+
const beforeHealth = this.isHealthyV2(pool, accountState.status, pricesData);
|
|
2084
|
+
const riskCalculator = new risk_calculator_1.RiskCalculator(accountState.status, pricesData, onchainData, pool);
|
|
2085
|
+
const deltaSolutionsForTargetRatio = riskCalculator.calculateDeltaForTargetRiskRatio(pool.maxLoanVarRatio - BUFFER, tokenAddress);
|
|
2086
|
+
const deltaSolutionForLeverage = riskCalculator.calculateDeltaForTargetLeverage(pool.maxLoanLeverageRatio - BUFFER, tokenAddress, "supply");
|
|
2087
|
+
const solutionsForTargetRatio = deltaSolutionsForTargetRatio.map((solution) => (0, utils_1.bigIntMin)([solution.delta, 0n]) * -1n);
|
|
2088
|
+
const hasTargetRatioAnswer = solutionsForTargetRatio.length > 0;
|
|
2089
|
+
const solutionForTargetRatio = hasTargetRatioAnswer
|
|
2090
|
+
? (0, utils_1.bigIntMin)(solutionsForTargetRatio)
|
|
2091
|
+
: utils_1.MAX256;
|
|
2092
|
+
const solutionForLeverage = (0, utils_1.bigIntMin)([deltaSolutionForLeverage.delta, 0n]) * -1n;
|
|
2093
|
+
const userSupplyAmount = accountState.status[tokenAddress]?.supply;
|
|
2094
|
+
const maxWithdrawableAmount = (0, utils_1.bigIntMin)([
|
|
2095
|
+
userSupplyAmount,
|
|
2096
|
+
solutionForTargetRatio,
|
|
2097
|
+
solutionForLeverage,
|
|
2098
|
+
cash ?? 0n,
|
|
2099
|
+
]);
|
|
2100
|
+
let reason;
|
|
2101
|
+
if (maxWithdrawableAmount === solutionForTargetRatio) {
|
|
2102
|
+
reason = "RISK_RATIO_CONSTRAINT";
|
|
2103
|
+
}
|
|
2104
|
+
else if (maxWithdrawableAmount === solutionForLeverage) {
|
|
2105
|
+
reason = "LEVERAGE_CONSTRAINT";
|
|
2106
|
+
}
|
|
2107
|
+
else if (maxWithdrawableAmount === cash) {
|
|
2108
|
+
reason = "POOL_CASH_CONSTRAINT";
|
|
2109
|
+
}
|
|
2110
|
+
else if (maxWithdrawableAmount === userSupplyAmount) {
|
|
2111
|
+
reason = "USER_SUPPLY_CONSTRAINT";
|
|
2112
|
+
}
|
|
2113
|
+
else {
|
|
2114
|
+
throw new Error("Unknown reason for max withdrawable amount");
|
|
2115
|
+
}
|
|
2116
|
+
const accountState2 = account_1.Account.applyDelta(accountState, {
|
|
2117
|
+
[tokenAddress]: {
|
|
2118
|
+
address: ton_1.Address.parse(tokenAddress),
|
|
2119
|
+
supply: -maxWithdrawableAmount,
|
|
2120
|
+
borrow: 0n,
|
|
2121
|
+
},
|
|
2122
|
+
});
|
|
2123
|
+
const afterHealth = this.isHealthyV2(pool, accountState2.status, pricesData);
|
|
2124
|
+
return {
|
|
2125
|
+
amount: maxWithdrawableAmount,
|
|
2126
|
+
reason,
|
|
2127
|
+
beforeAccountHealth: beforeHealth,
|
|
2128
|
+
afterAccountHealth: afterHealth,
|
|
2129
|
+
};
|
|
2130
|
+
}
|
|
2131
|
+
;
|
|
2132
|
+
async getPoolData(poolAddress) {
|
|
2133
|
+
if (!(poolAddress instanceof ton_1.Address)) {
|
|
2134
|
+
poolAddress = ton_1.Address.parse(poolAddress);
|
|
2135
|
+
}
|
|
2136
|
+
const pool = this.open(pool_1.Pool.createFromAddress(poolAddress));
|
|
2137
|
+
return await pool.getPoolData();
|
|
2138
|
+
}
|
|
2139
|
+
async getAccountData(poolAddress, userAddress) {
|
|
2140
|
+
if (!(poolAddress instanceof ton_1.Address)) {
|
|
2141
|
+
poolAddress = ton_1.Address.parse(poolAddress);
|
|
2142
|
+
}
|
|
2143
|
+
if (!(userAddress instanceof ton_1.Address)) {
|
|
2144
|
+
userAddress = ton_1.Address.parse(userAddress);
|
|
2145
|
+
}
|
|
2146
|
+
const pool = this.open(pool_1.Pool.createFromAddress(poolAddress));
|
|
2147
|
+
if (!this.accountAddresses[userAddress.toString()]?.[poolAddress.toString()]) {
|
|
2148
|
+
if (!this.accountAddresses[userAddress.toString()]) {
|
|
2149
|
+
this.accountAddresses[userAddress.toString()] = {};
|
|
2150
|
+
}
|
|
2151
|
+
this.accountAddresses[userAddress.toString()][poolAddress.toString()] =
|
|
2152
|
+
await pool.getAccountAddress(userAddress);
|
|
2153
|
+
}
|
|
2154
|
+
const account = this.open(account_1.Account.createFromAddress(this.accountAddresses[userAddress.toString()][poolAddress.toString()]));
|
|
2155
|
+
let accountData;
|
|
2156
|
+
const poolData = await pool.getPoolData();
|
|
2157
|
+
const assets = poolData.assets;
|
|
2158
|
+
const emptyStatus = Object.keys(assets).reduce((acc, asset) => {
|
|
2159
|
+
acc[asset] = {
|
|
2160
|
+
address: ton_1.Address.parse(asset),
|
|
2161
|
+
supply: 0n,
|
|
2162
|
+
borrow: 0n,
|
|
2163
|
+
};
|
|
2164
|
+
return acc;
|
|
2165
|
+
}, {});
|
|
2166
|
+
try {
|
|
2167
|
+
/** When Account is deployed */
|
|
2168
|
+
const accountDataFromOnchain = await account.getAccountData();
|
|
2169
|
+
const parsedAccountData = {
|
|
2170
|
+
...accountDataFromOnchain,
|
|
2171
|
+
status: { ...emptyStatus, ...accountDataFromOnchain.status },
|
|
2172
|
+
};
|
|
2173
|
+
accountData = parsedAccountData;
|
|
2174
|
+
}
|
|
2175
|
+
catch {
|
|
2176
|
+
/** When Account is not deployed(User never interacted with the pool), "Not Active" thrown */
|
|
2177
|
+
accountData = {
|
|
2178
|
+
address: userAddress,
|
|
2179
|
+
pool: poolAddress,
|
|
2180
|
+
owner: poolData.owner,
|
|
2181
|
+
status: emptyStatus,
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
return accountData;
|
|
2185
|
+
}
|
|
2186
|
+
async separateAssets(_assets, oracleConfig) {
|
|
2187
|
+
const noVaultAssets = [
|
|
2188
|
+
...Object.values(oracleConfig.redstoneAssetInfo).map((item) => item.address.toString()),
|
|
2189
|
+
...Object.keys(oracleConfig.assetOnchainDataInfo).map((item) => item),
|
|
2190
|
+
];
|
|
2191
|
+
const assets = [];
|
|
2192
|
+
const vaultAssets = [];
|
|
2193
|
+
for (const asset of _assets) {
|
|
2194
|
+
if (noVaultAssets.includes(asset.toString())) {
|
|
2195
|
+
assets.push(asset);
|
|
2196
|
+
}
|
|
2197
|
+
else {
|
|
2198
|
+
vaultAssets.push(asset);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
return {
|
|
2202
|
+
assets,
|
|
2203
|
+
vaultAssets,
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
async getPoolOracleParams(poolAddress, actor, executeAsset) {
|
|
2207
|
+
const pool = this.open(pool_1.Pool.createFromAddress(toAddress(poolAddress)));
|
|
2208
|
+
const poolData = (await pool.getPoolData());
|
|
2209
|
+
const senderAccountAddress = await this.getAccountAddress(toString(actor), toString(poolAddress));
|
|
2210
|
+
const senderAccount = this.open(account_1.Account.createFromAddress(senderAccountAddress));
|
|
2211
|
+
const accountData = await senderAccount.getAccountData();
|
|
2212
|
+
const userAssets = [
|
|
2213
|
+
...new Set([...account_1.Account.haveAssets(accountData), toString(executeAsset)]),
|
|
2214
|
+
];
|
|
2215
|
+
let { assets, vaultAssets } = await this.separateAssets(userAssets, poolData.oracleConfig);
|
|
2216
|
+
const vaultPositions = await this.getParsedVaults(vaultAssets);
|
|
2217
|
+
const exposures = await this.getExposures(vaultPositions);
|
|
2218
|
+
const exposurePools = exposures.pools;
|
|
2219
|
+
assets = [...new Set([...assets, ...exposures.assets])];
|
|
2220
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, poolData.oracleConfig);
|
|
2221
|
+
const helper = (0, redstoneHelper_1.createRedstoneHelper)("prod");
|
|
2222
|
+
const payload = await helper.createPayload(result.redstoneAssetNames);
|
|
2223
|
+
const requestAssetCell = redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(result.requestAssets);
|
|
2224
|
+
const dataFeedIdsTupleBuilder = new ton_1.TupleBuilder();
|
|
2225
|
+
result.feedIds.forEach((item) => dataFeedIdsTupleBuilder.writeNumber(item));
|
|
2226
|
+
const feedIdCell = (0, ton_1.serializeTuple)(dataFeedIdsTupleBuilder.build());
|
|
2227
|
+
let requestFactorialPoolsCell = exposurePools.length > 0
|
|
2228
|
+
? redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(exposurePools.map((pool) => ton_1.Address.parse(pool)))
|
|
2229
|
+
: null;
|
|
2230
|
+
let requestFactorialVaultsCell = vaultAssets.length > 0
|
|
2231
|
+
? redstone_onchain_oracle_1.RedstoneOnchainOracle.createAddressToTupleCell(vaultAssets.map((vault) => ton_1.Address.parse(vault)))
|
|
2232
|
+
: null;
|
|
2233
|
+
let requestFactorialCell = (0, ton_1.beginCell)()
|
|
2234
|
+
.storeMaybeRef(requestFactorialPoolsCell)
|
|
2235
|
+
.storeMaybeRef(requestFactorialVaultsCell)
|
|
2236
|
+
.endCell();
|
|
2237
|
+
const oracleParams = (0, ton_1.beginCell)()
|
|
2238
|
+
.storeRef(feedIdCell)
|
|
2239
|
+
.storeRef(payload)
|
|
2240
|
+
.storeRef(requestAssetCell)
|
|
2241
|
+
.storeRef(requestFactorialCell)
|
|
2242
|
+
.endCell();
|
|
2243
|
+
return oracleParams;
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
exports.PoolV1 = PoolV1;
|
|
2247
|
+
const shareToAmount = (vault, poolInfos) => {
|
|
2248
|
+
const amountVaultPosition = {};
|
|
2249
|
+
const assetAmount = {};
|
|
2250
|
+
const decomposed = {};
|
|
2251
|
+
for (let asset of Object.keys(vault.assets)) {
|
|
2252
|
+
assetAmount[asset] = vault.assets[asset];
|
|
2253
|
+
decomposed[asset] = {
|
|
2254
|
+
supply: vault.assets[asset],
|
|
2255
|
+
borrow: 0n,
|
|
2256
|
+
};
|
|
2257
|
+
}
|
|
2258
|
+
for (let pool of Object.keys(vault.poolPositions)) {
|
|
2259
|
+
const poolInfo = poolInfos[pool];
|
|
2260
|
+
const assets = vault.poolPositions[pool];
|
|
2261
|
+
for (let asset of Object.keys(assets)) {
|
|
2262
|
+
const position = assets[asset];
|
|
2263
|
+
let supply = 0n;
|
|
2264
|
+
let borrow = 0n;
|
|
2265
|
+
if (position.supply !== 0n &&
|
|
2266
|
+
poolInfo.assets[asset].totalSupplyShare !== 0n) {
|
|
2267
|
+
supply =
|
|
2268
|
+
(position.supply * poolInfo.assets[asset].totalSupplyAmount) /
|
|
2269
|
+
poolInfo.assets[asset].totalSupplyShare;
|
|
2270
|
+
}
|
|
2271
|
+
if (position.borrow !== 0n &&
|
|
2272
|
+
poolInfo.assets[asset].totalBorrowShare !== 0n) {
|
|
2273
|
+
borrow =
|
|
2274
|
+
(position.borrow * poolInfo.assets[asset].totalBorrowAmount) /
|
|
2275
|
+
poolInfo.assets[asset].totalBorrowShare;
|
|
2276
|
+
}
|
|
2277
|
+
amountVaultPosition[pool] ??= {};
|
|
2278
|
+
amountVaultPosition[pool][asset] ??= {
|
|
2279
|
+
supply,
|
|
2280
|
+
borrow,
|
|
2281
|
+
};
|
|
2282
|
+
assetAmount[asset] ??= 0n;
|
|
2283
|
+
assetAmount[asset] += supply - borrow;
|
|
2284
|
+
decomposed[asset].supply += supply;
|
|
2285
|
+
decomposed[asset].borrow += borrow;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
return {
|
|
2289
|
+
assets: vault.assets,
|
|
2290
|
+
poolPositions: amountVaultPosition,
|
|
2291
|
+
assetAmounts: assetAmount,
|
|
2292
|
+
totalSupply: vault.totalSupply,
|
|
2293
|
+
additionalData: {
|
|
2294
|
+
decomposed: decomposed,
|
|
2295
|
+
totalSupply: vault.totalSupply,
|
|
2296
|
+
},
|
|
2297
|
+
};
|
|
2298
|
+
};
|