@morpho-dev/router 0.7.2 → 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 +834 -334
- 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/0026_add-receiver-if-maker-is-seller.sql +1 -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/0026_snapshot.json +1454 -0
- package/dist/drizzle/migrations/meta/_journal.json +21 -0
- package/dist/evm/bytecode/morpho.txt +1 -1
- package/dist/index.browser.d.mts +206 -77
- package/dist/index.browser.d.mts.map +1 -1
- package/dist/index.browser.d.ts +206 -77
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +445 -197
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +440 -198
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.mts +347 -119
- package/dist/index.node.d.mts.map +1 -1
- package/dist/index.node.d.ts +347 -119
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +865 -312
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +861 -314
- package/dist/index.node.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.node.js
CHANGED
|
@@ -608,7 +608,7 @@ var utils_exports = /* @__PURE__ */ __exportAll({
|
|
|
608
608
|
|
|
609
609
|
//#endregion
|
|
610
610
|
//#region src/indexer/collectors/Admin.ts
|
|
611
|
-
function create$
|
|
611
|
+
function create$21(parameters) {
|
|
612
612
|
const collector = "admin";
|
|
613
613
|
const { client, db, options: { maxBatchSize = 25, maxBlockNumber } = {} } = parameters;
|
|
614
614
|
const maxBlockNumberBI = maxBlockNumber !== void 0 ? BigInt(maxBlockNumber) : void 0;
|
|
@@ -848,8 +848,8 @@ const names = [
|
|
|
848
848
|
"positions",
|
|
849
849
|
"prices"
|
|
850
850
|
];
|
|
851
|
-
function create$
|
|
852
|
-
const admin = create$
|
|
851
|
+
function create$20({ name, collect, client, db, options }) {
|
|
852
|
+
const admin = create$21({
|
|
853
853
|
client,
|
|
854
854
|
db,
|
|
855
855
|
options
|
|
@@ -1015,18 +1015,18 @@ const MorphoV2 = (0, viem.parseAbi)([
|
|
|
1015
1015
|
"function setFeeSetter(address newFeeSetter)",
|
|
1016
1016
|
"function setObligationTradingFee(bytes32 id, uint256 index, uint256 newTradingFee)",
|
|
1017
1017
|
"function setOwner(address newOwner)",
|
|
1018
|
-
"function setTradingFeeRecipient(address
|
|
1018
|
+
"function setTradingFeeRecipient(address feeRecipient)",
|
|
1019
1019
|
"function sharesOf(bytes32 id, address user) view returns (uint256)",
|
|
1020
1020
|
"function shuffleSession()",
|
|
1021
1021
|
"function supplyCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)",
|
|
1022
|
-
"function take(uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, address taker, ((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bool buy, address maker, uint256 assets, uint256 obligationUnits, uint256 obligationShares, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof
|
|
1022
|
+
"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)",
|
|
1023
1023
|
"function totalShares(bytes32 id) view returns (uint256)",
|
|
1024
1024
|
"function totalUnits(bytes32 id) view returns (uint256)",
|
|
1025
1025
|
"function touchObligation((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation) returns (bytes32)",
|
|
1026
1026
|
"function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)",
|
|
1027
1027
|
"function tradingFeeRecipient() view returns (address)",
|
|
1028
|
-
"function withdraw((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, uint256 shares, address onBehalf) returns (uint256, uint256)",
|
|
1029
|
-
"function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)",
|
|
1028
|
+
"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)",
|
|
1029
|
+
"function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf, address receiver)",
|
|
1030
1030
|
"function withdrawable(bytes32 id) view returns (uint256)",
|
|
1031
1031
|
"event Constructor(address indexed owner)",
|
|
1032
1032
|
"event Consume(address indexed user, bytes32 indexed group, uint256 amount)",
|
|
@@ -1038,12 +1038,12 @@ const MorphoV2 = (0, viem.parseAbi)([
|
|
|
1038
1038
|
"event SetFeeSetter(address indexed feeSetter)",
|
|
1039
1039
|
"event SetObligationTradingFee(bytes32 indexed id, uint256 indexed index, uint256 newTradingFee)",
|
|
1040
1040
|
"event SetOwner(address indexed owner)",
|
|
1041
|
-
"event SetTradingFeeRecipient(address indexed
|
|
1041
|
+
"event SetTradingFeeRecipient(address indexed feeRecipient)",
|
|
1042
1042
|
"event ShuffleSession(address indexed user, bytes32 session)",
|
|
1043
1043
|
"event SupplyCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)",
|
|
1044
|
-
"event Take(address caller, bytes32 indexed id, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, bool buyerIsLender, bool sellerIsBorrower, bytes32 group, uint256 consumed)",
|
|
1045
|
-
"event Withdraw(address
|
|
1046
|
-
"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)"
|
|
1044
|
+
"event Take(address caller, bytes32 indexed id, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, bool buyerIsLender, bool sellerIsBorrower, address sellerReceiver, bytes32 group, uint256 consumed)",
|
|
1045
|
+
"event Withdraw(address caller, bytes32 indexed id, uint256 obligationUnits, uint256 shares, address indexed onBehalf, address indexed receiver)",
|
|
1046
|
+
"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf, address receiver)"
|
|
1047
1047
|
]);
|
|
1048
1048
|
|
|
1049
1049
|
//#endregion
|
|
@@ -1315,8 +1315,8 @@ const chains$2 = {
|
|
|
1315
1315
|
name: "ethereum-virtual-testnet",
|
|
1316
1316
|
custom: {
|
|
1317
1317
|
morpho: {
|
|
1318
|
-
address: "
|
|
1319
|
-
blockCreated:
|
|
1318
|
+
address: "0xc9f3c65996fc46b9500608b2c9a9152c01c540f7",
|
|
1319
|
+
blockCreated: 23226871
|
|
1320
1320
|
},
|
|
1321
1321
|
morphoBlue: {
|
|
1322
1322
|
address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
@@ -1462,13 +1462,13 @@ var MissingBlockNumberError = class extends BaseError {
|
|
|
1462
1462
|
|
|
1463
1463
|
//#endregion
|
|
1464
1464
|
//#region src/core/ChainRegistry.ts
|
|
1465
|
-
var ChainRegistry_exports = /* @__PURE__ */ __exportAll({ create: () => create$
|
|
1465
|
+
var ChainRegistry_exports = /* @__PURE__ */ __exportAll({ create: () => create$19 });
|
|
1466
1466
|
/**
|
|
1467
1467
|
* Creates a chain registry from a list of chains.
|
|
1468
1468
|
* @param chains - Array of chain objects to register.
|
|
1469
1469
|
* @returns A registry for looking up chains by ID. {@link ChainRegistry}
|
|
1470
1470
|
*/
|
|
1471
|
-
function create$
|
|
1471
|
+
function create$19(chains) {
|
|
1472
1472
|
const byId = /* @__PURE__ */ new Map();
|
|
1473
1473
|
for (const chain of chains) byId.set(chain.id, chain);
|
|
1474
1474
|
return {
|
|
@@ -2122,7 +2122,7 @@ const OfferSchema = () => {
|
|
|
2122
2122
|
assets: zod.bigint({ coerce: true }).min(0n).max(viem.maxUint256),
|
|
2123
2123
|
obligationUnits: zod.bigint({ coerce: true }).min(0n).max(viem.maxUint256).optional().default(0n),
|
|
2124
2124
|
obligationShares: zod.bigint({ coerce: true }).min(0n).max(viem.maxUint256).optional().default(0n),
|
|
2125
|
-
|
|
2125
|
+
tick: zod.coerce.number().int().min(0).max(990),
|
|
2126
2126
|
maturity: MaturitySchema,
|
|
2127
2127
|
expiry: zod.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
2128
2128
|
start: zod.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
@@ -2143,7 +2143,8 @@ const OfferSchema = () => {
|
|
|
2143
2143
|
callback: zod.object({
|
|
2144
2144
|
address: zod.string().transform(transformAddress),
|
|
2145
2145
|
data: zod.string().transform(transformHex)
|
|
2146
|
-
})
|
|
2146
|
+
}),
|
|
2147
|
+
receiverIfMakerIsSeller: zod.string().transform(transformAddress)
|
|
2147
2148
|
}).refine((data) => data.start < data.expiry, {
|
|
2148
2149
|
message: "start must be before expiry",
|
|
2149
2150
|
path: ["start"]
|
|
@@ -2159,8 +2160,12 @@ const OfferSchema = () => {
|
|
|
2159
2160
|
* @returns The created offer.
|
|
2160
2161
|
*/
|
|
2161
2162
|
function from$14(input) {
|
|
2163
|
+
const normalizedInput = {
|
|
2164
|
+
...input,
|
|
2165
|
+
receiverIfMakerIsSeller: input.receiverIfMakerIsSeller ?? input.maker
|
|
2166
|
+
};
|
|
2162
2167
|
try {
|
|
2163
|
-
return OfferSchema().parse(
|
|
2168
|
+
return OfferSchema().parse(normalizedInput);
|
|
2164
2169
|
} catch (error) {
|
|
2165
2170
|
throw new InvalidOfferError(error);
|
|
2166
2171
|
}
|
|
@@ -2194,7 +2199,7 @@ const serialize = (offer) => ({
|
|
|
2194
2199
|
assets: offer.assets.toString(),
|
|
2195
2200
|
obligationUnits: offer.obligationUnits.toString(),
|
|
2196
2201
|
obligationShares: offer.obligationShares.toString(),
|
|
2197
|
-
|
|
2202
|
+
tick: offer.tick,
|
|
2198
2203
|
maturity: Number(offer.maturity),
|
|
2199
2204
|
expiry: Number(offer.expiry),
|
|
2200
2205
|
start: Number(offer.start),
|
|
@@ -2212,6 +2217,7 @@ const serialize = (offer) => ({
|
|
|
2212
2217
|
address: offer.callback.address,
|
|
2213
2218
|
data: offer.callback.data
|
|
2214
2219
|
},
|
|
2220
|
+
receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller,
|
|
2215
2221
|
hash: hash(offer)
|
|
2216
2222
|
});
|
|
2217
2223
|
/**
|
|
@@ -2239,14 +2245,13 @@ function random$1(config) {
|
|
|
2239
2245
|
[.98, 2]
|
|
2240
2246
|
]));
|
|
2241
2247
|
const buy = config?.buy !== void 0 ? config.buy : bool();
|
|
2242
|
-
const
|
|
2243
|
-
const
|
|
2244
|
-
const
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
return [BigInt(q) * (ONE / 4n), buy ? 1 + idx : 1 + (len - 1 - idx)];
|
|
2248
|
+
const tickMin = buy ? 0 : 495;
|
|
2249
|
+
const len = (buy ? 495 : 990) - tickMin + 1;
|
|
2250
|
+
const tickPairs = Array.from({ length: len }, (_, idx) => {
|
|
2251
|
+
const weight = buy ? 1 + idx : 1 + (len - 1 - idx);
|
|
2252
|
+
return [tickMin + idx, weight];
|
|
2248
2253
|
});
|
|
2249
|
-
const
|
|
2254
|
+
const tick = config?.tick ?? weightedChoice(tickPairs);
|
|
2250
2255
|
const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
|
|
2251
2256
|
const unit = BigInt(10) ** BigInt(loanTokenDecimals);
|
|
2252
2257
|
const amountBase = BigInt(100 + int(999901));
|
|
@@ -2255,12 +2260,13 @@ function random$1(config) {
|
|
|
2255
2260
|
address: viem.zeroAddress,
|
|
2256
2261
|
data: "0x"
|
|
2257
2262
|
};
|
|
2263
|
+
const maker = config?.maker ?? address();
|
|
2258
2264
|
return from$14({
|
|
2259
|
-
maker
|
|
2265
|
+
maker,
|
|
2260
2266
|
assets: assetsScaled,
|
|
2261
2267
|
obligationUnits: config?.obligationUnits ?? 0n,
|
|
2262
2268
|
obligationShares: config?.obligationShares ?? 0n,
|
|
2263
|
-
|
|
2269
|
+
tick,
|
|
2264
2270
|
maturity,
|
|
2265
2271
|
expiry: config?.expiry ?? maturity - 1,
|
|
2266
2272
|
start: config?.start ?? maturity - 10,
|
|
@@ -2273,7 +2279,8 @@ function random$1(config) {
|
|
|
2273
2279
|
...random$3(),
|
|
2274
2280
|
lltv
|
|
2275
2281
|
})).sort((a, b) => a.asset.localeCompare(b.asset)),
|
|
2276
|
-
callback: config?.callback ?? emptyCallback
|
|
2282
|
+
callback: config?.callback ?? emptyCallback,
|
|
2283
|
+
receiverIfMakerIsSeller: config?.receiverIfMakerIsSeller ?? maker
|
|
2277
2284
|
});
|
|
2278
2285
|
}
|
|
2279
2286
|
const weightedChoice = (pairs) => {
|
|
@@ -2325,7 +2332,7 @@ const types = {
|
|
|
2325
2332
|
type: "uint256"
|
|
2326
2333
|
},
|
|
2327
2334
|
{
|
|
2328
|
-
name: "
|
|
2335
|
+
name: "tick",
|
|
2329
2336
|
type: "uint256"
|
|
2330
2337
|
},
|
|
2331
2338
|
{
|
|
@@ -2359,6 +2366,10 @@ const types = {
|
|
|
2359
2366
|
{
|
|
2360
2367
|
name: "callback",
|
|
2361
2368
|
type: "Callback"
|
|
2369
|
+
},
|
|
2370
|
+
{
|
|
2371
|
+
name: "receiverIfMakerIsSeller",
|
|
2372
|
+
type: "address"
|
|
2362
2373
|
}
|
|
2363
2374
|
],
|
|
2364
2375
|
Collateral: [
|
|
@@ -2393,7 +2404,7 @@ function hash(offer) {
|
|
|
2393
2404
|
assets: offer.assets,
|
|
2394
2405
|
obligationUnits: offer.obligationUnits,
|
|
2395
2406
|
obligationShares: offer.obligationShares,
|
|
2396
|
-
|
|
2407
|
+
tick: BigInt(offer.tick),
|
|
2397
2408
|
maturity: BigInt(offer.maturity),
|
|
2398
2409
|
expiry: BigInt(offer.expiry),
|
|
2399
2410
|
group: offer.group,
|
|
@@ -2404,7 +2415,8 @@ function hash(offer) {
|
|
|
2404
2415
|
callback: {
|
|
2405
2416
|
address: offer.callback.address.toLowerCase(),
|
|
2406
2417
|
data: offer.callback.data
|
|
2407
|
-
}
|
|
2418
|
+
},
|
|
2419
|
+
receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller.toLowerCase()
|
|
2408
2420
|
},
|
|
2409
2421
|
primaryType: "Offer",
|
|
2410
2422
|
types
|
|
@@ -2444,7 +2456,7 @@ const OfferAbi = [
|
|
|
2444
2456
|
type: "uint256"
|
|
2445
2457
|
},
|
|
2446
2458
|
{
|
|
2447
|
-
name: "
|
|
2459
|
+
name: "tick",
|
|
2448
2460
|
type: "uint256"
|
|
2449
2461
|
},
|
|
2450
2462
|
{
|
|
@@ -2507,6 +2519,10 @@ const OfferAbi = [
|
|
|
2507
2519
|
name: "data",
|
|
2508
2520
|
type: "bytes"
|
|
2509
2521
|
}]
|
|
2522
|
+
},
|
|
2523
|
+
{
|
|
2524
|
+
name: "receiverIfMakerIsSeller",
|
|
2525
|
+
type: "address"
|
|
2510
2526
|
}
|
|
2511
2527
|
];
|
|
2512
2528
|
function encode$1(offer) {
|
|
@@ -2515,7 +2531,7 @@ function encode$1(offer) {
|
|
|
2515
2531
|
offer.assets,
|
|
2516
2532
|
offer.obligationUnits,
|
|
2517
2533
|
offer.obligationShares,
|
|
2518
|
-
offer.
|
|
2534
|
+
BigInt(offer.tick),
|
|
2519
2535
|
BigInt(offer.maturity),
|
|
2520
2536
|
BigInt(offer.expiry),
|
|
2521
2537
|
offer.group,
|
|
@@ -2525,7 +2541,8 @@ function encode$1(offer) {
|
|
|
2525
2541
|
offer.loanToken,
|
|
2526
2542
|
BigInt(offer.start),
|
|
2527
2543
|
offer.collaterals,
|
|
2528
|
-
offer.callback
|
|
2544
|
+
offer.callback,
|
|
2545
|
+
offer.receiverIfMakerIsSeller
|
|
2529
2546
|
]);
|
|
2530
2547
|
}
|
|
2531
2548
|
function decode$1(data) {
|
|
@@ -2540,7 +2557,7 @@ function decode$1(data) {
|
|
|
2540
2557
|
assets: decoded[1],
|
|
2541
2558
|
obligationUnits: decoded[2],
|
|
2542
2559
|
obligationShares: decoded[3],
|
|
2543
|
-
|
|
2560
|
+
tick: Number(decoded[4]),
|
|
2544
2561
|
maturity: from$16(Number(decoded[5])),
|
|
2545
2562
|
expiry: Number(decoded[6]),
|
|
2546
2563
|
group: decoded[7],
|
|
@@ -2559,7 +2576,8 @@ function decode$1(data) {
|
|
|
2559
2576
|
callback: {
|
|
2560
2577
|
address: decoded[14].address,
|
|
2561
2578
|
data: decoded[14].data
|
|
2562
|
-
}
|
|
2579
|
+
},
|
|
2580
|
+
receiverIfMakerIsSeller: decoded[15]
|
|
2563
2581
|
});
|
|
2564
2582
|
}
|
|
2565
2583
|
/**
|
|
@@ -2635,6 +2653,12 @@ const takeEvent = {
|
|
|
2635
2653
|
indexed: false,
|
|
2636
2654
|
internalType: "bool"
|
|
2637
2655
|
},
|
|
2656
|
+
{
|
|
2657
|
+
name: "sellerReceiver",
|
|
2658
|
+
type: "address",
|
|
2659
|
+
indexed: false,
|
|
2660
|
+
internalType: "address"
|
|
2661
|
+
},
|
|
2638
2662
|
{
|
|
2639
2663
|
name: "group",
|
|
2640
2664
|
type: "bytes32",
|
|
@@ -2820,20 +2844,99 @@ function from$12(parameters) {
|
|
|
2820
2844
|
};
|
|
2821
2845
|
}
|
|
2822
2846
|
|
|
2847
|
+
//#endregion
|
|
2848
|
+
//#region src/core/Tick.ts
|
|
2849
|
+
var Tick_exports = /* @__PURE__ */ __exportAll({
|
|
2850
|
+
InvalidPriceError: () => InvalidPriceError,
|
|
2851
|
+
InvalidTickError: () => InvalidTickError,
|
|
2852
|
+
MAX_PRICE: () => MAX_PRICE,
|
|
2853
|
+
TICK_RANGE: () => TICK_RANGE,
|
|
2854
|
+
priceToTick: () => priceToTick,
|
|
2855
|
+
tickToPrice: () => tickToPrice
|
|
2856
|
+
});
|
|
2857
|
+
/** ln(1 + 0.025), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2858
|
+
const LN_ONE_PLUS_DELTA = 24692612590371501n;
|
|
2859
|
+
/** ln(2), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2860
|
+
const LN2 = 693147180559945309n;
|
|
2861
|
+
const WAD$1 = 10n ** 18n;
|
|
2862
|
+
const WAD_SQUARED = 10n ** 36n;
|
|
2863
|
+
const PRICE_STEP = 10n ** 13n;
|
|
2864
|
+
const HALF_TICK_RANGE = 495n;
|
|
2865
|
+
/** Tick domain supported by Morpho V2. */
|
|
2866
|
+
const TICK_RANGE = 990;
|
|
2867
|
+
/** Max allowed price (1e18 in wad). */
|
|
2868
|
+
const MAX_PRICE = WAD$1;
|
|
2869
|
+
/**
|
|
2870
|
+
* Converts a tick to a wad price using the same approximation and rounding as TickLib.
|
|
2871
|
+
* @param tick - Tick value in the inclusive range [0, 990].
|
|
2872
|
+
* @returns The price in wad units.
|
|
2873
|
+
* @throws {@link InvalidTickError} If tick is not an integer in range [0, 990].
|
|
2874
|
+
*/
|
|
2875
|
+
function tickToPrice(tick) {
|
|
2876
|
+
assertTick(tick);
|
|
2877
|
+
return divHalfDownUnchecked(divHalfDownUnchecked(WAD_SQUARED, WAD$1 + wExp(LN_ONE_PLUS_DELTA * (HALF_TICK_RANGE - BigInt(tick)))), PRICE_STEP) * PRICE_STEP;
|
|
2878
|
+
}
|
|
2879
|
+
/**
|
|
2880
|
+
* Returns the lowest tick with a higher-or-equal price.
|
|
2881
|
+
* @param price - Price in wad units.
|
|
2882
|
+
* @returns The first tick whose {@link tickToPrice} is greater than or equal to `price`.
|
|
2883
|
+
* @throws {@link InvalidPriceError} If price is outside [0, 1e18].
|
|
2884
|
+
*/
|
|
2885
|
+
function priceToTick(price) {
|
|
2886
|
+
assertPrice(price);
|
|
2887
|
+
let low = 0;
|
|
2888
|
+
let high = TICK_RANGE;
|
|
2889
|
+
while (low !== high) {
|
|
2890
|
+
const mid = Math.floor((low + high) / 2);
|
|
2891
|
+
if (tickToPrice(mid) < price) low = mid + 1;
|
|
2892
|
+
else high = mid;
|
|
2893
|
+
}
|
|
2894
|
+
return low;
|
|
2895
|
+
}
|
|
2896
|
+
function divHalfDownUnchecked(x, d) {
|
|
2897
|
+
return (x + (d - 1n) / 2n) / d;
|
|
2898
|
+
}
|
|
2899
|
+
function wExp(x) {
|
|
2900
|
+
if (x < 0n) return WAD_SQUARED / wExp(-x);
|
|
2901
|
+
const q = (x + LN2 / 2n) / LN2;
|
|
2902
|
+
const r = x - q * LN2;
|
|
2903
|
+
const secondTerm = r * r / (2n * WAD$1);
|
|
2904
|
+
const thirdTerm = secondTerm * r / (3n * WAD$1);
|
|
2905
|
+
return WAD$1 + r + secondTerm + thirdTerm << q;
|
|
2906
|
+
}
|
|
2907
|
+
function assertTick(tick) {
|
|
2908
|
+
if (!Number.isInteger(tick) || tick < 0 || tick > TICK_RANGE) throw new InvalidTickError(tick);
|
|
2909
|
+
}
|
|
2910
|
+
function assertPrice(price) {
|
|
2911
|
+
if (price < 0n || price > MAX_PRICE) throw new InvalidPriceError(price);
|
|
2912
|
+
}
|
|
2913
|
+
var InvalidTickError = class extends BaseError {
|
|
2914
|
+
name = "Tick.InvalidTickError";
|
|
2915
|
+
constructor(tick) {
|
|
2916
|
+
super(`Invalid tick: ${tick}. Tick must be an integer between 0 and ${TICK_RANGE}.`);
|
|
2917
|
+
}
|
|
2918
|
+
};
|
|
2919
|
+
var InvalidPriceError = class extends BaseError {
|
|
2920
|
+
name = "Tick.InvalidPriceError";
|
|
2921
|
+
constructor(price) {
|
|
2922
|
+
super(`Invalid price: ${price}. Price must be between 0 and ${MAX_PRICE}.`);
|
|
2923
|
+
}
|
|
2924
|
+
};
|
|
2925
|
+
|
|
2823
2926
|
//#endregion
|
|
2824
2927
|
//#region src/core/Quote.ts
|
|
2825
2928
|
var Quote_exports = /* @__PURE__ */ __exportAll({
|
|
2826
2929
|
InvalidQuoteError: () => InvalidQuoteError,
|
|
2827
|
-
QuoteSchema: () => QuoteSchema,
|
|
2828
2930
|
from: () => from$11,
|
|
2829
2931
|
fromSnakeCase: () => fromSnakeCase,
|
|
2830
2932
|
random: () => random
|
|
2831
2933
|
});
|
|
2832
|
-
const
|
|
2934
|
+
const SideInputSchema = zod.object({ tick: zod.number().int().min(0).max(TICK_RANGE).nullable() }).strict();
|
|
2935
|
+
const QuoteInputSchema = zod.object({
|
|
2833
2936
|
obligationId: zod.string().transform(transformHex),
|
|
2834
|
-
ask:
|
|
2835
|
-
bid:
|
|
2836
|
-
});
|
|
2937
|
+
ask: SideInputSchema,
|
|
2938
|
+
bid: SideInputSchema
|
|
2939
|
+
}).strict();
|
|
2837
2940
|
/**
|
|
2838
2941
|
* Creates a quote for a given obligation.
|
|
2839
2942
|
* @constructor
|
|
@@ -2843,16 +2946,16 @@ const QuoteSchema = zod.object({
|
|
|
2843
2946
|
*
|
|
2844
2947
|
* @example
|
|
2845
2948
|
* ```ts
|
|
2846
|
-
* const quote = Quote.from({ obligationId: "0x123", ask: {
|
|
2949
|
+
* const quote = Quote.from({ obligationId: "0x123", ask: { tick: 500 }, bid: { tick: 510 } });
|
|
2847
2950
|
* ```
|
|
2848
2951
|
*/
|
|
2849
2952
|
function from$11(parameters) {
|
|
2850
2953
|
try {
|
|
2851
|
-
const parsedQuote =
|
|
2954
|
+
const parsedQuote = QuoteInputSchema.parse(parameters);
|
|
2852
2955
|
return {
|
|
2853
2956
|
obligationId: parsedQuote.obligationId,
|
|
2854
|
-
ask: parsedQuote.ask,
|
|
2855
|
-
bid: parsedQuote.bid
|
|
2957
|
+
ask: sideFromTick(parsedQuote.ask),
|
|
2958
|
+
bid: sideFromTick(parsedQuote.bid)
|
|
2856
2959
|
};
|
|
2857
2960
|
} catch (error) {
|
|
2858
2961
|
throw new InvalidQuoteError(error);
|
|
@@ -2879,8 +2982,8 @@ function fromSnakeCase(snake) {
|
|
|
2879
2982
|
function random() {
|
|
2880
2983
|
return from$11({
|
|
2881
2984
|
obligationId: id(random$2()),
|
|
2882
|
-
ask: {
|
|
2883
|
-
bid: {
|
|
2985
|
+
ask: { tick: int(TICK_RANGE + 1) },
|
|
2986
|
+
bid: { tick: int(TICK_RANGE + 1) }
|
|
2884
2987
|
});
|
|
2885
2988
|
}
|
|
2886
2989
|
var InvalidQuoteError = class extends BaseError {
|
|
@@ -2889,6 +2992,12 @@ var InvalidQuoteError = class extends BaseError {
|
|
|
2889
2992
|
super("Invalid quote.", { cause: error });
|
|
2890
2993
|
}
|
|
2891
2994
|
};
|
|
2995
|
+
function sideFromTick(side) {
|
|
2996
|
+
return {
|
|
2997
|
+
tick: side.tick,
|
|
2998
|
+
price: side.tick === null ? 0n : tickToPrice(side.tick)
|
|
2999
|
+
};
|
|
3000
|
+
}
|
|
2892
3001
|
|
|
2893
3002
|
//#endregion
|
|
2894
3003
|
//#region src/core/TradingFee.ts
|
|
@@ -3403,7 +3512,7 @@ const BrandTypeId = Symbol.for("mempool/Brand");
|
|
|
3403
3512
|
|
|
3404
3513
|
//#endregion
|
|
3405
3514
|
//#region src/database/drizzle/VERSION.ts
|
|
3406
|
-
const VERSION = "router_v1.
|
|
3515
|
+
const VERSION = "router_v1.8";
|
|
3407
3516
|
|
|
3408
3517
|
//#endregion
|
|
3409
3518
|
//#region src/database/drizzle/schema.ts
|
|
@@ -3555,10 +3664,7 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
3555
3664
|
precision: 78,
|
|
3556
3665
|
scale: 0
|
|
3557
3666
|
}).notNull().default("0"),
|
|
3558
|
-
|
|
3559
|
-
precision: 78,
|
|
3560
|
-
scale: 0
|
|
3561
|
-
}).notNull(),
|
|
3667
|
+
tick: (0, drizzle_orm_pg_core.integer)("tick").notNull(),
|
|
3562
3668
|
maturity: (0, drizzle_orm_pg_core.integer)("maturity").notNull(),
|
|
3563
3669
|
expiry: (0, drizzle_orm_pg_core.integer)("expiry").notNull(),
|
|
3564
3670
|
start: (0, drizzle_orm_pg_core.integer)("start").notNull(),
|
|
@@ -3569,6 +3675,7 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
3569
3675
|
buy: (0, drizzle_orm_pg_core.boolean)("buy").notNull(),
|
|
3570
3676
|
callbackAddress: (0, drizzle_orm_pg_core.varchar)("callback_address", { length: 42 }).notNull(),
|
|
3571
3677
|
callbackData: (0, drizzle_orm_pg_core.text)("callback_data").notNull(),
|
|
3678
|
+
receiverIfMakerIsSeller: (0, drizzle_orm_pg_core.varchar)("receiver_if_maker_is_seller", { length: 42 }),
|
|
3572
3679
|
blockNumber: (0, drizzle_orm_pg_core.bigint)("block_number", { mode: "number" }).notNull(),
|
|
3573
3680
|
updatedAt: (0, drizzle_orm_pg_core.timestamp)("updated_at").defaultNow().notNull()
|
|
3574
3681
|
}, (table) => [
|
|
@@ -3623,6 +3730,7 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3623
3730
|
user: (0, drizzle_orm_pg_core.varchar)("user", { length: 42 }).notNull(),
|
|
3624
3731
|
contract: (0, drizzle_orm_pg_core.varchar)("contract", { length: 42 }).notNull(),
|
|
3625
3732
|
group: (0, drizzle_orm_pg_core.varchar)("group", { length: 66 }).notNull(),
|
|
3733
|
+
obligationId: (0, drizzle_orm_pg_core.varchar)("obligation_id", { length: 66 }).notNull(),
|
|
3626
3734
|
lower: (0, drizzle_orm_pg_core.numeric)("lower", {
|
|
3627
3735
|
precision: 78,
|
|
3628
3736
|
scale: 0
|
|
@@ -3637,7 +3745,8 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3637
3745
|
table.chainId,
|
|
3638
3746
|
table.user,
|
|
3639
3747
|
table.contract,
|
|
3640
|
-
table.group
|
|
3748
|
+
table.group,
|
|
3749
|
+
table.obligationId
|
|
3641
3750
|
],
|
|
3642
3751
|
name: "lots_pk"
|
|
3643
3752
|
}),
|
|
@@ -3673,6 +3782,7 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3673
3782
|
user: (0, drizzle_orm_pg_core.varchar)("user", { length: 42 }).notNull(),
|
|
3674
3783
|
contract: (0, drizzle_orm_pg_core.varchar)("contract", { length: 42 }).notNull(),
|
|
3675
3784
|
group: (0, drizzle_orm_pg_core.varchar)("group", { length: 66 }).notNull(),
|
|
3785
|
+
obligationId: (0, drizzle_orm_pg_core.varchar)("obligation_id", { length: 66 }).notNull(),
|
|
3676
3786
|
value: (0, drizzle_orm_pg_core.numeric)("value", {
|
|
3677
3787
|
precision: 78,
|
|
3678
3788
|
scale: 0
|
|
@@ -3682,7 +3792,8 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3682
3792
|
table.chainId,
|
|
3683
3793
|
table.user,
|
|
3684
3794
|
table.contract,
|
|
3685
|
-
table.group
|
|
3795
|
+
table.group,
|
|
3796
|
+
table.obligationId
|
|
3686
3797
|
],
|
|
3687
3798
|
name: "offsets_pk"
|
|
3688
3799
|
}), (0, drizzle_orm_pg_core.foreignKey)({
|
|
@@ -4273,6 +4384,7 @@ function decodeCallbacks(parameters) {
|
|
|
4273
4384
|
positionContract: loanToken,
|
|
4274
4385
|
positionUser: offer.maker,
|
|
4275
4386
|
group: offer.group,
|
|
4387
|
+
obligationId: obligationId(offer),
|
|
4276
4388
|
size: offer.assets
|
|
4277
4389
|
});
|
|
4278
4390
|
callbacks.push({
|
|
@@ -4945,7 +5057,7 @@ async function* collectPrices(parameters) {
|
|
|
4945
5057
|
//#region src/indexer/collectors/CollectorBuilder.ts
|
|
4946
5058
|
function createBuilder(parameters) {
|
|
4947
5059
|
const { client, db, gatekeeper, options: { maxBlockNumber, blockWindow, interval } = {} } = parameters;
|
|
4948
|
-
const createCollector = (name, collect) => create$
|
|
5060
|
+
const createCollector = (name, collect) => create$20({
|
|
4949
5061
|
name,
|
|
4950
5062
|
collect,
|
|
4951
5063
|
client,
|
|
@@ -5037,7 +5149,7 @@ const from$7 = (parameters) => {
|
|
|
5037
5149
|
//#endregion
|
|
5038
5150
|
//#region src/indexer/Indexer.ts
|
|
5039
5151
|
var Indexer_exports = /* @__PURE__ */ __exportAll({
|
|
5040
|
-
create: () => create$
|
|
5152
|
+
create: () => create$18,
|
|
5041
5153
|
from: () => from$6
|
|
5042
5154
|
});
|
|
5043
5155
|
function from$6(config) {
|
|
@@ -5053,7 +5165,7 @@ function from$6(config) {
|
|
|
5053
5165
|
retryAttempts,
|
|
5054
5166
|
retryDelayMs
|
|
5055
5167
|
});
|
|
5056
|
-
return create$
|
|
5168
|
+
return create$18({
|
|
5057
5169
|
client,
|
|
5058
5170
|
collectors: [
|
|
5059
5171
|
offersCollector,
|
|
@@ -5063,7 +5175,7 @@ function from$6(config) {
|
|
|
5063
5175
|
]
|
|
5064
5176
|
});
|
|
5065
5177
|
}
|
|
5066
|
-
function create$
|
|
5178
|
+
function create$18(params) {
|
|
5067
5179
|
const { collectors, client } = params;
|
|
5068
5180
|
const indexerId = `${client.chain.id.toString()}.indexer`;
|
|
5069
5181
|
const tracer = getTracer(`router.${indexerId}`);
|
|
@@ -5092,12 +5204,12 @@ function create$17(params) {
|
|
|
5092
5204
|
|
|
5093
5205
|
//#endregion
|
|
5094
5206
|
//#region src/api/Health.ts
|
|
5095
|
-
var Health_exports = /* @__PURE__ */ __exportAll({ create: () => create$
|
|
5207
|
+
var Health_exports = /* @__PURE__ */ __exportAll({ create: () => create$17 });
|
|
5096
5208
|
const DEFAULT_MAX_ALLOWED_LAG = 5;
|
|
5097
5209
|
/**
|
|
5098
5210
|
* Create a health service that exposes collector and chain block numbers.
|
|
5099
5211
|
*/
|
|
5100
|
-
function create$
|
|
5212
|
+
function create$17(parameters) {
|
|
5101
5213
|
const { db, maxAllowedLag = DEFAULT_MAX_ALLOWED_LAG, healthClients, chainRegistry } = parameters;
|
|
5102
5214
|
const loadSnapshot = async () => {
|
|
5103
5215
|
const [collectorRows, chainRows, remoteBlockByChainId] = await Promise.all([
|
|
@@ -5211,8 +5323,10 @@ async function getRemoteBlockNumbers(healthClients) {
|
|
|
5211
5323
|
//#region src/api/Schema/BookResponse.ts
|
|
5212
5324
|
var BookResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$5 });
|
|
5213
5325
|
function from$5(level) {
|
|
5326
|
+
const price = tickToPrice(level.tick);
|
|
5214
5327
|
return {
|
|
5215
|
-
|
|
5328
|
+
tick: level.tick,
|
|
5329
|
+
price: price.toString(),
|
|
5216
5330
|
assets: level.assets.toString(),
|
|
5217
5331
|
count: level.count
|
|
5218
5332
|
};
|
|
@@ -5259,6 +5373,7 @@ var ObligationResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$
|
|
|
5259
5373
|
* Creates an `ObligationResponse` from a `Obligation`.
|
|
5260
5374
|
* @constructor
|
|
5261
5375
|
* @param obligation - {@link Obligation}
|
|
5376
|
+
* @param quote - {@link Quote}
|
|
5262
5377
|
* @returns The created `ObligationResponse`. {@link ObligationResponse}
|
|
5263
5378
|
*/
|
|
5264
5379
|
function from$4(obligation, quote) {
|
|
@@ -5272,8 +5387,14 @@ function from$4(obligation, quote) {
|
|
|
5272
5387
|
oracle: c.oracle
|
|
5273
5388
|
})),
|
|
5274
5389
|
maturity: obligation.maturity,
|
|
5275
|
-
ask: {
|
|
5276
|
-
|
|
5390
|
+
ask: {
|
|
5391
|
+
tick: quote.ask.tick,
|
|
5392
|
+
price: quote.ask.price.toString()
|
|
5393
|
+
},
|
|
5394
|
+
bid: {
|
|
5395
|
+
tick: quote.bid.tick,
|
|
5396
|
+
price: quote.bid.price.toString()
|
|
5397
|
+
}
|
|
5277
5398
|
};
|
|
5278
5399
|
}
|
|
5279
5400
|
|
|
@@ -5317,11 +5438,12 @@ function from$3(input) {
|
|
|
5317
5438
|
obligation_shares: input.obligationShares.toString(),
|
|
5318
5439
|
start: input.start,
|
|
5319
5440
|
expiry: input.expiry,
|
|
5320
|
-
|
|
5441
|
+
tick: input.tick,
|
|
5321
5442
|
group: input.group,
|
|
5322
5443
|
session: input.session,
|
|
5323
5444
|
callback: input.callback.address,
|
|
5324
|
-
callback_data: input.callback.data
|
|
5445
|
+
callback_data: input.callback.data,
|
|
5446
|
+
receiver_if_maker_is_seller: input.receiverIfMakerIsSeller
|
|
5325
5447
|
},
|
|
5326
5448
|
offer_hash: input.hash,
|
|
5327
5449
|
obligation_id: id({
|
|
@@ -5388,7 +5510,7 @@ var InternalServerError = class extends APIError {
|
|
|
5388
5510
|
super(STATUS_CODE.INTERNAL_SERVER_ERROR, message, "INTERNAL_SERVER_ERROR");
|
|
5389
5511
|
}
|
|
5390
5512
|
};
|
|
5391
|
-
var BadRequestError = class extends APIError {
|
|
5513
|
+
var BadRequestError$1 = class extends APIError {
|
|
5392
5514
|
constructor(message = "Invalid JSON format", details) {
|
|
5393
5515
|
super(STATUS_CODE.BAD_REQUEST, message, "BAD_REQUEST", details);
|
|
5394
5516
|
}
|
|
@@ -5410,7 +5532,7 @@ function success(args) {
|
|
|
5410
5532
|
*/
|
|
5411
5533
|
function failure(err) {
|
|
5412
5534
|
if (err instanceof APIError) return handleAPIError(err);
|
|
5413
|
-
if (err instanceof SyntaxError) return handleAPIError(new BadRequestError(err.message));
|
|
5535
|
+
if (err instanceof SyntaxError) return handleAPIError(new BadRequestError$1(err.message));
|
|
5414
5536
|
if (err instanceof zod.ZodError) return handleAPIError(handleZodError(err));
|
|
5415
5537
|
return handleAPIError(new InternalServerError());
|
|
5416
5538
|
}
|
|
@@ -5460,7 +5582,7 @@ function __decorate(decorators, target, key, desc) {
|
|
|
5460
5582
|
//#region src/api/Schema/openapi.ts
|
|
5461
5583
|
const timestampExample = "2024-01-01T12:00:00.000Z";
|
|
5462
5584
|
const offerCursorExample = "eyJvZmZzZXQiOjEwMH0";
|
|
5463
|
-
const obligationCursorExample = "
|
|
5585
|
+
const obligationCursorExample = "eyJzb3J0IjpbImlkIl0sImlkIjoiMHgxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAiLCJhc2siOiIwIiwiYmlkIjoiMCIsIm1hdHVyaXR5IjoxNzYxOTIyODAwfQ";
|
|
5464
5586
|
const offerExample = {
|
|
5465
5587
|
offer: {
|
|
5466
5588
|
obligation: {
|
|
@@ -5479,11 +5601,12 @@ const offerExample = {
|
|
|
5479
5601
|
obligation_shares: "0",
|
|
5480
5602
|
start: 1761922790,
|
|
5481
5603
|
expiry: 1761922799,
|
|
5482
|
-
|
|
5604
|
+
tick: 495,
|
|
5483
5605
|
group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
|
|
5484
5606
|
session: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
5485
5607
|
callback: "0x0000000000000000000000000000000000000000",
|
|
5486
|
-
callback_data: "0x"
|
|
5608
|
+
callback_data: "0x",
|
|
5609
|
+
receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
|
|
5487
5610
|
},
|
|
5488
5611
|
offer_hash: "0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427",
|
|
5489
5612
|
obligation_id: "0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc",
|
|
@@ -5520,7 +5643,7 @@ const validateOfferExample = {
|
|
|
5520
5643
|
assets: "369216000000000000000000",
|
|
5521
5644
|
obligation_units: "0",
|
|
5522
5645
|
obligation_shares: "0",
|
|
5523
|
-
|
|
5646
|
+
tick: 495,
|
|
5524
5647
|
maturity: 1761922799,
|
|
5525
5648
|
expiry: 1761922799,
|
|
5526
5649
|
start: 1761922790,
|
|
@@ -5537,7 +5660,8 @@ const validateOfferExample = {
|
|
|
5537
5660
|
callback: {
|
|
5538
5661
|
address: "0x0000000000000000000000000000000000000000",
|
|
5539
5662
|
data: "0x"
|
|
5540
|
-
}
|
|
5663
|
+
},
|
|
5664
|
+
receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
|
|
5541
5665
|
};
|
|
5542
5666
|
const routerStatusExample = {
|
|
5543
5667
|
status: "live",
|
|
@@ -5608,11 +5732,23 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5608
5732
|
example: validateOfferExample.callback.data
|
|
5609
5733
|
})], ValidateCallbackRequest.prototype, "data", void 0);
|
|
5610
5734
|
var AskResponse = class {};
|
|
5735
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5736
|
+
type: "number",
|
|
5737
|
+
nullable: true,
|
|
5738
|
+
example: 500,
|
|
5739
|
+
description: "Best ask tick. Null when there is no active ask quote."
|
|
5740
|
+
})], AskResponse.prototype, "tick", void 0);
|
|
5611
5741
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5612
5742
|
type: "string",
|
|
5613
5743
|
example: "1000000000000000000"
|
|
5614
5744
|
})], AskResponse.prototype, "price", void 0);
|
|
5615
5745
|
var BidResponse = class {};
|
|
5746
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5747
|
+
type: "number",
|
|
5748
|
+
nullable: true,
|
|
5749
|
+
example: 500,
|
|
5750
|
+
description: "Best bid tick. Null when there is no active bid quote."
|
|
5751
|
+
})], BidResponse.prototype, "tick", void 0);
|
|
5616
5752
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5617
5753
|
type: "string",
|
|
5618
5754
|
example: "1000000000000000000"
|
|
@@ -5664,9 +5800,11 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5664
5800
|
example: offerExample.offer.expiry
|
|
5665
5801
|
})], OfferDataResponse.prototype, "expiry", void 0);
|
|
5666
5802
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5667
|
-
type: "
|
|
5668
|
-
example: offerExample.offer.
|
|
5669
|
-
|
|
5803
|
+
type: "number",
|
|
5804
|
+
example: offerExample.offer.tick,
|
|
5805
|
+
minimum: 0,
|
|
5806
|
+
maximum: 990
|
|
5807
|
+
})], OfferDataResponse.prototype, "tick", void 0);
|
|
5670
5808
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5671
5809
|
type: "string",
|
|
5672
5810
|
example: offerExample.offer.group
|
|
@@ -5683,6 +5821,10 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5683
5821
|
type: "string",
|
|
5684
5822
|
example: offerExample.offer.callback_data
|
|
5685
5823
|
})], OfferDataResponse.prototype, "callback_data", void 0);
|
|
5824
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5825
|
+
type: "string",
|
|
5826
|
+
example: offerExample.offer.receiver_if_maker_is_seller
|
|
5827
|
+
})], OfferDataResponse.prototype, "receiver_if_maker_is_seller", void 0);
|
|
5686
5828
|
var OfferListItemResponse = class {};
|
|
5687
5829
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5688
5830
|
type: () => OfferDataResponse,
|
|
@@ -5907,9 +6049,11 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5907
6049
|
required: false
|
|
5908
6050
|
})], ValidateOfferRequest.prototype, "obligation_shares", void 0);
|
|
5909
6051
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5910
|
-
type: "
|
|
5911
|
-
example: validateOfferExample.
|
|
5912
|
-
|
|
6052
|
+
type: "number",
|
|
6053
|
+
example: validateOfferExample.tick,
|
|
6054
|
+
minimum: 0,
|
|
6055
|
+
maximum: 990
|
|
6056
|
+
})], ValidateOfferRequest.prototype, "tick", void 0);
|
|
5913
6057
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5914
6058
|
type: "number",
|
|
5915
6059
|
example: validateOfferExample.maturity
|
|
@@ -5950,6 +6094,10 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
5950
6094
|
type: () => ValidateCallbackRequest,
|
|
5951
6095
|
example: validateOfferExample.callback
|
|
5952
6096
|
})], ValidateOfferRequest.prototype, "callback", void 0);
|
|
6097
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6098
|
+
type: "string",
|
|
6099
|
+
example: validateOfferExample.receiver_if_maker_is_seller
|
|
6100
|
+
})], ValidateOfferRequest.prototype, "receiver_if_maker_is_seller", void 0);
|
|
5953
6101
|
var ValidateOffersRequest = class {};
|
|
5954
6102
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
5955
6103
|
type: () => [ValidateOfferRequest],
|
|
@@ -6009,9 +6157,16 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
6009
6157
|
description: "List of validation issues. Returned when any offer fails validation."
|
|
6010
6158
|
})], ValidationFailureResponse.prototype, "data", void 0);
|
|
6011
6159
|
var BookLevelResponse = class {};
|
|
6160
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6161
|
+
type: "number",
|
|
6162
|
+
example: 495,
|
|
6163
|
+
minimum: 0,
|
|
6164
|
+
maximum: 990
|
|
6165
|
+
})], BookLevelResponse.prototype, "tick", void 0);
|
|
6012
6166
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6013
6167
|
type: "string",
|
|
6014
|
-
example: "
|
|
6168
|
+
example: "500000000000000000",
|
|
6169
|
+
description: "Price derived from tick, scaled by 1e18."
|
|
6015
6170
|
})], BookLevelResponse.prototype, "price", void 0);
|
|
6016
6171
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6017
6172
|
type: "string",
|
|
@@ -6025,6 +6180,7 @@ const positionExample = {
|
|
|
6025
6180
|
chain_id: 1,
|
|
6026
6181
|
contract: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
|
|
6027
6182
|
user: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
|
|
6183
|
+
obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
|
|
6028
6184
|
reserved: "200000000000000000000",
|
|
6029
6185
|
block_number: 21345678
|
|
6030
6186
|
};
|
|
@@ -6041,6 +6197,12 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
6041
6197
|
type: "string",
|
|
6042
6198
|
example: positionExample.user
|
|
6043
6199
|
})], PositionListItemResponse.prototype, "user", void 0);
|
|
6200
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6201
|
+
type: "string",
|
|
6202
|
+
nullable: true,
|
|
6203
|
+
example: positionExample.obligation_id,
|
|
6204
|
+
description: "Obligation id this reserved amount belongs to, or null if no lots exist."
|
|
6205
|
+
})], PositionListItemResponse.prototype, "obligation_id", void 0);
|
|
6044
6206
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6045
6207
|
type: "string",
|
|
6046
6208
|
example: positionExample.reserved
|
|
@@ -6068,7 +6230,7 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
6068
6230
|
})], BookListResponse.prototype, "cursor", void 0);
|
|
6069
6231
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
6070
6232
|
type: () => [BookLevelResponse],
|
|
6071
|
-
description: "Aggregated book levels grouped by
|
|
6233
|
+
description: "Aggregated book levels grouped by offer tick."
|
|
6072
6234
|
})], BookListResponse.prototype, "data", void 0);
|
|
6073
6235
|
let BooksController = class BooksController {
|
|
6074
6236
|
async getBook() {}
|
|
@@ -6078,7 +6240,7 @@ __decorate([
|
|
|
6078
6240
|
methods: ["get"],
|
|
6079
6241
|
path: "/v1/books/{obligationId}/{side}",
|
|
6080
6242
|
summary: "Get aggregated book",
|
|
6081
|
-
description: "Returns aggregated book data for a given obligation and side. Offers are grouped by
|
|
6243
|
+
description: "Returns aggregated book data for a given obligation and side. Offers are grouped by tick with summed takeable amounts, and each level includes the corresponding wad-scaled price. Book levels are sorted by tick (ascending for sell side, descending for buy side)."
|
|
6082
6244
|
}),
|
|
6083
6245
|
(0, openapi_metadata_decorators.ApiParam)({
|
|
6084
6246
|
name: "obligationId",
|
|
@@ -6103,7 +6265,7 @@ __decorate([
|
|
|
6103
6265
|
name: "limit",
|
|
6104
6266
|
type: "number",
|
|
6105
6267
|
example: 10,
|
|
6106
|
-
description: "Maximum number of
|
|
6268
|
+
description: "Maximum number of tick levels to return."
|
|
6107
6269
|
}),
|
|
6108
6270
|
(0, openapi_metadata_decorators.ApiResponse)({
|
|
6109
6271
|
status: 200,
|
|
@@ -6297,6 +6459,11 @@ const configRulesLoanTokenExample = {
|
|
|
6297
6459
|
chain_id: 1,
|
|
6298
6460
|
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
6299
6461
|
};
|
|
6462
|
+
const configRulesCollateralTokenExample = {
|
|
6463
|
+
type: "collateral_token",
|
|
6464
|
+
chain_id: 1,
|
|
6465
|
+
address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
6466
|
+
};
|
|
6300
6467
|
const configRulesOracleExample = {
|
|
6301
6468
|
type: "oracle",
|
|
6302
6469
|
chain_id: 1,
|
|
@@ -6306,6 +6473,7 @@ const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
|
|
|
6306
6473
|
const configRulesPayloadExample = [
|
|
6307
6474
|
configRulesMaturityExample,
|
|
6308
6475
|
configRulesLoanTokenExample,
|
|
6476
|
+
configRulesCollateralTokenExample,
|
|
6309
6477
|
configRulesOracleExample
|
|
6310
6478
|
];
|
|
6311
6479
|
const configContractNames = [
|
|
@@ -6432,7 +6600,7 @@ __decorate([
|
|
|
6432
6600
|
methods: ["get"],
|
|
6433
6601
|
path: "/v1/config/rules",
|
|
6434
6602
|
summary: "Get config rules",
|
|
6435
|
-
description: "Returns configured rules (maturities, loan tokens, oracles) for supported chains."
|
|
6603
|
+
description: "Returns configured rules (maturities, loan tokens, collateral tokens, oracles) for supported chains."
|
|
6436
6604
|
}),
|
|
6437
6605
|
(0, openapi_metadata_decorators.ApiQuery)({
|
|
6438
6606
|
name: "cursor",
|
|
@@ -6452,7 +6620,7 @@ __decorate([
|
|
|
6452
6620
|
name: "types",
|
|
6453
6621
|
type: ["string"],
|
|
6454
6622
|
required: false,
|
|
6455
|
-
example: "maturity,loan_token,oracle",
|
|
6623
|
+
example: "maturity,loan_token,collateral_token,oracle",
|
|
6456
6624
|
description: "Filter by rule types (comma-separated).",
|
|
6457
6625
|
style: "form",
|
|
6458
6626
|
explode: false
|
|
@@ -6482,13 +6650,13 @@ __decorate([
|
|
|
6482
6650
|
methods: ["get"],
|
|
6483
6651
|
path: "/v1/obligations",
|
|
6484
6652
|
summary: "List all obligations",
|
|
6485
|
-
description: "Returns a list of obligations with their current best ask and bid.
|
|
6653
|
+
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."
|
|
6486
6654
|
}),
|
|
6487
6655
|
(0, openapi_metadata_decorators.ApiQuery)({
|
|
6488
6656
|
name: "cursor",
|
|
6489
6657
|
type: "string",
|
|
6490
6658
|
example: obligationCursorExample,
|
|
6491
|
-
description: "
|
|
6659
|
+
description: "Pagination cursor in base64url-encoded format."
|
|
6492
6660
|
}),
|
|
6493
6661
|
(0, openapi_metadata_decorators.ApiQuery)({
|
|
6494
6662
|
name: "limit",
|
|
@@ -6532,6 +6700,15 @@ __decorate([
|
|
|
6532
6700
|
style: "form",
|
|
6533
6701
|
explode: false
|
|
6534
6702
|
}),
|
|
6703
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
6704
|
+
name: "sort",
|
|
6705
|
+
type: "string",
|
|
6706
|
+
required: false,
|
|
6707
|
+
example: "-ask,bid,maturity",
|
|
6708
|
+
description: "Sort order as comma-separated fields (`id`, `ask`, `bid`, `maturity`). Prefix with `-` for descending order. Max 3 fields.",
|
|
6709
|
+
style: "form",
|
|
6710
|
+
explode: false
|
|
6711
|
+
}),
|
|
6535
6712
|
(0, openapi_metadata_decorators.ApiResponse)({
|
|
6536
6713
|
status: 200,
|
|
6537
6714
|
description: "Success",
|
|
@@ -6570,7 +6747,7 @@ __decorate([
|
|
|
6570
6747
|
methods: ["get"],
|
|
6571
6748
|
path: "/v1/users/{userAddress}/positions",
|
|
6572
6749
|
summary: "Get user positions",
|
|
6573
|
-
description: "Returns positions for a user with reserved balance.
|
|
6750
|
+
description: "Returns positions for a user with reserved balance per obligation. Each (position, obligation) pair is returned as a separate row. Positions with no lots return a single row with obligation_id = null and reserved = 0."
|
|
6574
6751
|
}),
|
|
6575
6752
|
(0, openapi_metadata_decorators.ApiParam)({
|
|
6576
6753
|
name: "userAddress",
|
|
@@ -6658,6 +6835,7 @@ function from$2(position) {
|
|
|
6658
6835
|
chain_id: position.chainId,
|
|
6659
6836
|
contract: position.contract,
|
|
6660
6837
|
user: position.user,
|
|
6838
|
+
obligation_id: position.obligationId,
|
|
6661
6839
|
reserved: position.reserved.toString(),
|
|
6662
6840
|
block_number: position.blockNumber
|
|
6663
6841
|
};
|
|
@@ -6666,11 +6844,13 @@ function from$2(position) {
|
|
|
6666
6844
|
//#endregion
|
|
6667
6845
|
//#region src/api/Schema/requests.ts
|
|
6668
6846
|
const MAX_LIMIT = 100;
|
|
6669
|
-
const DEFAULT_LIMIT$
|
|
6847
|
+
const DEFAULT_LIMIT$5 = 20;
|
|
6848
|
+
const MAX_OBLIGATION_SORT_FIELDS = 3;
|
|
6670
6849
|
const CONFIG_RULES_MAX_LIMIT = 1e3;
|
|
6671
6850
|
const CONFIG_RULES_DEFAULT_LIMIT = 100;
|
|
6672
6851
|
const CONFIG_CONTRACTS_MAX_LIMIT = 1e3;
|
|
6673
6852
|
const CONFIG_CONTRACTS_DEFAULT_LIMIT = 1e3;
|
|
6853
|
+
const OBLIGATION_SORT_ENTRY_REGEX = /^-?(id|ask|bid|maturity)$/;
|
|
6674
6854
|
/** Validate cursor is a valid base64url-encoded JSON object.
|
|
6675
6855
|
* Domain layer handles semantic validation of cursor fields. */
|
|
6676
6856
|
function isValidBase64urlJson(val) {
|
|
@@ -6702,8 +6882,8 @@ const PaginationQueryParams = zod.object({
|
|
|
6702
6882
|
description: "Pagination cursor in base64url-encoded format",
|
|
6703
6883
|
example: "eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ"
|
|
6704
6884
|
}),
|
|
6705
|
-
limit: zod.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(zod.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$
|
|
6706
|
-
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$
|
|
6885
|
+
limit: zod.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(zod.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$5).meta({
|
|
6886
|
+
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$5}`,
|
|
6707
6887
|
example: 10
|
|
6708
6888
|
})
|
|
6709
6889
|
});
|
|
@@ -6711,10 +6891,11 @@ const ConfigRuleTypes = zod.enum([
|
|
|
6711
6891
|
"maturity",
|
|
6712
6892
|
"callback",
|
|
6713
6893
|
"loan_token",
|
|
6894
|
+
"collateral_token",
|
|
6714
6895
|
"oracle"
|
|
6715
6896
|
]);
|
|
6716
6897
|
const GetConfigRulesQueryParams = zod.object({
|
|
6717
|
-
cursor: zod.string().regex(/^(maturity|callback|loan_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
6898
|
+
cursor: zod.string().regex(/^(maturity|callback|loan_token|collateral_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
6718
6899
|
description: "Pagination cursor in type:chain_id:<value> format",
|
|
6719
6900
|
example: "maturity:1:1730415600:end_of_next_month"
|
|
6720
6901
|
}),
|
|
@@ -6724,7 +6905,7 @@ const GetConfigRulesQueryParams = zod.object({
|
|
|
6724
6905
|
}),
|
|
6725
6906
|
types: csvArray(ConfigRuleTypes).meta({
|
|
6726
6907
|
description: "Filter by rule types (comma-separated).",
|
|
6727
|
-
example: "maturity,loan_token,oracle"
|
|
6908
|
+
example: "maturity,loan_token,collateral_token,oracle"
|
|
6728
6909
|
}),
|
|
6729
6910
|
chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
6730
6911
|
description: "Filter by chain IDs (comma-separated).",
|
|
@@ -6799,9 +6980,12 @@ const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend
|
|
|
6799
6980
|
});
|
|
6800
6981
|
const GetObligationsQueryParams = zod.object({
|
|
6801
6982
|
...PaginationQueryParams.shape,
|
|
6802
|
-
cursor: zod.string().optional().
|
|
6803
|
-
|
|
6804
|
-
|
|
6983
|
+
cursor: zod.string().optional().refine((val) => {
|
|
6984
|
+
if (!val) return true;
|
|
6985
|
+
return isValidBase64urlJson(val);
|
|
6986
|
+
}, { message: "Invalid cursor format. Must be a valid base64url-encoded cursor object" }).meta({
|
|
6987
|
+
description: "Pagination cursor in base64url-encoded format.",
|
|
6988
|
+
example: "eyJzb3J0IjpbImlkIl0sImlkIjoiMHgxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAiLCJhc2siOiIwIiwiYmlkIjoiMCIsIm1hdHVyaXR5IjoxNzYxOTIyODAwfQ"
|
|
6805
6989
|
}),
|
|
6806
6990
|
chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
6807
6991
|
description: "Filter by chain IDs (comma-separated).",
|
|
@@ -6818,18 +7002,35 @@ const GetObligationsQueryParams = zod.object({
|
|
|
6818
7002
|
maturities: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Maturity must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
6819
7003
|
description: "Filter by exact maturity timestamps (comma-separated, unix seconds).",
|
|
6820
7004
|
example: "1761922800,1764524800"
|
|
7005
|
+
}),
|
|
7006
|
+
sort: csvArray(zod.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) => {
|
|
7007
|
+
if (!entries) return;
|
|
7008
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7009
|
+
for (const entry of entries) {
|
|
7010
|
+
const field = entry.startsWith("-") ? entry.slice(1) : entry;
|
|
7011
|
+
if (seen.has(field)) {
|
|
7012
|
+
ctx.addIssue({
|
|
7013
|
+
code: "custom",
|
|
7014
|
+
message: `Duplicate sort field: ${field}`
|
|
7015
|
+
});
|
|
7016
|
+
return;
|
|
7017
|
+
}
|
|
7018
|
+
seen.add(field);
|
|
7019
|
+
}
|
|
7020
|
+
}).meta({
|
|
7021
|
+
description: "Sort order as comma-separated fields. Prefix a field with '-' for descending order. Max 3 fields.",
|
|
7022
|
+
example: "-ask,bid,maturity"
|
|
6821
7023
|
})
|
|
6822
7024
|
});
|
|
6823
7025
|
const GetObligationParams = zod.object({ obligation_id: zod.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({
|
|
6824
7026
|
description: "Obligation id",
|
|
6825
7027
|
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
6826
7028
|
}) });
|
|
6827
|
-
/** Validate a book cursor format: {side,
|
|
7029
|
+
/** Validate a book cursor format: {side, lastTick, offersCursor} */
|
|
6828
7030
|
function isValidBookCursor(cursorString) {
|
|
6829
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
6830
7031
|
try {
|
|
6831
7032
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
6832
|
-
return (v?.side === "buy" || v?.side === "sell") &&
|
|
7033
|
+
return (v?.side === "buy" || v?.side === "sell") && typeof v?.lastTick === "number" && Number.isInteger(v.lastTick) && (v?.offersCursor === null || typeof v?.offersCursor === "string");
|
|
6833
7034
|
} catch {
|
|
6834
7035
|
return false;
|
|
6835
7036
|
}
|
|
@@ -6842,8 +7043,8 @@ const BookPaginationQueryParams = zod.object({
|
|
|
6842
7043
|
description: "Pagination cursor in base64url-encoded format for book levels",
|
|
6843
7044
|
example: "eyJzaWRlIjoiYnV5IiwibGFzdFJhdGUiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwib2ZmZXJzQ3Vyc29yIjpudWxsfQ"
|
|
6844
7045
|
}),
|
|
6845
|
-
limit: zod.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(zod.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$
|
|
6846
|
-
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$
|
|
7046
|
+
limit: zod.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(zod.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$5).meta({
|
|
7047
|
+
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$5}`,
|
|
6847
7048
|
example: 10
|
|
6848
7049
|
})
|
|
6849
7050
|
});
|
|
@@ -6927,7 +7128,7 @@ async function getBook(params, db) {
|
|
|
6927
7128
|
side: query.side,
|
|
6928
7129
|
levels_count: levels.length,
|
|
6929
7130
|
has_next_cursor: nextCursor != null,
|
|
6930
|
-
|
|
7131
|
+
first_level_tick: firstLevel?.tick ?? null,
|
|
6931
7132
|
first_level_assets: firstLevel?.assets.toString() ?? null,
|
|
6932
7133
|
first_level_count: firstLevel?.count ?? null
|
|
6933
7134
|
});
|
|
@@ -7020,7 +7221,7 @@ async function getConfigContracts(query, chainRegistry) {
|
|
|
7020
7221
|
}
|
|
7021
7222
|
function parseCursor$1(cursor) {
|
|
7022
7223
|
const [chain, address] = cursor.split(":", 2);
|
|
7023
|
-
if (!chain || !address) throw new BadRequestError("Cursor must be in the format chain_id:0x...");
|
|
7224
|
+
if (!chain || !address) throw new BadRequestError$1("Cursor must be in the format chain_id:0x...");
|
|
7024
7225
|
return {
|
|
7025
7226
|
chain_id: Number.parseInt(chain, 10),
|
|
7026
7227
|
address: address.toLowerCase()
|
|
@@ -7079,6 +7280,33 @@ const assets = {
|
|
|
7079
7280
|
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
7080
7281
|
]
|
|
7081
7282
|
};
|
|
7283
|
+
const collateralAssets = {
|
|
7284
|
+
[ChainId.ETHEREUM.toString()]: [
|
|
7285
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7286
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7287
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7288
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7289
|
+
],
|
|
7290
|
+
[ChainId.BASE.toString()]: [
|
|
7291
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
7292
|
+
"0x4200000000000000000000000000000000000006",
|
|
7293
|
+
"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
|
|
7294
|
+
"0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
|
|
7295
|
+
"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
|
|
7296
|
+
],
|
|
7297
|
+
[ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
|
|
7298
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7299
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7300
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7301
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7302
|
+
],
|
|
7303
|
+
[ChainId.ANVIL.toString()]: [
|
|
7304
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7305
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7306
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7307
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7308
|
+
]
|
|
7309
|
+
};
|
|
7082
7310
|
const oracles = {
|
|
7083
7311
|
[ChainId.ETHEREUM.toString()]: [
|
|
7084
7312
|
"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
|
|
@@ -7119,26 +7347,26 @@ const oracles = {
|
|
|
7119
7347
|
const configs = {
|
|
7120
7348
|
ethereum: {
|
|
7121
7349
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
7122
|
-
maturities: [MaturityType.
|
|
7350
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
7123
7351
|
},
|
|
7124
7352
|
base: {
|
|
7125
7353
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
7126
|
-
maturities: [MaturityType.
|
|
7354
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
7127
7355
|
},
|
|
7128
7356
|
"ethereum-virtual-testnet": {
|
|
7129
7357
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
7130
|
-
maturities: [MaturityType.
|
|
7358
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
7131
7359
|
},
|
|
7132
7360
|
anvil: {
|
|
7133
7361
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
7134
|
-
maturities: [MaturityType.
|
|
7362
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
7135
7363
|
}
|
|
7136
7364
|
};
|
|
7137
7365
|
|
|
7138
7366
|
//#endregion
|
|
7139
7367
|
//#region src/gatekeeper/ConfigRules.ts
|
|
7140
7368
|
/**
|
|
7141
|
-
* Build the configured rules (maturities + callback addresses + loan tokens + oracles) for the provided chains.
|
|
7369
|
+
* Build the configured rules (maturities + callback addresses + loan tokens + collateral tokens + oracles) for the provided chains.
|
|
7142
7370
|
* @param chains - Chains to include in the configured rules.
|
|
7143
7371
|
* @returns Sorted list of config rules.
|
|
7144
7372
|
*/
|
|
@@ -7158,6 +7386,12 @@ function buildConfigRules(chains) {
|
|
|
7158
7386
|
chain_id: chain.id,
|
|
7159
7387
|
address: normalizeAddress(address)
|
|
7160
7388
|
});
|
|
7389
|
+
const collateralTokens = collateralAssets[chain.id.toString()] ?? [];
|
|
7390
|
+
for (const address of collateralTokens) rules.push({
|
|
7391
|
+
type: "collateral_token",
|
|
7392
|
+
chain_id: chain.id,
|
|
7393
|
+
address: normalizeAddress(address)
|
|
7394
|
+
});
|
|
7161
7395
|
const oracles$2 = oracles[chain.id.toString()] ?? [];
|
|
7162
7396
|
for (const address of oracles$2) rules.push({
|
|
7163
7397
|
type: "oracle",
|
|
@@ -7185,6 +7419,10 @@ function buildConfigRulesChecksum(rules) {
|
|
|
7185
7419
|
hash.update(`callback:${rule.chain_id}:${rule.callback_type}:${rule.address}\n`);
|
|
7186
7420
|
continue;
|
|
7187
7421
|
}
|
|
7422
|
+
if (rule.type === "collateral_token") {
|
|
7423
|
+
hash.update(`collateral_token:${rule.chain_id}:${rule.address}\n`);
|
|
7424
|
+
continue;
|
|
7425
|
+
}
|
|
7188
7426
|
if (rule.type === "oracle") {
|
|
7189
7427
|
hash.update(`oracle:${rule.chain_id}:${rule.address}\n`);
|
|
7190
7428
|
continue;
|
|
@@ -7205,6 +7443,7 @@ function compareConfigRules(left, right) {
|
|
|
7205
7443
|
return left.address.localeCompare(right.address);
|
|
7206
7444
|
}
|
|
7207
7445
|
if (left.type === "loan_token" && right.type === "loan_token") return left.address.localeCompare(right.address);
|
|
7446
|
+
if (left.type === "collateral_token" && right.type === "collateral_token") return left.address.localeCompare(right.address);
|
|
7208
7447
|
if (left.type === "oracle" && right.type === "oracle") return left.address.localeCompare(right.address);
|
|
7209
7448
|
return 0;
|
|
7210
7449
|
}
|
|
@@ -7235,8 +7474,8 @@ async function getConfigRules(query, chains) {
|
|
|
7235
7474
|
} catch (err) {
|
|
7236
7475
|
return failure(err);
|
|
7237
7476
|
}
|
|
7238
|
-
if (cursorRule && typeFilter && !typeFilter.has(cursorRule.type)) return failure(new BadRequestError("Cursor type must match requested rule types"));
|
|
7239
|
-
if (cursorRule && chainFilter && !chainFilter.has(cursorRule.chain_id)) return failure(new BadRequestError("Cursor chain_id must match requested chains"));
|
|
7477
|
+
if (cursorRule && typeFilter && !typeFilter.has(cursorRule.type)) return failure(new BadRequestError$1("Cursor type must match requested rule types"));
|
|
7478
|
+
if (cursorRule && chainFilter && !chainFilter.has(cursorRule.chain_id)) return failure(new BadRequestError$1("Cursor chain_id must match requested chains"));
|
|
7240
7479
|
const startIndex = cursorRule ? findStartIndex(filteredRules, cursorRule) : 0;
|
|
7241
7480
|
const page = filteredRules.slice(startIndex, startIndex + limit);
|
|
7242
7481
|
const nextCursor = startIndex + limit < filteredRules.length && page.length > 0 ? formatCursor(page.at(-1)) : null;
|
|
@@ -7251,19 +7490,20 @@ function formatCursor(rule) {
|
|
|
7251
7490
|
if (rule.type === "maturity") return `maturity:${rule.chain_id}:${rule.timestamp}:${rule.name}`;
|
|
7252
7491
|
if (rule.type === "callback") return `callback:${rule.chain_id}:${rule.callback_type}:${rule.address.toLowerCase()}`;
|
|
7253
7492
|
if (rule.type === "oracle") return `oracle:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7493
|
+
if (rule.type === "collateral_token") return `collateral_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7254
7494
|
return `loan_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7255
7495
|
}
|
|
7256
7496
|
function parseCursor(cursor) {
|
|
7257
7497
|
const [type, chain, ...rest] = cursor.split(":");
|
|
7258
|
-
if (!type || !chain || rest.length === 0) throw new BadRequestError("Cursor must be in the format type:chain_id:<value>");
|
|
7259
|
-
if (!isConfigRuleType(type)) throw new BadRequestError("Cursor has an invalid rule type");
|
|
7498
|
+
if (!type || !chain || rest.length === 0) throw new BadRequestError$1("Cursor must be in the format type:chain_id:<value>");
|
|
7499
|
+
if (!isConfigRuleType(type)) throw new BadRequestError$1("Cursor has an invalid rule type");
|
|
7260
7500
|
const chain_id = Number.parseInt(chain, 10);
|
|
7261
|
-
if (!Number.isFinite(chain_id)) throw new BadRequestError("Cursor has an invalid chain_id");
|
|
7501
|
+
if (!Number.isFinite(chain_id)) throw new BadRequestError$1("Cursor has an invalid chain_id");
|
|
7262
7502
|
if (type === "maturity") {
|
|
7263
7503
|
const timestampValue = Number.parseInt(rest[0] ?? "", 10);
|
|
7264
7504
|
const nameValue = rest.slice(1).join(":");
|
|
7265
|
-
if (!Number.isFinite(timestampValue) || nameValue.length === 0) throw new BadRequestError("Cursor must be in the format maturity:chain_id:timestamp:name");
|
|
7266
|
-
if (!isMaturityType(nameValue)) throw new BadRequestError("Cursor has an invalid maturity name");
|
|
7505
|
+
if (!Number.isFinite(timestampValue) || nameValue.length === 0) throw new BadRequestError$1("Cursor must be in the format maturity:chain_id:timestamp:name");
|
|
7506
|
+
if (!isMaturityType(nameValue)) throw new BadRequestError$1("Cursor has an invalid maturity name");
|
|
7267
7507
|
return {
|
|
7268
7508
|
type,
|
|
7269
7509
|
chain_id,
|
|
@@ -7274,8 +7514,8 @@ function parseCursor(cursor) {
|
|
|
7274
7514
|
if (type === "callback") {
|
|
7275
7515
|
const callbackTypeValue = rest[0] ?? "";
|
|
7276
7516
|
const addressValue = rest.slice(1).join(":");
|
|
7277
|
-
if (!callbackTypeValue || !addressValue) throw new BadRequestError("Cursor must be in the format callback:chain_id:callback_type:address");
|
|
7278
|
-
if (!isCallbackType(callbackTypeValue)) throw new BadRequestError("Cursor has an invalid callback type");
|
|
7517
|
+
if (!callbackTypeValue || !addressValue) throw new BadRequestError$1("Cursor must be in the format callback:chain_id:callback_type:address");
|
|
7518
|
+
if (!isCallbackType(callbackTypeValue)) throw new BadRequestError$1("Cursor has an invalid callback type");
|
|
7279
7519
|
return {
|
|
7280
7520
|
type,
|
|
7281
7521
|
chain_id,
|
|
@@ -7283,16 +7523,16 @@ function parseCursor(cursor) {
|
|
|
7283
7523
|
address: parseAddress(addressValue, "Cursor address")
|
|
7284
7524
|
};
|
|
7285
7525
|
}
|
|
7286
|
-
if (type === "loan_token" || type === "oracle") {
|
|
7526
|
+
if (type === "loan_token" || type === "collateral_token" || type === "oracle") {
|
|
7287
7527
|
const addressValue = rest.join(":");
|
|
7288
|
-
if (!addressValue) throw new BadRequestError(`Cursor must be in the format ${type}:chain_id:address`);
|
|
7528
|
+
if (!addressValue) throw new BadRequestError$1(`Cursor must be in the format ${type}:chain_id:address`);
|
|
7289
7529
|
return {
|
|
7290
7530
|
type,
|
|
7291
7531
|
chain_id,
|
|
7292
7532
|
address: parseAddress(addressValue, "Cursor address")
|
|
7293
7533
|
};
|
|
7294
7534
|
}
|
|
7295
|
-
throw new BadRequestError("Cursor has an invalid rule type");
|
|
7535
|
+
throw new BadRequestError$1("Cursor has an invalid rule type");
|
|
7296
7536
|
}
|
|
7297
7537
|
function findStartIndex(rules, cursor) {
|
|
7298
7538
|
let low = 0;
|
|
@@ -7306,11 +7546,11 @@ function findStartIndex(rules, cursor) {
|
|
|
7306
7546
|
return low;
|
|
7307
7547
|
}
|
|
7308
7548
|
function parseAddress(address, label) {
|
|
7309
|
-
if (!/^0x[a-fA-F0-9]{40}$/.test(address)) throw new BadRequestError(`${label} must be a valid 20-byte address`);
|
|
7549
|
+
if (!/^0x[a-fA-F0-9]{40}$/.test(address)) throw new BadRequestError$1(`${label} must be a valid 20-byte address`);
|
|
7310
7550
|
return address.toLowerCase();
|
|
7311
7551
|
}
|
|
7312
7552
|
function isConfigRuleType(value) {
|
|
7313
|
-
return value === "maturity" || value === "callback" || value === "loan_token" || value === "oracle";
|
|
7553
|
+
return value === "maturity" || value === "callback" || value === "loan_token" || value === "collateral_token" || value === "oracle";
|
|
7314
7554
|
}
|
|
7315
7555
|
function isMaturityType(value) {
|
|
7316
7556
|
return Object.values(MaturityType).includes(value);
|
|
@@ -7319,7 +7559,7 @@ function parseMaturity(value) {
|
|
|
7319
7559
|
try {
|
|
7320
7560
|
return from$16(value);
|
|
7321
7561
|
} catch (err) {
|
|
7322
|
-
throw new BadRequestError(err instanceof Error ? err.message : "Invalid maturity timestamp");
|
|
7562
|
+
throw new BadRequestError$1(err instanceof Error ? err.message : "Invalid maturity timestamp");
|
|
7323
7563
|
}
|
|
7324
7564
|
}
|
|
7325
7565
|
function isCallbackType(value) {
|
|
@@ -7415,7 +7655,7 @@ async function getHealth(query, db, chainRegistry) {
|
|
|
7415
7655
|
try {
|
|
7416
7656
|
const parsed = safeParse("get_health", query);
|
|
7417
7657
|
if (!parsed.success) return failure(parsed.error);
|
|
7418
|
-
const snapshot = await create$
|
|
7658
|
+
const snapshot = await create$17({
|
|
7419
7659
|
db,
|
|
7420
7660
|
chainRegistry
|
|
7421
7661
|
}).getSnapshot();
|
|
@@ -7444,7 +7684,7 @@ async function getHealthChains(query, db, healthClients, chainRegistry) {
|
|
|
7444
7684
|
try {
|
|
7445
7685
|
const parsed = safeParse("get_health_chains", query);
|
|
7446
7686
|
if (!parsed.success) return failure(parsed.error);
|
|
7447
|
-
const snapshot = await create$
|
|
7687
|
+
const snapshot = await create$17({
|
|
7448
7688
|
db,
|
|
7449
7689
|
healthClients,
|
|
7450
7690
|
chainRegistry
|
|
@@ -7476,7 +7716,7 @@ async function getHealthCollectors(query, db, chainRegistry) {
|
|
|
7476
7716
|
try {
|
|
7477
7717
|
const parsed = safeParse("get_health_collectors", query);
|
|
7478
7718
|
if (!parsed.success) return failure(parsed.error);
|
|
7479
|
-
const snapshot = await create$
|
|
7719
|
+
const snapshot = await create$17({
|
|
7480
7720
|
db,
|
|
7481
7721
|
chainRegistry
|
|
7482
7722
|
}).getSnapshot();
|
|
@@ -7505,39 +7745,274 @@ async function getHealthCollectors(query, db, chainRegistry) {
|
|
|
7505
7745
|
}
|
|
7506
7746
|
}
|
|
7507
7747
|
|
|
7748
|
+
//#endregion
|
|
7749
|
+
//#region src/database/readers/ObligationsListing.ts
|
|
7750
|
+
const SORT_FIELDS = [
|
|
7751
|
+
"id",
|
|
7752
|
+
"ask",
|
|
7753
|
+
"bid",
|
|
7754
|
+
"maturity"
|
|
7755
|
+
];
|
|
7756
|
+
const CURSOR_ID_REGEX = /^0x[a-f0-9]{64}$/i;
|
|
7757
|
+
const INT32_MIN = -2147483648;
|
|
7758
|
+
const INT32_MAX = 2147483647;
|
|
7759
|
+
const INT32_MAX_BIGINT = BigInt(INT32_MAX);
|
|
7760
|
+
const MAX_CURSOR_SORT_FIELDS = 4;
|
|
7761
|
+
const DEFAULT_LIMIT$4 = 20;
|
|
7762
|
+
var BadRequestError = class extends Error {
|
|
7763
|
+
constructor(message) {
|
|
7764
|
+
super(message);
|
|
7765
|
+
this.name = "ObligationsListingBadRequestError";
|
|
7766
|
+
}
|
|
7767
|
+
};
|
|
7768
|
+
/**
|
|
7769
|
+
* Creates the obligations listing reader facade.
|
|
7770
|
+
* @param parameters - Reader dependencies.
|
|
7771
|
+
* @returns Obligations listing reader.
|
|
7772
|
+
*/
|
|
7773
|
+
function create$16(parameters) {
|
|
7774
|
+
const { db } = parameters;
|
|
7775
|
+
return { list: async (queryParameters) => {
|
|
7776
|
+
const { ids, chainId: chainIds, loanToken: loanTokens, collateralToken: collateralTokens, maturity: maturities, sort: sortTokens, cursor: encodedCursor, limit: requestedLimit } = queryParameters ?? {};
|
|
7777
|
+
const limit = requestedLimit ?? DEFAULT_LIMIT$4;
|
|
7778
|
+
if (!Number.isInteger(limit) || limit <= 0) throw new BadRequestError("Limit must be a positive integer");
|
|
7779
|
+
const cursorPayload = encodedCursor ? decodeCursorPayload(encodedCursor) : void 0;
|
|
7780
|
+
const requestedSort = normalizeSort(sortTokens);
|
|
7781
|
+
const cursorSort = cursorPayload ? normalizeSort(cursorPayload.sort) : void 0;
|
|
7782
|
+
if (cursorSort !== void 0 && sortTokens !== void 0 && !hasSameSort(requestedSort, cursorSort)) throw new BadRequestError("Cursor sort does not match requested sort");
|
|
7783
|
+
const sort = sortTokens !== void 0 ? requestedSort : cursorSort ?? requestedSort;
|
|
7784
|
+
const cursorValues = cursorPayload ? cursorValuesFromPayload(cursorPayload) : void 0;
|
|
7785
|
+
const now$3 = now();
|
|
7786
|
+
const loanTokenFilter = loanTokens !== void 0 && loanTokens.length > 0 ? drizzle_orm.sql`(${drizzle_orm.sql.join(loanTokens.map((token) => drizzle_orm.sql`LOWER(${obligations.loanToken}) = ${token.toLowerCase()}`), drizzle_orm.sql` OR `)})` : void 0;
|
|
7787
|
+
const collateralFilter = collateralTokens !== void 0 && collateralTokens.length > 0 ? drizzle_orm.sql`EXISTS (
|
|
7788
|
+
SELECT 1 FROM ${obligationCollateralsV2} oc
|
|
7789
|
+
WHERE oc.obligation_id = ${obligations.obligationId}
|
|
7790
|
+
AND (${drizzle_orm.sql.join(collateralTokens.map((token) => drizzle_orm.sql`LOWER(oc.asset) = ${token.toLowerCase()}`), drizzle_orm.sql` OR `)})
|
|
7791
|
+
)` : void 0;
|
|
7792
|
+
const bestAskTick = db.select({ askTick: offers.tick }).from(offers).innerJoin(groups, (0, drizzle_orm.and)((0, drizzle_orm.eq)(offers.groupChainId, groups.chainId), (0, drizzle_orm.eq)(offers.groupMaker, groups.maker), (0, drizzle_orm.eq)(offers.group, groups.group))).leftJoin(validations, (0, drizzle_orm.eq)(offers.hash, validations.offerHash)).leftJoin(status, (0, drizzle_orm.eq)(validations.statusId, status.id)).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(offers.obligationId, obligations.obligationId), (0, drizzle_orm.eq)(offers.buy, false), (0, drizzle_orm.gte)(offers.expiry, now$3), (0, drizzle_orm.gte)(offers.maturity, now$3), (0, drizzle_orm.lte)(offers.start, now$3), drizzle_orm.sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy((0, drizzle_orm.desc)(offers.tick)).limit(1).as("best_ask_tick");
|
|
7793
|
+
const bestBidTick = db.select({ bidTick: offers.tick }).from(offers).innerJoin(groups, (0, drizzle_orm.and)((0, drizzle_orm.eq)(offers.groupChainId, groups.chainId), (0, drizzle_orm.eq)(offers.groupMaker, groups.maker), (0, drizzle_orm.eq)(offers.group, groups.group))).leftJoin(validations, (0, drizzle_orm.eq)(offers.hash, validations.offerHash)).leftJoin(status, (0, drizzle_orm.eq)(validations.statusId, status.id)).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(offers.obligationId, obligations.obligationId), (0, drizzle_orm.eq)(offers.buy, true), (0, drizzle_orm.gte)(offers.expiry, now$3), (0, drizzle_orm.gte)(offers.maturity, now$3), (0, drizzle_orm.lte)(offers.start, now$3), drizzle_orm.sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy((0, drizzle_orm.asc)(offers.tick)).limit(1).as("best_bid_tick");
|
|
7794
|
+
const obligationsWithQuotes = db.select({
|
|
7795
|
+
obligationId: obligations.obligationId,
|
|
7796
|
+
chainId: obligations.chainId,
|
|
7797
|
+
loanToken: obligations.loanToken,
|
|
7798
|
+
collaterals: drizzle_orm.sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${oracles$1.address}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
7799
|
+
maturity: obligations.maturity,
|
|
7800
|
+
askTick: drizzle_orm.sql`MAX(${bestAskTick.askTick})`.as("ask_tick"),
|
|
7801
|
+
bidTick: drizzle_orm.sql`MAX(${bestBidTick.bidTick})`.as("bid_tick"),
|
|
7802
|
+
ask: drizzle_orm.sql`COALESCE(MAX(${bestAskTick.askTick}) + 1, 0)`.as("ask"),
|
|
7803
|
+
bid: drizzle_orm.sql`COALESCE(MAX(${bestBidTick.bidTick}) + 1, 0)`.as("bid")
|
|
7804
|
+
}).from(obligations).innerJoin(obligationCollateralsV2, (0, drizzle_orm.eq)(obligations.obligationId, obligationCollateralsV2.obligationId)).innerJoin(oracles$1, drizzle_orm.sql`${obligationCollateralsV2.oracleChainId} = ${oracles$1.chainId}
|
|
7805
|
+
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).leftJoinLateral(bestAskTick, drizzle_orm.sql`true`).leftJoinLateral(bestBidTick, drizzle_orm.sql`true`).groupBy(obligations.obligationId).where((0, drizzle_orm.and)(ids !== void 0 && ids.length > 0 ? (0, drizzle_orm.inArray)(obligations.obligationId, ids) : void 0, chainIds !== void 0 && chainIds.length > 0 ? (0, drizzle_orm.inArray)(obligations.chainId, chainIds) : void 0, loanTokenFilter, maturities !== void 0 && maturities.length > 0 ? (0, drizzle_orm.inArray)(obligations.maturity, maturities) : (0, drizzle_orm.gte)(obligations.maturity, now$3), collateralFilter)).as("obligations_with_quotes");
|
|
7806
|
+
const sortColumns = {
|
|
7807
|
+
id: obligationsWithQuotes.obligationId,
|
|
7808
|
+
ask: obligationsWithQuotes.ask,
|
|
7809
|
+
bid: obligationsWithQuotes.bid,
|
|
7810
|
+
maturity: obligationsWithQuotes.maturity
|
|
7811
|
+
};
|
|
7812
|
+
const rows = await db.select({
|
|
7813
|
+
obligationId: obligationsWithQuotes.obligationId,
|
|
7814
|
+
chainId: obligationsWithQuotes.chainId,
|
|
7815
|
+
loanToken: obligationsWithQuotes.loanToken,
|
|
7816
|
+
collaterals: obligationsWithQuotes.collaterals,
|
|
7817
|
+
maturity: obligationsWithQuotes.maturity,
|
|
7818
|
+
askTick: obligationsWithQuotes.askTick,
|
|
7819
|
+
bidTick: obligationsWithQuotes.bidTick,
|
|
7820
|
+
ask: obligationsWithQuotes.ask,
|
|
7821
|
+
bid: obligationsWithQuotes.bid
|
|
7822
|
+
}).from(obligationsWithQuotes).where(buildCursorFilter(sortColumns, sort, cursorValues)).orderBy(...buildOrderBy(sortColumns, sort)).limit(limit + 1);
|
|
7823
|
+
const hasMore = rows.length > limit;
|
|
7824
|
+
const listedRows = (hasMore ? rows.slice(0, limit) : rows).map((row) => {
|
|
7825
|
+
return {
|
|
7826
|
+
obligation: from$15({
|
|
7827
|
+
chainId: row.chainId,
|
|
7828
|
+
loanToken: row.loanToken,
|
|
7829
|
+
collaterals: row.collaterals.sort((left, right) => left.asset.localeCompare(right.asset)).map((collateral) => from$17({
|
|
7830
|
+
asset: collateral.asset,
|
|
7831
|
+
oracle: collateral.oracle,
|
|
7832
|
+
lltv: from$18(BigInt(collateral.lltv))
|
|
7833
|
+
})),
|
|
7834
|
+
maturity: row.maturity
|
|
7835
|
+
}),
|
|
7836
|
+
quote: from$11({
|
|
7837
|
+
obligationId: row.obligationId,
|
|
7838
|
+
ask: { tick: row.askTick },
|
|
7839
|
+
bid: { tick: row.bidTick }
|
|
7840
|
+
}),
|
|
7841
|
+
cursorValues: {
|
|
7842
|
+
id: row.obligationId,
|
|
7843
|
+
ask: toBigInt(row.ask),
|
|
7844
|
+
bid: toBigInt(row.bid),
|
|
7845
|
+
maturity: row.maturity
|
|
7846
|
+
}
|
|
7847
|
+
};
|
|
7848
|
+
});
|
|
7849
|
+
const nextCursor = hasMore && listedRows.length > 0 ? encodeCursorPayload({
|
|
7850
|
+
sort: sortToTokens(sort),
|
|
7851
|
+
id: listedRows[listedRows.length - 1].cursorValues.id,
|
|
7852
|
+
ask: listedRows[listedRows.length - 1].cursorValues.ask.toString(),
|
|
7853
|
+
bid: listedRows[listedRows.length - 1].cursorValues.bid.toString(),
|
|
7854
|
+
maturity: listedRows[listedRows.length - 1].cursorValues.maturity
|
|
7855
|
+
}) : null;
|
|
7856
|
+
return {
|
|
7857
|
+
obligations: listedRows.map((row) => ({
|
|
7858
|
+
obligation: row.obligation,
|
|
7859
|
+
quote: row.quote
|
|
7860
|
+
})),
|
|
7861
|
+
nextCursor
|
|
7862
|
+
};
|
|
7863
|
+
} };
|
|
7864
|
+
}
|
|
7865
|
+
function isSortField(value) {
|
|
7866
|
+
return SORT_FIELDS.includes(value);
|
|
7867
|
+
}
|
|
7868
|
+
function parseSortToken(token) {
|
|
7869
|
+
const direction = token.startsWith("-") ? "desc" : "asc";
|
|
7870
|
+
const rawField = token.startsWith("-") ? token.slice(1) : token;
|
|
7871
|
+
if (!isSortField(rawField)) throw new BadRequestError(`Invalid sort field: ${rawField}`);
|
|
7872
|
+
return {
|
|
7873
|
+
field: rawField,
|
|
7874
|
+
direction
|
|
7875
|
+
};
|
|
7876
|
+
}
|
|
7877
|
+
function normalizeSort(sortTokens) {
|
|
7878
|
+
const parsed = sortTokens?.length ? sortTokens.map(parseSortToken) : [{
|
|
7879
|
+
field: "id",
|
|
7880
|
+
direction: "asc"
|
|
7881
|
+
}];
|
|
7882
|
+
return parsed.some((entry) => entry.field === "id") ? parsed : [...parsed, {
|
|
7883
|
+
field: "id",
|
|
7884
|
+
direction: "asc"
|
|
7885
|
+
}];
|
|
7886
|
+
}
|
|
7887
|
+
function sortToTokens(sortEntries) {
|
|
7888
|
+
return sortEntries.map((entry) => entry.direction === "desc" ? `-${entry.field}` : entry.field);
|
|
7889
|
+
}
|
|
7890
|
+
function hasSameSort(left, right) {
|
|
7891
|
+
if (left.length !== right.length) return false;
|
|
7892
|
+
return left.every((sortEntry, index) => sortEntry.field === right[index]?.field && sortEntry.direction === right[index]?.direction);
|
|
7893
|
+
}
|
|
7894
|
+
function decodeCursorPayload(cursor) {
|
|
7895
|
+
let decoded;
|
|
7896
|
+
try {
|
|
7897
|
+
decoded = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
7898
|
+
} catch {
|
|
7899
|
+
throw new BadRequestError("Invalid cursor format");
|
|
7900
|
+
}
|
|
7901
|
+
if (decoded === null || typeof decoded !== "object") throw new BadRequestError("Invalid cursor payload");
|
|
7902
|
+
const payload = decoded;
|
|
7903
|
+
const sortTokens = parseCursorSortTokens(payload.sort);
|
|
7904
|
+
if (typeof payload.id !== "string" || !CURSOR_ID_REGEX.test(payload.id)) throw new BadRequestError("Invalid cursor obligation id");
|
|
7905
|
+
const ask = parseCursorNonNegativeInt32(payload.ask, "ask");
|
|
7906
|
+
const bid = parseCursorNonNegativeInt32(payload.bid, "bid");
|
|
7907
|
+
if (!isInt32(payload.maturity)) throw new BadRequestError("Invalid cursor maturity value");
|
|
7908
|
+
return {
|
|
7909
|
+
sort: sortTokens,
|
|
7910
|
+
id: payload.id,
|
|
7911
|
+
ask,
|
|
7912
|
+
bid,
|
|
7913
|
+
maturity: payload.maturity
|
|
7914
|
+
};
|
|
7915
|
+
}
|
|
7916
|
+
function parseCursorSortTokens(value) {
|
|
7917
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > MAX_CURSOR_SORT_FIELDS) throw new BadRequestError("Invalid cursor sort");
|
|
7918
|
+
const sortEntries = value.map((token) => {
|
|
7919
|
+
if (typeof token !== "string") throw new BadRequestError("Invalid cursor sort");
|
|
7920
|
+
try {
|
|
7921
|
+
return parseSortToken(token);
|
|
7922
|
+
} catch {
|
|
7923
|
+
throw new BadRequestError("Invalid cursor sort");
|
|
7924
|
+
}
|
|
7925
|
+
});
|
|
7926
|
+
if (new Set(sortEntries.map((entry) => entry.field)).size !== sortEntries.length) throw new BadRequestError("Invalid cursor sort");
|
|
7927
|
+
return sortToTokens(sortEntries);
|
|
7928
|
+
}
|
|
7929
|
+
function parseCursorNonNegativeInt32(value, field) {
|
|
7930
|
+
if (typeof value !== "string" || !/^\d+$/.test(value)) throw new BadRequestError(`Invalid cursor ${field} value`);
|
|
7931
|
+
if (BigInt(value) > INT32_MAX_BIGINT) throw new BadRequestError(`Invalid cursor ${field} value`);
|
|
7932
|
+
return value;
|
|
7933
|
+
}
|
|
7934
|
+
function isInt32(value) {
|
|
7935
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= INT32_MIN && value <= INT32_MAX;
|
|
7936
|
+
}
|
|
7937
|
+
function encodeCursorPayload(payload) {
|
|
7938
|
+
return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
7939
|
+
}
|
|
7940
|
+
function cursorValuesFromPayload(payload) {
|
|
7941
|
+
return {
|
|
7942
|
+
id: payload.id,
|
|
7943
|
+
ask: BigInt(payload.ask),
|
|
7944
|
+
bid: BigInt(payload.bid),
|
|
7945
|
+
maturity: payload.maturity
|
|
7946
|
+
};
|
|
7947
|
+
}
|
|
7948
|
+
function cursorComparisonValue(cursorValues, field) {
|
|
7949
|
+
switch (field) {
|
|
7950
|
+
case "id": return cursorValues.id;
|
|
7951
|
+
case "maturity": return cursorValues.maturity;
|
|
7952
|
+
case "ask": return cursorValues.ask.toString();
|
|
7953
|
+
case "bid": return cursorValues.bid.toString();
|
|
7954
|
+
}
|
|
7955
|
+
}
|
|
7956
|
+
function buildCursorFilter(columns, sortEntries, cursorValues) {
|
|
7957
|
+
if (cursorValues === void 0) return void 0;
|
|
7958
|
+
const comparisons = sortEntries.map((sortEntry, index) => {
|
|
7959
|
+
const equals = sortEntries.slice(0, index).map((previous) => {
|
|
7960
|
+
return drizzle_orm.sql`${columns[previous.field]} = ${cursorComparisonValue(cursorValues, previous.field)}`;
|
|
7961
|
+
});
|
|
7962
|
+
const comparison = sortEntry.direction === "asc" ? drizzle_orm.sql`${columns[sortEntry.field]} > ${cursorComparisonValue(cursorValues, sortEntry.field)}` : drizzle_orm.sql`${columns[sortEntry.field]} < ${cursorComparisonValue(cursorValues, sortEntry.field)}`;
|
|
7963
|
+
return equals.length > 0 ? drizzle_orm.sql`(${drizzle_orm.sql.join([...equals, comparison], drizzle_orm.sql` AND `)})` : drizzle_orm.sql`(${comparison})`;
|
|
7964
|
+
});
|
|
7965
|
+
return comparisons.length > 0 ? drizzle_orm.sql`(${drizzle_orm.sql.join(comparisons, drizzle_orm.sql` OR `)})` : void 0;
|
|
7966
|
+
}
|
|
7967
|
+
function buildOrderBy(columns, sortEntries) {
|
|
7968
|
+
return sortEntries.map((sortEntry) => sortEntry.direction === "asc" ? (0, drizzle_orm.asc)(columns[sortEntry.field]) : (0, drizzle_orm.desc)(columns[sortEntry.field]));
|
|
7969
|
+
}
|
|
7970
|
+
function toBigInt(value) {
|
|
7971
|
+
if (typeof value === "bigint") return value;
|
|
7972
|
+
if (typeof value === "number") return BigInt(value);
|
|
7973
|
+
return BigInt(value.split(".")[0] ?? "0");
|
|
7974
|
+
}
|
|
7975
|
+
|
|
7508
7976
|
//#endregion
|
|
7509
7977
|
//#region src/api/Controllers/getObligation.ts
|
|
7978
|
+
function toPayloadError$1(err) {
|
|
7979
|
+
if (err instanceof BadRequestError) return new BadRequestError$1(err.message);
|
|
7980
|
+
return err;
|
|
7981
|
+
}
|
|
7510
7982
|
async function getObligation(params, db) {
|
|
7511
7983
|
const logger = getLogger();
|
|
7512
7984
|
const result = safeParse("get_obligation", params, (issue) => issue.message);
|
|
7513
7985
|
if (!result.success) return failure(result.error);
|
|
7514
7986
|
const query = result.data;
|
|
7515
7987
|
try {
|
|
7516
|
-
const
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7988
|
+
const listing = await db.readers.obligations.list({
|
|
7989
|
+
ids: [query.obligation_id],
|
|
7990
|
+
limit: 1
|
|
7991
|
+
});
|
|
7992
|
+
if (listing.obligations.length === 0) return failure(new NotFoundError("Obligation not found"));
|
|
7993
|
+
const obligation = listing.obligations[0];
|
|
7520
7994
|
return success({
|
|
7521
|
-
data: from$4(obligation, quote
|
|
7522
|
-
obligationId: id(obligation),
|
|
7523
|
-
ask: { price: 0n },
|
|
7524
|
-
bid: { price: 0n }
|
|
7525
|
-
}),
|
|
7995
|
+
data: from$4(obligation.obligation, obligation.quote),
|
|
7526
7996
|
cursor: null
|
|
7527
7997
|
});
|
|
7528
7998
|
} catch (err) {
|
|
7999
|
+
const payloadError = toPayloadError$1(err);
|
|
7529
8000
|
logger.error({
|
|
7530
|
-
err,
|
|
8001
|
+
err: payloadError,
|
|
7531
8002
|
msg: "Error get obligation",
|
|
7532
|
-
errorMessage:
|
|
7533
|
-
errorStack:
|
|
8003
|
+
errorMessage: payloadError instanceof Error ? payloadError.message : String(payloadError),
|
|
8004
|
+
errorStack: payloadError instanceof Error ? payloadError.stack : void 0
|
|
7534
8005
|
});
|
|
7535
|
-
return failure(
|
|
8006
|
+
return failure(payloadError);
|
|
7536
8007
|
}
|
|
7537
8008
|
}
|
|
7538
8009
|
|
|
7539
8010
|
//#endregion
|
|
7540
8011
|
//#region src/api/Controllers/getObligations.ts
|
|
8012
|
+
function toPayloadError(err) {
|
|
8013
|
+
if (err instanceof BadRequestError) return new BadRequestError$1(err.message);
|
|
8014
|
+
return err;
|
|
8015
|
+
}
|
|
7541
8016
|
async function getObligations$1(queryParameters, db) {
|
|
7542
8017
|
const logger = getLogger();
|
|
7543
8018
|
const result = safeParse("get_obligations", queryParameters, (issue) => issue.message);
|
|
@@ -7548,31 +8023,28 @@ async function getObligations$1(queryParameters, db) {
|
|
|
7548
8023
|
const loanTokens = query.loan_tokens?.length ? query.loan_tokens : void 0;
|
|
7549
8024
|
const collateralTokens = query.collateral_tokens?.length ? query.collateral_tokens : void 0;
|
|
7550
8025
|
const maturities = query.maturities?.length ? query.maturities : void 0;
|
|
7551
|
-
const
|
|
7552
|
-
cursor: query.cursor,
|
|
7553
|
-
limit: query.limit,
|
|
8026
|
+
const listing = await db.readers.obligations.list({
|
|
7554
8027
|
chainId: chainIds,
|
|
7555
8028
|
loanToken: loanTokens,
|
|
7556
8029
|
collateralToken: collateralTokens,
|
|
7557
|
-
maturity: maturities
|
|
8030
|
+
maturity: maturities,
|
|
8031
|
+
sort: query.sort,
|
|
8032
|
+
cursor: query.cursor,
|
|
8033
|
+
limit: query.limit
|
|
7558
8034
|
});
|
|
7559
|
-
const quotes = await db.offers.getQuotes({ obligationIds: obligations.map((o) => id(o)) });
|
|
7560
8035
|
return success({
|
|
7561
|
-
data: obligations.map((
|
|
7562
|
-
|
|
7563
|
-
ask: { price: 0n },
|
|
7564
|
-
bid: { price: 0n }
|
|
7565
|
-
})),
|
|
7566
|
-
cursor: nextCursor ?? null
|
|
8036
|
+
data: listing.obligations.map((item) => from$4(item.obligation, item.quote)),
|
|
8037
|
+
cursor: listing.nextCursor
|
|
7567
8038
|
});
|
|
7568
8039
|
} catch (err) {
|
|
8040
|
+
const payloadError = toPayloadError(err);
|
|
7569
8041
|
logger.error({
|
|
7570
|
-
err,
|
|
8042
|
+
err: payloadError,
|
|
7571
8043
|
msg: "Error get obligations",
|
|
7572
|
-
errorMessage:
|
|
7573
|
-
errorStack:
|
|
8044
|
+
errorMessage: payloadError instanceof Error ? payloadError.message : String(payloadError),
|
|
8045
|
+
errorStack: payloadError instanceof Error ? payloadError.stack : void 0
|
|
7574
8046
|
});
|
|
7575
|
-
return failure(
|
|
8047
|
+
return failure(payloadError);
|
|
7576
8048
|
}
|
|
7577
8049
|
}
|
|
7578
8050
|
|
|
@@ -7606,6 +8078,7 @@ function create$15(config) {
|
|
|
7606
8078
|
groupMaker: offer.maker.toLowerCase(),
|
|
7607
8079
|
callbackAddress: offer.callback.address.toLowerCase(),
|
|
7608
8080
|
callbackData: offer.callback.data,
|
|
8081
|
+
receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller.toLowerCase(),
|
|
7609
8082
|
blockNumber
|
|
7610
8083
|
})));
|
|
7611
8084
|
if (offersRows.length === 0) return [];
|
|
@@ -7657,7 +8130,7 @@ function create$15(config) {
|
|
|
7657
8130
|
assets: offers.assets,
|
|
7658
8131
|
obligationUnits: offers.obligationUnits,
|
|
7659
8132
|
obligationShares: offers.obligationShares,
|
|
7660
|
-
|
|
8133
|
+
tick: offers.tick,
|
|
7661
8134
|
maturity: offers.maturity,
|
|
7662
8135
|
expiry: offers.expiry,
|
|
7663
8136
|
start: offers.start,
|
|
@@ -7668,16 +8141,18 @@ function create$15(config) {
|
|
|
7668
8141
|
loanToken: obligations.loanToken,
|
|
7669
8142
|
callbackAddress: offers.callbackAddress,
|
|
7670
8143
|
callbackData: offers.callbackData,
|
|
8144
|
+
receiverIfMakerIsSeller: offers.receiverIfMakerIsSeller,
|
|
7671
8145
|
collaterals: collateralsLateral.collaterals,
|
|
7672
8146
|
blockNumber: offers.blockNumber
|
|
7673
8147
|
}).from(offers).innerJoin(obligations, (0, drizzle_orm.eq)(offers.obligationId, obligations.obligationId)).innerJoinLateral(collateralsLateral, drizzle_orm.sql`true`).where((0, drizzle_orm.and)(cursor !== null && cursor !== void 0 ? (0, drizzle_orm.gt)(offers.hash, cursor) : void 0, maker !== void 0 ? (0, drizzle_orm.eq)(offers.groupMaker, maker.toLowerCase()) : void 0)).orderBy((0, drizzle_orm.asc)(offers.hash)).limit(limit)).map((row) => {
|
|
8148
|
+
const receiverIfMakerIsSeller = (row.receiverIfMakerIsSeller ?? row.maker).toLowerCase();
|
|
7674
8149
|
return {
|
|
7675
8150
|
hash: row.hash,
|
|
7676
8151
|
maker: row.maker,
|
|
7677
8152
|
assets: BigInt(row.assets),
|
|
7678
8153
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7679
8154
|
obligationShares: BigInt(row.obligationShares),
|
|
7680
|
-
|
|
8155
|
+
tick: row.tick,
|
|
7681
8156
|
maturity: from$16(row.maturity),
|
|
7682
8157
|
expiry: row.expiry,
|
|
7683
8158
|
start: row.start,
|
|
@@ -7695,6 +8170,7 @@ function create$15(config) {
|
|
|
7695
8170
|
address: row.callbackAddress,
|
|
7696
8171
|
data: row.callbackData
|
|
7697
8172
|
},
|
|
8173
|
+
receiverIfMakerIsSeller,
|
|
7698
8174
|
consumed: 0n,
|
|
7699
8175
|
available: 0n,
|
|
7700
8176
|
takeable: 0n,
|
|
@@ -7719,64 +8195,30 @@ function create$15(config) {
|
|
|
7719
8195
|
}
|
|
7720
8196
|
throw new Error("Invalid parameters");
|
|
7721
8197
|
},
|
|
7722
|
-
getObligations: async (parameters) => {
|
|
7723
|
-
const { ids, chainId: chainIds, loanToken: loanTokens, collateralToken: collateralTokens, maturity: maturities, cursor, limit = DEFAULT_LIMIT$3 } = parameters ?? {};
|
|
7724
|
-
const now$1 = now();
|
|
7725
|
-
const loanTokenFilter = loanTokens !== void 0 && loanTokens.length > 0 ? drizzle_orm.sql`(${drizzle_orm.sql.join(loanTokens.map((token) => drizzle_orm.sql`LOWER(${obligations.loanToken}) = ${token.toLowerCase()}`), drizzle_orm.sql` OR `)})` : void 0;
|
|
7726
|
-
const collateralFilter = collateralTokens !== void 0 && collateralTokens.length > 0 ? drizzle_orm.sql`EXISTS (
|
|
7727
|
-
SELECT 1 FROM ${obligationCollateralsV2} oc
|
|
7728
|
-
WHERE oc.obligation_id = ${obligations.obligationId}
|
|
7729
|
-
AND (${drizzle_orm.sql.join(collateralTokens.map((token) => drizzle_orm.sql`LOWER(oc.asset) = ${token.toLowerCase()}`), drizzle_orm.sql` OR `)})
|
|
7730
|
-
)` : void 0;
|
|
7731
|
-
const result = await db.select({
|
|
7732
|
-
obligationId: obligations.obligationId,
|
|
7733
|
-
chainId: obligations.chainId,
|
|
7734
|
-
loanToken: obligations.loanToken,
|
|
7735
|
-
collaterals: drizzle_orm.sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${oracles$1.address}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
7736
|
-
maturity: obligations.maturity
|
|
7737
|
-
}).from(obligations).innerJoin(obligationCollateralsV2, (0, drizzle_orm.eq)(obligations.obligationId, obligationCollateralsV2.obligationId)).innerJoin(oracles$1, drizzle_orm.sql`${obligationCollateralsV2.oracleChainId} = ${oracles$1.chainId}
|
|
7738
|
-
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).groupBy(obligations.obligationId).where((0, drizzle_orm.and)(cursor !== null && cursor !== void 0 ? (0, drizzle_orm.gt)(obligations.obligationId, cursor) : drizzle_orm.sql`true`, ids !== void 0 && ids.length > 0 ? (0, drizzle_orm.inArray)(obligations.obligationId, ids) : void 0, chainIds !== void 0 && chainIds.length > 0 ? (0, drizzle_orm.inArray)(obligations.chainId, chainIds) : void 0, loanTokenFilter, maturities !== void 0 && maturities.length > 0 ? (0, drizzle_orm.inArray)(obligations.maturity, maturities) : (0, drizzle_orm.gte)(obligations.maturity, now$1), collateralFilter)).orderBy((0, drizzle_orm.asc)(obligations.obligationId)).limit(limit);
|
|
7739
|
-
const items = [];
|
|
7740
|
-
for (const row of result) items.push(from$15({
|
|
7741
|
-
chainId: row.chainId,
|
|
7742
|
-
loanToken: row.loanToken,
|
|
7743
|
-
collaterals: row.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)).map((c) => from$17({
|
|
7744
|
-
asset: c.asset,
|
|
7745
|
-
oracle: c.oracle,
|
|
7746
|
-
lltv: from$18(BigInt(c.lltv))
|
|
7747
|
-
})),
|
|
7748
|
-
maturity: row.maturity
|
|
7749
|
-
}));
|
|
7750
|
-
const returnedItems = Array.from(items.values());
|
|
7751
|
-
return {
|
|
7752
|
-
obligations: returnedItems,
|
|
7753
|
-
nextCursor: returnedItems.length === limit && returnedItems.length > 0 ? result[result.length - 1].obligationId : null
|
|
7754
|
-
};
|
|
7755
|
-
},
|
|
7756
8198
|
getQuotes: async (parameters) => {
|
|
7757
8199
|
const { obligationIds } = parameters;
|
|
7758
8200
|
if (obligationIds.length === 0) return [];
|
|
7759
8201
|
const now$2 = now();
|
|
7760
8202
|
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
7761
8203
|
obligationId: offers.obligationId,
|
|
7762
|
-
|
|
7763
|
-
}).from(offers).innerJoin(groups, (0, drizzle_orm.and)((0, drizzle_orm.eq)(offers.groupChainId, groups.chainId), (0, drizzle_orm.eq)(offers.groupMaker, groups.maker), (0, drizzle_orm.eq)(offers.group, groups.group))).leftJoin(validations, (0, drizzle_orm.eq)(offers.hash, validations.offerHash)).leftJoin(status, (0, drizzle_orm.eq)(validations.statusId, status.id)).where((0, drizzle_orm.and)((0, drizzle_orm.inArray)(offers.obligationId, obligationIds), (0, drizzle_orm.eq)(offers.buy, side === "buy"), (0, drizzle_orm.gte)(offers.expiry, now$2), (0, drizzle_orm.gte)(offers.maturity, now$2), (0, drizzle_orm.lte)(offers.start, now$2), drizzle_orm.sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? drizzle_orm.sql`${offers.
|
|
8204
|
+
tick: offers.tick
|
|
8205
|
+
}).from(offers).innerJoin(groups, (0, drizzle_orm.and)((0, drizzle_orm.eq)(offers.groupChainId, groups.chainId), (0, drizzle_orm.eq)(offers.groupMaker, groups.maker), (0, drizzle_orm.eq)(offers.group, groups.group))).leftJoin(validations, (0, drizzle_orm.eq)(offers.hash, validations.offerHash)).leftJoin(status, (0, drizzle_orm.eq)(validations.statusId, status.id)).where((0, drizzle_orm.and)((0, drizzle_orm.inArray)(offers.obligationId, obligationIds), (0, drizzle_orm.eq)(offers.buy, side === "buy"), (0, drizzle_orm.gte)(offers.expiry, now$2), (0, drizzle_orm.gte)(offers.maturity, now$2), (0, drizzle_orm.lte)(offers.start, now$2), drizzle_orm.sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? drizzle_orm.sql`${offers.tick} ASC` : drizzle_orm.sql`${offers.tick} DESC`);
|
|
7764
8206
|
const [bestBuys, bestSells] = await Promise.all([query({ side: "buy" }), query({ side: "sell" })]);
|
|
7765
8207
|
const quotes = /* @__PURE__ */ new Map();
|
|
7766
8208
|
for (const row of bestSells) quotes.set(row.obligationId, {
|
|
7767
|
-
ask: {
|
|
7768
|
-
bid: {
|
|
8209
|
+
ask: { tick: row.tick },
|
|
8210
|
+
bid: { tick: null }
|
|
7769
8211
|
});
|
|
7770
8212
|
for (const row of bestBuys) {
|
|
7771
8213
|
const quote = quotes.get(row.obligationId);
|
|
7772
8214
|
if (!quote) {
|
|
7773
8215
|
quotes.set(row.obligationId, {
|
|
7774
|
-
ask: {
|
|
7775
|
-
bid: {
|
|
8216
|
+
ask: { tick: null },
|
|
8217
|
+
bid: { tick: row.tick }
|
|
7776
8218
|
});
|
|
7777
8219
|
continue;
|
|
7778
8220
|
}
|
|
7779
|
-
quote.bid = {
|
|
8221
|
+
quote.bid = { tick: row.tick };
|
|
7780
8222
|
}
|
|
7781
8223
|
return Array.from(quotes.entries()).map(([id, quote]) => {
|
|
7782
8224
|
return from$11({
|
|
@@ -7876,7 +8318,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7876
8318
|
obligationUnits: offers.obligationUnits,
|
|
7877
8319
|
obligationShares: offers.obligationShares,
|
|
7878
8320
|
consumed: groups.consumed,
|
|
7879
|
-
|
|
8321
|
+
tick: offers.tick,
|
|
7880
8322
|
maturity: offers.maturity,
|
|
7881
8323
|
expiry: offers.expiry,
|
|
7882
8324
|
start: offers.start,
|
|
@@ -7887,6 +8329,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7887
8329
|
loanToken: obligations.loanToken,
|
|
7888
8330
|
callbackAddress: offers.callbackAddress,
|
|
7889
8331
|
callbackData: offers.callbackData,
|
|
8332
|
+
receiverIfMakerIsSeller: offers.receiverIfMakerIsSeller,
|
|
7890
8333
|
collaterals: collateralsLateral.collaterals,
|
|
7891
8334
|
blockNumber: offers.blockNumber,
|
|
7892
8335
|
available: drizzle_orm.sql`${availableExpr}::numeric`.as("available"),
|
|
@@ -7908,13 +8351,14 @@ async function getOffersQuery(db, parameters) {
|
|
|
7908
8351
|
)
|
|
7909
8352
|
END
|
|
7910
8353
|
) > 0` : void 0)).orderBy((0, drizzle_orm.asc)(offers.hash)).limit(limit)).map((row) => {
|
|
8354
|
+
const receiverIfMakerIsSeller = (row.receiverIfMakerIsSeller ?? row.maker).toLowerCase();
|
|
7911
8355
|
return {
|
|
7912
8356
|
hash: row.hash,
|
|
7913
8357
|
maker: row.maker,
|
|
7914
8358
|
assets: BigInt(row.assets),
|
|
7915
8359
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7916
8360
|
obligationShares: BigInt(row.obligationShares),
|
|
7917
|
-
|
|
8361
|
+
tick: row.tick,
|
|
7918
8362
|
maturity: from$16(row.maturity),
|
|
7919
8363
|
expiry: row.expiry,
|
|
7920
8364
|
start: row.start,
|
|
@@ -7932,6 +8376,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7932
8376
|
address: row.callbackAddress,
|
|
7933
8377
|
data: row.callbackData
|
|
7934
8378
|
},
|
|
8379
|
+
receiverIfMakerIsSeller,
|
|
7935
8380
|
consumed: BigInt(row.consumed),
|
|
7936
8381
|
available: BigInt(String(row.available ?? "0").split(".")[0] ?? "0"),
|
|
7937
8382
|
takeable: BigInt(String(row.takeable ?? "0").split(".")[0] ?? "0"),
|
|
@@ -8022,7 +8467,7 @@ async function getUserPositions(queryParameters, db) {
|
|
|
8022
8467
|
async function validateOffers(body, gatekeeper) {
|
|
8023
8468
|
const logger = getLogger();
|
|
8024
8469
|
const result = safeParse("validate_offers", body, (issue) => issue.message);
|
|
8025
|
-
if (!result.success) return failure(new BadRequestError(result.error.issues[0]?.message ?? "Invalid request body"));
|
|
8470
|
+
if (!result.success) return failure(new BadRequestError$1(result.error.issues[0]?.message ?? "Invalid request body"));
|
|
8026
8471
|
const { offers: rawOffers } = result.data;
|
|
8027
8472
|
const parsedOffers = [];
|
|
8028
8473
|
const offerIndexByHash = /* @__PURE__ */ new Map();
|
|
@@ -8038,7 +8483,7 @@ async function validateOffers(body, gatekeeper) {
|
|
|
8038
8483
|
} catch (err) {
|
|
8039
8484
|
let message = err instanceof Error ? err.message : String(err);
|
|
8040
8485
|
if (err instanceof InvalidOfferError) message = err.formattedMessage;
|
|
8041
|
-
return failure(new BadRequestError(`Offer at index ${i} failed to parse: ${message}`));
|
|
8486
|
+
return failure(new BadRequestError$1(`Offer at index ${i} failed to parse: ${message}`));
|
|
8042
8487
|
}
|
|
8043
8488
|
}
|
|
8044
8489
|
try {
|
|
@@ -8313,7 +8758,7 @@ async function getOffers(apiClient, parameters) {
|
|
|
8313
8758
|
assets: offerData.assets,
|
|
8314
8759
|
obligation_units: offerData.obligation_units,
|
|
8315
8760
|
obligation_shares: offerData.obligation_shares,
|
|
8316
|
-
|
|
8761
|
+
tick: offerData.tick,
|
|
8317
8762
|
maturity: from$16(offerData.obligation.maturity),
|
|
8318
8763
|
expiry: offerData.expiry,
|
|
8319
8764
|
start: offerData.start,
|
|
@@ -8330,7 +8775,8 @@ async function getOffers(apiClient, parameters) {
|
|
|
8330
8775
|
callback: {
|
|
8331
8776
|
address: offerData.callback,
|
|
8332
8777
|
data: offerData.callback_data
|
|
8333
|
-
}
|
|
8778
|
+
},
|
|
8779
|
+
receiver_if_maker_is_seller: offerData.receiver_if_maker_is_seller
|
|
8334
8780
|
}),
|
|
8335
8781
|
hash: item.offer_hash,
|
|
8336
8782
|
consumed: BigInt(item.consumed),
|
|
@@ -8347,13 +8793,15 @@ async function getOffers(apiClient, parameters) {
|
|
|
8347
8793
|
};
|
|
8348
8794
|
}
|
|
8349
8795
|
async function getObligations(apiClient, parameters) {
|
|
8796
|
+
const sort = parameters?.sort?.length ? parameters.sort.join(",") : void 0;
|
|
8350
8797
|
const { data, error, response } = await apiClient.GET("/v1/obligations", { params: { query: {
|
|
8351
8798
|
cursor: parameters?.cursor,
|
|
8352
8799
|
limit: parameters?.limit,
|
|
8353
8800
|
chains: parameters?.chainIds,
|
|
8354
8801
|
loan_tokens: parameters?.loanTokens,
|
|
8355
8802
|
collateral_tokens: parameters?.collateralTokens,
|
|
8356
|
-
maturities: parameters?.maturities
|
|
8803
|
+
maturities: parameters?.maturities,
|
|
8804
|
+
sort
|
|
8357
8805
|
} } });
|
|
8358
8806
|
if (error !== void 0) {
|
|
8359
8807
|
switch (response.status) {
|
|
@@ -8377,10 +8825,10 @@ async function getObligations(apiClient, parameters) {
|
|
|
8377
8825
|
const { obligationId: _, ...returned } = {
|
|
8378
8826
|
id: () => id(obligation),
|
|
8379
8827
|
...obligation,
|
|
8380
|
-
...
|
|
8381
|
-
|
|
8382
|
-
ask: item.ask,
|
|
8383
|
-
bid: item.bid
|
|
8828
|
+
...from$11({
|
|
8829
|
+
obligationId: item.id,
|
|
8830
|
+
ask: { tick: item.ask.tick },
|
|
8831
|
+
bid: { tick: item.bid.tick }
|
|
8384
8832
|
})
|
|
8385
8833
|
};
|
|
8386
8834
|
return returned;
|
|
@@ -8672,6 +9120,7 @@ function create$12(config) {
|
|
|
8672
9120
|
return {
|
|
8673
9121
|
get: async (parameters) => {
|
|
8674
9122
|
const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT$2 } = parameters;
|
|
9123
|
+
const tickSortDirection = side === "sell" ? "asc" : "desc";
|
|
8675
9124
|
const inputCursor = LevelCursor.decode(cursorString, logger);
|
|
8676
9125
|
if (cursorString != null && inputCursor === null) return {
|
|
8677
9126
|
levels: [],
|
|
@@ -8686,23 +9135,23 @@ function create$12(config) {
|
|
|
8686
9135
|
cursor: inputCursor?.offersCursor ?? void 0,
|
|
8687
9136
|
limit: fetchLimit
|
|
8688
9137
|
});
|
|
8689
|
-
const
|
|
9138
|
+
const tickMap = /* @__PURE__ */ new Map();
|
|
8690
9139
|
for (const row of rows) {
|
|
8691
|
-
const
|
|
8692
|
-
const existing = priceMap.get(priceKey);
|
|
9140
|
+
const existing = tickMap.get(row.tick);
|
|
8693
9141
|
if (existing) {
|
|
8694
9142
|
existing.assets += row.takeable;
|
|
8695
9143
|
existing.count += 1;
|
|
8696
|
-
} else
|
|
9144
|
+
} else tickMap.set(row.tick, {
|
|
8697
9145
|
assets: row.takeable,
|
|
8698
9146
|
count: 1
|
|
8699
9147
|
});
|
|
8700
9148
|
}
|
|
8701
|
-
const levels = Array.from(
|
|
8702
|
-
|
|
8703
|
-
assets:
|
|
8704
|
-
count:
|
|
9149
|
+
const levels = Array.from(tickMap.entries()).map(([tick, level]) => ({
|
|
9150
|
+
tick,
|
|
9151
|
+
assets: level.assets,
|
|
9152
|
+
count: level.count
|
|
8705
9153
|
}));
|
|
9154
|
+
levels.sort((a, b) => tickSortDirection === "asc" ? a.tick - b.tick : b.tick - a.tick);
|
|
8706
9155
|
const paginatedLevels = levels.slice(0, limit);
|
|
8707
9156
|
const hasMore = levels.length > limit || offersNextCursor !== null;
|
|
8708
9157
|
const lastLevel = paginatedLevels[paginatedLevels.length - 1];
|
|
@@ -8748,14 +9197,14 @@ async function _getOffers(db, params) {
|
|
|
8748
9197
|
AND (s.code IS NULL OR s.code = ${Status.VALID})
|
|
8749
9198
|
ORDER BY
|
|
8750
9199
|
o.group_chain_id, o.group_maker, o."group_group",
|
|
8751
|
-
o.
|
|
9200
|
+
o.tick ${priceSortDirection === "asc" ? drizzle_orm.sql`ASC` : drizzle_orm.sql`DESC`}, o.block_number ASC, o.assets DESC, o.hash ASC
|
|
8752
9201
|
),
|
|
8753
9202
|
enriched AS (
|
|
8754
9203
|
SELECT
|
|
8755
9204
|
w.*,
|
|
8756
9205
|
g.consumed, g.chain_id, obl.loan_token,
|
|
8757
9206
|
CASE WHEN ${priceSortDirection === "asc" ? drizzle_orm.sql`TRUE` : drizzle_orm.sql`FALSE`}
|
|
8758
|
-
THEN w.
|
|
9207
|
+
THEN w.tick ELSE -w.tick END AS tick_norm,
|
|
8759
9208
|
w.block_number AS block_norm,
|
|
8760
9209
|
-w.assets AS assets_norm,
|
|
8761
9210
|
w.hash AS hash_norm
|
|
@@ -8772,33 +9221,35 @@ async function _getOffers(db, params) {
|
|
|
8772
9221
|
FROM enriched e
|
|
8773
9222
|
${cursor != null ? drizzle_orm.sql`
|
|
8774
9223
|
WHERE
|
|
8775
|
-
(e.
|
|
9224
|
+
(e.tick_norm, e.block_norm, e.assets_norm, e.hash_norm)
|
|
8776
9225
|
> (
|
|
8777
9226
|
CASE WHEN ${priceSortDirection === "asc" ? drizzle_orm.sql`TRUE` : drizzle_orm.sql`FALSE`}
|
|
8778
|
-
THEN ${cursor.
|
|
9227
|
+
THEN ${cursor.tick}::integer ELSE -${cursor.tick}::integer END,
|
|
8779
9228
|
${cursor.blockNumber},
|
|
8780
9229
|
-${cursor.assets}::numeric,
|
|
8781
9230
|
${cursor.hash}
|
|
8782
9231
|
)` : drizzle_orm.sql``}
|
|
8783
|
-
ORDER BY e.
|
|
9232
|
+
ORDER BY e.tick ${priceSortDirection === "asc" ? drizzle_orm.sql`ASC` : drizzle_orm.sql`DESC`}, e.block_number ASC, e.assets DESC, e.hash ASC
|
|
8784
9233
|
LIMIT ${limit}
|
|
8785
9234
|
),
|
|
8786
|
-
-- Compute sum of offsets per position
|
|
9235
|
+
-- Compute sum of offsets per position and obligation
|
|
8787
9236
|
position_offsets AS (
|
|
8788
9237
|
SELECT
|
|
8789
9238
|
chain_id,
|
|
8790
9239
|
"user",
|
|
8791
9240
|
contract,
|
|
9241
|
+
obligation_id,
|
|
8792
9242
|
SUM(value::numeric) AS total_offset
|
|
8793
9243
|
FROM ${offsets}
|
|
8794
|
-
GROUP BY chain_id, "user", contract
|
|
9244
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
8795
9245
|
),
|
|
8796
|
-
-- Compute position_consumed: sum of consumed from all groups with lots on each position (converted to lot terms)
|
|
9246
|
+
-- Compute position_consumed: sum of consumed from all groups with lots on each position+obligation (converted to lot terms)
|
|
8797
9247
|
position_consumed AS (
|
|
8798
9248
|
SELECT
|
|
8799
9249
|
l.chain_id,
|
|
8800
9250
|
l.contract,
|
|
8801
9251
|
l."user",
|
|
9252
|
+
l.obligation_id,
|
|
8802
9253
|
SUM(
|
|
8803
9254
|
CASE
|
|
8804
9255
|
WHEN wo.assets::numeric > 0
|
|
@@ -8815,7 +9266,7 @@ async function _getOffers(db, params) {
|
|
|
8815
9266
|
ON wo.group_chain_id = g.chain_id
|
|
8816
9267
|
AND LOWER(wo.group_maker) = LOWER(g.maker)
|
|
8817
9268
|
AND wo.group_group = g."group"
|
|
8818
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
9269
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
8819
9270
|
),
|
|
8820
9271
|
-- Compute callback contributions with lot balance
|
|
8821
9272
|
callback_contributions AS (
|
|
@@ -8823,7 +9274,7 @@ async function _getOffers(db, params) {
|
|
|
8823
9274
|
p.hash,
|
|
8824
9275
|
p.obligation_id,
|
|
8825
9276
|
p.assets,
|
|
8826
|
-
p.
|
|
9277
|
+
p.tick,
|
|
8827
9278
|
p.obligation_units,
|
|
8828
9279
|
p.obligation_shares,
|
|
8829
9280
|
p.maturity,
|
|
@@ -8833,6 +9284,7 @@ async function _getOffers(db, params) {
|
|
|
8833
9284
|
p.buy,
|
|
8834
9285
|
p.callback_address,
|
|
8835
9286
|
p.callback_data,
|
|
9287
|
+
p.receiver_if_maker_is_seller,
|
|
8836
9288
|
p.block_number,
|
|
8837
9289
|
p.group_chain_id,
|
|
8838
9290
|
p.group_maker,
|
|
@@ -8868,6 +9320,7 @@ async function _getOffers(db, params) {
|
|
|
8868
9320
|
AND LOWER(l.contract) = LOWER(c.position_contract)
|
|
8869
9321
|
AND LOWER(l."user") = LOWER(c.position_user)
|
|
8870
9322
|
AND l."group" = p.group_group
|
|
9323
|
+
AND l.obligation_id = p.obligation_id
|
|
8871
9324
|
LEFT JOIN ${positions} pos
|
|
8872
9325
|
ON pos.chain_id = c.position_chain_id
|
|
8873
9326
|
AND LOWER(pos.contract) = LOWER(c.position_contract)
|
|
@@ -8876,10 +9329,12 @@ async function _getOffers(db, params) {
|
|
|
8876
9329
|
ON pos_offsets.chain_id = c.position_chain_id
|
|
8877
9330
|
AND LOWER(pos_offsets.contract) = LOWER(c.position_contract)
|
|
8878
9331
|
AND LOWER(pos_offsets."user") = LOWER(c.position_user)
|
|
9332
|
+
AND pos_offsets.obligation_id = p.obligation_id
|
|
8879
9333
|
LEFT JOIN position_consumed pc
|
|
8880
9334
|
ON pc.chain_id = c.position_chain_id
|
|
8881
9335
|
AND LOWER(pc.contract) = LOWER(c.position_contract)
|
|
8882
9336
|
AND LOWER(pc."user") = LOWER(c.position_user)
|
|
9337
|
+
AND pc.obligation_id = p.obligation_id
|
|
8883
9338
|
),
|
|
8884
9339
|
-- Compute contribution per callback in loan terms (loan token only — collateral positions are not indexed)
|
|
8885
9340
|
callback_loan_contribution AS (
|
|
@@ -8897,7 +9352,7 @@ async function _getOffers(db, params) {
|
|
|
8897
9352
|
hash,
|
|
8898
9353
|
obligation_id,
|
|
8899
9354
|
assets,
|
|
8900
|
-
|
|
9355
|
+
tick,
|
|
8901
9356
|
obligation_units,
|
|
8902
9357
|
obligation_shares,
|
|
8903
9358
|
maturity,
|
|
@@ -8907,6 +9362,7 @@ async function _getOffers(db, params) {
|
|
|
8907
9362
|
buy,
|
|
8908
9363
|
callback_address,
|
|
8909
9364
|
callback_data,
|
|
9365
|
+
receiver_if_maker_is_seller,
|
|
8910
9366
|
block_number,
|
|
8911
9367
|
group_chain_id,
|
|
8912
9368
|
group_maker,
|
|
@@ -8923,16 +9379,17 @@ async function _getOffers(db, params) {
|
|
|
8923
9379
|
WHERE clc.callback_id IS NOT NULL
|
|
8924
9380
|
ORDER BY clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user, clc.contribution_in_loan DESC
|
|
8925
9381
|
) deduped
|
|
8926
|
-
GROUP BY hash, obligation_id, assets,
|
|
8927
|
-
|
|
8928
|
-
consumed, chain_id, loan_token, session
|
|
9382
|
+
GROUP BY hash, obligation_id, assets, tick, obligation_units, obligation_shares, maturity, expiry, start, group_group, buy,
|
|
9383
|
+
callback_address, callback_data, block_number, group_chain_id, group_maker,
|
|
9384
|
+
consumed, chain_id, loan_token, session, receiver_if_maker_is_seller
|
|
8929
9385
|
UNION ALL
|
|
8930
9386
|
-- Sell offers without callbacks: collateral positions not indexed, takeable = assets - consumed
|
|
8931
9387
|
SELECT
|
|
8932
|
-
p.hash, p.obligation_id, p.assets, p.
|
|
9388
|
+
p.hash, p.obligation_id, p.assets, p.tick,
|
|
8933
9389
|
p.obligation_units, p.obligation_shares,
|
|
8934
9390
|
p.maturity, p.expiry, p.start, p.group_group,
|
|
8935
9391
|
p.buy, p.callback_address, p.callback_data,
|
|
9392
|
+
p.receiver_if_maker_is_seller,
|
|
8936
9393
|
p.block_number, p.group_chain_id, p.group_maker,
|
|
8937
9394
|
p.consumed, p.chain_id, p.loan_token, p.session,
|
|
8938
9395
|
0 AS total_available
|
|
@@ -8951,7 +9408,7 @@ async function _getOffers(db, params) {
|
|
|
8951
9408
|
oc.obligation_units,
|
|
8952
9409
|
oc.obligation_shares,
|
|
8953
9410
|
oc.consumed,
|
|
8954
|
-
oc.
|
|
9411
|
+
oc.tick,
|
|
8955
9412
|
oc.maturity,
|
|
8956
9413
|
oc.expiry,
|
|
8957
9414
|
oc.start,
|
|
@@ -8961,6 +9418,7 @@ async function _getOffers(db, params) {
|
|
|
8961
9418
|
oc.loan_token,
|
|
8962
9419
|
oc.callback_address,
|
|
8963
9420
|
oc.callback_data,
|
|
9421
|
+
oc.receiver_if_maker_is_seller,
|
|
8964
9422
|
oc.block_number,
|
|
8965
9423
|
oc.session,
|
|
8966
9424
|
COALESCE(oc.total_available, 0) AS available,
|
|
@@ -8983,20 +9441,21 @@ async function _getOffers(db, params) {
|
|
|
8983
9441
|
))
|
|
8984
9442
|
END > 0
|
|
8985
9443
|
ORDER BY
|
|
8986
|
-
oc.
|
|
9444
|
+
oc.tick ${priceSortDirection === "asc" ? drizzle_orm.sql`ASC` : drizzle_orm.sql`DESC`},
|
|
8987
9445
|
oc.block_number ASC,
|
|
8988
9446
|
oc.assets DESC,
|
|
8989
9447
|
oc.hash ASC;
|
|
8990
9448
|
`);
|
|
8991
9449
|
return {
|
|
8992
9450
|
rows: raw.rows.map((row) => {
|
|
9451
|
+
const receiverIfMakerIsSeller = (row.receiver_if_maker_is_seller ?? row.group_maker).toLowerCase();
|
|
8993
9452
|
return {
|
|
8994
9453
|
hash: row.hash,
|
|
8995
9454
|
maker: row.group_maker,
|
|
8996
9455
|
assets: BigInt(row.assets),
|
|
8997
9456
|
obligationUnits: BigInt(row.obligation_units ?? 0),
|
|
8998
9457
|
obligationShares: BigInt(row.obligation_shares ?? 0),
|
|
8999
|
-
|
|
9458
|
+
tick: row.tick,
|
|
9000
9459
|
maturity: row.maturity,
|
|
9001
9460
|
expiry: row.expiry,
|
|
9002
9461
|
start: row.start,
|
|
@@ -9014,6 +9473,7 @@ async function _getOffers(db, params) {
|
|
|
9014
9473
|
address: row.callback_address,
|
|
9015
9474
|
data: row.callback_data
|
|
9016
9475
|
},
|
|
9476
|
+
receiverIfMakerIsSeller,
|
|
9017
9477
|
blockNumber: row.block_number,
|
|
9018
9478
|
consumed: BigInt(row.consumed ?? 0),
|
|
9019
9479
|
available: BigInt(String(row.available ?? "0").split(".")[0] ?? "0"),
|
|
@@ -9028,7 +9488,7 @@ let Cursor;
|
|
|
9028
9488
|
function encode(row, totalReturned, now, side) {
|
|
9029
9489
|
return Buffer.from(JSON.stringify({
|
|
9030
9490
|
side,
|
|
9031
|
-
|
|
9491
|
+
tick: row.tick,
|
|
9032
9492
|
blockNumber: row.blockNumber,
|
|
9033
9493
|
assets: row.assets.toString(),
|
|
9034
9494
|
hash: row.hash,
|
|
@@ -9039,10 +9499,9 @@ let Cursor;
|
|
|
9039
9499
|
_Cursor.encode = encode;
|
|
9040
9500
|
function decode(cursorString, logger) {
|
|
9041
9501
|
if (cursorString == null) return null;
|
|
9042
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
9043
9502
|
try {
|
|
9044
9503
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
9045
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
9504
|
+
if ((v?.side === "buy" || v?.side === "sell") && typeof v?.tick === "number" && Number.isInteger(v.tick) && typeof v?.blockNumber === "number" && Number.isInteger(v.blockNumber) && typeof v?.assets === "string" && /^-?\d+$/.test(v.assets) && (0, viem.isHex)(v?.hash) && typeof v?.totalReturned === "number" && Number.isInteger(v.totalReturned) && typeof v?.now === "number" && Number.isInteger(v.now)) return v;
|
|
9046
9505
|
throw new Error("Invalid cursor");
|
|
9047
9506
|
} catch {
|
|
9048
9507
|
logger.error({
|
|
@@ -9060,7 +9519,7 @@ let LevelCursor;
|
|
|
9060
9519
|
function encode(lastLevel, offersCursor, side, now) {
|
|
9061
9520
|
return Buffer.from(JSON.stringify({
|
|
9062
9521
|
side,
|
|
9063
|
-
|
|
9522
|
+
lastTick: lastLevel.tick,
|
|
9064
9523
|
now,
|
|
9065
9524
|
offersCursor
|
|
9066
9525
|
})).toString("base64url");
|
|
@@ -9068,10 +9527,9 @@ let LevelCursor;
|
|
|
9068
9527
|
_LevelCursor.encode = encode;
|
|
9069
9528
|
function decode(cursorString, logger) {
|
|
9070
9529
|
if (cursorString == null) return null;
|
|
9071
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
9072
9530
|
try {
|
|
9073
9531
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
9074
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
9532
|
+
if ((v?.side === "buy" || v?.side === "sell") && typeof v?.lastTick === "number" && Number.isInteger(v.lastTick) && typeof v?.now === "number" && Number.isInteger(v.now) && (v?.offersCursor === null || typeof v?.offersCursor === "string")) return v;
|
|
9075
9533
|
throw new Error("Invalid book cursor");
|
|
9076
9534
|
} catch {
|
|
9077
9535
|
logger.error({
|
|
@@ -9214,31 +9672,33 @@ function create$9(db) {
|
|
|
9214
9672
|
function create$8(db) {
|
|
9215
9673
|
return {
|
|
9216
9674
|
get: async (parameters) => {
|
|
9217
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9675
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9218
9676
|
const conditions = [];
|
|
9219
9677
|
if (chainId !== void 0) conditions.push((0, drizzle_orm.eq)(lots.chainId, chainId));
|
|
9220
9678
|
if (user !== void 0) conditions.push((0, drizzle_orm.eq)(lots.user, user.toLowerCase()));
|
|
9221
9679
|
if (contract !== void 0) conditions.push((0, drizzle_orm.eq)(lots.contract, contract.toLowerCase()));
|
|
9222
9680
|
if (group !== void 0) conditions.push((0, drizzle_orm.eq)(lots.group, group));
|
|
9681
|
+
if (obligationId !== void 0) conditions.push((0, drizzle_orm.eq)(lots.obligationId, obligationId));
|
|
9223
9682
|
return (await db.select().from(lots).where(conditions.length > 0 ? (0, drizzle_orm.and)(...conditions) : void 0)).map((row) => ({
|
|
9224
9683
|
chainId: row.chainId,
|
|
9225
9684
|
user: row.user,
|
|
9226
9685
|
contract: row.contract,
|
|
9227
9686
|
group: row.group,
|
|
9687
|
+
obligationId: row.obligationId,
|
|
9228
9688
|
lower: BigInt(row.lower),
|
|
9229
9689
|
upper: BigInt(row.upper)
|
|
9230
9690
|
}));
|
|
9231
9691
|
},
|
|
9232
9692
|
create: async (parameters) => {
|
|
9233
9693
|
if (parameters.length === 0) return;
|
|
9234
|
-
const
|
|
9694
|
+
const lotsByKey = /* @__PURE__ */ new Map();
|
|
9235
9695
|
for (const offer of parameters) {
|
|
9236
|
-
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}`.toLowerCase();
|
|
9237
|
-
const existing =
|
|
9238
|
-
if (!existing || offer.size > existing.size)
|
|
9696
|
+
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}-${offer.obligationId}`.toLowerCase();
|
|
9697
|
+
const existing = lotsByKey.get(key);
|
|
9698
|
+
if (!existing || offer.size > existing.size) lotsByKey.set(key, offer);
|
|
9239
9699
|
}
|
|
9240
|
-
for (const offer of
|
|
9241
|
-
const maxUpperResult = await db.select({ maxUpper: drizzle_orm.sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(lots.chainId, offer.positionChainId), (0, drizzle_orm.eq)(lots.contract, offer.positionContract.toLowerCase()), (0, drizzle_orm.eq)(lots.user, offer.positionUser.toLowerCase())));
|
|
9700
|
+
for (const offer of lotsByKey.values()) if ((await db.select().from(lots).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(lots.chainId, offer.positionChainId), (0, drizzle_orm.eq)(lots.contract, offer.positionContract.toLowerCase()), (0, drizzle_orm.eq)(lots.user, offer.positionUser.toLowerCase()), (0, drizzle_orm.eq)(lots.group, offer.group.toLowerCase()), (0, drizzle_orm.eq)(lots.obligationId, offer.obligationId.toLowerCase()))).limit(1)).length === 0) {
|
|
9701
|
+
const maxUpperResult = await db.select({ maxUpper: drizzle_orm.sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where((0, drizzle_orm.and)((0, drizzle_orm.eq)(lots.chainId, offer.positionChainId), (0, drizzle_orm.eq)(lots.contract, offer.positionContract.toLowerCase()), (0, drizzle_orm.eq)(lots.user, offer.positionUser.toLowerCase()), (0, drizzle_orm.eq)(lots.obligationId, offer.obligationId.toLowerCase())));
|
|
9242
9702
|
const newLower = BigInt(maxUpperResult[0]?.maxUpper ?? "0");
|
|
9243
9703
|
const newUpper = newLower + offer.size;
|
|
9244
9704
|
await db.insert(lots).values({
|
|
@@ -9246,6 +9706,7 @@ function create$8(db) {
|
|
|
9246
9706
|
user: offer.positionUser.toLowerCase(),
|
|
9247
9707
|
contract: offer.positionContract.toLowerCase(),
|
|
9248
9708
|
group: offer.group.toLowerCase(),
|
|
9709
|
+
obligationId: offer.obligationId.toLowerCase(),
|
|
9249
9710
|
lower: newLower.toString(),
|
|
9250
9711
|
upper: newUpper.toString()
|
|
9251
9712
|
});
|
|
@@ -9262,55 +9723,79 @@ function create$8(db) {
|
|
|
9262
9723
|
* @returns Obligations domain. {@link ObligationsDomain}
|
|
9263
9724
|
*/
|
|
9264
9725
|
function create$7(db) {
|
|
9265
|
-
return {
|
|
9266
|
-
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
|
|
9272
|
-
|
|
9273
|
-
|
|
9274
|
-
|
|
9275
|
-
|
|
9276
|
-
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9282
|
-
|
|
9726
|
+
return {
|
|
9727
|
+
get: async (parameters) => {
|
|
9728
|
+
const chainIds = parameters?.chainId;
|
|
9729
|
+
const now$1 = now();
|
|
9730
|
+
return (await db.select({
|
|
9731
|
+
chainId: obligations.chainId,
|
|
9732
|
+
loanToken: obligations.loanToken,
|
|
9733
|
+
collaterals: drizzle_orm.sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${oracles$1.address}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
9734
|
+
maturity: obligations.maturity
|
|
9735
|
+
}).from(obligations).innerJoin(obligationCollateralsV2, (0, drizzle_orm.eq)(obligations.obligationId, obligationCollateralsV2.obligationId)).innerJoin(oracles$1, drizzle_orm.sql`${obligationCollateralsV2.oracleChainId} = ${oracles$1.chainId}
|
|
9736
|
+
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).groupBy(obligations.obligationId).where((0, drizzle_orm.and)(chainIds !== void 0 && chainIds.length > 0 ? (0, drizzle_orm.inArray)(obligations.chainId, chainIds) : void 0, (0, drizzle_orm.gte)(obligations.maturity, now$1))).orderBy((0, drizzle_orm.asc)(obligations.obligationId))).map((row) => from$15({
|
|
9737
|
+
chainId: row.chainId,
|
|
9738
|
+
loanToken: row.loanToken,
|
|
9739
|
+
collaterals: row.collaterals.sort((left, right) => left.asset.localeCompare(right.asset)).map((collateral) => from$17({
|
|
9740
|
+
asset: collateral.asset,
|
|
9741
|
+
oracle: collateral.oracle,
|
|
9742
|
+
lltv: from$18(BigInt(collateral.lltv))
|
|
9743
|
+
})),
|
|
9744
|
+
maturity: row.maturity
|
|
9745
|
+
}));
|
|
9746
|
+
},
|
|
9747
|
+
create: async (obligations$1) => {
|
|
9748
|
+
if (obligations$1.length === 0) return;
|
|
9749
|
+
const obligationsById = /* @__PURE__ */ new Map();
|
|
9750
|
+
for (const obligation of obligations$1) {
|
|
9751
|
+
const id$1 = id(obligation).toLowerCase();
|
|
9752
|
+
if (!obligationsById.get(id$1)) obligationsById.set(id$1, obligation);
|
|
9753
|
+
}
|
|
9754
|
+
try {
|
|
9755
|
+
await db.transaction(async (dbTx) => {
|
|
9756
|
+
const obligationRows = obligations$1.map((obligation) => ({
|
|
9283
9757
|
obligationId: id(obligation),
|
|
9284
|
-
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
lltv: collateral.lltv
|
|
9758
|
+
chainId: obligation.chainId,
|
|
9759
|
+
loanToken: obligation.loanToken.toLowerCase(),
|
|
9760
|
+
maturity: obligation.maturity
|
|
9288
9761
|
}));
|
|
9762
|
+
for (const batch of batch$1(obligationRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(obligations).values(batch).onConflictDoNothing();
|
|
9763
|
+
const collateralRows = obligations$1.flatMap((obligation) => {
|
|
9764
|
+
return obligation.collaterals.map((collateral) => ({
|
|
9765
|
+
obligationId: id(obligation),
|
|
9766
|
+
asset: collateral.asset.toLowerCase(),
|
|
9767
|
+
oracleChainId: obligation.chainId,
|
|
9768
|
+
oracleAddress: collateral.oracle.toLowerCase(),
|
|
9769
|
+
lltv: collateral.lltv
|
|
9770
|
+
}));
|
|
9771
|
+
});
|
|
9772
|
+
for (const batch of batch$1(collateralRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(obligationCollateralsV2).values(batch).onConflictDoNothing();
|
|
9289
9773
|
});
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9293
|
-
|
|
9294
|
-
throw new Error("Obligations.create failed. Ensure oracles exist before inserting obligations.", { cause: error });
|
|
9774
|
+
} catch (err) {
|
|
9775
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
9776
|
+
throw new Error("Obligations.create failed. Ensure oracles exist before inserting obligations.", { cause: error });
|
|
9777
|
+
}
|
|
9295
9778
|
}
|
|
9296
|
-
}
|
|
9779
|
+
};
|
|
9297
9780
|
}
|
|
9298
9781
|
|
|
9299
9782
|
//#endregion
|
|
9300
9783
|
//#region src/database/domains/Offsets.ts
|
|
9301
9784
|
function create$6(db) {
|
|
9302
9785
|
return { get: async (parameters) => {
|
|
9303
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9786
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9304
9787
|
const conditions = [];
|
|
9305
9788
|
if (chainId !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.chainId, chainId));
|
|
9306
9789
|
if (user !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.user, user.toLowerCase()));
|
|
9307
9790
|
if (contract !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.contract, contract.toLowerCase()));
|
|
9308
9791
|
if (group !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.group, group));
|
|
9792
|
+
if (obligationId !== void 0) conditions.push((0, drizzle_orm.eq)(offsets.obligationId, obligationId));
|
|
9309
9793
|
return (await db.select().from(offsets).where(conditions.length > 0 ? (0, drizzle_orm.and)(...conditions) : void 0)).map((row) => ({
|
|
9310
9794
|
chainId: row.chainId,
|
|
9311
9795
|
user: row.user,
|
|
9312
9796
|
contract: row.contract,
|
|
9313
9797
|
group: row.group,
|
|
9798
|
+
obligationId: row.obligationId,
|
|
9314
9799
|
value: BigInt(row.value)
|
|
9315
9800
|
}));
|
|
9316
9801
|
} };
|
|
@@ -9460,7 +9945,8 @@ const create$4 = (db) => {
|
|
|
9460
9945
|
if (!parsed.chainId || !parsed.contract) throw new Error("Invalid cursor format");
|
|
9461
9946
|
cursor = {
|
|
9462
9947
|
chainId: parsed.chainId,
|
|
9463
|
-
contract: parsed.contract
|
|
9948
|
+
contract: parsed.contract,
|
|
9949
|
+
obligationId: parsed.obligationId ?? null
|
|
9464
9950
|
};
|
|
9465
9951
|
}
|
|
9466
9952
|
const raw = await db.execute(drizzle_orm.sql`
|
|
@@ -9469,16 +9955,18 @@ const create$4 = (db) => {
|
|
|
9469
9955
|
chain_id,
|
|
9470
9956
|
"user",
|
|
9471
9957
|
contract,
|
|
9958
|
+
obligation_id,
|
|
9472
9959
|
SUM(value::numeric) AS total_offset
|
|
9473
9960
|
FROM ${offsets}
|
|
9474
9961
|
WHERE LOWER("user") = LOWER(${user})
|
|
9475
|
-
GROUP BY chain_id, "user", contract
|
|
9962
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
9476
9963
|
),
|
|
9477
9964
|
position_consumed AS (
|
|
9478
9965
|
SELECT
|
|
9479
9966
|
l.chain_id,
|
|
9480
9967
|
l.contract,
|
|
9481
9968
|
l."user",
|
|
9969
|
+
l.obligation_id,
|
|
9482
9970
|
SUM(
|
|
9483
9971
|
CASE
|
|
9484
9972
|
WHEN offer_agg.assets > 0
|
|
@@ -9504,50 +9992,64 @@ const create$4 = (db) => {
|
|
|
9504
9992
|
AND LOWER(offer_agg.group_maker) = LOWER(g.maker)
|
|
9505
9993
|
AND offer_agg."group_group" = g."group"
|
|
9506
9994
|
WHERE LOWER(l."user") = LOWER(${user})
|
|
9507
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
9995
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
9508
9996
|
),
|
|
9509
9997
|
position_max_lot AS (
|
|
9510
9998
|
SELECT
|
|
9511
9999
|
chain_id,
|
|
9512
10000
|
contract,
|
|
9513
10001
|
"user",
|
|
10002
|
+
obligation_id,
|
|
9514
10003
|
MAX(upper::numeric) AS max_upper
|
|
9515
10004
|
FROM ${lots}
|
|
9516
10005
|
WHERE LOWER("user") = LOWER(${user})
|
|
9517
|
-
GROUP BY chain_id, contract, "user"
|
|
10006
|
+
GROUP BY chain_id, contract, "user", obligation_id
|
|
10007
|
+
),
|
|
10008
|
+
per_obligation AS (
|
|
10009
|
+
SELECT
|
|
10010
|
+
pml.chain_id,
|
|
10011
|
+
pml.contract,
|
|
10012
|
+
pml."user",
|
|
10013
|
+
pml.obligation_id,
|
|
10014
|
+
GREATEST(0,
|
|
10015
|
+
COALESCE(pml.max_upper, 0)
|
|
10016
|
+
- COALESCE(po.total_offset, 0)
|
|
10017
|
+
- COALESCE(pc.consumed, 0)
|
|
10018
|
+
)::text AS reserved_balance
|
|
10019
|
+
FROM position_max_lot pml
|
|
10020
|
+
LEFT JOIN position_offsets po
|
|
10021
|
+
ON po.chain_id = pml.chain_id
|
|
10022
|
+
AND LOWER(po.contract) = LOWER(pml.contract)
|
|
10023
|
+
AND LOWER(po."user") = LOWER(pml."user")
|
|
10024
|
+
AND po.obligation_id = pml.obligation_id
|
|
10025
|
+
LEFT JOIN position_consumed pc
|
|
10026
|
+
ON pc.chain_id = pml.chain_id
|
|
10027
|
+
AND LOWER(pc.contract) = LOWER(pml.contract)
|
|
10028
|
+
AND LOWER(pc."user") = LOWER(pml."user")
|
|
10029
|
+
AND pc.obligation_id = pml.obligation_id
|
|
9518
10030
|
)
|
|
9519
10031
|
SELECT
|
|
9520
10032
|
p.chain_id,
|
|
9521
10033
|
p.contract,
|
|
9522
10034
|
p."user",
|
|
9523
10035
|
p.block_number,
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
- COALESCE(po.total_offset, 0)
|
|
9527
|
-
- COALESCE(pc.consumed, 0)
|
|
9528
|
-
)::text AS reserved_balance
|
|
10036
|
+
po.obligation_id,
|
|
10037
|
+
COALESCE(po.reserved_balance, '0') AS reserved_balance
|
|
9529
10038
|
FROM ${positions} p
|
|
9530
|
-
LEFT JOIN
|
|
10039
|
+
LEFT JOIN per_obligation po
|
|
9531
10040
|
ON po.chain_id = p.chain_id
|
|
9532
10041
|
AND LOWER(po.contract) = LOWER(p.contract)
|
|
9533
10042
|
AND LOWER(po."user") = LOWER(p."user")
|
|
9534
|
-
LEFT JOIN position_consumed pc
|
|
9535
|
-
ON pc.chain_id = p.chain_id
|
|
9536
|
-
AND LOWER(pc.contract) = LOWER(p.contract)
|
|
9537
|
-
AND LOWER(pc."user") = LOWER(p."user")
|
|
9538
|
-
LEFT JOIN position_max_lot pml
|
|
9539
|
-
ON pml.chain_id = p.chain_id
|
|
9540
|
-
AND LOWER(pml.contract) = LOWER(p.contract)
|
|
9541
|
-
AND LOWER(pml."user") = LOWER(p."user")
|
|
9542
10043
|
WHERE LOWER(p."user") = LOWER(${user})
|
|
9543
10044
|
AND p."user" != ${viem.zeroAddress}
|
|
9544
|
-
${cursor !== null ? drizzle_orm.sql`AND (p.chain_id, p.contract) > (${cursor.chainId}, ${cursor.contract})` : drizzle_orm.sql``}
|
|
9545
|
-
ORDER BY p.chain_id ASC, p.contract ASC
|
|
10045
|
+
${cursor !== null ? drizzle_orm.sql`AND (p.chain_id, p.contract, COALESCE(po.obligation_id, '')) > (${cursor.chainId}, ${cursor.contract}, ${cursor.obligationId ?? ""})` : drizzle_orm.sql``}
|
|
10046
|
+
ORDER BY p.chain_id ASC, p.contract ASC, po.obligation_id ASC NULLS FIRST
|
|
9546
10047
|
LIMIT ${limit}
|
|
9547
10048
|
`);
|
|
9548
10049
|
const nextCursor = raw.rows.length === limit ? Buffer.from(JSON.stringify({
|
|
9549
10050
|
chainId: raw.rows[raw.rows.length - 1].chain_id.toString(),
|
|
9550
|
-
contract: raw.rows[raw.rows.length - 1].contract
|
|
10051
|
+
contract: raw.rows[raw.rows.length - 1].contract,
|
|
10052
|
+
obligationId: raw.rows[raw.rows.length - 1].obligation_id
|
|
9551
10053
|
})).toString("base64url") : null;
|
|
9552
10054
|
return {
|
|
9553
10055
|
positions: raw.rows.map((row) => ({
|
|
@@ -9555,6 +10057,7 @@ const create$4 = (db) => {
|
|
|
9555
10057
|
contract: row.contract,
|
|
9556
10058
|
user: row.user,
|
|
9557
10059
|
blockNumber: row.block_number,
|
|
10060
|
+
obligationId: row.obligation_id,
|
|
9558
10061
|
reserved: BigInt(row.reserved_balance.split(".")[0] ?? "0")
|
|
9559
10062
|
})),
|
|
9560
10063
|
nextCursor
|
|
@@ -9833,7 +10336,10 @@ function create$1(db) {
|
|
|
9833
10336
|
|
|
9834
10337
|
//#endregion
|
|
9835
10338
|
//#region src/database/Database.ts
|
|
9836
|
-
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
10339
|
+
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
10340
|
+
connect: () => connect$1,
|
|
10341
|
+
getSchemaNamesForMigration: () => getSchemaNamesForMigration
|
|
10342
|
+
});
|
|
9837
10343
|
function createDomains(core, chainRegistry) {
|
|
9838
10344
|
return {
|
|
9839
10345
|
book: create$12({ db: core }),
|
|
@@ -9855,6 +10361,9 @@ function createDomains(core, chainRegistry) {
|
|
|
9855
10361
|
transfers: create$3(core)
|
|
9856
10362
|
};
|
|
9857
10363
|
}
|
|
10364
|
+
function createReaders(core) {
|
|
10365
|
+
return { obligations: create$16({ db: core }) };
|
|
10366
|
+
}
|
|
9858
10367
|
const AUGMENT_CACHE = /* @__PURE__ */ new WeakMap();
|
|
9859
10368
|
function augmentWithDomains(base, chainRegistry) {
|
|
9860
10369
|
const cached = AUGMENT_CACHE.get(base)?.get(chainRegistry);
|
|
@@ -9866,6 +10375,7 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9866
10375
|
});
|
|
9867
10376
|
};
|
|
9868
10377
|
const dms = createDomains(wrapped, chainRegistry);
|
|
10378
|
+
const readers = createReaders(wrapped);
|
|
9869
10379
|
Object.defineProperties(wrapped, {
|
|
9870
10380
|
book: {
|
|
9871
10381
|
value: dms.book,
|
|
@@ -9922,6 +10432,10 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9922
10432
|
transfers: {
|
|
9923
10433
|
value: dms.transfers,
|
|
9924
10434
|
enumerable: true
|
|
10435
|
+
},
|
|
10436
|
+
readers: {
|
|
10437
|
+
value: readers,
|
|
10438
|
+
enumerable: true
|
|
9925
10439
|
}
|
|
9926
10440
|
});
|
|
9927
10441
|
const chainRegistryMap = AUGMENT_CACHE.get(base);
|
|
@@ -9930,6 +10444,7 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9930
10444
|
return wrapped;
|
|
9931
10445
|
}
|
|
9932
10446
|
const InMemoryDbMap = /* @__PURE__ */ new Map();
|
|
10447
|
+
const LEGACY_SCHEMA_START_MINOR = 7;
|
|
9933
10448
|
/**
|
|
9934
10449
|
* Connect to the database.
|
|
9935
10450
|
* @notice If no connection string is provided, an in-process PGLite database is created.
|
|
@@ -9984,9 +10499,26 @@ function applyMigrations(kind, driver) {
|
|
|
9984
10499
|
async function preMigrate(driver) {
|
|
9985
10500
|
const tracer = getTracer("db.preMigrate");
|
|
9986
10501
|
await startActiveSpan(tracer, "db.preMigrate", async () => {
|
|
9987
|
-
|
|
10502
|
+
const schemaNames = getSchemaNamesForMigration(VERSION);
|
|
10503
|
+
for (const schemaName of schemaNames) await driver.execute(`create schema if not exists "${schemaName}"`);
|
|
9988
10504
|
});
|
|
9989
10505
|
}
|
|
10506
|
+
/**
|
|
10507
|
+
* Build the list of router schemas that should exist before running migrations.
|
|
10508
|
+
* @param version - Current schema version (e.g. `router_v1.8`).
|
|
10509
|
+
* @returns Ordered schema names from `router_v1.7` to current, or just current if parsing fails.
|
|
10510
|
+
*/
|
|
10511
|
+
function getSchemaNamesForMigration(version) {
|
|
10512
|
+
const parsed = /^router_v(?<major>\d+)\.(?<minor>\d+)$/.exec(version);
|
|
10513
|
+
if (!parsed?.groups?.major || !parsed.groups.minor) return [version];
|
|
10514
|
+
const major = Number.parseInt(parsed.groups.major, 10);
|
|
10515
|
+
const currentMinor = Number.parseInt(parsed.groups.minor, 10);
|
|
10516
|
+
if (!Number.isInteger(major) || !Number.isInteger(currentMinor)) return [version];
|
|
10517
|
+
if (currentMinor < LEGACY_SCHEMA_START_MINOR) return [version];
|
|
10518
|
+
const schemaNames = [];
|
|
10519
|
+
for (let minor = LEGACY_SCHEMA_START_MINOR; minor <= currentMinor; minor += 1) schemaNames.push(`router_v${major}.${minor}`);
|
|
10520
|
+
return schemaNames;
|
|
10521
|
+
}
|
|
9990
10522
|
async function postMigrate(driver) {
|
|
9991
10523
|
const tracer = getTracer("db.postMigrate");
|
|
9992
10524
|
await startActiveSpan(tracer, "db.postMigrate", async () => {
|
|
@@ -10256,15 +10788,16 @@ async function postMigrate(driver) {
|
|
|
10256
10788
|
RETURNS trigger
|
|
10257
10789
|
LANGUAGE plpgsql AS $$
|
|
10258
10790
|
BEGIN
|
|
10259
|
-
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", value)
|
|
10791
|
+
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", obligation_id, value)
|
|
10260
10792
|
VALUES (
|
|
10261
10793
|
OLD.chain_id,
|
|
10262
10794
|
OLD."user",
|
|
10263
10795
|
OLD.contract,
|
|
10264
10796
|
OLD."group",
|
|
10797
|
+
OLD.obligation_id,
|
|
10265
10798
|
OLD.upper::numeric - OLD.lower::numeric
|
|
10266
10799
|
)
|
|
10267
|
-
ON CONFLICT (chain_id, "user", contract, "group") DO NOTHING;
|
|
10800
|
+
ON CONFLICT (chain_id, "user", contract, "group", obligation_id) DO NOTHING;
|
|
10268
10801
|
RETURN OLD;
|
|
10269
10802
|
END;
|
|
10270
10803
|
$$;
|
|
@@ -10518,10 +11051,11 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
|
10518
11051
|
amountMutualExclusivity: () => amountMutualExclusivity,
|
|
10519
11052
|
callback: () => callback,
|
|
10520
11053
|
chains: () => chains,
|
|
11054
|
+
collateralToken: () => collateralToken,
|
|
11055
|
+
loanToken: () => loanToken,
|
|
10521
11056
|
maturity: () => maturity,
|
|
10522
11057
|
oracle: () => oracle,
|
|
10523
11058
|
sameMaker: () => sameMaker,
|
|
10524
|
-
token: () => token,
|
|
10525
11059
|
validity: () => validity
|
|
10526
11060
|
});
|
|
10527
11061
|
/**
|
|
@@ -10541,7 +11075,7 @@ const chains = ({ chains }) => single("chain_ids", `Validates that offer chain i
|
|
|
10541
11075
|
});
|
|
10542
11076
|
const maturity = ({ maturities }) => single("maturity", `Validates that offer maturity is one of: [${maturities.join(", ")}]`, (offer) => {
|
|
10543
11077
|
const allowedMaturities = maturities.map((m) => from$16(m));
|
|
10544
|
-
if (!allowedMaturities.includes(offer.maturity)) return { message: `Maturity must be
|
|
11078
|
+
if (!allowedMaturities.includes(offer.maturity)) return { message: `Maturity must be one of (${allowedMaturities.join(", ")}). Got: ${offer.maturity}` };
|
|
10545
11079
|
});
|
|
10546
11080
|
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) => {
|
|
10547
11081
|
if (!isEmptyCallback(offer)) return { message: "Non-empty callbacks are not supported." };
|
|
@@ -10549,15 +11083,25 @@ const callback = ({ callbacks }) => single("callback", `Validates callbacks: buy
|
|
|
10549
11083
|
if (isEmptyCallback(offer) && !offer.buy && !callbacks.includes(Type$1.SellWithEmptyCallback)) return { message: "Sell offers with empty callback not allowed." };
|
|
10550
11084
|
});
|
|
10551
11085
|
/**
|
|
10552
|
-
* A validation rule that checks if the offer's
|
|
10553
|
-
* @param assetsByChainId - Allowed
|
|
11086
|
+
* A validation rule that checks if the offer's loan token is allowed for its chain.
|
|
11087
|
+
* @param assetsByChainId - Allowed loan tokens indexed by chain id.
|
|
10554
11088
|
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
10555
11089
|
*/
|
|
10556
|
-
const
|
|
10557
|
-
const
|
|
10558
|
-
if (!
|
|
10559
|
-
if (!
|
|
10560
|
-
|
|
11090
|
+
const loanToken = ({ assetsByChainId }) => single("loan_token", "Validates that offer loan token is in the allowed token list for the offer chain", (offer) => {
|
|
11091
|
+
const allowedLoanTokens = assetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase());
|
|
11092
|
+
if (!allowedLoanTokens || allowedLoanTokens.length === 0) return { message: `No allowed loan tokens for chain ${offer.chainId}` };
|
|
11093
|
+
if (!allowedLoanTokens.includes(offer.loanToken.toLowerCase())) return { message: "Loan token is not allowed" };
|
|
11094
|
+
});
|
|
11095
|
+
/**
|
|
11096
|
+
* A validation rule that checks if the offer's collateral tokens are allowed for its chain.
|
|
11097
|
+
* @param collateralAssetsByChainId - Allowed collateral tokens indexed by chain id.
|
|
11098
|
+
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
11099
|
+
*/
|
|
11100
|
+
const collateralToken = ({ collateralAssetsByChainId }) => single("collateral_token", "Validates that offer collateral tokens are in the allowed token list for the offer chain", (offer) => {
|
|
11101
|
+
const allowedCollateralTokens = collateralAssetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase()) ?? [];
|
|
11102
|
+
if (allowedCollateralTokens.length === 0) return { message: `No allowed collateral tokens for chain ${offer.chainId}` };
|
|
11103
|
+
if (offer.collaterals.length === 0) return { message: "At least one collateral token is required" };
|
|
11104
|
+
if (offer.collaterals.some((collateral) => !allowedCollateralTokens.includes(collateral.asset.toLowerCase()))) return { message: "Collateral token is not allowed" };
|
|
10561
11105
|
});
|
|
10562
11106
|
/**
|
|
10563
11107
|
* A validation rule that checks if the offer's oracle addresses are allowed for its chain.
|
|
@@ -10600,21 +11144,24 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
|
|
|
10600
11144
|
//#region src/gatekeeper/morphoRules.ts
|
|
10601
11145
|
const morphoRules = (chains$3) => {
|
|
10602
11146
|
const assetsByChainId = {};
|
|
11147
|
+
const collateralAssetsByChainId = {};
|
|
10603
11148
|
const oraclesByChainId = {};
|
|
10604
11149
|
for (const chain of chains$3) {
|
|
10605
11150
|
assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
|
|
11151
|
+
collateralAssetsByChainId[chain.id] = collateralAssets[chain.id.toString()] ?? [];
|
|
10606
11152
|
oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
|
|
10607
11153
|
}
|
|
10608
11154
|
return [
|
|
10609
11155
|
sameMaker(),
|
|
10610
11156
|
amountMutualExclusivity(),
|
|
10611
11157
|
chains({ chains: chains$3 }),
|
|
10612
|
-
maturity({ maturities: [MaturityType.
|
|
11158
|
+
maturity({ maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek] }),
|
|
10613
11159
|
callback({
|
|
10614
11160
|
callbacks: [Type$1.BuyWithEmptyCallback, Type$1.SellWithEmptyCallback],
|
|
10615
11161
|
allowedAddresses: []
|
|
10616
11162
|
}),
|
|
10617
|
-
|
|
11163
|
+
loanToken({ assetsByChainId }),
|
|
11164
|
+
collateralToken({ collateralAssetsByChainId }),
|
|
10618
11165
|
oracle({ oraclesByChainId })
|
|
10619
11166
|
];
|
|
10620
11167
|
};
|
|
@@ -11026,6 +11573,12 @@ Object.defineProperty(exports, 'Rules', {
|
|
|
11026
11573
|
return Rules_exports;
|
|
11027
11574
|
}
|
|
11028
11575
|
});
|
|
11576
|
+
Object.defineProperty(exports, 'Tick', {
|
|
11577
|
+
enumerable: true,
|
|
11578
|
+
get: function () {
|
|
11579
|
+
return Tick_exports;
|
|
11580
|
+
}
|
|
11581
|
+
});
|
|
11029
11582
|
Object.defineProperty(exports, 'Time', {
|
|
11030
11583
|
enumerable: true,
|
|
11031
11584
|
get: function () {
|