@gearbox-protocol/sdk 3.0.0-vfour.31 → 3.0.0-vfour.33
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/cjs/sdk/index.cjs +1781 -1559
- package/dist/cjs/sdk/index.d.ts +116 -1
- package/dist/esm/sdk/index.d.mts +116 -1
- package/dist/esm/sdk/index.mjs +1781 -1561
- package/package.json +1 -1
package/dist/cjs/sdk/index.cjs
CHANGED
|
@@ -2067,6 +2067,239 @@ var iMarketCompressorAbi = [
|
|
|
2067
2067
|
stateMutability: "view"
|
|
2068
2068
|
}
|
|
2069
2069
|
];
|
|
2070
|
+
var iPriceFeedCompressorAbi = [
|
|
2071
|
+
{
|
|
2072
|
+
type: "function",
|
|
2073
|
+
inputs: [],
|
|
2074
|
+
name: "contractType",
|
|
2075
|
+
outputs: [{ name: "", internalType: "bytes32", type: "bytes32" }],
|
|
2076
|
+
stateMutability: "view"
|
|
2077
|
+
},
|
|
2078
|
+
{
|
|
2079
|
+
type: "function",
|
|
2080
|
+
inputs: [
|
|
2081
|
+
{ name: "priceOracle", internalType: "address", type: "address" },
|
|
2082
|
+
{ name: "tokens", internalType: "address[]", type: "address[]" }
|
|
2083
|
+
],
|
|
2084
|
+
name: "getPriceFeeds",
|
|
2085
|
+
outputs: [
|
|
2086
|
+
{
|
|
2087
|
+
name: "priceFeedMap",
|
|
2088
|
+
internalType: "struct PriceFeedMapEntry[]",
|
|
2089
|
+
type: "tuple[]",
|
|
2090
|
+
components: [
|
|
2091
|
+
{ name: "token", internalType: "address", type: "address" },
|
|
2092
|
+
{ name: "reserve", internalType: "bool", type: "bool" },
|
|
2093
|
+
{ name: "priceFeed", internalType: "address", type: "address" },
|
|
2094
|
+
{ name: "stalenessPeriod", internalType: "uint32", type: "uint32" }
|
|
2095
|
+
]
|
|
2096
|
+
},
|
|
2097
|
+
{
|
|
2098
|
+
name: "priceFeedTree",
|
|
2099
|
+
internalType: "struct PriceFeedTreeNode[]",
|
|
2100
|
+
type: "tuple[]",
|
|
2101
|
+
components: [
|
|
2102
|
+
{
|
|
2103
|
+
name: "baseParams",
|
|
2104
|
+
internalType: "struct BaseParams",
|
|
2105
|
+
type: "tuple",
|
|
2106
|
+
components: [
|
|
2107
|
+
{ name: "addr", internalType: "address", type: "address" },
|
|
2108
|
+
{ name: "version", internalType: "uint256", type: "uint256" },
|
|
2109
|
+
{
|
|
2110
|
+
name: "contractType",
|
|
2111
|
+
internalType: "bytes32",
|
|
2112
|
+
type: "bytes32"
|
|
2113
|
+
},
|
|
2114
|
+
{
|
|
2115
|
+
name: "serializedParams",
|
|
2116
|
+
internalType: "bytes",
|
|
2117
|
+
type: "bytes"
|
|
2118
|
+
}
|
|
2119
|
+
]
|
|
2120
|
+
},
|
|
2121
|
+
{ name: "decimals", internalType: "uint8", type: "uint8" },
|
|
2122
|
+
{ name: "skipCheck", internalType: "bool", type: "bool" },
|
|
2123
|
+
{ name: "updatable", internalType: "bool", type: "bool" },
|
|
2124
|
+
{
|
|
2125
|
+
name: "underlyingFeeds",
|
|
2126
|
+
internalType: "address[]",
|
|
2127
|
+
type: "address[]"
|
|
2128
|
+
},
|
|
2129
|
+
{
|
|
2130
|
+
name: "underlyingStalenessPeriods",
|
|
2131
|
+
internalType: "uint32[]",
|
|
2132
|
+
type: "uint32[]"
|
|
2133
|
+
},
|
|
2134
|
+
{
|
|
2135
|
+
name: "answer",
|
|
2136
|
+
internalType: "struct PriceFeedAnswer",
|
|
2137
|
+
type: "tuple",
|
|
2138
|
+
components: [
|
|
2139
|
+
{ name: "price", internalType: "int256", type: "int256" },
|
|
2140
|
+
{ name: "updatedAt", internalType: "uint256", type: "uint256" },
|
|
2141
|
+
{ name: "success", internalType: "bool", type: "bool" }
|
|
2142
|
+
]
|
|
2143
|
+
}
|
|
2144
|
+
]
|
|
2145
|
+
}
|
|
2146
|
+
],
|
|
2147
|
+
stateMutability: "view"
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
type: "function",
|
|
2151
|
+
inputs: [{ name: "priceOracle", internalType: "address", type: "address" }],
|
|
2152
|
+
name: "getPriceFeeds",
|
|
2153
|
+
outputs: [
|
|
2154
|
+
{
|
|
2155
|
+
name: "priceFeedMap",
|
|
2156
|
+
internalType: "struct PriceFeedMapEntry[]",
|
|
2157
|
+
type: "tuple[]",
|
|
2158
|
+
components: [
|
|
2159
|
+
{ name: "token", internalType: "address", type: "address" },
|
|
2160
|
+
{ name: "reserve", internalType: "bool", type: "bool" },
|
|
2161
|
+
{ name: "priceFeed", internalType: "address", type: "address" },
|
|
2162
|
+
{ name: "stalenessPeriod", internalType: "uint32", type: "uint32" }
|
|
2163
|
+
]
|
|
2164
|
+
},
|
|
2165
|
+
{
|
|
2166
|
+
name: "priceFeedTree",
|
|
2167
|
+
internalType: "struct PriceFeedTreeNode[]",
|
|
2168
|
+
type: "tuple[]",
|
|
2169
|
+
components: [
|
|
2170
|
+
{
|
|
2171
|
+
name: "baseParams",
|
|
2172
|
+
internalType: "struct BaseParams",
|
|
2173
|
+
type: "tuple",
|
|
2174
|
+
components: [
|
|
2175
|
+
{ name: "addr", internalType: "address", type: "address" },
|
|
2176
|
+
{ name: "version", internalType: "uint256", type: "uint256" },
|
|
2177
|
+
{
|
|
2178
|
+
name: "contractType",
|
|
2179
|
+
internalType: "bytes32",
|
|
2180
|
+
type: "bytes32"
|
|
2181
|
+
},
|
|
2182
|
+
{
|
|
2183
|
+
name: "serializedParams",
|
|
2184
|
+
internalType: "bytes",
|
|
2185
|
+
type: "bytes"
|
|
2186
|
+
}
|
|
2187
|
+
]
|
|
2188
|
+
},
|
|
2189
|
+
{ name: "decimals", internalType: "uint8", type: "uint8" },
|
|
2190
|
+
{ name: "skipCheck", internalType: "bool", type: "bool" },
|
|
2191
|
+
{ name: "updatable", internalType: "bool", type: "bool" },
|
|
2192
|
+
{
|
|
2193
|
+
name: "underlyingFeeds",
|
|
2194
|
+
internalType: "address[]",
|
|
2195
|
+
type: "address[]"
|
|
2196
|
+
},
|
|
2197
|
+
{
|
|
2198
|
+
name: "underlyingStalenessPeriods",
|
|
2199
|
+
internalType: "uint32[]",
|
|
2200
|
+
type: "uint32[]"
|
|
2201
|
+
},
|
|
2202
|
+
{
|
|
2203
|
+
name: "answer",
|
|
2204
|
+
internalType: "struct PriceFeedAnswer",
|
|
2205
|
+
type: "tuple",
|
|
2206
|
+
components: [
|
|
2207
|
+
{ name: "price", internalType: "int256", type: "int256" },
|
|
2208
|
+
{ name: "updatedAt", internalType: "uint256", type: "uint256" },
|
|
2209
|
+
{ name: "success", internalType: "bool", type: "bool" }
|
|
2210
|
+
]
|
|
2211
|
+
}
|
|
2212
|
+
]
|
|
2213
|
+
}
|
|
2214
|
+
],
|
|
2215
|
+
stateMutability: "view"
|
|
2216
|
+
},
|
|
2217
|
+
{
|
|
2218
|
+
type: "function",
|
|
2219
|
+
inputs: [
|
|
2220
|
+
{ name: "priceFeeds", internalType: "address[]", type: "address[]" }
|
|
2221
|
+
],
|
|
2222
|
+
name: "loadPriceFeedTree",
|
|
2223
|
+
outputs: [
|
|
2224
|
+
{
|
|
2225
|
+
name: "priceFeedTree",
|
|
2226
|
+
internalType: "struct PriceFeedTreeNode[]",
|
|
2227
|
+
type: "tuple[]",
|
|
2228
|
+
components: [
|
|
2229
|
+
{
|
|
2230
|
+
name: "baseParams",
|
|
2231
|
+
internalType: "struct BaseParams",
|
|
2232
|
+
type: "tuple",
|
|
2233
|
+
components: [
|
|
2234
|
+
{ name: "addr", internalType: "address", type: "address" },
|
|
2235
|
+
{ name: "version", internalType: "uint256", type: "uint256" },
|
|
2236
|
+
{
|
|
2237
|
+
name: "contractType",
|
|
2238
|
+
internalType: "bytes32",
|
|
2239
|
+
type: "bytes32"
|
|
2240
|
+
},
|
|
2241
|
+
{
|
|
2242
|
+
name: "serializedParams",
|
|
2243
|
+
internalType: "bytes",
|
|
2244
|
+
type: "bytes"
|
|
2245
|
+
}
|
|
2246
|
+
]
|
|
2247
|
+
},
|
|
2248
|
+
{ name: "decimals", internalType: "uint8", type: "uint8" },
|
|
2249
|
+
{ name: "skipCheck", internalType: "bool", type: "bool" },
|
|
2250
|
+
{ name: "updatable", internalType: "bool", type: "bool" },
|
|
2251
|
+
{
|
|
2252
|
+
name: "underlyingFeeds",
|
|
2253
|
+
internalType: "address[]",
|
|
2254
|
+
type: "address[]"
|
|
2255
|
+
},
|
|
2256
|
+
{
|
|
2257
|
+
name: "underlyingStalenessPeriods",
|
|
2258
|
+
internalType: "uint32[]",
|
|
2259
|
+
type: "uint32[]"
|
|
2260
|
+
},
|
|
2261
|
+
{
|
|
2262
|
+
name: "answer",
|
|
2263
|
+
internalType: "struct PriceFeedAnswer",
|
|
2264
|
+
type: "tuple",
|
|
2265
|
+
components: [
|
|
2266
|
+
{ name: "price", internalType: "int256", type: "int256" },
|
|
2267
|
+
{ name: "updatedAt", internalType: "uint256", type: "uint256" },
|
|
2268
|
+
{ name: "success", internalType: "bool", type: "bool" }
|
|
2269
|
+
]
|
|
2270
|
+
}
|
|
2271
|
+
]
|
|
2272
|
+
}
|
|
2273
|
+
],
|
|
2274
|
+
stateMutability: "view"
|
|
2275
|
+
},
|
|
2276
|
+
{
|
|
2277
|
+
type: "function",
|
|
2278
|
+
inputs: [],
|
|
2279
|
+
name: "version",
|
|
2280
|
+
outputs: [{ name: "", internalType: "uint256", type: "uint256" }],
|
|
2281
|
+
stateMutability: "view"
|
|
2282
|
+
},
|
|
2283
|
+
{
|
|
2284
|
+
type: "event",
|
|
2285
|
+
anonymous: false,
|
|
2286
|
+
inputs: [
|
|
2287
|
+
{
|
|
2288
|
+
name: "contractType",
|
|
2289
|
+
internalType: "bytes32",
|
|
2290
|
+
type: "bytes32",
|
|
2291
|
+
indexed: true
|
|
2292
|
+
},
|
|
2293
|
+
{
|
|
2294
|
+
name: "serializer",
|
|
2295
|
+
internalType: "address",
|
|
2296
|
+
type: "address",
|
|
2297
|
+
indexed: true
|
|
2298
|
+
}
|
|
2299
|
+
],
|
|
2300
|
+
name: "SetSerializer"
|
|
2301
|
+
}
|
|
2302
|
+
];
|
|
2070
2303
|
|
|
2071
2304
|
// src/sdk/abi/oracles.ts
|
|
2072
2305
|
var bptStablePriceFeedAbi = [
|
|
@@ -16745,6 +16978,7 @@ var AP_PRICE_ORACLE = "PRICE_ORACLE";
|
|
|
16745
16978
|
var AP_ACCOUNT_FACTORY = "ACCOUNT_FACTORY";
|
|
16746
16979
|
var AP_DATA_COMPRESSOR = "DATA_COMPRESSOR";
|
|
16747
16980
|
var AP_MARKET_COMPRESSOR = "MARKET_COMPRESSOR";
|
|
16981
|
+
var AP_PRICE_FEED_COMPRESSOR = "PRICE_FEED_COMPRESSOR";
|
|
16748
16982
|
var AP_CREDIT_ACCOUNT_COMPRESSOR = "CREDIT_ACCOUNT_COMPRESSOR";
|
|
16749
16983
|
var AP_TREASURY = "TREASURY";
|
|
16750
16984
|
var AP_GEAR_TOKEN = "GEAR_TOKEN";
|
|
@@ -17273,748 +17507,24 @@ var VotingContractStatus = /* @__PURE__ */ ((VotingContractStatus2) => {
|
|
|
17273
17507
|
VotingContractStatus2[VotingContractStatus2["UNVOTE_ONLY"] = 2] = "UNVOTE_ONLY";
|
|
17274
17508
|
return VotingContractStatus2;
|
|
17275
17509
|
})(VotingContractStatus || {});
|
|
17276
|
-
|
|
17277
|
-
|
|
17278
|
-
|
|
17279
|
-
|
|
17280
|
-
|
|
17281
|
-
|
|
17282
|
-
|
|
17283
|
-
|
|
17284
|
-
|
|
17285
|
-
|
|
17286
|
-
Base: chains$1.base
|
|
17287
|
-
};
|
|
17288
|
-
var Provider = class {
|
|
17289
|
-
account;
|
|
17290
|
-
chainId;
|
|
17291
|
-
chain;
|
|
17292
|
-
networkType;
|
|
17293
|
-
publicClient;
|
|
17294
|
-
addressLabels;
|
|
17295
|
-
transport;
|
|
17296
|
-
constructor(opts) {
|
|
17297
|
-
const {
|
|
17298
|
-
account,
|
|
17299
|
-
chainId,
|
|
17300
|
-
networkType,
|
|
17301
|
-
rpcURLs,
|
|
17302
|
-
timeout = 12e4,
|
|
17303
|
-
retryCount
|
|
17304
|
-
} = opts;
|
|
17305
|
-
this.account = account;
|
|
17306
|
-
this.chainId = chainId;
|
|
17307
|
-
this.networkType = networkType;
|
|
17308
|
-
this.chain = viem.defineChain({
|
|
17309
|
-
...chains[networkType],
|
|
17310
|
-
id: chainId
|
|
17311
|
-
});
|
|
17312
|
-
const rpcs = rpcURLs.map((url) => viem.http(url, { timeout, retryCount }));
|
|
17313
|
-
this.transport = rpcs.length ? viem.fallback(rpcs) : rpcs[0];
|
|
17314
|
-
this.publicClient = viem.createPublicClient({
|
|
17315
|
-
chain: this.chain,
|
|
17316
|
-
transport: this.transport
|
|
17510
|
+
|
|
17511
|
+
// src/sdk/market/CreditConfiguratorContract.ts
|
|
17512
|
+
var CreditConfiguratorContract = class extends BaseContract {
|
|
17513
|
+
adapters = [];
|
|
17514
|
+
emergencyLiquidators = [];
|
|
17515
|
+
constructor(sdk, { creditConfigurator, creditManager }, emergencyLiquidators) {
|
|
17516
|
+
super(sdk, {
|
|
17517
|
+
...creditConfigurator.baseParams,
|
|
17518
|
+
name: `CreditConfigurator(${creditManager.name})`,
|
|
17519
|
+
abi: creditConfiguratorV3Abi
|
|
17317
17520
|
});
|
|
17318
|
-
this.
|
|
17521
|
+
this.emergencyLiquidators = [...emergencyLiquidators];
|
|
17319
17522
|
}
|
|
17320
|
-
|
|
17321
|
-
|
|
17322
|
-
|
|
17323
|
-
|
|
17324
|
-
|
|
17325
|
-
try {
|
|
17326
|
-
await client.readContract({
|
|
17327
|
-
abi: ierc20MetadataAbi,
|
|
17328
|
-
address: USDC[chain],
|
|
17329
|
-
functionName: "symbol"
|
|
17330
|
-
});
|
|
17331
|
-
return chain;
|
|
17332
|
-
} catch {
|
|
17333
|
-
}
|
|
17334
|
-
}
|
|
17335
|
-
throw new Error("Unsupported network");
|
|
17336
|
-
}
|
|
17337
|
-
async function simulateMulticall(client, parameters) {
|
|
17338
|
-
const {
|
|
17339
|
-
account,
|
|
17340
|
-
allowFailure = true,
|
|
17341
|
-
batchSize: batchSize_,
|
|
17342
|
-
blockNumber,
|
|
17343
|
-
blockTag,
|
|
17344
|
-
gas,
|
|
17345
|
-
multicallAddress: multicallAddress_,
|
|
17346
|
-
stateOverride
|
|
17347
|
-
} = parameters;
|
|
17348
|
-
const contracts = parameters.contracts;
|
|
17349
|
-
const batchSize = batchSize_ ?? (typeof client.batch?.multicall === "object" && client.batch.multicall.batchSize || 1024);
|
|
17350
|
-
let multicallAddress = multicallAddress_;
|
|
17351
|
-
if (!multicallAddress) {
|
|
17352
|
-
if (!client.chain)
|
|
17353
|
-
throw new Error(
|
|
17354
|
-
"client chain not configured. multicallAddress is required."
|
|
17355
|
-
);
|
|
17356
|
-
multicallAddress = viem.getChainContractAddress({
|
|
17357
|
-
blockNumber,
|
|
17358
|
-
chain: client.chain,
|
|
17359
|
-
contract: "multicall3"
|
|
17360
|
-
});
|
|
17361
|
-
}
|
|
17362
|
-
const chunkedCalls = [[]];
|
|
17363
|
-
let currentChunk = 0;
|
|
17364
|
-
let currentChunkSize = 0;
|
|
17365
|
-
for (const contract of contracts) {
|
|
17366
|
-
const { abi: abi17, address, args, functionName } = contract;
|
|
17367
|
-
try {
|
|
17368
|
-
const callData = viem.encodeFunctionData({ abi: abi17, args, functionName });
|
|
17369
|
-
currentChunkSize += (callData.length - 2) / 2;
|
|
17370
|
-
if (
|
|
17371
|
-
// Check if batching is enabled.
|
|
17372
|
-
batchSize > 0 && // Check if the current size of the batch exceeds the size limit.
|
|
17373
|
-
currentChunkSize > batchSize && // Check if the current chunk is not already empty.
|
|
17374
|
-
chunkedCalls[currentChunk].length > 0
|
|
17375
|
-
) {
|
|
17376
|
-
currentChunk++;
|
|
17377
|
-
currentChunkSize = (callData.length - 2) / 2;
|
|
17378
|
-
chunkedCalls[currentChunk] = [];
|
|
17379
|
-
}
|
|
17380
|
-
chunkedCalls[currentChunk] = [
|
|
17381
|
-
...chunkedCalls[currentChunk],
|
|
17382
|
-
{
|
|
17383
|
-
allowFailure: true,
|
|
17384
|
-
callData,
|
|
17385
|
-
target: address
|
|
17386
|
-
}
|
|
17387
|
-
];
|
|
17388
|
-
} catch (err) {
|
|
17389
|
-
const error = viem.getContractError(err, {
|
|
17390
|
-
abi: abi17,
|
|
17391
|
-
address,
|
|
17392
|
-
args,
|
|
17393
|
-
docsPath: "/docs/contract/multicall",
|
|
17394
|
-
functionName
|
|
17395
|
-
});
|
|
17396
|
-
if (!allowFailure) throw error;
|
|
17397
|
-
chunkedCalls[currentChunk] = [
|
|
17398
|
-
...chunkedCalls[currentChunk],
|
|
17399
|
-
{
|
|
17400
|
-
allowFailure: true,
|
|
17401
|
-
callData: "0x",
|
|
17402
|
-
target: address
|
|
17403
|
-
}
|
|
17404
|
-
];
|
|
17405
|
-
}
|
|
17406
|
-
}
|
|
17407
|
-
const aggregate3Results = await Promise.allSettled(
|
|
17408
|
-
chunkedCalls.map(
|
|
17409
|
-
(calls) => utils.getAction(
|
|
17410
|
-
client,
|
|
17411
|
-
actions.simulateContract,
|
|
17412
|
-
"simulateContract"
|
|
17413
|
-
)({
|
|
17414
|
-
account,
|
|
17415
|
-
abi: viem.multicall3Abi,
|
|
17416
|
-
address: multicallAddress,
|
|
17417
|
-
args: [calls],
|
|
17418
|
-
blockNumber,
|
|
17419
|
-
blockTag,
|
|
17420
|
-
// does not infer well that either blockNumber or blockTag must be present
|
|
17421
|
-
functionName: "aggregate3",
|
|
17422
|
-
stateOverride,
|
|
17423
|
-
gas
|
|
17424
|
-
})
|
|
17425
|
-
)
|
|
17426
|
-
);
|
|
17427
|
-
const results = [];
|
|
17428
|
-
for (let i = 0; i < aggregate3Results.length; i++) {
|
|
17429
|
-
const result = aggregate3Results[i];
|
|
17430
|
-
if (result.status === "rejected") {
|
|
17431
|
-
if (!allowFailure) {
|
|
17432
|
-
throw result.reason;
|
|
17433
|
-
}
|
|
17434
|
-
for (const _i of chunkedCalls[i]) {
|
|
17435
|
-
results.push({
|
|
17436
|
-
status: "failure",
|
|
17437
|
-
error: result.reason,
|
|
17438
|
-
result: void 0
|
|
17439
|
-
});
|
|
17440
|
-
}
|
|
17441
|
-
continue;
|
|
17442
|
-
}
|
|
17443
|
-
const aggregate3Result = result.value.result;
|
|
17444
|
-
for (let j = 0; j < aggregate3Result.length; j++) {
|
|
17445
|
-
const { returnData, success } = aggregate3Result[j];
|
|
17446
|
-
const { callData } = chunkedCalls[i][j];
|
|
17447
|
-
const { abi: abi17, address, functionName, args } = contracts[results.length];
|
|
17448
|
-
try {
|
|
17449
|
-
if (callData === "0x") throw new viem.AbiDecodingZeroDataError();
|
|
17450
|
-
if (!success) throw new viem.RawContractError({ data: returnData });
|
|
17451
|
-
const result2 = viem.decodeFunctionResult({
|
|
17452
|
-
abi: abi17,
|
|
17453
|
-
args,
|
|
17454
|
-
data: returnData,
|
|
17455
|
-
functionName
|
|
17456
|
-
});
|
|
17457
|
-
results.push(allowFailure ? { result: result2, status: "success" } : result2);
|
|
17458
|
-
} catch (err) {
|
|
17459
|
-
const error = viem.getContractError(err, {
|
|
17460
|
-
abi: abi17,
|
|
17461
|
-
address,
|
|
17462
|
-
args,
|
|
17463
|
-
docsPath: "/docs/contract/multicall",
|
|
17464
|
-
functionName
|
|
17465
|
-
});
|
|
17466
|
-
if (!allowFailure) throw error;
|
|
17467
|
-
results.push({ error, result: void 0, status: "failure" });
|
|
17468
|
-
}
|
|
17469
|
-
}
|
|
17470
|
-
}
|
|
17471
|
-
if (results.length !== contracts.length)
|
|
17472
|
-
throw new viem.BaseError("multicall results mismatch");
|
|
17473
|
-
return results;
|
|
17474
|
-
}
|
|
17475
|
-
|
|
17476
|
-
// src/sdk/accounts/CreditAccountsService.ts
|
|
17477
|
-
var CreditAccountsService = class extends SDKConstruct {
|
|
17478
|
-
#compressor;
|
|
17479
|
-
constructor(sdk) {
|
|
17480
|
-
super(sdk);
|
|
17481
|
-
this.#compressor = sdk.addressProvider.getLatestVersion(
|
|
17482
|
-
AP_CREDIT_ACCOUNT_COMPRESSOR
|
|
17483
|
-
);
|
|
17484
|
-
}
|
|
17485
|
-
/**
|
|
17486
|
-
* Returns single credit account data, or undefined if it's not found
|
|
17487
|
-
* Performs all necessary price feed updates under the hood
|
|
17488
|
-
* @param account
|
|
17489
|
-
* @returns
|
|
17490
|
-
*/
|
|
17491
|
-
async getCreditAccountData(account) {
|
|
17492
|
-
let raw;
|
|
17493
|
-
try {
|
|
17494
|
-
raw = await this.provider.publicClient.readContract({
|
|
17495
|
-
abi: iCreditAccountCompressorAbi,
|
|
17496
|
-
address: this.#compressor,
|
|
17497
|
-
functionName: "getCreditAccountData",
|
|
17498
|
-
args: [account]
|
|
17499
|
-
});
|
|
17500
|
-
} catch (e) {
|
|
17501
|
-
return void 0;
|
|
17502
|
-
}
|
|
17503
|
-
if (raw.success) {
|
|
17504
|
-
return raw;
|
|
17505
|
-
}
|
|
17506
|
-
const { txs: priceUpdateTxs, timestamp: _ } = await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs();
|
|
17507
|
-
const resp = await simulateMulticall(this.provider.publicClient, {
|
|
17508
|
-
account: this.provider.account,
|
|
17509
|
-
contracts: [
|
|
17510
|
-
...priceUpdateTxs.map(rawTxToMulticallPriceUpdate),
|
|
17511
|
-
{
|
|
17512
|
-
abi: iCreditAccountCompressorAbi,
|
|
17513
|
-
address: this.#compressor,
|
|
17514
|
-
functionName: "getCreditAccountData",
|
|
17515
|
-
args: [account]
|
|
17516
|
-
}
|
|
17517
|
-
],
|
|
17518
|
-
allowFailure: false,
|
|
17519
|
-
gas: 550000000n,
|
|
17520
|
-
batchSize: 0
|
|
17521
|
-
// we cannot have price updates and compressor request in different batches
|
|
17522
|
-
});
|
|
17523
|
-
const cad = resp.pop();
|
|
17524
|
-
return cad;
|
|
17525
|
-
}
|
|
17526
|
-
/**
|
|
17527
|
-
* Methods to get all credit accounts with some optional filtering
|
|
17528
|
-
* Performs all necessary price feed updates under the hood
|
|
17529
|
-
*
|
|
17530
|
-
* TODO: do we want to expose pagination?
|
|
17531
|
-
* TODO: do we want to expose "reverting"?
|
|
17532
|
-
* TODO: do we want to expose MarketFilter in any way? If so, we need to check that the MarketFilter is compatibled with attached markets?
|
|
17533
|
-
* @param args
|
|
17534
|
-
* @returns returned credit accounts are sorted by health factor in ascending order
|
|
17535
|
-
*/
|
|
17536
|
-
async getCreditAccounts(args) {
|
|
17537
|
-
const {
|
|
17538
|
-
creditManager,
|
|
17539
|
-
includeZeroDebt = false,
|
|
17540
|
-
maxHealthFactor = 65535,
|
|
17541
|
-
// TODO: this will change to bigint
|
|
17542
|
-
minHealthFactor = 0,
|
|
17543
|
-
owner = ADDRESS_0X0
|
|
17544
|
-
} = args ?? {};
|
|
17545
|
-
const arg0 = creditManager ?? {
|
|
17546
|
-
curators: [],
|
|
17547
|
-
pools: this.pools,
|
|
17548
|
-
underlying: ADDRESS_0X0
|
|
17549
|
-
};
|
|
17550
|
-
const caFilter = {
|
|
17551
|
-
owner,
|
|
17552
|
-
includeZeroDebt,
|
|
17553
|
-
minHealthFactor,
|
|
17554
|
-
maxHealthFactor
|
|
17555
|
-
};
|
|
17556
|
-
const { txs: priceUpdateTxs, timestamp: _ } = await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs();
|
|
17557
|
-
const allCAs = [];
|
|
17558
|
-
for (const reverting of [false, true]) {
|
|
17559
|
-
let offset = 0n;
|
|
17560
|
-
do {
|
|
17561
|
-
const [accounts, newOffset] = await this.#getCreditAccounts(
|
|
17562
|
-
[arg0, { ...caFilter, reverting }, offset],
|
|
17563
|
-
priceUpdateTxs
|
|
17564
|
-
);
|
|
17565
|
-
allCAs.push(...accounts);
|
|
17566
|
-
offset = newOffset;
|
|
17567
|
-
} while (offset !== 0n);
|
|
17568
|
-
}
|
|
17569
|
-
return allCAs.sort((a, b) => Number(a.healthFactor - b.healthFactor));
|
|
17570
|
-
}
|
|
17571
|
-
/**
|
|
17572
|
-
* Generates transaction to liquidate credit account
|
|
17573
|
-
* @param account
|
|
17574
|
-
* @param to Address to transfer underlying left after liquidation
|
|
17575
|
-
* @param slippage
|
|
17576
|
-
* @returns
|
|
17577
|
-
*/
|
|
17578
|
-
async fullyLiquidate(account, to, slippage = 50n) {
|
|
17579
|
-
const cm = this.sdk.marketRegister.findCreditManager(account.creditManager);
|
|
17580
|
-
const preview = await this.sdk.router.findBestClosePath(
|
|
17581
|
-
account,
|
|
17582
|
-
cm.creditManager,
|
|
17583
|
-
slippage
|
|
17584
|
-
);
|
|
17585
|
-
const priceUpdates = await this.getPriceUpdatesForFacade(account);
|
|
17586
|
-
const recipient = to ?? this.sdk.provider.account;
|
|
17587
|
-
if (!recipient) {
|
|
17588
|
-
throw new Error("liquidate account: assets recipient not specied");
|
|
17589
|
-
}
|
|
17590
|
-
return cm.creditFacade.createRawTx({
|
|
17591
|
-
functionName: "liquidateCreditAccount",
|
|
17592
|
-
args: [
|
|
17593
|
-
account.creditAccount,
|
|
17594
|
-
recipient,
|
|
17595
|
-
[...priceUpdates, ...preview.calls]
|
|
17596
|
-
],
|
|
17597
|
-
description: `fully liquidate ${account.creditAccount}`
|
|
17598
|
-
});
|
|
17599
|
-
}
|
|
17600
|
-
/**
|
|
17601
|
-
* Closes credit account or sets debt to zero (but keep account)
|
|
17602
|
-
* @param operation
|
|
17603
|
-
* @param ca
|
|
17604
|
-
* @param assetsToKeep Tokens to withdraw from credit account
|
|
17605
|
-
* @param to Address to withdraw underlying to
|
|
17606
|
-
* @param slippage
|
|
17607
|
-
* @returns
|
|
17608
|
-
*/
|
|
17609
|
-
async closeCreditAccount(operation, ca, assetsToKeep, to, slippage = 50n) {
|
|
17610
|
-
const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
|
|
17611
|
-
const recipient = to ?? this.sdk.provider.account;
|
|
17612
|
-
if (!recipient) {
|
|
17613
|
-
throw new Error("close account: assets recipient not specied");
|
|
17614
|
-
}
|
|
17615
|
-
const calls = await this.#prepareCloseCreditAccount(
|
|
17616
|
-
ca,
|
|
17617
|
-
cm,
|
|
17618
|
-
assetsToKeep,
|
|
17619
|
-
recipient,
|
|
17620
|
-
slippage
|
|
17621
|
-
);
|
|
17622
|
-
return cm.creditFacade.createRawTx({
|
|
17623
|
-
functionName: operation === "close" ? "closeCreditAccount" : "multicall",
|
|
17624
|
-
args: [ca.creditAccount, calls],
|
|
17625
|
-
description: `${operation} account ${ca.creditAccount}`
|
|
17626
|
-
});
|
|
17627
|
-
}
|
|
17628
|
-
/**
|
|
17629
|
-
* Internal wrapper for CreditAccountCompressor.getCreditAccounts + price updates wrapped into multicall
|
|
17630
|
-
* @param args
|
|
17631
|
-
* @param priceUpdateTxs
|
|
17632
|
-
* @returns
|
|
17633
|
-
*/
|
|
17634
|
-
async #getCreditAccounts(args, priceUpdateTxs) {
|
|
17635
|
-
if (priceUpdateTxs?.length) {
|
|
17636
|
-
const resp = await simulateMulticall(this.provider.publicClient, {
|
|
17637
|
-
account: this.provider.account,
|
|
17638
|
-
contracts: [
|
|
17639
|
-
...priceUpdateTxs.map(rawTxToMulticallPriceUpdate),
|
|
17640
|
-
{
|
|
17641
|
-
abi: iCreditAccountCompressorAbi,
|
|
17642
|
-
address: this.#compressor,
|
|
17643
|
-
functionName: "getCreditAccounts",
|
|
17644
|
-
args
|
|
17645
|
-
}
|
|
17646
|
-
],
|
|
17647
|
-
allowFailure: false,
|
|
17648
|
-
gas: 550000000n,
|
|
17649
|
-
batchSize: 0
|
|
17650
|
-
// we cannot have price updates and compressor request in different batches
|
|
17651
|
-
});
|
|
17652
|
-
const getCreditAccountsResp = resp.pop();
|
|
17653
|
-
return getCreditAccountsResp;
|
|
17654
|
-
}
|
|
17655
|
-
return this.provider.publicClient.readContract({
|
|
17656
|
-
abi: iCreditAccountCompressorAbi,
|
|
17657
|
-
address: this.#compressor,
|
|
17658
|
-
functionName: "getCreditAccounts",
|
|
17659
|
-
args
|
|
17660
|
-
});
|
|
17661
|
-
}
|
|
17662
|
-
/**
|
|
17663
|
-
* Returns raw txs that are needed to update all price feeds so that all credit accounts (possibly from different markets) compute
|
|
17664
|
-
* @param accounts
|
|
17665
|
-
* @returns
|
|
17666
|
-
*/
|
|
17667
|
-
async getUpdateForAccounts(accounts) {
|
|
17668
|
-
const tokensByPool = /* @__PURE__ */ new Map();
|
|
17669
|
-
const oracleByPool = /* @__PURE__ */ new Map();
|
|
17670
|
-
for (const acc of accounts) {
|
|
17671
|
-
const market = this.sdk.marketRegister.findByCreditManager(
|
|
17672
|
-
acc.creditManager
|
|
17673
|
-
);
|
|
17674
|
-
const pool = market.state.pool.pool.address;
|
|
17675
|
-
oracleByPool.set(pool, market.priceOracle);
|
|
17676
|
-
for (const t of acc.tokens) {
|
|
17677
|
-
if (t.balance > 10n) {
|
|
17678
|
-
const tokens = tokensByPool.get(pool) ?? /* @__PURE__ */ new Set();
|
|
17679
|
-
tokens.add(t.token);
|
|
17680
|
-
tokensByPool.set(pool, tokens);
|
|
17681
|
-
}
|
|
17682
|
-
}
|
|
17683
|
-
}
|
|
17684
|
-
const priceFeeds = [];
|
|
17685
|
-
for (const [pool, priceFeedFactory] of oracleByPool.entries()) {
|
|
17686
|
-
const tokens = Array.from(tokensByPool.get(pool) ?? []);
|
|
17687
|
-
priceFeeds.push(...priceFeedFactory.priceFeedsForTokens(tokens));
|
|
17688
|
-
}
|
|
17689
|
-
return this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(priceFeeds);
|
|
17690
|
-
}
|
|
17691
|
-
/**
|
|
17692
|
-
* Returns account price updates in a non-encoded format
|
|
17693
|
-
* @param acc
|
|
17694
|
-
* @returns
|
|
17695
|
-
*/
|
|
17696
|
-
async getOnDemandPriceUpdates(acc) {
|
|
17697
|
-
const market = this.sdk.marketRegister.findByCreditManager(
|
|
17698
|
-
acc.creditManager
|
|
17699
|
-
);
|
|
17700
|
-
const update = await this.getUpdateForAccounts([acc]);
|
|
17701
|
-
return market.priceOracle.onDemandPriceUpdates(update);
|
|
17702
|
-
}
|
|
17703
|
-
/**
|
|
17704
|
-
* Returns price updates in format that is accepted by various credit facade methods (multicall, close/liquidate, etc...)
|
|
17705
|
-
* @param acc
|
|
17706
|
-
* @returns
|
|
17707
|
-
*/
|
|
17708
|
-
async getPriceUpdatesForFacade(acc) {
|
|
17709
|
-
const cm = this.sdk.marketRegister.findCreditManager(acc.creditManager);
|
|
17710
|
-
const updates = await this.getOnDemandPriceUpdates(acc);
|
|
17711
|
-
return updates.map(({ token, reserve, data }) => ({
|
|
17712
|
-
target: cm.creditFacade.address,
|
|
17713
|
-
callData: viem.encodeFunctionData({
|
|
17714
|
-
abi: iCreditFacadeV3MulticallAbi,
|
|
17715
|
-
functionName: "onDemandPriceUpdate",
|
|
17716
|
-
args: [token, reserve, data]
|
|
17717
|
-
})
|
|
17718
|
-
}));
|
|
17719
|
-
}
|
|
17720
|
-
async #prepareCloseCreditAccount(ca, cm, assetsToKeep, to, slippage = 50n) {
|
|
17721
|
-
const closePath = await this.sdk.router.findBestClosePath(
|
|
17722
|
-
ca,
|
|
17723
|
-
cm.creditManager,
|
|
17724
|
-
slippage
|
|
17725
|
-
);
|
|
17726
|
-
const priceUpdates = await this.getPriceUpdatesForFacade(ca);
|
|
17727
|
-
return [
|
|
17728
|
-
...priceUpdates,
|
|
17729
|
-
...closePath.calls,
|
|
17730
|
-
...this.#prepareDisableQuotas(ca),
|
|
17731
|
-
...this.#prepareDecreaseDebt(ca),
|
|
17732
|
-
...this.#prepareDisableTokens(ca),
|
|
17733
|
-
...assetsToKeep.map(
|
|
17734
|
-
(t) => this.#prepareWithdrawToken(ca, t, MAX_UINT256, to)
|
|
17735
|
-
)
|
|
17736
|
-
];
|
|
17737
|
-
}
|
|
17738
|
-
#prepareDisableQuotas(ca) {
|
|
17739
|
-
const calls = [];
|
|
17740
|
-
for (const { token, quota } of ca.tokens) {
|
|
17741
|
-
if (quota > 0n) {
|
|
17742
|
-
calls.push({
|
|
17743
|
-
target: ca.creditFacade,
|
|
17744
|
-
callData: viem.encodeFunctionData({
|
|
17745
|
-
abi: iCreditFacadeV3MulticallAbi,
|
|
17746
|
-
functionName: "updateQuota",
|
|
17747
|
-
args: [token, MIN_INT96, 0n]
|
|
17748
|
-
})
|
|
17749
|
-
});
|
|
17750
|
-
}
|
|
17751
|
-
}
|
|
17752
|
-
return calls;
|
|
17753
|
-
}
|
|
17754
|
-
#prepareDecreaseDebt(ca) {
|
|
17755
|
-
if (ca.totalDebtUSD > 0n) {
|
|
17756
|
-
return [
|
|
17757
|
-
{
|
|
17758
|
-
target: ca.creditFacade,
|
|
17759
|
-
callData: viem.encodeFunctionData({
|
|
17760
|
-
abi: iCreditFacadeV3MulticallAbi,
|
|
17761
|
-
functionName: "decreaseDebt",
|
|
17762
|
-
args: [MAX_UINT256]
|
|
17763
|
-
})
|
|
17764
|
-
}
|
|
17765
|
-
];
|
|
17766
|
-
}
|
|
17767
|
-
return [];
|
|
17768
|
-
}
|
|
17769
|
-
#prepareDisableTokens(ca) {
|
|
17770
|
-
const calls = [];
|
|
17771
|
-
for (const t of ca.tokens) {
|
|
17772
|
-
if (t.token !== ca.underlying && (t.mask & ca.enabledTokensMask) !== 0n && t.quota === 0n) {
|
|
17773
|
-
calls.push({
|
|
17774
|
-
target: ca.creditFacade,
|
|
17775
|
-
callData: viem.encodeFunctionData({
|
|
17776
|
-
abi: iCreditFacadeV3MulticallAbi,
|
|
17777
|
-
functionName: "disableToken",
|
|
17778
|
-
args: [t.token]
|
|
17779
|
-
})
|
|
17780
|
-
});
|
|
17781
|
-
}
|
|
17782
|
-
}
|
|
17783
|
-
return calls;
|
|
17784
|
-
}
|
|
17785
|
-
#prepareWithdrawToken(ca, token, amount, to) {
|
|
17786
|
-
return {
|
|
17787
|
-
target: ca.creditFacade,
|
|
17788
|
-
callData: viem.encodeFunctionData({
|
|
17789
|
-
abi: iCreditFacadeV3MulticallAbi,
|
|
17790
|
-
functionName: "withdrawCollateral",
|
|
17791
|
-
args: [token, amount, to]
|
|
17792
|
-
})
|
|
17793
|
-
};
|
|
17794
|
-
}
|
|
17795
|
-
/**
|
|
17796
|
-
* Returns addresses of pools of attached markets
|
|
17797
|
-
*/
|
|
17798
|
-
get pools() {
|
|
17799
|
-
return this.sdk.marketRegister.poolState.map((p) => p.pool.address);
|
|
17800
|
-
}
|
|
17801
|
-
};
|
|
17802
|
-
function rawTxToMulticallPriceUpdate(tx) {
|
|
17803
|
-
const { to, callData } = tx;
|
|
17804
|
-
const { args, functionName } = viem.decodeFunctionData({
|
|
17805
|
-
abi: iUpdatablePriceFeedAbi,
|
|
17806
|
-
data: callData
|
|
17807
|
-
});
|
|
17808
|
-
return {
|
|
17809
|
-
abi: iUpdatablePriceFeedAbi,
|
|
17810
|
-
address: to,
|
|
17811
|
-
functionName,
|
|
17812
|
-
args
|
|
17813
|
-
};
|
|
17814
|
-
}
|
|
17815
|
-
var AddressProviderContractV3_1 = class extends BaseContract {
|
|
17816
|
-
#addresses = {};
|
|
17817
|
-
versions = {};
|
|
17818
|
-
latest = {};
|
|
17819
|
-
constructor(sdk, address) {
|
|
17820
|
-
super(sdk, {
|
|
17821
|
-
addr: address,
|
|
17822
|
-
name: "AddressProviderV3",
|
|
17823
|
-
abi: iAddressProviderV3_1Abi
|
|
17824
|
-
});
|
|
17825
|
-
}
|
|
17826
|
-
parseFunctionParams(params) {
|
|
17827
|
-
switch (params.functionName) {
|
|
17828
|
-
case "setAddress": {
|
|
17829
|
-
if (params.args.length !== 3) {
|
|
17830
|
-
const [key2, saveVersion2] = params.args;
|
|
17831
|
-
return [key2, `${saveVersion2}`];
|
|
17832
|
-
}
|
|
17833
|
-
const [key, value, saveVersion] = params.args;
|
|
17834
|
-
return [viem.bytesToString(viem.toBytes(key)), value, `${saveVersion}`];
|
|
17835
|
-
}
|
|
17836
|
-
default:
|
|
17837
|
-
return void 0;
|
|
17838
|
-
}
|
|
17839
|
-
}
|
|
17840
|
-
setInternalAddress(key, address, version) {
|
|
17841
|
-
if (!this.#addresses[key]) {
|
|
17842
|
-
this.#addresses[key] = {};
|
|
17843
|
-
}
|
|
17844
|
-
this.#addresses[key][version] = address;
|
|
17845
|
-
if (!this.latest[key] || version > this.latest[key]) {
|
|
17846
|
-
this.latest[key] = version;
|
|
17847
|
-
}
|
|
17848
|
-
if (!this.versions[key]) {
|
|
17849
|
-
this.versions[key] = /* @__PURE__ */ new Set();
|
|
17850
|
-
}
|
|
17851
|
-
this.versions[key].add(version);
|
|
17852
|
-
}
|
|
17853
|
-
getAddress(contract, version = NO_VERSION) {
|
|
17854
|
-
if (!this.#addresses[contract]) {
|
|
17855
|
-
throw new Error(`Address ${contract}, version: ${version} not found`);
|
|
17856
|
-
}
|
|
17857
|
-
const result = this.#addresses[contract][version];
|
|
17858
|
-
if (!result) {
|
|
17859
|
-
throw new Error(`Address ${contract}, version: ${version} not found`);
|
|
17860
|
-
}
|
|
17861
|
-
return result;
|
|
17862
|
-
}
|
|
17863
|
-
getLatestVersion(contract) {
|
|
17864
|
-
if (!this.latest[contract]) {
|
|
17865
|
-
throw new Error(`Latest version for ${contract} not found`);
|
|
17866
|
-
}
|
|
17867
|
-
this.logger?.debug(
|
|
17868
|
-
`Latest version found for ${contract} : ${this.latest[contract]}`
|
|
17869
|
-
);
|
|
17870
|
-
return this.getAddress(contract, this.latest[contract]);
|
|
17871
|
-
}
|
|
17872
|
-
async fetchState(toBlock) {
|
|
17873
|
-
const entries = await this.contract.read.getAllSavedContracts({
|
|
17874
|
-
blockNumber: toBlock
|
|
17875
|
-
});
|
|
17876
|
-
entries.forEach((log) => {
|
|
17877
|
-
this.setInternalAddress(log.key, log.value, Number(log.version));
|
|
17878
|
-
});
|
|
17879
|
-
this.version = 310;
|
|
17880
|
-
}
|
|
17881
|
-
get state() {
|
|
17882
|
-
return {
|
|
17883
|
-
...this.contractData,
|
|
17884
|
-
addresses: this.#addresses
|
|
17885
|
-
};
|
|
17886
|
-
}
|
|
17887
|
-
parseLog(log) {
|
|
17888
|
-
const parsedLog = viem.parseEventLogs({
|
|
17889
|
-
abi: this.abi,
|
|
17890
|
-
logs: [log]
|
|
17891
|
-
})[0];
|
|
17892
|
-
switch (parsedLog.eventName) {
|
|
17893
|
-
case "SetAddress": {
|
|
17894
|
-
const parsedLog2 = viem.parseEventLogs({
|
|
17895
|
-
abi: this.abi,
|
|
17896
|
-
eventName: "SetAddress",
|
|
17897
|
-
logs: [log]
|
|
17898
|
-
})[0];
|
|
17899
|
-
const key = parsedLog2.args.key;
|
|
17900
|
-
this.setInternalAddress(
|
|
17901
|
-
key,
|
|
17902
|
-
parsedLog.args.value,
|
|
17903
|
-
Number(parsedLog2.args.version)
|
|
17904
|
-
);
|
|
17905
|
-
break;
|
|
17906
|
-
}
|
|
17907
|
-
default:
|
|
17908
|
-
this.logger?.warn(`Unknown event: ${parsedLog.eventName}`);
|
|
17909
|
-
break;
|
|
17910
|
-
}
|
|
17911
|
-
}
|
|
17912
|
-
};
|
|
17913
|
-
var BotListContract = class extends BaseContract {
|
|
17914
|
-
approvedCreditManagers = /* @__PURE__ */ new Set();
|
|
17915
|
-
constructor(sdk, address) {
|
|
17916
|
-
super(sdk, { addr: address, name: "BotListV3", abi: botListV3Abi });
|
|
17917
|
-
}
|
|
17918
|
-
parseFunctionParams(params) {
|
|
17919
|
-
switch (params.functionName) {
|
|
17920
|
-
case "setCreditManagerApprovedStatus": {
|
|
17921
|
-
const [creditManager, status] = params.args;
|
|
17922
|
-
return [this.addressLabels.get(creditManager), `${status}`];
|
|
17923
|
-
}
|
|
17924
|
-
case "setBotSpecialPermissions": {
|
|
17925
|
-
const [bot, creditManager, permissions] = params.args;
|
|
17926
|
-
return [
|
|
17927
|
-
this.addressLabels.get(bot),
|
|
17928
|
-
this.addressLabels.get(creditManager),
|
|
17929
|
-
botPermissionsToString(permissions)
|
|
17930
|
-
];
|
|
17931
|
-
}
|
|
17932
|
-
default:
|
|
17933
|
-
return void 0;
|
|
17934
|
-
}
|
|
17935
|
-
}
|
|
17936
|
-
async fetchState(toBlock) {
|
|
17937
|
-
const logs = await this.provider.publicClient.getContractEvents({
|
|
17938
|
-
address: this.address,
|
|
17939
|
-
abi: this.abi,
|
|
17940
|
-
fromBlock: 0n,
|
|
17941
|
-
toBlock
|
|
17942
|
-
});
|
|
17943
|
-
logs.forEach((e) => this.parseLog(e));
|
|
17944
|
-
}
|
|
17945
|
-
parseLog(log) {
|
|
17946
|
-
const parsedLog = viem.parseEventLogs({
|
|
17947
|
-
abi: this.abi,
|
|
17948
|
-
logs: [log]
|
|
17949
|
-
})[0];
|
|
17950
|
-
switch (parsedLog.eventName) {
|
|
17951
|
-
case "SetCreditManagerApprovedStatus":
|
|
17952
|
-
if (parsedLog.args.approved) {
|
|
17953
|
-
this.approvedCreditManagers.add(parsedLog.args.creditManager);
|
|
17954
|
-
} else {
|
|
17955
|
-
this.approvedCreditManagers.delete(parsedLog.args.creditManager);
|
|
17956
|
-
}
|
|
17957
|
-
break;
|
|
17958
|
-
case "SetBotSpecialPermissions":
|
|
17959
|
-
this.logger?.debug(
|
|
17960
|
-
`Bot ${parsedLog.args.bot} has been given permissions ${botPermissionsToString(
|
|
17961
|
-
parsedLog.args.permissions
|
|
17962
|
-
)} for credit manager ${parsedLog.args.creditManager}`
|
|
17963
|
-
);
|
|
17964
|
-
break;
|
|
17965
|
-
default:
|
|
17966
|
-
this.logger?.warn(`Unknown event: ${parsedLog.eventName}`);
|
|
17967
|
-
break;
|
|
17968
|
-
}
|
|
17969
|
-
}
|
|
17970
|
-
get state() {
|
|
17971
|
-
return {
|
|
17972
|
-
...this.contractData
|
|
17973
|
-
};
|
|
17974
|
-
}
|
|
17975
|
-
};
|
|
17976
|
-
|
|
17977
|
-
// src/sdk/core/GearStakingV3Contract.ts
|
|
17978
|
-
var GearStakingContract = class extends BaseContract {
|
|
17979
|
-
constructor(sdk, address) {
|
|
17980
|
-
super(sdk, { addr: address, name: "GearStakingV3", abi: gearStakingV3Abi });
|
|
17981
|
-
}
|
|
17982
|
-
parseFunctionParams(params) {
|
|
17983
|
-
switch (params.functionName) {
|
|
17984
|
-
case "setVotingContractStatus": {
|
|
17985
|
-
const [address, status] = params.args;
|
|
17986
|
-
return [this.addressLabels.get(address), VotingContractStatus[status]];
|
|
17987
|
-
}
|
|
17988
|
-
default:
|
|
17989
|
-
return void 0;
|
|
17990
|
-
}
|
|
17991
|
-
}
|
|
17992
|
-
get state() {
|
|
17993
|
-
return {
|
|
17994
|
-
...this.contractData,
|
|
17995
|
-
successor: ADDRESS_0X0,
|
|
17996
|
-
migrator: ADDRESS_0X0
|
|
17997
|
-
};
|
|
17998
|
-
}
|
|
17999
|
-
};
|
|
18000
|
-
|
|
18001
|
-
// src/sdk/market/CreditConfiguratorContract.ts
|
|
18002
|
-
var CreditConfiguratorContract = class extends BaseContract {
|
|
18003
|
-
adapters = [];
|
|
18004
|
-
emergencyLiquidators = [];
|
|
18005
|
-
constructor(sdk, { creditConfigurator, creditManager }, emergencyLiquidators) {
|
|
18006
|
-
super(sdk, {
|
|
18007
|
-
...creditConfigurator.baseParams,
|
|
18008
|
-
name: `CreditConfigurator(${creditManager.name})`,
|
|
18009
|
-
abi: creditConfiguratorV3Abi
|
|
18010
|
-
});
|
|
18011
|
-
this.emergencyLiquidators = [...emergencyLiquidators];
|
|
18012
|
-
}
|
|
18013
|
-
get state() {
|
|
18014
|
-
return {
|
|
18015
|
-
...this.contractData,
|
|
18016
|
-
emergencyLiquidators: this.emergencyLiquidators
|
|
18017
|
-
};
|
|
17523
|
+
get state() {
|
|
17524
|
+
return {
|
|
17525
|
+
...this.contractData,
|
|
17526
|
+
emergencyLiquidators: this.emergencyLiquidators
|
|
17527
|
+
};
|
|
18018
17528
|
}
|
|
18019
17529
|
parseFunctionParams(params) {
|
|
18020
17530
|
switch (params.functionName) {
|
|
@@ -18666,7 +18176,206 @@ var PoolFactory = class {
|
|
|
18666
18176
|
gauge: this.gaugeContract.state
|
|
18667
18177
|
};
|
|
18668
18178
|
}
|
|
18669
|
-
};
|
|
18179
|
+
};
|
|
18180
|
+
var SUPPORTED_CHAINS = [
|
|
18181
|
+
"Mainnet",
|
|
18182
|
+
"Arbitrum",
|
|
18183
|
+
"Optimism",
|
|
18184
|
+
"Base"
|
|
18185
|
+
];
|
|
18186
|
+
var chains = {
|
|
18187
|
+
Mainnet: chains$1.mainnet,
|
|
18188
|
+
Arbitrum: chains$1.arbitrum,
|
|
18189
|
+
Optimism: chains$1.optimism,
|
|
18190
|
+
Base: chains$1.base
|
|
18191
|
+
};
|
|
18192
|
+
var Provider = class {
|
|
18193
|
+
account;
|
|
18194
|
+
chainId;
|
|
18195
|
+
chain;
|
|
18196
|
+
networkType;
|
|
18197
|
+
publicClient;
|
|
18198
|
+
addressLabels;
|
|
18199
|
+
transport;
|
|
18200
|
+
constructor(opts) {
|
|
18201
|
+
const {
|
|
18202
|
+
account,
|
|
18203
|
+
chainId,
|
|
18204
|
+
networkType,
|
|
18205
|
+
rpcURLs,
|
|
18206
|
+
timeout = 12e4,
|
|
18207
|
+
retryCount
|
|
18208
|
+
} = opts;
|
|
18209
|
+
this.account = account;
|
|
18210
|
+
this.chainId = chainId;
|
|
18211
|
+
this.networkType = networkType;
|
|
18212
|
+
this.chain = viem.defineChain({
|
|
18213
|
+
...chains[networkType],
|
|
18214
|
+
id: chainId
|
|
18215
|
+
});
|
|
18216
|
+
const rpcs = rpcURLs.map((url) => viem.http(url, { timeout, retryCount }));
|
|
18217
|
+
this.transport = rpcs.length ? viem.fallback(rpcs) : rpcs[0];
|
|
18218
|
+
this.publicClient = viem.createPublicClient({
|
|
18219
|
+
chain: this.chain,
|
|
18220
|
+
transport: this.transport
|
|
18221
|
+
});
|
|
18222
|
+
this.addressLabels = new AddressLabeller();
|
|
18223
|
+
}
|
|
18224
|
+
};
|
|
18225
|
+
|
|
18226
|
+
// src/sdk/utils/viem/detectNetwork.ts
|
|
18227
|
+
async function detectNetwork(client) {
|
|
18228
|
+
for (const chain of SUPPORTED_CHAINS) {
|
|
18229
|
+
try {
|
|
18230
|
+
await client.readContract({
|
|
18231
|
+
abi: ierc20MetadataAbi,
|
|
18232
|
+
address: USDC[chain],
|
|
18233
|
+
functionName: "symbol"
|
|
18234
|
+
});
|
|
18235
|
+
return chain;
|
|
18236
|
+
} catch {
|
|
18237
|
+
}
|
|
18238
|
+
}
|
|
18239
|
+
throw new Error("Unsupported network");
|
|
18240
|
+
}
|
|
18241
|
+
async function simulateMulticall(client, parameters) {
|
|
18242
|
+
const {
|
|
18243
|
+
account,
|
|
18244
|
+
allowFailure = true,
|
|
18245
|
+
batchSize: batchSize_,
|
|
18246
|
+
blockNumber,
|
|
18247
|
+
blockTag,
|
|
18248
|
+
gas,
|
|
18249
|
+
multicallAddress: multicallAddress_,
|
|
18250
|
+
stateOverride
|
|
18251
|
+
} = parameters;
|
|
18252
|
+
const contracts = parameters.contracts;
|
|
18253
|
+
const batchSize = batchSize_ ?? (typeof client.batch?.multicall === "object" && client.batch.multicall.batchSize || 1024);
|
|
18254
|
+
let multicallAddress = multicallAddress_;
|
|
18255
|
+
if (!multicallAddress) {
|
|
18256
|
+
if (!client.chain)
|
|
18257
|
+
throw new Error(
|
|
18258
|
+
"client chain not configured. multicallAddress is required."
|
|
18259
|
+
);
|
|
18260
|
+
multicallAddress = viem.getChainContractAddress({
|
|
18261
|
+
blockNumber,
|
|
18262
|
+
chain: client.chain,
|
|
18263
|
+
contract: "multicall3"
|
|
18264
|
+
});
|
|
18265
|
+
}
|
|
18266
|
+
const chunkedCalls = [[]];
|
|
18267
|
+
let currentChunk = 0;
|
|
18268
|
+
let currentChunkSize = 0;
|
|
18269
|
+
for (const contract of contracts) {
|
|
18270
|
+
const { abi: abi17, address, args, functionName } = contract;
|
|
18271
|
+
try {
|
|
18272
|
+
const callData = viem.encodeFunctionData({ abi: abi17, args, functionName });
|
|
18273
|
+
currentChunkSize += (callData.length - 2) / 2;
|
|
18274
|
+
if (
|
|
18275
|
+
// Check if batching is enabled.
|
|
18276
|
+
batchSize > 0 && // Check if the current size of the batch exceeds the size limit.
|
|
18277
|
+
currentChunkSize > batchSize && // Check if the current chunk is not already empty.
|
|
18278
|
+
chunkedCalls[currentChunk].length > 0
|
|
18279
|
+
) {
|
|
18280
|
+
currentChunk++;
|
|
18281
|
+
currentChunkSize = (callData.length - 2) / 2;
|
|
18282
|
+
chunkedCalls[currentChunk] = [];
|
|
18283
|
+
}
|
|
18284
|
+
chunkedCalls[currentChunk] = [
|
|
18285
|
+
...chunkedCalls[currentChunk],
|
|
18286
|
+
{
|
|
18287
|
+
allowFailure: true,
|
|
18288
|
+
callData,
|
|
18289
|
+
target: address
|
|
18290
|
+
}
|
|
18291
|
+
];
|
|
18292
|
+
} catch (err) {
|
|
18293
|
+
const error = viem.getContractError(err, {
|
|
18294
|
+
abi: abi17,
|
|
18295
|
+
address,
|
|
18296
|
+
args,
|
|
18297
|
+
docsPath: "/docs/contract/multicall",
|
|
18298
|
+
functionName
|
|
18299
|
+
});
|
|
18300
|
+
if (!allowFailure) throw error;
|
|
18301
|
+
chunkedCalls[currentChunk] = [
|
|
18302
|
+
...chunkedCalls[currentChunk],
|
|
18303
|
+
{
|
|
18304
|
+
allowFailure: true,
|
|
18305
|
+
callData: "0x",
|
|
18306
|
+
target: address
|
|
18307
|
+
}
|
|
18308
|
+
];
|
|
18309
|
+
}
|
|
18310
|
+
}
|
|
18311
|
+
const aggregate3Results = await Promise.allSettled(
|
|
18312
|
+
chunkedCalls.map(
|
|
18313
|
+
(calls) => utils.getAction(
|
|
18314
|
+
client,
|
|
18315
|
+
actions.simulateContract,
|
|
18316
|
+
"simulateContract"
|
|
18317
|
+
)({
|
|
18318
|
+
account,
|
|
18319
|
+
abi: viem.multicall3Abi,
|
|
18320
|
+
address: multicallAddress,
|
|
18321
|
+
args: [calls],
|
|
18322
|
+
blockNumber,
|
|
18323
|
+
blockTag,
|
|
18324
|
+
// does not infer well that either blockNumber or blockTag must be present
|
|
18325
|
+
functionName: "aggregate3",
|
|
18326
|
+
stateOverride,
|
|
18327
|
+
gas
|
|
18328
|
+
})
|
|
18329
|
+
)
|
|
18330
|
+
);
|
|
18331
|
+
const results = [];
|
|
18332
|
+
for (let i = 0; i < aggregate3Results.length; i++) {
|
|
18333
|
+
const result = aggregate3Results[i];
|
|
18334
|
+
if (result.status === "rejected") {
|
|
18335
|
+
if (!allowFailure) {
|
|
18336
|
+
throw result.reason;
|
|
18337
|
+
}
|
|
18338
|
+
for (const _i of chunkedCalls[i]) {
|
|
18339
|
+
results.push({
|
|
18340
|
+
status: "failure",
|
|
18341
|
+
error: result.reason,
|
|
18342
|
+
result: void 0
|
|
18343
|
+
});
|
|
18344
|
+
}
|
|
18345
|
+
continue;
|
|
18346
|
+
}
|
|
18347
|
+
const aggregate3Result = result.value.result;
|
|
18348
|
+
for (let j = 0; j < aggregate3Result.length; j++) {
|
|
18349
|
+
const { returnData, success } = aggregate3Result[j];
|
|
18350
|
+
const { callData } = chunkedCalls[i][j];
|
|
18351
|
+
const { abi: abi17, address, functionName, args } = contracts[results.length];
|
|
18352
|
+
try {
|
|
18353
|
+
if (callData === "0x") throw new viem.AbiDecodingZeroDataError();
|
|
18354
|
+
if (!success) throw new viem.RawContractError({ data: returnData });
|
|
18355
|
+
const result2 = viem.decodeFunctionResult({
|
|
18356
|
+
abi: abi17,
|
|
18357
|
+
args,
|
|
18358
|
+
data: returnData,
|
|
18359
|
+
functionName
|
|
18360
|
+
});
|
|
18361
|
+
results.push(allowFailure ? { result: result2, status: "success" } : result2);
|
|
18362
|
+
} catch (err) {
|
|
18363
|
+
const error = viem.getContractError(err, {
|
|
18364
|
+
abi: abi17,
|
|
18365
|
+
address,
|
|
18366
|
+
args,
|
|
18367
|
+
docsPath: "/docs/contract/multicall",
|
|
18368
|
+
functionName
|
|
18369
|
+
});
|
|
18370
|
+
if (!allowFailure) throw error;
|
|
18371
|
+
results.push({ error, result: void 0, status: "failure" });
|
|
18372
|
+
}
|
|
18373
|
+
}
|
|
18374
|
+
}
|
|
18375
|
+
if (results.length !== contracts.length)
|
|
18376
|
+
throw new viem.BaseError("multicall results mismatch");
|
|
18377
|
+
return results;
|
|
18378
|
+
}
|
|
18670
18379
|
|
|
18671
18380
|
// src/sdk/market/pricefeeds/PriceFeedRef.ts
|
|
18672
18381
|
var PriceFeedRef = class {
|
|
@@ -18865,101 +18574,460 @@ var ChainlinkPriceFeedContract = class extends AbstractPriceFeedContract {
|
|
|
18865
18574
|
get state() {
|
|
18866
18575
|
return {
|
|
18867
18576
|
...this.contractData,
|
|
18868
|
-
contractType: this.priceFeedType,
|
|
18869
|
-
skipCheck: false,
|
|
18870
|
-
pricefeeds: []
|
|
18577
|
+
contractType: this.priceFeedType,
|
|
18578
|
+
skipCheck: false,
|
|
18579
|
+
pricefeeds: []
|
|
18580
|
+
};
|
|
18581
|
+
}
|
|
18582
|
+
};
|
|
18583
|
+
|
|
18584
|
+
// src/sdk/market/pricefeeds/CompositePriceFeed.ts
|
|
18585
|
+
var CompositePriceFeedContract = class extends AbstractPriceFeedContract {
|
|
18586
|
+
constructor(sdk, args) {
|
|
18587
|
+
super(sdk, {
|
|
18588
|
+
...args,
|
|
18589
|
+
name: "CompositePriceFeed",
|
|
18590
|
+
abi: compositePriceFeedAbi,
|
|
18591
|
+
decimals: 8
|
|
18592
|
+
});
|
|
18593
|
+
}
|
|
18594
|
+
get targetToBasePriceFeed() {
|
|
18595
|
+
return this.underlyingPriceFeeds[0];
|
|
18596
|
+
}
|
|
18597
|
+
get baseToUsdPriceFeed() {
|
|
18598
|
+
return this.underlyingPriceFeeds[1];
|
|
18599
|
+
}
|
|
18600
|
+
get state() {
|
|
18601
|
+
return {
|
|
18602
|
+
...this.contractData,
|
|
18603
|
+
contractType: this.priceFeedType,
|
|
18604
|
+
pricefeeds: [
|
|
18605
|
+
this.targetToBasePriceFeed.state,
|
|
18606
|
+
this.baseToUsdPriceFeed.state
|
|
18607
|
+
],
|
|
18608
|
+
skipCheck: true
|
|
18609
|
+
};
|
|
18610
|
+
}
|
|
18611
|
+
};
|
|
18612
|
+
|
|
18613
|
+
// src/sdk/market/pricefeeds/CurveCryptoPriceFeed.ts
|
|
18614
|
+
var CurveCryptoPriceFeedContract = class extends AbstractLPPriceFeedContract {
|
|
18615
|
+
constructor(sdk, args) {
|
|
18616
|
+
super(sdk, {
|
|
18617
|
+
...args,
|
|
18618
|
+
name: "CurveCryptoPriceFeed",
|
|
18619
|
+
abi: curveCryptoLpPriceFeedAbi
|
|
18620
|
+
});
|
|
18621
|
+
}
|
|
18622
|
+
get state() {
|
|
18623
|
+
return {
|
|
18624
|
+
...this.contractData,
|
|
18625
|
+
contractType: this.priceFeedType,
|
|
18626
|
+
skipCheck: true,
|
|
18627
|
+
pricefeeds: this.underlyingPriceFeeds.map((pf) => pf.state)
|
|
18628
|
+
};
|
|
18629
|
+
}
|
|
18630
|
+
async getValue() {
|
|
18631
|
+
return await this.sdk.provider.publicClient.readContract({
|
|
18632
|
+
abi: iCurvePoolAbi,
|
|
18633
|
+
address: this.lpContract,
|
|
18634
|
+
functionName: "get_virtual_price"
|
|
18635
|
+
});
|
|
18636
|
+
}
|
|
18637
|
+
};
|
|
18638
|
+
|
|
18639
|
+
// src/sdk/market/pricefeeds/CurveStablePriceFeed.ts
|
|
18640
|
+
var CurveStablePriceFeedContract = class extends AbstractLPPriceFeedContract {
|
|
18641
|
+
constructor(sdk, args) {
|
|
18642
|
+
super(sdk, {
|
|
18643
|
+
...args,
|
|
18644
|
+
name: "CurveStablePriceFeed",
|
|
18645
|
+
abi: curveStableLpPriceFeedAbi
|
|
18646
|
+
});
|
|
18647
|
+
}
|
|
18648
|
+
get state() {
|
|
18649
|
+
return {
|
|
18650
|
+
...this.contractData,
|
|
18651
|
+
contractType: this.priceFeedType,
|
|
18652
|
+
skipCheck: true,
|
|
18653
|
+
pricefeeds: this.underlyingPriceFeeds.map((pf) => pf.state)
|
|
18654
|
+
};
|
|
18655
|
+
}
|
|
18656
|
+
async getValue() {
|
|
18657
|
+
return await this.sdk.provider.publicClient.readContract({
|
|
18658
|
+
abi: iCurvePoolAbi,
|
|
18659
|
+
address: this.lpContract,
|
|
18660
|
+
functionName: "get_virtual_price"
|
|
18661
|
+
});
|
|
18662
|
+
}
|
|
18663
|
+
};
|
|
18664
|
+
|
|
18665
|
+
// src/sdk/market/pricefeeds/CurveUSDPriceFeed.ts
|
|
18666
|
+
var CurveUSDPriceFeedContract = class extends AbstractLPPriceFeedContract {
|
|
18667
|
+
constructor(sdk, args) {
|
|
18668
|
+
super(sdk, {
|
|
18669
|
+
...args,
|
|
18670
|
+
name: "CurveUSDPriceFeed",
|
|
18671
|
+
abi: curveUsdPriceFeedAbi
|
|
18672
|
+
});
|
|
18673
|
+
}
|
|
18674
|
+
get state() {
|
|
18675
|
+
return {
|
|
18676
|
+
...this.contractData,
|
|
18677
|
+
contractType: this.priceFeedType,
|
|
18678
|
+
skipCheck: true,
|
|
18679
|
+
pricefeeds: [this.underlyingPriceFeeds[0].state]
|
|
18680
|
+
};
|
|
18681
|
+
}
|
|
18682
|
+
async getValue() {
|
|
18683
|
+
return await this.sdk.provider.publicClient.readContract({
|
|
18684
|
+
abi: iCurvePoolAbi,
|
|
18685
|
+
address: this.lpContract,
|
|
18686
|
+
functionName: "get_virtual_price"
|
|
18687
|
+
});
|
|
18688
|
+
}
|
|
18689
|
+
};
|
|
18690
|
+
var Erc4626PriceFeedContract = class extends AbstractLPPriceFeedContract {
|
|
18691
|
+
constructor(sdk, args) {
|
|
18692
|
+
super(sdk, {
|
|
18693
|
+
...args,
|
|
18694
|
+
name: "ERC4626PriceFeed",
|
|
18695
|
+
abi: erc4626PriceFeedAbi
|
|
18696
|
+
});
|
|
18697
|
+
}
|
|
18698
|
+
get state() {
|
|
18699
|
+
return {
|
|
18700
|
+
...this.contractData,
|
|
18701
|
+
contractType: this.priceFeedType,
|
|
18702
|
+
skipCheck: true,
|
|
18703
|
+
pricefeeds: [this.underlyingPriceFeeds[0].state]
|
|
18704
|
+
};
|
|
18705
|
+
}
|
|
18706
|
+
async getValue() {
|
|
18707
|
+
const decimals2 = await this.sdk.provider.publicClient.readContract({
|
|
18708
|
+
abi: erc20Abi,
|
|
18709
|
+
address: this.lpContract,
|
|
18710
|
+
functionName: "decimals"
|
|
18711
|
+
});
|
|
18712
|
+
const price = await this.sdk.provider.publicClient.readContract({
|
|
18713
|
+
abi: viem.erc4626Abi,
|
|
18714
|
+
address: this.lpContract,
|
|
18715
|
+
functionName: "convertToAssets",
|
|
18716
|
+
args: [10n ** BigInt(decimals2)]
|
|
18717
|
+
});
|
|
18718
|
+
return price;
|
|
18719
|
+
}
|
|
18720
|
+
};
|
|
18721
|
+
|
|
18722
|
+
// src/sdk/market/pricefeeds/MellowLRTPriceFeed.ts
|
|
18723
|
+
var MellowLRTPriceFeedContract = class extends AbstractLPPriceFeedContract {
|
|
18724
|
+
constructor(sdk, args) {
|
|
18725
|
+
super(sdk, {
|
|
18726
|
+
...args,
|
|
18727
|
+
name: "MellowLRTPriceFeed",
|
|
18728
|
+
abi: mellowLrtPriceFeedAbi
|
|
18729
|
+
});
|
|
18730
|
+
}
|
|
18731
|
+
get state() {
|
|
18732
|
+
return {
|
|
18733
|
+
...this.contractData,
|
|
18734
|
+
contractType: this.priceFeedType,
|
|
18735
|
+
skipCheck: true,
|
|
18736
|
+
pricefeeds: [this.underlyingPriceFeeds[0].state]
|
|
18737
|
+
};
|
|
18738
|
+
}
|
|
18739
|
+
async getValue() {
|
|
18740
|
+
const stack = await this.sdk.provider.publicClient.readContract({
|
|
18741
|
+
abi: iMellowVaultAbi,
|
|
18742
|
+
address: this.lpContract,
|
|
18743
|
+
functionName: "calculateStack"
|
|
18744
|
+
});
|
|
18745
|
+
return stack.totalValue * BigInt(1e18) / stack.totalSupply;
|
|
18746
|
+
}
|
|
18747
|
+
};
|
|
18748
|
+
|
|
18749
|
+
// src/sdk/utils/internal/Hooks.ts
|
|
18750
|
+
var Hooks = class {
|
|
18751
|
+
#reg = {};
|
|
18752
|
+
addHook(hookName, fn) {
|
|
18753
|
+
if (!this.#reg[hookName]) {
|
|
18754
|
+
this.#reg[hookName] = [];
|
|
18755
|
+
}
|
|
18756
|
+
this.#reg[hookName].push(fn);
|
|
18757
|
+
}
|
|
18758
|
+
removeHook(hookName, fn) {
|
|
18759
|
+
if (!this.#reg[hookName]) {
|
|
18760
|
+
return;
|
|
18761
|
+
}
|
|
18762
|
+
this.#reg[hookName] = this.#reg[hookName]?.filter((hookFn) => hookFn !== fn) ?? [];
|
|
18763
|
+
}
|
|
18764
|
+
async triggerHooks(hookName, ...args) {
|
|
18765
|
+
if (!this.#reg[hookName]) {
|
|
18766
|
+
return;
|
|
18767
|
+
}
|
|
18768
|
+
for (const fn of this.#reg[hookName]) {
|
|
18769
|
+
await fn(...args);
|
|
18770
|
+
}
|
|
18771
|
+
}
|
|
18772
|
+
};
|
|
18773
|
+
var RedstonePriceFeedContract = class extends AbstractPriceFeedContract {
|
|
18774
|
+
decimals = 8;
|
|
18775
|
+
dataServiceId;
|
|
18776
|
+
dataId;
|
|
18777
|
+
signers;
|
|
18778
|
+
signersThreshold;
|
|
18779
|
+
constructor(sdk, args) {
|
|
18780
|
+
super(sdk, {
|
|
18781
|
+
...args,
|
|
18782
|
+
name: `RedstonePriceFeed`,
|
|
18783
|
+
abi: redstonePriceFeedAbi
|
|
18784
|
+
});
|
|
18785
|
+
const decoder = viem.decodeAbiParameters(
|
|
18786
|
+
[
|
|
18787
|
+
{ type: "address" },
|
|
18788
|
+
// [0]: pf.token(),
|
|
18789
|
+
{ type: "bytes32" },
|
|
18790
|
+
// [1]: pf.dataFeedId(),
|
|
18791
|
+
{ type: "address" },
|
|
18792
|
+
// [2]: pf.signerAddress0(),
|
|
18793
|
+
{ type: "address" },
|
|
18794
|
+
// [3]: pf.signerAddress1(),
|
|
18795
|
+
{ type: "address" },
|
|
18796
|
+
// [4]: pf.signerAddress2(),
|
|
18797
|
+
{ type: "address" },
|
|
18798
|
+
// [5]: pf.signerAddress3(),
|
|
18799
|
+
{ type: "address" },
|
|
18800
|
+
// [6]: pf.signerAddress4(),
|
|
18801
|
+
{ type: "address" },
|
|
18802
|
+
// [7]: pf.signerAddress5()
|
|
18803
|
+
{ type: "address" },
|
|
18804
|
+
// [8]: pf.signerAddress6(),
|
|
18805
|
+
{ type: "address" },
|
|
18806
|
+
// [9]: pf.signerAddress7(),
|
|
18807
|
+
{ type: "address" },
|
|
18808
|
+
// [10]: pf.signerAddress8(),
|
|
18809
|
+
{ type: "address" },
|
|
18810
|
+
// [11]: pf.signerAddress9(),
|
|
18811
|
+
{ type: "uint8" },
|
|
18812
|
+
// [12]: pf.getUniqueSignersThreshold()
|
|
18813
|
+
{ type: "uint128" },
|
|
18814
|
+
// [13]: pf.lastPrice(),
|
|
18815
|
+
{ type: "uint40" }
|
|
18816
|
+
// [14]: pf.lastPayloadTimestamp()
|
|
18817
|
+
],
|
|
18818
|
+
args.baseParams.serializedParams
|
|
18819
|
+
);
|
|
18820
|
+
this.dataId = viem.bytesToString(viem.toBytes(decoder[1])).replaceAll("\0", "");
|
|
18821
|
+
this.signers = decoder.slice(2, 11);
|
|
18822
|
+
this.signersThreshold = Number(decoder[12]);
|
|
18823
|
+
this.dataServiceId = ["GMX", "BAL"].includes(this.dataId) ? "redstone-arbitrum-prod" : "redstone-primary-prod";
|
|
18824
|
+
}
|
|
18825
|
+
get state() {
|
|
18826
|
+
return {
|
|
18827
|
+
...this.contractData,
|
|
18828
|
+
contractType: "PF_REDSTONE_ORACLE",
|
|
18829
|
+
dataId: this.dataId,
|
|
18830
|
+
signers: this.signers,
|
|
18831
|
+
signersThreshold: this.signersThreshold,
|
|
18832
|
+
skipCheck: true
|
|
18871
18833
|
};
|
|
18872
18834
|
}
|
|
18873
18835
|
};
|
|
18874
|
-
|
|
18875
|
-
|
|
18876
|
-
|
|
18877
|
-
|
|
18878
|
-
|
|
18879
|
-
|
|
18880
|
-
|
|
18881
|
-
abi: compositePriceFeedAbi,
|
|
18882
|
-
decimals: 8
|
|
18883
|
-
});
|
|
18836
|
+
var RedstoneUpdater = class extends SDKConstruct {
|
|
18837
|
+
#logger;
|
|
18838
|
+
#cache = /* @__PURE__ */ new Map();
|
|
18839
|
+
#historicalTimestamp;
|
|
18840
|
+
constructor(sdk) {
|
|
18841
|
+
super(sdk);
|
|
18842
|
+
this.#logger = childLogger("RedstoneUpdater", sdk.logger);
|
|
18884
18843
|
}
|
|
18885
|
-
|
|
18886
|
-
|
|
18844
|
+
setHistoricalTimestamp(timestamp) {
|
|
18845
|
+
this.#historicalTimestamp = timestamp;
|
|
18887
18846
|
}
|
|
18888
|
-
|
|
18889
|
-
|
|
18847
|
+
async getUpdateTxs(feeds) {
|
|
18848
|
+
this.#logger?.debug(
|
|
18849
|
+
`generating update transactions for ${feeds.length} redstone price feeds`
|
|
18850
|
+
);
|
|
18851
|
+
const groupedFeeds = {};
|
|
18852
|
+
const priceFeeds = /* @__PURE__ */ new Map();
|
|
18853
|
+
for (const feed of feeds) {
|
|
18854
|
+
const key = `${feed.dataServiceId}:${feed.signersThreshold}`;
|
|
18855
|
+
if (!groupedFeeds[key]) {
|
|
18856
|
+
groupedFeeds[key] = /* @__PURE__ */ new Set();
|
|
18857
|
+
}
|
|
18858
|
+
groupedFeeds[key].add(feed.dataId);
|
|
18859
|
+
priceFeeds.set(feed.dataId, feed);
|
|
18860
|
+
}
|
|
18861
|
+
const results = [];
|
|
18862
|
+
for (const [key, group] of Object.entries(groupedFeeds)) {
|
|
18863
|
+
const [dataServiceId, signersStr] = key.split(":");
|
|
18864
|
+
const uniqueSignersCount = parseInt(signersStr, 10);
|
|
18865
|
+
this.#logger?.debug(
|
|
18866
|
+
`fetching redstone payloads for ${group.size} data feeds in ${dataServiceId} with ${uniqueSignersCount} signers: ${Array.from(group).join(", ")}`
|
|
18867
|
+
);
|
|
18868
|
+
const payloads = await this.#getPayloads(
|
|
18869
|
+
dataServiceId,
|
|
18870
|
+
group,
|
|
18871
|
+
uniqueSignersCount
|
|
18872
|
+
);
|
|
18873
|
+
for (const { dataFeedId, data, timestamp } of payloads) {
|
|
18874
|
+
const priceFeed = priceFeeds.get(dataFeedId);
|
|
18875
|
+
if (!priceFeed) {
|
|
18876
|
+
throw new Error(`cannot get price feed address for ${dataFeedId}`);
|
|
18877
|
+
}
|
|
18878
|
+
results.push({
|
|
18879
|
+
priceFeed: priceFeed.address.toLowerCase(),
|
|
18880
|
+
tx: priceFeed.createRawTx({
|
|
18881
|
+
functionName: "updatePrice",
|
|
18882
|
+
args: [data],
|
|
18883
|
+
description: `updating price for ${dataFeedId} [${priceFeed.address}]`
|
|
18884
|
+
}),
|
|
18885
|
+
timestamp
|
|
18886
|
+
});
|
|
18887
|
+
}
|
|
18888
|
+
}
|
|
18889
|
+
this.#logger?.debug(
|
|
18890
|
+
`generated ${results.length} update transactions for redstone price feeds`
|
|
18891
|
+
);
|
|
18892
|
+
return results;
|
|
18890
18893
|
}
|
|
18891
|
-
|
|
18892
|
-
|
|
18893
|
-
|
|
18894
|
-
|
|
18895
|
-
|
|
18896
|
-
|
|
18897
|
-
|
|
18898
|
-
|
|
18899
|
-
|
|
18900
|
-
|
|
18894
|
+
/**
|
|
18895
|
+
* Gets redstone payloads in one request for multiple feeds with the same dataServiceId and uniqueSignersCount
|
|
18896
|
+
* If historicalTimestamp is set, responses will be cached
|
|
18897
|
+
* @param dataServiceId
|
|
18898
|
+
* @param dataFeedsIds
|
|
18899
|
+
* @param uniqueSignersCount
|
|
18900
|
+
* @returns
|
|
18901
|
+
*/
|
|
18902
|
+
async #getPayloads(dataServiceId, dataFeedsIds, uniqueSignersCount) {
|
|
18903
|
+
const fromCache = [];
|
|
18904
|
+
const uncached = [];
|
|
18905
|
+
for (const dataFeedId of dataFeedsIds) {
|
|
18906
|
+
const key = cacheKey(
|
|
18907
|
+
dataServiceId,
|
|
18908
|
+
dataFeedId,
|
|
18909
|
+
uniqueSignersCount,
|
|
18910
|
+
this.#historicalTimestamp
|
|
18911
|
+
);
|
|
18912
|
+
const cached = this.#cache.get(key);
|
|
18913
|
+
if (this.#historicalTimestamp && !!cached) {
|
|
18914
|
+
fromCache.push(cached);
|
|
18915
|
+
} else {
|
|
18916
|
+
uncached.push(dataFeedId);
|
|
18917
|
+
}
|
|
18918
|
+
}
|
|
18919
|
+
const fromRedstone = await this.#fetchPayloads(
|
|
18920
|
+
dataServiceId,
|
|
18921
|
+
new Set(uncached),
|
|
18922
|
+
uniqueSignersCount
|
|
18923
|
+
);
|
|
18924
|
+
if (this.#historicalTimestamp) {
|
|
18925
|
+
for (const resp of fromRedstone) {
|
|
18926
|
+
const key = cacheKey(
|
|
18927
|
+
dataServiceId,
|
|
18928
|
+
resp.dataFeedId,
|
|
18929
|
+
uniqueSignersCount,
|
|
18930
|
+
this.#historicalTimestamp
|
|
18931
|
+
);
|
|
18932
|
+
this.#cache.set(key, resp);
|
|
18933
|
+
}
|
|
18934
|
+
}
|
|
18935
|
+
return [...fromCache, ...fromRedstone];
|
|
18901
18936
|
}
|
|
18902
|
-
|
|
18903
|
-
|
|
18904
|
-
|
|
18905
|
-
|
|
18906
|
-
|
|
18907
|
-
|
|
18908
|
-
|
|
18909
|
-
|
|
18910
|
-
|
|
18937
|
+
/**
|
|
18938
|
+
* Fetches redstone payloads in one request for multiple feeds with the same dataServiceId and uniqueSignersCount
|
|
18939
|
+
* Payloads are loaded in one request to avoid redstone rate limit
|
|
18940
|
+
* @param dataServiceId
|
|
18941
|
+
* @param dataFeedsIds
|
|
18942
|
+
* @param uniqueSignersCount
|
|
18943
|
+
* @returns
|
|
18944
|
+
*/
|
|
18945
|
+
async #fetchPayloads(dataServiceId, dataFeedsIds, uniqueSignersCount) {
|
|
18946
|
+
if (dataFeedsIds.size === 0) {
|
|
18947
|
+
return [];
|
|
18948
|
+
}
|
|
18949
|
+
const dataPackagesIds = Array.from(dataFeedsIds);
|
|
18950
|
+
const wrapper = new evmConnector.DataServiceWrapper({
|
|
18951
|
+
dataServiceId,
|
|
18952
|
+
dataPackagesIds,
|
|
18953
|
+
uniqueSignersCount,
|
|
18954
|
+
historicalTimestamp: this.#historicalTimestamp
|
|
18911
18955
|
});
|
|
18912
|
-
|
|
18913
|
-
|
|
18914
|
-
|
|
18915
|
-
|
|
18916
|
-
|
|
18917
|
-
|
|
18918
|
-
|
|
18919
|
-
|
|
18920
|
-
|
|
18921
|
-
|
|
18922
|
-
|
|
18923
|
-
|
|
18924
|
-
|
|
18925
|
-
|
|
18956
|
+
const dataPayload = await wrapper.prepareRedstonePayload(true);
|
|
18957
|
+
const parsed = redstoneProtocol.RedstonePayload.parse(viem.toBytes(`0x${dataPayload}`));
|
|
18958
|
+
const packagesByDataFeedId = groupDataPackages(parsed.signedDataPackages);
|
|
18959
|
+
return dataPackagesIds.map((dataFeedId) => {
|
|
18960
|
+
const signedDataPackages = packagesByDataFeedId[dataFeedId];
|
|
18961
|
+
if (!signedDataPackages) {
|
|
18962
|
+
throw new Error(`cannot find data packages for ${dataFeedId}`);
|
|
18963
|
+
}
|
|
18964
|
+
if (signedDataPackages.length !== uniqueSignersCount) {
|
|
18965
|
+
throw new Error(
|
|
18966
|
+
`got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`
|
|
18967
|
+
);
|
|
18968
|
+
}
|
|
18969
|
+
return getCalldataWithTimestamp(
|
|
18970
|
+
dataFeedId,
|
|
18971
|
+
signedDataPackages,
|
|
18972
|
+
wrapper.getUnsignedMetadata()
|
|
18973
|
+
);
|
|
18926
18974
|
});
|
|
18927
18975
|
}
|
|
18928
18976
|
};
|
|
18929
|
-
|
|
18930
|
-
|
|
18931
|
-
|
|
18932
|
-
|
|
18933
|
-
|
|
18934
|
-
|
|
18935
|
-
|
|
18936
|
-
|
|
18937
|
-
|
|
18938
|
-
|
|
18939
|
-
|
|
18940
|
-
|
|
18941
|
-
|
|
18942
|
-
|
|
18943
|
-
|
|
18944
|
-
|
|
18945
|
-
|
|
18977
|
+
function cacheKey(dataServiceId, dataFeedId, uniqueSignersCount, historicalTimestamp = 0) {
|
|
18978
|
+
return `${dataServiceId}:${dataFeedId}:${uniqueSignersCount}:${historicalTimestamp}`;
|
|
18979
|
+
}
|
|
18980
|
+
function groupDataPackages(signedDataPackages) {
|
|
18981
|
+
const packagesByDataFeedId = {};
|
|
18982
|
+
for (const p of signedDataPackages) {
|
|
18983
|
+
const { dataPoints } = p.dataPackage;
|
|
18984
|
+
const dataFeedId0 = dataPoints[0].dataFeedId;
|
|
18985
|
+
for (const dp of dataPoints) {
|
|
18986
|
+
if (dp.dataFeedId !== dataFeedId0) {
|
|
18987
|
+
throw new Error(
|
|
18988
|
+
`data package contains data points with different dataFeedIds: ${dp.dataFeedId} and ${dataFeedId0}`
|
|
18989
|
+
);
|
|
18990
|
+
}
|
|
18991
|
+
}
|
|
18992
|
+
if (!packagesByDataFeedId[dataFeedId0]) {
|
|
18993
|
+
packagesByDataFeedId[dataFeedId0] = [];
|
|
18994
|
+
}
|
|
18995
|
+
packagesByDataFeedId[dataFeedId0].push(p);
|
|
18946
18996
|
}
|
|
18947
|
-
|
|
18948
|
-
|
|
18949
|
-
|
|
18950
|
-
|
|
18951
|
-
|
|
18952
|
-
|
|
18997
|
+
return packagesByDataFeedId;
|
|
18998
|
+
}
|
|
18999
|
+
function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata) {
|
|
19000
|
+
const originalPayload = redstoneProtocol.RedstonePayload.prepare(packages, unsignedMetadata);
|
|
19001
|
+
const originalPayloadLength = originalPayload.length / 2;
|
|
19002
|
+
const bytesToAdd = 32 - originalPayloadLength % 32;
|
|
19003
|
+
const newUnsignedMetadata = unsignedMetadata + "_".repeat(bytesToAdd);
|
|
19004
|
+
const payload = redstoneProtocol.RedstonePayload.prepare(packages, newUnsignedMetadata);
|
|
19005
|
+
let timestamp = 0;
|
|
19006
|
+
for (const p of packages) {
|
|
19007
|
+
const newTimestamp = p.dataPackage.timestampMilliseconds / 1e3;
|
|
19008
|
+
if (timestamp === 0) {
|
|
19009
|
+
timestamp = newTimestamp;
|
|
19010
|
+
} else if (timestamp !== newTimestamp) {
|
|
19011
|
+
throw new Error("Timestamps are not equal");
|
|
19012
|
+
}
|
|
18953
19013
|
}
|
|
18954
|
-
|
|
19014
|
+
return {
|
|
19015
|
+
dataFeedId,
|
|
19016
|
+
data: viem.encodeAbiParameters(
|
|
19017
|
+
[{ type: "uint256" }, { type: "bytes" }],
|
|
19018
|
+
[BigInt(timestamp), `0x${payload}`]
|
|
19019
|
+
),
|
|
19020
|
+
timestamp
|
|
19021
|
+
};
|
|
19022
|
+
}
|
|
18955
19023
|
|
|
18956
|
-
// src/sdk/market/pricefeeds/
|
|
18957
|
-
var
|
|
19024
|
+
// src/sdk/market/pricefeeds/WstETHPriceFeed.ts
|
|
19025
|
+
var WstETHPriceFeedContract = class extends AbstractLPPriceFeedContract {
|
|
18958
19026
|
constructor(sdk, args) {
|
|
18959
19027
|
super(sdk, {
|
|
18960
19028
|
...args,
|
|
18961
|
-
name: "
|
|
18962
|
-
abi:
|
|
19029
|
+
name: "WstETHPriceFeed",
|
|
19030
|
+
abi: wstEthPriceFeedAbi
|
|
18963
19031
|
});
|
|
18964
19032
|
}
|
|
18965
19033
|
get state() {
|
|
@@ -18972,18 +19040,20 @@ var CurveUSDPriceFeedContract = class extends AbstractLPPriceFeedContract {
|
|
|
18972
19040
|
}
|
|
18973
19041
|
async getValue() {
|
|
18974
19042
|
return await this.sdk.provider.publicClient.readContract({
|
|
18975
|
-
abi:
|
|
19043
|
+
abi: iwstEthAbi,
|
|
18976
19044
|
address: this.lpContract,
|
|
18977
|
-
functionName: "
|
|
19045
|
+
functionName: "stEthPerToken"
|
|
18978
19046
|
});
|
|
18979
19047
|
}
|
|
18980
19048
|
};
|
|
18981
|
-
|
|
19049
|
+
|
|
19050
|
+
// src/sdk/market/pricefeeds/YearnPriceFeed.ts
|
|
19051
|
+
var YearnPriceFeedContract = class extends AbstractLPPriceFeedContract {
|
|
18982
19052
|
constructor(sdk, args) {
|
|
18983
19053
|
super(sdk, {
|
|
18984
19054
|
...args,
|
|
18985
|
-
name: "
|
|
18986
|
-
abi:
|
|
19055
|
+
name: "YearnPriceFeed",
|
|
19056
|
+
abi: yearnPriceFeedAbi
|
|
18987
19057
|
});
|
|
18988
19058
|
}
|
|
18989
19059
|
get state() {
|
|
@@ -18995,878 +19065,1028 @@ var Erc4626PriceFeedContract = class extends AbstractLPPriceFeedContract {
|
|
|
18995
19065
|
};
|
|
18996
19066
|
}
|
|
18997
19067
|
async getValue() {
|
|
18998
|
-
|
|
18999
|
-
abi:
|
|
19000
|
-
address: this.lpContract,
|
|
19001
|
-
functionName: "decimals"
|
|
19002
|
-
});
|
|
19003
|
-
const price = await this.sdk.provider.publicClient.readContract({
|
|
19004
|
-
abi: viem.erc4626Abi,
|
|
19068
|
+
return await this.sdk.provider.publicClient.readContract({
|
|
19069
|
+
abi: iyVaultAbi,
|
|
19005
19070
|
address: this.lpContract,
|
|
19006
|
-
functionName: "
|
|
19007
|
-
args: [10n ** BigInt(decimals2)]
|
|
19071
|
+
functionName: "pricePerShare"
|
|
19008
19072
|
});
|
|
19009
|
-
return price;
|
|
19010
19073
|
}
|
|
19011
19074
|
};
|
|
19012
19075
|
|
|
19013
|
-
// src/sdk/market/pricefeeds/
|
|
19014
|
-
var
|
|
19076
|
+
// src/sdk/market/pricefeeds/ZeroPriceFeed.ts
|
|
19077
|
+
var ZeroPriceFeedContract = class extends AbstractPriceFeedContract {
|
|
19015
19078
|
constructor(sdk, args) {
|
|
19016
19079
|
super(sdk, {
|
|
19017
19080
|
...args,
|
|
19018
|
-
name: "
|
|
19019
|
-
abi:
|
|
19081
|
+
name: "ZeroPriceFeed",
|
|
19082
|
+
abi: zeroPriceFeedAbi,
|
|
19083
|
+
decimals: 8
|
|
19020
19084
|
});
|
|
19021
19085
|
}
|
|
19022
19086
|
get state() {
|
|
19023
19087
|
return {
|
|
19024
19088
|
...this.contractData,
|
|
19025
|
-
contractType:
|
|
19089
|
+
contractType: "PF_ZERO_ORACLE",
|
|
19026
19090
|
skipCheck: true,
|
|
19027
|
-
|
|
19091
|
+
stalenessPeriod: 0,
|
|
19092
|
+
pricefeeds: []
|
|
19028
19093
|
};
|
|
19029
19094
|
}
|
|
19030
|
-
async getValue() {
|
|
19031
|
-
const stack = await this.sdk.provider.publicClient.readContract({
|
|
19032
|
-
abi: iMellowVaultAbi,
|
|
19033
|
-
address: this.lpContract,
|
|
19034
|
-
functionName: "calculateStack"
|
|
19035
|
-
});
|
|
19036
|
-
return stack.totalValue * BigInt(1e18) / stack.totalSupply;
|
|
19037
|
-
}
|
|
19038
19095
|
};
|
|
19039
19096
|
|
|
19040
|
-
// src/sdk/
|
|
19041
|
-
var
|
|
19042
|
-
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
return;
|
|
19052
|
-
}
|
|
19053
|
-
this.#reg[hookName] = this.#reg[hookName]?.filter((hookFn) => hookFn !== fn) ?? [];
|
|
19097
|
+
// src/sdk/market/pricefeeds/PriceFeedsRegister.ts
|
|
19098
|
+
var PriceFeedRegister = class extends SDKConstruct {
|
|
19099
|
+
logger;
|
|
19100
|
+
#hooks = new Hooks();
|
|
19101
|
+
#feeds = new AddressMap();
|
|
19102
|
+
#redstoneUpdater;
|
|
19103
|
+
// public readonly zeroPriceFeed: ZeroPriceFeedContract;
|
|
19104
|
+
constructor(sdk) {
|
|
19105
|
+
super(sdk);
|
|
19106
|
+
this.logger = childLogger("PriceFeedRegister", sdk.logger);
|
|
19107
|
+
this.#redstoneUpdater = new RedstoneUpdater(sdk);
|
|
19054
19108
|
}
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
|
|
19109
|
+
addHook = this.#hooks.addHook.bind(this.#hooks);
|
|
19110
|
+
removeHook = this.#hooks.removeHook.bind(this.#hooks);
|
|
19111
|
+
/**
|
|
19112
|
+
* Returns RawTxs to update price feeds
|
|
19113
|
+
* @param priceFeeds top-level price feeds, actual updatable price feeds will be derived. If not provided will use all price feeds that are attached
|
|
19114
|
+
* @returns
|
|
19115
|
+
*/
|
|
19116
|
+
async generatePriceFeedsUpdateTxs(priceFeeds) {
|
|
19117
|
+
const priceFeedz = priceFeeds ?? Object.values(this.#feeds);
|
|
19118
|
+
const updateables = priceFeedz.flatMap((pf) => pf.updatableDependencies());
|
|
19119
|
+
const txs = [];
|
|
19120
|
+
const redstonePFs = [];
|
|
19121
|
+
for (const pf of updateables) {
|
|
19122
|
+
if (pf instanceof RedstonePriceFeedContract) {
|
|
19123
|
+
redstonePFs.push(pf);
|
|
19124
|
+
}
|
|
19058
19125
|
}
|
|
19059
|
-
|
|
19060
|
-
|
|
19126
|
+
let maxTimestamp = 0;
|
|
19127
|
+
if (redstonePFs.length > 0) {
|
|
19128
|
+
const redstoneUpdates = await this.#redstoneUpdater.getUpdateTxs(redstonePFs);
|
|
19129
|
+
for (const { tx, timestamp } of redstoneUpdates) {
|
|
19130
|
+
if (timestamp > maxTimestamp) {
|
|
19131
|
+
maxTimestamp = timestamp;
|
|
19132
|
+
}
|
|
19133
|
+
txs.push(tx);
|
|
19134
|
+
}
|
|
19061
19135
|
}
|
|
19136
|
+
const result = { txs, timestamp: maxTimestamp };
|
|
19137
|
+
await this.#hooks.triggerHooks("updatesGenerated", result);
|
|
19138
|
+
return result;
|
|
19062
19139
|
}
|
|
19063
|
-
|
|
19064
|
-
|
|
19065
|
-
decimals = 8;
|
|
19066
|
-
dataServiceId;
|
|
19067
|
-
dataId;
|
|
19068
|
-
signers;
|
|
19069
|
-
signersThreshold;
|
|
19070
|
-
constructor(sdk, args) {
|
|
19071
|
-
super(sdk, {
|
|
19072
|
-
...args,
|
|
19073
|
-
name: `RedstonePriceFeed`,
|
|
19074
|
-
abi: redstonePriceFeedAbi
|
|
19075
|
-
});
|
|
19076
|
-
const decoder = viem.decodeAbiParameters(
|
|
19077
|
-
[
|
|
19078
|
-
{ type: "address" },
|
|
19079
|
-
// [0]: pf.token(),
|
|
19080
|
-
{ type: "bytes32" },
|
|
19081
|
-
// [1]: pf.dataFeedId(),
|
|
19082
|
-
{ type: "address" },
|
|
19083
|
-
// [2]: pf.signerAddress0(),
|
|
19084
|
-
{ type: "address" },
|
|
19085
|
-
// [3]: pf.signerAddress1(),
|
|
19086
|
-
{ type: "address" },
|
|
19087
|
-
// [4]: pf.signerAddress2(),
|
|
19088
|
-
{ type: "address" },
|
|
19089
|
-
// [5]: pf.signerAddress3(),
|
|
19090
|
-
{ type: "address" },
|
|
19091
|
-
// [6]: pf.signerAddress4(),
|
|
19092
|
-
{ type: "address" },
|
|
19093
|
-
// [7]: pf.signerAddress5()
|
|
19094
|
-
{ type: "address" },
|
|
19095
|
-
// [8]: pf.signerAddress6(),
|
|
19096
|
-
{ type: "address" },
|
|
19097
|
-
// [9]: pf.signerAddress7(),
|
|
19098
|
-
{ type: "address" },
|
|
19099
|
-
// [10]: pf.signerAddress8(),
|
|
19100
|
-
{ type: "address" },
|
|
19101
|
-
// [11]: pf.signerAddress9(),
|
|
19102
|
-
{ type: "uint8" },
|
|
19103
|
-
// [12]: pf.getUniqueSignersThreshold()
|
|
19104
|
-
{ type: "uint128" },
|
|
19105
|
-
// [13]: pf.lastPrice(),
|
|
19106
|
-
{ type: "uint40" }
|
|
19107
|
-
// [14]: pf.lastPayloadTimestamp()
|
|
19108
|
-
],
|
|
19109
|
-
args.baseParams.serializedParams
|
|
19110
|
-
);
|
|
19111
|
-
this.dataId = viem.bytesToString(viem.toBytes(decoder[1])).replaceAll("\0", "");
|
|
19112
|
-
this.signers = decoder.slice(2, 11);
|
|
19113
|
-
this.signersThreshold = Number(decoder[12]);
|
|
19114
|
-
this.dataServiceId = ["GMX", "BAL"].includes(this.dataId) ? "redstone-arbitrum-prod" : "redstone-primary-prod";
|
|
19140
|
+
get(address) {
|
|
19141
|
+
return this.#feeds.get(address);
|
|
19115
19142
|
}
|
|
19116
|
-
|
|
19117
|
-
return
|
|
19118
|
-
...this.contractData,
|
|
19119
|
-
contractType: "PF_REDSTONE_ORACLE",
|
|
19120
|
-
dataId: this.dataId,
|
|
19121
|
-
signers: this.signers,
|
|
19122
|
-
signersThreshold: this.signersThreshold,
|
|
19123
|
-
skipCheck: true
|
|
19124
|
-
};
|
|
19143
|
+
mustGet(address) {
|
|
19144
|
+
return this.#feeds.mustGet(address);
|
|
19125
19145
|
}
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
|
|
19130
|
-
#historicalTimestamp;
|
|
19131
|
-
constructor(sdk) {
|
|
19132
|
-
super(sdk);
|
|
19133
|
-
this.#logger = childLogger("RedstoneUpdater", sdk.logger);
|
|
19146
|
+
create(data) {
|
|
19147
|
+
const feed = this.#create(data);
|
|
19148
|
+
this.#feeds.upsert(data.baseParams.addr, feed);
|
|
19149
|
+
return feed;
|
|
19134
19150
|
}
|
|
19135
|
-
|
|
19136
|
-
|
|
19151
|
+
/**
|
|
19152
|
+
* Set redstone historical timestamp
|
|
19153
|
+
* @param timestampMs in milliseconds
|
|
19154
|
+
*/
|
|
19155
|
+
setRedstoneHistoricalTimestamp(timestampMs) {
|
|
19156
|
+
this.#redstoneUpdater.setHistoricalTimestamp(timestampMs);
|
|
19137
19157
|
}
|
|
19138
|
-
|
|
19139
|
-
|
|
19140
|
-
|
|
19158
|
+
#create(data) {
|
|
19159
|
+
const contractType = bytes32ToString(
|
|
19160
|
+
data.baseParams.contractType
|
|
19141
19161
|
);
|
|
19142
|
-
|
|
19143
|
-
|
|
19144
|
-
|
|
19145
|
-
|
|
19146
|
-
|
|
19147
|
-
|
|
19148
|
-
|
|
19149
|
-
|
|
19150
|
-
|
|
19162
|
+
switch (contractType) {
|
|
19163
|
+
case "PF_CHAINLINK_ORACLE":
|
|
19164
|
+
return new ChainlinkPriceFeedContract(this.sdk, data);
|
|
19165
|
+
case "PF_YEARN_ORACLE":
|
|
19166
|
+
return new YearnPriceFeedContract(this.sdk, data);
|
|
19167
|
+
case "PF_CURVE_STABLE_LP_ORACLE":
|
|
19168
|
+
return new CurveStablePriceFeedContract(this.sdk, data);
|
|
19169
|
+
case "PF_WSTETH_ORACLE":
|
|
19170
|
+
return new WstETHPriceFeedContract(this.sdk, data);
|
|
19171
|
+
case "PF_BOUNDED_ORACLE":
|
|
19172
|
+
return new BoundedPriceFeedContract(this.sdk, data);
|
|
19173
|
+
case "PF_COMPOSITE_ORACLE":
|
|
19174
|
+
return new CompositePriceFeedContract(this.sdk, data);
|
|
19175
|
+
case "PF_BALANCER_STABLE_LP_ORACLE":
|
|
19176
|
+
return new BalancerStablePriceFeedContract(this.sdk, data);
|
|
19177
|
+
case "PF_BALANCER_WEIGHTED_LP_ORACLE":
|
|
19178
|
+
return new BalancerWeightedPriceFeedContract(this.sdk, data);
|
|
19179
|
+
case "PF_CURVE_CRYPTO_LP_ORACLE":
|
|
19180
|
+
return new CurveCryptoPriceFeedContract(this.sdk, data);
|
|
19181
|
+
case "PF_REDSTONE_ORACLE":
|
|
19182
|
+
return new RedstonePriceFeedContract(this.sdk, data);
|
|
19183
|
+
case "PF_ERC4626_ORACLE":
|
|
19184
|
+
return new Erc4626PriceFeedContract(this.sdk, data);
|
|
19185
|
+
case "PF_CURVE_USD_ORACLE":
|
|
19186
|
+
return new CurveUSDPriceFeedContract(this.sdk, data);
|
|
19187
|
+
case "PF_ZERO_ORACLE":
|
|
19188
|
+
return new ZeroPriceFeedContract(this.sdk, data);
|
|
19189
|
+
case "PF_MELLOW_LRT_ORACLE":
|
|
19190
|
+
return new MellowLRTPriceFeedContract(this.sdk, data);
|
|
19191
|
+
default:
|
|
19192
|
+
throw new Error(`Price feed type ${contractType} not supported, `);
|
|
19193
|
+
}
|
|
19194
|
+
}
|
|
19195
|
+
};
|
|
19196
|
+
function rawTxToMulticallPriceUpdate(tx) {
|
|
19197
|
+
const { to, callData } = tx;
|
|
19198
|
+
const { args, functionName } = viem.decodeFunctionData({
|
|
19199
|
+
abi: iUpdatablePriceFeedAbi,
|
|
19200
|
+
data: callData
|
|
19201
|
+
});
|
|
19202
|
+
return {
|
|
19203
|
+
abi: iUpdatablePriceFeedAbi,
|
|
19204
|
+
address: to,
|
|
19205
|
+
functionName,
|
|
19206
|
+
args
|
|
19207
|
+
};
|
|
19208
|
+
}
|
|
19209
|
+
|
|
19210
|
+
// src/sdk/market/PriceOracleContract.ts
|
|
19211
|
+
var PriceOracleContract = class extends BaseContract {
|
|
19212
|
+
/**
|
|
19213
|
+
* Underlying token of market to which this price oracle belongs
|
|
19214
|
+
*/
|
|
19215
|
+
underlying;
|
|
19216
|
+
/**
|
|
19217
|
+
* Mapping Token => [PriceFeed Address, stalenessPeriod]
|
|
19218
|
+
*/
|
|
19219
|
+
mainPriceFeeds = {};
|
|
19220
|
+
/**
|
|
19221
|
+
* Mapping Token => [PriceFeed Address, stalenessPeriod]
|
|
19222
|
+
*/
|
|
19223
|
+
reservePriceFeeds = {};
|
|
19224
|
+
/**
|
|
19225
|
+
* Mapping Token => Price in underlying
|
|
19226
|
+
*/
|
|
19227
|
+
mainPrices = new AddressMap();
|
|
19228
|
+
/**
|
|
19229
|
+
* Mapping Token => Price in underlying
|
|
19230
|
+
*/
|
|
19231
|
+
reservePrices = new AddressMap();
|
|
19232
|
+
#priceFeedTree;
|
|
19233
|
+
constructor(sdk, data, underlying) {
|
|
19234
|
+
super(sdk, {
|
|
19235
|
+
...data.baseParams,
|
|
19236
|
+
name: "PriceOracleV3",
|
|
19237
|
+
abi: priceOracleV3Abi
|
|
19238
|
+
});
|
|
19239
|
+
this.underlying = underlying;
|
|
19240
|
+
const { priceFeedMapping, priceFeedStructure } = data;
|
|
19241
|
+
this.#priceFeedTree = priceFeedStructure;
|
|
19242
|
+
for (const node of priceFeedStructure) {
|
|
19243
|
+
sdk.priceFeeds.create(node);
|
|
19151
19244
|
}
|
|
19152
|
-
|
|
19153
|
-
|
|
19154
|
-
const
|
|
19155
|
-
const
|
|
19156
|
-
|
|
19157
|
-
|
|
19158
|
-
)
|
|
19159
|
-
|
|
19160
|
-
|
|
19161
|
-
|
|
19162
|
-
|
|
19163
|
-
|
|
19164
|
-
|
|
19165
|
-
|
|
19166
|
-
|
|
19167
|
-
throw new Error(`cannot get price feed address for ${dataFeedId}`);
|
|
19245
|
+
priceFeedMapping.forEach((node) => {
|
|
19246
|
+
const { token, priceFeed, reserve, stalenessPeriod } = node;
|
|
19247
|
+
const ref = new PriceFeedRef(sdk, priceFeed, stalenessPeriod);
|
|
19248
|
+
const price = this.#priceFeedTree.find(
|
|
19249
|
+
(n) => n.baseParams.addr === priceFeed
|
|
19250
|
+
)?.answer?.price;
|
|
19251
|
+
if (reserve) {
|
|
19252
|
+
this.reservePriceFeeds[token] = ref;
|
|
19253
|
+
if (price) {
|
|
19254
|
+
this.reservePrices.upsert(token, price);
|
|
19255
|
+
}
|
|
19256
|
+
} else {
|
|
19257
|
+
this.mainPriceFeeds[token] = ref;
|
|
19258
|
+
if (price) {
|
|
19259
|
+
this.mainPrices.upsert(token, price);
|
|
19168
19260
|
}
|
|
19169
|
-
results.push({
|
|
19170
|
-
priceFeed: priceFeed.address.toLowerCase(),
|
|
19171
|
-
tx: priceFeed.createRawTx({
|
|
19172
|
-
functionName: "updatePrice",
|
|
19173
|
-
args: [data],
|
|
19174
|
-
description: `updating price for ${dataFeedId} [${priceFeed.address}]`
|
|
19175
|
-
}),
|
|
19176
|
-
timestamp
|
|
19177
|
-
});
|
|
19178
19261
|
}
|
|
19179
|
-
|
|
19180
|
-
|
|
19181
|
-
|
|
19262
|
+
this.#labelPriceFeed(priceFeed, reserve ? "Reserve" : "Main", token);
|
|
19263
|
+
});
|
|
19264
|
+
this.logger?.debug(
|
|
19265
|
+
`Got ${Object.keys(this.mainPriceFeeds).length} main and ${Object.keys(this.reservePriceFeeds).length} reserve price feeds`
|
|
19182
19266
|
);
|
|
19183
|
-
return results;
|
|
19184
19267
|
}
|
|
19185
19268
|
/**
|
|
19186
|
-
*
|
|
19187
|
-
*
|
|
19188
|
-
* @param
|
|
19189
|
-
* @param dataFeedsIds
|
|
19190
|
-
* @param uniqueSignersCount
|
|
19269
|
+
* Returns main and reserve price feeds for given tokens
|
|
19270
|
+
* @param tokens
|
|
19271
|
+
* @param opts Option to include main/reserve feeds only, defaults to both
|
|
19191
19272
|
* @returns
|
|
19192
19273
|
*/
|
|
19193
|
-
|
|
19194
|
-
const
|
|
19195
|
-
const
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
|
|
19199
|
-
|
|
19200
|
-
uniqueSignersCount,
|
|
19201
|
-
this.#historicalTimestamp
|
|
19202
|
-
);
|
|
19203
|
-
const cached = this.#cache.get(key);
|
|
19204
|
-
if (this.#historicalTimestamp && !!cached) {
|
|
19205
|
-
fromCache.push(cached);
|
|
19206
|
-
} else {
|
|
19207
|
-
uncached.push(dataFeedId);
|
|
19208
|
-
}
|
|
19209
|
-
}
|
|
19210
|
-
const fromRedstone = await this.#fetchPayloads(
|
|
19211
|
-
dataServiceId,
|
|
19212
|
-
new Set(uncached),
|
|
19213
|
-
uniqueSignersCount
|
|
19214
|
-
);
|
|
19215
|
-
if (this.#historicalTimestamp) {
|
|
19216
|
-
for (const resp of fromRedstone) {
|
|
19217
|
-
const key = cacheKey(
|
|
19218
|
-
dataServiceId,
|
|
19219
|
-
resp.dataFeedId,
|
|
19220
|
-
uniqueSignersCount,
|
|
19221
|
-
this.#historicalTimestamp
|
|
19222
|
-
);
|
|
19223
|
-
this.#cache.set(key, resp);
|
|
19224
|
-
}
|
|
19225
|
-
}
|
|
19226
|
-
return [...fromCache, ...fromRedstone];
|
|
19274
|
+
priceFeedsForTokens(tokens, opts) {
|
|
19275
|
+
const main = opts?.main ?? true;
|
|
19276
|
+
const reserve = opts?.reserve ?? true;
|
|
19277
|
+
return tokens.flatMap((t) => [
|
|
19278
|
+
main ? this.mainPriceFeeds[t]?.priceFeed : void 0,
|
|
19279
|
+
reserve ? this.reservePriceFeeds[t]?.priceFeed : void 0
|
|
19280
|
+
]).filter((f) => !!f);
|
|
19227
19281
|
}
|
|
19228
19282
|
/**
|
|
19229
|
-
*
|
|
19230
|
-
* Payloads are loaded in one request to avoid redstone rate limit
|
|
19231
|
-
* @param dataServiceId
|
|
19232
|
-
* @param dataFeedsIds
|
|
19233
|
-
* @param uniqueSignersCount
|
|
19283
|
+
* Generates updates for all updateable price feeds in this oracle (including dependencies)
|
|
19234
19284
|
* @returns
|
|
19235
19285
|
*/
|
|
19236
|
-
async
|
|
19237
|
-
|
|
19238
|
-
|
|
19239
|
-
|
|
19240
|
-
|
|
19241
|
-
const wrapper = new evmConnector.DataServiceWrapper({
|
|
19242
|
-
dataServiceId,
|
|
19243
|
-
dataPackagesIds,
|
|
19244
|
-
uniqueSignersCount,
|
|
19245
|
-
historicalTimestamp: this.#historicalTimestamp
|
|
19246
|
-
});
|
|
19247
|
-
const dataPayload = await wrapper.prepareRedstonePayload(true);
|
|
19248
|
-
const parsed = redstoneProtocol.RedstonePayload.parse(viem.toBytes(`0x${dataPayload}`));
|
|
19249
|
-
const packagesByDataFeedId = groupDataPackages(parsed.signedDataPackages);
|
|
19250
|
-
return dataPackagesIds.map((dataFeedId) => {
|
|
19251
|
-
const signedDataPackages = packagesByDataFeedId[dataFeedId];
|
|
19252
|
-
if (!signedDataPackages) {
|
|
19253
|
-
throw new Error(`cannot find data packages for ${dataFeedId}`);
|
|
19254
|
-
}
|
|
19255
|
-
if (signedDataPackages.length !== uniqueSignersCount) {
|
|
19256
|
-
throw new Error(
|
|
19257
|
-
`got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`
|
|
19258
|
-
);
|
|
19286
|
+
async updatePriceFeeds() {
|
|
19287
|
+
const updatables = [];
|
|
19288
|
+
for (const node of this.#priceFeedTree) {
|
|
19289
|
+
if (node.updatable) {
|
|
19290
|
+
updatables.push(this.sdk.priceFeeds.mustGet(node.baseParams.addr));
|
|
19259
19291
|
}
|
|
19260
|
-
|
|
19261
|
-
|
|
19262
|
-
signedDataPackages,
|
|
19263
|
-
wrapper.getUnsignedMetadata()
|
|
19264
|
-
);
|
|
19265
|
-
});
|
|
19292
|
+
}
|
|
19293
|
+
return this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(updatables);
|
|
19266
19294
|
}
|
|
19267
|
-
|
|
19268
|
-
|
|
19269
|
-
|
|
19270
|
-
|
|
19271
|
-
|
|
19272
|
-
|
|
19273
|
-
|
|
19274
|
-
const
|
|
19275
|
-
|
|
19276
|
-
|
|
19277
|
-
if (dp.dataFeedId !== dataFeedId0) {
|
|
19278
|
-
throw new Error(
|
|
19279
|
-
`data package contains data points with different dataFeedIds: ${dp.dataFeedId} and ${dataFeedId0}`
|
|
19280
|
-
);
|
|
19281
|
-
}
|
|
19295
|
+
/**
|
|
19296
|
+
* Converts previously obtained price updates into CreditFacade multicall entries
|
|
19297
|
+
* @param creditFacade
|
|
19298
|
+
* @param updates
|
|
19299
|
+
* @returns
|
|
19300
|
+
*/
|
|
19301
|
+
onDemandPriceUpdates(updates) {
|
|
19302
|
+
const result = [];
|
|
19303
|
+
if (!updates) {
|
|
19304
|
+
return result;
|
|
19282
19305
|
}
|
|
19283
|
-
|
|
19284
|
-
|
|
19306
|
+
const { txs } = updates;
|
|
19307
|
+
for (const tx of txs) {
|
|
19308
|
+
const { to: priceFeed, callData } = tx;
|
|
19309
|
+
const [token, reserve] = this.#findTokenForPriceFeed(priceFeed);
|
|
19310
|
+
const { args } = viem.decodeFunctionData({
|
|
19311
|
+
abi: iUpdatablePriceFeedAbi,
|
|
19312
|
+
data: callData
|
|
19313
|
+
});
|
|
19314
|
+
const data = args[0];
|
|
19315
|
+
result.push({
|
|
19316
|
+
token,
|
|
19317
|
+
reserve,
|
|
19318
|
+
data
|
|
19319
|
+
});
|
|
19285
19320
|
}
|
|
19286
|
-
|
|
19321
|
+
return result;
|
|
19287
19322
|
}
|
|
19288
|
-
|
|
19289
|
-
|
|
19290
|
-
|
|
19291
|
-
|
|
19292
|
-
|
|
19293
|
-
|
|
19294
|
-
|
|
19295
|
-
|
|
19296
|
-
|
|
19297
|
-
|
|
19298
|
-
|
|
19299
|
-
|
|
19300
|
-
|
|
19301
|
-
|
|
19302
|
-
|
|
19323
|
+
/**
|
|
19324
|
+
* Tries to convert amount of token into underlying of current market
|
|
19325
|
+
* @param token
|
|
19326
|
+
* @param amount
|
|
19327
|
+
* @param reserve
|
|
19328
|
+
* @returns
|
|
19329
|
+
*/
|
|
19330
|
+
convertToUnderlying(token, amount, reserve = false) {
|
|
19331
|
+
return this.convert(token, this.underlying, amount, reserve);
|
|
19332
|
+
}
|
|
19333
|
+
/**
|
|
19334
|
+
* Tries to convert amount of from one token to another, using latest known prices
|
|
19335
|
+
* @param from
|
|
19336
|
+
* @param to
|
|
19337
|
+
* @param amount
|
|
19338
|
+
* @param reserve
|
|
19339
|
+
*/
|
|
19340
|
+
convert(from, to, amount, reserve = false) {
|
|
19341
|
+
if (from === to) {
|
|
19342
|
+
return amount;
|
|
19303
19343
|
}
|
|
19344
|
+
const fromPrice = reserve ? this.reservePrices.mustGet(from) : this.mainPrices.mustGet(from);
|
|
19345
|
+
const fromScale = 10n ** BigInt(this.sdk.marketRegister.tokensMeta.mustGet(from).decimals);
|
|
19346
|
+
const toPrice = reserve ? this.reservePrices.mustGet(to) : this.mainPrices.mustGet(to);
|
|
19347
|
+
const toScale = 10n ** BigInt(this.sdk.marketRegister.tokensMeta.mustGet(to).decimals);
|
|
19348
|
+
return amount * fromPrice * toScale / (toPrice * fromScale);
|
|
19304
19349
|
}
|
|
19305
|
-
|
|
19306
|
-
|
|
19307
|
-
|
|
19308
|
-
|
|
19309
|
-
|
|
19310
|
-
)
|
|
19311
|
-
|
|
19312
|
-
|
|
19313
|
-
|
|
19314
|
-
|
|
19315
|
-
|
|
19316
|
-
|
|
19317
|
-
|
|
19318
|
-
|
|
19319
|
-
|
|
19320
|
-
|
|
19321
|
-
|
|
19350
|
+
/**
|
|
19351
|
+
* Loads new prices for this oracle from PriceFeedCompressor
|
|
19352
|
+
* Does not update price feeds, only updates prices
|
|
19353
|
+
*/
|
|
19354
|
+
async updatePrices() {
|
|
19355
|
+
const { txs } = await this.updatePriceFeeds();
|
|
19356
|
+
const resp = await simulateMulticall(this.provider.publicClient, {
|
|
19357
|
+
contracts: [
|
|
19358
|
+
...txs.map(rawTxToMulticallPriceUpdate),
|
|
19359
|
+
{
|
|
19360
|
+
abi: iPriceFeedCompressorAbi,
|
|
19361
|
+
address: this.sdk.addressProvider.getLatestVersion(
|
|
19362
|
+
AP_PRICE_FEED_COMPRESSOR
|
|
19363
|
+
),
|
|
19364
|
+
functionName: "getPriceFeeds",
|
|
19365
|
+
args: [this.address]
|
|
19366
|
+
}
|
|
19367
|
+
],
|
|
19368
|
+
allowFailure: false,
|
|
19369
|
+
gas: 550000000n,
|
|
19370
|
+
batchSize: 0
|
|
19371
|
+
// we cannot have price updates and compressor request in different batches
|
|
19322
19372
|
});
|
|
19323
|
-
|
|
19324
|
-
|
|
19325
|
-
|
|
19326
|
-
|
|
19327
|
-
|
|
19328
|
-
|
|
19329
|
-
|
|
19330
|
-
|
|
19331
|
-
}
|
|
19332
|
-
async getValue() {
|
|
19333
|
-
return await this.sdk.provider.publicClient.readContract({
|
|
19334
|
-
abi: iwstEthAbi,
|
|
19335
|
-
address: this.lpContract,
|
|
19336
|
-
functionName: "stEthPerToken"
|
|
19373
|
+
const [entries, tree] = resp.pop();
|
|
19374
|
+
entries.forEach(({ token, priceFeed, reserve }) => {
|
|
19375
|
+
const price = tree.find((n) => n.baseParams.addr === priceFeed)?.answer?.price;
|
|
19376
|
+
if (reserve && price) {
|
|
19377
|
+
this.reservePrices.upsert(token, price);
|
|
19378
|
+
} else if (price) {
|
|
19379
|
+
this.mainPrices.upsert(token, price);
|
|
19380
|
+
}
|
|
19337
19381
|
});
|
|
19338
19382
|
}
|
|
19339
|
-
|
|
19340
|
-
|
|
19341
|
-
|
|
19342
|
-
|
|
19343
|
-
|
|
19344
|
-
|
|
19345
|
-
|
|
19346
|
-
|
|
19347
|
-
abi: yearnPriceFeedAbi
|
|
19383
|
+
#labelPriceFeed(address, usage, token) {
|
|
19384
|
+
this.sdk.provider.addressLabels.set(address, (label) => {
|
|
19385
|
+
const { symbol } = this.sdk.marketRegister.tokensMeta.mustGet(token);
|
|
19386
|
+
let pricefeedTag = `${symbol}.${usage}`;
|
|
19387
|
+
if (label) {
|
|
19388
|
+
pricefeedTag = `${label}, ${pricefeedTag}`;
|
|
19389
|
+
}
|
|
19390
|
+
return pricefeedTag;
|
|
19348
19391
|
});
|
|
19349
19392
|
}
|
|
19393
|
+
/**
|
|
19394
|
+
* Helper method to find "attachment point" of price feed (makes sense for updatable price feeds only) - token (in v3.0 can be ticker) and main/reserve flag
|
|
19395
|
+
*
|
|
19396
|
+
* @param priceFeed
|
|
19397
|
+
* @returns
|
|
19398
|
+
*/
|
|
19399
|
+
#findTokenForPriceFeed(priceFeed) {
|
|
19400
|
+
for (const [token, pf] of Object.entries(this.mainPriceFeeds)) {
|
|
19401
|
+
if (pf.address === priceFeed) {
|
|
19402
|
+
return [token, false];
|
|
19403
|
+
}
|
|
19404
|
+
}
|
|
19405
|
+
for (const [token, pf] of Object.entries(this.reservePriceFeeds)) {
|
|
19406
|
+
if (pf.address === priceFeed) {
|
|
19407
|
+
return [token, true];
|
|
19408
|
+
}
|
|
19409
|
+
}
|
|
19410
|
+
const ticker = priceFeedToTicker[this.sdk.provider.networkType][priceFeed];
|
|
19411
|
+
if (ticker) {
|
|
19412
|
+
return [ticker, false];
|
|
19413
|
+
}
|
|
19414
|
+
throw new Error(`cannot find token for price feed ${priceFeed}`);
|
|
19415
|
+
}
|
|
19350
19416
|
get state() {
|
|
19351
19417
|
return {
|
|
19352
|
-
|
|
19353
|
-
|
|
19354
|
-
|
|
19355
|
-
|
|
19418
|
+
priceOracleV3: this.contractData,
|
|
19419
|
+
mainPriceFeeds: Object.fromEntries(
|
|
19420
|
+
Object.entries(this.mainPriceFeeds).map(([token, v]) => [
|
|
19421
|
+
token,
|
|
19422
|
+
v.state
|
|
19423
|
+
])
|
|
19424
|
+
),
|
|
19425
|
+
reservePriceFeeds: Object.fromEntries(
|
|
19426
|
+
Object.entries(this.reservePriceFeeds).map(([token, v]) => [
|
|
19427
|
+
token,
|
|
19428
|
+
v.state
|
|
19429
|
+
])
|
|
19430
|
+
)
|
|
19356
19431
|
};
|
|
19357
19432
|
}
|
|
19358
|
-
|
|
19359
|
-
|
|
19360
|
-
|
|
19361
|
-
|
|
19362
|
-
|
|
19363
|
-
|
|
19364
|
-
|
|
19433
|
+
};
|
|
19434
|
+
var priceFeedToTicker = {
|
|
19435
|
+
Mainnet: {
|
|
19436
|
+
"0x6F13996411743d22566176482B6b677Ec4eb6cE6": "0x8C23b9E4CB9884e807294c4b4C33820333cC613c",
|
|
19437
|
+
"0xa7cB34Cd731486F61cfDb7ff5F6fC7B40537eD76": "0xFb56Fb16B4F33A875b01881Da7458E09D286208e",
|
|
19438
|
+
"0xcf1FDc8DC6e83B38729d58C117BE704bb2AC362a": "0xf08D818be34C82cB5e3f33AC78F8268828764F17",
|
|
19439
|
+
"0xE683362b8ebcbfd9332CBB79BfAF9fC42073C49b": "0xBdb778F566b6cEd70D3d329DD1D14E221fFe1ba5",
|
|
19440
|
+
"0xB72A69e2182bE87bda706B7Ff9A539AC78338C61": "0x7fF63E75F48aad6F4bE97E75C6421f348f19fE7F",
|
|
19441
|
+
"0xd7396fA3aFB9833293Ce2149EEb3Dbf5380B1e0D": "0xB0EA0EC3Fd4947348816f76768b3a56249d47EEc"
|
|
19442
|
+
},
|
|
19443
|
+
Arbitrum: {
|
|
19444
|
+
"0xcB44ADd611f75F03191f8f1A2e2AF7a0113eadd1": "0x07299E4E806e4253727084c0493fFDf6fB2dBa3D",
|
|
19445
|
+
"0x354A63F07A5c1605920794aFFF09963b6DF897a9": "0x15094B05e679c9B7fDde6FB8e6BDa930ff1D6a62"
|
|
19446
|
+
},
|
|
19447
|
+
Optimism: {
|
|
19448
|
+
"0xF23C91b1E3B7FD9174c82F7Fb2BD270C3CfcC3CE": "0x658f8e60c57ad62a9299ef6c7b1da9a0d1d1e681"
|
|
19449
|
+
},
|
|
19450
|
+
Base: {}
|
|
19365
19451
|
};
|
|
19366
19452
|
|
|
19367
|
-
// src/sdk/market/
|
|
19368
|
-
var
|
|
19369
|
-
|
|
19370
|
-
|
|
19371
|
-
|
|
19372
|
-
|
|
19373
|
-
|
|
19374
|
-
|
|
19375
|
-
|
|
19453
|
+
// src/sdk/market/MarketFactory.ts
|
|
19454
|
+
var MarketFactory = class {
|
|
19455
|
+
riskCurator;
|
|
19456
|
+
poolFactory;
|
|
19457
|
+
priceOracle;
|
|
19458
|
+
creditManagers = [];
|
|
19459
|
+
constructor(sdk, marketData) {
|
|
19460
|
+
this.riskCurator = marketData.owner;
|
|
19461
|
+
for (const t of marketData.tokens) {
|
|
19462
|
+
sdk.marketRegister.tokensMeta.upsert(t.addr, t);
|
|
19463
|
+
sdk.provider.addressLabels.set(t.addr, t.symbol);
|
|
19464
|
+
}
|
|
19465
|
+
this.poolFactory = new PoolFactory(sdk, marketData);
|
|
19466
|
+
for (let i = 0; i < marketData.creditManagers.length; i++) {
|
|
19467
|
+
this.creditManagers.push(new CreditFactory(sdk, marketData, i));
|
|
19468
|
+
}
|
|
19469
|
+
this.priceOracle = new PriceOracleContract(
|
|
19470
|
+
sdk,
|
|
19471
|
+
marketData.priceOracleData,
|
|
19472
|
+
marketData.pool.underlying
|
|
19473
|
+
);
|
|
19376
19474
|
}
|
|
19377
19475
|
get state() {
|
|
19378
19476
|
return {
|
|
19379
|
-
|
|
19380
|
-
|
|
19381
|
-
|
|
19382
|
-
stalenessPeriod: 0,
|
|
19383
|
-
pricefeeds: []
|
|
19477
|
+
pool: this.poolFactory.state,
|
|
19478
|
+
creditManagers: this.creditManagers.map((cm) => cm.state),
|
|
19479
|
+
priceOracle: this.priceOracle.state
|
|
19384
19480
|
};
|
|
19385
19481
|
}
|
|
19386
19482
|
};
|
|
19387
19483
|
|
|
19388
|
-
// src/sdk/market/
|
|
19389
|
-
var
|
|
19390
|
-
logger;
|
|
19391
|
-
#hooks = new Hooks();
|
|
19392
|
-
#feeds = new AddressMap();
|
|
19393
|
-
#redstoneUpdater;
|
|
19394
|
-
// public readonly zeroPriceFeed: ZeroPriceFeedContract;
|
|
19395
|
-
constructor(sdk) {
|
|
19396
|
-
super(sdk);
|
|
19397
|
-
this.logger = childLogger("PriceFeedRegister", sdk.logger);
|
|
19398
|
-
this.#redstoneUpdater = new RedstoneUpdater(sdk);
|
|
19399
|
-
}
|
|
19400
|
-
addHook = this.#hooks.addHook.bind(this.#hooks);
|
|
19401
|
-
removeHook = this.#hooks.removeHook.bind(this.#hooks);
|
|
19484
|
+
// src/sdk/market/MarketRegister.ts
|
|
19485
|
+
var MarketRegister = class {
|
|
19486
|
+
#logger;
|
|
19402
19487
|
/**
|
|
19403
|
-
*
|
|
19404
|
-
* @param priceFeeds top-level price feeds, actual updatable price feeds will be derived. If not provided will use all price feeds that are attached
|
|
19405
|
-
* @returns
|
|
19488
|
+
* Mapping pool.name -> MarketFactory
|
|
19406
19489
|
*/
|
|
19407
|
-
|
|
19408
|
-
|
|
19409
|
-
|
|
19410
|
-
|
|
19411
|
-
|
|
19412
|
-
|
|
19413
|
-
|
|
19414
|
-
|
|
19415
|
-
|
|
19416
|
-
|
|
19417
|
-
|
|
19418
|
-
|
|
19419
|
-
|
|
19420
|
-
|
|
19421
|
-
|
|
19422
|
-
|
|
19490
|
+
#markets = {};
|
|
19491
|
+
/**
|
|
19492
|
+
* Token metadata such as symbol and decimals, common across all markets
|
|
19493
|
+
*/
|
|
19494
|
+
tokensMeta = new AddressMap();
|
|
19495
|
+
#sdk;
|
|
19496
|
+
constructor(sdk) {
|
|
19497
|
+
this.#sdk = sdk;
|
|
19498
|
+
this.#logger = childLogger("MarketRegister", sdk.logger);
|
|
19499
|
+
}
|
|
19500
|
+
async loadMarkets(curators) {
|
|
19501
|
+
this.#logger?.debug("loading markets");
|
|
19502
|
+
const marketCompressorAddress = this.#sdk.addressProvider.getAddress(
|
|
19503
|
+
AP_MARKET_COMPRESSOR,
|
|
19504
|
+
310
|
|
19505
|
+
);
|
|
19506
|
+
const markets = await this.#sdk.provider.publicClient.readContract({
|
|
19507
|
+
address: marketCompressorAddress,
|
|
19508
|
+
abi: iMarketCompressorAbi,
|
|
19509
|
+
functionName: "getMarkets",
|
|
19510
|
+
args: [
|
|
19511
|
+
{
|
|
19512
|
+
curators,
|
|
19513
|
+
pools: [],
|
|
19514
|
+
underlying: ADDRESS_0X0
|
|
19423
19515
|
}
|
|
19424
|
-
|
|
19425
|
-
|
|
19516
|
+
],
|
|
19517
|
+
// It's passed as ...rest in viem readContract action, but this might change
|
|
19518
|
+
// @ts-ignore
|
|
19519
|
+
gas: 500000000n
|
|
19520
|
+
});
|
|
19521
|
+
for (const data of markets) {
|
|
19522
|
+
this.#markets[data.pool.name] = new MarketFactory(this.#sdk, data);
|
|
19426
19523
|
}
|
|
19427
|
-
|
|
19428
|
-
await this.#hooks.triggerHooks("updatesGenerated", result);
|
|
19429
|
-
return result;
|
|
19524
|
+
this.#logger?.info(`loaded ${markets.length} markets`);
|
|
19430
19525
|
}
|
|
19431
|
-
get(
|
|
19432
|
-
return this.#
|
|
19526
|
+
get state() {
|
|
19527
|
+
return Object.values(this.#markets).map((market) => market.state);
|
|
19433
19528
|
}
|
|
19434
|
-
|
|
19435
|
-
return this.#
|
|
19529
|
+
get poolState() {
|
|
19530
|
+
return Object.values(this.#markets).map((market) => market.poolFactory.state);
|
|
19436
19531
|
}
|
|
19437
|
-
|
|
19438
|
-
|
|
19439
|
-
|
|
19440
|
-
|
|
19532
|
+
get creditManagerState() {
|
|
19533
|
+
return Object.values(this.#markets).flatMap(
|
|
19534
|
+
(market) => market.creditManagers.map((cm) => cm.state)
|
|
19535
|
+
);
|
|
19441
19536
|
}
|
|
19442
|
-
|
|
19443
|
-
|
|
19444
|
-
|
|
19445
|
-
|
|
19446
|
-
|
|
19447
|
-
|
|
19537
|
+
getPoolFactories() {
|
|
19538
|
+
return this.markets.map((market) => market.poolFactory);
|
|
19539
|
+
}
|
|
19540
|
+
get creditManagers() {
|
|
19541
|
+
return this.markets.flatMap((market) => market.creditManagers);
|
|
19542
|
+
}
|
|
19543
|
+
findCreditManager(creditManager) {
|
|
19544
|
+
for (const market of this.markets) {
|
|
19545
|
+
for (const cm of market.creditManagers) {
|
|
19546
|
+
if (cm.creditManager.address === creditManager) {
|
|
19547
|
+
return cm;
|
|
19548
|
+
}
|
|
19549
|
+
}
|
|
19550
|
+
}
|
|
19551
|
+
throw new Error(`cannot find credit manager ${creditManager}`);
|
|
19448
19552
|
}
|
|
19449
|
-
|
|
19450
|
-
const
|
|
19451
|
-
|
|
19553
|
+
findByCreditManager(creditManager) {
|
|
19554
|
+
const market = Object.values(this.#markets).find(
|
|
19555
|
+
(m) => m.creditManagers.some(
|
|
19556
|
+
(cm) => cm.creditManager.address.toLowerCase() === creditManager.toLowerCase()
|
|
19557
|
+
)
|
|
19452
19558
|
);
|
|
19453
|
-
|
|
19454
|
-
|
|
19455
|
-
return new ChainlinkPriceFeedContract(this.sdk, data);
|
|
19456
|
-
case "PF_YEARN_ORACLE":
|
|
19457
|
-
return new YearnPriceFeedContract(this.sdk, data);
|
|
19458
|
-
case "PF_CURVE_STABLE_LP_ORACLE":
|
|
19459
|
-
return new CurveStablePriceFeedContract(this.sdk, data);
|
|
19460
|
-
case "PF_WSTETH_ORACLE":
|
|
19461
|
-
return new WstETHPriceFeedContract(this.sdk, data);
|
|
19462
|
-
case "PF_BOUNDED_ORACLE":
|
|
19463
|
-
return new BoundedPriceFeedContract(this.sdk, data);
|
|
19464
|
-
case "PF_COMPOSITE_ORACLE":
|
|
19465
|
-
return new CompositePriceFeedContract(this.sdk, data);
|
|
19466
|
-
case "PF_BALANCER_STABLE_LP_ORACLE":
|
|
19467
|
-
return new BalancerStablePriceFeedContract(this.sdk, data);
|
|
19468
|
-
case "PF_BALANCER_WEIGHTED_LP_ORACLE":
|
|
19469
|
-
return new BalancerWeightedPriceFeedContract(this.sdk, data);
|
|
19470
|
-
case "PF_CURVE_CRYPTO_LP_ORACLE":
|
|
19471
|
-
return new CurveCryptoPriceFeedContract(this.sdk, data);
|
|
19472
|
-
case "PF_REDSTONE_ORACLE":
|
|
19473
|
-
return new RedstonePriceFeedContract(this.sdk, data);
|
|
19474
|
-
case "PF_ERC4626_ORACLE":
|
|
19475
|
-
return new Erc4626PriceFeedContract(this.sdk, data);
|
|
19476
|
-
case "PF_CURVE_USD_ORACLE":
|
|
19477
|
-
return new CurveUSDPriceFeedContract(this.sdk, data);
|
|
19478
|
-
case "PF_ZERO_ORACLE":
|
|
19479
|
-
return new ZeroPriceFeedContract(this.sdk, data);
|
|
19480
|
-
case "PF_MELLOW_LRT_ORACLE":
|
|
19481
|
-
return new MellowLRTPriceFeedContract(this.sdk, data);
|
|
19482
|
-
default:
|
|
19483
|
-
throw new Error(`Price feed type ${contractType} not supported, `);
|
|
19559
|
+
if (!market) {
|
|
19560
|
+
throw new Error(`cannot find market for credit manager ${creditManager}`);
|
|
19484
19561
|
}
|
|
19562
|
+
return market;
|
|
19563
|
+
}
|
|
19564
|
+
get markets() {
|
|
19565
|
+
return Object.values(this.#markets);
|
|
19566
|
+
}
|
|
19567
|
+
async tvl() {
|
|
19568
|
+
const creditManagers = this.creditManagers;
|
|
19569
|
+
const tvls = await Promise.all(creditManagers.map((cm) => cm.tvl()));
|
|
19570
|
+
return tvls.reduce(
|
|
19571
|
+
(acc, curr) => {
|
|
19572
|
+
acc.tvl += curr.tvl;
|
|
19573
|
+
acc.tvlUSD += curr.tvlUSD;
|
|
19574
|
+
return acc;
|
|
19575
|
+
},
|
|
19576
|
+
{ tvl: 0n, tvlUSD: 0n }
|
|
19577
|
+
);
|
|
19485
19578
|
}
|
|
19486
19579
|
};
|
|
19487
19580
|
|
|
19488
|
-
// src/sdk/
|
|
19489
|
-
var
|
|
19490
|
-
|
|
19491
|
-
|
|
19492
|
-
|
|
19493
|
-
|
|
19494
|
-
|
|
19495
|
-
|
|
19496
|
-
|
|
19497
|
-
mainPriceFeeds = {};
|
|
19581
|
+
// src/sdk/accounts/CreditAccountsService.ts
|
|
19582
|
+
var CreditAccountsService = class extends SDKConstruct {
|
|
19583
|
+
#compressor;
|
|
19584
|
+
constructor(sdk) {
|
|
19585
|
+
super(sdk);
|
|
19586
|
+
this.#compressor = sdk.addressProvider.getLatestVersion(
|
|
19587
|
+
AP_CREDIT_ACCOUNT_COMPRESSOR
|
|
19588
|
+
);
|
|
19589
|
+
}
|
|
19498
19590
|
/**
|
|
19499
|
-
*
|
|
19591
|
+
* Returns single credit account data, or undefined if it's not found
|
|
19592
|
+
* Performs all necessary price feed updates under the hood
|
|
19593
|
+
* @param account
|
|
19594
|
+
* @returns
|
|
19500
19595
|
*/
|
|
19501
|
-
|
|
19596
|
+
async getCreditAccountData(account) {
|
|
19597
|
+
let raw;
|
|
19598
|
+
try {
|
|
19599
|
+
raw = await this.provider.publicClient.readContract({
|
|
19600
|
+
abi: iCreditAccountCompressorAbi,
|
|
19601
|
+
address: this.#compressor,
|
|
19602
|
+
functionName: "getCreditAccountData",
|
|
19603
|
+
args: [account]
|
|
19604
|
+
});
|
|
19605
|
+
} catch (e) {
|
|
19606
|
+
return void 0;
|
|
19607
|
+
}
|
|
19608
|
+
if (raw.success) {
|
|
19609
|
+
return raw;
|
|
19610
|
+
}
|
|
19611
|
+
const { txs: priceUpdateTxs, timestamp: _ } = await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs();
|
|
19612
|
+
const resp = await simulateMulticall(this.provider.publicClient, {
|
|
19613
|
+
account: this.provider.account,
|
|
19614
|
+
contracts: [
|
|
19615
|
+
...priceUpdateTxs.map(rawTxToMulticallPriceUpdate),
|
|
19616
|
+
{
|
|
19617
|
+
abi: iCreditAccountCompressorAbi,
|
|
19618
|
+
address: this.#compressor,
|
|
19619
|
+
functionName: "getCreditAccountData",
|
|
19620
|
+
args: [account]
|
|
19621
|
+
}
|
|
19622
|
+
],
|
|
19623
|
+
allowFailure: false,
|
|
19624
|
+
gas: 550000000n,
|
|
19625
|
+
batchSize: 0
|
|
19626
|
+
// we cannot have price updates and compressor request in different batches
|
|
19627
|
+
});
|
|
19628
|
+
const cad = resp.pop();
|
|
19629
|
+
return cad;
|
|
19630
|
+
}
|
|
19502
19631
|
/**
|
|
19503
|
-
*
|
|
19632
|
+
* Methods to get all credit accounts with some optional filtering
|
|
19633
|
+
* Performs all necessary price feed updates under the hood
|
|
19634
|
+
*
|
|
19635
|
+
* TODO: do we want to expose pagination?
|
|
19636
|
+
* TODO: do we want to expose "reverting"?
|
|
19637
|
+
* TODO: do we want to expose MarketFilter in any way? If so, we need to check that the MarketFilter is compatibled with attached markets?
|
|
19638
|
+
* @param args
|
|
19639
|
+
* @returns returned credit accounts are sorted by health factor in ascending order
|
|
19504
19640
|
*/
|
|
19505
|
-
|
|
19641
|
+
async getCreditAccounts(args) {
|
|
19642
|
+
const {
|
|
19643
|
+
creditManager,
|
|
19644
|
+
includeZeroDebt = false,
|
|
19645
|
+
maxHealthFactor = 65535,
|
|
19646
|
+
// TODO: this will change to bigint
|
|
19647
|
+
minHealthFactor = 0,
|
|
19648
|
+
owner = ADDRESS_0X0
|
|
19649
|
+
} = args ?? {};
|
|
19650
|
+
const arg0 = creditManager ?? {
|
|
19651
|
+
curators: [],
|
|
19652
|
+
pools: this.pools,
|
|
19653
|
+
underlying: ADDRESS_0X0
|
|
19654
|
+
};
|
|
19655
|
+
const caFilter = {
|
|
19656
|
+
owner,
|
|
19657
|
+
includeZeroDebt,
|
|
19658
|
+
minHealthFactor,
|
|
19659
|
+
maxHealthFactor
|
|
19660
|
+
};
|
|
19661
|
+
const { txs: priceUpdateTxs, timestamp: _ } = await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs();
|
|
19662
|
+
const allCAs = [];
|
|
19663
|
+
for (const reverting of [false, true]) {
|
|
19664
|
+
let offset = 0n;
|
|
19665
|
+
do {
|
|
19666
|
+
const [accounts, newOffset] = await this.#getCreditAccounts(
|
|
19667
|
+
[arg0, { ...caFilter, reverting }, offset],
|
|
19668
|
+
priceUpdateTxs
|
|
19669
|
+
);
|
|
19670
|
+
allCAs.push(...accounts);
|
|
19671
|
+
offset = newOffset;
|
|
19672
|
+
} while (offset !== 0n);
|
|
19673
|
+
}
|
|
19674
|
+
return allCAs.sort((a, b) => Number(a.healthFactor - b.healthFactor));
|
|
19675
|
+
}
|
|
19506
19676
|
/**
|
|
19507
|
-
*
|
|
19677
|
+
* Generates transaction to liquidate credit account
|
|
19678
|
+
* @param account
|
|
19679
|
+
* @param to Address to transfer underlying left after liquidation
|
|
19680
|
+
* @param slippage
|
|
19681
|
+
* @returns
|
|
19508
19682
|
*/
|
|
19509
|
-
|
|
19510
|
-
|
|
19511
|
-
|
|
19512
|
-
|
|
19513
|
-
|
|
19514
|
-
|
|
19515
|
-
|
|
19516
|
-
|
|
19517
|
-
|
|
19518
|
-
|
|
19519
|
-
|
|
19520
|
-
for (const node of priceFeedStructure) {
|
|
19521
|
-
sdk.priceFeeds.create(node);
|
|
19683
|
+
async fullyLiquidate(account, to, slippage = 50n) {
|
|
19684
|
+
const cm = this.sdk.marketRegister.findCreditManager(account.creditManager);
|
|
19685
|
+
const preview = await this.sdk.router.findBestClosePath(
|
|
19686
|
+
account,
|
|
19687
|
+
cm.creditManager,
|
|
19688
|
+
slippage
|
|
19689
|
+
);
|
|
19690
|
+
const priceUpdates = await this.getPriceUpdatesForFacade(account);
|
|
19691
|
+
const recipient = to ?? this.sdk.provider.account;
|
|
19692
|
+
if (!recipient) {
|
|
19693
|
+
throw new Error("liquidate account: assets recipient not specied");
|
|
19522
19694
|
}
|
|
19523
|
-
|
|
19524
|
-
|
|
19525
|
-
|
|
19526
|
-
|
|
19527
|
-
|
|
19528
|
-
|
|
19529
|
-
|
|
19530
|
-
|
|
19531
|
-
if (price) {
|
|
19532
|
-
this.reservePrices.upsert(token, price);
|
|
19533
|
-
}
|
|
19534
|
-
} else {
|
|
19535
|
-
this.mainPriceFeeds[token] = ref;
|
|
19536
|
-
if (price) {
|
|
19537
|
-
this.mainPrices.upsert(token, price);
|
|
19538
|
-
}
|
|
19539
|
-
}
|
|
19540
|
-
this.#labelPriceFeed(priceFeed, reserve ? "Reserve" : "Main", token);
|
|
19695
|
+
return cm.creditFacade.createRawTx({
|
|
19696
|
+
functionName: "liquidateCreditAccount",
|
|
19697
|
+
args: [
|
|
19698
|
+
account.creditAccount,
|
|
19699
|
+
recipient,
|
|
19700
|
+
[...priceUpdates, ...preview.calls]
|
|
19701
|
+
],
|
|
19702
|
+
description: `fully liquidate ${account.creditAccount}`
|
|
19541
19703
|
});
|
|
19542
|
-
this.logger?.debug(
|
|
19543
|
-
`Got ${Object.keys(this.mainPriceFeeds).length} main and ${Object.keys(this.reservePriceFeeds).length} reserve price feeds`
|
|
19544
|
-
);
|
|
19545
19704
|
}
|
|
19546
19705
|
/**
|
|
19547
|
-
*
|
|
19548
|
-
* @param
|
|
19549
|
-
* @param
|
|
19706
|
+
* Closes credit account or sets debt to zero (but keep account)
|
|
19707
|
+
* @param operation
|
|
19708
|
+
* @param ca
|
|
19709
|
+
* @param assetsToKeep Tokens to withdraw from credit account
|
|
19710
|
+
* @param to Address to withdraw underlying to
|
|
19711
|
+
* @param slippage
|
|
19550
19712
|
* @returns
|
|
19551
19713
|
*/
|
|
19552
|
-
|
|
19553
|
-
const
|
|
19554
|
-
const
|
|
19555
|
-
|
|
19556
|
-
|
|
19557
|
-
|
|
19558
|
-
|
|
19714
|
+
async closeCreditAccount(operation, ca, assetsToKeep, to, slippage = 50n) {
|
|
19715
|
+
const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
|
|
19716
|
+
const recipient = to ?? this.sdk.provider.account;
|
|
19717
|
+
if (!recipient) {
|
|
19718
|
+
throw new Error("close account: assets recipient not specied");
|
|
19719
|
+
}
|
|
19720
|
+
const calls = await this.#prepareCloseCreditAccount(
|
|
19721
|
+
ca,
|
|
19722
|
+
cm,
|
|
19723
|
+
assetsToKeep,
|
|
19724
|
+
recipient,
|
|
19725
|
+
slippage
|
|
19726
|
+
);
|
|
19727
|
+
return cm.creditFacade.createRawTx({
|
|
19728
|
+
functionName: operation === "close" ? "closeCreditAccount" : "multicall",
|
|
19729
|
+
args: [ca.creditAccount, calls],
|
|
19730
|
+
description: `${operation} account ${ca.creditAccount}`
|
|
19731
|
+
});
|
|
19559
19732
|
}
|
|
19560
19733
|
/**
|
|
19561
|
-
*
|
|
19734
|
+
* Internal wrapper for CreditAccountCompressor.getCreditAccounts + price updates wrapped into multicall
|
|
19735
|
+
* @param args
|
|
19736
|
+
* @param priceUpdateTxs
|
|
19562
19737
|
* @returns
|
|
19563
19738
|
*/
|
|
19564
|
-
async
|
|
19565
|
-
|
|
19566
|
-
|
|
19567
|
-
|
|
19568
|
-
|
|
19569
|
-
|
|
19739
|
+
async #getCreditAccounts(args, priceUpdateTxs) {
|
|
19740
|
+
if (priceUpdateTxs?.length) {
|
|
19741
|
+
const resp = await simulateMulticall(this.provider.publicClient, {
|
|
19742
|
+
account: this.provider.account,
|
|
19743
|
+
contracts: [
|
|
19744
|
+
...priceUpdateTxs.map(rawTxToMulticallPriceUpdate),
|
|
19745
|
+
{
|
|
19746
|
+
abi: iCreditAccountCompressorAbi,
|
|
19747
|
+
address: this.#compressor,
|
|
19748
|
+
functionName: "getCreditAccounts",
|
|
19749
|
+
args
|
|
19750
|
+
}
|
|
19751
|
+
],
|
|
19752
|
+
allowFailure: false,
|
|
19753
|
+
gas: 550000000n,
|
|
19754
|
+
batchSize: 0
|
|
19755
|
+
// we cannot have price updates and compressor request in different batches
|
|
19756
|
+
});
|
|
19757
|
+
const getCreditAccountsResp = resp.pop();
|
|
19758
|
+
return getCreditAccountsResp;
|
|
19570
19759
|
}
|
|
19571
|
-
return this.
|
|
19760
|
+
return this.provider.publicClient.readContract({
|
|
19761
|
+
abi: iCreditAccountCompressorAbi,
|
|
19762
|
+
address: this.#compressor,
|
|
19763
|
+
functionName: "getCreditAccounts",
|
|
19764
|
+
args
|
|
19765
|
+
});
|
|
19572
19766
|
}
|
|
19573
19767
|
/**
|
|
19574
|
-
*
|
|
19575
|
-
* @param
|
|
19576
|
-
* @param updates
|
|
19768
|
+
* Returns raw txs that are needed to update all price feeds so that all credit accounts (possibly from different markets) compute
|
|
19769
|
+
* @param accounts
|
|
19577
19770
|
* @returns
|
|
19578
19771
|
*/
|
|
19579
|
-
|
|
19580
|
-
const
|
|
19581
|
-
|
|
19582
|
-
|
|
19772
|
+
async getUpdateForAccounts(accounts) {
|
|
19773
|
+
const tokensByPool = /* @__PURE__ */ new Map();
|
|
19774
|
+
const oracleByPool = /* @__PURE__ */ new Map();
|
|
19775
|
+
for (const acc of accounts) {
|
|
19776
|
+
const market = this.sdk.marketRegister.findByCreditManager(
|
|
19777
|
+
acc.creditManager
|
|
19778
|
+
);
|
|
19779
|
+
const pool = market.state.pool.pool.address;
|
|
19780
|
+
oracleByPool.set(pool, market.priceOracle);
|
|
19781
|
+
for (const t of acc.tokens) {
|
|
19782
|
+
if (t.balance > 10n) {
|
|
19783
|
+
const tokens = tokensByPool.get(pool) ?? /* @__PURE__ */ new Set();
|
|
19784
|
+
tokens.add(t.token);
|
|
19785
|
+
tokensByPool.set(pool, tokens);
|
|
19786
|
+
}
|
|
19787
|
+
}
|
|
19583
19788
|
}
|
|
19584
|
-
const
|
|
19585
|
-
for (const
|
|
19586
|
-
const
|
|
19587
|
-
|
|
19588
|
-
const { args } = viem.decodeFunctionData({
|
|
19589
|
-
abi: iUpdatablePriceFeedAbi,
|
|
19590
|
-
data: callData
|
|
19591
|
-
});
|
|
19592
|
-
const data = args[0];
|
|
19593
|
-
result.push({
|
|
19594
|
-
token,
|
|
19595
|
-
reserve,
|
|
19596
|
-
data
|
|
19597
|
-
});
|
|
19789
|
+
const priceFeeds = [];
|
|
19790
|
+
for (const [pool, priceFeedFactory] of oracleByPool.entries()) {
|
|
19791
|
+
const tokens = Array.from(tokensByPool.get(pool) ?? []);
|
|
19792
|
+
priceFeeds.push(...priceFeedFactory.priceFeedsForTokens(tokens));
|
|
19598
19793
|
}
|
|
19599
|
-
return
|
|
19794
|
+
return this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(priceFeeds);
|
|
19600
19795
|
}
|
|
19601
19796
|
/**
|
|
19602
|
-
*
|
|
19603
|
-
* @param
|
|
19604
|
-
* @param amount
|
|
19605
|
-
* @param reserve
|
|
19797
|
+
* Returns account price updates in a non-encoded format
|
|
19798
|
+
* @param acc
|
|
19606
19799
|
* @returns
|
|
19607
19800
|
*/
|
|
19608
|
-
|
|
19609
|
-
|
|
19801
|
+
async getOnDemandPriceUpdates(acc) {
|
|
19802
|
+
const market = this.sdk.marketRegister.findByCreditManager(
|
|
19803
|
+
acc.creditManager
|
|
19804
|
+
);
|
|
19805
|
+
const update = await this.getUpdateForAccounts([acc]);
|
|
19806
|
+
return market.priceOracle.onDemandPriceUpdates(update);
|
|
19610
19807
|
}
|
|
19611
19808
|
/**
|
|
19612
|
-
*
|
|
19613
|
-
* @param
|
|
19614
|
-
* @
|
|
19615
|
-
* @param amount
|
|
19616
|
-
* @param reserve
|
|
19809
|
+
* Returns price updates in format that is accepted by various credit facade methods (multicall, close/liquidate, etc...)
|
|
19810
|
+
* @param acc
|
|
19811
|
+
* @returns
|
|
19617
19812
|
*/
|
|
19618
|
-
|
|
19619
|
-
|
|
19620
|
-
|
|
19813
|
+
async getPriceUpdatesForFacade(acc) {
|
|
19814
|
+
const cm = this.sdk.marketRegister.findCreditManager(acc.creditManager);
|
|
19815
|
+
const updates = await this.getOnDemandPriceUpdates(acc);
|
|
19816
|
+
return updates.map(({ token, reserve, data }) => ({
|
|
19817
|
+
target: cm.creditFacade.address,
|
|
19818
|
+
callData: viem.encodeFunctionData({
|
|
19819
|
+
abi: iCreditFacadeV3MulticallAbi,
|
|
19820
|
+
functionName: "onDemandPriceUpdate",
|
|
19821
|
+
args: [token, reserve, data]
|
|
19822
|
+
})
|
|
19823
|
+
}));
|
|
19824
|
+
}
|
|
19825
|
+
async #prepareCloseCreditAccount(ca, cm, assetsToKeep, to, slippage = 50n) {
|
|
19826
|
+
const closePath = await this.sdk.router.findBestClosePath(
|
|
19827
|
+
ca,
|
|
19828
|
+
cm.creditManager,
|
|
19829
|
+
slippage
|
|
19830
|
+
);
|
|
19831
|
+
const priceUpdates = await this.getPriceUpdatesForFacade(ca);
|
|
19832
|
+
return [
|
|
19833
|
+
...priceUpdates,
|
|
19834
|
+
...closePath.calls,
|
|
19835
|
+
...this.#prepareDisableQuotas(ca),
|
|
19836
|
+
...this.#prepareDecreaseDebt(ca),
|
|
19837
|
+
...this.#prepareDisableTokens(ca),
|
|
19838
|
+
...assetsToKeep.map(
|
|
19839
|
+
(t) => this.#prepareWithdrawToken(ca, t, MAX_UINT256, to)
|
|
19840
|
+
)
|
|
19841
|
+
];
|
|
19842
|
+
}
|
|
19843
|
+
#prepareDisableQuotas(ca) {
|
|
19844
|
+
const calls = [];
|
|
19845
|
+
for (const { token, quota } of ca.tokens) {
|
|
19846
|
+
if (quota > 0n) {
|
|
19847
|
+
calls.push({
|
|
19848
|
+
target: ca.creditFacade,
|
|
19849
|
+
callData: viem.encodeFunctionData({
|
|
19850
|
+
abi: iCreditFacadeV3MulticallAbi,
|
|
19851
|
+
functionName: "updateQuota",
|
|
19852
|
+
args: [token, MIN_INT96, 0n]
|
|
19853
|
+
})
|
|
19854
|
+
});
|
|
19855
|
+
}
|
|
19621
19856
|
}
|
|
19622
|
-
|
|
19623
|
-
const fromScale = 10n ** BigInt(this.sdk.marketRegister.tokensMeta.mustGet(from).decimals);
|
|
19624
|
-
const toPrice = reserve ? this.reservePrices.mustGet(to) : this.mainPrices.mustGet(to);
|
|
19625
|
-
const toScale = 10n ** BigInt(this.sdk.marketRegister.tokensMeta.mustGet(to).decimals);
|
|
19626
|
-
return amount * fromPrice * toScale / (toPrice * fromScale);
|
|
19857
|
+
return calls;
|
|
19627
19858
|
}
|
|
19628
|
-
|
|
19629
|
-
|
|
19630
|
-
|
|
19631
|
-
|
|
19632
|
-
|
|
19633
|
-
|
|
19634
|
-
|
|
19635
|
-
|
|
19636
|
-
|
|
19637
|
-
|
|
19638
|
-
|
|
19639
|
-
|
|
19640
|
-
|
|
19641
|
-
|
|
19642
|
-
|
|
19643
|
-
|
|
19644
|
-
|
|
19645
|
-
|
|
19646
|
-
|
|
19647
|
-
|
|
19648
|
-
|
|
19649
|
-
|
|
19650
|
-
|
|
19651
|
-
|
|
19652
|
-
|
|
19653
|
-
|
|
19654
|
-
|
|
19655
|
-
// const { result } = await this.v3.publicClient.simulateContract({
|
|
19656
|
-
// address: MULTICALL_ADDRESS,
|
|
19657
|
-
// abi: multicall3Abi,
|
|
19658
|
-
// functionName: "aggregate3",
|
|
19659
|
-
// args: [
|
|
19660
|
-
// [
|
|
19661
|
-
// ...priceUpdateCalls,
|
|
19662
|
-
// ...getPricesRawCalls(false),
|
|
19663
|
-
// ...getPricesRawCalls(true),
|
|
19664
|
-
// ],
|
|
19665
|
-
// ],
|
|
19666
|
-
// chain: this.v3.publicClient.chain!,
|
|
19667
|
-
// account: this.v3.walletClient.account!,
|
|
19668
|
-
// gas: 550_000_000n,
|
|
19669
|
-
// // blockNumber: BigInt(block),
|
|
19670
|
-
// });
|
|
19671
|
-
// const returnRawPrices = (
|
|
19672
|
-
// result as Array<{ success: boolean; returnData: Hex }>
|
|
19673
|
-
// ).slice(priceUpdateCalls.length);
|
|
19674
|
-
// const prices = returnRawPrices.map(callReturn =>
|
|
19675
|
-
// callReturn.success
|
|
19676
|
-
// ? decodeFunctionResult({
|
|
19677
|
-
// functionName: "getPrice",
|
|
19678
|
-
// abi: this.abi,
|
|
19679
|
-
// data: callReturn.returnData! as Hex,
|
|
19680
|
-
// })
|
|
19681
|
-
// : 0n,
|
|
19682
|
-
// ) as Array<bigint>;
|
|
19683
|
-
// const mainPrices: Record<Address, bigint> = {};
|
|
19684
|
-
// const reservePrices: Record<Address, bigint> = {};
|
|
19685
|
-
// const mainPFlength = Object.keys(this.mainPriceFeeds).length;
|
|
19686
|
-
// prices.forEach((price, i) => {
|
|
19687
|
-
// if (i < mainPFlength) {
|
|
19688
|
-
// mainPrices[Object.keys(this.mainPriceFeeds)[i] as Address] = price;
|
|
19689
|
-
// } else {
|
|
19690
|
-
// reservePrices[
|
|
19691
|
-
// Object.keys(this.reservePriceFeeds)[i - mainPFlength] as Address
|
|
19692
|
-
// ] = price;
|
|
19693
|
-
// }
|
|
19694
|
-
// });
|
|
19695
|
-
// return { mainPrices, reservePrices };
|
|
19696
|
-
// }
|
|
19697
|
-
#labelPriceFeed(address, usage, token) {
|
|
19698
|
-
this.sdk.provider.addressLabels.set(address, (label) => {
|
|
19699
|
-
const { symbol } = this.sdk.marketRegister.tokensMeta.mustGet(token);
|
|
19700
|
-
let pricefeedTag = `${symbol}.${usage}`;
|
|
19701
|
-
if (label) {
|
|
19702
|
-
pricefeedTag = `${label}, ${pricefeedTag}`;
|
|
19859
|
+
#prepareDecreaseDebt(ca) {
|
|
19860
|
+
if (ca.totalDebtUSD > 0n) {
|
|
19861
|
+
return [
|
|
19862
|
+
{
|
|
19863
|
+
target: ca.creditFacade,
|
|
19864
|
+
callData: viem.encodeFunctionData({
|
|
19865
|
+
abi: iCreditFacadeV3MulticallAbi,
|
|
19866
|
+
functionName: "decreaseDebt",
|
|
19867
|
+
args: [MAX_UINT256]
|
|
19868
|
+
})
|
|
19869
|
+
}
|
|
19870
|
+
];
|
|
19871
|
+
}
|
|
19872
|
+
return [];
|
|
19873
|
+
}
|
|
19874
|
+
#prepareDisableTokens(ca) {
|
|
19875
|
+
const calls = [];
|
|
19876
|
+
for (const t of ca.tokens) {
|
|
19877
|
+
if (t.token !== ca.underlying && (t.mask & ca.enabledTokensMask) !== 0n && t.quota === 0n) {
|
|
19878
|
+
calls.push({
|
|
19879
|
+
target: ca.creditFacade,
|
|
19880
|
+
callData: viem.encodeFunctionData({
|
|
19881
|
+
abi: iCreditFacadeV3MulticallAbi,
|
|
19882
|
+
functionName: "disableToken",
|
|
19883
|
+
args: [t.token]
|
|
19884
|
+
})
|
|
19885
|
+
});
|
|
19703
19886
|
}
|
|
19704
|
-
|
|
19705
|
-
|
|
19887
|
+
}
|
|
19888
|
+
return calls;
|
|
19889
|
+
}
|
|
19890
|
+
#prepareWithdrawToken(ca, token, amount, to) {
|
|
19891
|
+
return {
|
|
19892
|
+
target: ca.creditFacade,
|
|
19893
|
+
callData: viem.encodeFunctionData({
|
|
19894
|
+
abi: iCreditFacadeV3MulticallAbi,
|
|
19895
|
+
functionName: "withdrawCollateral",
|
|
19896
|
+
args: [token, amount, to]
|
|
19897
|
+
})
|
|
19898
|
+
};
|
|
19706
19899
|
}
|
|
19707
19900
|
/**
|
|
19708
|
-
*
|
|
19709
|
-
*
|
|
19710
|
-
* @param priceFeed
|
|
19711
|
-
* @returns
|
|
19901
|
+
* Returns addresses of pools of attached markets
|
|
19712
19902
|
*/
|
|
19713
|
-
|
|
19714
|
-
|
|
19715
|
-
|
|
19716
|
-
|
|
19903
|
+
get pools() {
|
|
19904
|
+
return this.sdk.marketRegister.poolState.map((p) => p.pool.address);
|
|
19905
|
+
}
|
|
19906
|
+
};
|
|
19907
|
+
var AddressProviderContractV3_1 = class extends BaseContract {
|
|
19908
|
+
#addresses = {};
|
|
19909
|
+
versions = {};
|
|
19910
|
+
latest = {};
|
|
19911
|
+
constructor(sdk, address) {
|
|
19912
|
+
super(sdk, {
|
|
19913
|
+
addr: address,
|
|
19914
|
+
name: "AddressProviderV3",
|
|
19915
|
+
abi: iAddressProviderV3_1Abi
|
|
19916
|
+
});
|
|
19917
|
+
}
|
|
19918
|
+
parseFunctionParams(params) {
|
|
19919
|
+
switch (params.functionName) {
|
|
19920
|
+
case "setAddress": {
|
|
19921
|
+
if (params.args.length !== 3) {
|
|
19922
|
+
const [key2, saveVersion2] = params.args;
|
|
19923
|
+
return [key2, `${saveVersion2}`];
|
|
19924
|
+
}
|
|
19925
|
+
const [key, value, saveVersion] = params.args;
|
|
19926
|
+
return [viem.bytesToString(viem.toBytes(key)), value, `${saveVersion}`];
|
|
19717
19927
|
}
|
|
19928
|
+
default:
|
|
19929
|
+
return void 0;
|
|
19718
19930
|
}
|
|
19719
|
-
|
|
19720
|
-
|
|
19721
|
-
|
|
19722
|
-
}
|
|
19931
|
+
}
|
|
19932
|
+
setInternalAddress(key, address, version) {
|
|
19933
|
+
if (!this.#addresses[key]) {
|
|
19934
|
+
this.#addresses[key] = {};
|
|
19935
|
+
}
|
|
19936
|
+
this.#addresses[key][version] = address;
|
|
19937
|
+
if (!this.latest[key] || version > this.latest[key]) {
|
|
19938
|
+
this.latest[key] = version;
|
|
19723
19939
|
}
|
|
19724
|
-
|
|
19725
|
-
|
|
19726
|
-
|
|
19727
|
-
|
|
19728
|
-
priceOracleV3: this.contractData,
|
|
19729
|
-
mainPriceFeeds: Object.fromEntries(
|
|
19730
|
-
Object.entries(this.mainPriceFeeds).map(([token, v]) => [
|
|
19731
|
-
token,
|
|
19732
|
-
v.state
|
|
19733
|
-
])
|
|
19734
|
-
),
|
|
19735
|
-
reservePriceFeeds: Object.fromEntries(
|
|
19736
|
-
Object.entries(this.reservePriceFeeds).map(([token, v]) => [
|
|
19737
|
-
token,
|
|
19738
|
-
v.state
|
|
19739
|
-
])
|
|
19740
|
-
)
|
|
19741
|
-
};
|
|
19940
|
+
if (!this.versions[key]) {
|
|
19941
|
+
this.versions[key] = /* @__PURE__ */ new Set();
|
|
19942
|
+
}
|
|
19943
|
+
this.versions[key].add(version);
|
|
19742
19944
|
}
|
|
19743
|
-
|
|
19744
|
-
|
|
19745
|
-
|
|
19746
|
-
var MarketFactory = class {
|
|
19747
|
-
riskCurator;
|
|
19748
|
-
poolFactory;
|
|
19749
|
-
priceOracle;
|
|
19750
|
-
creditManagers = [];
|
|
19751
|
-
constructor(sdk, marketData) {
|
|
19752
|
-
this.riskCurator = marketData.owner;
|
|
19753
|
-
for (const t of marketData.tokens) {
|
|
19754
|
-
sdk.marketRegister.tokensMeta.upsert(t.addr, t);
|
|
19755
|
-
sdk.provider.addressLabels.set(t.addr, t.symbol);
|
|
19945
|
+
getAddress(contract, version = NO_VERSION) {
|
|
19946
|
+
if (!this.#addresses[contract]) {
|
|
19947
|
+
throw new Error(`Address ${contract}, version: ${version} not found`);
|
|
19756
19948
|
}
|
|
19757
|
-
|
|
19758
|
-
|
|
19759
|
-
|
|
19949
|
+
const result = this.#addresses[contract][version];
|
|
19950
|
+
if (!result) {
|
|
19951
|
+
throw new Error(`Address ${contract}, version: ${version} not found`);
|
|
19760
19952
|
}
|
|
19761
|
-
|
|
19762
|
-
|
|
19763
|
-
|
|
19764
|
-
|
|
19953
|
+
return result;
|
|
19954
|
+
}
|
|
19955
|
+
getLatestVersion(contract) {
|
|
19956
|
+
if (!this.latest[contract]) {
|
|
19957
|
+
throw new Error(`Latest version for ${contract} not found`);
|
|
19958
|
+
}
|
|
19959
|
+
this.logger?.debug(
|
|
19960
|
+
`Latest version found for ${contract} : ${this.latest[contract]}`
|
|
19765
19961
|
);
|
|
19962
|
+
return this.getAddress(contract, this.latest[contract]);
|
|
19963
|
+
}
|
|
19964
|
+
async fetchState(toBlock) {
|
|
19965
|
+
const entries = await this.contract.read.getAllSavedContracts({
|
|
19966
|
+
blockNumber: toBlock
|
|
19967
|
+
});
|
|
19968
|
+
entries.forEach((log) => {
|
|
19969
|
+
this.setInternalAddress(log.key, log.value, Number(log.version));
|
|
19970
|
+
});
|
|
19971
|
+
this.version = 310;
|
|
19766
19972
|
}
|
|
19767
19973
|
get state() {
|
|
19768
19974
|
return {
|
|
19769
|
-
|
|
19770
|
-
|
|
19771
|
-
priceOracle: this.priceOracle.state
|
|
19975
|
+
...this.contractData,
|
|
19976
|
+
addresses: this.#addresses
|
|
19772
19977
|
};
|
|
19773
19978
|
}
|
|
19979
|
+
parseLog(log) {
|
|
19980
|
+
const parsedLog = viem.parseEventLogs({
|
|
19981
|
+
abi: this.abi,
|
|
19982
|
+
logs: [log]
|
|
19983
|
+
})[0];
|
|
19984
|
+
switch (parsedLog.eventName) {
|
|
19985
|
+
case "SetAddress": {
|
|
19986
|
+
const parsedLog2 = viem.parseEventLogs({
|
|
19987
|
+
abi: this.abi,
|
|
19988
|
+
eventName: "SetAddress",
|
|
19989
|
+
logs: [log]
|
|
19990
|
+
})[0];
|
|
19991
|
+
const key = parsedLog2.args.key;
|
|
19992
|
+
this.setInternalAddress(
|
|
19993
|
+
key,
|
|
19994
|
+
parsedLog.args.value,
|
|
19995
|
+
Number(parsedLog2.args.version)
|
|
19996
|
+
);
|
|
19997
|
+
break;
|
|
19998
|
+
}
|
|
19999
|
+
default:
|
|
20000
|
+
this.logger?.warn(`Unknown event: ${parsedLog.eventName}`);
|
|
20001
|
+
break;
|
|
20002
|
+
}
|
|
20003
|
+
}
|
|
19774
20004
|
};
|
|
19775
|
-
|
|
19776
|
-
|
|
19777
|
-
|
|
19778
|
-
|
|
19779
|
-
/**
|
|
19780
|
-
* Mapping pool.name -> MarketFactory
|
|
19781
|
-
*/
|
|
19782
|
-
#markets = {};
|
|
19783
|
-
/**
|
|
19784
|
-
* Token metadata such as symbol and decimals, common across all markets
|
|
19785
|
-
*/
|
|
19786
|
-
tokensMeta = new AddressMap();
|
|
19787
|
-
#sdk;
|
|
19788
|
-
constructor(sdk) {
|
|
19789
|
-
this.#sdk = sdk;
|
|
19790
|
-
this.#logger = childLogger("MarketRegister", sdk.logger);
|
|
20005
|
+
var BotListContract = class extends BaseContract {
|
|
20006
|
+
approvedCreditManagers = /* @__PURE__ */ new Set();
|
|
20007
|
+
constructor(sdk, address) {
|
|
20008
|
+
super(sdk, { addr: address, name: "BotListV3", abi: botListV3Abi });
|
|
19791
20009
|
}
|
|
19792
|
-
|
|
19793
|
-
|
|
19794
|
-
|
|
19795
|
-
|
|
19796
|
-
|
|
19797
|
-
|
|
19798
|
-
|
|
19799
|
-
|
|
19800
|
-
|
|
19801
|
-
|
|
19802
|
-
|
|
19803
|
-
|
|
19804
|
-
|
|
19805
|
-
|
|
19806
|
-
|
|
19807
|
-
|
|
19808
|
-
],
|
|
19809
|
-
// It's passed as ...rest in viem readContract action, but this might change
|
|
19810
|
-
// @ts-ignore
|
|
19811
|
-
gas: 500000000n
|
|
19812
|
-
});
|
|
19813
|
-
for (const data of markets) {
|
|
19814
|
-
this.#markets[data.pool.name] = new MarketFactory(this.#sdk, data);
|
|
20010
|
+
parseFunctionParams(params) {
|
|
20011
|
+
switch (params.functionName) {
|
|
20012
|
+
case "setCreditManagerApprovedStatus": {
|
|
20013
|
+
const [creditManager, status] = params.args;
|
|
20014
|
+
return [this.addressLabels.get(creditManager), `${status}`];
|
|
20015
|
+
}
|
|
20016
|
+
case "setBotSpecialPermissions": {
|
|
20017
|
+
const [bot, creditManager, permissions] = params.args;
|
|
20018
|
+
return [
|
|
20019
|
+
this.addressLabels.get(bot),
|
|
20020
|
+
this.addressLabels.get(creditManager),
|
|
20021
|
+
botPermissionsToString(permissions)
|
|
20022
|
+
];
|
|
20023
|
+
}
|
|
20024
|
+
default:
|
|
20025
|
+
return void 0;
|
|
19815
20026
|
}
|
|
19816
|
-
this.#logger?.info(`loaded ${markets.length} markets`);
|
|
19817
20027
|
}
|
|
19818
|
-
|
|
19819
|
-
|
|
19820
|
-
|
|
19821
|
-
|
|
19822
|
-
|
|
20028
|
+
async fetchState(toBlock) {
|
|
20029
|
+
const logs = await this.provider.publicClient.getContractEvents({
|
|
20030
|
+
address: this.address,
|
|
20031
|
+
abi: this.abi,
|
|
20032
|
+
fromBlock: 0n,
|
|
20033
|
+
toBlock
|
|
20034
|
+
});
|
|
20035
|
+
logs.forEach((e) => this.parseLog(e));
|
|
19823
20036
|
}
|
|
19824
|
-
|
|
19825
|
-
|
|
19826
|
-
|
|
19827
|
-
|
|
20037
|
+
parseLog(log) {
|
|
20038
|
+
const parsedLog = viem.parseEventLogs({
|
|
20039
|
+
abi: this.abi,
|
|
20040
|
+
logs: [log]
|
|
20041
|
+
})[0];
|
|
20042
|
+
switch (parsedLog.eventName) {
|
|
20043
|
+
case "SetCreditManagerApprovedStatus":
|
|
20044
|
+
if (parsedLog.args.approved) {
|
|
20045
|
+
this.approvedCreditManagers.add(parsedLog.args.creditManager);
|
|
20046
|
+
} else {
|
|
20047
|
+
this.approvedCreditManagers.delete(parsedLog.args.creditManager);
|
|
20048
|
+
}
|
|
20049
|
+
break;
|
|
20050
|
+
case "SetBotSpecialPermissions":
|
|
20051
|
+
this.logger?.debug(
|
|
20052
|
+
`Bot ${parsedLog.args.bot} has been given permissions ${botPermissionsToString(
|
|
20053
|
+
parsedLog.args.permissions
|
|
20054
|
+
)} for credit manager ${parsedLog.args.creditManager}`
|
|
20055
|
+
);
|
|
20056
|
+
break;
|
|
20057
|
+
default:
|
|
20058
|
+
this.logger?.warn(`Unknown event: ${parsedLog.eventName}`);
|
|
20059
|
+
break;
|
|
20060
|
+
}
|
|
19828
20061
|
}
|
|
19829
|
-
|
|
19830
|
-
return
|
|
20062
|
+
get state() {
|
|
20063
|
+
return {
|
|
20064
|
+
...this.contractData
|
|
20065
|
+
};
|
|
19831
20066
|
}
|
|
19832
|
-
|
|
19833
|
-
|
|
20067
|
+
};
|
|
20068
|
+
|
|
20069
|
+
// src/sdk/core/GearStakingV3Contract.ts
|
|
20070
|
+
var GearStakingContract = class extends BaseContract {
|
|
20071
|
+
constructor(sdk, address) {
|
|
20072
|
+
super(sdk, { addr: address, name: "GearStakingV3", abi: gearStakingV3Abi });
|
|
19834
20073
|
}
|
|
19835
|
-
|
|
19836
|
-
|
|
19837
|
-
|
|
19838
|
-
|
|
19839
|
-
|
|
19840
|
-
}
|
|
20074
|
+
parseFunctionParams(params) {
|
|
20075
|
+
switch (params.functionName) {
|
|
20076
|
+
case "setVotingContractStatus": {
|
|
20077
|
+
const [address, status] = params.args;
|
|
20078
|
+
return [this.addressLabels.get(address), VotingContractStatus[status]];
|
|
19841
20079
|
}
|
|
20080
|
+
default:
|
|
20081
|
+
return void 0;
|
|
19842
20082
|
}
|
|
19843
|
-
throw new Error(`cannot find credit manager ${creditManager}`);
|
|
19844
|
-
}
|
|
19845
|
-
findByCreditManager(creditManager) {
|
|
19846
|
-
const market = Object.values(this.#markets).find(
|
|
19847
|
-
(m) => m.creditManagers.some(
|
|
19848
|
-
(cm) => cm.creditManager.address.toLowerCase() === creditManager.toLowerCase()
|
|
19849
|
-
)
|
|
19850
|
-
);
|
|
19851
|
-
if (!market) {
|
|
19852
|
-
throw new Error(`cannot find market for credit manager ${creditManager}`);
|
|
19853
|
-
}
|
|
19854
|
-
return market;
|
|
19855
20083
|
}
|
|
19856
|
-
get
|
|
19857
|
-
return
|
|
19858
|
-
|
|
19859
|
-
|
|
19860
|
-
|
|
19861
|
-
|
|
19862
|
-
return tvls.reduce(
|
|
19863
|
-
(acc, curr) => {
|
|
19864
|
-
acc.tvl += curr.tvl;
|
|
19865
|
-
acc.tvlUSD += curr.tvlUSD;
|
|
19866
|
-
return acc;
|
|
19867
|
-
},
|
|
19868
|
-
{ tvl: 0n, tvlUSD: 0n }
|
|
19869
|
-
);
|
|
20084
|
+
get state() {
|
|
20085
|
+
return {
|
|
20086
|
+
...this.contractData,
|
|
20087
|
+
successor: ADDRESS_0X0,
|
|
20088
|
+
migrator: ADDRESS_0X0
|
|
20089
|
+
};
|
|
19870
20090
|
}
|
|
19871
20091
|
};
|
|
19872
20092
|
var PathOptionFactory = class _PathOptionFactory {
|
|
@@ -20809,6 +21029,7 @@ exports.AP_INSOLVENCY_CHECKER = AP_INSOLVENCY_CHECKER;
|
|
|
20809
21029
|
exports.AP_MARKET_COMPRESSOR = AP_MARKET_COMPRESSOR;
|
|
20810
21030
|
exports.AP_MULTI_PAUSE = AP_MULTI_PAUSE;
|
|
20811
21031
|
exports.AP_PARTIAL_LIQUIDATION_BOT = AP_PARTIAL_LIQUIDATION_BOT;
|
|
21032
|
+
exports.AP_PRICE_FEED_COMPRESSOR = AP_PRICE_FEED_COMPRESSOR;
|
|
20812
21033
|
exports.AP_PRICE_ORACLE = AP_PRICE_ORACLE;
|
|
20813
21034
|
exports.AP_ROUTER = AP_ROUTER;
|
|
20814
21035
|
exports.AP_TREASURY = AP_TREASURY;
|
|
@@ -20908,5 +21129,6 @@ exports.json_parse = json_parse;
|
|
|
20908
21129
|
exports.json_stringify = json_stringify;
|
|
20909
21130
|
exports.numberWithCommas = numberWithCommas;
|
|
20910
21131
|
exports.percentFmt = percentFmt;
|
|
21132
|
+
exports.rawTxToMulticallPriceUpdate = rawTxToMulticallPriceUpdate;
|
|
20911
21133
|
exports.simulateMulticall = simulateMulticall;
|
|
20912
21134
|
exports.toHumanFormat = toHumanFormat;
|