@morpho-dev/router 0.7.2 → 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 +292 -122
- 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/index.browser.d.mts +103 -33
- package/dist/index.browser.d.mts.map +1 -1
- package/dist/index.browser.d.ts +103 -33
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +298 -146
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +293 -147
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.mts +182 -63
- package/dist/index.node.d.mts.map +1 -1
- package/dist/index.node.d.ts +182 -63
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +342 -127
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +337 -128
- package/dist/index.node.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.node.js
CHANGED
|
@@ -2122,7 +2122,7 @@ const OfferSchema = () => {
|
|
|
2122
2122
|
assets: zod.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
2123
2123
|
obligationUnits: zod.bigint({ coerce: true }).min(0n).max(viem.maxUint256).optional().default(0n),
|
|
2124
2124
|
obligationShares: zod.bigint({ coerce: true }).min(0n).max(viem.maxUint256).optional().default(0n),
|
|
2125
|
-
|
|
2125
|
+
tick: zod.coerce.number().int().min(0).max(990),
|
|
2126
2126
|
maturity: MaturitySchema,
|
|
2127
2127
|
expiry: zod.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
2128
2128
|
start: zod.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
@@ -2194,7 +2194,7 @@ const serialize = (offer) => ({
|
|
|
2194
2194
|
assets: offer.assets.toString(),
|
|
2195
2195
|
obligationUnits: offer.obligationUnits.toString(),
|
|
2196
2196
|
obligationShares: offer.obligationShares.toString(),
|
|
2197
|
-
|
|
2197
|
+
tick: offer.tick,
|
|
2198
2198
|
maturity: Number(offer.maturity),
|
|
2199
2199
|
expiry: Number(offer.expiry),
|
|
2200
2200
|
start: Number(offer.start),
|
|
@@ -2239,14 +2239,13 @@ function random$1(config) {
|
|
|
2239
2239
|
[.98, 2]
|
|
2240
2240
|
]));
|
|
2241
2241
|
const buy = config?.buy !== void 0 ? config.buy : bool();
|
|
2242
|
-
const
|
|
2243
|
-
const
|
|
2244
|
-
const
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
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];
|
|
2248
2247
|
});
|
|
2249
|
-
const
|
|
2248
|
+
const tick = config?.tick ?? weightedChoice(tickPairs);
|
|
2250
2249
|
const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
|
|
2251
2250
|
const unit = BigInt(10) ** BigInt(loanTokenDecimals);
|
|
2252
2251
|
const amountBase = BigInt(100 + int(999901));
|
|
@@ -2260,7 +2259,7 @@ function random$1(config) {
|
|
|
2260
2259
|
assets: assetsScaled,
|
|
2261
2260
|
obligationUnits: config?.obligationUnits ?? 0n,
|
|
2262
2261
|
obligationShares: config?.obligationShares ?? 0n,
|
|
2263
|
-
|
|
2262
|
+
tick,
|
|
2264
2263
|
maturity,
|
|
2265
2264
|
expiry: config?.expiry ?? maturity - 1,
|
|
2266
2265
|
start: config?.start ?? maturity - 10,
|
|
@@ -2325,7 +2324,7 @@ const types = {
|
|
|
2325
2324
|
type: "uint256"
|
|
2326
2325
|
},
|
|
2327
2326
|
{
|
|
2328
|
-
name: "
|
|
2327
|
+
name: "tick",
|
|
2329
2328
|
type: "uint256"
|
|
2330
2329
|
},
|
|
2331
2330
|
{
|
|
@@ -2393,7 +2392,7 @@ function hash(offer) {
|
|
|
2393
2392
|
assets: offer.assets,
|
|
2394
2393
|
obligationUnits: offer.obligationUnits,
|
|
2395
2394
|
obligationShares: offer.obligationShares,
|
|
2396
|
-
|
|
2395
|
+
tick: BigInt(offer.tick),
|
|
2397
2396
|
maturity: BigInt(offer.maturity),
|
|
2398
2397
|
expiry: BigInt(offer.expiry),
|
|
2399
2398
|
group: offer.group,
|
|
@@ -2444,7 +2443,7 @@ const OfferAbi = [
|
|
|
2444
2443
|
type: "uint256"
|
|
2445
2444
|
},
|
|
2446
2445
|
{
|
|
2447
|
-
name: "
|
|
2446
|
+
name: "tick",
|
|
2448
2447
|
type: "uint256"
|
|
2449
2448
|
},
|
|
2450
2449
|
{
|
|
@@ -2515,7 +2514,7 @@ function encode$1(offer) {
|
|
|
2515
2514
|
offer.assets,
|
|
2516
2515
|
offer.obligationUnits,
|
|
2517
2516
|
offer.obligationShares,
|
|
2518
|
-
offer.
|
|
2517
|
+
BigInt(offer.tick),
|
|
2519
2518
|
BigInt(offer.maturity),
|
|
2520
2519
|
BigInt(offer.expiry),
|
|
2521
2520
|
offer.group,
|
|
@@ -2540,7 +2539,7 @@ function decode$1(data) {
|
|
|
2540
2539
|
assets: decoded[1],
|
|
2541
2540
|
obligationUnits: decoded[2],
|
|
2542
2541
|
obligationShares: decoded[3],
|
|
2543
|
-
|
|
2542
|
+
tick: Number(decoded[4]),
|
|
2544
2543
|
maturity: from$16(Number(decoded[5])),
|
|
2545
2544
|
expiry: Number(decoded[6]),
|
|
2546
2545
|
group: decoded[7],
|
|
@@ -2890,6 +2889,85 @@ var InvalidQuoteError = class extends BaseError {
|
|
|
2890
2889
|
}
|
|
2891
2890
|
};
|
|
2892
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
|
+
|
|
2893
2971
|
//#endregion
|
|
2894
2972
|
//#region src/core/TradingFee.ts
|
|
2895
2973
|
var TradingFee_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -3403,7 +3481,7 @@ const BrandTypeId = Symbol.for("mempool/Brand");
|
|
|
3403
3481
|
|
|
3404
3482
|
//#endregion
|
|
3405
3483
|
//#region src/database/drizzle/VERSION.ts
|
|
3406
|
-
const VERSION = "router_v1.
|
|
3484
|
+
const VERSION = "router_v1.8";
|
|
3407
3485
|
|
|
3408
3486
|
//#endregion
|
|
3409
3487
|
//#region src/database/drizzle/schema.ts
|
|
@@ -3555,10 +3633,7 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
3555
3633
|
precision: 78,
|
|
3556
3634
|
scale: 0
|
|
3557
3635
|
}).notNull().default("0"),
|
|
3558
|
-
|
|
3559
|
-
precision: 78,
|
|
3560
|
-
scale: 0
|
|
3561
|
-
}).notNull(),
|
|
3636
|
+
tick: (0, drizzle_orm_pg_core.integer)("tick").notNull(),
|
|
3562
3637
|
maturity: (0, drizzle_orm_pg_core.integer)("maturity").notNull(),
|
|
3563
3638
|
expiry: (0, drizzle_orm_pg_core.integer)("expiry").notNull(),
|
|
3564
3639
|
start: (0, drizzle_orm_pg_core.integer)("start").notNull(),
|
|
@@ -3623,6 +3698,7 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3623
3698
|
user: (0, drizzle_orm_pg_core.varchar)("user", { length: 42 }).notNull(),
|
|
3624
3699
|
contract: (0, drizzle_orm_pg_core.varchar)("contract", { length: 42 }).notNull(),
|
|
3625
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(),
|
|
3626
3702
|
lower: (0, drizzle_orm_pg_core.numeric)("lower", {
|
|
3627
3703
|
precision: 78,
|
|
3628
3704
|
scale: 0
|
|
@@ -3637,7 +3713,8 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3637
3713
|
table.chainId,
|
|
3638
3714
|
table.user,
|
|
3639
3715
|
table.contract,
|
|
3640
|
-
table.group
|
|
3716
|
+
table.group,
|
|
3717
|
+
table.obligationId
|
|
3641
3718
|
],
|
|
3642
3719
|
name: "lots_pk"
|
|
3643
3720
|
}),
|
|
@@ -3673,6 +3750,7 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3673
3750
|
user: (0, drizzle_orm_pg_core.varchar)("user", { length: 42 }).notNull(),
|
|
3674
3751
|
contract: (0, drizzle_orm_pg_core.varchar)("contract", { length: 42 }).notNull(),
|
|
3675
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(),
|
|
3676
3754
|
value: (0, drizzle_orm_pg_core.numeric)("value", {
|
|
3677
3755
|
precision: 78,
|
|
3678
3756
|
scale: 0
|
|
@@ -3682,7 +3760,8 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3682
3760
|
table.chainId,
|
|
3683
3761
|
table.user,
|
|
3684
3762
|
table.contract,
|
|
3685
|
-
table.group
|
|
3763
|
+
table.group,
|
|
3764
|
+
table.obligationId
|
|
3686
3765
|
],
|
|
3687
3766
|
name: "offsets_pk"
|
|
3688
3767
|
}), (0, drizzle_orm_pg_core.foreignKey)({
|
|
@@ -4273,6 +4352,7 @@ function decodeCallbacks(parameters) {
|
|
|
4273
4352
|
positionContract: loanToken,
|
|
4274
4353
|
positionUser: offer.maker,
|
|
4275
4354
|
group: offer.group,
|
|
4355
|
+
obligationId: obligationId(offer),
|
|
4276
4356
|
size: offer.assets
|
|
4277
4357
|
});
|
|
4278
4358
|
callbacks.push({
|
|
@@ -5211,8 +5291,10 @@ async function getRemoteBlockNumbers(healthClients) {
|
|
|
5211
5291
|
//#region src/api/Schema/BookResponse.ts
|
|
5212
5292
|
var BookResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$5 });
|
|
5213
5293
|
function from$5(level) {
|
|
5294
|
+
const price = tickToPrice(level.tick);
|
|
5214
5295
|
return {
|
|
5215
|
-
|
|
5296
|
+
tick: level.tick,
|
|
5297
|
+
price: price.toString(),
|
|
5216
5298
|
assets: level.assets.toString(),
|
|
5217
5299
|
count: level.count
|
|
5218
5300
|
};
|
|
@@ -5317,7 +5399,7 @@ function from$3(input) {
|
|
|
5317
5399
|
obligation_shares: input.obligationShares.toString(),
|
|
5318
5400
|
start: input.start,
|
|
5319
5401
|
expiry: input.expiry,
|
|
5320
|
-
|
|
5402
|
+
tick: input.tick,
|
|
5321
5403
|
group: input.group,
|
|
5322
5404
|
session: input.session,
|
|
5323
5405
|
callback: input.callback.address,
|
|
@@ -5479,7 +5561,7 @@ const offerExample = {
|
|
|
5479
5561
|
obligation_shares: "0",
|
|
5480
5562
|
start: 1761922790,
|
|
5481
5563
|
expiry: 1761922799,
|
|
5482
|
-
|
|
5564
|
+
tick: 495,
|
|
5483
5565
|
group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
|
|
5484
5566
|
session: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
5485
5567
|
callback: "0x0000000000000000000000000000000000000000",
|
|
@@ -5520,7 +5602,7 @@ const validateOfferExample = {
|
|
|
5520
5602
|
assets: "369216000000000000000000",
|
|
5521
5603
|
obligation_units: "0",
|
|
5522
5604
|
obligation_shares: "0",
|
|
5523
|
-
|
|
5605
|
+
tick: 495,
|
|
5524
5606
|
maturity: 1761922799,
|
|
5525
5607
|
expiry: 1761922799,
|
|
5526
5608
|
start: 1761922790,
|
|
@@ -5664,9 +5746,11 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5664
5746
|
example: offerExample.offer.expiry
|
|
5665
5747
|
})], OfferDataResponse.prototype, "expiry", void 0);
|
|
5666
5748
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5667
|
-
type: "
|
|
5668
|
-
example: offerExample.offer.
|
|
5669
|
-
|
|
5749
|
+
type: "number",
|
|
5750
|
+
example: offerExample.offer.tick,
|
|
5751
|
+
minimum: 0,
|
|
5752
|
+
maximum: 990
|
|
5753
|
+
})], OfferDataResponse.prototype, "tick", void 0);
|
|
5670
5754
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5671
5755
|
type: "string",
|
|
5672
5756
|
example: offerExample.offer.group
|
|
@@ -5907,9 +5991,11 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5907
5991
|
required: false
|
|
5908
5992
|
})], ValidateOfferRequest.prototype, "obligation_shares", void 0);
|
|
5909
5993
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5910
|
-
type: "
|
|
5911
|
-
example: validateOfferExample.
|
|
5912
|
-
|
|
5994
|
+
type: "number",
|
|
5995
|
+
example: validateOfferExample.tick,
|
|
5996
|
+
minimum: 0,
|
|
5997
|
+
maximum: 990
|
|
5998
|
+
})], ValidateOfferRequest.prototype, "tick", void 0);
|
|
5913
5999
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5914
6000
|
type: "number",
|
|
5915
6001
|
example: validateOfferExample.maturity
|
|
@@ -6009,9 +6095,16 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
6009
6095
|
description: "List of validation issues. Returned when any offer fails validation."
|
|
6010
6096
|
})], ValidationFailureResponse.prototype, "data", void 0);
|
|
6011
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);
|
|
6012
6104
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6013
6105
|
type: "string",
|
|
6014
|
-
example: "
|
|
6106
|
+
example: "500000000000000000",
|
|
6107
|
+
description: "Price derived from tick, scaled by 1e18."
|
|
6015
6108
|
})], BookLevelResponse.prototype, "price", void 0);
|
|
6016
6109
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6017
6110
|
type: "string",
|
|
@@ -6025,6 +6118,7 @@ const positionExample = {
|
|
|
6025
6118
|
chain_id: 1,
|
|
6026
6119
|
contract: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
|
|
6027
6120
|
user: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
|
|
6121
|
+
obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
|
|
6028
6122
|
reserved: "200000000000000000000",
|
|
6029
6123
|
block_number: 21345678
|
|
6030
6124
|
};
|
|
@@ -6041,6 +6135,12 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
6041
6135
|
type: "string",
|
|
6042
6136
|
example: positionExample.user
|
|
6043
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);
|
|
6044
6144
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6045
6145
|
type: "string",
|
|
6046
6146
|
example: positionExample.reserved
|
|
@@ -6068,7 +6168,7 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
6068
6168
|
})], BookListResponse.prototype, "cursor", void 0);
|
|
6069
6169
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6070
6170
|
type: () => [BookLevelResponse],
|
|
6071
|
-
description: "Aggregated book levels grouped by
|
|
6171
|
+
description: "Aggregated book levels grouped by offer tick."
|
|
6072
6172
|
})], BookListResponse.prototype, "data", void 0);
|
|
6073
6173
|
let BooksController = class BooksController {
|
|
6074
6174
|
async getBook() {}
|
|
@@ -6078,7 +6178,7 @@ __decorate([
|
|
|
6078
6178
|
methods: ["get"],
|
|
6079
6179
|
path: "/v1/books/{obligationId}/{side}",
|
|
6080
6180
|
summary: "Get aggregated book",
|
|
6081
|
-
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)."
|
|
6082
6182
|
}),
|
|
6083
6183
|
(0, openapi_metadata_decorators.ApiParam)({
|
|
6084
6184
|
name: "obligationId",
|
|
@@ -6103,7 +6203,7 @@ __decorate([
|
|
|
6103
6203
|
name: "limit",
|
|
6104
6204
|
type: "number",
|
|
6105
6205
|
example: 10,
|
|
6106
|
-
description: "Maximum number of
|
|
6206
|
+
description: "Maximum number of tick levels to return."
|
|
6107
6207
|
}),
|
|
6108
6208
|
(0, openapi_metadata_decorators.ApiResponse)({
|
|
6109
6209
|
status: 200,
|
|
@@ -6297,6 +6397,11 @@ const configRulesLoanTokenExample = {
|
|
|
6297
6397
|
chain_id: 1,
|
|
6298
6398
|
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
6299
6399
|
};
|
|
6400
|
+
const configRulesCollateralTokenExample = {
|
|
6401
|
+
type: "collateral_token",
|
|
6402
|
+
chain_id: 1,
|
|
6403
|
+
address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
6404
|
+
};
|
|
6300
6405
|
const configRulesOracleExample = {
|
|
6301
6406
|
type: "oracle",
|
|
6302
6407
|
chain_id: 1,
|
|
@@ -6306,6 +6411,7 @@ const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
|
|
|
6306
6411
|
const configRulesPayloadExample = [
|
|
6307
6412
|
configRulesMaturityExample,
|
|
6308
6413
|
configRulesLoanTokenExample,
|
|
6414
|
+
configRulesCollateralTokenExample,
|
|
6309
6415
|
configRulesOracleExample
|
|
6310
6416
|
];
|
|
6311
6417
|
const configContractNames = [
|
|
@@ -6432,7 +6538,7 @@ __decorate([
|
|
|
6432
6538
|
methods: ["get"],
|
|
6433
6539
|
path: "/v1/config/rules",
|
|
6434
6540
|
summary: "Get config rules",
|
|
6435
|
-
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."
|
|
6436
6542
|
}),
|
|
6437
6543
|
(0, openapi_metadata_decorators.ApiQuery)({
|
|
6438
6544
|
name: "cursor",
|
|
@@ -6452,7 +6558,7 @@ __decorate([
|
|
|
6452
6558
|
name: "types",
|
|
6453
6559
|
type: ["string"],
|
|
6454
6560
|
required: false,
|
|
6455
|
-
example: "maturity,loan_token,oracle",
|
|
6561
|
+
example: "maturity,loan_token,collateral_token,oracle",
|
|
6456
6562
|
description: "Filter by rule types (comma-separated).",
|
|
6457
6563
|
style: "form",
|
|
6458
6564
|
explode: false
|
|
@@ -6570,7 +6676,7 @@ __decorate([
|
|
|
6570
6676
|
methods: ["get"],
|
|
6571
6677
|
path: "/v1/users/{userAddress}/positions",
|
|
6572
6678
|
summary: "Get user positions",
|
|
6573
|
-
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."
|
|
6574
6680
|
}),
|
|
6575
6681
|
(0, openapi_metadata_decorators.ApiParam)({
|
|
6576
6682
|
name: "userAddress",
|
|
@@ -6658,6 +6764,7 @@ function from$2(position) {
|
|
|
6658
6764
|
chain_id: position.chainId,
|
|
6659
6765
|
contract: position.contract,
|
|
6660
6766
|
user: position.user,
|
|
6767
|
+
obligation_id: position.obligationId,
|
|
6661
6768
|
reserved: position.reserved.toString(),
|
|
6662
6769
|
block_number: position.blockNumber
|
|
6663
6770
|
};
|
|
@@ -6711,10 +6818,11 @@ const ConfigRuleTypes = zod.enum([
|
|
|
6711
6818
|
"maturity",
|
|
6712
6819
|
"callback",
|
|
6713
6820
|
"loan_token",
|
|
6821
|
+
"collateral_token",
|
|
6714
6822
|
"oracle"
|
|
6715
6823
|
]);
|
|
6716
6824
|
const GetConfigRulesQueryParams = zod.object({
|
|
6717
|
-
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({
|
|
6718
6826
|
description: "Pagination cursor in type:chain_id:<value> format",
|
|
6719
6827
|
example: "maturity:1:1730415600:end_of_next_month"
|
|
6720
6828
|
}),
|
|
@@ -6724,7 +6832,7 @@ const GetConfigRulesQueryParams = zod.object({
|
|
|
6724
6832
|
}),
|
|
6725
6833
|
types: csvArray(ConfigRuleTypes).meta({
|
|
6726
6834
|
description: "Filter by rule types (comma-separated).",
|
|
6727
|
-
example: "maturity,loan_token,oracle"
|
|
6835
|
+
example: "maturity,loan_token,collateral_token,oracle"
|
|
6728
6836
|
}),
|
|
6729
6837
|
chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
6730
6838
|
description: "Filter by chain IDs (comma-separated).",
|
|
@@ -6824,12 +6932,11 @@ const GetObligationParams = zod.object({ obligation_id: zod.string({ error: "Obl
|
|
|
6824
6932
|
description: "Obligation id",
|
|
6825
6933
|
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
6826
6934
|
}) });
|
|
6827
|
-
/** Validate a book cursor format: {side,
|
|
6935
|
+
/** Validate a book cursor format: {side, lastTick, offersCursor} */
|
|
6828
6936
|
function isValidBookCursor(cursorString) {
|
|
6829
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
6830
6937
|
try {
|
|
6831
6938
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
6832
|
-
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");
|
|
6833
6940
|
} catch {
|
|
6834
6941
|
return false;
|
|
6835
6942
|
}
|
|
@@ -6927,7 +7034,7 @@ async function getBook(params, db) {
|
|
|
6927
7034
|
side: query.side,
|
|
6928
7035
|
levels_count: levels.length,
|
|
6929
7036
|
has_next_cursor: nextCursor != null,
|
|
6930
|
-
|
|
7037
|
+
first_level_tick: firstLevel?.tick ?? null,
|
|
6931
7038
|
first_level_assets: firstLevel?.assets.toString() ?? null,
|
|
6932
7039
|
first_level_count: firstLevel?.count ?? null
|
|
6933
7040
|
});
|
|
@@ -7079,6 +7186,33 @@ const assets = {
|
|
|
7079
7186
|
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
7080
7187
|
]
|
|
7081
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
|
+
};
|
|
7082
7216
|
const oracles = {
|
|
7083
7217
|
[ChainId.ETHEREUM.toString()]: [
|
|
7084
7218
|
"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
|
|
@@ -7138,7 +7272,7 @@ const configs = {
|
|
|
7138
7272
|
//#endregion
|
|
7139
7273
|
//#region src/gatekeeper/ConfigRules.ts
|
|
7140
7274
|
/**
|
|
7141
|
-
* 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.
|
|
7142
7276
|
* @param chains - Chains to include in the configured rules.
|
|
7143
7277
|
* @returns Sorted list of config rules.
|
|
7144
7278
|
*/
|
|
@@ -7158,6 +7292,12 @@ function buildConfigRules(chains) {
|
|
|
7158
7292
|
chain_id: chain.id,
|
|
7159
7293
|
address: normalizeAddress(address)
|
|
7160
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
|
+
});
|
|
7161
7301
|
const oracles$2 = oracles[chain.id.toString()] ?? [];
|
|
7162
7302
|
for (const address of oracles$2) rules.push({
|
|
7163
7303
|
type: "oracle",
|
|
@@ -7185,6 +7325,10 @@ function buildConfigRulesChecksum(rules) {
|
|
|
7185
7325
|
hash.update(`callback:${rule.chain_id}:${rule.callback_type}:${rule.address}\n`);
|
|
7186
7326
|
continue;
|
|
7187
7327
|
}
|
|
7328
|
+
if (rule.type === "collateral_token") {
|
|
7329
|
+
hash.update(`collateral_token:${rule.chain_id}:${rule.address}\n`);
|
|
7330
|
+
continue;
|
|
7331
|
+
}
|
|
7188
7332
|
if (rule.type === "oracle") {
|
|
7189
7333
|
hash.update(`oracle:${rule.chain_id}:${rule.address}\n`);
|
|
7190
7334
|
continue;
|
|
@@ -7205,6 +7349,7 @@ function compareConfigRules(left, right) {
|
|
|
7205
7349
|
return left.address.localeCompare(right.address);
|
|
7206
7350
|
}
|
|
7207
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);
|
|
7208
7353
|
if (left.type === "oracle" && right.type === "oracle") return left.address.localeCompare(right.address);
|
|
7209
7354
|
return 0;
|
|
7210
7355
|
}
|
|
@@ -7251,6 +7396,7 @@ function formatCursor(rule) {
|
|
|
7251
7396
|
if (rule.type === "maturity") return `maturity:${rule.chain_id}:${rule.timestamp}:${rule.name}`;
|
|
7252
7397
|
if (rule.type === "callback") return `callback:${rule.chain_id}:${rule.callback_type}:${rule.address.toLowerCase()}`;
|
|
7253
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()}`;
|
|
7254
7400
|
return `loan_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7255
7401
|
}
|
|
7256
7402
|
function parseCursor(cursor) {
|
|
@@ -7283,7 +7429,7 @@ function parseCursor(cursor) {
|
|
|
7283
7429
|
address: parseAddress(addressValue, "Cursor address")
|
|
7284
7430
|
};
|
|
7285
7431
|
}
|
|
7286
|
-
if (type === "loan_token" || type === "oracle") {
|
|
7432
|
+
if (type === "loan_token" || type === "collateral_token" || type === "oracle") {
|
|
7287
7433
|
const addressValue = rest.join(":");
|
|
7288
7434
|
if (!addressValue) throw new BadRequestError(`Cursor must be in the format ${type}:chain_id:address`);
|
|
7289
7435
|
return {
|
|
@@ -7310,7 +7456,7 @@ function parseAddress(address, label) {
|
|
|
7310
7456
|
return address.toLowerCase();
|
|
7311
7457
|
}
|
|
7312
7458
|
function isConfigRuleType(value) {
|
|
7313
|
-
return value === "maturity" || value === "callback" || value === "loan_token" || value === "oracle";
|
|
7459
|
+
return value === "maturity" || value === "callback" || value === "loan_token" || value === "collateral_token" || value === "oracle";
|
|
7314
7460
|
}
|
|
7315
7461
|
function isMaturityType(value) {
|
|
7316
7462
|
return Object.values(MaturityType).includes(value);
|
|
@@ -7657,7 +7803,7 @@ function create$15(config) {
|
|
|
7657
7803
|
assets: offers.assets,
|
|
7658
7804
|
obligationUnits: offers.obligationUnits,
|
|
7659
7805
|
obligationShares: offers.obligationShares,
|
|
7660
|
-
|
|
7806
|
+
tick: offers.tick,
|
|
7661
7807
|
maturity: offers.maturity,
|
|
7662
7808
|
expiry: offers.expiry,
|
|
7663
7809
|
start: offers.start,
|
|
@@ -7677,7 +7823,7 @@ function create$15(config) {
|
|
|
7677
7823
|
assets: BigInt(row.assets),
|
|
7678
7824
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7679
7825
|
obligationShares: BigInt(row.obligationShares),
|
|
7680
|
-
|
|
7826
|
+
tick: row.tick,
|
|
7681
7827
|
maturity: from$16(row.maturity),
|
|
7682
7828
|
expiry: row.expiry,
|
|
7683
7829
|
start: row.start,
|
|
@@ -7759,8 +7905,8 @@ function create$15(config) {
|
|
|
7759
7905
|
const now$2 = now();
|
|
7760
7906
|
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
7761
7907
|
obligationId: offers.obligationId,
|
|
7762
|
-
price: offers.
|
|
7763
|
-
}).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`);
|
|
7764
7910
|
const [bestBuys, bestSells] = await Promise.all([query({ side: "buy" }), query({ side: "sell" })]);
|
|
7765
7911
|
const quotes = /* @__PURE__ */ new Map();
|
|
7766
7912
|
for (const row of bestSells) quotes.set(row.obligationId, {
|
|
@@ -7876,7 +8022,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7876
8022
|
obligationUnits: offers.obligationUnits,
|
|
7877
8023
|
obligationShares: offers.obligationShares,
|
|
7878
8024
|
consumed: groups.consumed,
|
|
7879
|
-
|
|
8025
|
+
tick: offers.tick,
|
|
7880
8026
|
maturity: offers.maturity,
|
|
7881
8027
|
expiry: offers.expiry,
|
|
7882
8028
|
start: offers.start,
|
|
@@ -7914,7 +8060,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7914
8060
|
assets: BigInt(row.assets),
|
|
7915
8061
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7916
8062
|
obligationShares: BigInt(row.obligationShares),
|
|
7917
|
-
|
|
8063
|
+
tick: row.tick,
|
|
7918
8064
|
maturity: from$16(row.maturity),
|
|
7919
8065
|
expiry: row.expiry,
|
|
7920
8066
|
start: row.start,
|
|
@@ -8313,7 +8459,7 @@ async function getOffers(apiClient, parameters) {
|
|
|
8313
8459
|
assets: offerData.assets,
|
|
8314
8460
|
obligation_units: offerData.obligation_units,
|
|
8315
8461
|
obligation_shares: offerData.obligation_shares,
|
|
8316
|
-
|
|
8462
|
+
tick: offerData.tick,
|
|
8317
8463
|
maturity: from$16(offerData.obligation.maturity),
|
|
8318
8464
|
expiry: offerData.expiry,
|
|
8319
8465
|
start: offerData.start,
|
|
@@ -8672,6 +8818,7 @@ function create$12(config) {
|
|
|
8672
8818
|
return {
|
|
8673
8819
|
get: async (parameters) => {
|
|
8674
8820
|
const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT$2 } = parameters;
|
|
8821
|
+
const tickSortDirection = side === "sell" ? "asc" : "desc";
|
|
8675
8822
|
const inputCursor = LevelCursor.decode(cursorString, logger);
|
|
8676
8823
|
if (cursorString != null && inputCursor === null) return {
|
|
8677
8824
|
levels: [],
|
|
@@ -8686,23 +8833,23 @@ function create$12(config) {
|
|
|
8686
8833
|
cursor: inputCursor?.offersCursor ?? void 0,
|
|
8687
8834
|
limit: fetchLimit
|
|
8688
8835
|
});
|
|
8689
|
-
const
|
|
8836
|
+
const tickMap = /* @__PURE__ */ new Map();
|
|
8690
8837
|
for (const row of rows) {
|
|
8691
|
-
const
|
|
8692
|
-
const existing = priceMap.get(priceKey);
|
|
8838
|
+
const existing = tickMap.get(row.tick);
|
|
8693
8839
|
if (existing) {
|
|
8694
8840
|
existing.assets += row.takeable;
|
|
8695
8841
|
existing.count += 1;
|
|
8696
|
-
} else
|
|
8842
|
+
} else tickMap.set(row.tick, {
|
|
8697
8843
|
assets: row.takeable,
|
|
8698
8844
|
count: 1
|
|
8699
8845
|
});
|
|
8700
8846
|
}
|
|
8701
|
-
const levels = Array.from(
|
|
8702
|
-
|
|
8703
|
-
assets:
|
|
8704
|
-
count:
|
|
8847
|
+
const levels = Array.from(tickMap.entries()).map(([tick, level]) => ({
|
|
8848
|
+
tick,
|
|
8849
|
+
assets: level.assets,
|
|
8850
|
+
count: level.count
|
|
8705
8851
|
}));
|
|
8852
|
+
levels.sort((a, b) => tickSortDirection === "asc" ? a.tick - b.tick : b.tick - a.tick);
|
|
8706
8853
|
const paginatedLevels = levels.slice(0, limit);
|
|
8707
8854
|
const hasMore = levels.length > limit || offersNextCursor !== null;
|
|
8708
8855
|
const lastLevel = paginatedLevels[paginatedLevels.length - 1];
|
|
@@ -8748,14 +8895,14 @@ async function _getOffers(db, params) {
|
|
|
8748
8895
|
AND (s.code IS NULL OR s.code = ${Status.VALID})
|
|
8749
8896
|
ORDER BY
|
|
8750
8897
|
o.group_chain_id, o.group_maker, o."group_group",
|
|
8751
|
-
o.
|
|
8898
|
+
o.tick ${priceSortDirection === "asc" ? drizzle_orm.sql`ASC` : drizzle_orm.sql`DESC`}, o.block_number ASC, o.assets DESC, o.hash ASC
|
|
8752
8899
|
),
|
|
8753
8900
|
enriched AS (
|
|
8754
8901
|
SELECT
|
|
8755
8902
|
w.*,
|
|
8756
8903
|
g.consumed, g.chain_id, obl.loan_token,
|
|
8757
8904
|
CASE WHEN ${priceSortDirection === "asc" ? drizzle_orm.sql`TRUE` : drizzle_orm.sql`FALSE`}
|
|
8758
|
-
THEN w.
|
|
8905
|
+
THEN w.tick ELSE -w.tick END AS tick_norm,
|
|
8759
8906
|
w.block_number AS block_norm,
|
|
8760
8907
|
-w.assets AS assets_norm,
|
|
8761
8908
|
w.hash AS hash_norm
|
|
@@ -8772,33 +8919,35 @@ async function _getOffers(db, params) {
|
|
|
8772
8919
|
FROM enriched e
|
|
8773
8920
|
${cursor != null ? drizzle_orm.sql`
|
|
8774
8921
|
WHERE
|
|
8775
|
-
(e.
|
|
8922
|
+
(e.tick_norm, e.block_norm, e.assets_norm, e.hash_norm)
|
|
8776
8923
|
> (
|
|
8777
8924
|
CASE WHEN ${priceSortDirection === "asc" ? drizzle_orm.sql`TRUE` : drizzle_orm.sql`FALSE`}
|
|
8778
|
-
THEN ${cursor.
|
|
8925
|
+
THEN ${cursor.tick}::integer ELSE -${cursor.tick}::integer END,
|
|
8779
8926
|
${cursor.blockNumber},
|
|
8780
8927
|
-${cursor.assets}::numeric,
|
|
8781
8928
|
${cursor.hash}
|
|
8782
8929
|
)` : drizzle_orm.sql``}
|
|
8783
|
-
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
|
|
8784
8931
|
LIMIT ${limit}
|
|
8785
8932
|
),
|
|
8786
|
-
-- Compute sum of offsets per position
|
|
8933
|
+
-- Compute sum of offsets per position and obligation
|
|
8787
8934
|
position_offsets AS (
|
|
8788
8935
|
SELECT
|
|
8789
8936
|
chain_id,
|
|
8790
8937
|
"user",
|
|
8791
8938
|
contract,
|
|
8939
|
+
obligation_id,
|
|
8792
8940
|
SUM(value::numeric) AS total_offset
|
|
8793
8941
|
FROM ${offsets}
|
|
8794
|
-
GROUP BY chain_id, "user", contract
|
|
8942
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
8795
8943
|
),
|
|
8796
|
-
-- 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)
|
|
8797
8945
|
position_consumed AS (
|
|
8798
8946
|
SELECT
|
|
8799
8947
|
l.chain_id,
|
|
8800
8948
|
l.contract,
|
|
8801
8949
|
l."user",
|
|
8950
|
+
l.obligation_id,
|
|
8802
8951
|
SUM(
|
|
8803
8952
|
CASE
|
|
8804
8953
|
WHEN wo.assets::numeric > 0
|
|
@@ -8815,7 +8964,7 @@ async function _getOffers(db, params) {
|
|
|
8815
8964
|
ON wo.group_chain_id = g.chain_id
|
|
8816
8965
|
AND LOWER(wo.group_maker) = LOWER(g.maker)
|
|
8817
8966
|
AND wo.group_group = g."group"
|
|
8818
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
8967
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
8819
8968
|
),
|
|
8820
8969
|
-- Compute callback contributions with lot balance
|
|
8821
8970
|
callback_contributions AS (
|
|
@@ -8823,7 +8972,7 @@ async function _getOffers(db, params) {
|
|
|
8823
8972
|
p.hash,
|
|
8824
8973
|
p.obligation_id,
|
|
8825
8974
|
p.assets,
|
|
8826
|
-
p.
|
|
8975
|
+
p.tick,
|
|
8827
8976
|
p.obligation_units,
|
|
8828
8977
|
p.obligation_shares,
|
|
8829
8978
|
p.maturity,
|
|
@@ -8868,6 +9017,7 @@ async function _getOffers(db, params) {
|
|
|
8868
9017
|
AND LOWER(l.contract) = LOWER(c.position_contract)
|
|
8869
9018
|
AND LOWER(l."user") = LOWER(c.position_user)
|
|
8870
9019
|
AND l."group" = p.group_group
|
|
9020
|
+
AND l.obligation_id = p.obligation_id
|
|
8871
9021
|
LEFT JOIN ${positions} pos
|
|
8872
9022
|
ON pos.chain_id = c.position_chain_id
|
|
8873
9023
|
AND LOWER(pos.contract) = LOWER(c.position_contract)
|
|
@@ -8876,10 +9026,12 @@ async function _getOffers(db, params) {
|
|
|
8876
9026
|
ON pos_offsets.chain_id = c.position_chain_id
|
|
8877
9027
|
AND LOWER(pos_offsets.contract) = LOWER(c.position_contract)
|
|
8878
9028
|
AND LOWER(pos_offsets."user") = LOWER(c.position_user)
|
|
9029
|
+
AND pos_offsets.obligation_id = p.obligation_id
|
|
8879
9030
|
LEFT JOIN position_consumed pc
|
|
8880
9031
|
ON pc.chain_id = c.position_chain_id
|
|
8881
9032
|
AND LOWER(pc.contract) = LOWER(c.position_contract)
|
|
8882
9033
|
AND LOWER(pc."user") = LOWER(c.position_user)
|
|
9034
|
+
AND pc.obligation_id = p.obligation_id
|
|
8883
9035
|
),
|
|
8884
9036
|
-- Compute contribution per callback in loan terms (loan token only — collateral positions are not indexed)
|
|
8885
9037
|
callback_loan_contribution AS (
|
|
@@ -8897,7 +9049,7 @@ async function _getOffers(db, params) {
|
|
|
8897
9049
|
hash,
|
|
8898
9050
|
obligation_id,
|
|
8899
9051
|
assets,
|
|
8900
|
-
|
|
9052
|
+
tick,
|
|
8901
9053
|
obligation_units,
|
|
8902
9054
|
obligation_shares,
|
|
8903
9055
|
maturity,
|
|
@@ -8923,13 +9075,13 @@ async function _getOffers(db, params) {
|
|
|
8923
9075
|
WHERE clc.callback_id IS NOT NULL
|
|
8924
9076
|
ORDER BY clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user, clc.contribution_in_loan DESC
|
|
8925
9077
|
) deduped
|
|
8926
|
-
GROUP BY hash, obligation_id, assets,
|
|
9078
|
+
GROUP BY hash, obligation_id, assets, tick, obligation_units, obligation_shares, maturity, expiry, start, group_group, buy,
|
|
8927
9079
|
callback_address, callback_data, block_number, group_chain_id, group_maker,
|
|
8928
9080
|
consumed, chain_id, loan_token, session
|
|
8929
9081
|
UNION ALL
|
|
8930
9082
|
-- Sell offers without callbacks: collateral positions not indexed, takeable = assets - consumed
|
|
8931
9083
|
SELECT
|
|
8932
|
-
p.hash, p.obligation_id, p.assets, p.
|
|
9084
|
+
p.hash, p.obligation_id, p.assets, p.tick,
|
|
8933
9085
|
p.obligation_units, p.obligation_shares,
|
|
8934
9086
|
p.maturity, p.expiry, p.start, p.group_group,
|
|
8935
9087
|
p.buy, p.callback_address, p.callback_data,
|
|
@@ -8951,7 +9103,7 @@ async function _getOffers(db, params) {
|
|
|
8951
9103
|
oc.obligation_units,
|
|
8952
9104
|
oc.obligation_shares,
|
|
8953
9105
|
oc.consumed,
|
|
8954
|
-
oc.
|
|
9106
|
+
oc.tick,
|
|
8955
9107
|
oc.maturity,
|
|
8956
9108
|
oc.expiry,
|
|
8957
9109
|
oc.start,
|
|
@@ -8983,7 +9135,7 @@ async function _getOffers(db, params) {
|
|
|
8983
9135
|
))
|
|
8984
9136
|
END > 0
|
|
8985
9137
|
ORDER BY
|
|
8986
|
-
oc.
|
|
9138
|
+
oc.tick ${priceSortDirection === "asc" ? drizzle_orm.sql`ASC` : drizzle_orm.sql`DESC`},
|
|
8987
9139
|
oc.block_number ASC,
|
|
8988
9140
|
oc.assets DESC,
|
|
8989
9141
|
oc.hash ASC;
|
|
@@ -8996,7 +9148,7 @@ async function _getOffers(db, params) {
|
|
|
8996
9148
|
assets: BigInt(row.assets),
|
|
8997
9149
|
obligationUnits: BigInt(row.obligation_units ?? 0),
|
|
8998
9150
|
obligationShares: BigInt(row.obligation_shares ?? 0),
|
|
8999
|
-
|
|
9151
|
+
tick: row.tick,
|
|
9000
9152
|
maturity: row.maturity,
|
|
9001
9153
|
expiry: row.expiry,
|
|
9002
9154
|
start: row.start,
|
|
@@ -9028,7 +9180,7 @@ let Cursor;
|
|
|
9028
9180
|
function encode(row, totalReturned, now, side) {
|
|
9029
9181
|
return Buffer.from(JSON.stringify({
|
|
9030
9182
|
side,
|
|
9031
|
-
|
|
9183
|
+
tick: row.tick,
|
|
9032
9184
|
blockNumber: row.blockNumber,
|
|
9033
9185
|
assets: row.assets.toString(),
|
|
9034
9186
|
hash: row.hash,
|
|
@@ -9039,10 +9191,9 @@ let Cursor;
|
|
|
9039
9191
|
_Cursor.encode = encode;
|
|
9040
9192
|
function decode(cursorString, logger) {
|
|
9041
9193
|
if (cursorString == null) return null;
|
|
9042
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
9043
9194
|
try {
|
|
9044
9195
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
9045
|
-
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;
|
|
9046
9197
|
throw new Error("Invalid cursor");
|
|
9047
9198
|
} catch {
|
|
9048
9199
|
logger.error({
|
|
@@ -9060,7 +9211,7 @@ let LevelCursor;
|
|
|
9060
9211
|
function encode(lastLevel, offersCursor, side, now) {
|
|
9061
9212
|
return Buffer.from(JSON.stringify({
|
|
9062
9213
|
side,
|
|
9063
|
-
|
|
9214
|
+
lastTick: lastLevel.tick,
|
|
9064
9215
|
now,
|
|
9065
9216
|
offersCursor
|
|
9066
9217
|
})).toString("base64url");
|
|
@@ -9068,10 +9219,9 @@ let LevelCursor;
|
|
|
9068
9219
|
_LevelCursor.encode = encode;
|
|
9069
9220
|
function decode(cursorString, logger) {
|
|
9070
9221
|
if (cursorString == null) return null;
|
|
9071
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
9072
9222
|
try {
|
|
9073
9223
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
9074
|
-
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;
|
|
9075
9225
|
throw new Error("Invalid book cursor");
|
|
9076
9226
|
} catch {
|
|
9077
9227
|
logger.error({
|
|
@@ -9214,31 +9364,33 @@ function create$9(db) {
|
|
|
9214
9364
|
function create$8(db) {
|
|
9215
9365
|
return {
|
|
9216
9366
|
get: async (parameters) => {
|
|
9217
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9367
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9218
9368
|
const conditions = [];
|
|
9219
9369
|
if (chainId !== void 0) conditions.push((0, drizzle_orm.eq)(lots.chainId, chainId));
|
|
9220
9370
|
if (user !== void 0) conditions.push((0, drizzle_orm.eq)(lots.user, user.toLowerCase()));
|
|
9221
9371
|
if (contract !== void 0) conditions.push((0, drizzle_orm.eq)(lots.contract, contract.toLowerCase()));
|
|
9222
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));
|
|
9223
9374
|
return (await db.select().from(lots).where(conditions.length > 0 ? (0, drizzle_orm.and)(...conditions) : void 0)).map((row) => ({
|
|
9224
9375
|
chainId: row.chainId,
|
|
9225
9376
|
user: row.user,
|
|
9226
9377
|
contract: row.contract,
|
|
9227
9378
|
group: row.group,
|
|
9379
|
+
obligationId: row.obligationId,
|
|
9228
9380
|
lower: BigInt(row.lower),
|
|
9229
9381
|
upper: BigInt(row.upper)
|
|
9230
9382
|
}));
|
|
9231
9383
|
},
|
|
9232
9384
|
create: async (parameters) => {
|
|
9233
9385
|
if (parameters.length === 0) return;
|
|
9234
|
-
const
|
|
9386
|
+
const lotsByKey = /* @__PURE__ */ new Map();
|
|
9235
9387
|
for (const offer of parameters) {
|
|
9236
|
-
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}`.toLowerCase();
|
|
9237
|
-
const existing =
|
|
9238
|
-
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);
|
|
9239
9391
|
}
|
|
9240
|
-
for (const offer of
|
|
9241
|
-
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())));
|
|
9242
9394
|
const newLower = BigInt(maxUpperResult[0]?.maxUpper ?? "0");
|
|
9243
9395
|
const newUpper = newLower + offer.size;
|
|
9244
9396
|
await db.insert(lots).values({
|
|
@@ -9246,6 +9398,7 @@ function create$8(db) {
|
|
|
9246
9398
|
user: offer.positionUser.toLowerCase(),
|
|
9247
9399
|
contract: offer.positionContract.toLowerCase(),
|
|
9248
9400
|
group: offer.group.toLowerCase(),
|
|
9401
|
+
obligationId: offer.obligationId.toLowerCase(),
|
|
9249
9402
|
lower: newLower.toString(),
|
|
9250
9403
|
upper: newUpper.toString()
|
|
9251
9404
|
});
|
|
@@ -9300,17 +9453,19 @@ function create$7(db) {
|
|
|
9300
9453
|
//#region src/database/domains/Offsets.ts
|
|
9301
9454
|
function create$6(db) {
|
|
9302
9455
|
return { get: async (parameters) => {
|
|
9303
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9456
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9304
9457
|
const conditions = [];
|
|
9305
9458
|
if (chainId !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.chainId, chainId));
|
|
9306
9459
|
if (user !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.user, user.toLowerCase()));
|
|
9307
9460
|
if (contract !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.contract, contract.toLowerCase()));
|
|
9308
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));
|
|
9309
9463
|
return (await db.select().from(offsets).where(conditions.length > 0 ? (0, drizzle_orm.and)(...conditions) : void 0)).map((row) => ({
|
|
9310
9464
|
chainId: row.chainId,
|
|
9311
9465
|
user: row.user,
|
|
9312
9466
|
contract: row.contract,
|
|
9313
9467
|
group: row.group,
|
|
9468
|
+
obligationId: row.obligationId,
|
|
9314
9469
|
value: BigInt(row.value)
|
|
9315
9470
|
}));
|
|
9316
9471
|
} };
|
|
@@ -9460,7 +9615,8 @@ const create$4 = (db) => {
|
|
|
9460
9615
|
if (!parsed.chainId || !parsed.contract) throw new Error("Invalid cursor format");
|
|
9461
9616
|
cursor = {
|
|
9462
9617
|
chainId: parsed.chainId,
|
|
9463
|
-
contract: parsed.contract
|
|
9618
|
+
contract: parsed.contract,
|
|
9619
|
+
obligationId: parsed.obligationId ?? null
|
|
9464
9620
|
};
|
|
9465
9621
|
}
|
|
9466
9622
|
const raw = await db.execute(drizzle_orm.sql`
|
|
@@ -9469,16 +9625,18 @@ const create$4 = (db) => {
|
|
|
9469
9625
|
chain_id,
|
|
9470
9626
|
"user",
|
|
9471
9627
|
contract,
|
|
9628
|
+
obligation_id,
|
|
9472
9629
|
SUM(value::numeric) AS total_offset
|
|
9473
9630
|
FROM ${offsets}
|
|
9474
9631
|
WHERE LOWER("user") = LOWER(${user})
|
|
9475
|
-
GROUP BY chain_id, "user", contract
|
|
9632
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
9476
9633
|
),
|
|
9477
9634
|
position_consumed AS (
|
|
9478
9635
|
SELECT
|
|
9479
9636
|
l.chain_id,
|
|
9480
9637
|
l.contract,
|
|
9481
9638
|
l."user",
|
|
9639
|
+
l.obligation_id,
|
|
9482
9640
|
SUM(
|
|
9483
9641
|
CASE
|
|
9484
9642
|
WHEN offer_agg.assets > 0
|
|
@@ -9504,50 +9662,64 @@ const create$4 = (db) => {
|
|
|
9504
9662
|
AND LOWER(offer_agg.group_maker) = LOWER(g.maker)
|
|
9505
9663
|
AND offer_agg."group_group" = g."group"
|
|
9506
9664
|
WHERE LOWER(l."user") = LOWER(${user})
|
|
9507
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
9665
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
9508
9666
|
),
|
|
9509
9667
|
position_max_lot AS (
|
|
9510
9668
|
SELECT
|
|
9511
9669
|
chain_id,
|
|
9512
9670
|
contract,
|
|
9513
9671
|
"user",
|
|
9672
|
+
obligation_id,
|
|
9514
9673
|
MAX(upper::numeric) AS max_upper
|
|
9515
9674
|
FROM ${lots}
|
|
9516
9675
|
WHERE LOWER("user") = LOWER(${user})
|
|
9517
|
-
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
|
|
9518
9700
|
)
|
|
9519
9701
|
SELECT
|
|
9520
9702
|
p.chain_id,
|
|
9521
9703
|
p.contract,
|
|
9522
9704
|
p."user",
|
|
9523
9705
|
p.block_number,
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
- COALESCE(po.total_offset, 0)
|
|
9527
|
-
- COALESCE(pc.consumed, 0)
|
|
9528
|
-
)::text AS reserved_balance
|
|
9706
|
+
po.obligation_id,
|
|
9707
|
+
COALESCE(po.reserved_balance, '0') AS reserved_balance
|
|
9529
9708
|
FROM ${positions} p
|
|
9530
|
-
LEFT JOIN
|
|
9709
|
+
LEFT JOIN per_obligation po
|
|
9531
9710
|
ON po.chain_id = p.chain_id
|
|
9532
9711
|
AND LOWER(po.contract) = LOWER(p.contract)
|
|
9533
9712
|
AND LOWER(po."user") = LOWER(p."user")
|
|
9534
|
-
LEFT JOIN position_consumed pc
|
|
9535
|
-
ON pc.chain_id = p.chain_id
|
|
9536
|
-
AND LOWER(pc.contract) = LOWER(p.contract)
|
|
9537
|
-
AND LOWER(pc."user") = LOWER(p."user")
|
|
9538
|
-
LEFT JOIN position_max_lot pml
|
|
9539
|
-
ON pml.chain_id = p.chain_id
|
|
9540
|
-
AND LOWER(pml.contract) = LOWER(p.contract)
|
|
9541
|
-
AND LOWER(pml."user") = LOWER(p."user")
|
|
9542
9713
|
WHERE LOWER(p."user") = LOWER(${user})
|
|
9543
9714
|
AND p."user" != ${viem.zeroAddress}
|
|
9544
|
-
${cursor !== null ? drizzle_orm.sql`AND (p.chain_id, p.contract) > (${cursor.chainId}, ${cursor.contract})` : drizzle_orm.sql``}
|
|
9545
|
-
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
|
|
9546
9717
|
LIMIT ${limit}
|
|
9547
9718
|
`);
|
|
9548
9719
|
const nextCursor = raw.rows.length === limit ? Buffer.from(JSON.stringify({
|
|
9549
9720
|
chainId: raw.rows[raw.rows.length - 1].chain_id.toString(),
|
|
9550
|
-
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
|
|
9551
9723
|
})).toString("base64url") : null;
|
|
9552
9724
|
return {
|
|
9553
9725
|
positions: raw.rows.map((row) => ({
|
|
@@ -9555,6 +9727,7 @@ const create$4 = (db) => {
|
|
|
9555
9727
|
contract: row.contract,
|
|
9556
9728
|
user: row.user,
|
|
9557
9729
|
blockNumber: row.block_number,
|
|
9730
|
+
obligationId: row.obligation_id,
|
|
9558
9731
|
reserved: BigInt(row.reserved_balance.split(".")[0] ?? "0")
|
|
9559
9732
|
})),
|
|
9560
9733
|
nextCursor
|
|
@@ -9833,7 +10006,10 @@ function create$1(db) {
|
|
|
9833
10006
|
|
|
9834
10007
|
//#endregion
|
|
9835
10008
|
//#region src/database/Database.ts
|
|
9836
|
-
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
10009
|
+
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
10010
|
+
connect: () => connect$1,
|
|
10011
|
+
getSchemaNamesForMigration: () => getSchemaNamesForMigration
|
|
10012
|
+
});
|
|
9837
10013
|
function createDomains(core, chainRegistry) {
|
|
9838
10014
|
return {
|
|
9839
10015
|
book: create$12({ db: core }),
|
|
@@ -9930,6 +10106,7 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9930
10106
|
return wrapped;
|
|
9931
10107
|
}
|
|
9932
10108
|
const InMemoryDbMap = /* @__PURE__ */ new Map();
|
|
10109
|
+
const LEGACY_SCHEMA_START_MINOR = 7;
|
|
9933
10110
|
/**
|
|
9934
10111
|
* Connect to the database.
|
|
9935
10112
|
* @notice If no connection string is provided, an in-process PGLite database is created.
|
|
@@ -9984,9 +10161,26 @@ function applyMigrations(kind, driver) {
|
|
|
9984
10161
|
async function preMigrate(driver) {
|
|
9985
10162
|
const tracer = getTracer("db.preMigrate");
|
|
9986
10163
|
await startActiveSpan(tracer, "db.preMigrate", async () => {
|
|
9987
|
-
|
|
10164
|
+
const schemaNames = getSchemaNamesForMigration(VERSION);
|
|
10165
|
+
for (const schemaName of schemaNames) await driver.execute(`create schema if not exists "${schemaName}"`);
|
|
9988
10166
|
});
|
|
9989
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
|
+
}
|
|
9990
10184
|
async function postMigrate(driver) {
|
|
9991
10185
|
const tracer = getTracer("db.postMigrate");
|
|
9992
10186
|
await startActiveSpan(tracer, "db.postMigrate", async () => {
|
|
@@ -10256,15 +10450,16 @@ async function postMigrate(driver) {
|
|
|
10256
10450
|
RETURNS trigger
|
|
10257
10451
|
LANGUAGE plpgsql AS $$
|
|
10258
10452
|
BEGIN
|
|
10259
|
-
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", value)
|
|
10453
|
+
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", obligation_id, value)
|
|
10260
10454
|
VALUES (
|
|
10261
10455
|
OLD.chain_id,
|
|
10262
10456
|
OLD."user",
|
|
10263
10457
|
OLD.contract,
|
|
10264
10458
|
OLD."group",
|
|
10459
|
+
OLD.obligation_id,
|
|
10265
10460
|
OLD.upper::numeric - OLD.lower::numeric
|
|
10266
10461
|
)
|
|
10267
|
-
ON CONFLICT (chain_id, "user", contract, "group") DO NOTHING;
|
|
10462
|
+
ON CONFLICT (chain_id, "user", contract, "group", obligation_id) DO NOTHING;
|
|
10268
10463
|
RETURN OLD;
|
|
10269
10464
|
END;
|
|
10270
10465
|
$$;
|
|
@@ -10518,10 +10713,11 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
|
10518
10713
|
amountMutualExclusivity: () => amountMutualExclusivity,
|
|
10519
10714
|
callback: () => callback,
|
|
10520
10715
|
chains: () => chains,
|
|
10716
|
+
collateralToken: () => collateralToken,
|
|
10717
|
+
loanToken: () => loanToken,
|
|
10521
10718
|
maturity: () => maturity,
|
|
10522
10719
|
oracle: () => oracle,
|
|
10523
10720
|
sameMaker: () => sameMaker,
|
|
10524
|
-
token: () => token,
|
|
10525
10721
|
validity: () => validity
|
|
10526
10722
|
});
|
|
10527
10723
|
/**
|
|
@@ -10549,15 +10745,25 @@ const callback = ({ callbacks }) => single("callback", `Validates callbacks: buy
|
|
|
10549
10745
|
if (isEmptyCallback(offer) && !offer.buy && !callbacks.includes(Type$1.SellWithEmptyCallback)) return { message: "Sell offers with empty callback not allowed." };
|
|
10550
10746
|
});
|
|
10551
10747
|
/**
|
|
10552
|
-
* A validation rule that checks if the offer's
|
|
10553
|
-
* @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.
|
|
10554
10750
|
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
10555
10751
|
*/
|
|
10556
|
-
const
|
|
10557
|
-
const
|
|
10558
|
-
if (!
|
|
10559
|
-
if (!
|
|
10560
|
-
|
|
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" };
|
|
10561
10767
|
});
|
|
10562
10768
|
/**
|
|
10563
10769
|
* A validation rule that checks if the offer's oracle addresses are allowed for its chain.
|
|
@@ -10600,9 +10806,11 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
|
|
|
10600
10806
|
//#region src/gatekeeper/morphoRules.ts
|
|
10601
10807
|
const morphoRules = (chains$3) => {
|
|
10602
10808
|
const assetsByChainId = {};
|
|
10809
|
+
const collateralAssetsByChainId = {};
|
|
10603
10810
|
const oraclesByChainId = {};
|
|
10604
10811
|
for (const chain of chains$3) {
|
|
10605
10812
|
assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
|
|
10813
|
+
collateralAssetsByChainId[chain.id] = collateralAssets[chain.id.toString()] ?? [];
|
|
10606
10814
|
oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
|
|
10607
10815
|
}
|
|
10608
10816
|
return [
|
|
@@ -10614,7 +10822,8 @@ const morphoRules = (chains$3) => {
|
|
|
10614
10822
|
callbacks: [Type$1.BuyWithEmptyCallback, Type$1.SellWithEmptyCallback],
|
|
10615
10823
|
allowedAddresses: []
|
|
10616
10824
|
}),
|
|
10617
|
-
|
|
10825
|
+
loanToken({ assetsByChainId }),
|
|
10826
|
+
collateralToken({ collateralAssetsByChainId }),
|
|
10618
10827
|
oracle({ oraclesByChainId })
|
|
10619
10828
|
];
|
|
10620
10829
|
};
|
|
@@ -11026,6 +11235,12 @@ Object.defineProperty(exports, 'Rules', {
|
|
|
11026
11235
|
return Rules_exports;
|
|
11027
11236
|
}
|
|
11028
11237
|
});
|
|
11238
|
+
Object.defineProperty(exports, 'Tick', {
|
|
11239
|
+
enumerable: true,
|
|
11240
|
+
get: function () {
|
|
11241
|
+
return Tick_exports;
|
|
11242
|
+
}
|
|
11243
|
+
});
|
|
11029
11244
|
Object.defineProperty(exports, 'Time', {
|
|
11030
11245
|
enumerable: true,
|
|
11031
11246
|
get: function () {
|