@morpho-dev/router 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +441 -141
- package/dist/drizzle/migrations/0000_setup_single_migration_folder.sql +64 -64
- package/dist/drizzle/migrations/0001_add-trigger-for-consumed-events.sql +5 -5
- package/dist/drizzle/migrations/0002_insert-status-code.sql +1 -1
- package/dist/drizzle/migrations/0003_update-triggers-for-consumed-events.sql +1 -1
- package/dist/drizzle/migrations/0004_drop-status-offers-foreign-key-constraint.sql +1 -1
- package/dist/drizzle/migrations/0005_add-index-to-boost-group-query-and-offer-hash.sql +1 -1
- package/dist/drizzle/migrations/0006_add-callbacks-and-positions-relations.sql +11 -11
- package/dist/drizzle/migrations/0008_validation.sql +10 -10
- package/dist/drizzle/migrations/0009_add-transfers-table.sql +4 -4
- package/dist/drizzle/migrations/0010_add-price.sql +1 -1
- package/dist/drizzle/migrations/0011_nullable-callback-amount.sql +1 -1
- package/dist/drizzle/migrations/0012_add-position-asset.sql +1 -1
- package/dist/drizzle/migrations/0013_remove-depecrated-domains.sql +13 -13
- package/dist/drizzle/migrations/0014_rename-offers-v2-into-offers.sql +19 -19
- package/dist/drizzle/migrations/0015_add-lots-table.sql +3 -3
- package/dist/drizzle/migrations/0016_merkle-metadata.sql +7 -7
- package/dist/drizzle/migrations/0017_dusty_the_hunter.sql +1 -1
- package/dist/drizzle/migrations/0018_add_chain_collector_constraints.sql +3 -3
- package/dist/drizzle/migrations/0019_add-obligation-units-shares.sql +2 -2
- package/dist/drizzle/migrations/0020_add-session.sql +1 -1
- package/dist/drizzle/migrations/0021_drop_chain_collector_epoch_indexes.sql +2 -2
- package/dist/drizzle/migrations/0021_migrate-rate-to-price.sql +6 -6
- package/dist/drizzle/migrations/0022_consolidate-price.sql +5 -5
- package/dist/drizzle/migrations/0023_remove-block-number-for-collaterals.sql +1 -1
- package/dist/drizzle/migrations/0024_add-obligation-id-to-lots.sql +8 -0
- package/dist/drizzle/migrations/0025_rename-price-to-tick.sql +202 -0
- package/dist/drizzle/migrations/meta/0000_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0001_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0002_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0003_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0004_snapshot.json +47 -47
- package/dist/drizzle/migrations/meta/0005_snapshot.json +47 -47
- package/dist/drizzle/migrations/meta/0006_snapshot.json +61 -61
- package/dist/drizzle/migrations/meta/0008_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0009_snapshot.json +66 -66
- package/dist/drizzle/migrations/meta/0010_snapshot.json +66 -66
- package/dist/drizzle/migrations/meta/0013_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0014_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0015_snapshot.json +52 -52
- package/dist/drizzle/migrations/meta/0016_snapshot.json +61 -61
- package/dist/drizzle/migrations/meta/0017_snapshot.json +61 -61
- package/dist/drizzle/migrations/meta/0018_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0019_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0023_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0024_snapshot.json +1448 -0
- package/dist/drizzle/migrations/meta/0025_snapshot.json +1448 -0
- package/dist/drizzle/migrations/meta/_journal.json +14 -0
- package/dist/evm/bytecode/erc20.txt +1 -1
- package/dist/evm/bytecode/morpho.txt +1 -1
- package/dist/evm/bytecode/multicall3.txt +1 -1
- package/dist/evm/bytecode/oracle.txt +1 -1
- package/dist/evm/bytecode/vault.txt +1 -1
- package/dist/index.browser.d.mts +1157 -81
- package/dist/index.browser.d.mts.map +1 -1
- package/dist/index.browser.d.ts +1157 -81
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +371 -151
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +366 -152
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.mts +1196 -70
- package/dist/index.node.d.mts.map +1 -1
- package/dist/index.node.d.ts +1196 -70
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +491 -145
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +486 -146
- package/dist/index.node.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.node.js
CHANGED
|
@@ -991,6 +991,61 @@ const MetaMorpho = (0, viem.parseAbi)([
|
|
|
991
991
|
//#region src/core/Abi/MetaMorphoFactory.ts
|
|
992
992
|
const MetaMorphoFactory = (0, viem.parseAbi)(["event CreateMetaMorpho(address indexed metaMorpho,address indexed caller,address initialOwner,uint256 initialTimelock,address indexed asset,string name,string symbol,bytes32 salt)", "function isMetaMorpho(address) view returns (bool)"]);
|
|
993
993
|
|
|
994
|
+
//#endregion
|
|
995
|
+
//#region src/core/Abi/MorphoV2.ts
|
|
996
|
+
const MorphoV2 = (0, viem.parseAbi)([
|
|
997
|
+
"constructor()",
|
|
998
|
+
"function collateralOf(bytes32 id, address user, address collateralToken) view returns (uint256)",
|
|
999
|
+
"function consume(bytes32 group, uint256 amount)",
|
|
1000
|
+
"function consumed(address user, bytes32 group) view returns (uint256)",
|
|
1001
|
+
"function debtOf(bytes32 id, address user) view returns (uint256)",
|
|
1002
|
+
"function defaultFees(address loanToken, uint256 index) view returns (uint16)",
|
|
1003
|
+
"function feeSetter() view returns (address)",
|
|
1004
|
+
"function fees(bytes32 id) view returns (uint16[6])",
|
|
1005
|
+
"function flashLoan(address token, uint256 assets, address callback, bytes data)",
|
|
1006
|
+
"function isHealthy((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bytes32 id, address borrower) view returns (bool)",
|
|
1007
|
+
"function liquidate((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, (uint256 collateralIndex, uint256 repaid, uint256 seized)[] seizures, address borrower, bytes data) returns ((uint256 collateralIndex, uint256 repaid, uint256 seized)[])",
|
|
1008
|
+
"function multicall(bytes[] calls)",
|
|
1009
|
+
"function obligationCreated(bytes32 id) view returns (bool)",
|
|
1010
|
+
"function obligationState(bytes32 id) view returns (uint128 totalUnits, uint128 totalShares, uint256 withdrawable, bool created)",
|
|
1011
|
+
"function owner() view returns (address)",
|
|
1012
|
+
"function repay((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, address onBehalf)",
|
|
1013
|
+
"function session(address user) view returns (bytes32)",
|
|
1014
|
+
"function setDefaultTradingFee(address loanToken, uint256 index, uint256 newTradingFee)",
|
|
1015
|
+
"function setFeeSetter(address newFeeSetter)",
|
|
1016
|
+
"function setObligationTradingFee(bytes32 id, uint256 index, uint256 newTradingFee)",
|
|
1017
|
+
"function setOwner(address newOwner)",
|
|
1018
|
+
"function setTradingFeeRecipient(address recipient)",
|
|
1019
|
+
"function sharesOf(bytes32 id, address user) view returns (uint256)",
|
|
1020
|
+
"function shuffleSession()",
|
|
1021
|
+
"function supplyCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)",
|
|
1022
|
+
"function take(uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, address taker, ((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bool buy, address maker, uint256 assets, uint256 obligationUnits, uint256 obligationShares, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof, address takerCallback, bytes takerCallbackData) returns (uint256, uint256, uint256, uint256)",
|
|
1023
|
+
"function totalShares(bytes32 id) view returns (uint256)",
|
|
1024
|
+
"function totalUnits(bytes32 id) view returns (uint256)",
|
|
1025
|
+
"function touchObligation((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation) returns (bytes32)",
|
|
1026
|
+
"function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)",
|
|
1027
|
+
"function tradingFeeRecipient() view returns (address)",
|
|
1028
|
+
"function withdraw((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, uint256 shares, address onBehalf) returns (uint256, uint256)",
|
|
1029
|
+
"function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)",
|
|
1030
|
+
"function withdrawable(bytes32 id) view returns (uint256)",
|
|
1031
|
+
"event Constructor(address indexed owner)",
|
|
1032
|
+
"event Consume(address indexed user, bytes32 indexed group, uint256 amount)",
|
|
1033
|
+
"event FlashLoan(address indexed caller, address indexed token, uint256 assets)",
|
|
1034
|
+
"event Liquidate(address indexed caller, bytes32 indexed id, (uint256 collateralIndex, uint256 repaid, uint256 seized)[] seizures, address indexed borrower, uint256 totalRepaid, uint256 badDebt)",
|
|
1035
|
+
"event ObligationCreated(bytes32 indexed id, (address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation)",
|
|
1036
|
+
"event Repay(address indexed caller, bytes32 indexed id, uint256 obligationUnits, address indexed onBehalf)",
|
|
1037
|
+
"event SetDefaultTradingFee(address indexed loanToken, uint256 indexed index, uint256 newTradingFee)",
|
|
1038
|
+
"event SetFeeSetter(address indexed feeSetter)",
|
|
1039
|
+
"event SetObligationTradingFee(bytes32 indexed id, uint256 indexed index, uint256 newTradingFee)",
|
|
1040
|
+
"event SetOwner(address indexed owner)",
|
|
1041
|
+
"event SetTradingFeeRecipient(address indexed recipient)",
|
|
1042
|
+
"event ShuffleSession(address indexed user, bytes32 session)",
|
|
1043
|
+
"event SupplyCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)",
|
|
1044
|
+
"event Take(address caller, bytes32 indexed id, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, bool buyerIsLender, bool sellerIsBorrower, bytes32 group, uint256 consumed)",
|
|
1045
|
+
"event Withdraw(address indexed caller, bytes32 indexed id, uint256 obligationUnits, uint256 shares, address indexed onBehalf)",
|
|
1046
|
+
"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)"
|
|
1047
|
+
]);
|
|
1048
|
+
|
|
994
1049
|
//#endregion
|
|
995
1050
|
//#region src/core/Abi/index.ts
|
|
996
1051
|
var Abi_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -998,6 +1053,7 @@ var Abi_exports = /* @__PURE__ */ __exportAll({
|
|
|
998
1053
|
MetaMorpho: () => MetaMorpho,
|
|
999
1054
|
MetaMorphoFactory: () => MetaMorphoFactory,
|
|
1000
1055
|
Morpho: () => Morpho,
|
|
1056
|
+
MorphoV2: () => MorphoV2,
|
|
1001
1057
|
Oracle: () => Oracle
|
|
1002
1058
|
});
|
|
1003
1059
|
const Oracle = [{
|
|
@@ -1259,8 +1315,8 @@ const chains$2 = {
|
|
|
1259
1315
|
name: "ethereum-virtual-testnet",
|
|
1260
1316
|
custom: {
|
|
1261
1317
|
morpho: {
|
|
1262
|
-
address: "
|
|
1263
|
-
blockCreated:
|
|
1318
|
+
address: "0x634b095371e4e45feed94c1a45c37798e173ea50",
|
|
1319
|
+
blockCreated: 23226700
|
|
1264
1320
|
},
|
|
1265
1321
|
morphoBlue: {
|
|
1266
1322
|
address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
@@ -2066,7 +2122,7 @@ const OfferSchema = () => {
|
|
|
2066
2122
|
assets: zod.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
2067
2123
|
obligationUnits: zod.bigint({ coerce: true }).min(0n).max(viem.maxUint256).optional().default(0n),
|
|
2068
2124
|
obligationShares: zod.bigint({ coerce: true }).min(0n).max(viem.maxUint256).optional().default(0n),
|
|
2069
|
-
|
|
2125
|
+
tick: zod.coerce.number().int().min(0).max(990),
|
|
2070
2126
|
maturity: MaturitySchema,
|
|
2071
2127
|
expiry: zod.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
2072
2128
|
start: zod.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
@@ -2138,7 +2194,7 @@ const serialize = (offer) => ({
|
|
|
2138
2194
|
assets: offer.assets.toString(),
|
|
2139
2195
|
obligationUnits: offer.obligationUnits.toString(),
|
|
2140
2196
|
obligationShares: offer.obligationShares.toString(),
|
|
2141
|
-
|
|
2197
|
+
tick: offer.tick,
|
|
2142
2198
|
maturity: Number(offer.maturity),
|
|
2143
2199
|
expiry: Number(offer.expiry),
|
|
2144
2200
|
start: Number(offer.start),
|
|
@@ -2183,14 +2239,13 @@ function random$1(config) {
|
|
|
2183
2239
|
[.98, 2]
|
|
2184
2240
|
]));
|
|
2185
2241
|
const buy = config?.buy !== void 0 ? config.buy : bool();
|
|
2186
|
-
const
|
|
2187
|
-
const
|
|
2188
|
-
const
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
return [BigInt(q) * (ONE / 4n), buy ? 1 + idx : 1 + (len - 1 - idx)];
|
|
2242
|
+
const tickMin = buy ? 0 : 495;
|
|
2243
|
+
const len = (buy ? 495 : 990) - tickMin + 1;
|
|
2244
|
+
const tickPairs = Array.from({ length: len }, (_, idx) => {
|
|
2245
|
+
const weight = buy ? 1 + idx : 1 + (len - 1 - idx);
|
|
2246
|
+
return [tickMin + idx, weight];
|
|
2192
2247
|
});
|
|
2193
|
-
const
|
|
2248
|
+
const tick = config?.tick ?? weightedChoice(tickPairs);
|
|
2194
2249
|
const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
|
|
2195
2250
|
const unit = BigInt(10) ** BigInt(loanTokenDecimals);
|
|
2196
2251
|
const amountBase = BigInt(100 + int(999901));
|
|
@@ -2204,7 +2259,7 @@ function random$1(config) {
|
|
|
2204
2259
|
assets: assetsScaled,
|
|
2205
2260
|
obligationUnits: config?.obligationUnits ?? 0n,
|
|
2206
2261
|
obligationShares: config?.obligationShares ?? 0n,
|
|
2207
|
-
|
|
2262
|
+
tick,
|
|
2208
2263
|
maturity,
|
|
2209
2264
|
expiry: config?.expiry ?? maturity - 1,
|
|
2210
2265
|
start: config?.start ?? maturity - 10,
|
|
@@ -2269,7 +2324,7 @@ const types = {
|
|
|
2269
2324
|
type: "uint256"
|
|
2270
2325
|
},
|
|
2271
2326
|
{
|
|
2272
|
-
name: "
|
|
2327
|
+
name: "tick",
|
|
2273
2328
|
type: "uint256"
|
|
2274
2329
|
},
|
|
2275
2330
|
{
|
|
@@ -2337,7 +2392,7 @@ function hash(offer) {
|
|
|
2337
2392
|
assets: offer.assets,
|
|
2338
2393
|
obligationUnits: offer.obligationUnits,
|
|
2339
2394
|
obligationShares: offer.obligationShares,
|
|
2340
|
-
|
|
2395
|
+
tick: BigInt(offer.tick),
|
|
2341
2396
|
maturity: BigInt(offer.maturity),
|
|
2342
2397
|
expiry: BigInt(offer.expiry),
|
|
2343
2398
|
group: offer.group,
|
|
@@ -2388,7 +2443,7 @@ const OfferAbi = [
|
|
|
2388
2443
|
type: "uint256"
|
|
2389
2444
|
},
|
|
2390
2445
|
{
|
|
2391
|
-
name: "
|
|
2446
|
+
name: "tick",
|
|
2392
2447
|
type: "uint256"
|
|
2393
2448
|
},
|
|
2394
2449
|
{
|
|
@@ -2459,7 +2514,7 @@ function encode$1(offer) {
|
|
|
2459
2514
|
offer.assets,
|
|
2460
2515
|
offer.obligationUnits,
|
|
2461
2516
|
offer.obligationShares,
|
|
2462
|
-
offer.
|
|
2517
|
+
BigInt(offer.tick),
|
|
2463
2518
|
BigInt(offer.maturity),
|
|
2464
2519
|
BigInt(offer.expiry),
|
|
2465
2520
|
offer.group,
|
|
@@ -2484,7 +2539,7 @@ function decode$1(data) {
|
|
|
2484
2539
|
assets: decoded[1],
|
|
2485
2540
|
obligationUnits: decoded[2],
|
|
2486
2541
|
obligationShares: decoded[3],
|
|
2487
|
-
|
|
2542
|
+
tick: Number(decoded[4]),
|
|
2488
2543
|
maturity: from$16(Number(decoded[5])),
|
|
2489
2544
|
expiry: Number(decoded[6]),
|
|
2490
2545
|
group: decoded[7],
|
|
@@ -2834,6 +2889,85 @@ var InvalidQuoteError = class extends BaseError {
|
|
|
2834
2889
|
}
|
|
2835
2890
|
};
|
|
2836
2891
|
|
|
2892
|
+
//#endregion
|
|
2893
|
+
//#region src/core/Tick.ts
|
|
2894
|
+
var Tick_exports = /* @__PURE__ */ __exportAll({
|
|
2895
|
+
InvalidPriceError: () => InvalidPriceError,
|
|
2896
|
+
InvalidTickError: () => InvalidTickError,
|
|
2897
|
+
MAX_PRICE: () => MAX_PRICE,
|
|
2898
|
+
TICK_RANGE: () => TICK_RANGE,
|
|
2899
|
+
priceToTick: () => priceToTick,
|
|
2900
|
+
tickToPrice: () => tickToPrice
|
|
2901
|
+
});
|
|
2902
|
+
/** ln(1 + 0.025), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2903
|
+
const LN_ONE_PLUS_DELTA = 24692612590371501n;
|
|
2904
|
+
/** ln(2), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2905
|
+
const LN2 = 693147180559945309n;
|
|
2906
|
+
const WAD$1 = 10n ** 18n;
|
|
2907
|
+
const WAD_SQUARED = 10n ** 36n;
|
|
2908
|
+
const PRICE_STEP = 10n ** 13n;
|
|
2909
|
+
const HALF_TICK_RANGE = 495n;
|
|
2910
|
+
/** Tick domain supported by Morpho V2. */
|
|
2911
|
+
const TICK_RANGE = 990;
|
|
2912
|
+
/** Max allowed price (1e18 in wad). */
|
|
2913
|
+
const MAX_PRICE = WAD$1;
|
|
2914
|
+
/**
|
|
2915
|
+
* Converts a tick to a wad price using the same approximation and rounding as TickLib.
|
|
2916
|
+
* @param tick - Tick value in the inclusive range [0, 990].
|
|
2917
|
+
* @returns The price in wad units.
|
|
2918
|
+
* @throws {@link InvalidTickError} If tick is not an integer in range [0, 990].
|
|
2919
|
+
*/
|
|
2920
|
+
function tickToPrice(tick) {
|
|
2921
|
+
assertTick(tick);
|
|
2922
|
+
return divHalfDownUnchecked(divHalfDownUnchecked(WAD_SQUARED, WAD$1 + wExp(LN_ONE_PLUS_DELTA * (HALF_TICK_RANGE - BigInt(tick)))), PRICE_STEP) * PRICE_STEP;
|
|
2923
|
+
}
|
|
2924
|
+
/**
|
|
2925
|
+
* Returns the lowest tick with a higher-or-equal price.
|
|
2926
|
+
* @param price - Price in wad units.
|
|
2927
|
+
* @returns The first tick whose {@link tickToPrice} is greater than or equal to `price`.
|
|
2928
|
+
* @throws {@link InvalidPriceError} If price is outside [0, 1e18].
|
|
2929
|
+
*/
|
|
2930
|
+
function priceToTick(price) {
|
|
2931
|
+
assertPrice(price);
|
|
2932
|
+
let low = 0;
|
|
2933
|
+
let high = TICK_RANGE;
|
|
2934
|
+
while (low !== high) {
|
|
2935
|
+
const mid = Math.floor((low + high) / 2);
|
|
2936
|
+
if (tickToPrice(mid) < price) low = mid + 1;
|
|
2937
|
+
else high = mid;
|
|
2938
|
+
}
|
|
2939
|
+
return low;
|
|
2940
|
+
}
|
|
2941
|
+
function divHalfDownUnchecked(x, d) {
|
|
2942
|
+
return (x + (d - 1n) / 2n) / d;
|
|
2943
|
+
}
|
|
2944
|
+
function wExp(x) {
|
|
2945
|
+
if (x < 0n) return WAD_SQUARED / wExp(-x);
|
|
2946
|
+
const q = (x + LN2 / 2n) / LN2;
|
|
2947
|
+
const r = x - q * LN2;
|
|
2948
|
+
const secondTerm = r * r / (2n * WAD$1);
|
|
2949
|
+
const thirdTerm = secondTerm * r / (3n * WAD$1);
|
|
2950
|
+
return WAD$1 + r + secondTerm + thirdTerm << q;
|
|
2951
|
+
}
|
|
2952
|
+
function assertTick(tick) {
|
|
2953
|
+
if (!Number.isInteger(tick) || tick < 0 || tick > TICK_RANGE) throw new InvalidTickError(tick);
|
|
2954
|
+
}
|
|
2955
|
+
function assertPrice(price) {
|
|
2956
|
+
if (price < 0n || price > MAX_PRICE) throw new InvalidPriceError(price);
|
|
2957
|
+
}
|
|
2958
|
+
var InvalidTickError = class extends BaseError {
|
|
2959
|
+
name = "Tick.InvalidTickError";
|
|
2960
|
+
constructor(tick) {
|
|
2961
|
+
super(`Invalid tick: ${tick}. Tick must be an integer between 0 and ${TICK_RANGE}.`);
|
|
2962
|
+
}
|
|
2963
|
+
};
|
|
2964
|
+
var InvalidPriceError = class extends BaseError {
|
|
2965
|
+
name = "Tick.InvalidPriceError";
|
|
2966
|
+
constructor(price) {
|
|
2967
|
+
super(`Invalid price: ${price}. Price must be between 0 and ${MAX_PRICE}.`);
|
|
2968
|
+
}
|
|
2969
|
+
};
|
|
2970
|
+
|
|
2837
2971
|
//#endregion
|
|
2838
2972
|
//#region src/core/TradingFee.ts
|
|
2839
2973
|
var TradingFee_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -3347,7 +3481,7 @@ const BrandTypeId = Symbol.for("mempool/Brand");
|
|
|
3347
3481
|
|
|
3348
3482
|
//#endregion
|
|
3349
3483
|
//#region src/database/drizzle/VERSION.ts
|
|
3350
|
-
const VERSION = "router_v1.
|
|
3484
|
+
const VERSION = "router_v1.8";
|
|
3351
3485
|
|
|
3352
3486
|
//#endregion
|
|
3353
3487
|
//#region src/database/drizzle/schema.ts
|
|
@@ -3499,10 +3633,7 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
3499
3633
|
precision: 78,
|
|
3500
3634
|
scale: 0
|
|
3501
3635
|
}).notNull().default("0"),
|
|
3502
|
-
|
|
3503
|
-
precision: 78,
|
|
3504
|
-
scale: 0
|
|
3505
|
-
}).notNull(),
|
|
3636
|
+
tick: (0, drizzle_orm_pg_core.integer)("tick").notNull(),
|
|
3506
3637
|
maturity: (0, drizzle_orm_pg_core.integer)("maturity").notNull(),
|
|
3507
3638
|
expiry: (0, drizzle_orm_pg_core.integer)("expiry").notNull(),
|
|
3508
3639
|
start: (0, drizzle_orm_pg_core.integer)("start").notNull(),
|
|
@@ -3567,6 +3698,7 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3567
3698
|
user: (0, drizzle_orm_pg_core.varchar)("user", { length: 42 }).notNull(),
|
|
3568
3699
|
contract: (0, drizzle_orm_pg_core.varchar)("contract", { length: 42 }).notNull(),
|
|
3569
3700
|
group: (0, drizzle_orm_pg_core.varchar)("group", { length: 66 }).notNull(),
|
|
3701
|
+
obligationId: (0, drizzle_orm_pg_core.varchar)("obligation_id", { length: 66 }).notNull(),
|
|
3570
3702
|
lower: (0, drizzle_orm_pg_core.numeric)("lower", {
|
|
3571
3703
|
precision: 78,
|
|
3572
3704
|
scale: 0
|
|
@@ -3581,7 +3713,8 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3581
3713
|
table.chainId,
|
|
3582
3714
|
table.user,
|
|
3583
3715
|
table.contract,
|
|
3584
|
-
table.group
|
|
3716
|
+
table.group,
|
|
3717
|
+
table.obligationId
|
|
3585
3718
|
],
|
|
3586
3719
|
name: "lots_pk"
|
|
3587
3720
|
}),
|
|
@@ -3617,6 +3750,7 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3617
3750
|
user: (0, drizzle_orm_pg_core.varchar)("user", { length: 42 }).notNull(),
|
|
3618
3751
|
contract: (0, drizzle_orm_pg_core.varchar)("contract", { length: 42 }).notNull(),
|
|
3619
3752
|
group: (0, drizzle_orm_pg_core.varchar)("group", { length: 66 }).notNull(),
|
|
3753
|
+
obligationId: (0, drizzle_orm_pg_core.varchar)("obligation_id", { length: 66 }).notNull(),
|
|
3620
3754
|
value: (0, drizzle_orm_pg_core.numeric)("value", {
|
|
3621
3755
|
precision: 78,
|
|
3622
3756
|
scale: 0
|
|
@@ -3626,7 +3760,8 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3626
3760
|
table.chainId,
|
|
3627
3761
|
table.user,
|
|
3628
3762
|
table.contract,
|
|
3629
|
-
table.group
|
|
3763
|
+
table.group,
|
|
3764
|
+
table.obligationId
|
|
3630
3765
|
],
|
|
3631
3766
|
name: "offsets_pk"
|
|
3632
3767
|
}), (0, drizzle_orm_pg_core.foreignKey)({
|
|
@@ -4217,6 +4352,7 @@ function decodeCallbacks(parameters) {
|
|
|
4217
4352
|
positionContract: loanToken,
|
|
4218
4353
|
positionUser: offer.maker,
|
|
4219
4354
|
group: offer.group,
|
|
4355
|
+
obligationId: obligationId(offer),
|
|
4220
4356
|
size: offer.assets
|
|
4221
4357
|
});
|
|
4222
4358
|
callbacks.push({
|
|
@@ -5155,8 +5291,10 @@ async function getRemoteBlockNumbers(healthClients) {
|
|
|
5155
5291
|
//#region src/api/Schema/BookResponse.ts
|
|
5156
5292
|
var BookResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$5 });
|
|
5157
5293
|
function from$5(level) {
|
|
5294
|
+
const price = tickToPrice(level.tick);
|
|
5158
5295
|
return {
|
|
5159
|
-
|
|
5296
|
+
tick: level.tick,
|
|
5297
|
+
price: price.toString(),
|
|
5160
5298
|
assets: level.assets.toString(),
|
|
5161
5299
|
count: level.count
|
|
5162
5300
|
};
|
|
@@ -5224,6 +5362,16 @@ function from$4(obligation, quote) {
|
|
|
5224
5362
|
//#endregion
|
|
5225
5363
|
//#region src/api/Schema/OfferResponse.ts
|
|
5226
5364
|
var OfferResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$3 });
|
|
5365
|
+
function normalizeChainId(chainId) {
|
|
5366
|
+
const parsedChainId = Number(chainId);
|
|
5367
|
+
if (!Number.isInteger(parsedChainId) || parsedChainId <= 0) throw new Error(`Invalid chain id: ${String(chainId)}`);
|
|
5368
|
+
return parsedChainId;
|
|
5369
|
+
}
|
|
5370
|
+
function normalizeBlockNumber(blockNumber) {
|
|
5371
|
+
const parsedBlockNumber = Number(blockNumber);
|
|
5372
|
+
if (!Number.isInteger(parsedBlockNumber) || parsedBlockNumber < 0) throw new Error(`Invalid block number: ${String(blockNumber)}`);
|
|
5373
|
+
return parsedBlockNumber;
|
|
5374
|
+
}
|
|
5227
5375
|
/**
|
|
5228
5376
|
* Creates an `OfferResponse` matching the Solidity Offer struct layout.
|
|
5229
5377
|
* @constructor
|
|
@@ -5231,6 +5379,8 @@ var OfferResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$3 });
|
|
|
5231
5379
|
* @returns The created `OfferResponse`. {@link OfferResponse}
|
|
5232
5380
|
*/
|
|
5233
5381
|
function from$3(input) {
|
|
5382
|
+
const chainId = normalizeChainId(input.chainId);
|
|
5383
|
+
const blockNumber = normalizeBlockNumber(input.blockNumber);
|
|
5234
5384
|
const base = {
|
|
5235
5385
|
offer: {
|
|
5236
5386
|
obligation: {
|
|
@@ -5249,7 +5399,7 @@ function from$3(input) {
|
|
|
5249
5399
|
obligation_shares: input.obligationShares.toString(),
|
|
5250
5400
|
start: input.start,
|
|
5251
5401
|
expiry: input.expiry,
|
|
5252
|
-
|
|
5402
|
+
tick: input.tick,
|
|
5253
5403
|
group: input.group,
|
|
5254
5404
|
session: input.session,
|
|
5255
5405
|
callback: input.callback.address,
|
|
@@ -5257,15 +5407,15 @@ function from$3(input) {
|
|
|
5257
5407
|
},
|
|
5258
5408
|
offer_hash: input.hash,
|
|
5259
5409
|
obligation_id: id({
|
|
5260
|
-
chainId
|
|
5410
|
+
chainId,
|
|
5261
5411
|
loanToken: input.loanToken,
|
|
5262
5412
|
collaterals: [...input.collaterals],
|
|
5263
5413
|
maturity: input.maturity
|
|
5264
5414
|
}),
|
|
5265
|
-
chain_id:
|
|
5415
|
+
chain_id: chainId,
|
|
5266
5416
|
consumed: input.consumed.toString(),
|
|
5267
5417
|
takeable: input.takeable.toString(),
|
|
5268
|
-
block_number:
|
|
5418
|
+
block_number: blockNumber
|
|
5269
5419
|
};
|
|
5270
5420
|
if (!input.proof || !input.root || !input.signature) return {
|
|
5271
5421
|
...base,
|
|
@@ -5411,7 +5561,7 @@ const offerExample = {
|
|
|
5411
5561
|
obligation_shares: "0",
|
|
5412
5562
|
start: 1761922790,
|
|
5413
5563
|
expiry: 1761922799,
|
|
5414
|
-
|
|
5564
|
+
tick: 495,
|
|
5415
5565
|
group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
|
|
5416
5566
|
session: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
5417
5567
|
callback: "0x0000000000000000000000000000000000000000",
|
|
@@ -5452,7 +5602,7 @@ const validateOfferExample = {
|
|
|
5452
5602
|
assets: "369216000000000000000000",
|
|
5453
5603
|
obligation_units: "0",
|
|
5454
5604
|
obligation_shares: "0",
|
|
5455
|
-
|
|
5605
|
+
tick: 495,
|
|
5456
5606
|
maturity: 1761922799,
|
|
5457
5607
|
expiry: 1761922799,
|
|
5458
5608
|
start: 1761922790,
|
|
@@ -5596,9 +5746,11 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5596
5746
|
example: offerExample.offer.expiry
|
|
5597
5747
|
})], OfferDataResponse.prototype, "expiry", void 0);
|
|
5598
5748
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5599
|
-
type: "
|
|
5600
|
-
example: offerExample.offer.
|
|
5601
|
-
|
|
5749
|
+
type: "number",
|
|
5750
|
+
example: offerExample.offer.tick,
|
|
5751
|
+
minimum: 0,
|
|
5752
|
+
maximum: 990
|
|
5753
|
+
})], OfferDataResponse.prototype, "tick", void 0);
|
|
5602
5754
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5603
5755
|
type: "string",
|
|
5604
5756
|
example: offerExample.offer.group
|
|
@@ -5839,9 +5991,11 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5839
5991
|
required: false
|
|
5840
5992
|
})], ValidateOfferRequest.prototype, "obligation_shares", void 0);
|
|
5841
5993
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5842
|
-
type: "
|
|
5843
|
-
example: validateOfferExample.
|
|
5844
|
-
|
|
5994
|
+
type: "number",
|
|
5995
|
+
example: validateOfferExample.tick,
|
|
5996
|
+
minimum: 0,
|
|
5997
|
+
maximum: 990
|
|
5998
|
+
})], ValidateOfferRequest.prototype, "tick", void 0);
|
|
5845
5999
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5846
6000
|
type: "number",
|
|
5847
6001
|
example: validateOfferExample.maturity
|
|
@@ -5941,9 +6095,16 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5941
6095
|
description: "List of validation issues. Returned when any offer fails validation."
|
|
5942
6096
|
})], ValidationFailureResponse.prototype, "data", void 0);
|
|
5943
6097
|
var BookLevelResponse = class {};
|
|
6098
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6099
|
+
type: "number",
|
|
6100
|
+
example: 495,
|
|
6101
|
+
minimum: 0,
|
|
6102
|
+
maximum: 990
|
|
6103
|
+
})], BookLevelResponse.prototype, "tick", void 0);
|
|
5944
6104
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5945
6105
|
type: "string",
|
|
5946
|
-
example: "
|
|
6106
|
+
example: "500000000000000000",
|
|
6107
|
+
description: "Price derived from tick, scaled by 1e18."
|
|
5947
6108
|
})], BookLevelResponse.prototype, "price", void 0);
|
|
5948
6109
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5949
6110
|
type: "string",
|
|
@@ -5957,6 +6118,7 @@ const positionExample = {
|
|
|
5957
6118
|
chain_id: 1,
|
|
5958
6119
|
contract: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
|
|
5959
6120
|
user: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
|
|
6121
|
+
obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
|
|
5960
6122
|
reserved: "200000000000000000000",
|
|
5961
6123
|
block_number: 21345678
|
|
5962
6124
|
};
|
|
@@ -5973,6 +6135,12 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5973
6135
|
type: "string",
|
|
5974
6136
|
example: positionExample.user
|
|
5975
6137
|
})], PositionListItemResponse.prototype, "user", void 0);
|
|
6138
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6139
|
+
type: "string",
|
|
6140
|
+
nullable: true,
|
|
6141
|
+
example: positionExample.obligation_id,
|
|
6142
|
+
description: "Obligation id this reserved amount belongs to, or null if no lots exist."
|
|
6143
|
+
})], PositionListItemResponse.prototype, "obligation_id", void 0);
|
|
5976
6144
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5977
6145
|
type: "string",
|
|
5978
6146
|
example: positionExample.reserved
|
|
@@ -6000,7 +6168,7 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
6000
6168
|
})], BookListResponse.prototype, "cursor", void 0);
|
|
6001
6169
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6002
6170
|
type: () => [BookLevelResponse],
|
|
6003
|
-
description: "Aggregated book levels grouped by
|
|
6171
|
+
description: "Aggregated book levels grouped by offer tick."
|
|
6004
6172
|
})], BookListResponse.prototype, "data", void 0);
|
|
6005
6173
|
let BooksController = class BooksController {
|
|
6006
6174
|
async getBook() {}
|
|
@@ -6010,7 +6178,7 @@ __decorate([
|
|
|
6010
6178
|
methods: ["get"],
|
|
6011
6179
|
path: "/v1/books/{obligationId}/{side}",
|
|
6012
6180
|
summary: "Get aggregated book",
|
|
6013
|
-
description: "Returns aggregated book data for a given obligation and side. Offers are grouped by
|
|
6181
|
+
description: "Returns aggregated book data for a given obligation and side. Offers are grouped by tick with summed takeable amounts, and each level includes the corresponding wad-scaled price. Book levels are sorted by tick (ascending for sell side, descending for buy side)."
|
|
6014
6182
|
}),
|
|
6015
6183
|
(0, openapi_metadata_decorators.ApiParam)({
|
|
6016
6184
|
name: "obligationId",
|
|
@@ -6035,7 +6203,7 @@ __decorate([
|
|
|
6035
6203
|
name: "limit",
|
|
6036
6204
|
type: "number",
|
|
6037
6205
|
example: 10,
|
|
6038
|
-
description: "Maximum number of
|
|
6206
|
+
description: "Maximum number of tick levels to return."
|
|
6039
6207
|
}),
|
|
6040
6208
|
(0, openapi_metadata_decorators.ApiResponse)({
|
|
6041
6209
|
status: 200,
|
|
@@ -6229,6 +6397,11 @@ const configRulesLoanTokenExample = {
|
|
|
6229
6397
|
chain_id: 1,
|
|
6230
6398
|
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
6231
6399
|
};
|
|
6400
|
+
const configRulesCollateralTokenExample = {
|
|
6401
|
+
type: "collateral_token",
|
|
6402
|
+
chain_id: 1,
|
|
6403
|
+
address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
6404
|
+
};
|
|
6232
6405
|
const configRulesOracleExample = {
|
|
6233
6406
|
type: "oracle",
|
|
6234
6407
|
chain_id: 1,
|
|
@@ -6238,6 +6411,7 @@ const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
|
|
|
6238
6411
|
const configRulesPayloadExample = [
|
|
6239
6412
|
configRulesMaturityExample,
|
|
6240
6413
|
configRulesLoanTokenExample,
|
|
6414
|
+
configRulesCollateralTokenExample,
|
|
6241
6415
|
configRulesOracleExample
|
|
6242
6416
|
];
|
|
6243
6417
|
const configContractNames = [
|
|
@@ -6364,7 +6538,7 @@ __decorate([
|
|
|
6364
6538
|
methods: ["get"],
|
|
6365
6539
|
path: "/v1/config/rules",
|
|
6366
6540
|
summary: "Get config rules",
|
|
6367
|
-
description: "Returns configured rules (maturities, loan tokens, oracles) for supported chains."
|
|
6541
|
+
description: "Returns configured rules (maturities, loan tokens, collateral tokens, oracles) for supported chains."
|
|
6368
6542
|
}),
|
|
6369
6543
|
(0, openapi_metadata_decorators.ApiQuery)({
|
|
6370
6544
|
name: "cursor",
|
|
@@ -6384,7 +6558,7 @@ __decorate([
|
|
|
6384
6558
|
name: "types",
|
|
6385
6559
|
type: ["string"],
|
|
6386
6560
|
required: false,
|
|
6387
|
-
example: "maturity,loan_token,oracle",
|
|
6561
|
+
example: "maturity,loan_token,collateral_token,oracle",
|
|
6388
6562
|
description: "Filter by rule types (comma-separated).",
|
|
6389
6563
|
style: "form",
|
|
6390
6564
|
explode: false
|
|
@@ -6502,7 +6676,7 @@ __decorate([
|
|
|
6502
6676
|
methods: ["get"],
|
|
6503
6677
|
path: "/v1/users/{userAddress}/positions",
|
|
6504
6678
|
summary: "Get user positions",
|
|
6505
|
-
description: "Returns positions for a user with reserved balance.
|
|
6679
|
+
description: "Returns positions for a user with reserved balance per obligation. Each (position, obligation) pair is returned as a separate row. Positions with no lots return a single row with obligation_id = null and reserved = 0."
|
|
6506
6680
|
}),
|
|
6507
6681
|
(0, openapi_metadata_decorators.ApiParam)({
|
|
6508
6682
|
name: "userAddress",
|
|
@@ -6590,6 +6764,7 @@ function from$2(position) {
|
|
|
6590
6764
|
chain_id: position.chainId,
|
|
6591
6765
|
contract: position.contract,
|
|
6592
6766
|
user: position.user,
|
|
6767
|
+
obligation_id: position.obligationId,
|
|
6593
6768
|
reserved: position.reserved.toString(),
|
|
6594
6769
|
block_number: position.blockNumber
|
|
6595
6770
|
};
|
|
@@ -6643,10 +6818,11 @@ const ConfigRuleTypes = zod.enum([
|
|
|
6643
6818
|
"maturity",
|
|
6644
6819
|
"callback",
|
|
6645
6820
|
"loan_token",
|
|
6821
|
+
"collateral_token",
|
|
6646
6822
|
"oracle"
|
|
6647
6823
|
]);
|
|
6648
6824
|
const GetConfigRulesQueryParams = zod.object({
|
|
6649
|
-
cursor: zod.string().regex(/^(maturity|callback|loan_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
6825
|
+
cursor: zod.string().regex(/^(maturity|callback|loan_token|collateral_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
6650
6826
|
description: "Pagination cursor in type:chain_id:<value> format",
|
|
6651
6827
|
example: "maturity:1:1730415600:end_of_next_month"
|
|
6652
6828
|
}),
|
|
@@ -6656,7 +6832,7 @@ const GetConfigRulesQueryParams = zod.object({
|
|
|
6656
6832
|
}),
|
|
6657
6833
|
types: csvArray(ConfigRuleTypes).meta({
|
|
6658
6834
|
description: "Filter by rule types (comma-separated).",
|
|
6659
|
-
example: "maturity,loan_token,oracle"
|
|
6835
|
+
example: "maturity,loan_token,collateral_token,oracle"
|
|
6660
6836
|
}),
|
|
6661
6837
|
chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
6662
6838
|
description: "Filter by chain IDs (comma-separated).",
|
|
@@ -6756,12 +6932,11 @@ const GetObligationParams = zod.object({ obligation_id: zod.string({ error: "Obl
|
|
|
6756
6932
|
description: "Obligation id",
|
|
6757
6933
|
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
6758
6934
|
}) });
|
|
6759
|
-
/** Validate a book cursor format: {side,
|
|
6935
|
+
/** Validate a book cursor format: {side, lastTick, offersCursor} */
|
|
6760
6936
|
function isValidBookCursor(cursorString) {
|
|
6761
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
6762
6937
|
try {
|
|
6763
6938
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
6764
|
-
return (v?.side === "buy" || v?.side === "sell") &&
|
|
6939
|
+
return (v?.side === "buy" || v?.side === "sell") && typeof v?.lastTick === "number" && Number.isInteger(v.lastTick) && (v?.offersCursor === null || typeof v?.offersCursor === "string");
|
|
6765
6940
|
} catch {
|
|
6766
6941
|
return false;
|
|
6767
6942
|
}
|
|
@@ -6835,12 +7010,34 @@ async function getBook(params, db) {
|
|
|
6835
7010
|
if (!result.success) return failure(result.error);
|
|
6836
7011
|
const query = result.data;
|
|
6837
7012
|
try {
|
|
7013
|
+
logger.debug({
|
|
7014
|
+
service: "api_controller",
|
|
7015
|
+
endpoint: "get_book",
|
|
7016
|
+
msg: "Loading book levels",
|
|
7017
|
+
obligation_id: query.obligation_id,
|
|
7018
|
+
side: query.side,
|
|
7019
|
+
limit: query.limit ?? null,
|
|
7020
|
+
has_cursor: query.cursor != null
|
|
7021
|
+
});
|
|
6838
7022
|
const { levels, nextCursor } = await db.book.get({
|
|
6839
7023
|
side: query.side,
|
|
6840
7024
|
obligationId: query.obligation_id,
|
|
6841
7025
|
cursor: query.cursor,
|
|
6842
7026
|
limit: query.limit
|
|
6843
7027
|
});
|
|
7028
|
+
const firstLevel = levels[0];
|
|
7029
|
+
logger.debug({
|
|
7030
|
+
service: "api_controller",
|
|
7031
|
+
endpoint: "get_book",
|
|
7032
|
+
msg: "Loaded book levels",
|
|
7033
|
+
obligation_id: query.obligation_id,
|
|
7034
|
+
side: query.side,
|
|
7035
|
+
levels_count: levels.length,
|
|
7036
|
+
has_next_cursor: nextCursor != null,
|
|
7037
|
+
first_level_tick: firstLevel?.tick ?? null,
|
|
7038
|
+
first_level_assets: firstLevel?.assets.toString() ?? null,
|
|
7039
|
+
first_level_count: firstLevel?.count ?? null
|
|
7040
|
+
});
|
|
6844
7041
|
return success({
|
|
6845
7042
|
data: levels.map(from$5),
|
|
6846
7043
|
cursor: nextCursor
|
|
@@ -6989,6 +7186,33 @@ const assets = {
|
|
|
6989
7186
|
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
6990
7187
|
]
|
|
6991
7188
|
};
|
|
7189
|
+
const collateralAssets = {
|
|
7190
|
+
[ChainId.ETHEREUM.toString()]: [
|
|
7191
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7192
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7193
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7194
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7195
|
+
],
|
|
7196
|
+
[ChainId.BASE.toString()]: [
|
|
7197
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
7198
|
+
"0x4200000000000000000000000000000000000006",
|
|
7199
|
+
"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
|
|
7200
|
+
"0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
|
|
7201
|
+
"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
|
|
7202
|
+
],
|
|
7203
|
+
[ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
|
|
7204
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7205
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7206
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7207
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7208
|
+
],
|
|
7209
|
+
[ChainId.ANVIL.toString()]: [
|
|
7210
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7211
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7212
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7213
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7214
|
+
]
|
|
7215
|
+
};
|
|
6992
7216
|
const oracles = {
|
|
6993
7217
|
[ChainId.ETHEREUM.toString()]: [
|
|
6994
7218
|
"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
|
|
@@ -7048,7 +7272,7 @@ const configs = {
|
|
|
7048
7272
|
//#endregion
|
|
7049
7273
|
//#region src/gatekeeper/ConfigRules.ts
|
|
7050
7274
|
/**
|
|
7051
|
-
* Build the configured rules (maturities + callback addresses + loan tokens + oracles) for the provided chains.
|
|
7275
|
+
* Build the configured rules (maturities + callback addresses + loan tokens + collateral tokens + oracles) for the provided chains.
|
|
7052
7276
|
* @param chains - Chains to include in the configured rules.
|
|
7053
7277
|
* @returns Sorted list of config rules.
|
|
7054
7278
|
*/
|
|
@@ -7068,6 +7292,12 @@ function buildConfigRules(chains) {
|
|
|
7068
7292
|
chain_id: chain.id,
|
|
7069
7293
|
address: normalizeAddress(address)
|
|
7070
7294
|
});
|
|
7295
|
+
const collateralTokens = collateralAssets[chain.id.toString()] ?? [];
|
|
7296
|
+
for (const address of collateralTokens) rules.push({
|
|
7297
|
+
type: "collateral_token",
|
|
7298
|
+
chain_id: chain.id,
|
|
7299
|
+
address: normalizeAddress(address)
|
|
7300
|
+
});
|
|
7071
7301
|
const oracles$2 = oracles[chain.id.toString()] ?? [];
|
|
7072
7302
|
for (const address of oracles$2) rules.push({
|
|
7073
7303
|
type: "oracle",
|
|
@@ -7095,6 +7325,10 @@ function buildConfigRulesChecksum(rules) {
|
|
|
7095
7325
|
hash.update(`callback:${rule.chain_id}:${rule.callback_type}:${rule.address}\n`);
|
|
7096
7326
|
continue;
|
|
7097
7327
|
}
|
|
7328
|
+
if (rule.type === "collateral_token") {
|
|
7329
|
+
hash.update(`collateral_token:${rule.chain_id}:${rule.address}\n`);
|
|
7330
|
+
continue;
|
|
7331
|
+
}
|
|
7098
7332
|
if (rule.type === "oracle") {
|
|
7099
7333
|
hash.update(`oracle:${rule.chain_id}:${rule.address}\n`);
|
|
7100
7334
|
continue;
|
|
@@ -7115,6 +7349,7 @@ function compareConfigRules(left, right) {
|
|
|
7115
7349
|
return left.address.localeCompare(right.address);
|
|
7116
7350
|
}
|
|
7117
7351
|
if (left.type === "loan_token" && right.type === "loan_token") return left.address.localeCompare(right.address);
|
|
7352
|
+
if (left.type === "collateral_token" && right.type === "collateral_token") return left.address.localeCompare(right.address);
|
|
7118
7353
|
if (left.type === "oracle" && right.type === "oracle") return left.address.localeCompare(right.address);
|
|
7119
7354
|
return 0;
|
|
7120
7355
|
}
|
|
@@ -7161,6 +7396,7 @@ function formatCursor(rule) {
|
|
|
7161
7396
|
if (rule.type === "maturity") return `maturity:${rule.chain_id}:${rule.timestamp}:${rule.name}`;
|
|
7162
7397
|
if (rule.type === "callback") return `callback:${rule.chain_id}:${rule.callback_type}:${rule.address.toLowerCase()}`;
|
|
7163
7398
|
if (rule.type === "oracle") return `oracle:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7399
|
+
if (rule.type === "collateral_token") return `collateral_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7164
7400
|
return `loan_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7165
7401
|
}
|
|
7166
7402
|
function parseCursor(cursor) {
|
|
@@ -7193,7 +7429,7 @@ function parseCursor(cursor) {
|
|
|
7193
7429
|
address: parseAddress(addressValue, "Cursor address")
|
|
7194
7430
|
};
|
|
7195
7431
|
}
|
|
7196
|
-
if (type === "loan_token" || type === "oracle") {
|
|
7432
|
+
if (type === "loan_token" || type === "collateral_token" || type === "oracle") {
|
|
7197
7433
|
const addressValue = rest.join(":");
|
|
7198
7434
|
if (!addressValue) throw new BadRequestError(`Cursor must be in the format ${type}:chain_id:address`);
|
|
7199
7435
|
return {
|
|
@@ -7220,7 +7456,7 @@ function parseAddress(address, label) {
|
|
|
7220
7456
|
return address.toLowerCase();
|
|
7221
7457
|
}
|
|
7222
7458
|
function isConfigRuleType(value) {
|
|
7223
|
-
return value === "maturity" || value === "callback" || value === "loan_token" || value === "oracle";
|
|
7459
|
+
return value === "maturity" || value === "callback" || value === "loan_token" || value === "collateral_token" || value === "oracle";
|
|
7224
7460
|
}
|
|
7225
7461
|
function isMaturityType(value) {
|
|
7226
7462
|
return Object.values(MaturityType).includes(value);
|
|
@@ -7567,7 +7803,7 @@ function create$15(config) {
|
|
|
7567
7803
|
assets: offers.assets,
|
|
7568
7804
|
obligationUnits: offers.obligationUnits,
|
|
7569
7805
|
obligationShares: offers.obligationShares,
|
|
7570
|
-
|
|
7806
|
+
tick: offers.tick,
|
|
7571
7807
|
maturity: offers.maturity,
|
|
7572
7808
|
expiry: offers.expiry,
|
|
7573
7809
|
start: offers.start,
|
|
@@ -7587,7 +7823,7 @@ function create$15(config) {
|
|
|
7587
7823
|
assets: BigInt(row.assets),
|
|
7588
7824
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7589
7825
|
obligationShares: BigInt(row.obligationShares),
|
|
7590
|
-
|
|
7826
|
+
tick: row.tick,
|
|
7591
7827
|
maturity: from$16(row.maturity),
|
|
7592
7828
|
expiry: row.expiry,
|
|
7593
7829
|
start: row.start,
|
|
@@ -7669,8 +7905,8 @@ function create$15(config) {
|
|
|
7669
7905
|
const now$2 = now();
|
|
7670
7906
|
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
7671
7907
|
obligationId: offers.obligationId,
|
|
7672
|
-
price: offers.
|
|
7673
|
-
}).from(offers).innerJoin(groups, (0, drizzle_orm.and)((0, drizzle_orm.eq)(offers.groupChainId, groups.chainId), (0, drizzle_orm.eq)(offers.groupMaker, groups.maker), (0, drizzle_orm.eq)(offers.group, groups.group))).leftJoin(validations, (0, drizzle_orm.eq)(offers.hash, validations.offerHash)).leftJoin(status, (0, drizzle_orm.eq)(validations.statusId, status.id)).where((0, drizzle_orm.and)((0, drizzle_orm.inArray)(offers.obligationId, obligationIds), (0, drizzle_orm.eq)(offers.buy, side === "buy"), (0, drizzle_orm.gte)(offers.expiry, now$2), (0, drizzle_orm.gte)(offers.maturity, now$2), (0, drizzle_orm.lte)(offers.start, now$2), drizzle_orm.sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? drizzle_orm.sql`${offers.
|
|
7908
|
+
price: offers.tick
|
|
7909
|
+
}).from(offers).innerJoin(groups, (0, drizzle_orm.and)((0, drizzle_orm.eq)(offers.groupChainId, groups.chainId), (0, drizzle_orm.eq)(offers.groupMaker, groups.maker), (0, drizzle_orm.eq)(offers.group, groups.group))).leftJoin(validations, (0, drizzle_orm.eq)(offers.hash, validations.offerHash)).leftJoin(status, (0, drizzle_orm.eq)(validations.statusId, status.id)).where((0, drizzle_orm.and)((0, drizzle_orm.inArray)(offers.obligationId, obligationIds), (0, drizzle_orm.eq)(offers.buy, side === "buy"), (0, drizzle_orm.gte)(offers.expiry, now$2), (0, drizzle_orm.gte)(offers.maturity, now$2), (0, drizzle_orm.lte)(offers.start, now$2), drizzle_orm.sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? drizzle_orm.sql`${offers.tick} ASC` : drizzle_orm.sql`${offers.tick} DESC`);
|
|
7674
7910
|
const [bestBuys, bestSells] = await Promise.all([query({ side: "buy" }), query({ side: "sell" })]);
|
|
7675
7911
|
const quotes = /* @__PURE__ */ new Map();
|
|
7676
7912
|
for (const row of bestSells) quotes.set(row.obligationId, {
|
|
@@ -7728,16 +7964,57 @@ async function getOffersQuery(db, parameters) {
|
|
|
7728
7964
|
'[]'::jsonb
|
|
7729
7965
|
)`.as("collaterals") }).from(obligationCollateralsV2).innerJoin(oracles$1, drizzle_orm.sql`${obligationCollateralsV2.oracleChainId} = ${oracles$1.chainId}
|
|
7730
7966
|
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).where((0, drizzle_orm.eq)(obligationCollateralsV2.obligationId, offers.obligationId)).as("collaterals_lateral");
|
|
7731
|
-
const
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7967
|
+
const lotBalanceExpr = drizzle_orm.sql`GREATEST(0, LEAST(
|
|
7968
|
+
COALESCE(${positions.balance}, 0)::numeric
|
|
7969
|
+
+ COALESCE((
|
|
7970
|
+
SELECT SUM(${offsets.value}::numeric)
|
|
7971
|
+
FROM ${offsets}
|
|
7972
|
+
WHERE ${offsets.chainId} = ${callbacks.positionChainId}
|
|
7973
|
+
AND LOWER(${offsets.contract}) = LOWER(${callbacks.positionContract})
|
|
7974
|
+
AND LOWER(${offsets.user}) = LOWER(${callbacks.positionUser})
|
|
7975
|
+
), 0)
|
|
7976
|
+
- COALESCE(${lots.lower}::numeric, 0),
|
|
7977
|
+
(COALESCE(${lots.upper}::numeric, 0) - COALESCE(${lots.lower}::numeric, 0))
|
|
7978
|
+
- CASE
|
|
7979
|
+
WHEN ${offers.assets}::numeric > 0
|
|
7980
|
+
THEN COALESCE(${groups.consumed}::numeric, 0)
|
|
7981
|
+
* (COALESCE(${lots.upper}::numeric, 0) - COALESCE(${lots.lower}::numeric, 0))
|
|
7982
|
+
/ ${offers.assets}::numeric
|
|
7983
|
+
ELSE 0
|
|
7984
|
+
END
|
|
7985
|
+
))`;
|
|
7986
|
+
const contributionExpr = drizzle_orm.sql`CASE
|
|
7987
|
+
WHEN ${positions.asset} IS NULL OR ${lots.lower} IS NULL THEN 0
|
|
7988
|
+
ELSE LEAST(COALESCE(${callbacks.amount}::numeric, ${lotBalanceExpr}), ${lotBalanceExpr})
|
|
7989
|
+
END`;
|
|
7990
|
+
const availableExpr = drizzle_orm.sql`COALESCE((
|
|
7991
|
+
SELECT SUM(deduped.contribution)
|
|
7992
|
+
FROM (
|
|
7993
|
+
SELECT DISTINCT ON (
|
|
7994
|
+
${callbacks.positionChainId},
|
|
7995
|
+
LOWER(${callbacks.positionContract}),
|
|
7996
|
+
LOWER(${callbacks.positionUser})
|
|
7997
|
+
)
|
|
7998
|
+
${contributionExpr} AS contribution
|
|
7999
|
+
FROM ${offersCallbacks}
|
|
8000
|
+
INNER JOIN ${callbacks} ON ${offersCallbacks.callbackId} = ${callbacks.id}
|
|
8001
|
+
LEFT JOIN ${positions}
|
|
8002
|
+
ON ${positions.chainId} = ${callbacks.positionChainId}
|
|
8003
|
+
AND LOWER(${positions.contract}) = LOWER(${callbacks.positionContract})
|
|
8004
|
+
AND LOWER(${positions.user}) = LOWER(${callbacks.positionUser})
|
|
8005
|
+
LEFT JOIN ${lots}
|
|
8006
|
+
ON ${lots.chainId} = ${callbacks.positionChainId}
|
|
8007
|
+
AND LOWER(${lots.contract}) = LOWER(${callbacks.positionContract})
|
|
8008
|
+
AND LOWER(${lots.user}) = LOWER(${callbacks.positionUser})
|
|
8009
|
+
AND LOWER(${lots.group}) = LOWER(${offers.group})
|
|
8010
|
+
WHERE ${offersCallbacks.offerHash} = ${offers.hash}
|
|
8011
|
+
ORDER BY
|
|
8012
|
+
${callbacks.positionChainId},
|
|
8013
|
+
LOWER(${callbacks.positionContract}),
|
|
8014
|
+
LOWER(${callbacks.positionUser}),
|
|
8015
|
+
${contributionExpr} DESC
|
|
8016
|
+
) deduped
|
|
8017
|
+
), 0)`;
|
|
7741
8018
|
const rows = (await db.select({
|
|
7742
8019
|
hash: offers.hash,
|
|
7743
8020
|
maker: offers.groupMaker,
|
|
@@ -7745,7 +8022,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7745
8022
|
obligationUnits: offers.obligationUnits,
|
|
7746
8023
|
obligationShares: offers.obligationShares,
|
|
7747
8024
|
consumed: groups.consumed,
|
|
7748
|
-
|
|
8025
|
+
tick: offers.tick,
|
|
7749
8026
|
maturity: offers.maturity,
|
|
7750
8027
|
expiry: offers.expiry,
|
|
7751
8028
|
start: offers.start,
|
|
@@ -7758,22 +8035,22 @@ async function getOffersQuery(db, parameters) {
|
|
|
7758
8035
|
callbackData: offers.callbackData,
|
|
7759
8036
|
collaterals: collateralsLateral.collaterals,
|
|
7760
8037
|
blockNumber: offers.blockNumber,
|
|
7761
|
-
available: drizzle_orm.sql
|
|
8038
|
+
available: drizzle_orm.sql`${availableExpr}::numeric`.as("available"),
|
|
7762
8039
|
takeable: drizzle_orm.sql`FLOOR(GREATEST(0,
|
|
7763
8040
|
CASE WHEN ${offers.buy} = false
|
|
7764
8041
|
THEN ${offers.assets}::numeric - ${groups.consumed}::numeric
|
|
7765
8042
|
ELSE LEAST(
|
|
7766
8043
|
${offers.assets}::numeric - ${groups.consumed}::numeric,
|
|
7767
|
-
|
|
8044
|
+
${availableExpr}::numeric
|
|
7768
8045
|
)
|
|
7769
8046
|
END
|
|
7770
8047
|
))`.as("takeable")
|
|
7771
|
-
}).from(offers).innerJoin(obligations, (0, drizzle_orm.eq)(offers.obligationId, obligations.obligationId)).innerJoin(groups, (0, drizzle_orm.and)((0, drizzle_orm.eq)(offers.groupChainId, groups.chainId), (0, drizzle_orm.eq)(offers.groupMaker, groups.maker), (0, drizzle_orm.eq)(offers.group, groups.group))).innerJoinLateral(collateralsLateral, drizzle_orm.sql`true`).
|
|
8048
|
+
}).from(offers).innerJoin(obligations, (0, drizzle_orm.eq)(offers.obligationId, obligations.obligationId)).innerJoin(groups, (0, drizzle_orm.and)((0, drizzle_orm.eq)(offers.groupChainId, groups.chainId), (0, drizzle_orm.eq)(offers.groupMaker, groups.maker), (0, drizzle_orm.eq)(offers.group, groups.group))).innerJoinLateral(collateralsLateral, drizzle_orm.sql`true`).where((0, drizzle_orm.and)(cursor !== null && cursor !== void 0 ? (0, drizzle_orm.gt)(offers.hash, cursor) : void 0, maker !== void 0 ? (0, drizzle_orm.eq)(offers.groupMaker, maker.toLowerCase()) : void 0, (0, drizzle_orm.gte)(offers.expiry, now), (0, drizzle_orm.gte)(offers.maturity, now), maker === void 0 ? drizzle_orm.sql`GREATEST(0,
|
|
7772
8049
|
CASE WHEN ${offers.buy} = false
|
|
7773
8050
|
THEN ${offers.assets}::numeric - ${groups.consumed}::numeric
|
|
7774
8051
|
ELSE LEAST(
|
|
7775
8052
|
${offers.assets}::numeric - ${groups.consumed}::numeric,
|
|
7776
|
-
|
|
8053
|
+
${availableExpr}::numeric
|
|
7777
8054
|
)
|
|
7778
8055
|
END
|
|
7779
8056
|
) > 0` : void 0)).orderBy((0, drizzle_orm.asc)(offers.hash)).limit(limit)).map((row) => {
|
|
@@ -7783,7 +8060,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7783
8060
|
assets: BigInt(row.assets),
|
|
7784
8061
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7785
8062
|
obligationShares: BigInt(row.obligationShares),
|
|
7786
|
-
|
|
8063
|
+
tick: row.tick,
|
|
7787
8064
|
maturity: from$16(row.maturity),
|
|
7788
8065
|
expiry: row.expiry,
|
|
7789
8066
|
start: row.start,
|
|
@@ -8182,7 +8459,7 @@ async function getOffers(apiClient, parameters) {
|
|
|
8182
8459
|
assets: offerData.assets,
|
|
8183
8460
|
obligation_units: offerData.obligation_units,
|
|
8184
8461
|
obligation_shares: offerData.obligation_shares,
|
|
8185
|
-
|
|
8462
|
+
tick: offerData.tick,
|
|
8186
8463
|
maturity: from$16(offerData.obligation.maturity),
|
|
8187
8464
|
expiry: offerData.expiry,
|
|
8188
8465
|
start: offerData.start,
|
|
@@ -8541,6 +8818,7 @@ function create$12(config) {
|
|
|
8541
8818
|
return {
|
|
8542
8819
|
get: async (parameters) => {
|
|
8543
8820
|
const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT$2 } = parameters;
|
|
8821
|
+
const tickSortDirection = side === "sell" ? "asc" : "desc";
|
|
8544
8822
|
const inputCursor = LevelCursor.decode(cursorString, logger);
|
|
8545
8823
|
if (cursorString != null && inputCursor === null) return {
|
|
8546
8824
|
levels: [],
|
|
@@ -8555,23 +8833,23 @@ function create$12(config) {
|
|
|
8555
8833
|
cursor: inputCursor?.offersCursor ?? void 0,
|
|
8556
8834
|
limit: fetchLimit
|
|
8557
8835
|
});
|
|
8558
|
-
const
|
|
8836
|
+
const tickMap = /* @__PURE__ */ new Map();
|
|
8559
8837
|
for (const row of rows) {
|
|
8560
|
-
const
|
|
8561
|
-
const existing = priceMap.get(priceKey);
|
|
8838
|
+
const existing = tickMap.get(row.tick);
|
|
8562
8839
|
if (existing) {
|
|
8563
8840
|
existing.assets += row.takeable;
|
|
8564
8841
|
existing.count += 1;
|
|
8565
|
-
} else
|
|
8842
|
+
} else tickMap.set(row.tick, {
|
|
8566
8843
|
assets: row.takeable,
|
|
8567
8844
|
count: 1
|
|
8568
8845
|
});
|
|
8569
8846
|
}
|
|
8570
|
-
const levels = Array.from(
|
|
8571
|
-
|
|
8572
|
-
assets:
|
|
8573
|
-
count:
|
|
8847
|
+
const levels = Array.from(tickMap.entries()).map(([tick, level]) => ({
|
|
8848
|
+
tick,
|
|
8849
|
+
assets: level.assets,
|
|
8850
|
+
count: level.count
|
|
8574
8851
|
}));
|
|
8852
|
+
levels.sort((a, b) => tickSortDirection === "asc" ? a.tick - b.tick : b.tick - a.tick);
|
|
8575
8853
|
const paginatedLevels = levels.slice(0, limit);
|
|
8576
8854
|
const hasMore = levels.length > limit || offersNextCursor !== null;
|
|
8577
8855
|
const lastLevel = paginatedLevels[paginatedLevels.length - 1];
|
|
@@ -8617,14 +8895,14 @@ async function _getOffers(db, params) {
|
|
|
8617
8895
|
AND (s.code IS NULL OR s.code = ${Status.VALID})
|
|
8618
8896
|
ORDER BY
|
|
8619
8897
|
o.group_chain_id, o.group_maker, o."group_group",
|
|
8620
|
-
o.
|
|
8898
|
+
o.tick ${priceSortDirection === "asc" ? drizzle_orm.sql`ASC` : drizzle_orm.sql`DESC`}, o.block_number ASC, o.assets DESC, o.hash ASC
|
|
8621
8899
|
),
|
|
8622
8900
|
enriched AS (
|
|
8623
8901
|
SELECT
|
|
8624
8902
|
w.*,
|
|
8625
8903
|
g.consumed, g.chain_id, obl.loan_token,
|
|
8626
8904
|
CASE WHEN ${priceSortDirection === "asc" ? drizzle_orm.sql`TRUE` : drizzle_orm.sql`FALSE`}
|
|
8627
|
-
THEN w.
|
|
8905
|
+
THEN w.tick ELSE -w.tick END AS tick_norm,
|
|
8628
8906
|
w.block_number AS block_norm,
|
|
8629
8907
|
-w.assets AS assets_norm,
|
|
8630
8908
|
w.hash AS hash_norm
|
|
@@ -8641,33 +8919,35 @@ async function _getOffers(db, params) {
|
|
|
8641
8919
|
FROM enriched e
|
|
8642
8920
|
${cursor != null ? drizzle_orm.sql`
|
|
8643
8921
|
WHERE
|
|
8644
|
-
(e.
|
|
8922
|
+
(e.tick_norm, e.block_norm, e.assets_norm, e.hash_norm)
|
|
8645
8923
|
> (
|
|
8646
8924
|
CASE WHEN ${priceSortDirection === "asc" ? drizzle_orm.sql`TRUE` : drizzle_orm.sql`FALSE`}
|
|
8647
|
-
THEN ${cursor.
|
|
8925
|
+
THEN ${cursor.tick}::integer ELSE -${cursor.tick}::integer END,
|
|
8648
8926
|
${cursor.blockNumber},
|
|
8649
8927
|
-${cursor.assets}::numeric,
|
|
8650
8928
|
${cursor.hash}
|
|
8651
8929
|
)` : drizzle_orm.sql``}
|
|
8652
|
-
ORDER BY e.
|
|
8930
|
+
ORDER BY e.tick ${priceSortDirection === "asc" ? drizzle_orm.sql`ASC` : drizzle_orm.sql`DESC`}, e.block_number ASC, e.assets DESC, e.hash ASC
|
|
8653
8931
|
LIMIT ${limit}
|
|
8654
8932
|
),
|
|
8655
|
-
-- Compute sum of offsets per position
|
|
8933
|
+
-- Compute sum of offsets per position and obligation
|
|
8656
8934
|
position_offsets AS (
|
|
8657
8935
|
SELECT
|
|
8658
8936
|
chain_id,
|
|
8659
8937
|
"user",
|
|
8660
8938
|
contract,
|
|
8939
|
+
obligation_id,
|
|
8661
8940
|
SUM(value::numeric) AS total_offset
|
|
8662
8941
|
FROM ${offsets}
|
|
8663
|
-
GROUP BY chain_id, "user", contract
|
|
8942
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
8664
8943
|
),
|
|
8665
|
-
-- Compute position_consumed: sum of consumed from all groups with lots on each position (converted to lot terms)
|
|
8944
|
+
-- Compute position_consumed: sum of consumed from all groups with lots on each position+obligation (converted to lot terms)
|
|
8666
8945
|
position_consumed AS (
|
|
8667
8946
|
SELECT
|
|
8668
8947
|
l.chain_id,
|
|
8669
8948
|
l.contract,
|
|
8670
8949
|
l."user",
|
|
8950
|
+
l.obligation_id,
|
|
8671
8951
|
SUM(
|
|
8672
8952
|
CASE
|
|
8673
8953
|
WHEN wo.assets::numeric > 0
|
|
@@ -8684,7 +8964,7 @@ async function _getOffers(db, params) {
|
|
|
8684
8964
|
ON wo.group_chain_id = g.chain_id
|
|
8685
8965
|
AND LOWER(wo.group_maker) = LOWER(g.maker)
|
|
8686
8966
|
AND wo.group_group = g."group"
|
|
8687
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
8967
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
8688
8968
|
),
|
|
8689
8969
|
-- Compute callback contributions with lot balance
|
|
8690
8970
|
callback_contributions AS (
|
|
@@ -8692,7 +8972,7 @@ async function _getOffers(db, params) {
|
|
|
8692
8972
|
p.hash,
|
|
8693
8973
|
p.obligation_id,
|
|
8694
8974
|
p.assets,
|
|
8695
|
-
p.
|
|
8975
|
+
p.tick,
|
|
8696
8976
|
p.obligation_units,
|
|
8697
8977
|
p.obligation_shares,
|
|
8698
8978
|
p.maturity,
|
|
@@ -8737,6 +9017,7 @@ async function _getOffers(db, params) {
|
|
|
8737
9017
|
AND LOWER(l.contract) = LOWER(c.position_contract)
|
|
8738
9018
|
AND LOWER(l."user") = LOWER(c.position_user)
|
|
8739
9019
|
AND l."group" = p.group_group
|
|
9020
|
+
AND l.obligation_id = p.obligation_id
|
|
8740
9021
|
LEFT JOIN ${positions} pos
|
|
8741
9022
|
ON pos.chain_id = c.position_chain_id
|
|
8742
9023
|
AND LOWER(pos.contract) = LOWER(c.position_contract)
|
|
@@ -8745,10 +9026,12 @@ async function _getOffers(db, params) {
|
|
|
8745
9026
|
ON pos_offsets.chain_id = c.position_chain_id
|
|
8746
9027
|
AND LOWER(pos_offsets.contract) = LOWER(c.position_contract)
|
|
8747
9028
|
AND LOWER(pos_offsets."user") = LOWER(c.position_user)
|
|
9029
|
+
AND pos_offsets.obligation_id = p.obligation_id
|
|
8748
9030
|
LEFT JOIN position_consumed pc
|
|
8749
9031
|
ON pc.chain_id = c.position_chain_id
|
|
8750
9032
|
AND LOWER(pc.contract) = LOWER(c.position_contract)
|
|
8751
9033
|
AND LOWER(pc."user") = LOWER(c.position_user)
|
|
9034
|
+
AND pc.obligation_id = p.obligation_id
|
|
8752
9035
|
),
|
|
8753
9036
|
-- Compute contribution per callback in loan terms (loan token only — collateral positions are not indexed)
|
|
8754
9037
|
callback_loan_contribution AS (
|
|
@@ -8766,7 +9049,7 @@ async function _getOffers(db, params) {
|
|
|
8766
9049
|
hash,
|
|
8767
9050
|
obligation_id,
|
|
8768
9051
|
assets,
|
|
8769
|
-
|
|
9052
|
+
tick,
|
|
8770
9053
|
obligation_units,
|
|
8771
9054
|
obligation_shares,
|
|
8772
9055
|
maturity,
|
|
@@ -8792,13 +9075,13 @@ async function _getOffers(db, params) {
|
|
|
8792
9075
|
WHERE clc.callback_id IS NOT NULL
|
|
8793
9076
|
ORDER BY clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user, clc.contribution_in_loan DESC
|
|
8794
9077
|
) deduped
|
|
8795
|
-
GROUP BY hash, obligation_id, assets,
|
|
9078
|
+
GROUP BY hash, obligation_id, assets, tick, obligation_units, obligation_shares, maturity, expiry, start, group_group, buy,
|
|
8796
9079
|
callback_address, callback_data, block_number, group_chain_id, group_maker,
|
|
8797
9080
|
consumed, chain_id, loan_token, session
|
|
8798
9081
|
UNION ALL
|
|
8799
9082
|
-- Sell offers without callbacks: collateral positions not indexed, takeable = assets - consumed
|
|
8800
9083
|
SELECT
|
|
8801
|
-
p.hash, p.obligation_id, p.assets, p.
|
|
9084
|
+
p.hash, p.obligation_id, p.assets, p.tick,
|
|
8802
9085
|
p.obligation_units, p.obligation_shares,
|
|
8803
9086
|
p.maturity, p.expiry, p.start, p.group_group,
|
|
8804
9087
|
p.buy, p.callback_address, p.callback_data,
|
|
@@ -8820,7 +9103,7 @@ async function _getOffers(db, params) {
|
|
|
8820
9103
|
oc.obligation_units,
|
|
8821
9104
|
oc.obligation_shares,
|
|
8822
9105
|
oc.consumed,
|
|
8823
|
-
oc.
|
|
9106
|
+
oc.tick,
|
|
8824
9107
|
oc.maturity,
|
|
8825
9108
|
oc.expiry,
|
|
8826
9109
|
oc.start,
|
|
@@ -8852,7 +9135,7 @@ async function _getOffers(db, params) {
|
|
|
8852
9135
|
))
|
|
8853
9136
|
END > 0
|
|
8854
9137
|
ORDER BY
|
|
8855
|
-
oc.
|
|
9138
|
+
oc.tick ${priceSortDirection === "asc" ? drizzle_orm.sql`ASC` : drizzle_orm.sql`DESC`},
|
|
8856
9139
|
oc.block_number ASC,
|
|
8857
9140
|
oc.assets DESC,
|
|
8858
9141
|
oc.hash ASC;
|
|
@@ -8865,7 +9148,7 @@ async function _getOffers(db, params) {
|
|
|
8865
9148
|
assets: BigInt(row.assets),
|
|
8866
9149
|
obligationUnits: BigInt(row.obligation_units ?? 0),
|
|
8867
9150
|
obligationShares: BigInt(row.obligation_shares ?? 0),
|
|
8868
|
-
|
|
9151
|
+
tick: row.tick,
|
|
8869
9152
|
maturity: row.maturity,
|
|
8870
9153
|
expiry: row.expiry,
|
|
8871
9154
|
start: row.start,
|
|
@@ -8897,7 +9180,7 @@ let Cursor;
|
|
|
8897
9180
|
function encode(row, totalReturned, now, side) {
|
|
8898
9181
|
return Buffer.from(JSON.stringify({
|
|
8899
9182
|
side,
|
|
8900
|
-
|
|
9183
|
+
tick: row.tick,
|
|
8901
9184
|
blockNumber: row.blockNumber,
|
|
8902
9185
|
assets: row.assets.toString(),
|
|
8903
9186
|
hash: row.hash,
|
|
@@ -8908,10 +9191,9 @@ let Cursor;
|
|
|
8908
9191
|
_Cursor.encode = encode;
|
|
8909
9192
|
function decode(cursorString, logger) {
|
|
8910
9193
|
if (cursorString == null) return null;
|
|
8911
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
8912
9194
|
try {
|
|
8913
9195
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
8914
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
9196
|
+
if ((v?.side === "buy" || v?.side === "sell") && typeof v?.tick === "number" && Number.isInteger(v.tick) && typeof v?.blockNumber === "number" && Number.isInteger(v.blockNumber) && typeof v?.assets === "string" && /^-?\d+$/.test(v.assets) && (0, viem.isHex)(v?.hash) && typeof v?.totalReturned === "number" && Number.isInteger(v.totalReturned) && typeof v?.now === "number" && Number.isInteger(v.now)) return v;
|
|
8915
9197
|
throw new Error("Invalid cursor");
|
|
8916
9198
|
} catch {
|
|
8917
9199
|
logger.error({
|
|
@@ -8929,7 +9211,7 @@ let LevelCursor;
|
|
|
8929
9211
|
function encode(lastLevel, offersCursor, side, now) {
|
|
8930
9212
|
return Buffer.from(JSON.stringify({
|
|
8931
9213
|
side,
|
|
8932
|
-
|
|
9214
|
+
lastTick: lastLevel.tick,
|
|
8933
9215
|
now,
|
|
8934
9216
|
offersCursor
|
|
8935
9217
|
})).toString("base64url");
|
|
@@ -8937,10 +9219,9 @@ let LevelCursor;
|
|
|
8937
9219
|
_LevelCursor.encode = encode;
|
|
8938
9220
|
function decode(cursorString, logger) {
|
|
8939
9221
|
if (cursorString == null) return null;
|
|
8940
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
8941
9222
|
try {
|
|
8942
9223
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
8943
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
9224
|
+
if ((v?.side === "buy" || v?.side === "sell") && typeof v?.lastTick === "number" && Number.isInteger(v.lastTick) && typeof v?.now === "number" && Number.isInteger(v.now) && (v?.offersCursor === null || typeof v?.offersCursor === "string")) return v;
|
|
8944
9225
|
throw new Error("Invalid book cursor");
|
|
8945
9226
|
} catch {
|
|
8946
9227
|
logger.error({
|
|
@@ -9083,31 +9364,33 @@ function create$9(db) {
|
|
|
9083
9364
|
function create$8(db) {
|
|
9084
9365
|
return {
|
|
9085
9366
|
get: async (parameters) => {
|
|
9086
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9367
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9087
9368
|
const conditions = [];
|
|
9088
9369
|
if (chainId !== void 0) conditions.push((0, drizzle_orm.eq)(lots.chainId, chainId));
|
|
9089
9370
|
if (user !== void 0) conditions.push((0, drizzle_orm.eq)(lots.user, user.toLowerCase()));
|
|
9090
9371
|
if (contract !== void 0) conditions.push((0, drizzle_orm.eq)(lots.contract, contract.toLowerCase()));
|
|
9091
9372
|
if (group !== void 0) conditions.push((0, drizzle_orm.eq)(lots.group, group));
|
|
9373
|
+
if (obligationId !== void 0) conditions.push((0, drizzle_orm.eq)(lots.obligationId, obligationId));
|
|
9092
9374
|
return (await db.select().from(lots).where(conditions.length > 0 ? (0, drizzle_orm.and)(...conditions) : void 0)).map((row) => ({
|
|
9093
9375
|
chainId: row.chainId,
|
|
9094
9376
|
user: row.user,
|
|
9095
9377
|
contract: row.contract,
|
|
9096
9378
|
group: row.group,
|
|
9379
|
+
obligationId: row.obligationId,
|
|
9097
9380
|
lower: BigInt(row.lower),
|
|
9098
9381
|
upper: BigInt(row.upper)
|
|
9099
9382
|
}));
|
|
9100
9383
|
},
|
|
9101
9384
|
create: async (parameters) => {
|
|
9102
9385
|
if (parameters.length === 0) return;
|
|
9103
|
-
const
|
|
9386
|
+
const lotsByKey = /* @__PURE__ */ new Map();
|
|
9104
9387
|
for (const offer of parameters) {
|
|
9105
|
-
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}`.toLowerCase();
|
|
9106
|
-
const existing =
|
|
9107
|
-
if (!existing || offer.size > existing.size)
|
|
9388
|
+
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}-${offer.obligationId}`.toLowerCase();
|
|
9389
|
+
const existing = lotsByKey.get(key);
|
|
9390
|
+
if (!existing || offer.size > existing.size) lotsByKey.set(key, offer);
|
|
9108
9391
|
}
|
|
9109
|
-
for (const offer of
|
|
9110
|
-
const maxUpperResult = await db.select({ maxUpper: drizzle_orm.sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(lots.chainId, offer.positionChainId), (0, drizzle_orm.eq)(lots.contract, offer.positionContract.toLowerCase()), (0, drizzle_orm.eq)(lots.user, offer.positionUser.toLowerCase())));
|
|
9392
|
+
for (const offer of lotsByKey.values()) if ((await db.select().from(lots).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(lots.chainId, offer.positionChainId), (0, drizzle_orm.eq)(lots.contract, offer.positionContract.toLowerCase()), (0, drizzle_orm.eq)(lots.user, offer.positionUser.toLowerCase()), (0, drizzle_orm.eq)(lots.group, offer.group.toLowerCase()), (0, drizzle_orm.eq)(lots.obligationId, offer.obligationId.toLowerCase()))).limit(1)).length === 0) {
|
|
9393
|
+
const maxUpperResult = await db.select({ maxUpper: drizzle_orm.sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(lots.chainId, offer.positionChainId), (0, drizzle_orm.eq)(lots.contract, offer.positionContract.toLowerCase()), (0, drizzle_orm.eq)(lots.user, offer.positionUser.toLowerCase()), (0, drizzle_orm.eq)(lots.obligationId, offer.obligationId.toLowerCase())));
|
|
9111
9394
|
const newLower = BigInt(maxUpperResult[0]?.maxUpper ?? "0");
|
|
9112
9395
|
const newUpper = newLower + offer.size;
|
|
9113
9396
|
await db.insert(lots).values({
|
|
@@ -9115,6 +9398,7 @@ function create$8(db) {
|
|
|
9115
9398
|
user: offer.positionUser.toLowerCase(),
|
|
9116
9399
|
contract: offer.positionContract.toLowerCase(),
|
|
9117
9400
|
group: offer.group.toLowerCase(),
|
|
9401
|
+
obligationId: offer.obligationId.toLowerCase(),
|
|
9118
9402
|
lower: newLower.toString(),
|
|
9119
9403
|
upper: newUpper.toString()
|
|
9120
9404
|
});
|
|
@@ -9169,17 +9453,19 @@ function create$7(db) {
|
|
|
9169
9453
|
//#region src/database/domains/Offsets.ts
|
|
9170
9454
|
function create$6(db) {
|
|
9171
9455
|
return { get: async (parameters) => {
|
|
9172
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9456
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9173
9457
|
const conditions = [];
|
|
9174
9458
|
if (chainId !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.chainId, chainId));
|
|
9175
9459
|
if (user !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.user, user.toLowerCase()));
|
|
9176
9460
|
if (contract !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.contract, contract.toLowerCase()));
|
|
9177
9461
|
if (group !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.group, group));
|
|
9462
|
+
if (obligationId !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.obligationId, obligationId));
|
|
9178
9463
|
return (await db.select().from(offsets).where(conditions.length > 0 ? (0, drizzle_orm.and)(...conditions) : void 0)).map((row) => ({
|
|
9179
9464
|
chainId: row.chainId,
|
|
9180
9465
|
user: row.user,
|
|
9181
9466
|
contract: row.contract,
|
|
9182
9467
|
group: row.group,
|
|
9468
|
+
obligationId: row.obligationId,
|
|
9183
9469
|
value: BigInt(row.value)
|
|
9184
9470
|
}));
|
|
9185
9471
|
} };
|
|
@@ -9329,7 +9615,8 @@ const create$4 = (db) => {
|
|
|
9329
9615
|
if (!parsed.chainId || !parsed.contract) throw new Error("Invalid cursor format");
|
|
9330
9616
|
cursor = {
|
|
9331
9617
|
chainId: parsed.chainId,
|
|
9332
|
-
contract: parsed.contract
|
|
9618
|
+
contract: parsed.contract,
|
|
9619
|
+
obligationId: parsed.obligationId ?? null
|
|
9333
9620
|
};
|
|
9334
9621
|
}
|
|
9335
9622
|
const raw = await db.execute(drizzle_orm.sql`
|
|
@@ -9338,16 +9625,18 @@ const create$4 = (db) => {
|
|
|
9338
9625
|
chain_id,
|
|
9339
9626
|
"user",
|
|
9340
9627
|
contract,
|
|
9628
|
+
obligation_id,
|
|
9341
9629
|
SUM(value::numeric) AS total_offset
|
|
9342
9630
|
FROM ${offsets}
|
|
9343
9631
|
WHERE LOWER("user") = LOWER(${user})
|
|
9344
|
-
GROUP BY chain_id, "user", contract
|
|
9632
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
9345
9633
|
),
|
|
9346
9634
|
position_consumed AS (
|
|
9347
9635
|
SELECT
|
|
9348
9636
|
l.chain_id,
|
|
9349
9637
|
l.contract,
|
|
9350
9638
|
l."user",
|
|
9639
|
+
l.obligation_id,
|
|
9351
9640
|
SUM(
|
|
9352
9641
|
CASE
|
|
9353
9642
|
WHEN offer_agg.assets > 0
|
|
@@ -9373,50 +9662,64 @@ const create$4 = (db) => {
|
|
|
9373
9662
|
AND LOWER(offer_agg.group_maker) = LOWER(g.maker)
|
|
9374
9663
|
AND offer_agg."group_group" = g."group"
|
|
9375
9664
|
WHERE LOWER(l."user") = LOWER(${user})
|
|
9376
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
9665
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
9377
9666
|
),
|
|
9378
9667
|
position_max_lot AS (
|
|
9379
9668
|
SELECT
|
|
9380
9669
|
chain_id,
|
|
9381
9670
|
contract,
|
|
9382
9671
|
"user",
|
|
9672
|
+
obligation_id,
|
|
9383
9673
|
MAX(upper::numeric) AS max_upper
|
|
9384
9674
|
FROM ${lots}
|
|
9385
9675
|
WHERE LOWER("user") = LOWER(${user})
|
|
9386
|
-
GROUP BY chain_id, contract, "user"
|
|
9676
|
+
GROUP BY chain_id, contract, "user", obligation_id
|
|
9677
|
+
),
|
|
9678
|
+
per_obligation AS (
|
|
9679
|
+
SELECT
|
|
9680
|
+
pml.chain_id,
|
|
9681
|
+
pml.contract,
|
|
9682
|
+
pml."user",
|
|
9683
|
+
pml.obligation_id,
|
|
9684
|
+
GREATEST(0,
|
|
9685
|
+
COALESCE(pml.max_upper, 0)
|
|
9686
|
+
- COALESCE(po.total_offset, 0)
|
|
9687
|
+
- COALESCE(pc.consumed, 0)
|
|
9688
|
+
)::text AS reserved_balance
|
|
9689
|
+
FROM position_max_lot pml
|
|
9690
|
+
LEFT JOIN position_offsets po
|
|
9691
|
+
ON po.chain_id = pml.chain_id
|
|
9692
|
+
AND LOWER(po.contract) = LOWER(pml.contract)
|
|
9693
|
+
AND LOWER(po."user") = LOWER(pml."user")
|
|
9694
|
+
AND po.obligation_id = pml.obligation_id
|
|
9695
|
+
LEFT JOIN position_consumed pc
|
|
9696
|
+
ON pc.chain_id = pml.chain_id
|
|
9697
|
+
AND LOWER(pc.contract) = LOWER(pml.contract)
|
|
9698
|
+
AND LOWER(pc."user") = LOWER(pml."user")
|
|
9699
|
+
AND pc.obligation_id = pml.obligation_id
|
|
9387
9700
|
)
|
|
9388
9701
|
SELECT
|
|
9389
9702
|
p.chain_id,
|
|
9390
9703
|
p.contract,
|
|
9391
9704
|
p."user",
|
|
9392
9705
|
p.block_number,
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
- COALESCE(po.total_offset, 0)
|
|
9396
|
-
- COALESCE(pc.consumed, 0)
|
|
9397
|
-
)::text AS reserved_balance
|
|
9706
|
+
po.obligation_id,
|
|
9707
|
+
COALESCE(po.reserved_balance, '0') AS reserved_balance
|
|
9398
9708
|
FROM ${positions} p
|
|
9399
|
-
LEFT JOIN
|
|
9709
|
+
LEFT JOIN per_obligation po
|
|
9400
9710
|
ON po.chain_id = p.chain_id
|
|
9401
9711
|
AND LOWER(po.contract) = LOWER(p.contract)
|
|
9402
9712
|
AND LOWER(po."user") = LOWER(p."user")
|
|
9403
|
-
LEFT JOIN position_consumed pc
|
|
9404
|
-
ON pc.chain_id = p.chain_id
|
|
9405
|
-
AND LOWER(pc.contract) = LOWER(p.contract)
|
|
9406
|
-
AND LOWER(pc."user") = LOWER(p."user")
|
|
9407
|
-
LEFT JOIN position_max_lot pml
|
|
9408
|
-
ON pml.chain_id = p.chain_id
|
|
9409
|
-
AND LOWER(pml.contract) = LOWER(p.contract)
|
|
9410
|
-
AND LOWER(pml."user") = LOWER(p."user")
|
|
9411
9713
|
WHERE LOWER(p."user") = LOWER(${user})
|
|
9412
9714
|
AND p."user" != ${viem.zeroAddress}
|
|
9413
|
-
${cursor !== null ? drizzle_orm.sql`AND (p.chain_id, p.contract) > (${cursor.chainId}, ${cursor.contract})` : drizzle_orm.sql``}
|
|
9414
|
-
ORDER BY p.chain_id ASC, p.contract ASC
|
|
9715
|
+
${cursor !== null ? drizzle_orm.sql`AND (p.chain_id, p.contract, COALESCE(po.obligation_id, '')) > (${cursor.chainId}, ${cursor.contract}, ${cursor.obligationId ?? ""})` : drizzle_orm.sql``}
|
|
9716
|
+
ORDER BY p.chain_id ASC, p.contract ASC, po.obligation_id ASC NULLS FIRST
|
|
9415
9717
|
LIMIT ${limit}
|
|
9416
9718
|
`);
|
|
9417
9719
|
const nextCursor = raw.rows.length === limit ? Buffer.from(JSON.stringify({
|
|
9418
9720
|
chainId: raw.rows[raw.rows.length - 1].chain_id.toString(),
|
|
9419
|
-
contract: raw.rows[raw.rows.length - 1].contract
|
|
9721
|
+
contract: raw.rows[raw.rows.length - 1].contract,
|
|
9722
|
+
obligationId: raw.rows[raw.rows.length - 1].obligation_id
|
|
9420
9723
|
})).toString("base64url") : null;
|
|
9421
9724
|
return {
|
|
9422
9725
|
positions: raw.rows.map((row) => ({
|
|
@@ -9424,6 +9727,7 @@ const create$4 = (db) => {
|
|
|
9424
9727
|
contract: row.contract,
|
|
9425
9728
|
user: row.user,
|
|
9426
9729
|
blockNumber: row.block_number,
|
|
9730
|
+
obligationId: row.obligation_id,
|
|
9427
9731
|
reserved: BigInt(row.reserved_balance.split(".")[0] ?? "0")
|
|
9428
9732
|
})),
|
|
9429
9733
|
nextCursor
|
|
@@ -9702,7 +10006,10 @@ function create$1(db) {
|
|
|
9702
10006
|
|
|
9703
10007
|
//#endregion
|
|
9704
10008
|
//#region src/database/Database.ts
|
|
9705
|
-
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
10009
|
+
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
10010
|
+
connect: () => connect$1,
|
|
10011
|
+
getSchemaNamesForMigration: () => getSchemaNamesForMigration
|
|
10012
|
+
});
|
|
9706
10013
|
function createDomains(core, chainRegistry) {
|
|
9707
10014
|
return {
|
|
9708
10015
|
book: create$12({ db: core }),
|
|
@@ -9799,6 +10106,7 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9799
10106
|
return wrapped;
|
|
9800
10107
|
}
|
|
9801
10108
|
const InMemoryDbMap = /* @__PURE__ */ new Map();
|
|
10109
|
+
const LEGACY_SCHEMA_START_MINOR = 7;
|
|
9802
10110
|
/**
|
|
9803
10111
|
* Connect to the database.
|
|
9804
10112
|
* @notice If no connection string is provided, an in-process PGLite database is created.
|
|
@@ -9853,9 +10161,26 @@ function applyMigrations(kind, driver) {
|
|
|
9853
10161
|
async function preMigrate(driver) {
|
|
9854
10162
|
const tracer = getTracer("db.preMigrate");
|
|
9855
10163
|
await startActiveSpan(tracer, "db.preMigrate", async () => {
|
|
9856
|
-
|
|
10164
|
+
const schemaNames = getSchemaNamesForMigration(VERSION);
|
|
10165
|
+
for (const schemaName of schemaNames) await driver.execute(`create schema if not exists "${schemaName}"`);
|
|
9857
10166
|
});
|
|
9858
10167
|
}
|
|
10168
|
+
/**
|
|
10169
|
+
* Build the list of router schemas that should exist before running migrations.
|
|
10170
|
+
* @param version - Current schema version (e.g. `router_v1.8`).
|
|
10171
|
+
* @returns Ordered schema names from `router_v1.7` to current, or just current if parsing fails.
|
|
10172
|
+
*/
|
|
10173
|
+
function getSchemaNamesForMigration(version) {
|
|
10174
|
+
const parsed = /^router_v(?<major>\d+)\.(?<minor>\d+)$/.exec(version);
|
|
10175
|
+
if (!parsed?.groups?.major || !parsed.groups.minor) return [version];
|
|
10176
|
+
const major = Number.parseInt(parsed.groups.major, 10);
|
|
10177
|
+
const currentMinor = Number.parseInt(parsed.groups.minor, 10);
|
|
10178
|
+
if (!Number.isInteger(major) || !Number.isInteger(currentMinor)) return [version];
|
|
10179
|
+
if (currentMinor < LEGACY_SCHEMA_START_MINOR) return [version];
|
|
10180
|
+
const schemaNames = [];
|
|
10181
|
+
for (let minor = LEGACY_SCHEMA_START_MINOR; minor <= currentMinor; minor += 1) schemaNames.push(`router_v${major}.${minor}`);
|
|
10182
|
+
return schemaNames;
|
|
10183
|
+
}
|
|
9859
10184
|
async function postMigrate(driver) {
|
|
9860
10185
|
const tracer = getTracer("db.postMigrate");
|
|
9861
10186
|
await startActiveSpan(tracer, "db.postMigrate", async () => {
|
|
@@ -10125,15 +10450,16 @@ async function postMigrate(driver) {
|
|
|
10125
10450
|
RETURNS trigger
|
|
10126
10451
|
LANGUAGE plpgsql AS $$
|
|
10127
10452
|
BEGIN
|
|
10128
|
-
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", value)
|
|
10453
|
+
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", obligation_id, value)
|
|
10129
10454
|
VALUES (
|
|
10130
10455
|
OLD.chain_id,
|
|
10131
10456
|
OLD."user",
|
|
10132
10457
|
OLD.contract,
|
|
10133
10458
|
OLD."group",
|
|
10459
|
+
OLD.obligation_id,
|
|
10134
10460
|
OLD.upper::numeric - OLD.lower::numeric
|
|
10135
10461
|
)
|
|
10136
|
-
ON CONFLICT (chain_id, "user", contract, "group") DO NOTHING;
|
|
10462
|
+
ON CONFLICT (chain_id, "user", contract, "group", obligation_id) DO NOTHING;
|
|
10137
10463
|
RETURN OLD;
|
|
10138
10464
|
END;
|
|
10139
10465
|
$$;
|
|
@@ -10387,10 +10713,11 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
|
10387
10713
|
amountMutualExclusivity: () => amountMutualExclusivity,
|
|
10388
10714
|
callback: () => callback,
|
|
10389
10715
|
chains: () => chains,
|
|
10716
|
+
collateralToken: () => collateralToken,
|
|
10717
|
+
loanToken: () => loanToken,
|
|
10390
10718
|
maturity: () => maturity,
|
|
10391
10719
|
oracle: () => oracle,
|
|
10392
10720
|
sameMaker: () => sameMaker,
|
|
10393
|
-
token: () => token,
|
|
10394
10721
|
validity: () => validity
|
|
10395
10722
|
});
|
|
10396
10723
|
/**
|
|
@@ -10418,15 +10745,25 @@ const callback = ({ callbacks }) => single("callback", `Validates callbacks: buy
|
|
|
10418
10745
|
if (isEmptyCallback(offer) && !offer.buy && !callbacks.includes(Type$1.SellWithEmptyCallback)) return { message: "Sell offers with empty callback not allowed." };
|
|
10419
10746
|
});
|
|
10420
10747
|
/**
|
|
10421
|
-
* A validation rule that checks if the offer's
|
|
10422
|
-
* @param assetsByChainId - Allowed
|
|
10748
|
+
* A validation rule that checks if the offer's loan token is allowed for its chain.
|
|
10749
|
+
* @param assetsByChainId - Allowed loan tokens indexed by chain id.
|
|
10423
10750
|
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
10424
10751
|
*/
|
|
10425
|
-
const
|
|
10426
|
-
const
|
|
10427
|
-
if (!
|
|
10428
|
-
if (!
|
|
10429
|
-
|
|
10752
|
+
const loanToken = ({ assetsByChainId }) => single("loan_token", "Validates that offer loan token is in the allowed token list for the offer chain", (offer) => {
|
|
10753
|
+
const allowedLoanTokens = assetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase());
|
|
10754
|
+
if (!allowedLoanTokens || allowedLoanTokens.length === 0) return { message: `No allowed loan tokens for chain ${offer.chainId}` };
|
|
10755
|
+
if (!allowedLoanTokens.includes(offer.loanToken.toLowerCase())) return { message: "Loan token is not allowed" };
|
|
10756
|
+
});
|
|
10757
|
+
/**
|
|
10758
|
+
* A validation rule that checks if the offer's collateral tokens are allowed for its chain.
|
|
10759
|
+
* @param collateralAssetsByChainId - Allowed collateral tokens indexed by chain id.
|
|
10760
|
+
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
10761
|
+
*/
|
|
10762
|
+
const collateralToken = ({ collateralAssetsByChainId }) => single("collateral_token", "Validates that offer collateral tokens are in the allowed token list for the offer chain", (offer) => {
|
|
10763
|
+
const allowedCollateralTokens = collateralAssetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase()) ?? [];
|
|
10764
|
+
if (allowedCollateralTokens.length === 0) return { message: `No allowed collateral tokens for chain ${offer.chainId}` };
|
|
10765
|
+
if (offer.collaterals.length === 0) return { message: "At least one collateral token is required" };
|
|
10766
|
+
if (offer.collaterals.some((collateral) => !allowedCollateralTokens.includes(collateral.asset.toLowerCase()))) return { message: "Collateral token is not allowed" };
|
|
10430
10767
|
});
|
|
10431
10768
|
/**
|
|
10432
10769
|
* A validation rule that checks if the offer's oracle addresses are allowed for its chain.
|
|
@@ -10469,9 +10806,11 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
|
|
|
10469
10806
|
//#region src/gatekeeper/morphoRules.ts
|
|
10470
10807
|
const morphoRules = (chains$3) => {
|
|
10471
10808
|
const assetsByChainId = {};
|
|
10809
|
+
const collateralAssetsByChainId = {};
|
|
10472
10810
|
const oraclesByChainId = {};
|
|
10473
10811
|
for (const chain of chains$3) {
|
|
10474
10812
|
assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
|
|
10813
|
+
collateralAssetsByChainId[chain.id] = collateralAssets[chain.id.toString()] ?? [];
|
|
10475
10814
|
oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
|
|
10476
10815
|
}
|
|
10477
10816
|
return [
|
|
@@ -10483,7 +10822,8 @@ const morphoRules = (chains$3) => {
|
|
|
10483
10822
|
callbacks: [Type$1.BuyWithEmptyCallback, Type$1.SellWithEmptyCallback],
|
|
10484
10823
|
allowedAddresses: []
|
|
10485
10824
|
}),
|
|
10486
|
-
|
|
10825
|
+
loanToken({ assetsByChainId }),
|
|
10826
|
+
collateralToken({ collateralAssetsByChainId }),
|
|
10487
10827
|
oracle({ oraclesByChainId })
|
|
10488
10828
|
];
|
|
10489
10829
|
};
|
|
@@ -10895,6 +11235,12 @@ Object.defineProperty(exports, 'Rules', {
|
|
|
10895
11235
|
return Rules_exports;
|
|
10896
11236
|
}
|
|
10897
11237
|
});
|
|
11238
|
+
Object.defineProperty(exports, 'Tick', {
|
|
11239
|
+
enumerable: true,
|
|
11240
|
+
get: function () {
|
|
11241
|
+
return Tick_exports;
|
|
11242
|
+
}
|
|
11243
|
+
});
|
|
10898
11244
|
Object.defineProperty(exports, 'Time', {
|
|
10899
11245
|
enumerable: true,
|
|
10900
11246
|
get: function () {
|