@1delta/margin-fetcher 5.0.46 → 5.0.47
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/index.d.ts +22 -3
- package/dist/index.js +322 -78
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -273,7 +273,19 @@ interface MulticallRetryParams {
|
|
|
273
273
|
logErrors?: boolean;
|
|
274
274
|
}
|
|
275
275
|
type MulticallRetryFunction = (params: MulticallRetryParams) => Promise<any[]>;
|
|
276
|
-
|
|
276
|
+
/**
|
|
277
|
+
* Options a caller may ask the client factory for.
|
|
278
|
+
*
|
|
279
|
+
* `timeoutMs` is optional in both directions: a factory that ignores it still
|
|
280
|
+
* satisfies this type (TypeScript accepts a 2-arg function here), and every
|
|
281
|
+
* existing implementation does exactly that. Only the sharded multicall passes
|
|
282
|
+
* it, and only because viem's 10s default turns one stalled request into a 10s
|
|
283
|
+
* response for the whole batch.
|
|
284
|
+
*/
|
|
285
|
+
interface GetEvmClientOptions {
|
|
286
|
+
timeoutMs?: number;
|
|
287
|
+
}
|
|
288
|
+
type GetEvmClientFunction = (chain: string, rpcId?: number, options?: GetEvmClientOptions) => PublicClient;
|
|
277
289
|
|
|
278
290
|
type SerializedBigNumber = string;
|
|
279
291
|
interface LenderUserQuery {
|
|
@@ -5623,8 +5635,15 @@ interface FlashLoanLiquidityForAsset {
|
|
|
5623
5635
|
source: string;
|
|
5624
5636
|
fee: string;
|
|
5625
5637
|
availableRaw: string;
|
|
5626
|
-
|
|
5627
|
-
|
|
5638
|
+
/**
|
|
5639
|
+
* `availableRaw` scaled by `decimals`. ABSENT when the asset's decimals
|
|
5640
|
+
* could not be resolved — neither from the token list nor from an on-chain
|
|
5641
|
+
* `decimals()` — because a guessed scale silently misreports liquidity by
|
|
5642
|
+
* orders of magnitude. `availableRaw` is always exact; prefer it.
|
|
5643
|
+
*/
|
|
5644
|
+
available?: number;
|
|
5645
|
+
/** ABSENT when unresolvable — see `available`. */
|
|
5646
|
+
decimals?: number;
|
|
5628
5647
|
}
|
|
5629
5648
|
type FlashLiquiditiesOnChain = {
|
|
5630
5649
|
[asset: string]: FlashLoanLiquidityForAsset[];
|
package/dist/index.js
CHANGED
|
@@ -14976,8 +14976,46 @@ var ComptrollerAbi = [
|
|
|
14976
14976
|
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
14977
14977
|
stateMutability: "view",
|
|
14978
14978
|
type: "function"
|
|
14979
|
+
},
|
|
14980
|
+
// Per-market pause guardians. Classic Compound V2 keeps them as public
|
|
14981
|
+
// mappings on the Comptroller — the cToken lenses do NOT expose them, so a
|
|
14982
|
+
// fork on the standard lens path can only learn its pause state from here.
|
|
14983
|
+
// `mintAllowed` / `borrowAllowed` hard-revert ("mint is paused" /
|
|
14984
|
+
// "borrow is paused") when set, which is why they gate `depositsEnabled` /
|
|
14985
|
+
// `borrowingEnabled` rather than merely capping an amount.
|
|
14986
|
+
{
|
|
14987
|
+
inputs: [{ internalType: "address", name: "", type: "address" }],
|
|
14988
|
+
name: "mintGuardianPaused",
|
|
14989
|
+
outputs: [{ internalType: "bool", name: "", type: "bool" }],
|
|
14990
|
+
stateMutability: "view",
|
|
14991
|
+
type: "function"
|
|
14992
|
+
},
|
|
14993
|
+
{
|
|
14994
|
+
inputs: [{ internalType: "address", name: "", type: "address" }],
|
|
14995
|
+
name: "borrowGuardianPaused",
|
|
14996
|
+
outputs: [{ internalType: "bool", name: "", type: "bool" }],
|
|
14997
|
+
stateMutability: "view",
|
|
14998
|
+
type: "function"
|
|
14979
14999
|
}
|
|
14980
15000
|
];
|
|
15001
|
+
var COMPTROLLER_PAUSE_READ_LENDERS = [
|
|
15002
|
+
Lender.COMPOUND_V2,
|
|
15003
|
+
Lender.CREAM_FINANCE,
|
|
15004
|
+
Lender.FLUX_FINANCE,
|
|
15005
|
+
Lender.WE_PIGGY,
|
|
15006
|
+
Lender.GAMMA,
|
|
15007
|
+
Lender.CAPY_FI,
|
|
15008
|
+
Lender.LODESTAR,
|
|
15009
|
+
Lender.TENDER
|
|
15010
|
+
];
|
|
15011
|
+
var usesComptrollerPauseReads = (lender) => COMPTROLLER_PAUSE_READ_LENDERS.includes(lender);
|
|
15012
|
+
var parsePausedFlag = (raw) => typeof raw === "boolean" ? raw : void 0;
|
|
15013
|
+
var resolveMarketPause = (token, live) => {
|
|
15014
|
+
const mintPaused = live?.mintPaused ?? token?.mintPaused;
|
|
15015
|
+
const borrowPaused = live?.borrowPaused ?? token?.borrowPaused;
|
|
15016
|
+
if (mintPaused === void 0 && borrowPaused === void 0) return void 0;
|
|
15017
|
+
return { mintPaused, borrowPaused };
|
|
15018
|
+
};
|
|
14981
15019
|
|
|
14982
15020
|
// src/lending/public-data/compound-v2/publicCallBuild.ts
|
|
14983
15021
|
var buildCompoundV2StyleLenderReserveCall = (chainId, lender) => {
|
|
@@ -15058,6 +15096,18 @@ var buildCompoundV2StyleLenderReserveCall = (chainId, lender) => {
|
|
|
15058
15096
|
name: "liquidationIncentiveMantissa",
|
|
15059
15097
|
params: []
|
|
15060
15098
|
});
|
|
15099
|
+
if (usesComptrollerPauseReads(lender)) {
|
|
15100
|
+
for (const name of ["mintGuardianPaused", "borrowGuardianPaused"]) {
|
|
15101
|
+
for (const tk of tokens) {
|
|
15102
|
+
calls.push({
|
|
15103
|
+
abi: ComptrollerAbi,
|
|
15104
|
+
address: stdComptroller,
|
|
15105
|
+
name,
|
|
15106
|
+
params: [tk.cToken]
|
|
15107
|
+
});
|
|
15108
|
+
}
|
|
15109
|
+
}
|
|
15110
|
+
}
|
|
15061
15111
|
}
|
|
15062
15112
|
return calls;
|
|
15063
15113
|
};
|
|
@@ -15513,7 +15563,10 @@ function convertSingleEntry(opts) {
|
|
|
15513
15563
|
if (perMarketIncentive !== void 0 && Number(perMarketIncentive) > 0) {
|
|
15514
15564
|
liquidationPenalty = Math.max(
|
|
15515
15565
|
Number(
|
|
15516
|
-
parseRawAmount(
|
|
15566
|
+
parseRawAmount(
|
|
15567
|
+
perMarketIncentive.toString(),
|
|
15568
|
+
RESERVE_MANTISSA_DECIMALS
|
|
15569
|
+
)
|
|
15517
15570
|
) - 1,
|
|
15518
15571
|
0
|
|
15519
15572
|
);
|
|
@@ -15534,7 +15587,11 @@ function convertSingleEntry(opts) {
|
|
|
15534
15587
|
);
|
|
15535
15588
|
const liquidity = totalSupplyUnderlying - totalDebt;
|
|
15536
15589
|
const price2 = prices[asset.assetGroup] ?? 0;
|
|
15537
|
-
const pausedActions = currentEntry.pausedActions;
|
|
15590
|
+
const pausedActions = { ...currentEntry.pausedActions };
|
|
15591
|
+
if (opts.pause?.mintPaused !== void 0)
|
|
15592
|
+
pausedActions[0 /* MINT */] = opts.pause.mintPaused;
|
|
15593
|
+
if (opts.pause?.borrowPaused !== void 0)
|
|
15594
|
+
pausedActions[2 /* BORROW */] = opts.pause.borrowPaused;
|
|
15538
15595
|
const allPaused = pausedActions[0 /* MINT */] && pausedActions[2 /* BORROW */] && pausedActions[1 /* REDEEM */] && pausedActions[3 /* REPAY */];
|
|
15539
15596
|
const poolId = asset.address;
|
|
15540
15597
|
const collateralActive = Boolean(currentEntry?.isListed);
|
|
@@ -16366,7 +16423,9 @@ var getCompoundV2DataConverter = (lender, chainId, prices, additionalYields, tok
|
|
|
16366
16423
|
const isSumer = isSumerType(lender);
|
|
16367
16424
|
const stdComptroller = isSumer ? void 0 : getCompoundV2Comptroller(chainId, lender);
|
|
16368
16425
|
const stdComptrollerCalls = stdComptroller ? 2 : 0;
|
|
16369
|
-
const
|
|
16426
|
+
const pauseReads = Boolean(stdComptroller) && usesComptrollerPauseReads(lender);
|
|
16427
|
+
const pauseCalls = pauseReads ? tokenCount * 2 : 0;
|
|
16428
|
+
const expectedNumberOfCalls = isSumer ? tokenCount + SUMER_GROUP_COUNT : tokenCount + stdComptrollerCalls + pauseCalls;
|
|
16370
16429
|
const reader = getReader(lender, chainId);
|
|
16371
16430
|
return [
|
|
16372
16431
|
(data) => {
|
|
@@ -16403,6 +16462,8 @@ var getCompoundV2DataConverter = (lender, chainId, prices, additionalYields, tok
|
|
|
16403
16462
|
globalCloseFactor = closeFactorMantissa;
|
|
16404
16463
|
globalLiquidationPenalty = incentiveMantissa !== void 0 ? Math.max(incentiveMantissa - 1, 0) : void 0;
|
|
16405
16464
|
}
|
|
16465
|
+
const mintPausedBase = tokenCount + stdComptrollerCalls;
|
|
16466
|
+
const borrowPausedBase = mintPausedBase + tokenCount;
|
|
16406
16467
|
for (let i = 0; i < tokenCount; i++) {
|
|
16407
16468
|
const { underlying, cToken } = compoundV2Tokens2[i];
|
|
16408
16469
|
if (!cToken || !underlying) continue;
|
|
@@ -16419,7 +16480,13 @@ var getCompoundV2DataConverter = (lender, chainId, prices, additionalYields, tok
|
|
|
16419
16480
|
additionalYields,
|
|
16420
16481
|
cToken,
|
|
16421
16482
|
closeFactor: globalCloseFactor,
|
|
16422
|
-
liquidationPenalty: globalLiquidationPenalty
|
|
16483
|
+
liquidationPenalty: globalLiquidationPenalty,
|
|
16484
|
+
// live guardian read first, then the static fallback published on
|
|
16485
|
+
// the token entry for forks that expose no getter at all
|
|
16486
|
+
pause: pauseReads ? resolveMarketPause(compoundV2Tokens2[i], {
|
|
16487
|
+
mintPaused: parsePausedFlag(data[mintPausedBase + i]),
|
|
16488
|
+
borrowPaused: parsePausedFlag(data[borrowPausedBase + i])
|
|
16489
|
+
}) : void 0
|
|
16423
16490
|
});
|
|
16424
16491
|
out.data[entry.marketUid] = entry;
|
|
16425
16492
|
}
|
|
@@ -27655,7 +27722,31 @@ var maxRetries = 3;
|
|
|
27655
27722
|
var MULTICALL_FAILURE = "0x";
|
|
27656
27723
|
var isFailedCall = (value) => value === void 0 || value === null || value === MULTICALL_FAILURE;
|
|
27657
27724
|
var MULTICALL_REPAIR_ROUNDS = 3;
|
|
27658
|
-
var MAX_CALLS_PER_SHARD =
|
|
27725
|
+
var MAX_CALLS_PER_SHARD = 300;
|
|
27726
|
+
var ONE_REQUEST_BATCH_BYTES = 1e6;
|
|
27727
|
+
var MAX_INFLIGHT_REQUESTS = 6;
|
|
27728
|
+
var HEDGE_DELAY_MS = 1200;
|
|
27729
|
+
var SHARD_TIMEOUT_MS = 4e3;
|
|
27730
|
+
var MIN_ADAPTIVE_SHARD = 25;
|
|
27731
|
+
var ADAPTIVE_CAP_TTL_MS = 6e4;
|
|
27732
|
+
var endpointCallCap = /* @__PURE__ */ new Map();
|
|
27733
|
+
var capFor = (url, requested) => {
|
|
27734
|
+
const hit = endpointCallCap.get(url);
|
|
27735
|
+
if (!hit) return requested;
|
|
27736
|
+
if (Date.now() - hit.at > ADAPTIVE_CAP_TTL_MS) {
|
|
27737
|
+
endpointCallCap.delete(url);
|
|
27738
|
+
return requested;
|
|
27739
|
+
}
|
|
27740
|
+
return Math.min(requested, hit.calls);
|
|
27741
|
+
};
|
|
27742
|
+
var noteEndpointRefusal = (url, calls) => {
|
|
27743
|
+
if (calls <= MIN_ADAPTIVE_SHARD) return;
|
|
27744
|
+
const next = Math.max(MIN_ADAPTIVE_SHARD, Math.floor(calls / 2));
|
|
27745
|
+
const current = endpointCallCap.get(url);
|
|
27746
|
+
if (current && Date.now() - current.at <= ADAPTIVE_CAP_TTL_MS && current.calls <= next)
|
|
27747
|
+
return;
|
|
27748
|
+
endpointCallCap.set(url, { calls: next, at: Date.now() });
|
|
27749
|
+
};
|
|
27659
27750
|
var DETERMINISTIC_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
27660
27751
|
"ContractFunctionRevertedError",
|
|
27661
27752
|
"RawContractError",
|
|
@@ -27679,13 +27770,13 @@ var REPAIR_BACKOFF_JITTER_MS = 60;
|
|
|
27679
27770
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
27680
27771
|
var backoffForRound = (round) => REPAIR_BACKOFF_BASE_MS * 2 ** round + Math.random() * REPAIR_BACKOFF_JITTER_MS;
|
|
27681
27772
|
var endpointUrl = (client, rpcId) => client?.transport?.url ?? `rpc#${rpcId}`;
|
|
27682
|
-
var resolveEndpoint = (chainId, getEvmClient17, startRpcId, tried, maxProbe = 12) => {
|
|
27773
|
+
var resolveEndpoint = (chainId, getEvmClient17, startRpcId, tried, maxProbe = 12, timeoutMs) => {
|
|
27683
27774
|
let fallback = null;
|
|
27684
27775
|
for (let probe = 0; probe < maxProbe; probe++) {
|
|
27685
27776
|
const rpcId = startRpcId + probe;
|
|
27686
27777
|
let client;
|
|
27687
27778
|
try {
|
|
27688
|
-
client = getEvmClient17(chainId, rpcId);
|
|
27779
|
+
client = getEvmClient17(chainId, rpcId, { timeoutMs });
|
|
27689
27780
|
} catch {
|
|
27690
27781
|
break;
|
|
27691
27782
|
}
|
|
@@ -27894,39 +27985,30 @@ var multicallShardedAbiArray = async (chainId, abi, calls, getEvmClient17, poolS
|
|
|
27894
27985
|
functionName: name,
|
|
27895
27986
|
args: params
|
|
27896
27987
|
}));
|
|
27988
|
+
const requestBytes = batchSize < MULTICALL_DEFAULT_BATCH_SIZE ? batchSize : ONE_REQUEST_BATCH_BYTES;
|
|
27989
|
+
const workerBudget = Math.max(1, Math.floor(MAX_INFLIGHT_REQUESTS / 2));
|
|
27990
|
+
const workers = Math.max(1, Math.min(poolSize, workerBudget));
|
|
27897
27991
|
const shardSize = Math.max(
|
|
27898
27992
|
1,
|
|
27899
|
-
Math.min(MAX_CALLS_PER_SHARD, Math.ceil(contracts.length /
|
|
27993
|
+
Math.min(MAX_CALLS_PER_SHARD, Math.ceil(contracts.length / workers))
|
|
27900
27994
|
);
|
|
27901
27995
|
const batches = [];
|
|
27902
27996
|
for (let i = 0; i < contracts.length; i += shardSize) {
|
|
27903
27997
|
batches.push({ start: i, items: contracts.slice(i, i + shardSize) });
|
|
27904
27998
|
}
|
|
27905
27999
|
const results = new Array(contracts.length);
|
|
27906
|
-
const
|
|
27907
|
-
const endpoint = resolveEndpoint(chainId, getEvmClient17, rpcId, tried);
|
|
27908
|
-
if (!endpoint) {
|
|
27909
|
-
if (logs)
|
|
27910
|
-
console.log(
|
|
27911
|
-
`sharded multicall: no untried endpoint left for chain ${chainId}`
|
|
27912
|
-
);
|
|
27913
|
-
return;
|
|
27914
|
-
}
|
|
27915
|
-
const shardOptions = {
|
|
27916
|
-
tried,
|
|
27917
|
-
onEndpointFailure: options?.onEndpointFailure
|
|
27918
|
-
};
|
|
28000
|
+
const request = async (endpoint, items) => {
|
|
27919
28001
|
try {
|
|
27920
28002
|
const returnData = await endpoint.client.multicall({
|
|
27921
28003
|
allowFailure,
|
|
27922
|
-
batchSize:
|
|
27923
|
-
contracts:
|
|
28004
|
+
batchSize: requestBytes,
|
|
28005
|
+
contracts: items
|
|
27924
28006
|
});
|
|
27925
|
-
|
|
27926
|
-
if (allowFailure &&
|
|
28007
|
+
const slots = toSlots(returnData, allowFailure);
|
|
28008
|
+
if (allowFailure && slots.length > 0 && slots.every((s) => isFailedCall(s.value) && !s.permanent)) {
|
|
27927
28009
|
if (logs)
|
|
27928
28010
|
console.log(
|
|
27929
|
-
`sharded multicall
|
|
28011
|
+
`sharded multicall: rpc ${endpoint.rpcId} answered ${items.length} calls with nothing`
|
|
27930
28012
|
);
|
|
27931
28013
|
options?.onEndpointFailure?.({
|
|
27932
28014
|
chainId,
|
|
@@ -27934,61 +28016,165 @@ var multicallShardedAbiArray = async (chainId, abi, calls, getEvmClient17, poolS
|
|
|
27934
28016
|
rpcId: endpoint.rpcId,
|
|
27935
28017
|
kind: "slots"
|
|
27936
28018
|
});
|
|
27937
|
-
|
|
27938
|
-
return
|
|
27939
|
-
batch,
|
|
27940
|
-
endpoint.rpcId + 1,
|
|
27941
|
-
attemptsLeft - 1,
|
|
27942
|
-
size,
|
|
27943
|
-
tried
|
|
27944
|
-
);
|
|
27945
|
-
}
|
|
27946
|
-
if (allowFailure && retryFailed) {
|
|
27947
|
-
slots = await repairFailedSlots(
|
|
27948
|
-
chainId,
|
|
27949
|
-
batch.items,
|
|
27950
|
-
slots,
|
|
27951
|
-
getEvmClient17,
|
|
27952
|
-
endpoint.rpcId + 1,
|
|
27953
|
-
size,
|
|
27954
|
-
logs,
|
|
27955
|
-
MULTICALL_REPAIR_ROUNDS,
|
|
27956
|
-
shardOptions
|
|
27957
|
-
);
|
|
27958
|
-
}
|
|
27959
|
-
recordPermanentFailures(slots, batch.start, permanentFailures);
|
|
27960
|
-
for (let j = 0; j < slots.length; j++) {
|
|
27961
|
-
results[batch.start + j] = slots[j].value;
|
|
28019
|
+
noteEndpointRefusal(endpoint.url, items.length);
|
|
28020
|
+
return null;
|
|
27962
28021
|
}
|
|
28022
|
+
return slots;
|
|
27963
28023
|
} catch (error) {
|
|
27964
|
-
if (logs) console.log("error in sharded multicall
|
|
28024
|
+
if (logs) console.log("error in sharded multicall request", error);
|
|
27965
28025
|
options?.onEndpointFailure?.({
|
|
27966
28026
|
chainId,
|
|
27967
28027
|
url: endpoint.url,
|
|
27968
28028
|
rpcId: endpoint.rpcId,
|
|
27969
28029
|
kind: "transport"
|
|
27970
28030
|
});
|
|
27971
|
-
|
|
27972
|
-
|
|
27973
|
-
|
|
27974
|
-
|
|
27975
|
-
|
|
27976
|
-
|
|
27977
|
-
|
|
27978
|
-
|
|
28031
|
+
noteEndpointRefusal(endpoint.url, items.length);
|
|
28032
|
+
return null;
|
|
28033
|
+
}
|
|
28034
|
+
};
|
|
28035
|
+
const firstUsable = (attempts) => new Promise((resolve) => {
|
|
28036
|
+
let pending = attempts.length;
|
|
28037
|
+
let settled = false;
|
|
28038
|
+
const lose = () => {
|
|
28039
|
+
if (!settled && --pending === 0) resolve(null);
|
|
28040
|
+
};
|
|
28041
|
+
for (const attempt of attempts) {
|
|
28042
|
+
attempt.then((won) => {
|
|
28043
|
+
if (settled) return;
|
|
28044
|
+
if (won) {
|
|
28045
|
+
settled = true;
|
|
28046
|
+
resolve(won);
|
|
28047
|
+
} else lose();
|
|
28048
|
+
}, lose);
|
|
28049
|
+
}
|
|
28050
|
+
});
|
|
28051
|
+
const attemptHedged = async (items, startRpcId, tried) => {
|
|
28052
|
+
const primary = resolveEndpoint(
|
|
28053
|
+
chainId,
|
|
28054
|
+
getEvmClient17,
|
|
28055
|
+
startRpcId,
|
|
28056
|
+
tried,
|
|
28057
|
+
12,
|
|
28058
|
+
SHARD_TIMEOUT_MS
|
|
28059
|
+
);
|
|
28060
|
+
if (!primary) {
|
|
28061
|
+
if (logs)
|
|
28062
|
+
console.log(
|
|
28063
|
+
`sharded multicall: no untried endpoint left for chain ${chainId}`
|
|
28064
|
+
);
|
|
28065
|
+
return null;
|
|
28066
|
+
}
|
|
28067
|
+
let timer;
|
|
28068
|
+
let hedgeStarted = false;
|
|
28069
|
+
let beginHedge = () => {
|
|
28070
|
+
};
|
|
28071
|
+
const hedged = new Promise((resolve) => {
|
|
28072
|
+
beginHedge = () => {
|
|
28073
|
+
if (hedgeStarted) return;
|
|
28074
|
+
hedgeStarted = true;
|
|
28075
|
+
clearTimeout(timer);
|
|
28076
|
+
const alt = resolveEndpoint(
|
|
28077
|
+
chainId,
|
|
28078
|
+
getEvmClient17,
|
|
28079
|
+
primary.rpcId + 1,
|
|
28080
|
+
tried,
|
|
28081
|
+
12,
|
|
28082
|
+
SHARD_TIMEOUT_MS
|
|
28083
|
+
);
|
|
28084
|
+
if (!alt) return resolve(null);
|
|
28085
|
+
const altItems = items.slice(0, capFor(alt.url, items.length));
|
|
28086
|
+
if (altItems.length < items.length) return resolve(null);
|
|
28087
|
+
request(alt, items).then(
|
|
28088
|
+
(slots) => resolve(slots ? { slots, rpcId: alt.rpcId } : null)
|
|
28089
|
+
);
|
|
28090
|
+
};
|
|
28091
|
+
});
|
|
28092
|
+
timer = setTimeout(() => beginHedge(), HEDGE_DELAY_MS);
|
|
28093
|
+
const direct = request(primary, items).then((slots) => {
|
|
28094
|
+
if (slots) return { slots, rpcId: primary.rpcId };
|
|
28095
|
+
beginHedge();
|
|
28096
|
+
return null;
|
|
28097
|
+
});
|
|
28098
|
+
const won = await firstUsable([direct, hedged]);
|
|
28099
|
+
clearTimeout(timer);
|
|
28100
|
+
return won;
|
|
28101
|
+
};
|
|
28102
|
+
const runBatch = async (batch, rpcId, attemptsLeft, tried) => {
|
|
28103
|
+
if (!batch.items.length) return;
|
|
28104
|
+
const won = await attemptHedged(batch.items, rpcId, tried);
|
|
28105
|
+
if (!won) {
|
|
28106
|
+
if (attemptsLeft > 0 && batch.items.length > 1) {
|
|
28107
|
+
const half = Math.ceil(batch.items.length / 2);
|
|
28108
|
+
await sleep(backoffForRound(0));
|
|
28109
|
+
await runBatch(
|
|
28110
|
+
{ start: batch.start, items: batch.items.slice(0, half) },
|
|
28111
|
+
rpcId,
|
|
28112
|
+
attemptsLeft - 1,
|
|
28113
|
+
tried
|
|
28114
|
+
);
|
|
28115
|
+
await runBatch(
|
|
28116
|
+
{ start: batch.start + half, items: batch.items.slice(half) },
|
|
28117
|
+
rpcId + 1,
|
|
28118
|
+
attemptsLeft - 1,
|
|
28119
|
+
tried
|
|
28120
|
+
);
|
|
28121
|
+
}
|
|
28122
|
+
return;
|
|
28123
|
+
}
|
|
28124
|
+
let slots = won.slots;
|
|
28125
|
+
if (allowFailure && retryFailed) {
|
|
28126
|
+
slots = await repairFailedSlots(
|
|
28127
|
+
chainId,
|
|
28128
|
+
batch.items,
|
|
28129
|
+
slots,
|
|
28130
|
+
getEvmClient17,
|
|
28131
|
+
won.rpcId + 1,
|
|
28132
|
+
requestBytes,
|
|
28133
|
+
logs,
|
|
28134
|
+
MULTICALL_REPAIR_ROUNDS,
|
|
28135
|
+
{ tried, onEndpointFailure: options?.onEndpointFailure }
|
|
27979
28136
|
);
|
|
27980
28137
|
}
|
|
28138
|
+
recordPermanentFailures(slots, batch.start, permanentFailures);
|
|
28139
|
+
for (let j = 0; j < slots.length; j++) {
|
|
28140
|
+
results[batch.start + j] = slots[j].value;
|
|
28141
|
+
}
|
|
27981
28142
|
};
|
|
27982
|
-
const workers = Math.max(1, Math.min(poolSize, batches.length));
|
|
27983
28143
|
let cursor = 0;
|
|
27984
28144
|
const worker = async (workerId) => {
|
|
27985
28145
|
while (true) {
|
|
27986
28146
|
const idx = cursor++;
|
|
27987
28147
|
if (idx >= batches.length) break;
|
|
27988
|
-
|
|
28148
|
+
const batch = batches[idx];
|
|
28149
|
+
const tried = /* @__PURE__ */ new Set();
|
|
28150
|
+
const start = resolveEndpoint(
|
|
28151
|
+
chainId,
|
|
28152
|
+
getEvmClient17,
|
|
28153
|
+
workerId,
|
|
28154
|
+
void 0,
|
|
28155
|
+
12,
|
|
28156
|
+
SHARD_TIMEOUT_MS
|
|
28157
|
+
);
|
|
28158
|
+
const cap = start ? capFor(start.url, batch.items.length) : batch.items.length;
|
|
28159
|
+
for (let off = 0; off < batch.items.length; off += cap) {
|
|
28160
|
+
await runBatch(
|
|
28161
|
+
{
|
|
28162
|
+
start: batch.start + off,
|
|
28163
|
+
items: batch.items.slice(off, off + cap)
|
|
28164
|
+
},
|
|
28165
|
+
workerId,
|
|
28166
|
+
retries,
|
|
28167
|
+
tried
|
|
28168
|
+
);
|
|
28169
|
+
}
|
|
27989
28170
|
}
|
|
27990
28171
|
};
|
|
27991
|
-
await Promise.all(
|
|
28172
|
+
await Promise.all(
|
|
28173
|
+
Array.from(
|
|
28174
|
+
{ length: Math.min(workers, batches.length) },
|
|
28175
|
+
(_3, w) => worker(w)
|
|
28176
|
+
)
|
|
28177
|
+
);
|
|
27992
28178
|
return results;
|
|
27993
28179
|
};
|
|
27994
28180
|
function prepareMulticallInputs(abi, calls) {
|
|
@@ -53819,6 +54005,19 @@ var FlashAbi = [
|
|
|
53819
54005
|
name: "FLASHLOAN_PREMIUM_TOTAL",
|
|
53820
54006
|
inputs: []
|
|
53821
54007
|
},
|
|
54008
|
+
{
|
|
54009
|
+
inputs: [],
|
|
54010
|
+
name: "decimals",
|
|
54011
|
+
outputs: [
|
|
54012
|
+
{
|
|
54013
|
+
internalType: "uint8",
|
|
54014
|
+
name: "",
|
|
54015
|
+
type: "uint8"
|
|
54016
|
+
}
|
|
54017
|
+
],
|
|
54018
|
+
stateMutability: "view",
|
|
54019
|
+
type: "function"
|
|
54020
|
+
},
|
|
53822
54021
|
{
|
|
53823
54022
|
inputs: [
|
|
53824
54023
|
{
|
|
@@ -53841,6 +54040,14 @@ var FlashAbi = [
|
|
|
53841
54040
|
];
|
|
53842
54041
|
var DEFAULT_BATCH_SIZE = 4096;
|
|
53843
54042
|
var isValidResult = (v) => typeof v === "bigint";
|
|
54043
|
+
var NATIVE_DECIMALS = 18;
|
|
54044
|
+
function parseDecimalsResult(v) {
|
|
54045
|
+
const n = typeof v === "bigint" ? Number(v) : v;
|
|
54046
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n < 0 || n > 36) {
|
|
54047
|
+
return void 0;
|
|
54048
|
+
}
|
|
54049
|
+
return n;
|
|
54050
|
+
}
|
|
53844
54051
|
var FLASHLOAN_ENABLED_MASK = BigInt(
|
|
53845
54052
|
"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFF"
|
|
53846
54053
|
);
|
|
@@ -53906,6 +54113,20 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
53906
54113
|
const balancerV3Calls = buildBalanceCalls(balancerV3s);
|
|
53907
54114
|
const uniswapV4s = RELEVANT_UNISWAP_V4_FORKS[chain] ?? [];
|
|
53908
54115
|
const uniswapV4Calls = buildBalanceCalls(uniswapV4s);
|
|
54116
|
+
const decimalsByAsset = {
|
|
54117
|
+
[zeroAddress]: NATIVE_DECIMALS
|
|
54118
|
+
};
|
|
54119
|
+
for (const asset of unifiedAssets) {
|
|
54120
|
+
const fromList = list[asset]?.decimals;
|
|
54121
|
+
if (typeof fromList === "number") decimalsByAsset[asset] = fromList;
|
|
54122
|
+
}
|
|
54123
|
+
const assetsMissingDecimals = unifiedAssets.filter(
|
|
54124
|
+
(asset) => decimalsByAsset[asset] === void 0
|
|
54125
|
+
);
|
|
54126
|
+
const decimalsCalls = assetsMissingDecimals.map((address) => ({
|
|
54127
|
+
name: "decimals",
|
|
54128
|
+
address
|
|
54129
|
+
}));
|
|
53909
54130
|
const calls = [
|
|
53910
54131
|
...aaveCalls,
|
|
53911
54132
|
...balancerV2Calls,
|
|
@@ -53913,6 +54134,8 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
53913
54134
|
...balancerV3Calls,
|
|
53914
54135
|
...uniswapV4Calls
|
|
53915
54136
|
];
|
|
54137
|
+
const decimalsOffset = calls.length;
|
|
54138
|
+
calls.push(...decimalsCalls);
|
|
53916
54139
|
const rawResults = await multicallRetry({
|
|
53917
54140
|
chain,
|
|
53918
54141
|
calls,
|
|
@@ -53922,6 +54145,10 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
53922
54145
|
providerId: 0,
|
|
53923
54146
|
allowFailure: true
|
|
53924
54147
|
});
|
|
54148
|
+
assetsMissingDecimals.forEach((asset, i) => {
|
|
54149
|
+
const parsed = parseDecimalsResult(rawResults[decimalsOffset + i]);
|
|
54150
|
+
if (parsed !== void 0) decimalsByAsset[asset] = parsed;
|
|
54151
|
+
});
|
|
53925
54152
|
let liquidity = {};
|
|
53926
54153
|
let currentOffset = 0;
|
|
53927
54154
|
aaveProtocols.forEach((aave) => {
|
|
@@ -53934,7 +54161,7 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
53934
54161
|
const rawAmount = data[2 * i];
|
|
53935
54162
|
const config = data[2 * i + 1];
|
|
53936
54163
|
if (typeof rawAmount !== "bigint" || typeof config !== "bigint") return;
|
|
53937
|
-
const decimals =
|
|
54164
|
+
const decimals = decimalsByAsset[asset];
|
|
53938
54165
|
const enabled = !AAVE_V3_LENDERS.includes(aave) || getFlashLoanEnabled(config);
|
|
53939
54166
|
if (enabled && rawAmount > 0n && FLASH_LOAN_IDS[aave] !== void 0) {
|
|
53940
54167
|
if (!liquidity[asset]) liquidity[asset] = [];
|
|
@@ -53945,7 +54172,7 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
53945
54172
|
source: getAaveTypePoolAddress(chain, aave),
|
|
53946
54173
|
fee: fee.toString(),
|
|
53947
54174
|
availableRaw: rawAmount.toString(),
|
|
53948
|
-
available: Number(formatUnits(rawAmount, decimals
|
|
54175
|
+
available: decimals === void 0 ? void 0 : Number(formatUnits(rawAmount, decimals)),
|
|
53949
54176
|
decimals
|
|
53950
54177
|
});
|
|
53951
54178
|
}
|
|
@@ -53956,7 +54183,7 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
53956
54183
|
const data = rawResults.slice(currentOffset, callLen + currentOffset);
|
|
53957
54184
|
currentOffset += callLen;
|
|
53958
54185
|
unifiedAssets.forEach((asset, i) => {
|
|
53959
|
-
const decimals =
|
|
54186
|
+
const decimals = decimalsByAsset[asset];
|
|
53960
54187
|
const rawAmount = data[i];
|
|
53961
54188
|
if (isValidResult(rawAmount) && rawAmount > 0n) {
|
|
53962
54189
|
if (!liquidity[asset]) liquidity[asset] = [];
|
|
@@ -53967,7 +54194,7 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
53967
54194
|
source: balancer.address,
|
|
53968
54195
|
fee: "0",
|
|
53969
54196
|
availableRaw: rawAmount.toString(),
|
|
53970
|
-
available: Number(formatUnits(rawAmount, decimals
|
|
54197
|
+
available: decimals === void 0 ? void 0 : Number(formatUnits(rawAmount, decimals)),
|
|
53971
54198
|
decimals
|
|
53972
54199
|
});
|
|
53973
54200
|
}
|
|
@@ -53981,7 +54208,7 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
53981
54208
|
const rawAmount = data[i];
|
|
53982
54209
|
if (isValidResult(rawAmount) && rawAmount > 0n) {
|
|
53983
54210
|
if (!liquidity[asset]) liquidity[asset] = [];
|
|
53984
|
-
const decimals =
|
|
54211
|
+
const decimals = decimalsByAsset[asset];
|
|
53985
54212
|
liquidity[asset].push({
|
|
53986
54213
|
id: FLASH_LOAN_IDS[morpho.pool],
|
|
53987
54214
|
name: morpho.pool,
|
|
@@ -53989,7 +54216,7 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
53989
54216
|
source: morpho.address,
|
|
53990
54217
|
fee: "0",
|
|
53991
54218
|
availableRaw: rawAmount.toString(),
|
|
53992
|
-
available: Number(formatUnits(rawAmount, decimals
|
|
54219
|
+
available: decimals === void 0 ? void 0 : Number(formatUnits(rawAmount, decimals)),
|
|
53993
54220
|
decimals
|
|
53994
54221
|
});
|
|
53995
54222
|
}
|
|
@@ -54000,7 +54227,7 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
54000
54227
|
const data = rawResults.slice(currentOffset, callLen + currentOffset);
|
|
54001
54228
|
currentOffset += callLen;
|
|
54002
54229
|
unifiedAssets.forEach((asset, i) => {
|
|
54003
|
-
const decimals =
|
|
54230
|
+
const decimals = decimalsByAsset[asset];
|
|
54004
54231
|
const rawAmount = data[i];
|
|
54005
54232
|
if (isValidResult(rawAmount) && rawAmount > 0n) {
|
|
54006
54233
|
if (!liquidity[asset]) liquidity[asset] = [];
|
|
@@ -54011,7 +54238,7 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
54011
54238
|
source: balancerV3.address,
|
|
54012
54239
|
fee: "0",
|
|
54013
54240
|
availableRaw: rawAmount.toString(),
|
|
54014
|
-
available: Number(formatUnits(rawAmount, decimals
|
|
54241
|
+
available: decimals === void 0 ? void 0 : Number(formatUnits(rawAmount, decimals)),
|
|
54015
54242
|
decimals
|
|
54016
54243
|
});
|
|
54017
54244
|
}
|
|
@@ -54022,7 +54249,7 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
54022
54249
|
const data = rawResults.slice(currentOffset, callLen + currentOffset);
|
|
54023
54250
|
currentOffset += callLen;
|
|
54024
54251
|
unifiedAssets.forEach((asset, i) => {
|
|
54025
|
-
const decimals =
|
|
54252
|
+
const decimals = decimalsByAsset[asset];
|
|
54026
54253
|
const rawAmount = data[i];
|
|
54027
54254
|
if (isValidResult(rawAmount) && rawAmount > 0n) {
|
|
54028
54255
|
if (!liquidity[asset]) liquidity[asset] = [];
|
|
@@ -54033,7 +54260,7 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
|
|
|
54033
54260
|
source: uniV4.address,
|
|
54034
54261
|
fee: "0",
|
|
54035
54262
|
availableRaw: rawAmount.toString(),
|
|
54036
|
-
available: Number(formatUnits(rawAmount, decimals
|
|
54263
|
+
available: decimals === void 0 ? void 0 : Number(formatUnits(rawAmount, decimals)),
|
|
54037
54264
|
decimals
|
|
54038
54265
|
});
|
|
54039
54266
|
}
|
|
@@ -54050,7 +54277,9 @@ function attachPricesToFlashLiquidity(chainId, liq, prices, list = {}) {
|
|
|
54050
54277
|
const price2 = prices[priceKey] ?? 0;
|
|
54051
54278
|
liqCopy[asset] = entry.map((e) => ({
|
|
54052
54279
|
...e,
|
|
54053
|
-
|
|
54280
|
+
// absent when the token amount itself is unknown — never 0, which reads
|
|
54281
|
+
// as "no liquidity" rather than "not priced"
|
|
54282
|
+
availableUSD: e.available === void 0 ? void 0 : e.available * price2
|
|
54054
54283
|
}));
|
|
54055
54284
|
});
|
|
54056
54285
|
return liqCopy;
|
|
@@ -65653,9 +65882,8 @@ function borrowDescription(b) {
|
|
|
65653
65882
|
b.rate.minApr != null && b.rate.maxApr != null ? `You choose your own rate between ${pct(b.rate.minApr)} and ${pct(b.rate.maxApr)}; a lower rate is cheaper but makes you redeemed first.` : "You choose your own interest rate; a lower rate is cheaper but makes you redeemed first."
|
|
65654
65883
|
);
|
|
65655
65884
|
} else {
|
|
65656
|
-
|
|
65657
|
-
|
|
65658
|
-
);
|
|
65885
|
+
const how = b.rate.isLocked ? ", locked for the term" : b.rate.kind === "variable-curve" ? ", floating with utilization" : b.rate.kind === "variable-managed" ? ", set by the protocol rather than floating with utilization" : "";
|
|
65886
|
+
parts.push(`You pay ${pct(b.rate.apr)}${how}.`);
|
|
65659
65887
|
}
|
|
65660
65888
|
parts.push(
|
|
65661
65889
|
b.debtShape === "static-face" ? "The amount owed is fixed at trade time and does not accrue." : b.debtShape === "prepaid" ? "The debt principal is static; the cost is the prepaid interest token burning down." : "The amount owed grows continuously as interest accrues."
|
|
@@ -65674,11 +65902,27 @@ function borrowDescription(b) {
|
|
|
65674
65902
|
`It matures on ${shortDate(b.maturity.maturity)}${what ? `; if nothing is done then, ${what}` : ""}.`
|
|
65675
65903
|
);
|
|
65676
65904
|
}
|
|
65905
|
+
const withheld = (b.fees ?? []).filter(
|
|
65906
|
+
(f) => f.when === "entry" && f.basis === "principal" && f.unit === "percent" && f.value > 0
|
|
65907
|
+
);
|
|
65908
|
+
if (withheld.length > 0) {
|
|
65909
|
+
const total = withheld.reduce((a, f) => a + f.value, 0);
|
|
65910
|
+
const named = withheld.map((f) => `${f.label.toLowerCase()} ${pct(f.value)}`).join(" + ");
|
|
65911
|
+
parts.push(
|
|
65912
|
+
`${pct(total)} of anything you borrow is withheld at open` + (withheld.length > 1 ? ` (${named})` : "") + `, so you receive ${pct(100 - total)} of what you owe.`
|
|
65913
|
+
);
|
|
65914
|
+
}
|
|
65677
65915
|
if (b.liquidation.trigger === "time") {
|
|
65678
65916
|
parts.push(
|
|
65679
65917
|
"Liquidation here is triggered by TIME, not price \u2014 being late is the trigger, and being over-collateralised does not protect you."
|
|
65680
65918
|
);
|
|
65681
|
-
} else if (b.liquidation.liquidationLtv
|
|
65919
|
+
} else if (b.liquidation.model === "auction" && !(b.liquidation.liquidationLtv > 0)) {
|
|
65920
|
+
const pen = b.liquidation.penalty;
|
|
65921
|
+
const win = b.liquidation.windowSecs;
|
|
65922
|
+
parts.push(
|
|
65923
|
+
"Liquidation is a public auction rather than a loan-to-value threshold" + (win ? `, open for ${duration(win)} once started` : "") + (pen != null ? `, and the liquidator is paid ${pct(pen * 100)}` : "") + "."
|
|
65924
|
+
);
|
|
65925
|
+
} else if (b.liquidation.liquidationLtv != null && b.liquidation.liquidationLtv > 0) {
|
|
65682
65926
|
const pen = b.liquidation.penalty;
|
|
65683
65927
|
parts.push(
|
|
65684
65928
|
`Liquidation starts at ${pct(b.liquidation.liquidationLtv * 100)} LTV` + (pen != null ? `, with a ${pct(pen * 100)} penalty` : "") + "."
|