@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.mjs
CHANGED
|
@@ -2080,7 +2080,7 @@ const OfferSchema = () => {
|
|
|
2080
2080
|
assets: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
2081
2081
|
obligationUnits: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
|
|
2082
2082
|
obligationShares: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
|
|
2083
|
-
|
|
2083
|
+
tick: z$1.coerce.number().int().min(0).max(990),
|
|
2084
2084
|
maturity: MaturitySchema,
|
|
2085
2085
|
expiry: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
2086
2086
|
start: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
@@ -2152,7 +2152,7 @@ const serialize = (offer) => ({
|
|
|
2152
2152
|
assets: offer.assets.toString(),
|
|
2153
2153
|
obligationUnits: offer.obligationUnits.toString(),
|
|
2154
2154
|
obligationShares: offer.obligationShares.toString(),
|
|
2155
|
-
|
|
2155
|
+
tick: offer.tick,
|
|
2156
2156
|
maturity: Number(offer.maturity),
|
|
2157
2157
|
expiry: Number(offer.expiry),
|
|
2158
2158
|
start: Number(offer.start),
|
|
@@ -2197,14 +2197,13 @@ function random$1(config) {
|
|
|
2197
2197
|
[.98, 2]
|
|
2198
2198
|
]));
|
|
2199
2199
|
const buy = config?.buy !== void 0 ? config.buy : bool();
|
|
2200
|
-
const
|
|
2201
|
-
const
|
|
2202
|
-
const
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
return [BigInt(q) * (ONE / 4n), buy ? 1 + idx : 1 + (len - 1 - idx)];
|
|
2200
|
+
const tickMin = buy ? 0 : 495;
|
|
2201
|
+
const len = (buy ? 495 : 990) - tickMin + 1;
|
|
2202
|
+
const tickPairs = Array.from({ length: len }, (_, idx) => {
|
|
2203
|
+
const weight = buy ? 1 + idx : 1 + (len - 1 - idx);
|
|
2204
|
+
return [tickMin + idx, weight];
|
|
2206
2205
|
});
|
|
2207
|
-
const
|
|
2206
|
+
const tick = config?.tick ?? weightedChoice(tickPairs);
|
|
2208
2207
|
const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
|
|
2209
2208
|
const unit = BigInt(10) ** BigInt(loanTokenDecimals);
|
|
2210
2209
|
const amountBase = BigInt(100 + int(999901));
|
|
@@ -2218,7 +2217,7 @@ function random$1(config) {
|
|
|
2218
2217
|
assets: assetsScaled,
|
|
2219
2218
|
obligationUnits: config?.obligationUnits ?? 0n,
|
|
2220
2219
|
obligationShares: config?.obligationShares ?? 0n,
|
|
2221
|
-
|
|
2220
|
+
tick,
|
|
2222
2221
|
maturity,
|
|
2223
2222
|
expiry: config?.expiry ?? maturity - 1,
|
|
2224
2223
|
start: config?.start ?? maturity - 10,
|
|
@@ -2283,7 +2282,7 @@ const types = {
|
|
|
2283
2282
|
type: "uint256"
|
|
2284
2283
|
},
|
|
2285
2284
|
{
|
|
2286
|
-
name: "
|
|
2285
|
+
name: "tick",
|
|
2287
2286
|
type: "uint256"
|
|
2288
2287
|
},
|
|
2289
2288
|
{
|
|
@@ -2351,7 +2350,7 @@ function hash(offer) {
|
|
|
2351
2350
|
assets: offer.assets,
|
|
2352
2351
|
obligationUnits: offer.obligationUnits,
|
|
2353
2352
|
obligationShares: offer.obligationShares,
|
|
2354
|
-
|
|
2353
|
+
tick: BigInt(offer.tick),
|
|
2355
2354
|
maturity: BigInt(offer.maturity),
|
|
2356
2355
|
expiry: BigInt(offer.expiry),
|
|
2357
2356
|
group: offer.group,
|
|
@@ -2402,7 +2401,7 @@ const OfferAbi = [
|
|
|
2402
2401
|
type: "uint256"
|
|
2403
2402
|
},
|
|
2404
2403
|
{
|
|
2405
|
-
name: "
|
|
2404
|
+
name: "tick",
|
|
2406
2405
|
type: "uint256"
|
|
2407
2406
|
},
|
|
2408
2407
|
{
|
|
@@ -2473,7 +2472,7 @@ function encode$1(offer) {
|
|
|
2473
2472
|
offer.assets,
|
|
2474
2473
|
offer.obligationUnits,
|
|
2475
2474
|
offer.obligationShares,
|
|
2476
|
-
offer.
|
|
2475
|
+
BigInt(offer.tick),
|
|
2477
2476
|
BigInt(offer.maturity),
|
|
2478
2477
|
BigInt(offer.expiry),
|
|
2479
2478
|
offer.group,
|
|
@@ -2498,7 +2497,7 @@ function decode$1(data) {
|
|
|
2498
2497
|
assets: decoded[1],
|
|
2499
2498
|
obligationUnits: decoded[2],
|
|
2500
2499
|
obligationShares: decoded[3],
|
|
2501
|
-
|
|
2500
|
+
tick: Number(decoded[4]),
|
|
2502
2501
|
maturity: from$16(Number(decoded[5])),
|
|
2503
2502
|
expiry: Number(decoded[6]),
|
|
2504
2503
|
group: decoded[7],
|
|
@@ -2848,6 +2847,85 @@ var InvalidQuoteError = class extends BaseError {
|
|
|
2848
2847
|
}
|
|
2849
2848
|
};
|
|
2850
2849
|
|
|
2850
|
+
//#endregion
|
|
2851
|
+
//#region src/core/Tick.ts
|
|
2852
|
+
var Tick_exports = /* @__PURE__ */ __exportAll({
|
|
2853
|
+
InvalidPriceError: () => InvalidPriceError,
|
|
2854
|
+
InvalidTickError: () => InvalidTickError,
|
|
2855
|
+
MAX_PRICE: () => MAX_PRICE,
|
|
2856
|
+
TICK_RANGE: () => TICK_RANGE,
|
|
2857
|
+
priceToTick: () => priceToTick,
|
|
2858
|
+
tickToPrice: () => tickToPrice
|
|
2859
|
+
});
|
|
2860
|
+
/** ln(1 + 0.025), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2861
|
+
const LN_ONE_PLUS_DELTA = 24692612590371501n;
|
|
2862
|
+
/** ln(2), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2863
|
+
const LN2 = 693147180559945309n;
|
|
2864
|
+
const WAD$1 = 10n ** 18n;
|
|
2865
|
+
const WAD_SQUARED = 10n ** 36n;
|
|
2866
|
+
const PRICE_STEP = 10n ** 13n;
|
|
2867
|
+
const HALF_TICK_RANGE = 495n;
|
|
2868
|
+
/** Tick domain supported by Morpho V2. */
|
|
2869
|
+
const TICK_RANGE = 990;
|
|
2870
|
+
/** Max allowed price (1e18 in wad). */
|
|
2871
|
+
const MAX_PRICE = WAD$1;
|
|
2872
|
+
/**
|
|
2873
|
+
* Converts a tick to a wad price using the same approximation and rounding as TickLib.
|
|
2874
|
+
* @param tick - Tick value in the inclusive range [0, 990].
|
|
2875
|
+
* @returns The price in wad units.
|
|
2876
|
+
* @throws {@link InvalidTickError} If tick is not an integer in range [0, 990].
|
|
2877
|
+
*/
|
|
2878
|
+
function tickToPrice(tick) {
|
|
2879
|
+
assertTick(tick);
|
|
2880
|
+
return divHalfDownUnchecked(divHalfDownUnchecked(WAD_SQUARED, WAD$1 + wExp(LN_ONE_PLUS_DELTA * (HALF_TICK_RANGE - BigInt(tick)))), PRICE_STEP) * PRICE_STEP;
|
|
2881
|
+
}
|
|
2882
|
+
/**
|
|
2883
|
+
* Returns the lowest tick with a higher-or-equal price.
|
|
2884
|
+
* @param price - Price in wad units.
|
|
2885
|
+
* @returns The first tick whose {@link tickToPrice} is greater than or equal to `price`.
|
|
2886
|
+
* @throws {@link InvalidPriceError} If price is outside [0, 1e18].
|
|
2887
|
+
*/
|
|
2888
|
+
function priceToTick(price) {
|
|
2889
|
+
assertPrice(price);
|
|
2890
|
+
let low = 0;
|
|
2891
|
+
let high = TICK_RANGE;
|
|
2892
|
+
while (low !== high) {
|
|
2893
|
+
const mid = Math.floor((low + high) / 2);
|
|
2894
|
+
if (tickToPrice(mid) < price) low = mid + 1;
|
|
2895
|
+
else high = mid;
|
|
2896
|
+
}
|
|
2897
|
+
return low;
|
|
2898
|
+
}
|
|
2899
|
+
function divHalfDownUnchecked(x, d) {
|
|
2900
|
+
return (x + (d - 1n) / 2n) / d;
|
|
2901
|
+
}
|
|
2902
|
+
function wExp(x) {
|
|
2903
|
+
if (x < 0n) return WAD_SQUARED / wExp(-x);
|
|
2904
|
+
const q = (x + LN2 / 2n) / LN2;
|
|
2905
|
+
const r = x - q * LN2;
|
|
2906
|
+
const secondTerm = r * r / (2n * WAD$1);
|
|
2907
|
+
const thirdTerm = secondTerm * r / (3n * WAD$1);
|
|
2908
|
+
return WAD$1 + r + secondTerm + thirdTerm << q;
|
|
2909
|
+
}
|
|
2910
|
+
function assertTick(tick) {
|
|
2911
|
+
if (!Number.isInteger(tick) || tick < 0 || tick > TICK_RANGE) throw new InvalidTickError(tick);
|
|
2912
|
+
}
|
|
2913
|
+
function assertPrice(price) {
|
|
2914
|
+
if (price < 0n || price > MAX_PRICE) throw new InvalidPriceError(price);
|
|
2915
|
+
}
|
|
2916
|
+
var InvalidTickError = class extends BaseError {
|
|
2917
|
+
name = "Tick.InvalidTickError";
|
|
2918
|
+
constructor(tick) {
|
|
2919
|
+
super(`Invalid tick: ${tick}. Tick must be an integer between 0 and ${TICK_RANGE}.`);
|
|
2920
|
+
}
|
|
2921
|
+
};
|
|
2922
|
+
var InvalidPriceError = class extends BaseError {
|
|
2923
|
+
name = "Tick.InvalidPriceError";
|
|
2924
|
+
constructor(price) {
|
|
2925
|
+
super(`Invalid price: ${price}. Price must be between 0 and ${MAX_PRICE}.`);
|
|
2926
|
+
}
|
|
2927
|
+
};
|
|
2928
|
+
|
|
2851
2929
|
//#endregion
|
|
2852
2930
|
//#region src/core/TradingFee.ts
|
|
2853
2931
|
var TradingFee_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -3361,7 +3439,7 @@ const BrandTypeId = Symbol.for("mempool/Brand");
|
|
|
3361
3439
|
|
|
3362
3440
|
//#endregion
|
|
3363
3441
|
//#region src/database/drizzle/VERSION.ts
|
|
3364
|
-
const VERSION = "router_v1.
|
|
3442
|
+
const VERSION = "router_v1.8";
|
|
3365
3443
|
|
|
3366
3444
|
//#endregion
|
|
3367
3445
|
//#region src/database/drizzle/schema.ts
|
|
@@ -3513,10 +3591,7 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
3513
3591
|
precision: 78,
|
|
3514
3592
|
scale: 0
|
|
3515
3593
|
}).notNull().default("0"),
|
|
3516
|
-
|
|
3517
|
-
precision: 78,
|
|
3518
|
-
scale: 0
|
|
3519
|
-
}).notNull(),
|
|
3594
|
+
tick: integer("tick").notNull(),
|
|
3520
3595
|
maturity: integer("maturity").notNull(),
|
|
3521
3596
|
expiry: integer("expiry").notNull(),
|
|
3522
3597
|
start: integer("start").notNull(),
|
|
@@ -3581,6 +3656,7 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3581
3656
|
user: varchar("user", { length: 42 }).notNull(),
|
|
3582
3657
|
contract: varchar("contract", { length: 42 }).notNull(),
|
|
3583
3658
|
group: varchar("group", { length: 66 }).notNull(),
|
|
3659
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
3584
3660
|
lower: numeric("lower", {
|
|
3585
3661
|
precision: 78,
|
|
3586
3662
|
scale: 0
|
|
@@ -3595,7 +3671,8 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3595
3671
|
table.chainId,
|
|
3596
3672
|
table.user,
|
|
3597
3673
|
table.contract,
|
|
3598
|
-
table.group
|
|
3674
|
+
table.group,
|
|
3675
|
+
table.obligationId
|
|
3599
3676
|
],
|
|
3600
3677
|
name: "lots_pk"
|
|
3601
3678
|
}),
|
|
@@ -3631,6 +3708,7 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3631
3708
|
user: varchar("user", { length: 42 }).notNull(),
|
|
3632
3709
|
contract: varchar("contract", { length: 42 }).notNull(),
|
|
3633
3710
|
group: varchar("group", { length: 66 }).notNull(),
|
|
3711
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
3634
3712
|
value: numeric("value", {
|
|
3635
3713
|
precision: 78,
|
|
3636
3714
|
scale: 0
|
|
@@ -3640,7 +3718,8 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3640
3718
|
table.chainId,
|
|
3641
3719
|
table.user,
|
|
3642
3720
|
table.contract,
|
|
3643
|
-
table.group
|
|
3721
|
+
table.group,
|
|
3722
|
+
table.obligationId
|
|
3644
3723
|
],
|
|
3645
3724
|
name: "offsets_pk"
|
|
3646
3725
|
}), foreignKey({
|
|
@@ -4231,6 +4310,7 @@ function decodeCallbacks(parameters) {
|
|
|
4231
4310
|
positionContract: loanToken,
|
|
4232
4311
|
positionUser: offer.maker,
|
|
4233
4312
|
group: offer.group,
|
|
4313
|
+
obligationId: obligationId(offer),
|
|
4234
4314
|
size: offer.assets
|
|
4235
4315
|
});
|
|
4236
4316
|
callbacks.push({
|
|
@@ -5169,8 +5249,10 @@ async function getRemoteBlockNumbers(healthClients) {
|
|
|
5169
5249
|
//#region src/api/Schema/BookResponse.ts
|
|
5170
5250
|
var BookResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$5 });
|
|
5171
5251
|
function from$5(level) {
|
|
5252
|
+
const price = tickToPrice(level.tick);
|
|
5172
5253
|
return {
|
|
5173
|
-
|
|
5254
|
+
tick: level.tick,
|
|
5255
|
+
price: price.toString(),
|
|
5174
5256
|
assets: level.assets.toString(),
|
|
5175
5257
|
count: level.count
|
|
5176
5258
|
};
|
|
@@ -5275,7 +5357,7 @@ function from$3(input) {
|
|
|
5275
5357
|
obligation_shares: input.obligationShares.toString(),
|
|
5276
5358
|
start: input.start,
|
|
5277
5359
|
expiry: input.expiry,
|
|
5278
|
-
|
|
5360
|
+
tick: input.tick,
|
|
5279
5361
|
group: input.group,
|
|
5280
5362
|
session: input.session,
|
|
5281
5363
|
callback: input.callback.address,
|
|
@@ -5437,7 +5519,7 @@ const offerExample = {
|
|
|
5437
5519
|
obligation_shares: "0",
|
|
5438
5520
|
start: 1761922790,
|
|
5439
5521
|
expiry: 1761922799,
|
|
5440
|
-
|
|
5522
|
+
tick: 495,
|
|
5441
5523
|
group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
|
|
5442
5524
|
session: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
5443
5525
|
callback: "0x0000000000000000000000000000000000000000",
|
|
@@ -5478,7 +5560,7 @@ const validateOfferExample = {
|
|
|
5478
5560
|
assets: "369216000000000000000000",
|
|
5479
5561
|
obligation_units: "0",
|
|
5480
5562
|
obligation_shares: "0",
|
|
5481
|
-
|
|
5563
|
+
tick: 495,
|
|
5482
5564
|
maturity: 1761922799,
|
|
5483
5565
|
expiry: 1761922799,
|
|
5484
5566
|
start: 1761922790,
|
|
@@ -5622,9 +5704,11 @@ __decorate([ApiProperty({
|
|
|
5622
5704
|
example: offerExample.offer.expiry
|
|
5623
5705
|
})], OfferDataResponse.prototype, "expiry", void 0);
|
|
5624
5706
|
__decorate([ApiProperty({
|
|
5625
|
-
type: "
|
|
5626
|
-
example: offerExample.offer.
|
|
5627
|
-
|
|
5707
|
+
type: "number",
|
|
5708
|
+
example: offerExample.offer.tick,
|
|
5709
|
+
minimum: 0,
|
|
5710
|
+
maximum: 990
|
|
5711
|
+
})], OfferDataResponse.prototype, "tick", void 0);
|
|
5628
5712
|
__decorate([ApiProperty({
|
|
5629
5713
|
type: "string",
|
|
5630
5714
|
example: offerExample.offer.group
|
|
@@ -5865,9 +5949,11 @@ __decorate([ApiProperty({
|
|
|
5865
5949
|
required: false
|
|
5866
5950
|
})], ValidateOfferRequest.prototype, "obligation_shares", void 0);
|
|
5867
5951
|
__decorate([ApiProperty({
|
|
5868
|
-
type: "
|
|
5869
|
-
example: validateOfferExample.
|
|
5870
|
-
|
|
5952
|
+
type: "number",
|
|
5953
|
+
example: validateOfferExample.tick,
|
|
5954
|
+
minimum: 0,
|
|
5955
|
+
maximum: 990
|
|
5956
|
+
})], ValidateOfferRequest.prototype, "tick", void 0);
|
|
5871
5957
|
__decorate([ApiProperty({
|
|
5872
5958
|
type: "number",
|
|
5873
5959
|
example: validateOfferExample.maturity
|
|
@@ -5967,9 +6053,16 @@ __decorate([ApiProperty({
|
|
|
5967
6053
|
description: "List of validation issues. Returned when any offer fails validation."
|
|
5968
6054
|
})], ValidationFailureResponse.prototype, "data", void 0);
|
|
5969
6055
|
var BookLevelResponse = class {};
|
|
6056
|
+
__decorate([ApiProperty({
|
|
6057
|
+
type: "number",
|
|
6058
|
+
example: 495,
|
|
6059
|
+
minimum: 0,
|
|
6060
|
+
maximum: 990
|
|
6061
|
+
})], BookLevelResponse.prototype, "tick", void 0);
|
|
5970
6062
|
__decorate([ApiProperty({
|
|
5971
6063
|
type: "string",
|
|
5972
|
-
example: "
|
|
6064
|
+
example: "500000000000000000",
|
|
6065
|
+
description: "Price derived from tick, scaled by 1e18."
|
|
5973
6066
|
})], BookLevelResponse.prototype, "price", void 0);
|
|
5974
6067
|
__decorate([ApiProperty({
|
|
5975
6068
|
type: "string",
|
|
@@ -5983,6 +6076,7 @@ const positionExample = {
|
|
|
5983
6076
|
chain_id: 1,
|
|
5984
6077
|
contract: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
|
|
5985
6078
|
user: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
|
|
6079
|
+
obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
|
|
5986
6080
|
reserved: "200000000000000000000",
|
|
5987
6081
|
block_number: 21345678
|
|
5988
6082
|
};
|
|
@@ -5999,6 +6093,12 @@ __decorate([ApiProperty({
|
|
|
5999
6093
|
type: "string",
|
|
6000
6094
|
example: positionExample.user
|
|
6001
6095
|
})], PositionListItemResponse.prototype, "user", void 0);
|
|
6096
|
+
__decorate([ApiProperty({
|
|
6097
|
+
type: "string",
|
|
6098
|
+
nullable: true,
|
|
6099
|
+
example: positionExample.obligation_id,
|
|
6100
|
+
description: "Obligation id this reserved amount belongs to, or null if no lots exist."
|
|
6101
|
+
})], PositionListItemResponse.prototype, "obligation_id", void 0);
|
|
6002
6102
|
__decorate([ApiProperty({
|
|
6003
6103
|
type: "string",
|
|
6004
6104
|
example: positionExample.reserved
|
|
@@ -6026,7 +6126,7 @@ __decorate([ApiProperty({
|
|
|
6026
6126
|
})], BookListResponse.prototype, "cursor", void 0);
|
|
6027
6127
|
__decorate([ApiProperty({
|
|
6028
6128
|
type: () => [BookLevelResponse],
|
|
6029
|
-
description: "Aggregated book levels grouped by
|
|
6129
|
+
description: "Aggregated book levels grouped by offer tick."
|
|
6030
6130
|
})], BookListResponse.prototype, "data", void 0);
|
|
6031
6131
|
let BooksController = class BooksController {
|
|
6032
6132
|
async getBook() {}
|
|
@@ -6036,7 +6136,7 @@ __decorate([
|
|
|
6036
6136
|
methods: ["get"],
|
|
6037
6137
|
path: "/v1/books/{obligationId}/{side}",
|
|
6038
6138
|
summary: "Get aggregated book",
|
|
6039
|
-
description: "Returns aggregated book data for a given obligation and side. Offers are grouped by
|
|
6139
|
+
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)."
|
|
6040
6140
|
}),
|
|
6041
6141
|
ApiParam({
|
|
6042
6142
|
name: "obligationId",
|
|
@@ -6061,7 +6161,7 @@ __decorate([
|
|
|
6061
6161
|
name: "limit",
|
|
6062
6162
|
type: "number",
|
|
6063
6163
|
example: 10,
|
|
6064
|
-
description: "Maximum number of
|
|
6164
|
+
description: "Maximum number of tick levels to return."
|
|
6065
6165
|
}),
|
|
6066
6166
|
ApiResponse({
|
|
6067
6167
|
status: 200,
|
|
@@ -6255,6 +6355,11 @@ const configRulesLoanTokenExample = {
|
|
|
6255
6355
|
chain_id: 1,
|
|
6256
6356
|
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
6257
6357
|
};
|
|
6358
|
+
const configRulesCollateralTokenExample = {
|
|
6359
|
+
type: "collateral_token",
|
|
6360
|
+
chain_id: 1,
|
|
6361
|
+
address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
6362
|
+
};
|
|
6258
6363
|
const configRulesOracleExample = {
|
|
6259
6364
|
type: "oracle",
|
|
6260
6365
|
chain_id: 1,
|
|
@@ -6264,6 +6369,7 @@ const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
|
|
|
6264
6369
|
const configRulesPayloadExample = [
|
|
6265
6370
|
configRulesMaturityExample,
|
|
6266
6371
|
configRulesLoanTokenExample,
|
|
6372
|
+
configRulesCollateralTokenExample,
|
|
6267
6373
|
configRulesOracleExample
|
|
6268
6374
|
];
|
|
6269
6375
|
const configContractNames = [
|
|
@@ -6390,7 +6496,7 @@ __decorate([
|
|
|
6390
6496
|
methods: ["get"],
|
|
6391
6497
|
path: "/v1/config/rules",
|
|
6392
6498
|
summary: "Get config rules",
|
|
6393
|
-
description: "Returns configured rules (maturities, loan tokens, oracles) for supported chains."
|
|
6499
|
+
description: "Returns configured rules (maturities, loan tokens, collateral tokens, oracles) for supported chains."
|
|
6394
6500
|
}),
|
|
6395
6501
|
ApiQuery({
|
|
6396
6502
|
name: "cursor",
|
|
@@ -6410,7 +6516,7 @@ __decorate([
|
|
|
6410
6516
|
name: "types",
|
|
6411
6517
|
type: ["string"],
|
|
6412
6518
|
required: false,
|
|
6413
|
-
example: "maturity,loan_token,oracle",
|
|
6519
|
+
example: "maturity,loan_token,collateral_token,oracle",
|
|
6414
6520
|
description: "Filter by rule types (comma-separated).",
|
|
6415
6521
|
style: "form",
|
|
6416
6522
|
explode: false
|
|
@@ -6528,7 +6634,7 @@ __decorate([
|
|
|
6528
6634
|
methods: ["get"],
|
|
6529
6635
|
path: "/v1/users/{userAddress}/positions",
|
|
6530
6636
|
summary: "Get user positions",
|
|
6531
|
-
description: "Returns positions for a user with reserved balance.
|
|
6637
|
+
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."
|
|
6532
6638
|
}),
|
|
6533
6639
|
ApiParam({
|
|
6534
6640
|
name: "userAddress",
|
|
@@ -6616,6 +6722,7 @@ function from$2(position) {
|
|
|
6616
6722
|
chain_id: position.chainId,
|
|
6617
6723
|
contract: position.contract,
|
|
6618
6724
|
user: position.user,
|
|
6725
|
+
obligation_id: position.obligationId,
|
|
6619
6726
|
reserved: position.reserved.toString(),
|
|
6620
6727
|
block_number: position.blockNumber
|
|
6621
6728
|
};
|
|
@@ -6669,10 +6776,11 @@ const ConfigRuleTypes = z$1.enum([
|
|
|
6669
6776
|
"maturity",
|
|
6670
6777
|
"callback",
|
|
6671
6778
|
"loan_token",
|
|
6779
|
+
"collateral_token",
|
|
6672
6780
|
"oracle"
|
|
6673
6781
|
]);
|
|
6674
6782
|
const GetConfigRulesQueryParams = z$1.object({
|
|
6675
|
-
cursor: z$1.string().regex(/^(maturity|callback|loan_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
6783
|
+
cursor: z$1.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({
|
|
6676
6784
|
description: "Pagination cursor in type:chain_id:<value> format",
|
|
6677
6785
|
example: "maturity:1:1730415600:end_of_next_month"
|
|
6678
6786
|
}),
|
|
@@ -6682,7 +6790,7 @@ const GetConfigRulesQueryParams = z$1.object({
|
|
|
6682
6790
|
}),
|
|
6683
6791
|
types: csvArray(ConfigRuleTypes).meta({
|
|
6684
6792
|
description: "Filter by rule types (comma-separated).",
|
|
6685
|
-
example: "maturity,loan_token,oracle"
|
|
6793
|
+
example: "maturity,loan_token,collateral_token,oracle"
|
|
6686
6794
|
}),
|
|
6687
6795
|
chains: csvArray(z$1.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
6688
6796
|
description: "Filter by chain IDs (comma-separated).",
|
|
@@ -6782,12 +6890,11 @@ const GetObligationParams = z$1.object({ obligation_id: z$1.string({ error: "Obl
|
|
|
6782
6890
|
description: "Obligation id",
|
|
6783
6891
|
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
6784
6892
|
}) });
|
|
6785
|
-
/** Validate a book cursor format: {side,
|
|
6893
|
+
/** Validate a book cursor format: {side, lastTick, offersCursor} */
|
|
6786
6894
|
function isValidBookCursor(cursorString) {
|
|
6787
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
6788
6895
|
try {
|
|
6789
6896
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
6790
|
-
return (v?.side === "buy" || v?.side === "sell") &&
|
|
6897
|
+
return (v?.side === "buy" || v?.side === "sell") && typeof v?.lastTick === "number" && Number.isInteger(v.lastTick) && (v?.offersCursor === null || typeof v?.offersCursor === "string");
|
|
6791
6898
|
} catch {
|
|
6792
6899
|
return false;
|
|
6793
6900
|
}
|
|
@@ -6885,7 +6992,7 @@ async function getBook(params, db) {
|
|
|
6885
6992
|
side: query.side,
|
|
6886
6993
|
levels_count: levels.length,
|
|
6887
6994
|
has_next_cursor: nextCursor != null,
|
|
6888
|
-
|
|
6995
|
+
first_level_tick: firstLevel?.tick ?? null,
|
|
6889
6996
|
first_level_assets: firstLevel?.assets.toString() ?? null,
|
|
6890
6997
|
first_level_count: firstLevel?.count ?? null
|
|
6891
6998
|
});
|
|
@@ -7037,6 +7144,33 @@ const assets = {
|
|
|
7037
7144
|
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
7038
7145
|
]
|
|
7039
7146
|
};
|
|
7147
|
+
const collateralAssets = {
|
|
7148
|
+
[ChainId.ETHEREUM.toString()]: [
|
|
7149
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7150
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7151
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7152
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7153
|
+
],
|
|
7154
|
+
[ChainId.BASE.toString()]: [
|
|
7155
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
7156
|
+
"0x4200000000000000000000000000000000000006",
|
|
7157
|
+
"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
|
|
7158
|
+
"0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
|
|
7159
|
+
"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
|
|
7160
|
+
],
|
|
7161
|
+
[ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
|
|
7162
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7163
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7164
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7165
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7166
|
+
],
|
|
7167
|
+
[ChainId.ANVIL.toString()]: [
|
|
7168
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7169
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7170
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7171
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7172
|
+
]
|
|
7173
|
+
};
|
|
7040
7174
|
const oracles = {
|
|
7041
7175
|
[ChainId.ETHEREUM.toString()]: [
|
|
7042
7176
|
"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
|
|
@@ -7096,7 +7230,7 @@ const configs = {
|
|
|
7096
7230
|
//#endregion
|
|
7097
7231
|
//#region src/gatekeeper/ConfigRules.ts
|
|
7098
7232
|
/**
|
|
7099
|
-
* Build the configured rules (maturities + callback addresses + loan tokens + oracles) for the provided chains.
|
|
7233
|
+
* Build the configured rules (maturities + callback addresses + loan tokens + collateral tokens + oracles) for the provided chains.
|
|
7100
7234
|
* @param chains - Chains to include in the configured rules.
|
|
7101
7235
|
* @returns Sorted list of config rules.
|
|
7102
7236
|
*/
|
|
@@ -7116,6 +7250,12 @@ function buildConfigRules(chains) {
|
|
|
7116
7250
|
chain_id: chain.id,
|
|
7117
7251
|
address: normalizeAddress(address)
|
|
7118
7252
|
});
|
|
7253
|
+
const collateralTokens = collateralAssets[chain.id.toString()] ?? [];
|
|
7254
|
+
for (const address of collateralTokens) rules.push({
|
|
7255
|
+
type: "collateral_token",
|
|
7256
|
+
chain_id: chain.id,
|
|
7257
|
+
address: normalizeAddress(address)
|
|
7258
|
+
});
|
|
7119
7259
|
const oracles$2 = oracles[chain.id.toString()] ?? [];
|
|
7120
7260
|
for (const address of oracles$2) rules.push({
|
|
7121
7261
|
type: "oracle",
|
|
@@ -7143,6 +7283,10 @@ function buildConfigRulesChecksum(rules) {
|
|
|
7143
7283
|
hash.update(`callback:${rule.chain_id}:${rule.callback_type}:${rule.address}\n`);
|
|
7144
7284
|
continue;
|
|
7145
7285
|
}
|
|
7286
|
+
if (rule.type === "collateral_token") {
|
|
7287
|
+
hash.update(`collateral_token:${rule.chain_id}:${rule.address}\n`);
|
|
7288
|
+
continue;
|
|
7289
|
+
}
|
|
7146
7290
|
if (rule.type === "oracle") {
|
|
7147
7291
|
hash.update(`oracle:${rule.chain_id}:${rule.address}\n`);
|
|
7148
7292
|
continue;
|
|
@@ -7163,6 +7307,7 @@ function compareConfigRules(left, right) {
|
|
|
7163
7307
|
return left.address.localeCompare(right.address);
|
|
7164
7308
|
}
|
|
7165
7309
|
if (left.type === "loan_token" && right.type === "loan_token") return left.address.localeCompare(right.address);
|
|
7310
|
+
if (left.type === "collateral_token" && right.type === "collateral_token") return left.address.localeCompare(right.address);
|
|
7166
7311
|
if (left.type === "oracle" && right.type === "oracle") return left.address.localeCompare(right.address);
|
|
7167
7312
|
return 0;
|
|
7168
7313
|
}
|
|
@@ -7209,6 +7354,7 @@ function formatCursor(rule) {
|
|
|
7209
7354
|
if (rule.type === "maturity") return `maturity:${rule.chain_id}:${rule.timestamp}:${rule.name}`;
|
|
7210
7355
|
if (rule.type === "callback") return `callback:${rule.chain_id}:${rule.callback_type}:${rule.address.toLowerCase()}`;
|
|
7211
7356
|
if (rule.type === "oracle") return `oracle:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7357
|
+
if (rule.type === "collateral_token") return `collateral_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7212
7358
|
return `loan_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7213
7359
|
}
|
|
7214
7360
|
function parseCursor(cursor) {
|
|
@@ -7241,7 +7387,7 @@ function parseCursor(cursor) {
|
|
|
7241
7387
|
address: parseAddress(addressValue, "Cursor address")
|
|
7242
7388
|
};
|
|
7243
7389
|
}
|
|
7244
|
-
if (type === "loan_token" || type === "oracle") {
|
|
7390
|
+
if (type === "loan_token" || type === "collateral_token" || type === "oracle") {
|
|
7245
7391
|
const addressValue = rest.join(":");
|
|
7246
7392
|
if (!addressValue) throw new BadRequestError(`Cursor must be in the format ${type}:chain_id:address`);
|
|
7247
7393
|
return {
|
|
@@ -7268,7 +7414,7 @@ function parseAddress(address, label) {
|
|
|
7268
7414
|
return address.toLowerCase();
|
|
7269
7415
|
}
|
|
7270
7416
|
function isConfigRuleType(value) {
|
|
7271
|
-
return value === "maturity" || value === "callback" || value === "loan_token" || value === "oracle";
|
|
7417
|
+
return value === "maturity" || value === "callback" || value === "loan_token" || value === "collateral_token" || value === "oracle";
|
|
7272
7418
|
}
|
|
7273
7419
|
function isMaturityType(value) {
|
|
7274
7420
|
return Object.values(MaturityType).includes(value);
|
|
@@ -7615,7 +7761,7 @@ function create$15(config) {
|
|
|
7615
7761
|
assets: offers.assets,
|
|
7616
7762
|
obligationUnits: offers.obligationUnits,
|
|
7617
7763
|
obligationShares: offers.obligationShares,
|
|
7618
|
-
|
|
7764
|
+
tick: offers.tick,
|
|
7619
7765
|
maturity: offers.maturity,
|
|
7620
7766
|
expiry: offers.expiry,
|
|
7621
7767
|
start: offers.start,
|
|
@@ -7635,7 +7781,7 @@ function create$15(config) {
|
|
|
7635
7781
|
assets: BigInt(row.assets),
|
|
7636
7782
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7637
7783
|
obligationShares: BigInt(row.obligationShares),
|
|
7638
|
-
|
|
7784
|
+
tick: row.tick,
|
|
7639
7785
|
maturity: from$16(row.maturity),
|
|
7640
7786
|
expiry: row.expiry,
|
|
7641
7787
|
start: row.start,
|
|
@@ -7717,8 +7863,8 @@ function create$15(config) {
|
|
|
7717
7863
|
const now$2 = now();
|
|
7718
7864
|
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
7719
7865
|
obligationId: offers.obligationId,
|
|
7720
|
-
price: offers.
|
|
7721
|
-
}).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(inArray(offers.obligationId, obligationIds), eq(offers.buy, side === "buy"), gte(offers.expiry, now$2), gte(offers.maturity, now$2), lte(offers.start, now$2), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? sql`${offers.
|
|
7866
|
+
price: offers.tick
|
|
7867
|
+
}).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(inArray(offers.obligationId, obligationIds), eq(offers.buy, side === "buy"), gte(offers.expiry, now$2), gte(offers.maturity, now$2), lte(offers.start, now$2), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? sql`${offers.tick} ASC` : sql`${offers.tick} DESC`);
|
|
7722
7868
|
const [bestBuys, bestSells] = await Promise.all([query({ side: "buy" }), query({ side: "sell" })]);
|
|
7723
7869
|
const quotes = /* @__PURE__ */ new Map();
|
|
7724
7870
|
for (const row of bestSells) quotes.set(row.obligationId, {
|
|
@@ -7834,7 +7980,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7834
7980
|
obligationUnits: offers.obligationUnits,
|
|
7835
7981
|
obligationShares: offers.obligationShares,
|
|
7836
7982
|
consumed: groups.consumed,
|
|
7837
|
-
|
|
7983
|
+
tick: offers.tick,
|
|
7838
7984
|
maturity: offers.maturity,
|
|
7839
7985
|
expiry: offers.expiry,
|
|
7840
7986
|
start: offers.start,
|
|
@@ -7872,7 +8018,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7872
8018
|
assets: BigInt(row.assets),
|
|
7873
8019
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7874
8020
|
obligationShares: BigInt(row.obligationShares),
|
|
7875
|
-
|
|
8021
|
+
tick: row.tick,
|
|
7876
8022
|
maturity: from$16(row.maturity),
|
|
7877
8023
|
expiry: row.expiry,
|
|
7878
8024
|
start: row.start,
|
|
@@ -8271,7 +8417,7 @@ async function getOffers(apiClient, parameters) {
|
|
|
8271
8417
|
assets: offerData.assets,
|
|
8272
8418
|
obligation_units: offerData.obligation_units,
|
|
8273
8419
|
obligation_shares: offerData.obligation_shares,
|
|
8274
|
-
|
|
8420
|
+
tick: offerData.tick,
|
|
8275
8421
|
maturity: from$16(offerData.obligation.maturity),
|
|
8276
8422
|
expiry: offerData.expiry,
|
|
8277
8423
|
start: offerData.start,
|
|
@@ -8630,6 +8776,7 @@ function create$12(config) {
|
|
|
8630
8776
|
return {
|
|
8631
8777
|
get: async (parameters) => {
|
|
8632
8778
|
const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT$2 } = parameters;
|
|
8779
|
+
const tickSortDirection = side === "sell" ? "asc" : "desc";
|
|
8633
8780
|
const inputCursor = LevelCursor.decode(cursorString, logger);
|
|
8634
8781
|
if (cursorString != null && inputCursor === null) return {
|
|
8635
8782
|
levels: [],
|
|
@@ -8644,23 +8791,23 @@ function create$12(config) {
|
|
|
8644
8791
|
cursor: inputCursor?.offersCursor ?? void 0,
|
|
8645
8792
|
limit: fetchLimit
|
|
8646
8793
|
});
|
|
8647
|
-
const
|
|
8794
|
+
const tickMap = /* @__PURE__ */ new Map();
|
|
8648
8795
|
for (const row of rows) {
|
|
8649
|
-
const
|
|
8650
|
-
const existing = priceMap.get(priceKey);
|
|
8796
|
+
const existing = tickMap.get(row.tick);
|
|
8651
8797
|
if (existing) {
|
|
8652
8798
|
existing.assets += row.takeable;
|
|
8653
8799
|
existing.count += 1;
|
|
8654
|
-
} else
|
|
8800
|
+
} else tickMap.set(row.tick, {
|
|
8655
8801
|
assets: row.takeable,
|
|
8656
8802
|
count: 1
|
|
8657
8803
|
});
|
|
8658
8804
|
}
|
|
8659
|
-
const levels = Array.from(
|
|
8660
|
-
|
|
8661
|
-
assets:
|
|
8662
|
-
count:
|
|
8805
|
+
const levels = Array.from(tickMap.entries()).map(([tick, level]) => ({
|
|
8806
|
+
tick,
|
|
8807
|
+
assets: level.assets,
|
|
8808
|
+
count: level.count
|
|
8663
8809
|
}));
|
|
8810
|
+
levels.sort((a, b) => tickSortDirection === "asc" ? a.tick - b.tick : b.tick - a.tick);
|
|
8664
8811
|
const paginatedLevels = levels.slice(0, limit);
|
|
8665
8812
|
const hasMore = levels.length > limit || offersNextCursor !== null;
|
|
8666
8813
|
const lastLevel = paginatedLevels[paginatedLevels.length - 1];
|
|
@@ -8706,14 +8853,14 @@ async function _getOffers(db, params) {
|
|
|
8706
8853
|
AND (s.code IS NULL OR s.code = ${Status.VALID})
|
|
8707
8854
|
ORDER BY
|
|
8708
8855
|
o.group_chain_id, o.group_maker, o."group_group",
|
|
8709
|
-
o.
|
|
8856
|
+
o.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`}, o.block_number ASC, o.assets DESC, o.hash ASC
|
|
8710
8857
|
),
|
|
8711
8858
|
enriched AS (
|
|
8712
8859
|
SELECT
|
|
8713
8860
|
w.*,
|
|
8714
8861
|
g.consumed, g.chain_id, obl.loan_token,
|
|
8715
8862
|
CASE WHEN ${priceSortDirection === "asc" ? sql`TRUE` : sql`FALSE`}
|
|
8716
|
-
THEN w.
|
|
8863
|
+
THEN w.tick ELSE -w.tick END AS tick_norm,
|
|
8717
8864
|
w.block_number AS block_norm,
|
|
8718
8865
|
-w.assets AS assets_norm,
|
|
8719
8866
|
w.hash AS hash_norm
|
|
@@ -8730,33 +8877,35 @@ async function _getOffers(db, params) {
|
|
|
8730
8877
|
FROM enriched e
|
|
8731
8878
|
${cursor != null ? sql`
|
|
8732
8879
|
WHERE
|
|
8733
|
-
(e.
|
|
8880
|
+
(e.tick_norm, e.block_norm, e.assets_norm, e.hash_norm)
|
|
8734
8881
|
> (
|
|
8735
8882
|
CASE WHEN ${priceSortDirection === "asc" ? sql`TRUE` : sql`FALSE`}
|
|
8736
|
-
THEN ${cursor.
|
|
8883
|
+
THEN ${cursor.tick}::integer ELSE -${cursor.tick}::integer END,
|
|
8737
8884
|
${cursor.blockNumber},
|
|
8738
8885
|
-${cursor.assets}::numeric,
|
|
8739
8886
|
${cursor.hash}
|
|
8740
8887
|
)` : sql``}
|
|
8741
|
-
ORDER BY e.
|
|
8888
|
+
ORDER BY e.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`}, e.block_number ASC, e.assets DESC, e.hash ASC
|
|
8742
8889
|
LIMIT ${limit}
|
|
8743
8890
|
),
|
|
8744
|
-
-- Compute sum of offsets per position
|
|
8891
|
+
-- Compute sum of offsets per position and obligation
|
|
8745
8892
|
position_offsets AS (
|
|
8746
8893
|
SELECT
|
|
8747
8894
|
chain_id,
|
|
8748
8895
|
"user",
|
|
8749
8896
|
contract,
|
|
8897
|
+
obligation_id,
|
|
8750
8898
|
SUM(value::numeric) AS total_offset
|
|
8751
8899
|
FROM ${offsets}
|
|
8752
|
-
GROUP BY chain_id, "user", contract
|
|
8900
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
8753
8901
|
),
|
|
8754
|
-
-- Compute position_consumed: sum of consumed from all groups with lots on each position (converted to lot terms)
|
|
8902
|
+
-- Compute position_consumed: sum of consumed from all groups with lots on each position+obligation (converted to lot terms)
|
|
8755
8903
|
position_consumed AS (
|
|
8756
8904
|
SELECT
|
|
8757
8905
|
l.chain_id,
|
|
8758
8906
|
l.contract,
|
|
8759
8907
|
l."user",
|
|
8908
|
+
l.obligation_id,
|
|
8760
8909
|
SUM(
|
|
8761
8910
|
CASE
|
|
8762
8911
|
WHEN wo.assets::numeric > 0
|
|
@@ -8773,7 +8922,7 @@ async function _getOffers(db, params) {
|
|
|
8773
8922
|
ON wo.group_chain_id = g.chain_id
|
|
8774
8923
|
AND LOWER(wo.group_maker) = LOWER(g.maker)
|
|
8775
8924
|
AND wo.group_group = g."group"
|
|
8776
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
8925
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
8777
8926
|
),
|
|
8778
8927
|
-- Compute callback contributions with lot balance
|
|
8779
8928
|
callback_contributions AS (
|
|
@@ -8781,7 +8930,7 @@ async function _getOffers(db, params) {
|
|
|
8781
8930
|
p.hash,
|
|
8782
8931
|
p.obligation_id,
|
|
8783
8932
|
p.assets,
|
|
8784
|
-
p.
|
|
8933
|
+
p.tick,
|
|
8785
8934
|
p.obligation_units,
|
|
8786
8935
|
p.obligation_shares,
|
|
8787
8936
|
p.maturity,
|
|
@@ -8826,6 +8975,7 @@ async function _getOffers(db, params) {
|
|
|
8826
8975
|
AND LOWER(l.contract) = LOWER(c.position_contract)
|
|
8827
8976
|
AND LOWER(l."user") = LOWER(c.position_user)
|
|
8828
8977
|
AND l."group" = p.group_group
|
|
8978
|
+
AND l.obligation_id = p.obligation_id
|
|
8829
8979
|
LEFT JOIN ${positions} pos
|
|
8830
8980
|
ON pos.chain_id = c.position_chain_id
|
|
8831
8981
|
AND LOWER(pos.contract) = LOWER(c.position_contract)
|
|
@@ -8834,10 +8984,12 @@ async function _getOffers(db, params) {
|
|
|
8834
8984
|
ON pos_offsets.chain_id = c.position_chain_id
|
|
8835
8985
|
AND LOWER(pos_offsets.contract) = LOWER(c.position_contract)
|
|
8836
8986
|
AND LOWER(pos_offsets."user") = LOWER(c.position_user)
|
|
8987
|
+
AND pos_offsets.obligation_id = p.obligation_id
|
|
8837
8988
|
LEFT JOIN position_consumed pc
|
|
8838
8989
|
ON pc.chain_id = c.position_chain_id
|
|
8839
8990
|
AND LOWER(pc.contract) = LOWER(c.position_contract)
|
|
8840
8991
|
AND LOWER(pc."user") = LOWER(c.position_user)
|
|
8992
|
+
AND pc.obligation_id = p.obligation_id
|
|
8841
8993
|
),
|
|
8842
8994
|
-- Compute contribution per callback in loan terms (loan token only — collateral positions are not indexed)
|
|
8843
8995
|
callback_loan_contribution AS (
|
|
@@ -8855,7 +9007,7 @@ async function _getOffers(db, params) {
|
|
|
8855
9007
|
hash,
|
|
8856
9008
|
obligation_id,
|
|
8857
9009
|
assets,
|
|
8858
|
-
|
|
9010
|
+
tick,
|
|
8859
9011
|
obligation_units,
|
|
8860
9012
|
obligation_shares,
|
|
8861
9013
|
maturity,
|
|
@@ -8881,13 +9033,13 @@ async function _getOffers(db, params) {
|
|
|
8881
9033
|
WHERE clc.callback_id IS NOT NULL
|
|
8882
9034
|
ORDER BY clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user, clc.contribution_in_loan DESC
|
|
8883
9035
|
) deduped
|
|
8884
|
-
GROUP BY hash, obligation_id, assets,
|
|
9036
|
+
GROUP BY hash, obligation_id, assets, tick, obligation_units, obligation_shares, maturity, expiry, start, group_group, buy,
|
|
8885
9037
|
callback_address, callback_data, block_number, group_chain_id, group_maker,
|
|
8886
9038
|
consumed, chain_id, loan_token, session
|
|
8887
9039
|
UNION ALL
|
|
8888
9040
|
-- Sell offers without callbacks: collateral positions not indexed, takeable = assets - consumed
|
|
8889
9041
|
SELECT
|
|
8890
|
-
p.hash, p.obligation_id, p.assets, p.
|
|
9042
|
+
p.hash, p.obligation_id, p.assets, p.tick,
|
|
8891
9043
|
p.obligation_units, p.obligation_shares,
|
|
8892
9044
|
p.maturity, p.expiry, p.start, p.group_group,
|
|
8893
9045
|
p.buy, p.callback_address, p.callback_data,
|
|
@@ -8909,7 +9061,7 @@ async function _getOffers(db, params) {
|
|
|
8909
9061
|
oc.obligation_units,
|
|
8910
9062
|
oc.obligation_shares,
|
|
8911
9063
|
oc.consumed,
|
|
8912
|
-
oc.
|
|
9064
|
+
oc.tick,
|
|
8913
9065
|
oc.maturity,
|
|
8914
9066
|
oc.expiry,
|
|
8915
9067
|
oc.start,
|
|
@@ -8941,7 +9093,7 @@ async function _getOffers(db, params) {
|
|
|
8941
9093
|
))
|
|
8942
9094
|
END > 0
|
|
8943
9095
|
ORDER BY
|
|
8944
|
-
oc.
|
|
9096
|
+
oc.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`},
|
|
8945
9097
|
oc.block_number ASC,
|
|
8946
9098
|
oc.assets DESC,
|
|
8947
9099
|
oc.hash ASC;
|
|
@@ -8954,7 +9106,7 @@ async function _getOffers(db, params) {
|
|
|
8954
9106
|
assets: BigInt(row.assets),
|
|
8955
9107
|
obligationUnits: BigInt(row.obligation_units ?? 0),
|
|
8956
9108
|
obligationShares: BigInt(row.obligation_shares ?? 0),
|
|
8957
|
-
|
|
9109
|
+
tick: row.tick,
|
|
8958
9110
|
maturity: row.maturity,
|
|
8959
9111
|
expiry: row.expiry,
|
|
8960
9112
|
start: row.start,
|
|
@@ -8986,7 +9138,7 @@ let Cursor;
|
|
|
8986
9138
|
function encode(row, totalReturned, now, side) {
|
|
8987
9139
|
return Buffer.from(JSON.stringify({
|
|
8988
9140
|
side,
|
|
8989
|
-
|
|
9141
|
+
tick: row.tick,
|
|
8990
9142
|
blockNumber: row.blockNumber,
|
|
8991
9143
|
assets: row.assets.toString(),
|
|
8992
9144
|
hash: row.hash,
|
|
@@ -8997,10 +9149,9 @@ let Cursor;
|
|
|
8997
9149
|
_Cursor.encode = encode;
|
|
8998
9150
|
function decode(cursorString, logger) {
|
|
8999
9151
|
if (cursorString == null) return null;
|
|
9000
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
9001
9152
|
try {
|
|
9002
9153
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
9003
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
9154
|
+
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) && isHex(v?.hash) && typeof v?.totalReturned === "number" && Number.isInteger(v.totalReturned) && typeof v?.now === "number" && Number.isInteger(v.now)) return v;
|
|
9004
9155
|
throw new Error("Invalid cursor");
|
|
9005
9156
|
} catch {
|
|
9006
9157
|
logger.error({
|
|
@@ -9018,7 +9169,7 @@ let LevelCursor;
|
|
|
9018
9169
|
function encode(lastLevel, offersCursor, side, now) {
|
|
9019
9170
|
return Buffer.from(JSON.stringify({
|
|
9020
9171
|
side,
|
|
9021
|
-
|
|
9172
|
+
lastTick: lastLevel.tick,
|
|
9022
9173
|
now,
|
|
9023
9174
|
offersCursor
|
|
9024
9175
|
})).toString("base64url");
|
|
@@ -9026,10 +9177,9 @@ let LevelCursor;
|
|
|
9026
9177
|
_LevelCursor.encode = encode;
|
|
9027
9178
|
function decode(cursorString, logger) {
|
|
9028
9179
|
if (cursorString == null) return null;
|
|
9029
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
9030
9180
|
try {
|
|
9031
9181
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
9032
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
9182
|
+
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;
|
|
9033
9183
|
throw new Error("Invalid book cursor");
|
|
9034
9184
|
} catch {
|
|
9035
9185
|
logger.error({
|
|
@@ -9172,31 +9322,33 @@ function create$9(db) {
|
|
|
9172
9322
|
function create$8(db) {
|
|
9173
9323
|
return {
|
|
9174
9324
|
get: async (parameters) => {
|
|
9175
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9325
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9176
9326
|
const conditions = [];
|
|
9177
9327
|
if (chainId !== void 0) conditions.push(eq(lots.chainId, chainId));
|
|
9178
9328
|
if (user !== void 0) conditions.push(eq(lots.user, user.toLowerCase()));
|
|
9179
9329
|
if (contract !== void 0) conditions.push(eq(lots.contract, contract.toLowerCase()));
|
|
9180
9330
|
if (group !== void 0) conditions.push(eq(lots.group, group));
|
|
9331
|
+
if (obligationId !== void 0) conditions.push(eq(lots.obligationId, obligationId));
|
|
9181
9332
|
return (await db.select().from(lots).where(conditions.length > 0 ? and(...conditions) : void 0)).map((row) => ({
|
|
9182
9333
|
chainId: row.chainId,
|
|
9183
9334
|
user: row.user,
|
|
9184
9335
|
contract: row.contract,
|
|
9185
9336
|
group: row.group,
|
|
9337
|
+
obligationId: row.obligationId,
|
|
9186
9338
|
lower: BigInt(row.lower),
|
|
9187
9339
|
upper: BigInt(row.upper)
|
|
9188
9340
|
}));
|
|
9189
9341
|
},
|
|
9190
9342
|
create: async (parameters) => {
|
|
9191
9343
|
if (parameters.length === 0) return;
|
|
9192
|
-
const
|
|
9344
|
+
const lotsByKey = /* @__PURE__ */ new Map();
|
|
9193
9345
|
for (const offer of parameters) {
|
|
9194
|
-
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}`.toLowerCase();
|
|
9195
|
-
const existing =
|
|
9196
|
-
if (!existing || offer.size > existing.size)
|
|
9346
|
+
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}-${offer.obligationId}`.toLowerCase();
|
|
9347
|
+
const existing = lotsByKey.get(key);
|
|
9348
|
+
if (!existing || offer.size > existing.size) lotsByKey.set(key, offer);
|
|
9197
9349
|
}
|
|
9198
|
-
for (const offer of
|
|
9199
|
-
const maxUpperResult = await db.select({ maxUpper: sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase())));
|
|
9350
|
+
for (const offer of lotsByKey.values()) if ((await db.select().from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase()), eq(lots.group, offer.group.toLowerCase()), eq(lots.obligationId, offer.obligationId.toLowerCase()))).limit(1)).length === 0) {
|
|
9351
|
+
const maxUpperResult = await db.select({ maxUpper: sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase()), eq(lots.obligationId, offer.obligationId.toLowerCase())));
|
|
9200
9352
|
const newLower = BigInt(maxUpperResult[0]?.maxUpper ?? "0");
|
|
9201
9353
|
const newUpper = newLower + offer.size;
|
|
9202
9354
|
await db.insert(lots).values({
|
|
@@ -9204,6 +9356,7 @@ function create$8(db) {
|
|
|
9204
9356
|
user: offer.positionUser.toLowerCase(),
|
|
9205
9357
|
contract: offer.positionContract.toLowerCase(),
|
|
9206
9358
|
group: offer.group.toLowerCase(),
|
|
9359
|
+
obligationId: offer.obligationId.toLowerCase(),
|
|
9207
9360
|
lower: newLower.toString(),
|
|
9208
9361
|
upper: newUpper.toString()
|
|
9209
9362
|
});
|
|
@@ -9258,17 +9411,19 @@ function create$7(db) {
|
|
|
9258
9411
|
//#region src/database/domains/Offsets.ts
|
|
9259
9412
|
function create$6(db) {
|
|
9260
9413
|
return { get: async (parameters) => {
|
|
9261
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9414
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9262
9415
|
const conditions = [];
|
|
9263
9416
|
if (chainId !== void 0) conditions.push(eq(offsets.chainId, chainId));
|
|
9264
9417
|
if (user !== void 0) conditions.push(eq(offsets.user, user.toLowerCase()));
|
|
9265
9418
|
if (contract !== void 0) conditions.push(eq(offsets.contract, contract.toLowerCase()));
|
|
9266
9419
|
if (group !== void 0) conditions.push(eq(offsets.group, group));
|
|
9420
|
+
if (obligationId !== void 0) conditions.push(eq(offsets.obligationId, obligationId));
|
|
9267
9421
|
return (await db.select().from(offsets).where(conditions.length > 0 ? and(...conditions) : void 0)).map((row) => ({
|
|
9268
9422
|
chainId: row.chainId,
|
|
9269
9423
|
user: row.user,
|
|
9270
9424
|
contract: row.contract,
|
|
9271
9425
|
group: row.group,
|
|
9426
|
+
obligationId: row.obligationId,
|
|
9272
9427
|
value: BigInt(row.value)
|
|
9273
9428
|
}));
|
|
9274
9429
|
} };
|
|
@@ -9418,7 +9573,8 @@ const create$4 = (db) => {
|
|
|
9418
9573
|
if (!parsed.chainId || !parsed.contract) throw new Error("Invalid cursor format");
|
|
9419
9574
|
cursor = {
|
|
9420
9575
|
chainId: parsed.chainId,
|
|
9421
|
-
contract: parsed.contract
|
|
9576
|
+
contract: parsed.contract,
|
|
9577
|
+
obligationId: parsed.obligationId ?? null
|
|
9422
9578
|
};
|
|
9423
9579
|
}
|
|
9424
9580
|
const raw = await db.execute(sql`
|
|
@@ -9427,16 +9583,18 @@ const create$4 = (db) => {
|
|
|
9427
9583
|
chain_id,
|
|
9428
9584
|
"user",
|
|
9429
9585
|
contract,
|
|
9586
|
+
obligation_id,
|
|
9430
9587
|
SUM(value::numeric) AS total_offset
|
|
9431
9588
|
FROM ${offsets}
|
|
9432
9589
|
WHERE LOWER("user") = LOWER(${user})
|
|
9433
|
-
GROUP BY chain_id, "user", contract
|
|
9590
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
9434
9591
|
),
|
|
9435
9592
|
position_consumed AS (
|
|
9436
9593
|
SELECT
|
|
9437
9594
|
l.chain_id,
|
|
9438
9595
|
l.contract,
|
|
9439
9596
|
l."user",
|
|
9597
|
+
l.obligation_id,
|
|
9440
9598
|
SUM(
|
|
9441
9599
|
CASE
|
|
9442
9600
|
WHEN offer_agg.assets > 0
|
|
@@ -9462,50 +9620,64 @@ const create$4 = (db) => {
|
|
|
9462
9620
|
AND LOWER(offer_agg.group_maker) = LOWER(g.maker)
|
|
9463
9621
|
AND offer_agg."group_group" = g."group"
|
|
9464
9622
|
WHERE LOWER(l."user") = LOWER(${user})
|
|
9465
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
9623
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
9466
9624
|
),
|
|
9467
9625
|
position_max_lot AS (
|
|
9468
9626
|
SELECT
|
|
9469
9627
|
chain_id,
|
|
9470
9628
|
contract,
|
|
9471
9629
|
"user",
|
|
9630
|
+
obligation_id,
|
|
9472
9631
|
MAX(upper::numeric) AS max_upper
|
|
9473
9632
|
FROM ${lots}
|
|
9474
9633
|
WHERE LOWER("user") = LOWER(${user})
|
|
9475
|
-
GROUP BY chain_id, contract, "user"
|
|
9634
|
+
GROUP BY chain_id, contract, "user", obligation_id
|
|
9635
|
+
),
|
|
9636
|
+
per_obligation AS (
|
|
9637
|
+
SELECT
|
|
9638
|
+
pml.chain_id,
|
|
9639
|
+
pml.contract,
|
|
9640
|
+
pml."user",
|
|
9641
|
+
pml.obligation_id,
|
|
9642
|
+
GREATEST(0,
|
|
9643
|
+
COALESCE(pml.max_upper, 0)
|
|
9644
|
+
- COALESCE(po.total_offset, 0)
|
|
9645
|
+
- COALESCE(pc.consumed, 0)
|
|
9646
|
+
)::text AS reserved_balance
|
|
9647
|
+
FROM position_max_lot pml
|
|
9648
|
+
LEFT JOIN position_offsets po
|
|
9649
|
+
ON po.chain_id = pml.chain_id
|
|
9650
|
+
AND LOWER(po.contract) = LOWER(pml.contract)
|
|
9651
|
+
AND LOWER(po."user") = LOWER(pml."user")
|
|
9652
|
+
AND po.obligation_id = pml.obligation_id
|
|
9653
|
+
LEFT JOIN position_consumed pc
|
|
9654
|
+
ON pc.chain_id = pml.chain_id
|
|
9655
|
+
AND LOWER(pc.contract) = LOWER(pml.contract)
|
|
9656
|
+
AND LOWER(pc."user") = LOWER(pml."user")
|
|
9657
|
+
AND pc.obligation_id = pml.obligation_id
|
|
9476
9658
|
)
|
|
9477
9659
|
SELECT
|
|
9478
9660
|
p.chain_id,
|
|
9479
9661
|
p.contract,
|
|
9480
9662
|
p."user",
|
|
9481
9663
|
p.block_number,
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
- COALESCE(po.total_offset, 0)
|
|
9485
|
-
- COALESCE(pc.consumed, 0)
|
|
9486
|
-
)::text AS reserved_balance
|
|
9664
|
+
po.obligation_id,
|
|
9665
|
+
COALESCE(po.reserved_balance, '0') AS reserved_balance
|
|
9487
9666
|
FROM ${positions} p
|
|
9488
|
-
LEFT JOIN
|
|
9667
|
+
LEFT JOIN per_obligation po
|
|
9489
9668
|
ON po.chain_id = p.chain_id
|
|
9490
9669
|
AND LOWER(po.contract) = LOWER(p.contract)
|
|
9491
9670
|
AND LOWER(po."user") = LOWER(p."user")
|
|
9492
|
-
LEFT JOIN position_consumed pc
|
|
9493
|
-
ON pc.chain_id = p.chain_id
|
|
9494
|
-
AND LOWER(pc.contract) = LOWER(p.contract)
|
|
9495
|
-
AND LOWER(pc."user") = LOWER(p."user")
|
|
9496
|
-
LEFT JOIN position_max_lot pml
|
|
9497
|
-
ON pml.chain_id = p.chain_id
|
|
9498
|
-
AND LOWER(pml.contract) = LOWER(p.contract)
|
|
9499
|
-
AND LOWER(pml."user") = LOWER(p."user")
|
|
9500
9671
|
WHERE LOWER(p."user") = LOWER(${user})
|
|
9501
9672
|
AND p."user" != ${zeroAddress}
|
|
9502
|
-
${cursor !== null ? sql`AND (p.chain_id, p.contract) > (${cursor.chainId}, ${cursor.contract})` : sql``}
|
|
9503
|
-
ORDER BY p.chain_id ASC, p.contract ASC
|
|
9673
|
+
${cursor !== null ? sql`AND (p.chain_id, p.contract, COALESCE(po.obligation_id, '')) > (${cursor.chainId}, ${cursor.contract}, ${cursor.obligationId ?? ""})` : sql``}
|
|
9674
|
+
ORDER BY p.chain_id ASC, p.contract ASC, po.obligation_id ASC NULLS FIRST
|
|
9504
9675
|
LIMIT ${limit}
|
|
9505
9676
|
`);
|
|
9506
9677
|
const nextCursor = raw.rows.length === limit ? Buffer.from(JSON.stringify({
|
|
9507
9678
|
chainId: raw.rows[raw.rows.length - 1].chain_id.toString(),
|
|
9508
|
-
contract: raw.rows[raw.rows.length - 1].contract
|
|
9679
|
+
contract: raw.rows[raw.rows.length - 1].contract,
|
|
9680
|
+
obligationId: raw.rows[raw.rows.length - 1].obligation_id
|
|
9509
9681
|
})).toString("base64url") : null;
|
|
9510
9682
|
return {
|
|
9511
9683
|
positions: raw.rows.map((row) => ({
|
|
@@ -9513,6 +9685,7 @@ const create$4 = (db) => {
|
|
|
9513
9685
|
contract: row.contract,
|
|
9514
9686
|
user: row.user,
|
|
9515
9687
|
blockNumber: row.block_number,
|
|
9688
|
+
obligationId: row.obligation_id,
|
|
9516
9689
|
reserved: BigInt(row.reserved_balance.split(".")[0] ?? "0")
|
|
9517
9690
|
})),
|
|
9518
9691
|
nextCursor
|
|
@@ -9791,7 +9964,10 @@ function create$1(db) {
|
|
|
9791
9964
|
|
|
9792
9965
|
//#endregion
|
|
9793
9966
|
//#region src/database/Database.ts
|
|
9794
|
-
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
9967
|
+
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
9968
|
+
connect: () => connect$1,
|
|
9969
|
+
getSchemaNamesForMigration: () => getSchemaNamesForMigration
|
|
9970
|
+
});
|
|
9795
9971
|
function createDomains(core, chainRegistry) {
|
|
9796
9972
|
return {
|
|
9797
9973
|
book: create$12({ db: core }),
|
|
@@ -9888,6 +10064,7 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9888
10064
|
return wrapped;
|
|
9889
10065
|
}
|
|
9890
10066
|
const InMemoryDbMap = /* @__PURE__ */ new Map();
|
|
10067
|
+
const LEGACY_SCHEMA_START_MINOR = 7;
|
|
9891
10068
|
/**
|
|
9892
10069
|
* Connect to the database.
|
|
9893
10070
|
* @notice If no connection string is provided, an in-process PGLite database is created.
|
|
@@ -9942,9 +10119,26 @@ function applyMigrations(kind, driver) {
|
|
|
9942
10119
|
async function preMigrate(driver) {
|
|
9943
10120
|
const tracer = getTracer("db.preMigrate");
|
|
9944
10121
|
await startActiveSpan(tracer, "db.preMigrate", async () => {
|
|
9945
|
-
|
|
10122
|
+
const schemaNames = getSchemaNamesForMigration(VERSION);
|
|
10123
|
+
for (const schemaName of schemaNames) await driver.execute(`create schema if not exists "${schemaName}"`);
|
|
9946
10124
|
});
|
|
9947
10125
|
}
|
|
10126
|
+
/**
|
|
10127
|
+
* Build the list of router schemas that should exist before running migrations.
|
|
10128
|
+
* @param version - Current schema version (e.g. `router_v1.8`).
|
|
10129
|
+
* @returns Ordered schema names from `router_v1.7` to current, or just current if parsing fails.
|
|
10130
|
+
*/
|
|
10131
|
+
function getSchemaNamesForMigration(version) {
|
|
10132
|
+
const parsed = /^router_v(?<major>\d+)\.(?<minor>\d+)$/.exec(version);
|
|
10133
|
+
if (!parsed?.groups?.major || !parsed.groups.minor) return [version];
|
|
10134
|
+
const major = Number.parseInt(parsed.groups.major, 10);
|
|
10135
|
+
const currentMinor = Number.parseInt(parsed.groups.minor, 10);
|
|
10136
|
+
if (!Number.isInteger(major) || !Number.isInteger(currentMinor)) return [version];
|
|
10137
|
+
if (currentMinor < LEGACY_SCHEMA_START_MINOR) return [version];
|
|
10138
|
+
const schemaNames = [];
|
|
10139
|
+
for (let minor = LEGACY_SCHEMA_START_MINOR; minor <= currentMinor; minor += 1) schemaNames.push(`router_v${major}.${minor}`);
|
|
10140
|
+
return schemaNames;
|
|
10141
|
+
}
|
|
9948
10142
|
async function postMigrate(driver) {
|
|
9949
10143
|
const tracer = getTracer("db.postMigrate");
|
|
9950
10144
|
await startActiveSpan(tracer, "db.postMigrate", async () => {
|
|
@@ -10214,15 +10408,16 @@ async function postMigrate(driver) {
|
|
|
10214
10408
|
RETURNS trigger
|
|
10215
10409
|
LANGUAGE plpgsql AS $$
|
|
10216
10410
|
BEGIN
|
|
10217
|
-
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", value)
|
|
10411
|
+
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", obligation_id, value)
|
|
10218
10412
|
VALUES (
|
|
10219
10413
|
OLD.chain_id,
|
|
10220
10414
|
OLD."user",
|
|
10221
10415
|
OLD.contract,
|
|
10222
10416
|
OLD."group",
|
|
10417
|
+
OLD.obligation_id,
|
|
10223
10418
|
OLD.upper::numeric - OLD.lower::numeric
|
|
10224
10419
|
)
|
|
10225
|
-
ON CONFLICT (chain_id, "user", contract, "group") DO NOTHING;
|
|
10420
|
+
ON CONFLICT (chain_id, "user", contract, "group", obligation_id) DO NOTHING;
|
|
10226
10421
|
RETURN OLD;
|
|
10227
10422
|
END;
|
|
10228
10423
|
$$;
|
|
@@ -10476,10 +10671,11 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
|
10476
10671
|
amountMutualExclusivity: () => amountMutualExclusivity,
|
|
10477
10672
|
callback: () => callback,
|
|
10478
10673
|
chains: () => chains,
|
|
10674
|
+
collateralToken: () => collateralToken,
|
|
10675
|
+
loanToken: () => loanToken,
|
|
10479
10676
|
maturity: () => maturity,
|
|
10480
10677
|
oracle: () => oracle,
|
|
10481
10678
|
sameMaker: () => sameMaker,
|
|
10482
|
-
token: () => token,
|
|
10483
10679
|
validity: () => validity
|
|
10484
10680
|
});
|
|
10485
10681
|
/**
|
|
@@ -10507,15 +10703,25 @@ const callback = ({ callbacks }) => single("callback", `Validates callbacks: buy
|
|
|
10507
10703
|
if (isEmptyCallback(offer) && !offer.buy && !callbacks.includes(Type$1.SellWithEmptyCallback)) return { message: "Sell offers with empty callback not allowed." };
|
|
10508
10704
|
});
|
|
10509
10705
|
/**
|
|
10510
|
-
* A validation rule that checks if the offer's
|
|
10511
|
-
* @param assetsByChainId - Allowed
|
|
10706
|
+
* A validation rule that checks if the offer's loan token is allowed for its chain.
|
|
10707
|
+
* @param assetsByChainId - Allowed loan tokens indexed by chain id.
|
|
10708
|
+
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
10709
|
+
*/
|
|
10710
|
+
const loanToken = ({ assetsByChainId }) => single("loan_token", "Validates that offer loan token is in the allowed token list for the offer chain", (offer) => {
|
|
10711
|
+
const allowedLoanTokens = assetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase());
|
|
10712
|
+
if (!allowedLoanTokens || allowedLoanTokens.length === 0) return { message: `No allowed loan tokens for chain ${offer.chainId}` };
|
|
10713
|
+
if (!allowedLoanTokens.includes(offer.loanToken.toLowerCase())) return { message: "Loan token is not allowed" };
|
|
10714
|
+
});
|
|
10715
|
+
/**
|
|
10716
|
+
* A validation rule that checks if the offer's collateral tokens are allowed for its chain.
|
|
10717
|
+
* @param collateralAssetsByChainId - Allowed collateral tokens indexed by chain id.
|
|
10512
10718
|
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
10513
10719
|
*/
|
|
10514
|
-
const
|
|
10515
|
-
const
|
|
10516
|
-
if (
|
|
10517
|
-
if (
|
|
10518
|
-
if (offer.collaterals.some((collateral) => !
|
|
10720
|
+
const collateralToken = ({ collateralAssetsByChainId }) => single("collateral_token", "Validates that offer collateral tokens are in the allowed token list for the offer chain", (offer) => {
|
|
10721
|
+
const allowedCollateralTokens = collateralAssetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase()) ?? [];
|
|
10722
|
+
if (allowedCollateralTokens.length === 0) return { message: `No allowed collateral tokens for chain ${offer.chainId}` };
|
|
10723
|
+
if (offer.collaterals.length === 0) return { message: "At least one collateral token is required" };
|
|
10724
|
+
if (offer.collaterals.some((collateral) => !allowedCollateralTokens.includes(collateral.asset.toLowerCase()))) return { message: "Collateral token is not allowed" };
|
|
10519
10725
|
});
|
|
10520
10726
|
/**
|
|
10521
10727
|
* A validation rule that checks if the offer's oracle addresses are allowed for its chain.
|
|
@@ -10558,9 +10764,11 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
|
|
|
10558
10764
|
//#region src/gatekeeper/morphoRules.ts
|
|
10559
10765
|
const morphoRules = (chains$3) => {
|
|
10560
10766
|
const assetsByChainId = {};
|
|
10767
|
+
const collateralAssetsByChainId = {};
|
|
10561
10768
|
const oraclesByChainId = {};
|
|
10562
10769
|
for (const chain of chains$3) {
|
|
10563
10770
|
assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
|
|
10771
|
+
collateralAssetsByChainId[chain.id] = collateralAssets[chain.id.toString()] ?? [];
|
|
10564
10772
|
oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
|
|
10565
10773
|
}
|
|
10566
10774
|
return [
|
|
@@ -10572,7 +10780,8 @@ const morphoRules = (chains$3) => {
|
|
|
10572
10780
|
callbacks: [Type$1.BuyWithEmptyCallback, Type$1.SellWithEmptyCallback],
|
|
10573
10781
|
allowedAddresses: []
|
|
10574
10782
|
}),
|
|
10575
|
-
|
|
10783
|
+
loanToken({ assetsByChainId }),
|
|
10784
|
+
collateralToken({ collateralAssetsByChainId }),
|
|
10576
10785
|
oracle({ oraclesByChainId })
|
|
10577
10786
|
];
|
|
10578
10787
|
};
|
|
@@ -10755,5 +10964,5 @@ var mempool_exports = /* @__PURE__ */ __exportAll({
|
|
|
10755
10964
|
});
|
|
10756
10965
|
|
|
10757
10966
|
//#endregion
|
|
10758
|
-
export { Abi_exports as Abi, BookResponse_exports as BookResponse, BooksController, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainHealth, ChainRegistry_exports as ChainRegistry, ChainsHealthResponse, Collateral_exports as Collateral, CollectorHealth, CollectorsHealthResponse, ConfigContractsController, ConfigRulesController, Database_exports as Database, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, Gatekeeper_exports as Gatekeeper, Client_exports as GatekeeperClient, Health_exports as Health, HealthController, Indexer_exports as Indexer, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Logger_exports as Logger, Maturity_exports as Maturity, mempool_exports as Mempool, Obligation_exports as Obligation, ObligationResponse_exports as ObligationResponse, ObligationsController, Offer_exports as Offer, OfferResponse_exports as OfferResponse, OffersController, drizzle_exports as OffersSchema, OpenApi, Oracle_exports as Oracle, Position_exports as Position, PositionResponse_exports as PositionResponse, Quote_exports as Quote, RouterApi_exports as RouterApi, Client_exports$1 as RouterClient, RouterStatusResponse, Rules_exports as Rules, time_exports as Time, TradingFee_exports as TradingFee, Transfer_exports as Transfer, Tree_exports as Tree, UsersController, utils_exports as Utils, ValidateController, Gate_exports as Validation, morphoRules, parse, safeParse };
|
|
10967
|
+
export { Abi_exports as Abi, BookResponse_exports as BookResponse, BooksController, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainHealth, ChainRegistry_exports as ChainRegistry, ChainsHealthResponse, Collateral_exports as Collateral, CollectorHealth, CollectorsHealthResponse, ConfigContractsController, ConfigRulesController, Database_exports as Database, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, Gatekeeper_exports as Gatekeeper, Client_exports as GatekeeperClient, Health_exports as Health, HealthController, Indexer_exports as Indexer, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Logger_exports as Logger, Maturity_exports as Maturity, mempool_exports as Mempool, Obligation_exports as Obligation, ObligationResponse_exports as ObligationResponse, ObligationsController, Offer_exports as Offer, OfferResponse_exports as OfferResponse, OffersController, drizzle_exports as OffersSchema, OpenApi, Oracle_exports as Oracle, Position_exports as Position, PositionResponse_exports as PositionResponse, Quote_exports as Quote, RouterApi_exports as RouterApi, Client_exports$1 as RouterClient, RouterStatusResponse, Rules_exports as Rules, Tick_exports as Tick, time_exports as Time, TradingFee_exports as TradingFee, Transfer_exports as Transfer, Tree_exports as Tree, UsersController, utils_exports as Utils, ValidateController, Gate_exports as Validation, morphoRules, parse, safeParse };
|
|
10759
10968
|
//# sourceMappingURL=index.node.mjs.map
|