@gearbox-protocol/sdk 3.0.0-vfour.21 → 3.0.0-vfour.211
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/README.md +0 -1
- package/dist/cjs/dev/index.cjs +942 -65
- package/dist/cjs/dev/index.d.ts +347 -4
- package/dist/cjs/sdk/index.cjs +67414 -9725
- package/dist/cjs/sdk/index.d.ts +91280 -9877
- package/dist/esm/dev/index.d.mts +347 -4
- package/dist/esm/dev/index.mjs +939 -67
- package/dist/esm/sdk/index.d.mts +91280 -9877
- package/dist/esm/sdk/index.mjs +67088 -9787
- package/package.json +29 -15
package/dist/esm/dev/index.mjs
CHANGED
|
@@ -1,7 +1,385 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { createTestClient, publicActions, walletActions, toHex, isAddress, parseEther, createWalletClient, http, createPublicClient, stringToHex } from 'viem';
|
|
2
|
+
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
|
|
3
|
+
import { SDKConstruct, childLogger, AddressMap, sendRawTx, ADDRESS_0X0, formatBN, ierc20Abi, MAX_UINT256, iDegenNftv2Abi, PERCENTAGE_FACTOR, AP_PRICE_FEED_COMPRESSOR, iPriceFeedCompressorAbi, rawTxToMulticallPriceUpdate, GearboxSDK, json_stringify, iAddressProviderV3Abi, ADDRESS_PROVIDER, iAddressProviderV3_1Abi, WAD } from '../sdk/index.mjs';
|
|
4
|
+
import { writeFile, readFile } from 'node:fs/promises';
|
|
3
5
|
|
|
4
|
-
// src/dev/
|
|
6
|
+
// src/dev/AccountOpener.ts
|
|
7
|
+
function createAnvilClient({
|
|
8
|
+
chain,
|
|
9
|
+
transport
|
|
10
|
+
}) {
|
|
11
|
+
return createTestClient(
|
|
12
|
+
{
|
|
13
|
+
chain,
|
|
14
|
+
mode: "anvil",
|
|
15
|
+
transport,
|
|
16
|
+
cacheTime: 0,
|
|
17
|
+
pollingInterval: 50
|
|
18
|
+
}
|
|
19
|
+
).extend(publicActions).extend(walletActions).extend((client) => ({
|
|
20
|
+
anvilNodeInfo: () => anvilNodeInfo(client),
|
|
21
|
+
isAnvil: () => isAnvil(client),
|
|
22
|
+
evmMineDetailed: (timestamp) => evmMineDetailed(client, timestamp)
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
async function isAnvil(client) {
|
|
26
|
+
try {
|
|
27
|
+
const resp = await client.request({
|
|
28
|
+
method: "anvil_nodeInfo",
|
|
29
|
+
params: []
|
|
30
|
+
});
|
|
31
|
+
return !!resp.currentBlockNumber;
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function anvilNodeInfo(client) {
|
|
37
|
+
return client.request({
|
|
38
|
+
method: "anvil_nodeInfo",
|
|
39
|
+
params: []
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async function evmMineDetailed(client, timestamp) {
|
|
43
|
+
try {
|
|
44
|
+
const [block] = await client.request({
|
|
45
|
+
method: "evm_mine_detailed",
|
|
46
|
+
params: [toHex(timestamp)]
|
|
47
|
+
});
|
|
48
|
+
return block;
|
|
49
|
+
} catch {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/dev/AccountOpener.ts
|
|
55
|
+
var AccountOpener = class extends SDKConstruct {
|
|
56
|
+
#service;
|
|
57
|
+
#anvil;
|
|
58
|
+
#logger;
|
|
59
|
+
#borrower;
|
|
60
|
+
#faucet;
|
|
61
|
+
constructor(service, options = {}) {
|
|
62
|
+
super(service.sdk);
|
|
63
|
+
this.#service = service;
|
|
64
|
+
this.#logger = childLogger("AccountOpener", service.sdk.logger);
|
|
65
|
+
this.#anvil = createAnvilClient({
|
|
66
|
+
chain: service.sdk.provider.chain,
|
|
67
|
+
transport: service.sdk.provider.transport
|
|
68
|
+
});
|
|
69
|
+
this.#faucet = options.faucet ?? service.sdk.addressProvider.getAddress("FAUCET");
|
|
70
|
+
}
|
|
71
|
+
get borrower() {
|
|
72
|
+
if (!this.#borrower) {
|
|
73
|
+
throw new Error("borrower can be used only after openCreditAccounts");
|
|
74
|
+
}
|
|
75
|
+
return this.#borrower.address;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Tries to open account with underlying only in each CM
|
|
79
|
+
*/
|
|
80
|
+
async openCreditAccounts(targets) {
|
|
81
|
+
await this.#prepareBorrower(targets);
|
|
82
|
+
const toApprove = new AddressMap();
|
|
83
|
+
for (const c of targets) {
|
|
84
|
+
const cm = this.sdk.marketRegister.findCreditManager(c.creditManager);
|
|
85
|
+
const toApproveOnCM = toApprove.get(c.creditManager) ?? /* @__PURE__ */ new Set();
|
|
86
|
+
toApproveOnCM.add(cm.underlying);
|
|
87
|
+
toApprove.upsert(c.creditManager, toApproveOnCM);
|
|
88
|
+
}
|
|
89
|
+
for (const [cmAddr, tokens] of toApprove.entries()) {
|
|
90
|
+
const cm = this.sdk.marketRegister.findCreditManager(cmAddr);
|
|
91
|
+
for (const token of tokens) {
|
|
92
|
+
await this.#approve(token, cm);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (let i = 0; i < targets.length; i++) {
|
|
96
|
+
const target = targets[i];
|
|
97
|
+
try {
|
|
98
|
+
await this.#openAccount(target, i + 1, targets.length);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
this.#logger?.error(e);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const accounts = await this.getOpenedAccounts();
|
|
104
|
+
this.#logger?.info(`opened ${accounts.length} accounts`);
|
|
105
|
+
return accounts;
|
|
106
|
+
}
|
|
107
|
+
async #openAccount({ creditManager, collateral, leverage = 4, slippage = 50 }, index, total) {
|
|
108
|
+
const borrower = await this.#getBorrower();
|
|
109
|
+
const cm = this.sdk.marketRegister.findCreditManager(creditManager);
|
|
110
|
+
const symbol = this.sdk.tokensMeta.symbol(collateral);
|
|
111
|
+
const logger = this.#logger?.child?.({
|
|
112
|
+
creditManager: cm.name,
|
|
113
|
+
collateral: symbol
|
|
114
|
+
});
|
|
115
|
+
logger?.debug(`opening account #${index}/${total}`);
|
|
116
|
+
const { minDebt, underlying } = cm.creditFacade;
|
|
117
|
+
const expectedBalances = [];
|
|
118
|
+
const leftoverBalances = [];
|
|
119
|
+
for (const t of Object.keys(cm.collateralTokens)) {
|
|
120
|
+
const token = t;
|
|
121
|
+
expectedBalances.push({
|
|
122
|
+
token,
|
|
123
|
+
balance: token === underlying ? BigInt(leverage) * minDebt : 1n
|
|
124
|
+
});
|
|
125
|
+
leftoverBalances.push({
|
|
126
|
+
token,
|
|
127
|
+
balance: 1n
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
logger?.debug("looking for open strategy");
|
|
131
|
+
const strategy = await this.sdk.router.findOpenStrategyPath({
|
|
132
|
+
creditManager: cm.creditManager,
|
|
133
|
+
expectedBalances,
|
|
134
|
+
leftoverBalances,
|
|
135
|
+
slippage,
|
|
136
|
+
target: collateral
|
|
137
|
+
});
|
|
138
|
+
logger?.debug(strategy, "found open strategy");
|
|
139
|
+
const debt = minDebt * BigInt(leverage - 1);
|
|
140
|
+
const averageQuota = this.#getCollateralQuota(
|
|
141
|
+
cm,
|
|
142
|
+
collateral,
|
|
143
|
+
strategy.amount,
|
|
144
|
+
debt
|
|
145
|
+
);
|
|
146
|
+
const minQuota = this.#getCollateralQuota(
|
|
147
|
+
cm,
|
|
148
|
+
collateral,
|
|
149
|
+
strategy.minAmount,
|
|
150
|
+
debt
|
|
151
|
+
);
|
|
152
|
+
logger?.debug({ averageQuota, minQuota }, "calculated quotas");
|
|
153
|
+
const { tx, calls } = await this.#service.openCA({
|
|
154
|
+
creditManager: cm.creditManager.address,
|
|
155
|
+
averageQuota,
|
|
156
|
+
minQuota,
|
|
157
|
+
collateral: [{ token: underlying, balance: minDebt }],
|
|
158
|
+
debt,
|
|
159
|
+
calls: strategy.calls,
|
|
160
|
+
ethAmount: 0n,
|
|
161
|
+
permits: {},
|
|
162
|
+
to: borrower.address,
|
|
163
|
+
referralCode: 0n
|
|
164
|
+
});
|
|
165
|
+
for (let i = 0; i < calls.length; i++) {
|
|
166
|
+
const call = calls[i];
|
|
167
|
+
logger?.debug(
|
|
168
|
+
`call #${i + 1}: ${this.sdk.parseFunctionData(call.target, call.callData)}`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
logger?.debug("prepared open account transaction");
|
|
172
|
+
const hash = await sendRawTx(this.#anvil, {
|
|
173
|
+
tx,
|
|
174
|
+
account: borrower
|
|
175
|
+
});
|
|
176
|
+
logger?.debug(`send transaction ${hash}`);
|
|
177
|
+
const receipt = await this.#anvil.waitForTransactionReceipt({ hash });
|
|
178
|
+
if (receipt.status === "reverted") {
|
|
179
|
+
throw new Error(`open credit account tx ${hash} reverted`);
|
|
180
|
+
}
|
|
181
|
+
logger?.info(`opened credit account ${index}/${total}`);
|
|
182
|
+
}
|
|
183
|
+
async getOpenedAccounts() {
|
|
184
|
+
return await this.#service.getCreditAccounts({
|
|
185
|
+
owner: this.borrower
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Creates borrower wallet,
|
|
190
|
+
* Sets ETH balance,
|
|
191
|
+
* Gets tokens from faucet,
|
|
192
|
+
* Approves collateral tokens to credit manager,
|
|
193
|
+
* Gets DEGEN_NFT,
|
|
194
|
+
*/
|
|
195
|
+
async #prepareBorrower(targets) {
|
|
196
|
+
const borrower = await this.#getBorrower();
|
|
197
|
+
let claimUSD = 0n;
|
|
198
|
+
let degenNFTS = {};
|
|
199
|
+
for (const target of targets) {
|
|
200
|
+
const cm = this.sdk.marketRegister.findCreditManager(
|
|
201
|
+
target.creditManager
|
|
202
|
+
);
|
|
203
|
+
const market = this.sdk.marketRegister.findByCreditManager(
|
|
204
|
+
target.creditManager
|
|
205
|
+
);
|
|
206
|
+
const { minDebt, degenNFT } = cm.creditFacade;
|
|
207
|
+
claimUSD += market.priceOracle.convertToUSD(cm.underlying, minDebt);
|
|
208
|
+
if (isAddress(degenNFT) && degenNFT !== ADDRESS_0X0) {
|
|
209
|
+
degenNFTS[degenNFT] = (degenNFTS[degenNFT] ?? 0) + 1;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
claimUSD = claimUSD * 11n / 10n;
|
|
213
|
+
this.#logger?.debug(`claiming ${formatBN(claimUSD, 8)} USD from faucet`);
|
|
214
|
+
let hash = await this.#anvil.writeContract({
|
|
215
|
+
account: borrower,
|
|
216
|
+
address: this.#faucet,
|
|
217
|
+
abi: [
|
|
218
|
+
{
|
|
219
|
+
type: "function",
|
|
220
|
+
inputs: [
|
|
221
|
+
{ name: "amountUSD", internalType: "uint256", type: "uint256" }
|
|
222
|
+
],
|
|
223
|
+
name: "claim",
|
|
224
|
+
outputs: [],
|
|
225
|
+
stateMutability: "nonpayable"
|
|
226
|
+
}
|
|
227
|
+
],
|
|
228
|
+
functionName: "claim",
|
|
229
|
+
args: [claimUSD],
|
|
230
|
+
chain: this.#anvil.chain
|
|
231
|
+
});
|
|
232
|
+
let receipt = await this.#anvil.waitForTransactionReceipt({
|
|
233
|
+
hash
|
|
234
|
+
});
|
|
235
|
+
if (receipt.status === "reverted") {
|
|
236
|
+
throw new Error(
|
|
237
|
+
`borrower ${borrower.address} failed to claimed equivalent of ${formatBN(claimUSD, 8)} USD from faucet, tx: ${hash}`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
this.#logger?.debug(
|
|
241
|
+
`borrower ${borrower.address} claimed equivalent of ${formatBN(claimUSD, 8)} USD from faucet, tx: ${hash}`
|
|
242
|
+
);
|
|
243
|
+
for (const [degenNFT, amount] of Object.entries(degenNFTS)) {
|
|
244
|
+
await this.#mintDegenNft(degenNFT, borrower.address, amount);
|
|
245
|
+
}
|
|
246
|
+
this.#logger?.debug("prepared borrower");
|
|
247
|
+
return borrower;
|
|
248
|
+
}
|
|
249
|
+
async #approve(token, cm) {
|
|
250
|
+
const borrower = await this.#getBorrower();
|
|
251
|
+
const symbol = this.#service.sdk.tokensMeta.symbol(token);
|
|
252
|
+
try {
|
|
253
|
+
if (symbol === "USDT") {
|
|
254
|
+
const hash2 = await this.#anvil.writeContract({
|
|
255
|
+
account: borrower,
|
|
256
|
+
address: token,
|
|
257
|
+
abi: ierc20Abi,
|
|
258
|
+
functionName: "approve",
|
|
259
|
+
args: [cm.creditManager.address, 0n],
|
|
260
|
+
chain: this.#anvil.chain
|
|
261
|
+
});
|
|
262
|
+
await this.#anvil.waitForTransactionReceipt({
|
|
263
|
+
hash: hash2
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
const hash = await this.#anvil.writeContract({
|
|
267
|
+
account: borrower,
|
|
268
|
+
address: token,
|
|
269
|
+
abi: ierc20Abi,
|
|
270
|
+
functionName: "approve",
|
|
271
|
+
args: [cm.creditManager.address, MAX_UINT256],
|
|
272
|
+
chain: this.#anvil.chain
|
|
273
|
+
});
|
|
274
|
+
const receipt = await this.#anvil.waitForTransactionReceipt({
|
|
275
|
+
hash
|
|
276
|
+
});
|
|
277
|
+
if (receipt.status === "reverted") {
|
|
278
|
+
this.#logger?.error(
|
|
279
|
+
`failed to allowed credit manager ${cm.creditManager.name} to spend ${symbol} (${token}), tx reverted: ${hash}`
|
|
280
|
+
);
|
|
281
|
+
} else {
|
|
282
|
+
this.#logger?.debug(
|
|
283
|
+
`allowed credit manager ${cm.creditManager.name} to spend ${symbol} (${token}), tx: ${hash}`
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
} catch (e) {
|
|
287
|
+
this.#logger?.error(
|
|
288
|
+
`failed to allowed credit manager ${cm.creditManager.name} to spend ${symbol} (${token}): ${e}`
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async #mintDegenNft(degenNFT, to, amount) {
|
|
293
|
+
if (amount <= 0) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
let minter;
|
|
297
|
+
try {
|
|
298
|
+
minter = await this.#anvil.readContract({
|
|
299
|
+
address: degenNFT,
|
|
300
|
+
abi: iDegenNftv2Abi,
|
|
301
|
+
functionName: "minter"
|
|
302
|
+
});
|
|
303
|
+
} catch (e) {
|
|
304
|
+
this.#logger?.error(`failed to get minter of degenNFT ${degenNFT}: ${e}`);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
await this.#anvil.impersonateAccount({ address: minter });
|
|
309
|
+
await this.#anvil.setBalance({
|
|
310
|
+
address: minter,
|
|
311
|
+
value: parseEther("100")
|
|
312
|
+
});
|
|
313
|
+
const hash = await this.#anvil.writeContract({
|
|
314
|
+
account: minter,
|
|
315
|
+
address: degenNFT,
|
|
316
|
+
abi: iDegenNftv2Abi,
|
|
317
|
+
functionName: "mint",
|
|
318
|
+
args: [to, BigInt(amount)],
|
|
319
|
+
chain: this.#anvil.chain
|
|
320
|
+
});
|
|
321
|
+
const receipt = await this.#anvil.waitForTransactionReceipt({
|
|
322
|
+
hash
|
|
323
|
+
});
|
|
324
|
+
if (receipt.status === "reverted") {
|
|
325
|
+
this.#logger?.error(
|
|
326
|
+
`failed to mint ${amount} degenNFT ${degenNFT} to borrower ${to}, tx reverted: ${hash}`
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
this.#logger?.debug(
|
|
330
|
+
`minted ${amount} degenNFT ${degenNFT} to borrower ${to}, tx: ${hash}`
|
|
331
|
+
);
|
|
332
|
+
} catch (e) {
|
|
333
|
+
this.#logger?.error(
|
|
334
|
+
`failed to mint ${amount} degenNFT ${degenNFT} to borrower ${to}: ${e}`
|
|
335
|
+
);
|
|
336
|
+
} finally {
|
|
337
|
+
await this.#anvil.stopImpersonatingAccount({ address: minter });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async #getBorrower() {
|
|
341
|
+
if (!this.#borrower) {
|
|
342
|
+
this.#borrower = privateKeyToAccount(generatePrivateKey());
|
|
343
|
+
await this.#anvil.setBalance({
|
|
344
|
+
address: this.#borrower.address,
|
|
345
|
+
value: parseEther("100")
|
|
346
|
+
});
|
|
347
|
+
this.#logger?.info(`created borrower ${this.#borrower.address}`);
|
|
348
|
+
}
|
|
349
|
+
return this.#borrower;
|
|
350
|
+
}
|
|
351
|
+
#getCollateralQuota(cm, collateral, amount, debt) {
|
|
352
|
+
const { underlying, collateralTokens } = cm;
|
|
353
|
+
const inUnderlying = collateral.toLowerCase() === underlying.toLowerCase();
|
|
354
|
+
if (inUnderlying) {
|
|
355
|
+
return [];
|
|
356
|
+
}
|
|
357
|
+
const collateralLT = BigInt(collateralTokens[collateral]);
|
|
358
|
+
const market = this.sdk.marketRegister.findByCreditManager(
|
|
359
|
+
cm.creditManager.address
|
|
360
|
+
);
|
|
361
|
+
const quotaInfo = market.pool.pqk.quotas.mustGet(collateral);
|
|
362
|
+
const availableQuota = quotaInfo.limit - quotaInfo.totalQuoted;
|
|
363
|
+
if (availableQuota <= 0n) {
|
|
364
|
+
throw new Error(
|
|
365
|
+
`quota exceeded for asset ${this.labelAddress(collateral)} in ${cm.name}`
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
const desiredQuota = this.#calcQuota(amount, debt, collateralLT);
|
|
369
|
+
return [
|
|
370
|
+
{
|
|
371
|
+
token: collateral,
|
|
372
|
+
balance: desiredQuota < availableQuota ? desiredQuota : availableQuota
|
|
373
|
+
}
|
|
374
|
+
];
|
|
375
|
+
}
|
|
376
|
+
#calcQuota(amount, debt, lt) {
|
|
377
|
+
let quota = amount * lt / PERCENTAGE_FACTOR;
|
|
378
|
+
quota = debt < quota ? debt : quota;
|
|
379
|
+
quota = quota * (PERCENTAGE_FACTOR + 500n) / PERCENTAGE_FACTOR;
|
|
380
|
+
return quota / PERCENTAGE_FACTOR * PERCENTAGE_FACTOR;
|
|
381
|
+
}
|
|
382
|
+
};
|
|
5
383
|
async function calcLiquidatableLTs(sdk, ca, factor = 9990n, logger) {
|
|
6
384
|
const cm = sdk.marketRegister.findCreditManager(ca.creditManager);
|
|
7
385
|
const market = sdk.marketRegister.findByCreditManager(ca.creditManager);
|
|
@@ -40,51 +418,242 @@ async function calcLiquidatableLTs(sdk, ca, factor = 9990n, logger) {
|
|
|
40
418
|
if (token !== ca.underlying) {
|
|
41
419
|
const newLT = oldLT * k / WAD;
|
|
42
420
|
logger?.debug(
|
|
43
|
-
`proposed ${sdk.
|
|
421
|
+
`proposed ${sdk.tokensMeta.symbol(token)} LT change: ${oldLT} => ${newLT} `
|
|
44
422
|
);
|
|
45
423
|
result[token] = Number(newLT);
|
|
46
424
|
}
|
|
47
425
|
}
|
|
48
426
|
return result;
|
|
49
427
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
428
|
+
|
|
429
|
+
// src/dev/abi/iPriceFeedStore.ts
|
|
430
|
+
var iPriceFeedStoreAbi = [
|
|
431
|
+
{
|
|
432
|
+
type: "function",
|
|
433
|
+
name: "addPriceFeed",
|
|
434
|
+
inputs: [
|
|
435
|
+
{ name: "priceFeed", type: "address", internalType: "address" },
|
|
436
|
+
{ name: "stalenessPeriod", type: "uint32", internalType: "uint32" }
|
|
437
|
+
],
|
|
438
|
+
outputs: [],
|
|
439
|
+
stateMutability: "nonpayable"
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
type: "function",
|
|
443
|
+
name: "allowPriceFeed",
|
|
444
|
+
inputs: [
|
|
445
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
446
|
+
{ name: "priceFeed", type: "address", internalType: "address" }
|
|
447
|
+
],
|
|
448
|
+
outputs: [],
|
|
449
|
+
stateMutability: "nonpayable"
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
type: "function",
|
|
453
|
+
name: "contractType",
|
|
454
|
+
inputs: [],
|
|
455
|
+
outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
|
|
456
|
+
stateMutability: "view"
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
type: "function",
|
|
460
|
+
name: "forbidPriceFeed",
|
|
461
|
+
inputs: [
|
|
462
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
463
|
+
{ name: "priceFeed", type: "address", internalType: "address" }
|
|
464
|
+
],
|
|
465
|
+
outputs: [],
|
|
466
|
+
stateMutability: "nonpayable"
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
type: "function",
|
|
470
|
+
name: "getAllowanceTimestamp",
|
|
471
|
+
inputs: [
|
|
472
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
473
|
+
{ name: "priceFeed", type: "address", internalType: "address" }
|
|
474
|
+
],
|
|
475
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
476
|
+
stateMutability: "view"
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
type: "function",
|
|
480
|
+
name: "getKnownPriceFeeds",
|
|
481
|
+
inputs: [],
|
|
482
|
+
outputs: [{ name: "", type: "address[]", internalType: "address[]" }],
|
|
483
|
+
stateMutability: "view"
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
type: "function",
|
|
487
|
+
name: "getKnownTokens",
|
|
488
|
+
inputs: [],
|
|
489
|
+
outputs: [{ name: "", type: "address[]", internalType: "address[]" }],
|
|
490
|
+
stateMutability: "view"
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
type: "function",
|
|
494
|
+
name: "getPriceFeeds",
|
|
495
|
+
inputs: [{ name: "token", type: "address", internalType: "address" }],
|
|
496
|
+
outputs: [{ name: "", type: "address[]", internalType: "address[]" }],
|
|
497
|
+
stateMutability: "view"
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
type: "function",
|
|
501
|
+
name: "getStalenessPeriod",
|
|
502
|
+
inputs: [{ name: "priceFeed", type: "address", internalType: "address" }],
|
|
503
|
+
outputs: [{ name: "", type: "uint32", internalType: "uint32" }],
|
|
504
|
+
stateMutability: "view"
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
type: "function",
|
|
508
|
+
name: "getTokenPriceFeedsMap",
|
|
509
|
+
inputs: [],
|
|
510
|
+
outputs: [
|
|
511
|
+
{
|
|
512
|
+
name: "",
|
|
513
|
+
type: "tuple[]",
|
|
514
|
+
internalType: "struct ConnectedPriceFeed[]",
|
|
515
|
+
components: [
|
|
516
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
517
|
+
{ name: "priceFeeds", type: "address[]", internalType: "address[]" }
|
|
518
|
+
]
|
|
519
|
+
}
|
|
520
|
+
],
|
|
521
|
+
stateMutability: "view"
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
type: "function",
|
|
525
|
+
name: "isAllowedPriceFeed",
|
|
526
|
+
inputs: [
|
|
527
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
528
|
+
{ name: "priceFeed", type: "address", internalType: "address" }
|
|
529
|
+
],
|
|
530
|
+
outputs: [{ name: "", type: "bool", internalType: "bool" }],
|
|
531
|
+
stateMutability: "view"
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
type: "function",
|
|
535
|
+
name: "owner",
|
|
536
|
+
inputs: [],
|
|
537
|
+
outputs: [{ name: "", type: "address", internalType: "address" }],
|
|
538
|
+
stateMutability: "view"
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
type: "function",
|
|
542
|
+
name: "setStalenessPeriod",
|
|
543
|
+
inputs: [
|
|
544
|
+
{ name: "priceFeed", type: "address", internalType: "address" },
|
|
545
|
+
{ name: "stalenessPeriod", type: "uint32", internalType: "uint32" }
|
|
546
|
+
],
|
|
547
|
+
outputs: [],
|
|
548
|
+
stateMutability: "nonpayable"
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
type: "function",
|
|
552
|
+
name: "version",
|
|
553
|
+
inputs: [],
|
|
554
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
555
|
+
stateMutability: "view"
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
type: "event",
|
|
559
|
+
name: "AddPriceFeed",
|
|
560
|
+
inputs: [
|
|
561
|
+
{
|
|
562
|
+
name: "priceFeed",
|
|
563
|
+
type: "address",
|
|
564
|
+
indexed: false,
|
|
565
|
+
internalType: "address"
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
name: "stalenessPeriod",
|
|
569
|
+
type: "uint32",
|
|
570
|
+
indexed: false,
|
|
571
|
+
internalType: "uint32"
|
|
572
|
+
}
|
|
573
|
+
],
|
|
574
|
+
anonymous: false
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
type: "event",
|
|
578
|
+
name: "AllowPriceFeed",
|
|
579
|
+
inputs: [
|
|
580
|
+
{
|
|
581
|
+
name: "token",
|
|
582
|
+
type: "address",
|
|
583
|
+
indexed: false,
|
|
584
|
+
internalType: "address"
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
name: "priceFeed",
|
|
588
|
+
type: "address",
|
|
589
|
+
indexed: false,
|
|
590
|
+
internalType: "address"
|
|
591
|
+
}
|
|
592
|
+
],
|
|
593
|
+
anonymous: false
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
type: "event",
|
|
597
|
+
name: "ForbidPriceFeed",
|
|
598
|
+
inputs: [
|
|
599
|
+
{
|
|
600
|
+
name: "token",
|
|
601
|
+
type: "address",
|
|
602
|
+
indexed: false,
|
|
603
|
+
internalType: "address"
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
name: "priceFeed",
|
|
607
|
+
type: "address",
|
|
608
|
+
indexed: false,
|
|
609
|
+
internalType: "address"
|
|
610
|
+
}
|
|
611
|
+
],
|
|
612
|
+
anonymous: false
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
type: "event",
|
|
616
|
+
name: "SetStalenessPeriod",
|
|
617
|
+
inputs: [
|
|
618
|
+
{
|
|
619
|
+
name: "priceFeed",
|
|
620
|
+
type: "address",
|
|
621
|
+
indexed: false,
|
|
622
|
+
internalType: "address"
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
name: "stalenessPeriod",
|
|
626
|
+
type: "uint32",
|
|
627
|
+
indexed: false,
|
|
628
|
+
internalType: "uint32"
|
|
629
|
+
}
|
|
630
|
+
],
|
|
631
|
+
anonymous: false
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
type: "error",
|
|
635
|
+
name: "CallerIsNotOwnerException",
|
|
636
|
+
inputs: [{ name: "caller", type: "address", internalType: "address" }]
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
type: "error",
|
|
640
|
+
name: "PriceFeedAlreadyAddedException",
|
|
641
|
+
inputs: [{ name: "priceFeed", type: "address", internalType: "address" }]
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
type: "error",
|
|
645
|
+
name: "PriceFeedIsNotAllowedException",
|
|
646
|
+
inputs: [
|
|
647
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
648
|
+
{ name: "priceFeed", type: "address", internalType: "address" }
|
|
649
|
+
]
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
type: "error",
|
|
653
|
+
name: "PriceFeedNotKnownException",
|
|
654
|
+
inputs: [{ name: "priceFeed", type: "address", internalType: "address" }]
|
|
86
655
|
}
|
|
87
|
-
|
|
656
|
+
];
|
|
88
657
|
|
|
89
658
|
// src/dev/abi/v3.ts
|
|
90
659
|
var iaclAbi = [
|
|
@@ -186,6 +755,21 @@ var iaclAbi = [
|
|
|
186
755
|
name: "AddressNotUnpausableAdminException"
|
|
187
756
|
}
|
|
188
757
|
];
|
|
758
|
+
var iaclTraitAbi = [
|
|
759
|
+
{
|
|
760
|
+
type: "function",
|
|
761
|
+
name: "acl",
|
|
762
|
+
inputs: [],
|
|
763
|
+
outputs: [
|
|
764
|
+
{
|
|
765
|
+
name: "",
|
|
766
|
+
type: "address",
|
|
767
|
+
internalType: "address"
|
|
768
|
+
}
|
|
769
|
+
],
|
|
770
|
+
stateMutability: "view"
|
|
771
|
+
}
|
|
772
|
+
];
|
|
189
773
|
var iCreditConfiguratorV3Abi = [
|
|
190
774
|
{
|
|
191
775
|
type: "function",
|
|
@@ -1448,18 +2032,219 @@ var iCreditManagerV3Abi = [
|
|
|
1448
2032
|
}
|
|
1449
2033
|
];
|
|
1450
2034
|
|
|
1451
|
-
// src/dev/
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
2035
|
+
// src/dev/PriceFeedStore.ts
|
|
2036
|
+
var PriceFeedStore = class extends SDKConstruct {
|
|
2037
|
+
#store;
|
|
2038
|
+
#compressor;
|
|
2039
|
+
#logger;
|
|
2040
|
+
constructor(sdk) {
|
|
2041
|
+
super(sdk);
|
|
2042
|
+
this.#store = this.sdk.addressProvider.getAddress("PRICE_FEED_STORE");
|
|
2043
|
+
this.#compressor = this.sdk.addressProvider.getLatestVersion(
|
|
2044
|
+
AP_PRICE_FEED_COMPRESSOR
|
|
2045
|
+
);
|
|
2046
|
+
this.#logger = sdk.logger?.child?.({
|
|
2047
|
+
module: "PriceFeedStore"
|
|
2048
|
+
});
|
|
2049
|
+
}
|
|
2050
|
+
async load(update = true) {
|
|
2051
|
+
const pfMap = await this.provider.publicClient.readContract({
|
|
2052
|
+
address: this.#store,
|
|
2053
|
+
abi: iPriceFeedStoreAbi,
|
|
2054
|
+
functionName: "getTokenPriceFeedsMap"
|
|
2055
|
+
});
|
|
2056
|
+
const addresses = pfMap.flatMap((f) => f.priceFeeds);
|
|
2057
|
+
const nodes = await this.#loadFromCompressor(addresses, update);
|
|
2058
|
+
const result = new AddressMap();
|
|
2059
|
+
for (const { token, priceFeeds } of pfMap) {
|
|
2060
|
+
result.upsert(
|
|
2061
|
+
token,
|
|
2062
|
+
priceFeeds.map((pf) => nodes.find((n) => n.baseParams.addr === pf)).filter(Boolean)
|
|
2063
|
+
);
|
|
2064
|
+
}
|
|
2065
|
+
return result;
|
|
2066
|
+
}
|
|
2067
|
+
async #loadFromCompressor(priceFeeds, update = true) {
|
|
2068
|
+
let result = await this.provider.publicClient.readContract({
|
|
2069
|
+
address: this.#compressor,
|
|
2070
|
+
abi: iPriceFeedCompressorAbi,
|
|
2071
|
+
functionName: "loadPriceFeedTree",
|
|
2072
|
+
args: [priceFeeds]
|
|
2073
|
+
});
|
|
2074
|
+
if (update) {
|
|
2075
|
+
const feeds = result.map((f) => this.sdk.priceFeeds.create(f));
|
|
2076
|
+
const { txs } = await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(feeds);
|
|
2077
|
+
const resp = await this.provider.publicClient.multicall({
|
|
2078
|
+
contracts: [
|
|
2079
|
+
...txs.map(rawTxToMulticallPriceUpdate),
|
|
2080
|
+
{
|
|
2081
|
+
address: this.#compressor,
|
|
2082
|
+
abi: iPriceFeedCompressorAbi,
|
|
2083
|
+
functionName: "loadPriceFeedTree",
|
|
2084
|
+
args: [priceFeeds]
|
|
2085
|
+
}
|
|
2086
|
+
],
|
|
2087
|
+
allowFailure: false
|
|
2088
|
+
});
|
|
2089
|
+
result = resp.pop();
|
|
2090
|
+
}
|
|
2091
|
+
this.#logger?.debug(
|
|
2092
|
+
`loaded ${result.length} price feed nodes from compressor`
|
|
2093
|
+
);
|
|
2094
|
+
return [...result];
|
|
2095
|
+
}
|
|
2096
|
+
};
|
|
2097
|
+
var SDKExample = class {
|
|
2098
|
+
#sdk;
|
|
2099
|
+
#logger;
|
|
2100
|
+
constructor(logger) {
|
|
2101
|
+
this.#logger = logger;
|
|
2102
|
+
}
|
|
2103
|
+
async run(opts) {
|
|
2104
|
+
const {
|
|
2105
|
+
addressProvider: ap,
|
|
2106
|
+
addressProviderJson,
|
|
2107
|
+
marketConfigurators,
|
|
2108
|
+
anvilUrl = "http://127.0.0.1:8545",
|
|
2109
|
+
outFile
|
|
2110
|
+
} = opts;
|
|
2111
|
+
const addressProvider = await this.#readConfigAddress(
|
|
2112
|
+
"addressProvider",
|
|
2113
|
+
ap,
|
|
2114
|
+
addressProviderJson
|
|
2115
|
+
);
|
|
2116
|
+
this.#sdk = await GearboxSDK.attach({
|
|
2117
|
+
rpcURLs: [anvilUrl],
|
|
2118
|
+
timeout: 48e4,
|
|
2119
|
+
addressProvider,
|
|
2120
|
+
logger: this.#logger,
|
|
2121
|
+
ignoreUpdateablePrices: true,
|
|
2122
|
+
marketConfigurators
|
|
2123
|
+
});
|
|
2124
|
+
await this.#safeMigrateFaucet(addressProvider);
|
|
2125
|
+
const puTx = await this.#sdk.priceFeeds.getUpdatePriceFeedsTx(marketConfigurators);
|
|
2126
|
+
const updater = createWalletClient({
|
|
2127
|
+
account: privateKeyToAccount(
|
|
2128
|
+
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
|
|
2129
|
+
// well-known anvil private key
|
|
2130
|
+
),
|
|
2131
|
+
transport: http(anvilUrl)
|
|
2132
|
+
});
|
|
2133
|
+
const publicClient = createPublicClient({
|
|
2134
|
+
transport: http(anvilUrl)
|
|
2135
|
+
});
|
|
2136
|
+
const hash = await sendRawTx(updater, { tx: puTx });
|
|
2137
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
2138
|
+
await this.#sdk.marketRegister.loadMarkets(marketConfigurators, true);
|
|
2139
|
+
try {
|
|
2140
|
+
await this.#sdk.marketRegister.loadZappers();
|
|
2141
|
+
} catch (e) {
|
|
2142
|
+
this.#logger?.error(`failed to load zappers: ${e}`);
|
|
2143
|
+
}
|
|
2144
|
+
this.#logger?.info("attached sdk");
|
|
2145
|
+
if (outFile) {
|
|
2146
|
+
try {
|
|
2147
|
+
await writeFile(
|
|
2148
|
+
outFile,
|
|
2149
|
+
json_stringify(this.#sdk.stateHuman()),
|
|
2150
|
+
"utf-8"
|
|
2151
|
+
);
|
|
2152
|
+
} catch (e) {
|
|
2153
|
+
this.#logger?.error(`failed to write to ${outFile}: ${e}`);
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
async #readConfigAddress(name, value, file) {
|
|
2158
|
+
let result = value;
|
|
2159
|
+
if (!result) {
|
|
2160
|
+
if (!file) {
|
|
2161
|
+
throw new Error(`${name} is not specified`);
|
|
2162
|
+
}
|
|
2163
|
+
this.#logger?.debug(`reading ${name} json ${file}`);
|
|
2164
|
+
const apFile = await readFile(file, "utf-8").then(JSON.parse);
|
|
2165
|
+
result = apFile[name];
|
|
2166
|
+
}
|
|
2167
|
+
if (!result) {
|
|
2168
|
+
throw new Error(`${name} is not specified`);
|
|
2169
|
+
}
|
|
2170
|
+
if (!isAddress(result)) {
|
|
2171
|
+
throw new Error(`${name} is not a valid address: ${result}`);
|
|
2172
|
+
}
|
|
2173
|
+
this.#logger?.info(`using ${name} ${result}`);
|
|
2174
|
+
return result;
|
|
2175
|
+
}
|
|
2176
|
+
async #safeMigrateFaucet(addressProvider) {
|
|
2177
|
+
try {
|
|
2178
|
+
await this.#migrateFaucet(addressProvider);
|
|
2179
|
+
this.#logger?.info("faucet migrated successfully");
|
|
2180
|
+
} catch (e) {
|
|
2181
|
+
this.#logger?.error(`faucet migration failed: ${e}`);
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* Migrates faucet from address provider v3 to v3.1
|
|
2186
|
+
* @param addressProvider 3.1 address provider
|
|
2187
|
+
*/
|
|
2188
|
+
async #migrateFaucet(addressProvider) {
|
|
2189
|
+
const anvil = createAnvilClient({
|
|
2190
|
+
chain: this.sdk.provider.chain,
|
|
2191
|
+
transport: this.sdk.provider.transport
|
|
2192
|
+
});
|
|
2193
|
+
const [faucetAddr, owner] = await anvil.multicall({
|
|
2194
|
+
contracts: [
|
|
2195
|
+
{
|
|
2196
|
+
abi: iAddressProviderV3Abi,
|
|
2197
|
+
address: ADDRESS_PROVIDER[this.sdk.provider.networkType],
|
|
2198
|
+
functionName: "getAddressOrRevert",
|
|
2199
|
+
args: [stringToHex("FAUCET", { size: 32 }), 0n]
|
|
2200
|
+
},
|
|
2201
|
+
{
|
|
2202
|
+
abi: iAddressProviderV3_1Abi,
|
|
2203
|
+
address: addressProvider,
|
|
2204
|
+
functionName: "owner",
|
|
2205
|
+
args: []
|
|
2206
|
+
}
|
|
2207
|
+
],
|
|
2208
|
+
allowFailure: false
|
|
2209
|
+
});
|
|
2210
|
+
this.#logger?.debug(`faucet address: ${faucetAddr}, owner: ${owner}`);
|
|
2211
|
+
await anvil.impersonateAccount({ address: owner });
|
|
2212
|
+
await anvil.setBalance({
|
|
2213
|
+
address: owner,
|
|
2214
|
+
value: parseEther("100")
|
|
2215
|
+
});
|
|
2216
|
+
const hash = await anvil.writeContract({
|
|
2217
|
+
chain: anvil.chain,
|
|
2218
|
+
account: owner,
|
|
2219
|
+
address: addressProvider,
|
|
2220
|
+
abi: iAddressProviderV3_1Abi,
|
|
2221
|
+
functionName: "setAddress",
|
|
2222
|
+
args: [stringToHex("FAUCET", { size: 32 }), faucetAddr, true]
|
|
2223
|
+
});
|
|
2224
|
+
const receipt = await anvil.waitForTransactionReceipt({ hash });
|
|
2225
|
+
await anvil.stopImpersonatingAccount({ address: owner });
|
|
2226
|
+
if (receipt.status === "reverted") {
|
|
2227
|
+
throw new Error("faucet migration reverted");
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
get sdk() {
|
|
2231
|
+
if (!this.#sdk) {
|
|
2232
|
+
throw new Error("sdk is not attached");
|
|
2233
|
+
}
|
|
2234
|
+
return this.#sdk;
|
|
2235
|
+
}
|
|
2236
|
+
};
|
|
2237
|
+
async function setLTs(anvil, cm, newLTs, logger) {
|
|
2238
|
+
const aclAddr = await anvil.readContract({
|
|
2239
|
+
address: cm.creditConfigurator,
|
|
2240
|
+
abi: iaclTraitAbi,
|
|
2241
|
+
functionName: "acl"
|
|
2242
|
+
});
|
|
2243
|
+
const configuratorAddr = await anvil.readContract({
|
|
1455
2244
|
address: aclAddr,
|
|
1456
2245
|
abi: iaclAbi,
|
|
1457
2246
|
functionName: "owner"
|
|
1458
2247
|
});
|
|
1459
|
-
const anvil = createAnvilClient({
|
|
1460
|
-
transport: sdk.provider.transport,
|
|
1461
|
-
chain: sdk.provider.chain
|
|
1462
|
-
});
|
|
1463
2248
|
await anvil.impersonateAccount({
|
|
1464
2249
|
address: configuratorAddr
|
|
1465
2250
|
});
|
|
@@ -1468,27 +2253,114 @@ async function setLTs(sdk, cm, newLTs, logger) {
|
|
|
1468
2253
|
value: parseEther("100")
|
|
1469
2254
|
});
|
|
1470
2255
|
for (const [t, lt] of Object.entries(newLTs)) {
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
`set ${
|
|
1487
|
-
|
|
2256
|
+
try {
|
|
2257
|
+
await anvil.writeContract({
|
|
2258
|
+
chain: anvil.chain,
|
|
2259
|
+
address: cm.creditConfigurator,
|
|
2260
|
+
account: configuratorAddr,
|
|
2261
|
+
abi: iCreditConfiguratorV3Abi,
|
|
2262
|
+
functionName: "setLiquidationThreshold",
|
|
2263
|
+
args: [t, lt]
|
|
2264
|
+
});
|
|
2265
|
+
const newLT = await anvil.readContract({
|
|
2266
|
+
address: cm.address,
|
|
2267
|
+
abi: iCreditManagerV3Abi,
|
|
2268
|
+
functionName: "liquidationThresholds",
|
|
2269
|
+
args: [t]
|
|
2270
|
+
});
|
|
2271
|
+
logger?.debug(`set ${t} LT to ${newLT}`);
|
|
2272
|
+
} catch {
|
|
2273
|
+
}
|
|
1488
2274
|
}
|
|
1489
2275
|
await anvil.stopImpersonatingAccount({
|
|
1490
2276
|
address: configuratorAddr
|
|
1491
2277
|
});
|
|
1492
2278
|
}
|
|
2279
|
+
async function setLTZero(anvil, cm, logger) {
|
|
2280
|
+
const aclAddr = await anvil.readContract({
|
|
2281
|
+
address: cm.creditConfigurator,
|
|
2282
|
+
abi: iaclTraitAbi,
|
|
2283
|
+
functionName: "acl"
|
|
2284
|
+
});
|
|
2285
|
+
const configuratorAddr = await anvil.readContract({
|
|
2286
|
+
address: aclAddr,
|
|
2287
|
+
abi: iaclAbi,
|
|
2288
|
+
functionName: "owner"
|
|
2289
|
+
});
|
|
2290
|
+
await anvil.impersonateAccount({
|
|
2291
|
+
address: configuratorAddr
|
|
2292
|
+
});
|
|
2293
|
+
await anvil.setBalance({
|
|
2294
|
+
address: configuratorAddr,
|
|
2295
|
+
value: parseEther("100")
|
|
2296
|
+
});
|
|
2297
|
+
let hash = await anvil.writeContract({
|
|
2298
|
+
chain: anvil.chain,
|
|
2299
|
+
address: cm.creditConfigurator,
|
|
2300
|
+
account: configuratorAddr,
|
|
2301
|
+
abi: iCreditConfiguratorV3Abi,
|
|
2302
|
+
functionName: "setFees",
|
|
2303
|
+
args: [
|
|
2304
|
+
cm.feeInterest,
|
|
2305
|
+
cm.liquidationDiscount - 1,
|
|
2306
|
+
Number(PERCENTAGE_FACTOR) - cm.liquidationDiscount,
|
|
2307
|
+
cm.feeLiquidationExpired,
|
|
2308
|
+
cm.liquidationDiscountExpired
|
|
2309
|
+
]
|
|
2310
|
+
});
|
|
2311
|
+
await anvil.waitForTransactionReceipt({ hash });
|
|
2312
|
+
logger?.debug(`[${cm.name}] setFees part 2`);
|
|
2313
|
+
hash = await anvil.writeContract({
|
|
2314
|
+
chain: anvil.chain,
|
|
2315
|
+
address: cm.creditConfigurator,
|
|
2316
|
+
account: configuratorAddr,
|
|
2317
|
+
abi: iCreditConfiguratorV3Abi,
|
|
2318
|
+
functionName: "setFees",
|
|
2319
|
+
args: [
|
|
2320
|
+
cm.feeInterest,
|
|
2321
|
+
cm.feeLiquidation,
|
|
2322
|
+
Number(PERCENTAGE_FACTOR) - cm.liquidationDiscount,
|
|
2323
|
+
cm.feeLiquidationExpired,
|
|
2324
|
+
cm.liquidationDiscountExpired
|
|
2325
|
+
]
|
|
2326
|
+
});
|
|
2327
|
+
await anvil.waitForTransactionReceipt({ hash });
|
|
2328
|
+
logger?.debug(`[${cm.name}] setFees done`);
|
|
2329
|
+
await anvil.impersonateAccount({
|
|
2330
|
+
address: cm.creditConfigurator
|
|
2331
|
+
});
|
|
2332
|
+
await anvil.setBalance({
|
|
2333
|
+
address: cm.creditConfigurator,
|
|
2334
|
+
value: parseEther("100")
|
|
2335
|
+
});
|
|
2336
|
+
logger?.debug(
|
|
2337
|
+
`[${cm.name}] impresonating creditConfigurator ${cm.creditConfigurator}`
|
|
2338
|
+
);
|
|
2339
|
+
logger?.debug(`[${cm.name}] setting liquidation threshold`);
|
|
2340
|
+
hash = await anvil.writeContract({
|
|
2341
|
+
chain: anvil.chain,
|
|
2342
|
+
address: cm.baseParams.addr,
|
|
2343
|
+
account: cm.creditConfigurator,
|
|
2344
|
+
abi: iCreditManagerV3Abi,
|
|
2345
|
+
functionName: "setCollateralTokenData",
|
|
2346
|
+
args: [cm.underlying, 1, 1, Number(2n ** 40n - 1n), 0]
|
|
2347
|
+
});
|
|
2348
|
+
await anvil.waitForTransactionReceipt({ hash });
|
|
2349
|
+
logger?.debug(`[${cm.name}] setting configurator ${cm.creditConfigurator}`);
|
|
2350
|
+
hash = await anvil.writeContract({
|
|
2351
|
+
chain: anvil.chain,
|
|
2352
|
+
address: cm.baseParams.addr,
|
|
2353
|
+
account: cm.creditConfigurator,
|
|
2354
|
+
abi: iCreditManagerV3Abi,
|
|
2355
|
+
functionName: "setCreditConfigurator",
|
|
2356
|
+
args: [cm.creditConfigurator]
|
|
2357
|
+
});
|
|
2358
|
+
await anvil.waitForTransactionReceipt({ hash });
|
|
2359
|
+
logger?.debug(`[${cm.name}] done`);
|
|
2360
|
+
await anvil.stopImpersonatingAccount({
|
|
2361
|
+
address: cm.creditConfigurator
|
|
2362
|
+
});
|
|
2363
|
+
await anvil.stopImpersonatingAccount({ address: configuratorAddr });
|
|
2364
|
+
}
|
|
1493
2365
|
|
|
1494
|
-
export { calcLiquidatableLTs, createAnvilClient, evmMineDetailed, isAnvil, setLTs };
|
|
2366
|
+
export { AccountOpener, PriceFeedStore, SDKExample, anvilNodeInfo, calcLiquidatableLTs, createAnvilClient, evmMineDetailed, isAnvil, setLTZero, setLTs };
|