@morpho-dev/router 0.8.0 → 0.9.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 +574 -244
- package/dist/drizzle/migrations/0026_add-receiver-if-maker-is-seller.sql +1 -0
- package/dist/drizzle/migrations/meta/0026_snapshot.json +1454 -0
- package/dist/drizzle/migrations/meta/_journal.json +7 -0
- package/dist/evm/bytecode/morpho.txt +1 -1
- package/dist/index.browser.d.mts +105 -46
- package/dist/index.browser.d.mts.map +1 -1
- package/dist/index.browser.d.ts +105 -46
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +147 -51
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +147 -51
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.mts +165 -56
- package/dist/index.node.d.mts.map +1 -1
- package/dist/index.node.d.ts +165 -56
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +583 -245
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +584 -246
- package/dist/index.node.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -39,7 +39,7 @@ import { migrate } from "drizzle-orm/node-postgres/migrator";
|
|
|
39
39
|
import { drizzle as drizzle$1 } from "drizzle-orm/pglite";
|
|
40
40
|
import { migrate as migrate$1 } from "drizzle-orm/pglite/migrator";
|
|
41
41
|
import { Pool } from "pg";
|
|
42
|
-
import { and, asc, eq, gt, gte, inArray, lte, ne, sql } from "drizzle-orm";
|
|
42
|
+
import { and, asc, desc, eq, gt, gte, inArray, lte, ne, sql } from "drizzle-orm";
|
|
43
43
|
import { bigint, boolean, foreignKey, index, integer, numeric, pgSchema, primaryKey, serial, text, timestamp, uniqueIndex, varchar } from "drizzle-orm/pg-core";
|
|
44
44
|
import { parse } from "smol-toml";
|
|
45
45
|
import { cors } from "hono/cors";
|
|
@@ -152,7 +152,7 @@ function startActiveSpan(tracer, name, fn) {
|
|
|
152
152
|
//#endregion
|
|
153
153
|
//#region package.json
|
|
154
154
|
var name = "@morpho-dev/router";
|
|
155
|
-
var version = "0.
|
|
155
|
+
var version = "0.9.0";
|
|
156
156
|
var description = "Router package for Morpho protocol";
|
|
157
157
|
|
|
158
158
|
//#endregion
|
|
@@ -331,8 +331,8 @@ const chains$2 = {
|
|
|
331
331
|
name: "ethereum-virtual-testnet",
|
|
332
332
|
custom: {
|
|
333
333
|
morpho: {
|
|
334
|
-
address: "
|
|
335
|
-
blockCreated:
|
|
334
|
+
address: "0xc9f3c65996fc46b9500608b2c9a9152c01c540f7",
|
|
335
|
+
blockCreated: 23226871
|
|
336
336
|
},
|
|
337
337
|
morphoBlue: {
|
|
338
338
|
address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
@@ -1469,7 +1469,7 @@ async function run(parameters) {
|
|
|
1469
1469
|
* @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}
|
|
1470
1470
|
* @returns Gatekeeper instance. {@link Gatekeeper}
|
|
1471
1471
|
*/
|
|
1472
|
-
function create$
|
|
1472
|
+
function create$21(parameters) {
|
|
1473
1473
|
const { rules } = parameters;
|
|
1474
1474
|
return { isAllowed: async (offers) => {
|
|
1475
1475
|
return await run({
|
|
@@ -1707,19 +1707,19 @@ const oracles$1 = {
|
|
|
1707
1707
|
const configs = {
|
|
1708
1708
|
ethereum: {
|
|
1709
1709
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
1710
|
-
maturities: [MaturityType.
|
|
1710
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
1711
1711
|
},
|
|
1712
1712
|
base: {
|
|
1713
1713
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
1714
|
-
maturities: [MaturityType.
|
|
1714
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
1715
1715
|
},
|
|
1716
1716
|
"ethereum-virtual-testnet": {
|
|
1717
1717
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
1718
|
-
maturities: [MaturityType.
|
|
1718
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
1719
1719
|
},
|
|
1720
1720
|
anvil: {
|
|
1721
1721
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
1722
|
-
maturities: [MaturityType.
|
|
1722
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
1723
1723
|
}
|
|
1724
1724
|
};
|
|
1725
1725
|
|
|
@@ -1765,18 +1765,18 @@ const MorphoV2 = parseAbi([
|
|
|
1765
1765
|
"function setFeeSetter(address newFeeSetter)",
|
|
1766
1766
|
"function setObligationTradingFee(bytes32 id, uint256 index, uint256 newTradingFee)",
|
|
1767
1767
|
"function setOwner(address newOwner)",
|
|
1768
|
-
"function setTradingFeeRecipient(address
|
|
1768
|
+
"function setTradingFeeRecipient(address feeRecipient)",
|
|
1769
1769
|
"function sharesOf(bytes32 id, address user) view returns (uint256)",
|
|
1770
1770
|
"function shuffleSession()",
|
|
1771
1771
|
"function supplyCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)",
|
|
1772
|
-
"function take(uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, address taker, ((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bool buy, address maker, uint256 assets, uint256 obligationUnits, uint256 obligationShares, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof
|
|
1772
|
+
"function take(uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, address taker, address takerCallback, bytes takerCallbackData, address receiverIfTakerIsSeller, ((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bool buy, address maker, uint256 assets, uint256 obligationUnits, uint256 obligationShares, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData, address receiverIfMakerIsSeller) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof) returns (uint256, uint256, uint256, uint256)",
|
|
1773
1773
|
"function totalShares(bytes32 id) view returns (uint256)",
|
|
1774
1774
|
"function totalUnits(bytes32 id) view returns (uint256)",
|
|
1775
1775
|
"function touchObligation((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation) returns (bytes32)",
|
|
1776
1776
|
"function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)",
|
|
1777
1777
|
"function tradingFeeRecipient() view returns (address)",
|
|
1778
|
-
"function withdraw((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, uint256 shares, address onBehalf) returns (uint256, uint256)",
|
|
1779
|
-
"function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)",
|
|
1778
|
+
"function withdraw((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, uint256 shares, address onBehalf, address receiver) returns (uint256, uint256)",
|
|
1779
|
+
"function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf, address receiver)",
|
|
1780
1780
|
"function withdrawable(bytes32 id) view returns (uint256)",
|
|
1781
1781
|
"event Constructor(address indexed owner)",
|
|
1782
1782
|
"event Consume(address indexed user, bytes32 indexed group, uint256 amount)",
|
|
@@ -1788,12 +1788,12 @@ const MorphoV2 = parseAbi([
|
|
|
1788
1788
|
"event SetFeeSetter(address indexed feeSetter)",
|
|
1789
1789
|
"event SetObligationTradingFee(bytes32 indexed id, uint256 indexed index, uint256 newTradingFee)",
|
|
1790
1790
|
"event SetOwner(address indexed owner)",
|
|
1791
|
-
"event SetTradingFeeRecipient(address indexed
|
|
1791
|
+
"event SetTradingFeeRecipient(address indexed feeRecipient)",
|
|
1792
1792
|
"event ShuffleSession(address indexed user, bytes32 session)",
|
|
1793
1793
|
"event SupplyCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)",
|
|
1794
|
-
"event Take(address caller, bytes32 indexed id, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, bool buyerIsLender, bool sellerIsBorrower, bytes32 group, uint256 consumed)",
|
|
1795
|
-
"event Withdraw(address
|
|
1796
|
-
"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)"
|
|
1794
|
+
"event Take(address caller, bytes32 indexed id, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, bool buyerIsLender, bool sellerIsBorrower, address sellerReceiver, bytes32 group, uint256 consumed)",
|
|
1795
|
+
"event Withdraw(address caller, bytes32 indexed id, uint256 obligationUnits, uint256 shares, address indexed onBehalf, address indexed receiver)",
|
|
1796
|
+
"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf, address receiver)"
|
|
1797
1797
|
]);
|
|
1798
1798
|
|
|
1799
1799
|
//#endregion
|
|
@@ -1816,7 +1816,7 @@ const Oracle = [{
|
|
|
1816
1816
|
* @param chains - Array of chain objects to register.
|
|
1817
1817
|
* @returns A registry for looking up chains by ID. {@link ChainRegistry}
|
|
1818
1818
|
*/
|
|
1819
|
-
function create$
|
|
1819
|
+
function create$20(chains) {
|
|
1820
1820
|
const byId = /* @__PURE__ */ new Map();
|
|
1821
1821
|
for (const chain of chains) byId.set(chain.id, chain);
|
|
1822
1822
|
return {
|
|
@@ -2174,7 +2174,8 @@ const OfferSchema = () => {
|
|
|
2174
2174
|
callback: z$2.object({
|
|
2175
2175
|
address: z$2.string().transform(transformAddress),
|
|
2176
2176
|
data: z$2.string().transform(transformHex)
|
|
2177
|
-
})
|
|
2177
|
+
}),
|
|
2178
|
+
receiverIfMakerIsSeller: z$2.string().transform(transformAddress)
|
|
2178
2179
|
}).refine((data) => data.start < data.expiry, {
|
|
2179
2180
|
message: "start must be before expiry",
|
|
2180
2181
|
path: ["start"]
|
|
@@ -2190,8 +2191,12 @@ const OfferSchema = () => {
|
|
|
2190
2191
|
* @returns The created offer.
|
|
2191
2192
|
*/
|
|
2192
2193
|
function from$12(input) {
|
|
2194
|
+
const normalizedInput = {
|
|
2195
|
+
...input,
|
|
2196
|
+
receiverIfMakerIsSeller: input.receiverIfMakerIsSeller ?? input.maker
|
|
2197
|
+
};
|
|
2193
2198
|
try {
|
|
2194
|
-
return OfferSchema().parse(
|
|
2199
|
+
return OfferSchema().parse(normalizedInput);
|
|
2195
2200
|
} catch (error) {
|
|
2196
2201
|
throw new InvalidOfferError(error);
|
|
2197
2202
|
}
|
|
@@ -2243,6 +2248,7 @@ const serialize = (offer) => ({
|
|
|
2243
2248
|
address: offer.callback.address,
|
|
2244
2249
|
data: offer.callback.data
|
|
2245
2250
|
},
|
|
2251
|
+
receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller,
|
|
2246
2252
|
hash: hash(offer)
|
|
2247
2253
|
});
|
|
2248
2254
|
/**
|
|
@@ -2285,8 +2291,9 @@ function random(config) {
|
|
|
2285
2291
|
address: zeroAddress,
|
|
2286
2292
|
data: "0x"
|
|
2287
2293
|
};
|
|
2294
|
+
const maker = config?.maker ?? address();
|
|
2288
2295
|
return from$12({
|
|
2289
|
-
maker
|
|
2296
|
+
maker,
|
|
2290
2297
|
assets: assetsScaled,
|
|
2291
2298
|
obligationUnits: config?.obligationUnits ?? 0n,
|
|
2292
2299
|
obligationShares: config?.obligationShares ?? 0n,
|
|
@@ -2303,7 +2310,8 @@ function random(config) {
|
|
|
2303
2310
|
...random$1(),
|
|
2304
2311
|
lltv
|
|
2305
2312
|
})).sort((a, b) => a.asset.localeCompare(b.asset)),
|
|
2306
|
-
callback: config?.callback ?? emptyCallback
|
|
2313
|
+
callback: config?.callback ?? emptyCallback,
|
|
2314
|
+
receiverIfMakerIsSeller: config?.receiverIfMakerIsSeller ?? maker
|
|
2307
2315
|
});
|
|
2308
2316
|
}
|
|
2309
2317
|
const weightedChoice = (pairs) => {
|
|
@@ -2389,6 +2397,10 @@ const types = {
|
|
|
2389
2397
|
{
|
|
2390
2398
|
name: "callback",
|
|
2391
2399
|
type: "Callback"
|
|
2400
|
+
},
|
|
2401
|
+
{
|
|
2402
|
+
name: "receiverIfMakerIsSeller",
|
|
2403
|
+
type: "address"
|
|
2392
2404
|
}
|
|
2393
2405
|
],
|
|
2394
2406
|
Collateral: [
|
|
@@ -2434,7 +2446,8 @@ function hash(offer) {
|
|
|
2434
2446
|
callback: {
|
|
2435
2447
|
address: offer.callback.address.toLowerCase(),
|
|
2436
2448
|
data: offer.callback.data
|
|
2437
|
-
}
|
|
2449
|
+
},
|
|
2450
|
+
receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller.toLowerCase()
|
|
2438
2451
|
},
|
|
2439
2452
|
primaryType: "Offer",
|
|
2440
2453
|
types
|
|
@@ -2529,6 +2542,12 @@ const takeEvent = {
|
|
|
2529
2542
|
indexed: false,
|
|
2530
2543
|
internalType: "bool"
|
|
2531
2544
|
},
|
|
2545
|
+
{
|
|
2546
|
+
name: "sellerReceiver",
|
|
2547
|
+
type: "address",
|
|
2548
|
+
indexed: false,
|
|
2549
|
+
internalType: "address"
|
|
2550
|
+
},
|
|
2532
2551
|
{
|
|
2533
2552
|
name: "group",
|
|
2534
2553
|
type: "bytes32",
|
|
@@ -2650,44 +2669,6 @@ function from$10(parameters) {
|
|
|
2650
2669
|
};
|
|
2651
2670
|
}
|
|
2652
2671
|
|
|
2653
|
-
//#endregion
|
|
2654
|
-
//#region src/core/Quote.ts
|
|
2655
|
-
const QuoteSchema = z$2.object({
|
|
2656
|
-
obligationId: z$2.string().transform(transformHex),
|
|
2657
|
-
ask: z$2.object({ price: z$2.bigint({ coerce: true }).min(0n).max(maxUint256) }),
|
|
2658
|
-
bid: z$2.object({ price: z$2.bigint({ coerce: true }).min(0n).max(maxUint256) })
|
|
2659
|
-
});
|
|
2660
|
-
/**
|
|
2661
|
-
* Creates a quote for a given obligation.
|
|
2662
|
-
* @constructor
|
|
2663
|
-
* @param parameters - {@link from.Parameters}
|
|
2664
|
-
* @returns The created quote. {@link Quote}
|
|
2665
|
-
* @throws If the quote is invalid. {@link InvalidQuoteError}
|
|
2666
|
-
*
|
|
2667
|
-
* @example
|
|
2668
|
-
* ```ts
|
|
2669
|
-
* const quote = Quote.from({ obligationId: "0x123", ask: { price: 100n }, bid: { price: 100n } });
|
|
2670
|
-
* ```
|
|
2671
|
-
*/
|
|
2672
|
-
function from$9(parameters) {
|
|
2673
|
-
try {
|
|
2674
|
-
const parsedQuote = QuoteSchema.parse(parameters);
|
|
2675
|
-
return {
|
|
2676
|
-
obligationId: parsedQuote.obligationId,
|
|
2677
|
-
ask: parsedQuote.ask,
|
|
2678
|
-
bid: parsedQuote.bid
|
|
2679
|
-
};
|
|
2680
|
-
} catch (error) {
|
|
2681
|
-
throw new InvalidQuoteError(error);
|
|
2682
|
-
}
|
|
2683
|
-
}
|
|
2684
|
-
var InvalidQuoteError = class extends BaseError {
|
|
2685
|
-
name = "Quote.InvalidQuoteError";
|
|
2686
|
-
constructor(error) {
|
|
2687
|
-
super("Invalid quote.", { cause: error });
|
|
2688
|
-
}
|
|
2689
|
-
};
|
|
2690
|
-
|
|
2691
2672
|
//#endregion
|
|
2692
2673
|
//#region src/core/Tick.ts
|
|
2693
2674
|
/** ln(1 + 0.025), scaled by 1e18. Matches TickLib onchain constant. */
|
|
@@ -2731,6 +2712,51 @@ var InvalidTickError = class extends BaseError {
|
|
|
2731
2712
|
}
|
|
2732
2713
|
};
|
|
2733
2714
|
|
|
2715
|
+
//#endregion
|
|
2716
|
+
//#region src/core/Quote.ts
|
|
2717
|
+
const SideInputSchema = z$2.object({ tick: z$2.number().int().min(0).max(TICK_RANGE).nullable() }).strict();
|
|
2718
|
+
const QuoteInputSchema = z$2.object({
|
|
2719
|
+
obligationId: z$2.string().transform(transformHex),
|
|
2720
|
+
ask: SideInputSchema,
|
|
2721
|
+
bid: SideInputSchema
|
|
2722
|
+
}).strict();
|
|
2723
|
+
/**
|
|
2724
|
+
* Creates a quote for a given obligation.
|
|
2725
|
+
* @constructor
|
|
2726
|
+
* @param parameters - {@link from.Parameters}
|
|
2727
|
+
* @returns The created quote. {@link Quote}
|
|
2728
|
+
* @throws If the quote is invalid. {@link InvalidQuoteError}
|
|
2729
|
+
*
|
|
2730
|
+
* @example
|
|
2731
|
+
* ```ts
|
|
2732
|
+
* const quote = Quote.from({ obligationId: "0x123", ask: { tick: 500 }, bid: { tick: 510 } });
|
|
2733
|
+
* ```
|
|
2734
|
+
*/
|
|
2735
|
+
function from$9(parameters) {
|
|
2736
|
+
try {
|
|
2737
|
+
const parsedQuote = QuoteInputSchema.parse(parameters);
|
|
2738
|
+
return {
|
|
2739
|
+
obligationId: parsedQuote.obligationId,
|
|
2740
|
+
ask: sideFromTick(parsedQuote.ask),
|
|
2741
|
+
bid: sideFromTick(parsedQuote.bid)
|
|
2742
|
+
};
|
|
2743
|
+
} catch (error) {
|
|
2744
|
+
throw new InvalidQuoteError(error);
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
var InvalidQuoteError = class extends BaseError {
|
|
2748
|
+
name = "Quote.InvalidQuoteError";
|
|
2749
|
+
constructor(error) {
|
|
2750
|
+
super("Invalid quote.", { cause: error });
|
|
2751
|
+
}
|
|
2752
|
+
};
|
|
2753
|
+
function sideFromTick(side) {
|
|
2754
|
+
return {
|
|
2755
|
+
tick: side.tick,
|
|
2756
|
+
price: side.tick === null ? 0n : tickToPrice(side.tick)
|
|
2757
|
+
};
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2734
2760
|
//#endregion
|
|
2735
2761
|
//#region src/core/TradingFee.ts
|
|
2736
2762
|
/** WAD constant (1e18) for fee scaling. */
|
|
@@ -3011,7 +3037,7 @@ const chains$1 = ({ chains }) => single("chain_ids", `Validates that offer chain
|
|
|
3011
3037
|
});
|
|
3012
3038
|
const maturity = ({ maturities }) => single("maturity", `Validates that offer maturity is one of: [${maturities.join(", ")}]`, (offer) => {
|
|
3013
3039
|
const allowedMaturities = maturities.map((m) => from$16(m));
|
|
3014
|
-
if (!allowedMaturities.includes(offer.maturity)) return { message: `Maturity must be
|
|
3040
|
+
if (!allowedMaturities.includes(offer.maturity)) return { message: `Maturity must be one of (${allowedMaturities.join(", ")}). Got: ${offer.maturity}` };
|
|
3015
3041
|
});
|
|
3016
3042
|
const callback = ({ callbacks }) => single("callback", `Validates callbacks: buy empty callback is ${callbacks.includes(Type$1.BuyWithEmptyCallback) ? "allowed" : "not allowed"}; sell empty callback is ${callbacks.includes(Type$1.SellWithEmptyCallback) ? "allowed" : "not allowed"}; non-empty callbacks are rejected`, (offer) => {
|
|
3017
3043
|
if (!isEmptyCallback(offer)) return { message: "Non-empty callbacks are not supported." };
|
|
@@ -3091,7 +3117,7 @@ const morphoRules = (chains) => {
|
|
|
3091
3117
|
sameMaker(),
|
|
3092
3118
|
amountMutualExclusivity(),
|
|
3093
3119
|
chains$1({ chains }),
|
|
3094
|
-
maturity({ maturities: [MaturityType.
|
|
3120
|
+
maturity({ maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek] }),
|
|
3095
3121
|
callback({
|
|
3096
3122
|
callbacks: [Type$1.BuyWithEmptyCallback, Type$1.SellWithEmptyCallback],
|
|
3097
3123
|
allowedAddresses: []
|
|
@@ -3239,6 +3265,7 @@ const RouterStatusResponse = z$1.object({
|
|
|
3239
3265
|
* Creates an `ObligationResponse` from a `Obligation`.
|
|
3240
3266
|
* @constructor
|
|
3241
3267
|
* @param obligation - {@link Obligation}
|
|
3268
|
+
* @param quote - {@link Quote}
|
|
3242
3269
|
* @returns The created `ObligationResponse`. {@link ObligationResponse}
|
|
3243
3270
|
*/
|
|
3244
3271
|
function from$5(obligation, quote) {
|
|
@@ -3252,8 +3279,14 @@ function from$5(obligation, quote) {
|
|
|
3252
3279
|
oracle: c.oracle
|
|
3253
3280
|
})),
|
|
3254
3281
|
maturity: obligation.maturity,
|
|
3255
|
-
ask: {
|
|
3256
|
-
|
|
3282
|
+
ask: {
|
|
3283
|
+
tick: quote.ask.tick,
|
|
3284
|
+
price: quote.ask.price.toString()
|
|
3285
|
+
},
|
|
3286
|
+
bid: {
|
|
3287
|
+
tick: quote.bid.tick,
|
|
3288
|
+
price: quote.bid.price.toString()
|
|
3289
|
+
}
|
|
3257
3290
|
};
|
|
3258
3291
|
}
|
|
3259
3292
|
|
|
@@ -3300,7 +3333,8 @@ function from$4(input) {
|
|
|
3300
3333
|
group: input.group,
|
|
3301
3334
|
session: input.session,
|
|
3302
3335
|
callback: input.callback.address,
|
|
3303
|
-
callback_data: input.callback.data
|
|
3336
|
+
callback_data: input.callback.data,
|
|
3337
|
+
receiver_if_maker_is_seller: input.receiverIfMakerIsSeller
|
|
3304
3338
|
},
|
|
3305
3339
|
offer_hash: input.hash,
|
|
3306
3340
|
obligation_id: id({
|
|
@@ -3367,7 +3401,7 @@ var InternalServerError = class extends APIError {
|
|
|
3367
3401
|
super(STATUS_CODE.INTERNAL_SERVER_ERROR, message, "INTERNAL_SERVER_ERROR");
|
|
3368
3402
|
}
|
|
3369
3403
|
};
|
|
3370
|
-
var BadRequestError = class extends APIError {
|
|
3404
|
+
var BadRequestError$1 = class extends APIError {
|
|
3371
3405
|
constructor(message = "Invalid JSON format", details) {
|
|
3372
3406
|
super(STATUS_CODE.BAD_REQUEST, message, "BAD_REQUEST", details);
|
|
3373
3407
|
}
|
|
@@ -3389,7 +3423,7 @@ function success(args) {
|
|
|
3389
3423
|
*/
|
|
3390
3424
|
function failure(err) {
|
|
3391
3425
|
if (err instanceof APIError) return handleAPIError(err);
|
|
3392
|
-
if (err instanceof SyntaxError) return handleAPIError(new BadRequestError(err.message));
|
|
3426
|
+
if (err instanceof SyntaxError) return handleAPIError(new BadRequestError$1(err.message));
|
|
3393
3427
|
if (err instanceof z$2.ZodError) return handleAPIError(handleZodError(err));
|
|
3394
3428
|
return handleAPIError(new InternalServerError());
|
|
3395
3429
|
}
|
|
@@ -3439,7 +3473,7 @@ function __decorate(decorators, target, key, desc) {
|
|
|
3439
3473
|
//#region src/api/Schema/openapi.ts
|
|
3440
3474
|
const timestampExample = "2024-01-01T12:00:00.000Z";
|
|
3441
3475
|
const offerCursorExample = "eyJvZmZzZXQiOjEwMH0";
|
|
3442
|
-
const obligationCursorExample = "
|
|
3476
|
+
const obligationCursorExample = "eyJzb3J0IjpbImlkIl0sImlkIjoiMHgxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAiLCJhc2siOiIwIiwiYmlkIjoiMCIsIm1hdHVyaXR5IjoxNzYxOTIyODAwfQ";
|
|
3443
3477
|
const offerExample = {
|
|
3444
3478
|
offer: {
|
|
3445
3479
|
obligation: {
|
|
@@ -3462,7 +3496,8 @@ const offerExample = {
|
|
|
3462
3496
|
group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
|
|
3463
3497
|
session: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
3464
3498
|
callback: "0x0000000000000000000000000000000000000000",
|
|
3465
|
-
callback_data: "0x"
|
|
3499
|
+
callback_data: "0x",
|
|
3500
|
+
receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
|
|
3466
3501
|
},
|
|
3467
3502
|
offer_hash: "0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427",
|
|
3468
3503
|
obligation_id: "0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc",
|
|
@@ -3516,7 +3551,8 @@ const validateOfferExample = {
|
|
|
3516
3551
|
callback: {
|
|
3517
3552
|
address: "0x0000000000000000000000000000000000000000",
|
|
3518
3553
|
data: "0x"
|
|
3519
|
-
}
|
|
3554
|
+
},
|
|
3555
|
+
receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
|
|
3520
3556
|
};
|
|
3521
3557
|
const routerStatusExample = {
|
|
3522
3558
|
status: "live",
|
|
@@ -3587,11 +3623,23 @@ __decorate([ApiProperty({
|
|
|
3587
3623
|
example: validateOfferExample.callback.data
|
|
3588
3624
|
})], ValidateCallbackRequest.prototype, "data", void 0);
|
|
3589
3625
|
var AskResponse = class {};
|
|
3626
|
+
__decorate([ApiProperty({
|
|
3627
|
+
type: "number",
|
|
3628
|
+
nullable: true,
|
|
3629
|
+
example: 500,
|
|
3630
|
+
description: "Best ask tick. Null when there is no active ask quote."
|
|
3631
|
+
})], AskResponse.prototype, "tick", void 0);
|
|
3590
3632
|
__decorate([ApiProperty({
|
|
3591
3633
|
type: "string",
|
|
3592
3634
|
example: "1000000000000000000"
|
|
3593
3635
|
})], AskResponse.prototype, "price", void 0);
|
|
3594
3636
|
var BidResponse = class {};
|
|
3637
|
+
__decorate([ApiProperty({
|
|
3638
|
+
type: "number",
|
|
3639
|
+
nullable: true,
|
|
3640
|
+
example: 500,
|
|
3641
|
+
description: "Best bid tick. Null when there is no active bid quote."
|
|
3642
|
+
})], BidResponse.prototype, "tick", void 0);
|
|
3595
3643
|
__decorate([ApiProperty({
|
|
3596
3644
|
type: "string",
|
|
3597
3645
|
example: "1000000000000000000"
|
|
@@ -3664,6 +3712,10 @@ __decorate([ApiProperty({
|
|
|
3664
3712
|
type: "string",
|
|
3665
3713
|
example: offerExample.offer.callback_data
|
|
3666
3714
|
})], OfferDataResponse.prototype, "callback_data", void 0);
|
|
3715
|
+
__decorate([ApiProperty({
|
|
3716
|
+
type: "string",
|
|
3717
|
+
example: offerExample.offer.receiver_if_maker_is_seller
|
|
3718
|
+
})], OfferDataResponse.prototype, "receiver_if_maker_is_seller", void 0);
|
|
3667
3719
|
var OfferListItemResponse = class {};
|
|
3668
3720
|
__decorate([ApiProperty({
|
|
3669
3721
|
type: () => OfferDataResponse,
|
|
@@ -3933,6 +3985,10 @@ __decorate([ApiProperty({
|
|
|
3933
3985
|
type: () => ValidateCallbackRequest,
|
|
3934
3986
|
example: validateOfferExample.callback
|
|
3935
3987
|
})], ValidateOfferRequest.prototype, "callback", void 0);
|
|
3988
|
+
__decorate([ApiProperty({
|
|
3989
|
+
type: "string",
|
|
3990
|
+
example: validateOfferExample.receiver_if_maker_is_seller
|
|
3991
|
+
})], ValidateOfferRequest.prototype, "receiver_if_maker_is_seller", void 0);
|
|
3936
3992
|
var ValidateOffersRequest = class {};
|
|
3937
3993
|
__decorate([ApiProperty({
|
|
3938
3994
|
type: () => [ValidateOfferRequest],
|
|
@@ -4485,13 +4541,13 @@ __decorate([
|
|
|
4485
4541
|
methods: ["get"],
|
|
4486
4542
|
path: "/v1/obligations",
|
|
4487
4543
|
summary: "List all obligations",
|
|
4488
|
-
description: "Returns a list of obligations with their current best ask and bid.
|
|
4544
|
+
description: "Returns a list of obligations with their current best ask and bid. Sorting is customizable with the sort parameter and defaults to id ascending."
|
|
4489
4545
|
}),
|
|
4490
4546
|
ApiQuery({
|
|
4491
4547
|
name: "cursor",
|
|
4492
4548
|
type: "string",
|
|
4493
4549
|
example: obligationCursorExample,
|
|
4494
|
-
description: "
|
|
4550
|
+
description: "Pagination cursor in base64url-encoded format."
|
|
4495
4551
|
}),
|
|
4496
4552
|
ApiQuery({
|
|
4497
4553
|
name: "limit",
|
|
@@ -4535,6 +4591,15 @@ __decorate([
|
|
|
4535
4591
|
style: "form",
|
|
4536
4592
|
explode: false
|
|
4537
4593
|
}),
|
|
4594
|
+
ApiQuery({
|
|
4595
|
+
name: "sort",
|
|
4596
|
+
type: "string",
|
|
4597
|
+
required: false,
|
|
4598
|
+
example: "-ask,bid,maturity",
|
|
4599
|
+
description: "Sort order as comma-separated fields (`id`, `ask`, `bid`, `maturity`). Prefix with `-` for descending order. Max 3 fields.",
|
|
4600
|
+
style: "form",
|
|
4601
|
+
explode: false
|
|
4602
|
+
}),
|
|
4538
4603
|
ApiResponse({
|
|
4539
4604
|
status: 200,
|
|
4540
4605
|
description: "Success",
|
|
@@ -4669,11 +4734,13 @@ function from$3(position) {
|
|
|
4669
4734
|
//#endregion
|
|
4670
4735
|
//#region src/api/Schema/requests.ts
|
|
4671
4736
|
const MAX_LIMIT = 100;
|
|
4672
|
-
const DEFAULT_LIMIT$
|
|
4737
|
+
const DEFAULT_LIMIT$5 = 20;
|
|
4738
|
+
const MAX_OBLIGATION_SORT_FIELDS = 3;
|
|
4673
4739
|
const CONFIG_RULES_MAX_LIMIT = 1e3;
|
|
4674
4740
|
const CONFIG_RULES_DEFAULT_LIMIT = 100;
|
|
4675
4741
|
const CONFIG_CONTRACTS_MAX_LIMIT = 1e3;
|
|
4676
4742
|
const CONFIG_CONTRACTS_DEFAULT_LIMIT = 1e3;
|
|
4743
|
+
const OBLIGATION_SORT_ENTRY_REGEX = /^-?(id|ask|bid|maturity)$/;
|
|
4677
4744
|
/** Validate cursor is a valid base64url-encoded JSON object.
|
|
4678
4745
|
* Domain layer handles semantic validation of cursor fields. */
|
|
4679
4746
|
function isValidBase64urlJson(val) {
|
|
@@ -4705,8 +4772,8 @@ const PaginationQueryParams = z$2.object({
|
|
|
4705
4772
|
description: "Pagination cursor in base64url-encoded format",
|
|
4706
4773
|
example: "eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ"
|
|
4707
4774
|
}),
|
|
4708
|
-
limit: z$2.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$2.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$
|
|
4709
|
-
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$
|
|
4775
|
+
limit: z$2.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$2.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$5).meta({
|
|
4776
|
+
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$5}`,
|
|
4710
4777
|
example: 10
|
|
4711
4778
|
})
|
|
4712
4779
|
});
|
|
@@ -4803,9 +4870,12 @@ const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend
|
|
|
4803
4870
|
});
|
|
4804
4871
|
const GetObligationsQueryParams = z$2.object({
|
|
4805
4872
|
...PaginationQueryParams.shape,
|
|
4806
|
-
cursor: z$2.string().optional().
|
|
4807
|
-
|
|
4808
|
-
|
|
4873
|
+
cursor: z$2.string().optional().refine((val) => {
|
|
4874
|
+
if (!val) return true;
|
|
4875
|
+
return isValidBase64urlJson(val);
|
|
4876
|
+
}, { message: "Invalid cursor format. Must be a valid base64url-encoded cursor object" }).meta({
|
|
4877
|
+
description: "Pagination cursor in base64url-encoded format.",
|
|
4878
|
+
example: "eyJzb3J0IjpbImlkIl0sImlkIjoiMHgxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAiLCJhc2siOiIwIiwiYmlkIjoiMCIsIm1hdHVyaXR5IjoxNzYxOTIyODAwfQ"
|
|
4809
4879
|
}),
|
|
4810
4880
|
chains: csvArray(z$2.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
4811
4881
|
description: "Filter by chain IDs (comma-separated).",
|
|
@@ -4822,6 +4892,24 @@ const GetObligationsQueryParams = z$2.object({
|
|
|
4822
4892
|
maturities: csvArray(z$2.string().regex(/^[1-9]\d*$/, { message: "Maturity must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
4823
4893
|
description: "Filter by exact maturity timestamps (comma-separated, unix seconds).",
|
|
4824
4894
|
example: "1761922800,1764524800"
|
|
4895
|
+
}),
|
|
4896
|
+
sort: csvArray(z$2.string().regex(OBLIGATION_SORT_ENTRY_REGEX, { message: "Sort entries must be one of: id, ask, bid, maturity (optionally prefixed with '-')" })).refine((entries) => entries === void 0 || entries.length <= MAX_OBLIGATION_SORT_FIELDS, { message: `Sort cannot include more than ${MAX_OBLIGATION_SORT_FIELDS} fields` }).superRefine((entries, ctx) => {
|
|
4897
|
+
if (!entries) return;
|
|
4898
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4899
|
+
for (const entry of entries) {
|
|
4900
|
+
const field = entry.startsWith("-") ? entry.slice(1) : entry;
|
|
4901
|
+
if (seen.has(field)) {
|
|
4902
|
+
ctx.addIssue({
|
|
4903
|
+
code: "custom",
|
|
4904
|
+
message: `Duplicate sort field: ${field}`
|
|
4905
|
+
});
|
|
4906
|
+
return;
|
|
4907
|
+
}
|
|
4908
|
+
seen.add(field);
|
|
4909
|
+
}
|
|
4910
|
+
}).meta({
|
|
4911
|
+
description: "Sort order as comma-separated fields. Prefix a field with '-' for descending order. Max 3 fields.",
|
|
4912
|
+
example: "-ask,bid,maturity"
|
|
4825
4913
|
})
|
|
4826
4914
|
});
|
|
4827
4915
|
const GetObligationParams = z$2.object({ obligation_id: z$2.string({ error: "Obligation id is required and must be a valid 32-byte hex string" }).regex(/^0x[a-fA-F0-9]{64}$/, { error: "Obligation id must be a valid 32-byte hex string" }).transform((val) => val.toLowerCase()).meta({
|
|
@@ -4845,8 +4933,8 @@ const BookPaginationQueryParams = z$2.object({
|
|
|
4845
4933
|
description: "Pagination cursor in base64url-encoded format for book levels",
|
|
4846
4934
|
example: "eyJzaWRlIjoiYnV5IiwibGFzdFJhdGUiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwib2ZmZXJzQ3Vyc29yIjpudWxsfQ"
|
|
4847
4935
|
}),
|
|
4848
|
-
limit: z$2.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$2.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$
|
|
4849
|
-
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$
|
|
4936
|
+
limit: z$2.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$2.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$5).meta({
|
|
4937
|
+
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$5}`,
|
|
4850
4938
|
example: 10
|
|
4851
4939
|
})
|
|
4852
4940
|
});
|
|
@@ -4921,8 +5009,8 @@ async function getConfigRules(query, chains) {
|
|
|
4921
5009
|
} catch (err) {
|
|
4922
5010
|
return failure(err);
|
|
4923
5011
|
}
|
|
4924
|
-
if (cursorRule && typeFilter && !typeFilter.has(cursorRule.type)) return failure(new BadRequestError("Cursor type must match requested rule types"));
|
|
4925
|
-
if (cursorRule && chainFilter && !chainFilter.has(cursorRule.chain_id)) return failure(new BadRequestError("Cursor chain_id must match requested chains"));
|
|
5012
|
+
if (cursorRule && typeFilter && !typeFilter.has(cursorRule.type)) return failure(new BadRequestError$1("Cursor type must match requested rule types"));
|
|
5013
|
+
if (cursorRule && chainFilter && !chainFilter.has(cursorRule.chain_id)) return failure(new BadRequestError$1("Cursor chain_id must match requested chains"));
|
|
4926
5014
|
const startIndex = cursorRule ? findStartIndex$1(filteredRules, cursorRule) : 0;
|
|
4927
5015
|
const page = filteredRules.slice(startIndex, startIndex + limit);
|
|
4928
5016
|
const nextCursor = startIndex + limit < filteredRules.length && page.length > 0 ? formatCursor$1(page.at(-1)) : null;
|
|
@@ -4942,15 +5030,15 @@ function formatCursor$1(rule) {
|
|
|
4942
5030
|
}
|
|
4943
5031
|
function parseCursor$1(cursor) {
|
|
4944
5032
|
const [type, chain, ...rest] = cursor.split(":");
|
|
4945
|
-
if (!type || !chain || rest.length === 0) throw new BadRequestError("Cursor must be in the format type:chain_id:<value>");
|
|
4946
|
-
if (!isConfigRuleType(type)) throw new BadRequestError("Cursor has an invalid rule type");
|
|
5033
|
+
if (!type || !chain || rest.length === 0) throw new BadRequestError$1("Cursor must be in the format type:chain_id:<value>");
|
|
5034
|
+
if (!isConfigRuleType(type)) throw new BadRequestError$1("Cursor has an invalid rule type");
|
|
4947
5035
|
const chain_id = Number.parseInt(chain, 10);
|
|
4948
|
-
if (!Number.isFinite(chain_id)) throw new BadRequestError("Cursor has an invalid chain_id");
|
|
5036
|
+
if (!Number.isFinite(chain_id)) throw new BadRequestError$1("Cursor has an invalid chain_id");
|
|
4949
5037
|
if (type === "maturity") {
|
|
4950
5038
|
const timestampValue = Number.parseInt(rest[0] ?? "", 10);
|
|
4951
5039
|
const nameValue = rest.slice(1).join(":");
|
|
4952
|
-
if (!Number.isFinite(timestampValue) || nameValue.length === 0) throw new BadRequestError("Cursor must be in the format maturity:chain_id:timestamp:name");
|
|
4953
|
-
if (!isMaturityType(nameValue)) throw new BadRequestError("Cursor has an invalid maturity name");
|
|
5040
|
+
if (!Number.isFinite(timestampValue) || nameValue.length === 0) throw new BadRequestError$1("Cursor must be in the format maturity:chain_id:timestamp:name");
|
|
5041
|
+
if (!isMaturityType(nameValue)) throw new BadRequestError$1("Cursor has an invalid maturity name");
|
|
4954
5042
|
return {
|
|
4955
5043
|
type,
|
|
4956
5044
|
chain_id,
|
|
@@ -4961,8 +5049,8 @@ function parseCursor$1(cursor) {
|
|
|
4961
5049
|
if (type === "callback") {
|
|
4962
5050
|
const callbackTypeValue = rest[0] ?? "";
|
|
4963
5051
|
const addressValue = rest.slice(1).join(":");
|
|
4964
|
-
if (!callbackTypeValue || !addressValue) throw new BadRequestError("Cursor must be in the format callback:chain_id:callback_type:address");
|
|
4965
|
-
if (!isCallbackType(callbackTypeValue)) throw new BadRequestError("Cursor has an invalid callback type");
|
|
5052
|
+
if (!callbackTypeValue || !addressValue) throw new BadRequestError$1("Cursor must be in the format callback:chain_id:callback_type:address");
|
|
5053
|
+
if (!isCallbackType(callbackTypeValue)) throw new BadRequestError$1("Cursor has an invalid callback type");
|
|
4966
5054
|
return {
|
|
4967
5055
|
type,
|
|
4968
5056
|
chain_id,
|
|
@@ -4972,14 +5060,14 @@ function parseCursor$1(cursor) {
|
|
|
4972
5060
|
}
|
|
4973
5061
|
if (type === "loan_token" || type === "collateral_token" || type === "oracle") {
|
|
4974
5062
|
const addressValue = rest.join(":");
|
|
4975
|
-
if (!addressValue) throw new BadRequestError(`Cursor must be in the format ${type}:chain_id:address`);
|
|
5063
|
+
if (!addressValue) throw new BadRequestError$1(`Cursor must be in the format ${type}:chain_id:address`);
|
|
4976
5064
|
return {
|
|
4977
5065
|
type,
|
|
4978
5066
|
chain_id,
|
|
4979
5067
|
address: parseAddress(addressValue, "Cursor address")
|
|
4980
5068
|
};
|
|
4981
5069
|
}
|
|
4982
|
-
throw new BadRequestError("Cursor has an invalid rule type");
|
|
5070
|
+
throw new BadRequestError$1("Cursor has an invalid rule type");
|
|
4983
5071
|
}
|
|
4984
5072
|
function findStartIndex$1(rules, cursor) {
|
|
4985
5073
|
let low = 0;
|
|
@@ -4993,7 +5081,7 @@ function findStartIndex$1(rules, cursor) {
|
|
|
4993
5081
|
return low;
|
|
4994
5082
|
}
|
|
4995
5083
|
function parseAddress(address, label) {
|
|
4996
|
-
if (!/^0x[a-fA-F0-9]{40}$/.test(address)) throw new BadRequestError(`${label} must be a valid 20-byte address`);
|
|
5084
|
+
if (!/^0x[a-fA-F0-9]{40}$/.test(address)) throw new BadRequestError$1(`${label} must be a valid 20-byte address`);
|
|
4997
5085
|
return address.toLowerCase();
|
|
4998
5086
|
}
|
|
4999
5087
|
function isConfigRuleType(value) {
|
|
@@ -5006,7 +5094,7 @@ function parseMaturity(value) {
|
|
|
5006
5094
|
try {
|
|
5007
5095
|
return from$16(value);
|
|
5008
5096
|
} catch (err) {
|
|
5009
|
-
throw new BadRequestError(err instanceof Error ? err.message : "Invalid maturity timestamp");
|
|
5097
|
+
throw new BadRequestError$1(err instanceof Error ? err.message : "Invalid maturity timestamp");
|
|
5010
5098
|
}
|
|
5011
5099
|
}
|
|
5012
5100
|
function isCallbackType(value) {
|
|
@@ -5089,7 +5177,7 @@ function formatValue(value) {
|
|
|
5089
5177
|
async function validateOffers(body, gatekeeper) {
|
|
5090
5178
|
const logger = getLogger();
|
|
5091
5179
|
const result = safeParse("validate_offers", body, (issue) => issue.message);
|
|
5092
|
-
if (!result.success) return failure(new BadRequestError(result.error.issues[0]?.message ?? "Invalid request body"));
|
|
5180
|
+
if (!result.success) return failure(new BadRequestError$1(result.error.issues[0]?.message ?? "Invalid request body"));
|
|
5093
5181
|
const { offers: rawOffers } = result.data;
|
|
5094
5182
|
const parsedOffers = [];
|
|
5095
5183
|
const offerIndexByHash = /* @__PURE__ */ new Map();
|
|
@@ -5105,7 +5193,7 @@ async function validateOffers(body, gatekeeper) {
|
|
|
5105
5193
|
} catch (err) {
|
|
5106
5194
|
let message = err instanceof Error ? err.message : String(err);
|
|
5107
5195
|
if (err instanceof InvalidOfferError) message = err.formattedMessage;
|
|
5108
|
-
return failure(new BadRequestError(`Offer at index ${i} failed to parse: ${message}`));
|
|
5196
|
+
return failure(new BadRequestError$1(`Offer at index ${i} failed to parse: ${message}`));
|
|
5109
5197
|
}
|
|
5110
5198
|
}
|
|
5111
5199
|
try {
|
|
@@ -5164,7 +5252,7 @@ function createApp(parameters) {
|
|
|
5164
5252
|
return c.json(failure$4.body, failure$4.statusCode);
|
|
5165
5253
|
}
|
|
5166
5254
|
if (body === null || typeof body !== "object") {
|
|
5167
|
-
const failure$3 = failure(new BadRequestError("Request body must be a JSON object"));
|
|
5255
|
+
const failure$3 = failure(new BadRequestError$1("Request body must be a JSON object"));
|
|
5168
5256
|
return c.json(failure$3.body, failure$3.statusCode);
|
|
5169
5257
|
}
|
|
5170
5258
|
const { statusCode, body: payload } = await validateOffers(body, gatekeeper);
|
|
@@ -5433,6 +5521,7 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
5433
5521
|
buy: boolean("buy").notNull(),
|
|
5434
5522
|
callbackAddress: varchar("callback_address", { length: 42 }).notNull(),
|
|
5435
5523
|
callbackData: text("callback_data").notNull(),
|
|
5524
|
+
receiverIfMakerIsSeller: varchar("receiver_if_maker_is_seller", { length: 42 }),
|
|
5436
5525
|
blockNumber: bigint("block_number", { mode: "number" }).notNull(),
|
|
5437
5526
|
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
5438
5527
|
}, (table) => [
|
|
@@ -6814,7 +6903,7 @@ async function* collectPrices(parameters) {
|
|
|
6814
6903
|
//#region src/indexer/collectors/CollectorBuilder.ts
|
|
6815
6904
|
function createBuilder(parameters) {
|
|
6816
6905
|
const { client, db, gatekeeper, options: { maxBlockNumber, blockWindow, interval } = {} } = parameters;
|
|
6817
|
-
const createCollector = (name, collect) => create$
|
|
6906
|
+
const createCollector = (name, collect) => create$17({
|
|
6818
6907
|
name,
|
|
6819
6908
|
collect,
|
|
6820
6909
|
client,
|
|
@@ -6918,7 +7007,7 @@ function from$1(config) {
|
|
|
6918
7007
|
retryAttempts,
|
|
6919
7008
|
retryDelayMs
|
|
6920
7009
|
});
|
|
6921
|
-
return create$
|
|
7010
|
+
return create$19({
|
|
6922
7011
|
client,
|
|
6923
7012
|
collectors: [
|
|
6924
7013
|
offersCollector,
|
|
@@ -6928,7 +7017,7 @@ function from$1(config) {
|
|
|
6928
7017
|
]
|
|
6929
7018
|
});
|
|
6930
7019
|
}
|
|
6931
|
-
function create$
|
|
7020
|
+
function create$19(params) {
|
|
6932
7021
|
const { collectors, client } = params;
|
|
6933
7022
|
const indexerId = `${client.chain.id.toString()}.indexer`;
|
|
6934
7023
|
const tracer = getTracer(`router.${indexerId}`);
|
|
@@ -6957,7 +7046,7 @@ function create$18(params) {
|
|
|
6957
7046
|
|
|
6958
7047
|
//#endregion
|
|
6959
7048
|
//#region src/indexer/collectors/Admin.ts
|
|
6960
|
-
function create$
|
|
7049
|
+
function create$18(parameters) {
|
|
6961
7050
|
const collector = "admin";
|
|
6962
7051
|
const { client, db, options: { maxBatchSize = 25, maxBlockNumber } = {} } = parameters;
|
|
6963
7052
|
const maxBlockNumberBI = maxBlockNumber !== void 0 ? BigInt(maxBlockNumber) : void 0;
|
|
@@ -7197,8 +7286,8 @@ const names = [
|
|
|
7197
7286
|
"positions",
|
|
7198
7287
|
"prices"
|
|
7199
7288
|
];
|
|
7200
|
-
function create$
|
|
7201
|
-
const admin = create$
|
|
7289
|
+
function create$17({ name, collect, client, db, options }) {
|
|
7290
|
+
const admin = create$18({
|
|
7202
7291
|
client,
|
|
7203
7292
|
db,
|
|
7204
7293
|
options
|
|
@@ -7325,7 +7414,7 @@ function start(collector) {
|
|
|
7325
7414
|
//#endregion
|
|
7326
7415
|
//#region src/database/domains/Blocks.ts
|
|
7327
7416
|
/** Postgres implementation. */
|
|
7328
|
-
const create$
|
|
7417
|
+
const create$16 = (config) => {
|
|
7329
7418
|
const { db, chainRegistry } = config;
|
|
7330
7419
|
const getChain = async (chainId) => {
|
|
7331
7420
|
const rows = await db.select({
|
|
@@ -7504,14 +7593,14 @@ const create$15 = (config) => {
|
|
|
7504
7593
|
|
|
7505
7594
|
//#endregion
|
|
7506
7595
|
//#region src/database/domains/Book.ts
|
|
7507
|
-
const DEFAULT_LIMIT$
|
|
7596
|
+
const DEFAULT_LIMIT$4 = 100;
|
|
7508
7597
|
const MAX_TOTAL_OFFERS = 500;
|
|
7509
|
-
function create$
|
|
7598
|
+
function create$15(config) {
|
|
7510
7599
|
const db = config.db;
|
|
7511
7600
|
const logger = getLogger();
|
|
7512
7601
|
const getOffers = async (parameters) => {
|
|
7513
7602
|
const { side, obligationId, cursor: cursorString } = parameters;
|
|
7514
|
-
const requestedLimit = parameters.limit ?? DEFAULT_LIMIT$
|
|
7603
|
+
const requestedLimit = parameters.limit ?? DEFAULT_LIMIT$4;
|
|
7515
7604
|
const priceSortDirection = side === "sell" ? "asc" : "desc";
|
|
7516
7605
|
const inputCursor = Cursor.decode(cursorString, logger);
|
|
7517
7606
|
if (cursorString != null && inputCursor === null) return {
|
|
@@ -7543,7 +7632,7 @@ function create$14(config) {
|
|
|
7543
7632
|
};
|
|
7544
7633
|
return {
|
|
7545
7634
|
get: async (parameters) => {
|
|
7546
|
-
const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT$
|
|
7635
|
+
const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT$4 } = parameters;
|
|
7547
7636
|
const tickSortDirection = side === "sell" ? "asc" : "desc";
|
|
7548
7637
|
const inputCursor = LevelCursor.decode(cursorString, logger);
|
|
7549
7638
|
if (cursorString != null && inputCursor === null) return {
|
|
@@ -7708,6 +7797,7 @@ async function _getOffers(db, params) {
|
|
|
7708
7797
|
p.buy,
|
|
7709
7798
|
p.callback_address,
|
|
7710
7799
|
p.callback_data,
|
|
7800
|
+
p.receiver_if_maker_is_seller,
|
|
7711
7801
|
p.block_number,
|
|
7712
7802
|
p.group_chain_id,
|
|
7713
7803
|
p.group_maker,
|
|
@@ -7785,6 +7875,7 @@ async function _getOffers(db, params) {
|
|
|
7785
7875
|
buy,
|
|
7786
7876
|
callback_address,
|
|
7787
7877
|
callback_data,
|
|
7878
|
+
receiver_if_maker_is_seller,
|
|
7788
7879
|
block_number,
|
|
7789
7880
|
group_chain_id,
|
|
7790
7881
|
group_maker,
|
|
@@ -7802,8 +7893,8 @@ async function _getOffers(db, params) {
|
|
|
7802
7893
|
ORDER BY clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user, clc.contribution_in_loan DESC
|
|
7803
7894
|
) deduped
|
|
7804
7895
|
GROUP BY hash, obligation_id, assets, tick, obligation_units, obligation_shares, maturity, expiry, start, group_group, buy,
|
|
7805
|
-
|
|
7806
|
-
consumed, chain_id, loan_token, session
|
|
7896
|
+
callback_address, callback_data, block_number, group_chain_id, group_maker,
|
|
7897
|
+
consumed, chain_id, loan_token, session, receiver_if_maker_is_seller
|
|
7807
7898
|
UNION ALL
|
|
7808
7899
|
-- Sell offers without callbacks: collateral positions not indexed, takeable = assets - consumed
|
|
7809
7900
|
SELECT
|
|
@@ -7811,6 +7902,7 @@ async function _getOffers(db, params) {
|
|
|
7811
7902
|
p.obligation_units, p.obligation_shares,
|
|
7812
7903
|
p.maturity, p.expiry, p.start, p.group_group,
|
|
7813
7904
|
p.buy, p.callback_address, p.callback_data,
|
|
7905
|
+
p.receiver_if_maker_is_seller,
|
|
7814
7906
|
p.block_number, p.group_chain_id, p.group_maker,
|
|
7815
7907
|
p.consumed, p.chain_id, p.loan_token, p.session,
|
|
7816
7908
|
0 AS total_available
|
|
@@ -7839,6 +7931,7 @@ async function _getOffers(db, params) {
|
|
|
7839
7931
|
oc.loan_token,
|
|
7840
7932
|
oc.callback_address,
|
|
7841
7933
|
oc.callback_data,
|
|
7934
|
+
oc.receiver_if_maker_is_seller,
|
|
7842
7935
|
oc.block_number,
|
|
7843
7936
|
oc.session,
|
|
7844
7937
|
COALESCE(oc.total_available, 0) AS available,
|
|
@@ -7868,6 +7961,7 @@ async function _getOffers(db, params) {
|
|
|
7868
7961
|
`);
|
|
7869
7962
|
return {
|
|
7870
7963
|
rows: raw.rows.map((row) => {
|
|
7964
|
+
const receiverIfMakerIsSeller = (row.receiver_if_maker_is_seller ?? row.group_maker).toLowerCase();
|
|
7871
7965
|
return {
|
|
7872
7966
|
hash: row.hash,
|
|
7873
7967
|
maker: row.group_maker,
|
|
@@ -7892,6 +7986,7 @@ async function _getOffers(db, params) {
|
|
|
7892
7986
|
address: row.callback_address,
|
|
7893
7987
|
data: row.callback_data
|
|
7894
7988
|
},
|
|
7989
|
+
receiverIfMakerIsSeller,
|
|
7895
7990
|
blockNumber: row.block_number,
|
|
7896
7991
|
consumed: BigInt(row.consumed ?? 0),
|
|
7897
7992
|
available: BigInt(String(row.available ?? "0").split(".")[0] ?? "0"),
|
|
@@ -7983,7 +8078,7 @@ const DEFAULT_BATCH_SIZE = 4e3;
|
|
|
7983
8078
|
* @param db - Database core instance.
|
|
7984
8079
|
* @returns Callbacks domain. {@link CallbacksDomain}
|
|
7985
8080
|
*/
|
|
7986
|
-
function create$
|
|
8081
|
+
function create$14(db) {
|
|
7987
8082
|
return {
|
|
7988
8083
|
upsert: async (inputs) => {
|
|
7989
8084
|
if (inputs.length === 0) return;
|
|
@@ -8038,7 +8133,7 @@ function create$13(db) {
|
|
|
8038
8133
|
|
|
8039
8134
|
//#endregion
|
|
8040
8135
|
//#region src/database/domains/Consumed.ts
|
|
8041
|
-
function create$
|
|
8136
|
+
function create$13(db) {
|
|
8042
8137
|
return {
|
|
8043
8138
|
create: async (events) => {
|
|
8044
8139
|
if (events.length === 0) return;
|
|
@@ -8086,7 +8181,7 @@ function create$12(db) {
|
|
|
8086
8181
|
* @param db - Database core instance.
|
|
8087
8182
|
* @returns Groups domain. {@link GroupsDomain}
|
|
8088
8183
|
*/
|
|
8089
|
-
function create$
|
|
8184
|
+
function create$12(db) {
|
|
8090
8185
|
return { create: async (groups$1) => {
|
|
8091
8186
|
if (groups$1.length === 0) return;
|
|
8092
8187
|
const rows = groups$1.map((group) => ({
|
|
@@ -8102,7 +8197,7 @@ function create$11(db) {
|
|
|
8102
8197
|
|
|
8103
8198
|
//#endregion
|
|
8104
8199
|
//#region src/database/domains/Lots.ts
|
|
8105
|
-
function create$
|
|
8200
|
+
function create$11(db) {
|
|
8106
8201
|
return {
|
|
8107
8202
|
get: async (parameters) => {
|
|
8108
8203
|
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
@@ -8155,45 +8250,67 @@ function create$10(db) {
|
|
|
8155
8250
|
* @param db - Database core instance.
|
|
8156
8251
|
* @returns Obligations domain. {@link ObligationsDomain}
|
|
8157
8252
|
*/
|
|
8158
|
-
function create$
|
|
8159
|
-
return {
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
|
|
8253
|
+
function create$10(db) {
|
|
8254
|
+
return {
|
|
8255
|
+
get: async (parameters) => {
|
|
8256
|
+
const chainIds = parameters?.chainId;
|
|
8257
|
+
const now$3 = now();
|
|
8258
|
+
return (await db.select({
|
|
8259
|
+
chainId: obligations.chainId,
|
|
8260
|
+
loanToken: obligations.loanToken,
|
|
8261
|
+
collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${oracles.address}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
8262
|
+
maturity: obligations.maturity
|
|
8263
|
+
}).from(obligations).innerJoin(obligationCollateralsV2, eq(obligations.obligationId, obligationCollateralsV2.obligationId)).innerJoin(oracles, sql`${obligationCollateralsV2.oracleChainId} = ${oracles.chainId}
|
|
8264
|
+
AND ${obligationCollateralsV2.oracleAddress} = ${oracles.address}`).groupBy(obligations.obligationId).where(and(chainIds !== void 0 && chainIds.length > 0 ? inArray(obligations.chainId, chainIds) : void 0, gte(obligations.maturity, now$3))).orderBy(asc(obligations.obligationId))).map((row) => from$13({
|
|
8265
|
+
chainId: row.chainId,
|
|
8266
|
+
loanToken: row.loanToken,
|
|
8267
|
+
collaterals: row.collaterals.sort((left, right) => left.asset.localeCompare(right.asset)).map((collateral) => from$14({
|
|
8268
|
+
asset: collateral.asset,
|
|
8269
|
+
oracle: collateral.oracle,
|
|
8270
|
+
lltv: from$15(BigInt(collateral.lltv))
|
|
8271
|
+
})),
|
|
8272
|
+
maturity: row.maturity
|
|
8273
|
+
}));
|
|
8274
|
+
},
|
|
8275
|
+
create: async (obligations$1) => {
|
|
8276
|
+
if (obligations$1.length === 0) return;
|
|
8277
|
+
const obligationsById = /* @__PURE__ */ new Map();
|
|
8278
|
+
for (const obligation of obligations$1) {
|
|
8279
|
+
const id$1 = id(obligation).toLowerCase();
|
|
8280
|
+
if (!obligationsById.get(id$1)) obligationsById.set(id$1, obligation);
|
|
8281
|
+
}
|
|
8282
|
+
try {
|
|
8283
|
+
await db.transaction(async (dbTx) => {
|
|
8284
|
+
const obligationRows = obligations$1.map((obligation) => ({
|
|
8177
8285
|
obligationId: id(obligation),
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
lltv: collateral.lltv
|
|
8286
|
+
chainId: obligation.chainId,
|
|
8287
|
+
loanToken: obligation.loanToken.toLowerCase(),
|
|
8288
|
+
maturity: obligation.maturity
|
|
8182
8289
|
}));
|
|
8290
|
+
for (const batch of batch$1(obligationRows, DEFAULT_BATCH_SIZE)) await dbTx.insert(obligations).values(batch).onConflictDoNothing();
|
|
8291
|
+
const collateralRows = obligations$1.flatMap((obligation) => {
|
|
8292
|
+
return obligation.collaterals.map((collateral) => ({
|
|
8293
|
+
obligationId: id(obligation),
|
|
8294
|
+
asset: collateral.asset.toLowerCase(),
|
|
8295
|
+
oracleChainId: obligation.chainId,
|
|
8296
|
+
oracleAddress: collateral.oracle.toLowerCase(),
|
|
8297
|
+
lltv: collateral.lltv
|
|
8298
|
+
}));
|
|
8299
|
+
});
|
|
8300
|
+
for (const batch of batch$1(collateralRows, DEFAULT_BATCH_SIZE)) await dbTx.insert(obligationCollateralsV2).values(batch).onConflictDoNothing();
|
|
8183
8301
|
});
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
throw new Error("Obligations.create failed. Ensure oracles exist before inserting obligations.", { cause: error });
|
|
8302
|
+
} catch (err) {
|
|
8303
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
8304
|
+
throw new Error("Obligations.create failed. Ensure oracles exist before inserting obligations.", { cause: error });
|
|
8305
|
+
}
|
|
8189
8306
|
}
|
|
8190
|
-
}
|
|
8307
|
+
};
|
|
8191
8308
|
}
|
|
8192
8309
|
|
|
8193
8310
|
//#endregion
|
|
8194
8311
|
//#region src/database/domains/Offers.ts
|
|
8195
|
-
const DEFAULT_LIMIT$
|
|
8196
|
-
function create$
|
|
8312
|
+
const DEFAULT_LIMIT$3 = 100;
|
|
8313
|
+
function create$9(config) {
|
|
8197
8314
|
const { db } = config;
|
|
8198
8315
|
return {
|
|
8199
8316
|
create: async (batches) => {
|
|
@@ -8205,6 +8322,7 @@ function create$8(config) {
|
|
|
8205
8322
|
groupMaker: offer.maker.toLowerCase(),
|
|
8206
8323
|
callbackAddress: offer.callback.address.toLowerCase(),
|
|
8207
8324
|
callbackData: offer.callback.data,
|
|
8325
|
+
receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller.toLowerCase(),
|
|
8208
8326
|
blockNumber
|
|
8209
8327
|
})));
|
|
8210
8328
|
if (offersRows.length === 0) return [];
|
|
@@ -8233,7 +8351,7 @@ function create$8(config) {
|
|
|
8233
8351
|
}
|
|
8234
8352
|
},
|
|
8235
8353
|
get: async (parameters) => {
|
|
8236
|
-
const limit = parameters?.limit ?? DEFAULT_LIMIT$
|
|
8354
|
+
const limit = parameters?.limit ?? DEFAULT_LIMIT$3;
|
|
8237
8355
|
const cursor = parameters?.cursor;
|
|
8238
8356
|
const maker = parameters?.maker;
|
|
8239
8357
|
if (cursor !== null && cursor !== void 0) {
|
|
@@ -8267,9 +8385,11 @@ function create$8(config) {
|
|
|
8267
8385
|
loanToken: obligations.loanToken,
|
|
8268
8386
|
callbackAddress: offers.callbackAddress,
|
|
8269
8387
|
callbackData: offers.callbackData,
|
|
8388
|
+
receiverIfMakerIsSeller: offers.receiverIfMakerIsSeller,
|
|
8270
8389
|
collaterals: collateralsLateral.collaterals,
|
|
8271
8390
|
blockNumber: offers.blockNumber
|
|
8272
8391
|
}).from(offers).innerJoin(obligations, eq(offers.obligationId, obligations.obligationId)).innerJoinLateral(collateralsLateral, sql`true`).where(and(cursor !== null && cursor !== void 0 ? gt(offers.hash, cursor) : void 0, maker !== void 0 ? eq(offers.groupMaker, maker.toLowerCase()) : void 0)).orderBy(asc(offers.hash)).limit(limit)).map((row) => {
|
|
8392
|
+
const receiverIfMakerIsSeller = (row.receiverIfMakerIsSeller ?? row.maker).toLowerCase();
|
|
8273
8393
|
return {
|
|
8274
8394
|
hash: row.hash,
|
|
8275
8395
|
maker: row.maker,
|
|
@@ -8294,6 +8414,7 @@ function create$8(config) {
|
|
|
8294
8414
|
address: row.callbackAddress,
|
|
8295
8415
|
data: row.callbackData
|
|
8296
8416
|
},
|
|
8417
|
+
receiverIfMakerIsSeller,
|
|
8297
8418
|
consumed: 0n,
|
|
8298
8419
|
available: 0n,
|
|
8299
8420
|
takeable: 0n,
|
|
@@ -8318,64 +8439,30 @@ function create$8(config) {
|
|
|
8318
8439
|
}
|
|
8319
8440
|
throw new Error("Invalid parameters");
|
|
8320
8441
|
},
|
|
8321
|
-
getObligations: async (parameters) => {
|
|
8322
|
-
const { ids, chainId: chainIds, loanToken: loanTokens, collateralToken: collateralTokens, maturity: maturities, cursor, limit = DEFAULT_LIMIT$2 } = parameters ?? {};
|
|
8323
|
-
const now$1 = now();
|
|
8324
|
-
const loanTokenFilter = loanTokens !== void 0 && loanTokens.length > 0 ? sql`(${sql.join(loanTokens.map((token) => sql`LOWER(${obligations.loanToken}) = ${token.toLowerCase()}`), sql` OR `)})` : void 0;
|
|
8325
|
-
const collateralFilter = collateralTokens !== void 0 && collateralTokens.length > 0 ? sql`EXISTS (
|
|
8326
|
-
SELECT 1 FROM ${obligationCollateralsV2} oc
|
|
8327
|
-
WHERE oc.obligation_id = ${obligations.obligationId}
|
|
8328
|
-
AND (${sql.join(collateralTokens.map((token) => sql`LOWER(oc.asset) = ${token.toLowerCase()}`), sql` OR `)})
|
|
8329
|
-
)` : void 0;
|
|
8330
|
-
const result = await db.select({
|
|
8331
|
-
obligationId: obligations.obligationId,
|
|
8332
|
-
chainId: obligations.chainId,
|
|
8333
|
-
loanToken: obligations.loanToken,
|
|
8334
|
-
collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${oracles.address}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
8335
|
-
maturity: obligations.maturity
|
|
8336
|
-
}).from(obligations).innerJoin(obligationCollateralsV2, eq(obligations.obligationId, obligationCollateralsV2.obligationId)).innerJoin(oracles, sql`${obligationCollateralsV2.oracleChainId} = ${oracles.chainId}
|
|
8337
|
-
AND ${obligationCollateralsV2.oracleAddress} = ${oracles.address}`).groupBy(obligations.obligationId).where(and(cursor !== null && cursor !== void 0 ? gt(obligations.obligationId, cursor) : sql`true`, ids !== void 0 && ids.length > 0 ? inArray(obligations.obligationId, ids) : void 0, chainIds !== void 0 && chainIds.length > 0 ? inArray(obligations.chainId, chainIds) : void 0, loanTokenFilter, maturities !== void 0 && maturities.length > 0 ? inArray(obligations.maturity, maturities) : gte(obligations.maturity, now$1), collateralFilter)).orderBy(asc(obligations.obligationId)).limit(limit);
|
|
8338
|
-
const items = [];
|
|
8339
|
-
for (const row of result) items.push(from$13({
|
|
8340
|
-
chainId: row.chainId,
|
|
8341
|
-
loanToken: row.loanToken,
|
|
8342
|
-
collaterals: row.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)).map((c) => from$14({
|
|
8343
|
-
asset: c.asset,
|
|
8344
|
-
oracle: c.oracle,
|
|
8345
|
-
lltv: from$15(BigInt(c.lltv))
|
|
8346
|
-
})),
|
|
8347
|
-
maturity: row.maturity
|
|
8348
|
-
}));
|
|
8349
|
-
const returnedItems = Array.from(items.values());
|
|
8350
|
-
return {
|
|
8351
|
-
obligations: returnedItems,
|
|
8352
|
-
nextCursor: returnedItems.length === limit && returnedItems.length > 0 ? result[result.length - 1].obligationId : null
|
|
8353
|
-
};
|
|
8354
|
-
},
|
|
8355
8442
|
getQuotes: async (parameters) => {
|
|
8356
8443
|
const { obligationIds } = parameters;
|
|
8357
8444
|
if (obligationIds.length === 0) return [];
|
|
8358
8445
|
const now$2 = now();
|
|
8359
8446
|
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
8360
8447
|
obligationId: offers.obligationId,
|
|
8361
|
-
|
|
8448
|
+
tick: offers.tick
|
|
8362
8449
|
}).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`);
|
|
8363
8450
|
const [bestBuys, bestSells] = await Promise.all([query({ side: "buy" }), query({ side: "sell" })]);
|
|
8364
8451
|
const quotes = /* @__PURE__ */ new Map();
|
|
8365
8452
|
for (const row of bestSells) quotes.set(row.obligationId, {
|
|
8366
|
-
ask: {
|
|
8367
|
-
bid: {
|
|
8453
|
+
ask: { tick: row.tick },
|
|
8454
|
+
bid: { tick: null }
|
|
8368
8455
|
});
|
|
8369
8456
|
for (const row of bestBuys) {
|
|
8370
8457
|
const quote = quotes.get(row.obligationId);
|
|
8371
8458
|
if (!quote) {
|
|
8372
8459
|
quotes.set(row.obligationId, {
|
|
8373
|
-
ask: {
|
|
8374
|
-
bid: {
|
|
8460
|
+
ask: { tick: null },
|
|
8461
|
+
bid: { tick: row.tick }
|
|
8375
8462
|
});
|
|
8376
8463
|
continue;
|
|
8377
8464
|
}
|
|
8378
|
-
quote.bid = {
|
|
8465
|
+
quote.bid = { tick: row.tick };
|
|
8379
8466
|
}
|
|
8380
8467
|
return Array.from(quotes.entries()).map(([id, quote]) => {
|
|
8381
8468
|
return from$9({
|
|
@@ -8392,7 +8479,7 @@ function create$8(config) {
|
|
|
8392
8479
|
|
|
8393
8480
|
//#endregion
|
|
8394
8481
|
//#region src/database/domains/Offsets.ts
|
|
8395
|
-
function create$
|
|
8482
|
+
function create$8(db) {
|
|
8396
8483
|
return { get: async (parameters) => {
|
|
8397
8484
|
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
8398
8485
|
const conditions = [];
|
|
@@ -8414,7 +8501,7 @@ function create$7(db) {
|
|
|
8414
8501
|
|
|
8415
8502
|
//#endregion
|
|
8416
8503
|
//#region src/database/domains/Oracles.ts
|
|
8417
|
-
function create$
|
|
8504
|
+
function create$7(db) {
|
|
8418
8505
|
return {
|
|
8419
8506
|
get: async ({ chainId }) => {
|
|
8420
8507
|
return (await db.select({
|
|
@@ -8456,8 +8543,8 @@ function create$6(db) {
|
|
|
8456
8543
|
|
|
8457
8544
|
//#endregion
|
|
8458
8545
|
//#region src/database/domains/Positions.ts
|
|
8459
|
-
const DEFAULT_LIMIT$
|
|
8460
|
-
const create$
|
|
8546
|
+
const DEFAULT_LIMIT$2 = 100;
|
|
8547
|
+
const create$6 = (db) => {
|
|
8461
8548
|
return {
|
|
8462
8549
|
upsert: async (positions$1) => {
|
|
8463
8550
|
const positionsMap = /* @__PURE__ */ new Map();
|
|
@@ -8512,7 +8599,7 @@ const create$5 = (db) => {
|
|
|
8512
8599
|
return totalUpdated;
|
|
8513
8600
|
},
|
|
8514
8601
|
get: async (parameters) => {
|
|
8515
|
-
const { limit = DEFAULT_LIMIT$
|
|
8602
|
+
const { limit = DEFAULT_LIMIT$2, cursor: encodedCursor, chainId, type, filled } = parameters ?? {};
|
|
8516
8603
|
let cursor = null;
|
|
8517
8604
|
if (encodedCursor !== null && encodedCursor !== void 0) {
|
|
8518
8605
|
const parsed = JSON.parse(Buffer.from(encodedCursor, "base64url").toString("utf8"));
|
|
@@ -8549,7 +8636,7 @@ const create$5 = (db) => {
|
|
|
8549
8636
|
};
|
|
8550
8637
|
},
|
|
8551
8638
|
getByUser: async (parameters) => {
|
|
8552
|
-
const { user, limit = DEFAULT_LIMIT$
|
|
8639
|
+
const { user, limit = DEFAULT_LIMIT$2, cursor: encodedCursor } = parameters;
|
|
8553
8640
|
let cursor = null;
|
|
8554
8641
|
if (encodedCursor !== null && encodedCursor !== void 0) {
|
|
8555
8642
|
const parsed = JSON.parse(Buffer.from(encodedCursor, "base64url").toString("utf8"));
|
|
@@ -8699,7 +8786,7 @@ const create$5 = (db) => {
|
|
|
8699
8786
|
|
|
8700
8787
|
//#endregion
|
|
8701
8788
|
//#region src/database/domains/Transfers.ts
|
|
8702
|
-
const create$
|
|
8789
|
+
const create$5 = (db) => ({ create: async (transfers$1) => {
|
|
8703
8790
|
if (transfers$1.length === 0) return 0;
|
|
8704
8791
|
return await db.transaction(async (dbTx) => {
|
|
8705
8792
|
let totalInserted = 0;
|
|
@@ -8804,7 +8891,7 @@ const create$4 = (db) => ({ create: async (transfers$1) => {
|
|
|
8804
8891
|
* @param config - Configuration with database instance
|
|
8805
8892
|
* @returns TreesDomain instance
|
|
8806
8893
|
*/
|
|
8807
|
-
function create$
|
|
8894
|
+
function create$4(config) {
|
|
8808
8895
|
const db = config.db;
|
|
8809
8896
|
return {
|
|
8810
8897
|
create: async (trees$1) => {
|
|
@@ -8887,11 +8974,11 @@ function splitProofs(concatenated) {
|
|
|
8887
8974
|
|
|
8888
8975
|
//#endregion
|
|
8889
8976
|
//#region src/database/domains/Validations.ts
|
|
8890
|
-
const DEFAULT_LIMIT = 100;
|
|
8891
|
-
function create$
|
|
8977
|
+
const DEFAULT_LIMIT$1 = 100;
|
|
8978
|
+
function create$3(db) {
|
|
8892
8979
|
return {
|
|
8893
8980
|
get: async (params) => {
|
|
8894
|
-
const { status: status$2, cursor, limit = DEFAULT_LIMIT } = params ?? {};
|
|
8981
|
+
const { status: status$2, cursor, limit = DEFAULT_LIMIT$1 } = params ?? {};
|
|
8895
8982
|
if (cursor !== null && cursor !== void 0) {
|
|
8896
8983
|
if (!cursor.startsWith("0x") || cursor.length !== 66) throw new Error("Invalid cursor format");
|
|
8897
8984
|
}
|
|
@@ -8945,29 +9032,260 @@ function create$2(db) {
|
|
|
8945
9032
|
};
|
|
8946
9033
|
}
|
|
8947
9034
|
|
|
9035
|
+
//#endregion
|
|
9036
|
+
//#region src/database/readers/ObligationsListing.ts
|
|
9037
|
+
const SORT_FIELDS = [
|
|
9038
|
+
"id",
|
|
9039
|
+
"ask",
|
|
9040
|
+
"bid",
|
|
9041
|
+
"maturity"
|
|
9042
|
+
];
|
|
9043
|
+
const CURSOR_ID_REGEX = /^0x[a-f0-9]{64}$/i;
|
|
9044
|
+
const INT32_MIN = -2147483648;
|
|
9045
|
+
const INT32_MAX = 2147483647;
|
|
9046
|
+
const INT32_MAX_BIGINT = BigInt(INT32_MAX);
|
|
9047
|
+
const MAX_CURSOR_SORT_FIELDS = 4;
|
|
9048
|
+
const DEFAULT_LIMIT = 20;
|
|
9049
|
+
var BadRequestError = class extends Error {
|
|
9050
|
+
constructor(message) {
|
|
9051
|
+
super(message);
|
|
9052
|
+
this.name = "ObligationsListingBadRequestError";
|
|
9053
|
+
}
|
|
9054
|
+
};
|
|
9055
|
+
/**
|
|
9056
|
+
* Creates the obligations listing reader facade.
|
|
9057
|
+
* @param parameters - Reader dependencies.
|
|
9058
|
+
* @returns Obligations listing reader.
|
|
9059
|
+
*/
|
|
9060
|
+
function create$2(parameters) {
|
|
9061
|
+
const { db } = parameters;
|
|
9062
|
+
return { list: async (queryParameters) => {
|
|
9063
|
+
const { ids, chainId: chainIds, loanToken: loanTokens, collateralToken: collateralTokens, maturity: maturities, sort: sortTokens, cursor: encodedCursor, limit: requestedLimit } = queryParameters ?? {};
|
|
9064
|
+
const limit = requestedLimit ?? DEFAULT_LIMIT;
|
|
9065
|
+
if (!Number.isInteger(limit) || limit <= 0) throw new BadRequestError("Limit must be a positive integer");
|
|
9066
|
+
const cursorPayload = encodedCursor ? decodeCursorPayload(encodedCursor) : void 0;
|
|
9067
|
+
const requestedSort = normalizeSort(sortTokens);
|
|
9068
|
+
const cursorSort = cursorPayload ? normalizeSort(cursorPayload.sort) : void 0;
|
|
9069
|
+
if (cursorSort !== void 0 && sortTokens !== void 0 && !hasSameSort(requestedSort, cursorSort)) throw new BadRequestError("Cursor sort does not match requested sort");
|
|
9070
|
+
const sort = sortTokens !== void 0 ? requestedSort : cursorSort ?? requestedSort;
|
|
9071
|
+
const cursorValues = cursorPayload ? cursorValuesFromPayload(cursorPayload) : void 0;
|
|
9072
|
+
const now$1 = now();
|
|
9073
|
+
const loanTokenFilter = loanTokens !== void 0 && loanTokens.length > 0 ? sql`(${sql.join(loanTokens.map((token) => sql`LOWER(${obligations.loanToken}) = ${token.toLowerCase()}`), sql` OR `)})` : void 0;
|
|
9074
|
+
const collateralFilter = collateralTokens !== void 0 && collateralTokens.length > 0 ? sql`EXISTS (
|
|
9075
|
+
SELECT 1 FROM ${obligationCollateralsV2} oc
|
|
9076
|
+
WHERE oc.obligation_id = ${obligations.obligationId}
|
|
9077
|
+
AND (${sql.join(collateralTokens.map((token) => sql`LOWER(oc.asset) = ${token.toLowerCase()}`), sql` OR `)})
|
|
9078
|
+
)` : void 0;
|
|
9079
|
+
const bestAskTick = db.select({ askTick: offers.tick }).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(eq(offers.obligationId, obligations.obligationId), eq(offers.buy, false), gte(offers.expiry, now$1), gte(offers.maturity, now$1), lte(offers.start, now$1), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(desc(offers.tick)).limit(1).as("best_ask_tick");
|
|
9080
|
+
const bestBidTick = db.select({ bidTick: offers.tick }).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(eq(offers.obligationId, obligations.obligationId), eq(offers.buy, true), gte(offers.expiry, now$1), gte(offers.maturity, now$1), lte(offers.start, now$1), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(asc(offers.tick)).limit(1).as("best_bid_tick");
|
|
9081
|
+
const obligationsWithQuotes = db.select({
|
|
9082
|
+
obligationId: obligations.obligationId,
|
|
9083
|
+
chainId: obligations.chainId,
|
|
9084
|
+
loanToken: obligations.loanToken,
|
|
9085
|
+
collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${oracles.address}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
9086
|
+
maturity: obligations.maturity,
|
|
9087
|
+
askTick: sql`MAX(${bestAskTick.askTick})`.as("ask_tick"),
|
|
9088
|
+
bidTick: sql`MAX(${bestBidTick.bidTick})`.as("bid_tick"),
|
|
9089
|
+
ask: sql`COALESCE(MAX(${bestAskTick.askTick}) + 1, 0)`.as("ask"),
|
|
9090
|
+
bid: sql`COALESCE(MAX(${bestBidTick.bidTick}) + 1, 0)`.as("bid")
|
|
9091
|
+
}).from(obligations).innerJoin(obligationCollateralsV2, eq(obligations.obligationId, obligationCollateralsV2.obligationId)).innerJoin(oracles, sql`${obligationCollateralsV2.oracleChainId} = ${oracles.chainId}
|
|
9092
|
+
AND ${obligationCollateralsV2.oracleAddress} = ${oracles.address}`).leftJoinLateral(bestAskTick, sql`true`).leftJoinLateral(bestBidTick, sql`true`).groupBy(obligations.obligationId).where(and(ids !== void 0 && ids.length > 0 ? inArray(obligations.obligationId, ids) : void 0, chainIds !== void 0 && chainIds.length > 0 ? inArray(obligations.chainId, chainIds) : void 0, loanTokenFilter, maturities !== void 0 && maturities.length > 0 ? inArray(obligations.maturity, maturities) : gte(obligations.maturity, now$1), collateralFilter)).as("obligations_with_quotes");
|
|
9093
|
+
const sortColumns = {
|
|
9094
|
+
id: obligationsWithQuotes.obligationId,
|
|
9095
|
+
ask: obligationsWithQuotes.ask,
|
|
9096
|
+
bid: obligationsWithQuotes.bid,
|
|
9097
|
+
maturity: obligationsWithQuotes.maturity
|
|
9098
|
+
};
|
|
9099
|
+
const rows = await db.select({
|
|
9100
|
+
obligationId: obligationsWithQuotes.obligationId,
|
|
9101
|
+
chainId: obligationsWithQuotes.chainId,
|
|
9102
|
+
loanToken: obligationsWithQuotes.loanToken,
|
|
9103
|
+
collaterals: obligationsWithQuotes.collaterals,
|
|
9104
|
+
maturity: obligationsWithQuotes.maturity,
|
|
9105
|
+
askTick: obligationsWithQuotes.askTick,
|
|
9106
|
+
bidTick: obligationsWithQuotes.bidTick,
|
|
9107
|
+
ask: obligationsWithQuotes.ask,
|
|
9108
|
+
bid: obligationsWithQuotes.bid
|
|
9109
|
+
}).from(obligationsWithQuotes).where(buildCursorFilter(sortColumns, sort, cursorValues)).orderBy(...buildOrderBy(sortColumns, sort)).limit(limit + 1);
|
|
9110
|
+
const hasMore = rows.length > limit;
|
|
9111
|
+
const listedRows = (hasMore ? rows.slice(0, limit) : rows).map((row) => {
|
|
9112
|
+
return {
|
|
9113
|
+
obligation: from$13({
|
|
9114
|
+
chainId: row.chainId,
|
|
9115
|
+
loanToken: row.loanToken,
|
|
9116
|
+
collaterals: row.collaterals.sort((left, right) => left.asset.localeCompare(right.asset)).map((collateral) => from$14({
|
|
9117
|
+
asset: collateral.asset,
|
|
9118
|
+
oracle: collateral.oracle,
|
|
9119
|
+
lltv: from$15(BigInt(collateral.lltv))
|
|
9120
|
+
})),
|
|
9121
|
+
maturity: row.maturity
|
|
9122
|
+
}),
|
|
9123
|
+
quote: from$9({
|
|
9124
|
+
obligationId: row.obligationId,
|
|
9125
|
+
ask: { tick: row.askTick },
|
|
9126
|
+
bid: { tick: row.bidTick }
|
|
9127
|
+
}),
|
|
9128
|
+
cursorValues: {
|
|
9129
|
+
id: row.obligationId,
|
|
9130
|
+
ask: toBigInt(row.ask),
|
|
9131
|
+
bid: toBigInt(row.bid),
|
|
9132
|
+
maturity: row.maturity
|
|
9133
|
+
}
|
|
9134
|
+
};
|
|
9135
|
+
});
|
|
9136
|
+
const nextCursor = hasMore && listedRows.length > 0 ? encodeCursorPayload({
|
|
9137
|
+
sort: sortToTokens(sort),
|
|
9138
|
+
id: listedRows[listedRows.length - 1].cursorValues.id,
|
|
9139
|
+
ask: listedRows[listedRows.length - 1].cursorValues.ask.toString(),
|
|
9140
|
+
bid: listedRows[listedRows.length - 1].cursorValues.bid.toString(),
|
|
9141
|
+
maturity: listedRows[listedRows.length - 1].cursorValues.maturity
|
|
9142
|
+
}) : null;
|
|
9143
|
+
return {
|
|
9144
|
+
obligations: listedRows.map((row) => ({
|
|
9145
|
+
obligation: row.obligation,
|
|
9146
|
+
quote: row.quote
|
|
9147
|
+
})),
|
|
9148
|
+
nextCursor
|
|
9149
|
+
};
|
|
9150
|
+
} };
|
|
9151
|
+
}
|
|
9152
|
+
function isSortField(value) {
|
|
9153
|
+
return SORT_FIELDS.includes(value);
|
|
9154
|
+
}
|
|
9155
|
+
function parseSortToken(token) {
|
|
9156
|
+
const direction = token.startsWith("-") ? "desc" : "asc";
|
|
9157
|
+
const rawField = token.startsWith("-") ? token.slice(1) : token;
|
|
9158
|
+
if (!isSortField(rawField)) throw new BadRequestError(`Invalid sort field: ${rawField}`);
|
|
9159
|
+
return {
|
|
9160
|
+
field: rawField,
|
|
9161
|
+
direction
|
|
9162
|
+
};
|
|
9163
|
+
}
|
|
9164
|
+
function normalizeSort(sortTokens) {
|
|
9165
|
+
const parsed = sortTokens?.length ? sortTokens.map(parseSortToken) : [{
|
|
9166
|
+
field: "id",
|
|
9167
|
+
direction: "asc"
|
|
9168
|
+
}];
|
|
9169
|
+
return parsed.some((entry) => entry.field === "id") ? parsed : [...parsed, {
|
|
9170
|
+
field: "id",
|
|
9171
|
+
direction: "asc"
|
|
9172
|
+
}];
|
|
9173
|
+
}
|
|
9174
|
+
function sortToTokens(sortEntries) {
|
|
9175
|
+
return sortEntries.map((entry) => entry.direction === "desc" ? `-${entry.field}` : entry.field);
|
|
9176
|
+
}
|
|
9177
|
+
function hasSameSort(left, right) {
|
|
9178
|
+
if (left.length !== right.length) return false;
|
|
9179
|
+
return left.every((sortEntry, index) => sortEntry.field === right[index]?.field && sortEntry.direction === right[index]?.direction);
|
|
9180
|
+
}
|
|
9181
|
+
function decodeCursorPayload(cursor) {
|
|
9182
|
+
let decoded;
|
|
9183
|
+
try {
|
|
9184
|
+
decoded = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
9185
|
+
} catch {
|
|
9186
|
+
throw new BadRequestError("Invalid cursor format");
|
|
9187
|
+
}
|
|
9188
|
+
if (decoded === null || typeof decoded !== "object") throw new BadRequestError("Invalid cursor payload");
|
|
9189
|
+
const payload = decoded;
|
|
9190
|
+
const sortTokens = parseCursorSortTokens(payload.sort);
|
|
9191
|
+
if (typeof payload.id !== "string" || !CURSOR_ID_REGEX.test(payload.id)) throw new BadRequestError("Invalid cursor obligation id");
|
|
9192
|
+
const ask = parseCursorNonNegativeInt32(payload.ask, "ask");
|
|
9193
|
+
const bid = parseCursorNonNegativeInt32(payload.bid, "bid");
|
|
9194
|
+
if (!isInt32(payload.maturity)) throw new BadRequestError("Invalid cursor maturity value");
|
|
9195
|
+
return {
|
|
9196
|
+
sort: sortTokens,
|
|
9197
|
+
id: payload.id,
|
|
9198
|
+
ask,
|
|
9199
|
+
bid,
|
|
9200
|
+
maturity: payload.maturity
|
|
9201
|
+
};
|
|
9202
|
+
}
|
|
9203
|
+
function parseCursorSortTokens(value) {
|
|
9204
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > MAX_CURSOR_SORT_FIELDS) throw new BadRequestError("Invalid cursor sort");
|
|
9205
|
+
const sortEntries = value.map((token) => {
|
|
9206
|
+
if (typeof token !== "string") throw new BadRequestError("Invalid cursor sort");
|
|
9207
|
+
try {
|
|
9208
|
+
return parseSortToken(token);
|
|
9209
|
+
} catch {
|
|
9210
|
+
throw new BadRequestError("Invalid cursor sort");
|
|
9211
|
+
}
|
|
9212
|
+
});
|
|
9213
|
+
if (new Set(sortEntries.map((entry) => entry.field)).size !== sortEntries.length) throw new BadRequestError("Invalid cursor sort");
|
|
9214
|
+
return sortToTokens(sortEntries);
|
|
9215
|
+
}
|
|
9216
|
+
function parseCursorNonNegativeInt32(value, field) {
|
|
9217
|
+
if (typeof value !== "string" || !/^\d+$/.test(value)) throw new BadRequestError(`Invalid cursor ${field} value`);
|
|
9218
|
+
if (BigInt(value) > INT32_MAX_BIGINT) throw new BadRequestError(`Invalid cursor ${field} value`);
|
|
9219
|
+
return value;
|
|
9220
|
+
}
|
|
9221
|
+
function isInt32(value) {
|
|
9222
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= INT32_MIN && value <= INT32_MAX;
|
|
9223
|
+
}
|
|
9224
|
+
function encodeCursorPayload(payload) {
|
|
9225
|
+
return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
9226
|
+
}
|
|
9227
|
+
function cursorValuesFromPayload(payload) {
|
|
9228
|
+
return {
|
|
9229
|
+
id: payload.id,
|
|
9230
|
+
ask: BigInt(payload.ask),
|
|
9231
|
+
bid: BigInt(payload.bid),
|
|
9232
|
+
maturity: payload.maturity
|
|
9233
|
+
};
|
|
9234
|
+
}
|
|
9235
|
+
function cursorComparisonValue(cursorValues, field) {
|
|
9236
|
+
switch (field) {
|
|
9237
|
+
case "id": return cursorValues.id;
|
|
9238
|
+
case "maturity": return cursorValues.maturity;
|
|
9239
|
+
case "ask": return cursorValues.ask.toString();
|
|
9240
|
+
case "bid": return cursorValues.bid.toString();
|
|
9241
|
+
}
|
|
9242
|
+
}
|
|
9243
|
+
function buildCursorFilter(columns, sortEntries, cursorValues) {
|
|
9244
|
+
if (cursorValues === void 0) return void 0;
|
|
9245
|
+
const comparisons = sortEntries.map((sortEntry, index) => {
|
|
9246
|
+
const equals = sortEntries.slice(0, index).map((previous) => {
|
|
9247
|
+
return sql`${columns[previous.field]} = ${cursorComparisonValue(cursorValues, previous.field)}`;
|
|
9248
|
+
});
|
|
9249
|
+
const comparison = sortEntry.direction === "asc" ? sql`${columns[sortEntry.field]} > ${cursorComparisonValue(cursorValues, sortEntry.field)}` : sql`${columns[sortEntry.field]} < ${cursorComparisonValue(cursorValues, sortEntry.field)}`;
|
|
9250
|
+
return equals.length > 0 ? sql`(${sql.join([...equals, comparison], sql` AND `)})` : sql`(${comparison})`;
|
|
9251
|
+
});
|
|
9252
|
+
return comparisons.length > 0 ? sql`(${sql.join(comparisons, sql` OR `)})` : void 0;
|
|
9253
|
+
}
|
|
9254
|
+
function buildOrderBy(columns, sortEntries) {
|
|
9255
|
+
return sortEntries.map((sortEntry) => sortEntry.direction === "asc" ? asc(columns[sortEntry.field]) : desc(columns[sortEntry.field]));
|
|
9256
|
+
}
|
|
9257
|
+
function toBigInt(value) {
|
|
9258
|
+
if (typeof value === "bigint") return value;
|
|
9259
|
+
if (typeof value === "number") return BigInt(value);
|
|
9260
|
+
return BigInt(value.split(".")[0] ?? "0");
|
|
9261
|
+
}
|
|
9262
|
+
|
|
8948
9263
|
//#endregion
|
|
8949
9264
|
//#region src/database/Database.ts
|
|
8950
9265
|
function createDomains(core, chainRegistry) {
|
|
8951
9266
|
return {
|
|
8952
|
-
book: create$
|
|
8953
|
-
blocks: create$
|
|
9267
|
+
book: create$15({ db: core }),
|
|
9268
|
+
blocks: create$16({
|
|
8954
9269
|
db: core,
|
|
8955
9270
|
chainRegistry
|
|
8956
9271
|
}),
|
|
8957
|
-
callbacks: create$
|
|
8958
|
-
offers: create$
|
|
8959
|
-
consumed: create$
|
|
8960
|
-
groups: create$
|
|
8961
|
-
lots: create$
|
|
8962
|
-
obligations: create$
|
|
8963
|
-
offsets: create$
|
|
8964
|
-
oracles: create$
|
|
8965
|
-
trees: create$
|
|
8966
|
-
validations: create$
|
|
8967
|
-
positions: create$
|
|
8968
|
-
transfers: create$
|
|
9272
|
+
callbacks: create$14(core),
|
|
9273
|
+
offers: create$9({ db: core }),
|
|
9274
|
+
consumed: create$13(core),
|
|
9275
|
+
groups: create$12(core),
|
|
9276
|
+
lots: create$11(core),
|
|
9277
|
+
obligations: create$10(core),
|
|
9278
|
+
offsets: create$8(core),
|
|
9279
|
+
oracles: create$7(core),
|
|
9280
|
+
trees: create$4({ db: core }),
|
|
9281
|
+
validations: create$3(core),
|
|
9282
|
+
positions: create$6(core),
|
|
9283
|
+
transfers: create$5(core)
|
|
8969
9284
|
};
|
|
8970
9285
|
}
|
|
9286
|
+
function createReaders(core) {
|
|
9287
|
+
return { obligations: create$2({ db: core }) };
|
|
9288
|
+
}
|
|
8971
9289
|
const AUGMENT_CACHE = /* @__PURE__ */ new WeakMap();
|
|
8972
9290
|
function augmentWithDomains(base, chainRegistry) {
|
|
8973
9291
|
const cached = AUGMENT_CACHE.get(base)?.get(chainRegistry);
|
|
@@ -8979,6 +9297,7 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
8979
9297
|
});
|
|
8980
9298
|
};
|
|
8981
9299
|
const dms = createDomains(wrapped, chainRegistry);
|
|
9300
|
+
const readers = createReaders(wrapped);
|
|
8982
9301
|
Object.defineProperties(wrapped, {
|
|
8983
9302
|
book: {
|
|
8984
9303
|
value: dms.book,
|
|
@@ -9035,6 +9354,10 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9035
9354
|
transfers: {
|
|
9036
9355
|
value: dms.transfers,
|
|
9037
9356
|
enumerable: true
|
|
9357
|
+
},
|
|
9358
|
+
readers: {
|
|
9359
|
+
value: readers,
|
|
9360
|
+
enumerable: true
|
|
9038
9361
|
}
|
|
9039
9362
|
});
|
|
9040
9363
|
const chainRegistryMap = AUGMENT_CACHE.get(base);
|
|
@@ -9696,7 +10019,7 @@ var RouterCmd = class RouterCmd extends Command {
|
|
|
9696
10019
|
const configPath = resolveConfigPath(options.configFile);
|
|
9697
10020
|
const config = configPath !== null ? loadRouterConfig(configPath) : createDefaultConfig();
|
|
9698
10021
|
const logger = defaultLogger(config.logging.level, config.logging.pretty);
|
|
9699
|
-
const chainRegistry = create$
|
|
10022
|
+
const chainRegistry = create$20(Object.values(config.chains).map((entry) => entry.chain));
|
|
9700
10023
|
const clients = (config.indexer?.chains ?? []).map((name) => {
|
|
9701
10024
|
const chainConfig = config.chains[name];
|
|
9702
10025
|
if (!chainConfig) throw new Error(`Indexer chain ${name} is not defined under [chains].`);
|
|
@@ -9744,7 +10067,7 @@ const gatekeeperCmd = new RouterCmd("gatekeeper");
|
|
|
9744
10067
|
gatekeeperCmd.description("Start Gatekeeper validation service.").action(async (opts) => {
|
|
9745
10068
|
const { gatekeeper: gatekeeperConfig, chainRegistry, logger } = opts;
|
|
9746
10069
|
await runWithLogger(logger, async () => {
|
|
9747
|
-
const gatekeeperCore = create$
|
|
10070
|
+
const gatekeeperCore = create$21({ rules: morphoRules(chainRegistry.list()) });
|
|
9748
10071
|
const handle = await start$1({
|
|
9749
10072
|
gatekeeper: gatekeeperCore,
|
|
9750
10073
|
chainRegistry,
|
|
@@ -9890,7 +10213,7 @@ async function getConfigContracts(query, chainRegistry) {
|
|
|
9890
10213
|
}
|
|
9891
10214
|
function parseCursor(cursor) {
|
|
9892
10215
|
const [chain, address] = cursor.split(":", 2);
|
|
9893
|
-
if (!chain || !address) throw new BadRequestError("Cursor must be in the format chain_id:0x...");
|
|
10216
|
+
if (!chain || !address) throw new BadRequestError$1("Cursor must be in the format chain_id:0x...");
|
|
9894
10217
|
return {
|
|
9895
10218
|
chain_id: Number.parseInt(chain, 10),
|
|
9896
10219
|
address: address.toLowerCase()
|
|
@@ -10211,37 +10534,44 @@ async function getHealthCollectors(query, db, chainRegistry) {
|
|
|
10211
10534
|
|
|
10212
10535
|
//#endregion
|
|
10213
10536
|
//#region src/api/Controllers/getObligation.ts
|
|
10537
|
+
function toPayloadError$1(err) {
|
|
10538
|
+
if (err instanceof BadRequestError) return new BadRequestError$1(err.message);
|
|
10539
|
+
return err;
|
|
10540
|
+
}
|
|
10214
10541
|
async function getObligation(params, db) {
|
|
10215
10542
|
const logger = getLogger();
|
|
10216
10543
|
const result = safeParse("get_obligation", params, (issue) => issue.message);
|
|
10217
10544
|
if (!result.success) return failure(result.error);
|
|
10218
10545
|
const query = result.data;
|
|
10219
10546
|
try {
|
|
10220
|
-
const
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10547
|
+
const listing = await db.readers.obligations.list({
|
|
10548
|
+
ids: [query.obligation_id],
|
|
10549
|
+
limit: 1
|
|
10550
|
+
});
|
|
10551
|
+
if (listing.obligations.length === 0) return failure(new NotFoundError("Obligation not found"));
|
|
10552
|
+
const obligation = listing.obligations[0];
|
|
10224
10553
|
return success({
|
|
10225
|
-
data: from$5(obligation, quote
|
|
10226
|
-
obligationId: id(obligation),
|
|
10227
|
-
ask: { price: 0n },
|
|
10228
|
-
bid: { price: 0n }
|
|
10229
|
-
}),
|
|
10554
|
+
data: from$5(obligation.obligation, obligation.quote),
|
|
10230
10555
|
cursor: null
|
|
10231
10556
|
});
|
|
10232
10557
|
} catch (err) {
|
|
10558
|
+
const payloadError = toPayloadError$1(err);
|
|
10233
10559
|
logger.error({
|
|
10234
|
-
err,
|
|
10560
|
+
err: payloadError,
|
|
10235
10561
|
msg: "Error get obligation",
|
|
10236
|
-
errorMessage:
|
|
10237
|
-
errorStack:
|
|
10562
|
+
errorMessage: payloadError instanceof Error ? payloadError.message : String(payloadError),
|
|
10563
|
+
errorStack: payloadError instanceof Error ? payloadError.stack : void 0
|
|
10238
10564
|
});
|
|
10239
|
-
return failure(
|
|
10565
|
+
return failure(payloadError);
|
|
10240
10566
|
}
|
|
10241
10567
|
}
|
|
10242
10568
|
|
|
10243
10569
|
//#endregion
|
|
10244
10570
|
//#region src/api/Controllers/getObligations.ts
|
|
10571
|
+
function toPayloadError(err) {
|
|
10572
|
+
if (err instanceof BadRequestError) return new BadRequestError$1(err.message);
|
|
10573
|
+
return err;
|
|
10574
|
+
}
|
|
10245
10575
|
async function getObligations(queryParameters, db) {
|
|
10246
10576
|
const logger = getLogger();
|
|
10247
10577
|
const result = safeParse("get_obligations", queryParameters, (issue) => issue.message);
|
|
@@ -10252,31 +10582,28 @@ async function getObligations(queryParameters, db) {
|
|
|
10252
10582
|
const loanTokens = query.loan_tokens?.length ? query.loan_tokens : void 0;
|
|
10253
10583
|
const collateralTokens = query.collateral_tokens?.length ? query.collateral_tokens : void 0;
|
|
10254
10584
|
const maturities = query.maturities?.length ? query.maturities : void 0;
|
|
10255
|
-
const
|
|
10256
|
-
cursor: query.cursor,
|
|
10257
|
-
limit: query.limit,
|
|
10585
|
+
const listing = await db.readers.obligations.list({
|
|
10258
10586
|
chainId: chainIds,
|
|
10259
10587
|
loanToken: loanTokens,
|
|
10260
10588
|
collateralToken: collateralTokens,
|
|
10261
|
-
maturity: maturities
|
|
10589
|
+
maturity: maturities,
|
|
10590
|
+
sort: query.sort,
|
|
10591
|
+
cursor: query.cursor,
|
|
10592
|
+
limit: query.limit
|
|
10262
10593
|
});
|
|
10263
|
-
const quotes = await db.offers.getQuotes({ obligationIds: obligations.map((o) => id(o)) });
|
|
10264
10594
|
return success({
|
|
10265
|
-
data: obligations.map((
|
|
10266
|
-
|
|
10267
|
-
ask: { price: 0n },
|
|
10268
|
-
bid: { price: 0n }
|
|
10269
|
-
})),
|
|
10270
|
-
cursor: nextCursor ?? null
|
|
10595
|
+
data: listing.obligations.map((item) => from$5(item.obligation, item.quote)),
|
|
10596
|
+
cursor: listing.nextCursor
|
|
10271
10597
|
});
|
|
10272
10598
|
} catch (err) {
|
|
10599
|
+
const payloadError = toPayloadError(err);
|
|
10273
10600
|
logger.error({
|
|
10274
|
-
err,
|
|
10601
|
+
err: payloadError,
|
|
10275
10602
|
msg: "Error get obligations",
|
|
10276
|
-
errorMessage:
|
|
10277
|
-
errorStack:
|
|
10603
|
+
errorMessage: payloadError instanceof Error ? payloadError.message : String(payloadError),
|
|
10604
|
+
errorStack: payloadError instanceof Error ? payloadError.stack : void 0
|
|
10278
10605
|
});
|
|
10279
|
-
return failure(
|
|
10606
|
+
return failure(payloadError);
|
|
10280
10607
|
}
|
|
10281
10608
|
}
|
|
10282
10609
|
|
|
@@ -10289,7 +10616,7 @@ async function getObligations(queryParameters, db) {
|
|
|
10289
10616
|
* @returns The offers with pagination cursor.
|
|
10290
10617
|
*/
|
|
10291
10618
|
async function getOffersQuery(db, parameters) {
|
|
10292
|
-
const limit = parameters?.limit ?? DEFAULT_LIMIT$
|
|
10619
|
+
const limit = parameters?.limit ?? DEFAULT_LIMIT$3;
|
|
10293
10620
|
const cursor = parameters?.cursor;
|
|
10294
10621
|
const maker = parameters?.maker;
|
|
10295
10622
|
if (cursor !== null && cursor !== void 0) {
|
|
@@ -10376,6 +10703,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
10376
10703
|
loanToken: obligations.loanToken,
|
|
10377
10704
|
callbackAddress: offers.callbackAddress,
|
|
10378
10705
|
callbackData: offers.callbackData,
|
|
10706
|
+
receiverIfMakerIsSeller: offers.receiverIfMakerIsSeller,
|
|
10379
10707
|
collaterals: collateralsLateral.collaterals,
|
|
10380
10708
|
blockNumber: offers.blockNumber,
|
|
10381
10709
|
available: sql`${availableExpr}::numeric`.as("available"),
|
|
@@ -10397,6 +10725,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
10397
10725
|
)
|
|
10398
10726
|
END
|
|
10399
10727
|
) > 0` : void 0)).orderBy(asc(offers.hash)).limit(limit)).map((row) => {
|
|
10728
|
+
const receiverIfMakerIsSeller = (row.receiverIfMakerIsSeller ?? row.maker).toLowerCase();
|
|
10400
10729
|
return {
|
|
10401
10730
|
hash: row.hash,
|
|
10402
10731
|
maker: row.maker,
|
|
@@ -10421,6 +10750,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
10421
10750
|
address: row.callbackAddress,
|
|
10422
10751
|
data: row.callbackData
|
|
10423
10752
|
},
|
|
10753
|
+
receiverIfMakerIsSeller,
|
|
10424
10754
|
consumed: BigInt(row.consumed),
|
|
10425
10755
|
available: BigInt(String(row.available ?? "0").split(".")[0] ?? "0"),
|
|
10426
10756
|
takeable: BigInt(String(row.takeable ?? "0").split(".")[0] ?? "0"),
|
|
@@ -10734,7 +11064,7 @@ startCmd.description("Start Router services.").addOption(new Option("--mock <n>"
|
|
|
10734
11064
|
let gatekeeperUrl = gatekeeperConfig?.url;
|
|
10735
11065
|
let gatekeeperHandle = null;
|
|
10736
11066
|
if (!gatekeeperUrl) {
|
|
10737
|
-
const gatekeeperCore = create$
|
|
11067
|
+
const gatekeeperCore = create$21({ rules: morphoRules(chainRegistry.list()) });
|
|
10738
11068
|
gatekeeperHandle = await start$1({
|
|
10739
11069
|
gatekeeper: gatekeeperCore,
|
|
10740
11070
|
chainRegistry,
|