@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.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import "@opentelemetry/propagator-aws-xray";
|
|
|
12
12
|
import "@opentelemetry/resources";
|
|
13
13
|
import "@opentelemetry/sdk-trace-node";
|
|
14
14
|
import "@opentelemetry/semantic-conventions";
|
|
15
|
-
import { and, asc, eq, gt, gte, inArray, lte, ne, sql } from "drizzle-orm";
|
|
15
|
+
import { and, asc, desc, eq, gt, gte, inArray, lte, ne, sql } from "drizzle-orm";
|
|
16
16
|
import { anvil, base, mainnet } from "viem/chains";
|
|
17
17
|
import * as z$1 from "zod";
|
|
18
18
|
import { StandardMerkleTree } from "@openzeppelin/merkle-tree";
|
|
@@ -566,7 +566,7 @@ var utils_exports = /* @__PURE__ */ __exportAll({
|
|
|
566
566
|
|
|
567
567
|
//#endregion
|
|
568
568
|
//#region src/indexer/collectors/Admin.ts
|
|
569
|
-
function create$
|
|
569
|
+
function create$21(parameters) {
|
|
570
570
|
const collector = "admin";
|
|
571
571
|
const { client, db, options: { maxBatchSize = 25, maxBlockNumber } = {} } = parameters;
|
|
572
572
|
const maxBlockNumberBI = maxBlockNumber !== void 0 ? BigInt(maxBlockNumber) : void 0;
|
|
@@ -806,8 +806,8 @@ const names = [
|
|
|
806
806
|
"positions",
|
|
807
807
|
"prices"
|
|
808
808
|
];
|
|
809
|
-
function create$
|
|
810
|
-
const admin = create$
|
|
809
|
+
function create$20({ name, collect, client, db, options }) {
|
|
810
|
+
const admin = create$21({
|
|
811
811
|
client,
|
|
812
812
|
db,
|
|
813
813
|
options
|
|
@@ -973,18 +973,18 @@ const MorphoV2 = parseAbi([
|
|
|
973
973
|
"function setFeeSetter(address newFeeSetter)",
|
|
974
974
|
"function setObligationTradingFee(bytes32 id, uint256 index, uint256 newTradingFee)",
|
|
975
975
|
"function setOwner(address newOwner)",
|
|
976
|
-
"function setTradingFeeRecipient(address
|
|
976
|
+
"function setTradingFeeRecipient(address feeRecipient)",
|
|
977
977
|
"function sharesOf(bytes32 id, address user) view returns (uint256)",
|
|
978
978
|
"function shuffleSession()",
|
|
979
979
|
"function supplyCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)",
|
|
980
|
-
"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
|
|
980
|
+
"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)",
|
|
981
981
|
"function totalShares(bytes32 id) view returns (uint256)",
|
|
982
982
|
"function totalUnits(bytes32 id) view returns (uint256)",
|
|
983
983
|
"function touchObligation((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation) returns (bytes32)",
|
|
984
984
|
"function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)",
|
|
985
985
|
"function tradingFeeRecipient() view returns (address)",
|
|
986
|
-
"function withdraw((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, uint256 shares, address onBehalf) returns (uint256, uint256)",
|
|
987
|
-
"function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)",
|
|
986
|
+
"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)",
|
|
987
|
+
"function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf, address receiver)",
|
|
988
988
|
"function withdrawable(bytes32 id) view returns (uint256)",
|
|
989
989
|
"event Constructor(address indexed owner)",
|
|
990
990
|
"event Consume(address indexed user, bytes32 indexed group, uint256 amount)",
|
|
@@ -996,12 +996,12 @@ const MorphoV2 = parseAbi([
|
|
|
996
996
|
"event SetFeeSetter(address indexed feeSetter)",
|
|
997
997
|
"event SetObligationTradingFee(bytes32 indexed id, uint256 indexed index, uint256 newTradingFee)",
|
|
998
998
|
"event SetOwner(address indexed owner)",
|
|
999
|
-
"event SetTradingFeeRecipient(address indexed
|
|
999
|
+
"event SetTradingFeeRecipient(address indexed feeRecipient)",
|
|
1000
1000
|
"event ShuffleSession(address indexed user, bytes32 session)",
|
|
1001
1001
|
"event SupplyCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)",
|
|
1002
|
-
"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)",
|
|
1003
|
-
"event Withdraw(address
|
|
1004
|
-
"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)"
|
|
1002
|
+
"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)",
|
|
1003
|
+
"event Withdraw(address caller, bytes32 indexed id, uint256 obligationUnits, uint256 shares, address indexed onBehalf, address indexed receiver)",
|
|
1004
|
+
"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf, address receiver)"
|
|
1005
1005
|
]);
|
|
1006
1006
|
|
|
1007
1007
|
//#endregion
|
|
@@ -1273,8 +1273,8 @@ const chains$2 = {
|
|
|
1273
1273
|
name: "ethereum-virtual-testnet",
|
|
1274
1274
|
custom: {
|
|
1275
1275
|
morpho: {
|
|
1276
|
-
address: "
|
|
1277
|
-
blockCreated:
|
|
1276
|
+
address: "0xc9f3c65996fc46b9500608b2c9a9152c01c540f7",
|
|
1277
|
+
blockCreated: 23226871
|
|
1278
1278
|
},
|
|
1279
1279
|
morphoBlue: {
|
|
1280
1280
|
address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
@@ -1420,13 +1420,13 @@ var MissingBlockNumberError = class extends BaseError {
|
|
|
1420
1420
|
|
|
1421
1421
|
//#endregion
|
|
1422
1422
|
//#region src/core/ChainRegistry.ts
|
|
1423
|
-
var ChainRegistry_exports = /* @__PURE__ */ __exportAll({ create: () => create$
|
|
1423
|
+
var ChainRegistry_exports = /* @__PURE__ */ __exportAll({ create: () => create$19 });
|
|
1424
1424
|
/**
|
|
1425
1425
|
* Creates a chain registry from a list of chains.
|
|
1426
1426
|
* @param chains - Array of chain objects to register.
|
|
1427
1427
|
* @returns A registry for looking up chains by ID. {@link ChainRegistry}
|
|
1428
1428
|
*/
|
|
1429
|
-
function create$
|
|
1429
|
+
function create$19(chains) {
|
|
1430
1430
|
const byId = /* @__PURE__ */ new Map();
|
|
1431
1431
|
for (const chain of chains) byId.set(chain.id, chain);
|
|
1432
1432
|
return {
|
|
@@ -2080,7 +2080,7 @@ const OfferSchema = () => {
|
|
|
2080
2080
|
assets: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
2081
2081
|
obligationUnits: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
|
|
2082
2082
|
obligationShares: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
|
|
2083
|
-
|
|
2083
|
+
tick: z$1.coerce.number().int().min(0).max(990),
|
|
2084
2084
|
maturity: MaturitySchema,
|
|
2085
2085
|
expiry: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
2086
2086
|
start: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
@@ -2101,7 +2101,8 @@ const OfferSchema = () => {
|
|
|
2101
2101
|
callback: z$1.object({
|
|
2102
2102
|
address: z$1.string().transform(transformAddress),
|
|
2103
2103
|
data: z$1.string().transform(transformHex)
|
|
2104
|
-
})
|
|
2104
|
+
}),
|
|
2105
|
+
receiverIfMakerIsSeller: z$1.string().transform(transformAddress)
|
|
2105
2106
|
}).refine((data) => data.start < data.expiry, {
|
|
2106
2107
|
message: "start must be before expiry",
|
|
2107
2108
|
path: ["start"]
|
|
@@ -2117,8 +2118,12 @@ const OfferSchema = () => {
|
|
|
2117
2118
|
* @returns The created offer.
|
|
2118
2119
|
*/
|
|
2119
2120
|
function from$14(input) {
|
|
2121
|
+
const normalizedInput = {
|
|
2122
|
+
...input,
|
|
2123
|
+
receiverIfMakerIsSeller: input.receiverIfMakerIsSeller ?? input.maker
|
|
2124
|
+
};
|
|
2120
2125
|
try {
|
|
2121
|
-
return OfferSchema().parse(
|
|
2126
|
+
return OfferSchema().parse(normalizedInput);
|
|
2122
2127
|
} catch (error) {
|
|
2123
2128
|
throw new InvalidOfferError(error);
|
|
2124
2129
|
}
|
|
@@ -2152,7 +2157,7 @@ const serialize = (offer) => ({
|
|
|
2152
2157
|
assets: offer.assets.toString(),
|
|
2153
2158
|
obligationUnits: offer.obligationUnits.toString(),
|
|
2154
2159
|
obligationShares: offer.obligationShares.toString(),
|
|
2155
|
-
|
|
2160
|
+
tick: offer.tick,
|
|
2156
2161
|
maturity: Number(offer.maturity),
|
|
2157
2162
|
expiry: Number(offer.expiry),
|
|
2158
2163
|
start: Number(offer.start),
|
|
@@ -2170,6 +2175,7 @@ const serialize = (offer) => ({
|
|
|
2170
2175
|
address: offer.callback.address,
|
|
2171
2176
|
data: offer.callback.data
|
|
2172
2177
|
},
|
|
2178
|
+
receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller,
|
|
2173
2179
|
hash: hash(offer)
|
|
2174
2180
|
});
|
|
2175
2181
|
/**
|
|
@@ -2197,14 +2203,13 @@ function random$1(config) {
|
|
|
2197
2203
|
[.98, 2]
|
|
2198
2204
|
]));
|
|
2199
2205
|
const buy = config?.buy !== void 0 ? config.buy : bool();
|
|
2200
|
-
const
|
|
2201
|
-
const
|
|
2202
|
-
const
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
return [BigInt(q) * (ONE / 4n), buy ? 1 + idx : 1 + (len - 1 - idx)];
|
|
2206
|
+
const tickMin = buy ? 0 : 495;
|
|
2207
|
+
const len = (buy ? 495 : 990) - tickMin + 1;
|
|
2208
|
+
const tickPairs = Array.from({ length: len }, (_, idx) => {
|
|
2209
|
+
const weight = buy ? 1 + idx : 1 + (len - 1 - idx);
|
|
2210
|
+
return [tickMin + idx, weight];
|
|
2206
2211
|
});
|
|
2207
|
-
const
|
|
2212
|
+
const tick = config?.tick ?? weightedChoice(tickPairs);
|
|
2208
2213
|
const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
|
|
2209
2214
|
const unit = BigInt(10) ** BigInt(loanTokenDecimals);
|
|
2210
2215
|
const amountBase = BigInt(100 + int(999901));
|
|
@@ -2213,12 +2218,13 @@ function random$1(config) {
|
|
|
2213
2218
|
address: zeroAddress,
|
|
2214
2219
|
data: "0x"
|
|
2215
2220
|
};
|
|
2221
|
+
const maker = config?.maker ?? address();
|
|
2216
2222
|
return from$14({
|
|
2217
|
-
maker
|
|
2223
|
+
maker,
|
|
2218
2224
|
assets: assetsScaled,
|
|
2219
2225
|
obligationUnits: config?.obligationUnits ?? 0n,
|
|
2220
2226
|
obligationShares: config?.obligationShares ?? 0n,
|
|
2221
|
-
|
|
2227
|
+
tick,
|
|
2222
2228
|
maturity,
|
|
2223
2229
|
expiry: config?.expiry ?? maturity - 1,
|
|
2224
2230
|
start: config?.start ?? maturity - 10,
|
|
@@ -2231,7 +2237,8 @@ function random$1(config) {
|
|
|
2231
2237
|
...random$3(),
|
|
2232
2238
|
lltv
|
|
2233
2239
|
})).sort((a, b) => a.asset.localeCompare(b.asset)),
|
|
2234
|
-
callback: config?.callback ?? emptyCallback
|
|
2240
|
+
callback: config?.callback ?? emptyCallback,
|
|
2241
|
+
receiverIfMakerIsSeller: config?.receiverIfMakerIsSeller ?? maker
|
|
2235
2242
|
});
|
|
2236
2243
|
}
|
|
2237
2244
|
const weightedChoice = (pairs) => {
|
|
@@ -2283,7 +2290,7 @@ const types = {
|
|
|
2283
2290
|
type: "uint256"
|
|
2284
2291
|
},
|
|
2285
2292
|
{
|
|
2286
|
-
name: "
|
|
2293
|
+
name: "tick",
|
|
2287
2294
|
type: "uint256"
|
|
2288
2295
|
},
|
|
2289
2296
|
{
|
|
@@ -2317,6 +2324,10 @@ const types = {
|
|
|
2317
2324
|
{
|
|
2318
2325
|
name: "callback",
|
|
2319
2326
|
type: "Callback"
|
|
2327
|
+
},
|
|
2328
|
+
{
|
|
2329
|
+
name: "receiverIfMakerIsSeller",
|
|
2330
|
+
type: "address"
|
|
2320
2331
|
}
|
|
2321
2332
|
],
|
|
2322
2333
|
Collateral: [
|
|
@@ -2351,7 +2362,7 @@ function hash(offer) {
|
|
|
2351
2362
|
assets: offer.assets,
|
|
2352
2363
|
obligationUnits: offer.obligationUnits,
|
|
2353
2364
|
obligationShares: offer.obligationShares,
|
|
2354
|
-
|
|
2365
|
+
tick: BigInt(offer.tick),
|
|
2355
2366
|
maturity: BigInt(offer.maturity),
|
|
2356
2367
|
expiry: BigInt(offer.expiry),
|
|
2357
2368
|
group: offer.group,
|
|
@@ -2362,7 +2373,8 @@ function hash(offer) {
|
|
|
2362
2373
|
callback: {
|
|
2363
2374
|
address: offer.callback.address.toLowerCase(),
|
|
2364
2375
|
data: offer.callback.data
|
|
2365
|
-
}
|
|
2376
|
+
},
|
|
2377
|
+
receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller.toLowerCase()
|
|
2366
2378
|
},
|
|
2367
2379
|
primaryType: "Offer",
|
|
2368
2380
|
types
|
|
@@ -2402,7 +2414,7 @@ const OfferAbi = [
|
|
|
2402
2414
|
type: "uint256"
|
|
2403
2415
|
},
|
|
2404
2416
|
{
|
|
2405
|
-
name: "
|
|
2417
|
+
name: "tick",
|
|
2406
2418
|
type: "uint256"
|
|
2407
2419
|
},
|
|
2408
2420
|
{
|
|
@@ -2465,6 +2477,10 @@ const OfferAbi = [
|
|
|
2465
2477
|
name: "data",
|
|
2466
2478
|
type: "bytes"
|
|
2467
2479
|
}]
|
|
2480
|
+
},
|
|
2481
|
+
{
|
|
2482
|
+
name: "receiverIfMakerIsSeller",
|
|
2483
|
+
type: "address"
|
|
2468
2484
|
}
|
|
2469
2485
|
];
|
|
2470
2486
|
function encode$1(offer) {
|
|
@@ -2473,7 +2489,7 @@ function encode$1(offer) {
|
|
|
2473
2489
|
offer.assets,
|
|
2474
2490
|
offer.obligationUnits,
|
|
2475
2491
|
offer.obligationShares,
|
|
2476
|
-
offer.
|
|
2492
|
+
BigInt(offer.tick),
|
|
2477
2493
|
BigInt(offer.maturity),
|
|
2478
2494
|
BigInt(offer.expiry),
|
|
2479
2495
|
offer.group,
|
|
@@ -2483,7 +2499,8 @@ function encode$1(offer) {
|
|
|
2483
2499
|
offer.loanToken,
|
|
2484
2500
|
BigInt(offer.start),
|
|
2485
2501
|
offer.collaterals,
|
|
2486
|
-
offer.callback
|
|
2502
|
+
offer.callback,
|
|
2503
|
+
offer.receiverIfMakerIsSeller
|
|
2487
2504
|
]);
|
|
2488
2505
|
}
|
|
2489
2506
|
function decode$1(data) {
|
|
@@ -2498,7 +2515,7 @@ function decode$1(data) {
|
|
|
2498
2515
|
assets: decoded[1],
|
|
2499
2516
|
obligationUnits: decoded[2],
|
|
2500
2517
|
obligationShares: decoded[3],
|
|
2501
|
-
|
|
2518
|
+
tick: Number(decoded[4]),
|
|
2502
2519
|
maturity: from$16(Number(decoded[5])),
|
|
2503
2520
|
expiry: Number(decoded[6]),
|
|
2504
2521
|
group: decoded[7],
|
|
@@ -2517,7 +2534,8 @@ function decode$1(data) {
|
|
|
2517
2534
|
callback: {
|
|
2518
2535
|
address: decoded[14].address,
|
|
2519
2536
|
data: decoded[14].data
|
|
2520
|
-
}
|
|
2537
|
+
},
|
|
2538
|
+
receiverIfMakerIsSeller: decoded[15]
|
|
2521
2539
|
});
|
|
2522
2540
|
}
|
|
2523
2541
|
/**
|
|
@@ -2593,6 +2611,12 @@ const takeEvent = {
|
|
|
2593
2611
|
indexed: false,
|
|
2594
2612
|
internalType: "bool"
|
|
2595
2613
|
},
|
|
2614
|
+
{
|
|
2615
|
+
name: "sellerReceiver",
|
|
2616
|
+
type: "address",
|
|
2617
|
+
indexed: false,
|
|
2618
|
+
internalType: "address"
|
|
2619
|
+
},
|
|
2596
2620
|
{
|
|
2597
2621
|
name: "group",
|
|
2598
2622
|
type: "bytes32",
|
|
@@ -2778,20 +2802,99 @@ function from$12(parameters) {
|
|
|
2778
2802
|
};
|
|
2779
2803
|
}
|
|
2780
2804
|
|
|
2805
|
+
//#endregion
|
|
2806
|
+
//#region src/core/Tick.ts
|
|
2807
|
+
var Tick_exports = /* @__PURE__ */ __exportAll({
|
|
2808
|
+
InvalidPriceError: () => InvalidPriceError,
|
|
2809
|
+
InvalidTickError: () => InvalidTickError,
|
|
2810
|
+
MAX_PRICE: () => MAX_PRICE,
|
|
2811
|
+
TICK_RANGE: () => TICK_RANGE,
|
|
2812
|
+
priceToTick: () => priceToTick,
|
|
2813
|
+
tickToPrice: () => tickToPrice
|
|
2814
|
+
});
|
|
2815
|
+
/** ln(1 + 0.025), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2816
|
+
const LN_ONE_PLUS_DELTA = 24692612590371501n;
|
|
2817
|
+
/** ln(2), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2818
|
+
const LN2 = 693147180559945309n;
|
|
2819
|
+
const WAD$1 = 10n ** 18n;
|
|
2820
|
+
const WAD_SQUARED = 10n ** 36n;
|
|
2821
|
+
const PRICE_STEP = 10n ** 13n;
|
|
2822
|
+
const HALF_TICK_RANGE = 495n;
|
|
2823
|
+
/** Tick domain supported by Morpho V2. */
|
|
2824
|
+
const TICK_RANGE = 990;
|
|
2825
|
+
/** Max allowed price (1e18 in wad). */
|
|
2826
|
+
const MAX_PRICE = WAD$1;
|
|
2827
|
+
/**
|
|
2828
|
+
* Converts a tick to a wad price using the same approximation and rounding as TickLib.
|
|
2829
|
+
* @param tick - Tick value in the inclusive range [0, 990].
|
|
2830
|
+
* @returns The price in wad units.
|
|
2831
|
+
* @throws {@link InvalidTickError} If tick is not an integer in range [0, 990].
|
|
2832
|
+
*/
|
|
2833
|
+
function tickToPrice(tick) {
|
|
2834
|
+
assertTick(tick);
|
|
2835
|
+
return divHalfDownUnchecked(divHalfDownUnchecked(WAD_SQUARED, WAD$1 + wExp(LN_ONE_PLUS_DELTA * (HALF_TICK_RANGE - BigInt(tick)))), PRICE_STEP) * PRICE_STEP;
|
|
2836
|
+
}
|
|
2837
|
+
/**
|
|
2838
|
+
* Returns the lowest tick with a higher-or-equal price.
|
|
2839
|
+
* @param price - Price in wad units.
|
|
2840
|
+
* @returns The first tick whose {@link tickToPrice} is greater than or equal to `price`.
|
|
2841
|
+
* @throws {@link InvalidPriceError} If price is outside [0, 1e18].
|
|
2842
|
+
*/
|
|
2843
|
+
function priceToTick(price) {
|
|
2844
|
+
assertPrice(price);
|
|
2845
|
+
let low = 0;
|
|
2846
|
+
let high = TICK_RANGE;
|
|
2847
|
+
while (low !== high) {
|
|
2848
|
+
const mid = Math.floor((low + high) / 2);
|
|
2849
|
+
if (tickToPrice(mid) < price) low = mid + 1;
|
|
2850
|
+
else high = mid;
|
|
2851
|
+
}
|
|
2852
|
+
return low;
|
|
2853
|
+
}
|
|
2854
|
+
function divHalfDownUnchecked(x, d) {
|
|
2855
|
+
return (x + (d - 1n) / 2n) / d;
|
|
2856
|
+
}
|
|
2857
|
+
function wExp(x) {
|
|
2858
|
+
if (x < 0n) return WAD_SQUARED / wExp(-x);
|
|
2859
|
+
const q = (x + LN2 / 2n) / LN2;
|
|
2860
|
+
const r = x - q * LN2;
|
|
2861
|
+
const secondTerm = r * r / (2n * WAD$1);
|
|
2862
|
+
const thirdTerm = secondTerm * r / (3n * WAD$1);
|
|
2863
|
+
return WAD$1 + r + secondTerm + thirdTerm << q;
|
|
2864
|
+
}
|
|
2865
|
+
function assertTick(tick) {
|
|
2866
|
+
if (!Number.isInteger(tick) || tick < 0 || tick > TICK_RANGE) throw new InvalidTickError(tick);
|
|
2867
|
+
}
|
|
2868
|
+
function assertPrice(price) {
|
|
2869
|
+
if (price < 0n || price > MAX_PRICE) throw new InvalidPriceError(price);
|
|
2870
|
+
}
|
|
2871
|
+
var InvalidTickError = class extends BaseError {
|
|
2872
|
+
name = "Tick.InvalidTickError";
|
|
2873
|
+
constructor(tick) {
|
|
2874
|
+
super(`Invalid tick: ${tick}. Tick must be an integer between 0 and ${TICK_RANGE}.`);
|
|
2875
|
+
}
|
|
2876
|
+
};
|
|
2877
|
+
var InvalidPriceError = class extends BaseError {
|
|
2878
|
+
name = "Tick.InvalidPriceError";
|
|
2879
|
+
constructor(price) {
|
|
2880
|
+
super(`Invalid price: ${price}. Price must be between 0 and ${MAX_PRICE}.`);
|
|
2881
|
+
}
|
|
2882
|
+
};
|
|
2883
|
+
|
|
2781
2884
|
//#endregion
|
|
2782
2885
|
//#region src/core/Quote.ts
|
|
2783
2886
|
var Quote_exports = /* @__PURE__ */ __exportAll({
|
|
2784
2887
|
InvalidQuoteError: () => InvalidQuoteError,
|
|
2785
|
-
QuoteSchema: () => QuoteSchema,
|
|
2786
2888
|
from: () => from$11,
|
|
2787
2889
|
fromSnakeCase: () => fromSnakeCase,
|
|
2788
2890
|
random: () => random
|
|
2789
2891
|
});
|
|
2790
|
-
const
|
|
2892
|
+
const SideInputSchema = z$1.object({ tick: z$1.number().int().min(0).max(TICK_RANGE).nullable() }).strict();
|
|
2893
|
+
const QuoteInputSchema = z$1.object({
|
|
2791
2894
|
obligationId: z$1.string().transform(transformHex),
|
|
2792
|
-
ask:
|
|
2793
|
-
bid:
|
|
2794
|
-
});
|
|
2895
|
+
ask: SideInputSchema,
|
|
2896
|
+
bid: SideInputSchema
|
|
2897
|
+
}).strict();
|
|
2795
2898
|
/**
|
|
2796
2899
|
* Creates a quote for a given obligation.
|
|
2797
2900
|
* @constructor
|
|
@@ -2801,16 +2904,16 @@ const QuoteSchema = z$1.object({
|
|
|
2801
2904
|
*
|
|
2802
2905
|
* @example
|
|
2803
2906
|
* ```ts
|
|
2804
|
-
* const quote = Quote.from({ obligationId: "0x123", ask: {
|
|
2907
|
+
* const quote = Quote.from({ obligationId: "0x123", ask: { tick: 500 }, bid: { tick: 510 } });
|
|
2805
2908
|
* ```
|
|
2806
2909
|
*/
|
|
2807
2910
|
function from$11(parameters) {
|
|
2808
2911
|
try {
|
|
2809
|
-
const parsedQuote =
|
|
2912
|
+
const parsedQuote = QuoteInputSchema.parse(parameters);
|
|
2810
2913
|
return {
|
|
2811
2914
|
obligationId: parsedQuote.obligationId,
|
|
2812
|
-
ask: parsedQuote.ask,
|
|
2813
|
-
bid: parsedQuote.bid
|
|
2915
|
+
ask: sideFromTick(parsedQuote.ask),
|
|
2916
|
+
bid: sideFromTick(parsedQuote.bid)
|
|
2814
2917
|
};
|
|
2815
2918
|
} catch (error) {
|
|
2816
2919
|
throw new InvalidQuoteError(error);
|
|
@@ -2837,8 +2940,8 @@ function fromSnakeCase(snake) {
|
|
|
2837
2940
|
function random() {
|
|
2838
2941
|
return from$11({
|
|
2839
2942
|
obligationId: id(random$2()),
|
|
2840
|
-
ask: {
|
|
2841
|
-
bid: {
|
|
2943
|
+
ask: { tick: int(TICK_RANGE + 1) },
|
|
2944
|
+
bid: { tick: int(TICK_RANGE + 1) }
|
|
2842
2945
|
});
|
|
2843
2946
|
}
|
|
2844
2947
|
var InvalidQuoteError = class extends BaseError {
|
|
@@ -2847,6 +2950,12 @@ var InvalidQuoteError = class extends BaseError {
|
|
|
2847
2950
|
super("Invalid quote.", { cause: error });
|
|
2848
2951
|
}
|
|
2849
2952
|
};
|
|
2953
|
+
function sideFromTick(side) {
|
|
2954
|
+
return {
|
|
2955
|
+
tick: side.tick,
|
|
2956
|
+
price: side.tick === null ? 0n : tickToPrice(side.tick)
|
|
2957
|
+
};
|
|
2958
|
+
}
|
|
2850
2959
|
|
|
2851
2960
|
//#endregion
|
|
2852
2961
|
//#region src/core/TradingFee.ts
|
|
@@ -3361,7 +3470,7 @@ const BrandTypeId = Symbol.for("mempool/Brand");
|
|
|
3361
3470
|
|
|
3362
3471
|
//#endregion
|
|
3363
3472
|
//#region src/database/drizzle/VERSION.ts
|
|
3364
|
-
const VERSION = "router_v1.
|
|
3473
|
+
const VERSION = "router_v1.8";
|
|
3365
3474
|
|
|
3366
3475
|
//#endregion
|
|
3367
3476
|
//#region src/database/drizzle/schema.ts
|
|
@@ -3513,10 +3622,7 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
3513
3622
|
precision: 78,
|
|
3514
3623
|
scale: 0
|
|
3515
3624
|
}).notNull().default("0"),
|
|
3516
|
-
|
|
3517
|
-
precision: 78,
|
|
3518
|
-
scale: 0
|
|
3519
|
-
}).notNull(),
|
|
3625
|
+
tick: integer("tick").notNull(),
|
|
3520
3626
|
maturity: integer("maturity").notNull(),
|
|
3521
3627
|
expiry: integer("expiry").notNull(),
|
|
3522
3628
|
start: integer("start").notNull(),
|
|
@@ -3527,6 +3633,7 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
3527
3633
|
buy: boolean("buy").notNull(),
|
|
3528
3634
|
callbackAddress: varchar("callback_address", { length: 42 }).notNull(),
|
|
3529
3635
|
callbackData: text("callback_data").notNull(),
|
|
3636
|
+
receiverIfMakerIsSeller: varchar("receiver_if_maker_is_seller", { length: 42 }),
|
|
3530
3637
|
blockNumber: bigint("block_number", { mode: "number" }).notNull(),
|
|
3531
3638
|
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
3532
3639
|
}, (table) => [
|
|
@@ -3581,6 +3688,7 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3581
3688
|
user: varchar("user", { length: 42 }).notNull(),
|
|
3582
3689
|
contract: varchar("contract", { length: 42 }).notNull(),
|
|
3583
3690
|
group: varchar("group", { length: 66 }).notNull(),
|
|
3691
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
3584
3692
|
lower: numeric("lower", {
|
|
3585
3693
|
precision: 78,
|
|
3586
3694
|
scale: 0
|
|
@@ -3595,7 +3703,8 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3595
3703
|
table.chainId,
|
|
3596
3704
|
table.user,
|
|
3597
3705
|
table.contract,
|
|
3598
|
-
table.group
|
|
3706
|
+
table.group,
|
|
3707
|
+
table.obligationId
|
|
3599
3708
|
],
|
|
3600
3709
|
name: "lots_pk"
|
|
3601
3710
|
}),
|
|
@@ -3631,6 +3740,7 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3631
3740
|
user: varchar("user", { length: 42 }).notNull(),
|
|
3632
3741
|
contract: varchar("contract", { length: 42 }).notNull(),
|
|
3633
3742
|
group: varchar("group", { length: 66 }).notNull(),
|
|
3743
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
3634
3744
|
value: numeric("value", {
|
|
3635
3745
|
precision: 78,
|
|
3636
3746
|
scale: 0
|
|
@@ -3640,7 +3750,8 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3640
3750
|
table.chainId,
|
|
3641
3751
|
table.user,
|
|
3642
3752
|
table.contract,
|
|
3643
|
-
table.group
|
|
3753
|
+
table.group,
|
|
3754
|
+
table.obligationId
|
|
3644
3755
|
],
|
|
3645
3756
|
name: "offsets_pk"
|
|
3646
3757
|
}), foreignKey({
|
|
@@ -4231,6 +4342,7 @@ function decodeCallbacks(parameters) {
|
|
|
4231
4342
|
positionContract: loanToken,
|
|
4232
4343
|
positionUser: offer.maker,
|
|
4233
4344
|
group: offer.group,
|
|
4345
|
+
obligationId: obligationId(offer),
|
|
4234
4346
|
size: offer.assets
|
|
4235
4347
|
});
|
|
4236
4348
|
callbacks.push({
|
|
@@ -4903,7 +5015,7 @@ async function* collectPrices(parameters) {
|
|
|
4903
5015
|
//#region src/indexer/collectors/CollectorBuilder.ts
|
|
4904
5016
|
function createBuilder(parameters) {
|
|
4905
5017
|
const { client, db, gatekeeper, options: { maxBlockNumber, blockWindow, interval } = {} } = parameters;
|
|
4906
|
-
const createCollector = (name, collect) => create$
|
|
5018
|
+
const createCollector = (name, collect) => create$20({
|
|
4907
5019
|
name,
|
|
4908
5020
|
collect,
|
|
4909
5021
|
client,
|
|
@@ -4995,7 +5107,7 @@ const from$7 = (parameters) => {
|
|
|
4995
5107
|
//#endregion
|
|
4996
5108
|
//#region src/indexer/Indexer.ts
|
|
4997
5109
|
var Indexer_exports = /* @__PURE__ */ __exportAll({
|
|
4998
|
-
create: () => create$
|
|
5110
|
+
create: () => create$18,
|
|
4999
5111
|
from: () => from$6
|
|
5000
5112
|
});
|
|
5001
5113
|
function from$6(config) {
|
|
@@ -5011,7 +5123,7 @@ function from$6(config) {
|
|
|
5011
5123
|
retryAttempts,
|
|
5012
5124
|
retryDelayMs
|
|
5013
5125
|
});
|
|
5014
|
-
return create$
|
|
5126
|
+
return create$18({
|
|
5015
5127
|
client,
|
|
5016
5128
|
collectors: [
|
|
5017
5129
|
offersCollector,
|
|
@@ -5021,7 +5133,7 @@ function from$6(config) {
|
|
|
5021
5133
|
]
|
|
5022
5134
|
});
|
|
5023
5135
|
}
|
|
5024
|
-
function create$
|
|
5136
|
+
function create$18(params) {
|
|
5025
5137
|
const { collectors, client } = params;
|
|
5026
5138
|
const indexerId = `${client.chain.id.toString()}.indexer`;
|
|
5027
5139
|
const tracer = getTracer(`router.${indexerId}`);
|
|
@@ -5050,12 +5162,12 @@ function create$17(params) {
|
|
|
5050
5162
|
|
|
5051
5163
|
//#endregion
|
|
5052
5164
|
//#region src/api/Health.ts
|
|
5053
|
-
var Health_exports = /* @__PURE__ */ __exportAll({ create: () => create$
|
|
5165
|
+
var Health_exports = /* @__PURE__ */ __exportAll({ create: () => create$17 });
|
|
5054
5166
|
const DEFAULT_MAX_ALLOWED_LAG = 5;
|
|
5055
5167
|
/**
|
|
5056
5168
|
* Create a health service that exposes collector and chain block numbers.
|
|
5057
5169
|
*/
|
|
5058
|
-
function create$
|
|
5170
|
+
function create$17(parameters) {
|
|
5059
5171
|
const { db, maxAllowedLag = DEFAULT_MAX_ALLOWED_LAG, healthClients, chainRegistry } = parameters;
|
|
5060
5172
|
const loadSnapshot = async () => {
|
|
5061
5173
|
const [collectorRows, chainRows, remoteBlockByChainId] = await Promise.all([
|
|
@@ -5169,8 +5281,10 @@ async function getRemoteBlockNumbers(healthClients) {
|
|
|
5169
5281
|
//#region src/api/Schema/BookResponse.ts
|
|
5170
5282
|
var BookResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$5 });
|
|
5171
5283
|
function from$5(level) {
|
|
5284
|
+
const price = tickToPrice(level.tick);
|
|
5172
5285
|
return {
|
|
5173
|
-
|
|
5286
|
+
tick: level.tick,
|
|
5287
|
+
price: price.toString(),
|
|
5174
5288
|
assets: level.assets.toString(),
|
|
5175
5289
|
count: level.count
|
|
5176
5290
|
};
|
|
@@ -5217,6 +5331,7 @@ var ObligationResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$
|
|
|
5217
5331
|
* Creates an `ObligationResponse` from a `Obligation`.
|
|
5218
5332
|
* @constructor
|
|
5219
5333
|
* @param obligation - {@link Obligation}
|
|
5334
|
+
* @param quote - {@link Quote}
|
|
5220
5335
|
* @returns The created `ObligationResponse`. {@link ObligationResponse}
|
|
5221
5336
|
*/
|
|
5222
5337
|
function from$4(obligation, quote) {
|
|
@@ -5230,8 +5345,14 @@ function from$4(obligation, quote) {
|
|
|
5230
5345
|
oracle: c.oracle
|
|
5231
5346
|
})),
|
|
5232
5347
|
maturity: obligation.maturity,
|
|
5233
|
-
ask: {
|
|
5234
|
-
|
|
5348
|
+
ask: {
|
|
5349
|
+
tick: quote.ask.tick,
|
|
5350
|
+
price: quote.ask.price.toString()
|
|
5351
|
+
},
|
|
5352
|
+
bid: {
|
|
5353
|
+
tick: quote.bid.tick,
|
|
5354
|
+
price: quote.bid.price.toString()
|
|
5355
|
+
}
|
|
5235
5356
|
};
|
|
5236
5357
|
}
|
|
5237
5358
|
|
|
@@ -5275,11 +5396,12 @@ function from$3(input) {
|
|
|
5275
5396
|
obligation_shares: input.obligationShares.toString(),
|
|
5276
5397
|
start: input.start,
|
|
5277
5398
|
expiry: input.expiry,
|
|
5278
|
-
|
|
5399
|
+
tick: input.tick,
|
|
5279
5400
|
group: input.group,
|
|
5280
5401
|
session: input.session,
|
|
5281
5402
|
callback: input.callback.address,
|
|
5282
|
-
callback_data: input.callback.data
|
|
5403
|
+
callback_data: input.callback.data,
|
|
5404
|
+
receiver_if_maker_is_seller: input.receiverIfMakerIsSeller
|
|
5283
5405
|
},
|
|
5284
5406
|
offer_hash: input.hash,
|
|
5285
5407
|
obligation_id: id({
|
|
@@ -5346,7 +5468,7 @@ var InternalServerError = class extends APIError {
|
|
|
5346
5468
|
super(STATUS_CODE.INTERNAL_SERVER_ERROR, message, "INTERNAL_SERVER_ERROR");
|
|
5347
5469
|
}
|
|
5348
5470
|
};
|
|
5349
|
-
var BadRequestError = class extends APIError {
|
|
5471
|
+
var BadRequestError$1 = class extends APIError {
|
|
5350
5472
|
constructor(message = "Invalid JSON format", details) {
|
|
5351
5473
|
super(STATUS_CODE.BAD_REQUEST, message, "BAD_REQUEST", details);
|
|
5352
5474
|
}
|
|
@@ -5368,7 +5490,7 @@ function success(args) {
|
|
|
5368
5490
|
*/
|
|
5369
5491
|
function failure(err) {
|
|
5370
5492
|
if (err instanceof APIError) return handleAPIError(err);
|
|
5371
|
-
if (err instanceof SyntaxError) return handleAPIError(new BadRequestError(err.message));
|
|
5493
|
+
if (err instanceof SyntaxError) return handleAPIError(new BadRequestError$1(err.message));
|
|
5372
5494
|
if (err instanceof z$1.ZodError) return handleAPIError(handleZodError(err));
|
|
5373
5495
|
return handleAPIError(new InternalServerError());
|
|
5374
5496
|
}
|
|
@@ -5418,7 +5540,7 @@ function __decorate(decorators, target, key, desc) {
|
|
|
5418
5540
|
//#region src/api/Schema/openapi.ts
|
|
5419
5541
|
const timestampExample = "2024-01-01T12:00:00.000Z";
|
|
5420
5542
|
const offerCursorExample = "eyJvZmZzZXQiOjEwMH0";
|
|
5421
|
-
const obligationCursorExample = "
|
|
5543
|
+
const obligationCursorExample = "eyJzb3J0IjpbImlkIl0sImlkIjoiMHgxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAiLCJhc2siOiIwIiwiYmlkIjoiMCIsIm1hdHVyaXR5IjoxNzYxOTIyODAwfQ";
|
|
5422
5544
|
const offerExample = {
|
|
5423
5545
|
offer: {
|
|
5424
5546
|
obligation: {
|
|
@@ -5437,11 +5559,12 @@ const offerExample = {
|
|
|
5437
5559
|
obligation_shares: "0",
|
|
5438
5560
|
start: 1761922790,
|
|
5439
5561
|
expiry: 1761922799,
|
|
5440
|
-
|
|
5562
|
+
tick: 495,
|
|
5441
5563
|
group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
|
|
5442
5564
|
session: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
5443
5565
|
callback: "0x0000000000000000000000000000000000000000",
|
|
5444
|
-
callback_data: "0x"
|
|
5566
|
+
callback_data: "0x",
|
|
5567
|
+
receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
|
|
5445
5568
|
},
|
|
5446
5569
|
offer_hash: "0xac4bd8318ec914f89f8af913f162230575b0ac0696a19256bc12138c5cfe1427",
|
|
5447
5570
|
obligation_id: "0x25690ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9abc",
|
|
@@ -5478,7 +5601,7 @@ const validateOfferExample = {
|
|
|
5478
5601
|
assets: "369216000000000000000000",
|
|
5479
5602
|
obligation_units: "0",
|
|
5480
5603
|
obligation_shares: "0",
|
|
5481
|
-
|
|
5604
|
+
tick: 495,
|
|
5482
5605
|
maturity: 1761922799,
|
|
5483
5606
|
expiry: 1761922799,
|
|
5484
5607
|
start: 1761922790,
|
|
@@ -5495,7 +5618,8 @@ const validateOfferExample = {
|
|
|
5495
5618
|
callback: {
|
|
5496
5619
|
address: "0x0000000000000000000000000000000000000000",
|
|
5497
5620
|
data: "0x"
|
|
5498
|
-
}
|
|
5621
|
+
},
|
|
5622
|
+
receiver_if_maker_is_seller: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401"
|
|
5499
5623
|
};
|
|
5500
5624
|
const routerStatusExample = {
|
|
5501
5625
|
status: "live",
|
|
@@ -5566,11 +5690,23 @@ __decorate([ApiProperty({
|
|
|
5566
5690
|
example: validateOfferExample.callback.data
|
|
5567
5691
|
})], ValidateCallbackRequest.prototype, "data", void 0);
|
|
5568
5692
|
var AskResponse = class {};
|
|
5693
|
+
__decorate([ApiProperty({
|
|
5694
|
+
type: "number",
|
|
5695
|
+
nullable: true,
|
|
5696
|
+
example: 500,
|
|
5697
|
+
description: "Best ask tick. Null when there is no active ask quote."
|
|
5698
|
+
})], AskResponse.prototype, "tick", void 0);
|
|
5569
5699
|
__decorate([ApiProperty({
|
|
5570
5700
|
type: "string",
|
|
5571
5701
|
example: "1000000000000000000"
|
|
5572
5702
|
})], AskResponse.prototype, "price", void 0);
|
|
5573
5703
|
var BidResponse = class {};
|
|
5704
|
+
__decorate([ApiProperty({
|
|
5705
|
+
type: "number",
|
|
5706
|
+
nullable: true,
|
|
5707
|
+
example: 500,
|
|
5708
|
+
description: "Best bid tick. Null when there is no active bid quote."
|
|
5709
|
+
})], BidResponse.prototype, "tick", void 0);
|
|
5574
5710
|
__decorate([ApiProperty({
|
|
5575
5711
|
type: "string",
|
|
5576
5712
|
example: "1000000000000000000"
|
|
@@ -5622,9 +5758,11 @@ __decorate([ApiProperty({
|
|
|
5622
5758
|
example: offerExample.offer.expiry
|
|
5623
5759
|
})], OfferDataResponse.prototype, "expiry", void 0);
|
|
5624
5760
|
__decorate([ApiProperty({
|
|
5625
|
-
type: "
|
|
5626
|
-
example: offerExample.offer.
|
|
5627
|
-
|
|
5761
|
+
type: "number",
|
|
5762
|
+
example: offerExample.offer.tick,
|
|
5763
|
+
minimum: 0,
|
|
5764
|
+
maximum: 990
|
|
5765
|
+
})], OfferDataResponse.prototype, "tick", void 0);
|
|
5628
5766
|
__decorate([ApiProperty({
|
|
5629
5767
|
type: "string",
|
|
5630
5768
|
example: offerExample.offer.group
|
|
@@ -5641,6 +5779,10 @@ __decorate([ApiProperty({
|
|
|
5641
5779
|
type: "string",
|
|
5642
5780
|
example: offerExample.offer.callback_data
|
|
5643
5781
|
})], OfferDataResponse.prototype, "callback_data", void 0);
|
|
5782
|
+
__decorate([ApiProperty({
|
|
5783
|
+
type: "string",
|
|
5784
|
+
example: offerExample.offer.receiver_if_maker_is_seller
|
|
5785
|
+
})], OfferDataResponse.prototype, "receiver_if_maker_is_seller", void 0);
|
|
5644
5786
|
var OfferListItemResponse = class {};
|
|
5645
5787
|
__decorate([ApiProperty({
|
|
5646
5788
|
type: () => OfferDataResponse,
|
|
@@ -5865,9 +6007,11 @@ __decorate([ApiProperty({
|
|
|
5865
6007
|
required: false
|
|
5866
6008
|
})], ValidateOfferRequest.prototype, "obligation_shares", void 0);
|
|
5867
6009
|
__decorate([ApiProperty({
|
|
5868
|
-
type: "
|
|
5869
|
-
example: validateOfferExample.
|
|
5870
|
-
|
|
6010
|
+
type: "number",
|
|
6011
|
+
example: validateOfferExample.tick,
|
|
6012
|
+
minimum: 0,
|
|
6013
|
+
maximum: 990
|
|
6014
|
+
})], ValidateOfferRequest.prototype, "tick", void 0);
|
|
5871
6015
|
__decorate([ApiProperty({
|
|
5872
6016
|
type: "number",
|
|
5873
6017
|
example: validateOfferExample.maturity
|
|
@@ -5908,6 +6052,10 @@ __decorate([ApiProperty({
|
|
|
5908
6052
|
type: () => ValidateCallbackRequest,
|
|
5909
6053
|
example: validateOfferExample.callback
|
|
5910
6054
|
})], ValidateOfferRequest.prototype, "callback", void 0);
|
|
6055
|
+
__decorate([ApiProperty({
|
|
6056
|
+
type: "string",
|
|
6057
|
+
example: validateOfferExample.receiver_if_maker_is_seller
|
|
6058
|
+
})], ValidateOfferRequest.prototype, "receiver_if_maker_is_seller", void 0);
|
|
5911
6059
|
var ValidateOffersRequest = class {};
|
|
5912
6060
|
__decorate([ApiProperty({
|
|
5913
6061
|
type: () => [ValidateOfferRequest],
|
|
@@ -5967,9 +6115,16 @@ __decorate([ApiProperty({
|
|
|
5967
6115
|
description: "List of validation issues. Returned when any offer fails validation."
|
|
5968
6116
|
})], ValidationFailureResponse.prototype, "data", void 0);
|
|
5969
6117
|
var BookLevelResponse = class {};
|
|
6118
|
+
__decorate([ApiProperty({
|
|
6119
|
+
type: "number",
|
|
6120
|
+
example: 495,
|
|
6121
|
+
minimum: 0,
|
|
6122
|
+
maximum: 990
|
|
6123
|
+
})], BookLevelResponse.prototype, "tick", void 0);
|
|
5970
6124
|
__decorate([ApiProperty({
|
|
5971
6125
|
type: "string",
|
|
5972
|
-
example: "
|
|
6126
|
+
example: "500000000000000000",
|
|
6127
|
+
description: "Price derived from tick, scaled by 1e18."
|
|
5973
6128
|
})], BookLevelResponse.prototype, "price", void 0);
|
|
5974
6129
|
__decorate([ApiProperty({
|
|
5975
6130
|
type: "string",
|
|
@@ -5983,6 +6138,7 @@ const positionExample = {
|
|
|
5983
6138
|
chain_id: 1,
|
|
5984
6139
|
contract: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
|
|
5985
6140
|
user: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
|
|
6141
|
+
obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
|
|
5986
6142
|
reserved: "200000000000000000000",
|
|
5987
6143
|
block_number: 21345678
|
|
5988
6144
|
};
|
|
@@ -5999,6 +6155,12 @@ __decorate([ApiProperty({
|
|
|
5999
6155
|
type: "string",
|
|
6000
6156
|
example: positionExample.user
|
|
6001
6157
|
})], PositionListItemResponse.prototype, "user", void 0);
|
|
6158
|
+
__decorate([ApiProperty({
|
|
6159
|
+
type: "string",
|
|
6160
|
+
nullable: true,
|
|
6161
|
+
example: positionExample.obligation_id,
|
|
6162
|
+
description: "Obligation id this reserved amount belongs to, or null if no lots exist."
|
|
6163
|
+
})], PositionListItemResponse.prototype, "obligation_id", void 0);
|
|
6002
6164
|
__decorate([ApiProperty({
|
|
6003
6165
|
type: "string",
|
|
6004
6166
|
example: positionExample.reserved
|
|
@@ -6026,7 +6188,7 @@ __decorate([ApiProperty({
|
|
|
6026
6188
|
})], BookListResponse.prototype, "cursor", void 0);
|
|
6027
6189
|
__decorate([ApiProperty({
|
|
6028
6190
|
type: () => [BookLevelResponse],
|
|
6029
|
-
description: "Aggregated book levels grouped by
|
|
6191
|
+
description: "Aggregated book levels grouped by offer tick."
|
|
6030
6192
|
})], BookListResponse.prototype, "data", void 0);
|
|
6031
6193
|
let BooksController = class BooksController {
|
|
6032
6194
|
async getBook() {}
|
|
@@ -6036,7 +6198,7 @@ __decorate([
|
|
|
6036
6198
|
methods: ["get"],
|
|
6037
6199
|
path: "/v1/books/{obligationId}/{side}",
|
|
6038
6200
|
summary: "Get aggregated book",
|
|
6039
|
-
description: "Returns aggregated book data for a given obligation and side. Offers are grouped by
|
|
6201
|
+
description: "Returns aggregated book data for a given obligation and side. Offers are grouped by tick with summed takeable amounts, and each level includes the corresponding wad-scaled price. Book levels are sorted by tick (ascending for sell side, descending for buy side)."
|
|
6040
6202
|
}),
|
|
6041
6203
|
ApiParam({
|
|
6042
6204
|
name: "obligationId",
|
|
@@ -6061,7 +6223,7 @@ __decorate([
|
|
|
6061
6223
|
name: "limit",
|
|
6062
6224
|
type: "number",
|
|
6063
6225
|
example: 10,
|
|
6064
|
-
description: "Maximum number of
|
|
6226
|
+
description: "Maximum number of tick levels to return."
|
|
6065
6227
|
}),
|
|
6066
6228
|
ApiResponse({
|
|
6067
6229
|
status: 200,
|
|
@@ -6255,6 +6417,11 @@ const configRulesLoanTokenExample = {
|
|
|
6255
6417
|
chain_id: 1,
|
|
6256
6418
|
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
6257
6419
|
};
|
|
6420
|
+
const configRulesCollateralTokenExample = {
|
|
6421
|
+
type: "collateral_token",
|
|
6422
|
+
chain_id: 1,
|
|
6423
|
+
address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
6424
|
+
};
|
|
6258
6425
|
const configRulesOracleExample = {
|
|
6259
6426
|
type: "oracle",
|
|
6260
6427
|
chain_id: 1,
|
|
@@ -6264,6 +6431,7 @@ const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
|
|
|
6264
6431
|
const configRulesPayloadExample = [
|
|
6265
6432
|
configRulesMaturityExample,
|
|
6266
6433
|
configRulesLoanTokenExample,
|
|
6434
|
+
configRulesCollateralTokenExample,
|
|
6267
6435
|
configRulesOracleExample
|
|
6268
6436
|
];
|
|
6269
6437
|
const configContractNames = [
|
|
@@ -6390,7 +6558,7 @@ __decorate([
|
|
|
6390
6558
|
methods: ["get"],
|
|
6391
6559
|
path: "/v1/config/rules",
|
|
6392
6560
|
summary: "Get config rules",
|
|
6393
|
-
description: "Returns configured rules (maturities, loan tokens, oracles) for supported chains."
|
|
6561
|
+
description: "Returns configured rules (maturities, loan tokens, collateral tokens, oracles) for supported chains."
|
|
6394
6562
|
}),
|
|
6395
6563
|
ApiQuery({
|
|
6396
6564
|
name: "cursor",
|
|
@@ -6410,7 +6578,7 @@ __decorate([
|
|
|
6410
6578
|
name: "types",
|
|
6411
6579
|
type: ["string"],
|
|
6412
6580
|
required: false,
|
|
6413
|
-
example: "maturity,loan_token,oracle",
|
|
6581
|
+
example: "maturity,loan_token,collateral_token,oracle",
|
|
6414
6582
|
description: "Filter by rule types (comma-separated).",
|
|
6415
6583
|
style: "form",
|
|
6416
6584
|
explode: false
|
|
@@ -6440,13 +6608,13 @@ __decorate([
|
|
|
6440
6608
|
methods: ["get"],
|
|
6441
6609
|
path: "/v1/obligations",
|
|
6442
6610
|
summary: "List all obligations",
|
|
6443
|
-
description: "Returns a list of obligations with their current best ask and bid.
|
|
6611
|
+
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."
|
|
6444
6612
|
}),
|
|
6445
6613
|
ApiQuery({
|
|
6446
6614
|
name: "cursor",
|
|
6447
6615
|
type: "string",
|
|
6448
6616
|
example: obligationCursorExample,
|
|
6449
|
-
description: "
|
|
6617
|
+
description: "Pagination cursor in base64url-encoded format."
|
|
6450
6618
|
}),
|
|
6451
6619
|
ApiQuery({
|
|
6452
6620
|
name: "limit",
|
|
@@ -6490,6 +6658,15 @@ __decorate([
|
|
|
6490
6658
|
style: "form",
|
|
6491
6659
|
explode: false
|
|
6492
6660
|
}),
|
|
6661
|
+
ApiQuery({
|
|
6662
|
+
name: "sort",
|
|
6663
|
+
type: "string",
|
|
6664
|
+
required: false,
|
|
6665
|
+
example: "-ask,bid,maturity",
|
|
6666
|
+
description: "Sort order as comma-separated fields (`id`, `ask`, `bid`, `maturity`). Prefix with `-` for descending order. Max 3 fields.",
|
|
6667
|
+
style: "form",
|
|
6668
|
+
explode: false
|
|
6669
|
+
}),
|
|
6493
6670
|
ApiResponse({
|
|
6494
6671
|
status: 200,
|
|
6495
6672
|
description: "Success",
|
|
@@ -6528,7 +6705,7 @@ __decorate([
|
|
|
6528
6705
|
methods: ["get"],
|
|
6529
6706
|
path: "/v1/users/{userAddress}/positions",
|
|
6530
6707
|
summary: "Get user positions",
|
|
6531
|
-
description: "Returns positions for a user with reserved balance.
|
|
6708
|
+
description: "Returns positions for a user with reserved balance per obligation. Each (position, obligation) pair is returned as a separate row. Positions with no lots return a single row with obligation_id = null and reserved = 0."
|
|
6532
6709
|
}),
|
|
6533
6710
|
ApiParam({
|
|
6534
6711
|
name: "userAddress",
|
|
@@ -6616,6 +6793,7 @@ function from$2(position) {
|
|
|
6616
6793
|
chain_id: position.chainId,
|
|
6617
6794
|
contract: position.contract,
|
|
6618
6795
|
user: position.user,
|
|
6796
|
+
obligation_id: position.obligationId,
|
|
6619
6797
|
reserved: position.reserved.toString(),
|
|
6620
6798
|
block_number: position.blockNumber
|
|
6621
6799
|
};
|
|
@@ -6624,11 +6802,13 @@ function from$2(position) {
|
|
|
6624
6802
|
//#endregion
|
|
6625
6803
|
//#region src/api/Schema/requests.ts
|
|
6626
6804
|
const MAX_LIMIT = 100;
|
|
6627
|
-
const DEFAULT_LIMIT$
|
|
6805
|
+
const DEFAULT_LIMIT$5 = 20;
|
|
6806
|
+
const MAX_OBLIGATION_SORT_FIELDS = 3;
|
|
6628
6807
|
const CONFIG_RULES_MAX_LIMIT = 1e3;
|
|
6629
6808
|
const CONFIG_RULES_DEFAULT_LIMIT = 100;
|
|
6630
6809
|
const CONFIG_CONTRACTS_MAX_LIMIT = 1e3;
|
|
6631
6810
|
const CONFIG_CONTRACTS_DEFAULT_LIMIT = 1e3;
|
|
6811
|
+
const OBLIGATION_SORT_ENTRY_REGEX = /^-?(id|ask|bid|maturity)$/;
|
|
6632
6812
|
/** Validate cursor is a valid base64url-encoded JSON object.
|
|
6633
6813
|
* Domain layer handles semantic validation of cursor fields. */
|
|
6634
6814
|
function isValidBase64urlJson(val) {
|
|
@@ -6660,8 +6840,8 @@ const PaginationQueryParams = z$1.object({
|
|
|
6660
6840
|
description: "Pagination cursor in base64url-encoded format",
|
|
6661
6841
|
example: "eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ"
|
|
6662
6842
|
}),
|
|
6663
|
-
limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$
|
|
6664
|
-
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$
|
|
6843
|
+
limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$5).meta({
|
|
6844
|
+
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$5}`,
|
|
6665
6845
|
example: 10
|
|
6666
6846
|
})
|
|
6667
6847
|
});
|
|
@@ -6669,10 +6849,11 @@ const ConfigRuleTypes = z$1.enum([
|
|
|
6669
6849
|
"maturity",
|
|
6670
6850
|
"callback",
|
|
6671
6851
|
"loan_token",
|
|
6852
|
+
"collateral_token",
|
|
6672
6853
|
"oracle"
|
|
6673
6854
|
]);
|
|
6674
6855
|
const GetConfigRulesQueryParams = z$1.object({
|
|
6675
|
-
cursor: z$1.string().regex(/^(maturity|callback|loan_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
6856
|
+
cursor: z$1.string().regex(/^(maturity|callback|loan_token|collateral_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
6676
6857
|
description: "Pagination cursor in type:chain_id:<value> format",
|
|
6677
6858
|
example: "maturity:1:1730415600:end_of_next_month"
|
|
6678
6859
|
}),
|
|
@@ -6682,7 +6863,7 @@ const GetConfigRulesQueryParams = z$1.object({
|
|
|
6682
6863
|
}),
|
|
6683
6864
|
types: csvArray(ConfigRuleTypes).meta({
|
|
6684
6865
|
description: "Filter by rule types (comma-separated).",
|
|
6685
|
-
example: "maturity,loan_token,oracle"
|
|
6866
|
+
example: "maturity,loan_token,collateral_token,oracle"
|
|
6686
6867
|
}),
|
|
6687
6868
|
chains: csvArray(z$1.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
6688
6869
|
description: "Filter by chain IDs (comma-separated).",
|
|
@@ -6757,9 +6938,12 @@ const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend
|
|
|
6757
6938
|
});
|
|
6758
6939
|
const GetObligationsQueryParams = z$1.object({
|
|
6759
6940
|
...PaginationQueryParams.shape,
|
|
6760
|
-
cursor: z$1.string().optional().
|
|
6761
|
-
|
|
6762
|
-
|
|
6941
|
+
cursor: z$1.string().optional().refine((val) => {
|
|
6942
|
+
if (!val) return true;
|
|
6943
|
+
return isValidBase64urlJson(val);
|
|
6944
|
+
}, { message: "Invalid cursor format. Must be a valid base64url-encoded cursor object" }).meta({
|
|
6945
|
+
description: "Pagination cursor in base64url-encoded format.",
|
|
6946
|
+
example: "eyJzb3J0IjpbImlkIl0sImlkIjoiMHgxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAiLCJhc2siOiIwIiwiYmlkIjoiMCIsIm1hdHVyaXR5IjoxNzYxOTIyODAwfQ"
|
|
6763
6947
|
}),
|
|
6764
6948
|
chains: csvArray(z$1.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
6765
6949
|
description: "Filter by chain IDs (comma-separated).",
|
|
@@ -6776,18 +6960,35 @@ const GetObligationsQueryParams = z$1.object({
|
|
|
6776
6960
|
maturities: csvArray(z$1.string().regex(/^[1-9]\d*$/, { message: "Maturity must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
6777
6961
|
description: "Filter by exact maturity timestamps (comma-separated, unix seconds).",
|
|
6778
6962
|
example: "1761922800,1764524800"
|
|
6963
|
+
}),
|
|
6964
|
+
sort: csvArray(z$1.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) => {
|
|
6965
|
+
if (!entries) return;
|
|
6966
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6967
|
+
for (const entry of entries) {
|
|
6968
|
+
const field = entry.startsWith("-") ? entry.slice(1) : entry;
|
|
6969
|
+
if (seen.has(field)) {
|
|
6970
|
+
ctx.addIssue({
|
|
6971
|
+
code: "custom",
|
|
6972
|
+
message: `Duplicate sort field: ${field}`
|
|
6973
|
+
});
|
|
6974
|
+
return;
|
|
6975
|
+
}
|
|
6976
|
+
seen.add(field);
|
|
6977
|
+
}
|
|
6978
|
+
}).meta({
|
|
6979
|
+
description: "Sort order as comma-separated fields. Prefix a field with '-' for descending order. Max 3 fields.",
|
|
6980
|
+
example: "-ask,bid,maturity"
|
|
6779
6981
|
})
|
|
6780
6982
|
});
|
|
6781
6983
|
const GetObligationParams = z$1.object({ obligation_id: z$1.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({
|
|
6782
6984
|
description: "Obligation id",
|
|
6783
6985
|
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
6784
6986
|
}) });
|
|
6785
|
-
/** Validate a book cursor format: {side,
|
|
6987
|
+
/** Validate a book cursor format: {side, lastTick, offersCursor} */
|
|
6786
6988
|
function isValidBookCursor(cursorString) {
|
|
6787
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
6788
6989
|
try {
|
|
6789
6990
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
6790
|
-
return (v?.side === "buy" || v?.side === "sell") &&
|
|
6991
|
+
return (v?.side === "buy" || v?.side === "sell") && typeof v?.lastTick === "number" && Number.isInteger(v.lastTick) && (v?.offersCursor === null || typeof v?.offersCursor === "string");
|
|
6791
6992
|
} catch {
|
|
6792
6993
|
return false;
|
|
6793
6994
|
}
|
|
@@ -6800,8 +7001,8 @@ const BookPaginationQueryParams = z$1.object({
|
|
|
6800
7001
|
description: "Pagination cursor in base64url-encoded format for book levels",
|
|
6801
7002
|
example: "eyJzaWRlIjoiYnV5IiwibGFzdFJhdGUiOiIxMDAwMDAwMDAwMDAwMDAwMDAwIiwib2ZmZXJzQ3Vyc29yIjpudWxsfQ"
|
|
6802
7003
|
}),
|
|
6803
|
-
limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$
|
|
6804
|
-
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$
|
|
7004
|
+
limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(MAX_LIMIT, { message: `Limit cannot exceed ${MAX_LIMIT}` })).optional().default(DEFAULT_LIMIT$5).meta({
|
|
7005
|
+
description: `Limit maximum: ${MAX_LIMIT}. Default: ${DEFAULT_LIMIT$5}`,
|
|
6805
7006
|
example: 10
|
|
6806
7007
|
})
|
|
6807
7008
|
});
|
|
@@ -6885,7 +7086,7 @@ async function getBook(params, db) {
|
|
|
6885
7086
|
side: query.side,
|
|
6886
7087
|
levels_count: levels.length,
|
|
6887
7088
|
has_next_cursor: nextCursor != null,
|
|
6888
|
-
|
|
7089
|
+
first_level_tick: firstLevel?.tick ?? null,
|
|
6889
7090
|
first_level_assets: firstLevel?.assets.toString() ?? null,
|
|
6890
7091
|
first_level_count: firstLevel?.count ?? null
|
|
6891
7092
|
});
|
|
@@ -6978,7 +7179,7 @@ async function getConfigContracts(query, chainRegistry) {
|
|
|
6978
7179
|
}
|
|
6979
7180
|
function parseCursor$1(cursor) {
|
|
6980
7181
|
const [chain, address] = cursor.split(":", 2);
|
|
6981
|
-
if (!chain || !address) throw new BadRequestError("Cursor must be in the format chain_id:0x...");
|
|
7182
|
+
if (!chain || !address) throw new BadRequestError$1("Cursor must be in the format chain_id:0x...");
|
|
6982
7183
|
return {
|
|
6983
7184
|
chain_id: Number.parseInt(chain, 10),
|
|
6984
7185
|
address: address.toLowerCase()
|
|
@@ -7037,6 +7238,33 @@ const assets = {
|
|
|
7037
7238
|
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
7038
7239
|
]
|
|
7039
7240
|
};
|
|
7241
|
+
const collateralAssets = {
|
|
7242
|
+
[ChainId.ETHEREUM.toString()]: [
|
|
7243
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7244
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7245
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7246
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7247
|
+
],
|
|
7248
|
+
[ChainId.BASE.toString()]: [
|
|
7249
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
7250
|
+
"0x4200000000000000000000000000000000000006",
|
|
7251
|
+
"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
|
|
7252
|
+
"0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
|
|
7253
|
+
"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
|
|
7254
|
+
],
|
|
7255
|
+
[ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
|
|
7256
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7257
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7258
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7259
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7260
|
+
],
|
|
7261
|
+
[ChainId.ANVIL.toString()]: [
|
|
7262
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7263
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7264
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7265
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7266
|
+
]
|
|
7267
|
+
};
|
|
7040
7268
|
const oracles = {
|
|
7041
7269
|
[ChainId.ETHEREUM.toString()]: [
|
|
7042
7270
|
"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
|
|
@@ -7077,26 +7305,26 @@ const oracles = {
|
|
|
7077
7305
|
const configs = {
|
|
7078
7306
|
ethereum: {
|
|
7079
7307
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
7080
|
-
maturities: [MaturityType.
|
|
7308
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
7081
7309
|
},
|
|
7082
7310
|
base: {
|
|
7083
7311
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
7084
|
-
maturities: [MaturityType.
|
|
7312
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
7085
7313
|
},
|
|
7086
7314
|
"ethereum-virtual-testnet": {
|
|
7087
7315
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
7088
|
-
maturities: [MaturityType.
|
|
7316
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
7089
7317
|
},
|
|
7090
7318
|
anvil: {
|
|
7091
7319
|
callbacks: [{ type: Type$1.BuyWithEmptyCallback }, { type: Type$1.SellWithEmptyCallback }],
|
|
7092
|
-
maturities: [MaturityType.
|
|
7320
|
+
maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek]
|
|
7093
7321
|
}
|
|
7094
7322
|
};
|
|
7095
7323
|
|
|
7096
7324
|
//#endregion
|
|
7097
7325
|
//#region src/gatekeeper/ConfigRules.ts
|
|
7098
7326
|
/**
|
|
7099
|
-
* Build the configured rules (maturities + callback addresses + loan tokens + oracles) for the provided chains.
|
|
7327
|
+
* Build the configured rules (maturities + callback addresses + loan tokens + collateral tokens + oracles) for the provided chains.
|
|
7100
7328
|
* @param chains - Chains to include in the configured rules.
|
|
7101
7329
|
* @returns Sorted list of config rules.
|
|
7102
7330
|
*/
|
|
@@ -7116,6 +7344,12 @@ function buildConfigRules(chains) {
|
|
|
7116
7344
|
chain_id: chain.id,
|
|
7117
7345
|
address: normalizeAddress(address)
|
|
7118
7346
|
});
|
|
7347
|
+
const collateralTokens = collateralAssets[chain.id.toString()] ?? [];
|
|
7348
|
+
for (const address of collateralTokens) rules.push({
|
|
7349
|
+
type: "collateral_token",
|
|
7350
|
+
chain_id: chain.id,
|
|
7351
|
+
address: normalizeAddress(address)
|
|
7352
|
+
});
|
|
7119
7353
|
const oracles$2 = oracles[chain.id.toString()] ?? [];
|
|
7120
7354
|
for (const address of oracles$2) rules.push({
|
|
7121
7355
|
type: "oracle",
|
|
@@ -7143,6 +7377,10 @@ function buildConfigRulesChecksum(rules) {
|
|
|
7143
7377
|
hash.update(`callback:${rule.chain_id}:${rule.callback_type}:${rule.address}\n`);
|
|
7144
7378
|
continue;
|
|
7145
7379
|
}
|
|
7380
|
+
if (rule.type === "collateral_token") {
|
|
7381
|
+
hash.update(`collateral_token:${rule.chain_id}:${rule.address}\n`);
|
|
7382
|
+
continue;
|
|
7383
|
+
}
|
|
7146
7384
|
if (rule.type === "oracle") {
|
|
7147
7385
|
hash.update(`oracle:${rule.chain_id}:${rule.address}\n`);
|
|
7148
7386
|
continue;
|
|
@@ -7163,6 +7401,7 @@ function compareConfigRules(left, right) {
|
|
|
7163
7401
|
return left.address.localeCompare(right.address);
|
|
7164
7402
|
}
|
|
7165
7403
|
if (left.type === "loan_token" && right.type === "loan_token") return left.address.localeCompare(right.address);
|
|
7404
|
+
if (left.type === "collateral_token" && right.type === "collateral_token") return left.address.localeCompare(right.address);
|
|
7166
7405
|
if (left.type === "oracle" && right.type === "oracle") return left.address.localeCompare(right.address);
|
|
7167
7406
|
return 0;
|
|
7168
7407
|
}
|
|
@@ -7193,8 +7432,8 @@ async function getConfigRules(query, chains) {
|
|
|
7193
7432
|
} catch (err) {
|
|
7194
7433
|
return failure(err);
|
|
7195
7434
|
}
|
|
7196
|
-
if (cursorRule && typeFilter && !typeFilter.has(cursorRule.type)) return failure(new BadRequestError("Cursor type must match requested rule types"));
|
|
7197
|
-
if (cursorRule && chainFilter && !chainFilter.has(cursorRule.chain_id)) return failure(new BadRequestError("Cursor chain_id must match requested chains"));
|
|
7435
|
+
if (cursorRule && typeFilter && !typeFilter.has(cursorRule.type)) return failure(new BadRequestError$1("Cursor type must match requested rule types"));
|
|
7436
|
+
if (cursorRule && chainFilter && !chainFilter.has(cursorRule.chain_id)) return failure(new BadRequestError$1("Cursor chain_id must match requested chains"));
|
|
7198
7437
|
const startIndex = cursorRule ? findStartIndex(filteredRules, cursorRule) : 0;
|
|
7199
7438
|
const page = filteredRules.slice(startIndex, startIndex + limit);
|
|
7200
7439
|
const nextCursor = startIndex + limit < filteredRules.length && page.length > 0 ? formatCursor(page.at(-1)) : null;
|
|
@@ -7209,19 +7448,20 @@ function formatCursor(rule) {
|
|
|
7209
7448
|
if (rule.type === "maturity") return `maturity:${rule.chain_id}:${rule.timestamp}:${rule.name}`;
|
|
7210
7449
|
if (rule.type === "callback") return `callback:${rule.chain_id}:${rule.callback_type}:${rule.address.toLowerCase()}`;
|
|
7211
7450
|
if (rule.type === "oracle") return `oracle:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7451
|
+
if (rule.type === "collateral_token") return `collateral_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7212
7452
|
return `loan_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7213
7453
|
}
|
|
7214
7454
|
function parseCursor(cursor) {
|
|
7215
7455
|
const [type, chain, ...rest] = cursor.split(":");
|
|
7216
|
-
if (!type || !chain || rest.length === 0) throw new BadRequestError("Cursor must be in the format type:chain_id:<value>");
|
|
7217
|
-
if (!isConfigRuleType(type)) throw new BadRequestError("Cursor has an invalid rule type");
|
|
7456
|
+
if (!type || !chain || rest.length === 0) throw new BadRequestError$1("Cursor must be in the format type:chain_id:<value>");
|
|
7457
|
+
if (!isConfigRuleType(type)) throw new BadRequestError$1("Cursor has an invalid rule type");
|
|
7218
7458
|
const chain_id = Number.parseInt(chain, 10);
|
|
7219
|
-
if (!Number.isFinite(chain_id)) throw new BadRequestError("Cursor has an invalid chain_id");
|
|
7459
|
+
if (!Number.isFinite(chain_id)) throw new BadRequestError$1("Cursor has an invalid chain_id");
|
|
7220
7460
|
if (type === "maturity") {
|
|
7221
7461
|
const timestampValue = Number.parseInt(rest[0] ?? "", 10);
|
|
7222
7462
|
const nameValue = rest.slice(1).join(":");
|
|
7223
|
-
if (!Number.isFinite(timestampValue) || nameValue.length === 0) throw new BadRequestError("Cursor must be in the format maturity:chain_id:timestamp:name");
|
|
7224
|
-
if (!isMaturityType(nameValue)) throw new BadRequestError("Cursor has an invalid maturity name");
|
|
7463
|
+
if (!Number.isFinite(timestampValue) || nameValue.length === 0) throw new BadRequestError$1("Cursor must be in the format maturity:chain_id:timestamp:name");
|
|
7464
|
+
if (!isMaturityType(nameValue)) throw new BadRequestError$1("Cursor has an invalid maturity name");
|
|
7225
7465
|
return {
|
|
7226
7466
|
type,
|
|
7227
7467
|
chain_id,
|
|
@@ -7232,8 +7472,8 @@ function parseCursor(cursor) {
|
|
|
7232
7472
|
if (type === "callback") {
|
|
7233
7473
|
const callbackTypeValue = rest[0] ?? "";
|
|
7234
7474
|
const addressValue = rest.slice(1).join(":");
|
|
7235
|
-
if (!callbackTypeValue || !addressValue) throw new BadRequestError("Cursor must be in the format callback:chain_id:callback_type:address");
|
|
7236
|
-
if (!isCallbackType(callbackTypeValue)) throw new BadRequestError("Cursor has an invalid callback type");
|
|
7475
|
+
if (!callbackTypeValue || !addressValue) throw new BadRequestError$1("Cursor must be in the format callback:chain_id:callback_type:address");
|
|
7476
|
+
if (!isCallbackType(callbackTypeValue)) throw new BadRequestError$1("Cursor has an invalid callback type");
|
|
7237
7477
|
return {
|
|
7238
7478
|
type,
|
|
7239
7479
|
chain_id,
|
|
@@ -7241,16 +7481,16 @@ function parseCursor(cursor) {
|
|
|
7241
7481
|
address: parseAddress(addressValue, "Cursor address")
|
|
7242
7482
|
};
|
|
7243
7483
|
}
|
|
7244
|
-
if (type === "loan_token" || type === "oracle") {
|
|
7484
|
+
if (type === "loan_token" || type === "collateral_token" || type === "oracle") {
|
|
7245
7485
|
const addressValue = rest.join(":");
|
|
7246
|
-
if (!addressValue) throw new BadRequestError(`Cursor must be in the format ${type}:chain_id:address`);
|
|
7486
|
+
if (!addressValue) throw new BadRequestError$1(`Cursor must be in the format ${type}:chain_id:address`);
|
|
7247
7487
|
return {
|
|
7248
7488
|
type,
|
|
7249
7489
|
chain_id,
|
|
7250
7490
|
address: parseAddress(addressValue, "Cursor address")
|
|
7251
7491
|
};
|
|
7252
7492
|
}
|
|
7253
|
-
throw new BadRequestError("Cursor has an invalid rule type");
|
|
7493
|
+
throw new BadRequestError$1("Cursor has an invalid rule type");
|
|
7254
7494
|
}
|
|
7255
7495
|
function findStartIndex(rules, cursor) {
|
|
7256
7496
|
let low = 0;
|
|
@@ -7264,11 +7504,11 @@ function findStartIndex(rules, cursor) {
|
|
|
7264
7504
|
return low;
|
|
7265
7505
|
}
|
|
7266
7506
|
function parseAddress(address, label) {
|
|
7267
|
-
if (!/^0x[a-fA-F0-9]{40}$/.test(address)) throw new BadRequestError(`${label} must be a valid 20-byte address`);
|
|
7507
|
+
if (!/^0x[a-fA-F0-9]{40}$/.test(address)) throw new BadRequestError$1(`${label} must be a valid 20-byte address`);
|
|
7268
7508
|
return address.toLowerCase();
|
|
7269
7509
|
}
|
|
7270
7510
|
function isConfigRuleType(value) {
|
|
7271
|
-
return value === "maturity" || value === "callback" || value === "loan_token" || value === "oracle";
|
|
7511
|
+
return value === "maturity" || value === "callback" || value === "loan_token" || value === "collateral_token" || value === "oracle";
|
|
7272
7512
|
}
|
|
7273
7513
|
function isMaturityType(value) {
|
|
7274
7514
|
return Object.values(MaturityType).includes(value);
|
|
@@ -7277,7 +7517,7 @@ function parseMaturity(value) {
|
|
|
7277
7517
|
try {
|
|
7278
7518
|
return from$16(value);
|
|
7279
7519
|
} catch (err) {
|
|
7280
|
-
throw new BadRequestError(err instanceof Error ? err.message : "Invalid maturity timestamp");
|
|
7520
|
+
throw new BadRequestError$1(err instanceof Error ? err.message : "Invalid maturity timestamp");
|
|
7281
7521
|
}
|
|
7282
7522
|
}
|
|
7283
7523
|
function isCallbackType(value) {
|
|
@@ -7373,7 +7613,7 @@ async function getHealth(query, db, chainRegistry) {
|
|
|
7373
7613
|
try {
|
|
7374
7614
|
const parsed = safeParse("get_health", query);
|
|
7375
7615
|
if (!parsed.success) return failure(parsed.error);
|
|
7376
|
-
const snapshot = await create$
|
|
7616
|
+
const snapshot = await create$17({
|
|
7377
7617
|
db,
|
|
7378
7618
|
chainRegistry
|
|
7379
7619
|
}).getSnapshot();
|
|
@@ -7402,7 +7642,7 @@ async function getHealthChains(query, db, healthClients, chainRegistry) {
|
|
|
7402
7642
|
try {
|
|
7403
7643
|
const parsed = safeParse("get_health_chains", query);
|
|
7404
7644
|
if (!parsed.success) return failure(parsed.error);
|
|
7405
|
-
const snapshot = await create$
|
|
7645
|
+
const snapshot = await create$17({
|
|
7406
7646
|
db,
|
|
7407
7647
|
healthClients,
|
|
7408
7648
|
chainRegistry
|
|
@@ -7434,7 +7674,7 @@ async function getHealthCollectors(query, db, chainRegistry) {
|
|
|
7434
7674
|
try {
|
|
7435
7675
|
const parsed = safeParse("get_health_collectors", query);
|
|
7436
7676
|
if (!parsed.success) return failure(parsed.error);
|
|
7437
|
-
const snapshot = await create$
|
|
7677
|
+
const snapshot = await create$17({
|
|
7438
7678
|
db,
|
|
7439
7679
|
chainRegistry
|
|
7440
7680
|
}).getSnapshot();
|
|
@@ -7463,39 +7703,274 @@ async function getHealthCollectors(query, db, chainRegistry) {
|
|
|
7463
7703
|
}
|
|
7464
7704
|
}
|
|
7465
7705
|
|
|
7706
|
+
//#endregion
|
|
7707
|
+
//#region src/database/readers/ObligationsListing.ts
|
|
7708
|
+
const SORT_FIELDS = [
|
|
7709
|
+
"id",
|
|
7710
|
+
"ask",
|
|
7711
|
+
"bid",
|
|
7712
|
+
"maturity"
|
|
7713
|
+
];
|
|
7714
|
+
const CURSOR_ID_REGEX = /^0x[a-f0-9]{64}$/i;
|
|
7715
|
+
const INT32_MIN = -2147483648;
|
|
7716
|
+
const INT32_MAX = 2147483647;
|
|
7717
|
+
const INT32_MAX_BIGINT = BigInt(INT32_MAX);
|
|
7718
|
+
const MAX_CURSOR_SORT_FIELDS = 4;
|
|
7719
|
+
const DEFAULT_LIMIT$4 = 20;
|
|
7720
|
+
var BadRequestError = class extends Error {
|
|
7721
|
+
constructor(message) {
|
|
7722
|
+
super(message);
|
|
7723
|
+
this.name = "ObligationsListingBadRequestError";
|
|
7724
|
+
}
|
|
7725
|
+
};
|
|
7726
|
+
/**
|
|
7727
|
+
* Creates the obligations listing reader facade.
|
|
7728
|
+
* @param parameters - Reader dependencies.
|
|
7729
|
+
* @returns Obligations listing reader.
|
|
7730
|
+
*/
|
|
7731
|
+
function create$16(parameters) {
|
|
7732
|
+
const { db } = parameters;
|
|
7733
|
+
return { list: async (queryParameters) => {
|
|
7734
|
+
const { ids, chainId: chainIds, loanToken: loanTokens, collateralToken: collateralTokens, maturity: maturities, sort: sortTokens, cursor: encodedCursor, limit: requestedLimit } = queryParameters ?? {};
|
|
7735
|
+
const limit = requestedLimit ?? DEFAULT_LIMIT$4;
|
|
7736
|
+
if (!Number.isInteger(limit) || limit <= 0) throw new BadRequestError("Limit must be a positive integer");
|
|
7737
|
+
const cursorPayload = encodedCursor ? decodeCursorPayload(encodedCursor) : void 0;
|
|
7738
|
+
const requestedSort = normalizeSort(sortTokens);
|
|
7739
|
+
const cursorSort = cursorPayload ? normalizeSort(cursorPayload.sort) : void 0;
|
|
7740
|
+
if (cursorSort !== void 0 && sortTokens !== void 0 && !hasSameSort(requestedSort, cursorSort)) throw new BadRequestError("Cursor sort does not match requested sort");
|
|
7741
|
+
const sort = sortTokens !== void 0 ? requestedSort : cursorSort ?? requestedSort;
|
|
7742
|
+
const cursorValues = cursorPayload ? cursorValuesFromPayload(cursorPayload) : void 0;
|
|
7743
|
+
const now$3 = now();
|
|
7744
|
+
const loanTokenFilter = loanTokens !== void 0 && loanTokens.length > 0 ? sql`(${sql.join(loanTokens.map((token) => sql`LOWER(${obligations.loanToken}) = ${token.toLowerCase()}`), sql` OR `)})` : void 0;
|
|
7745
|
+
const collateralFilter = collateralTokens !== void 0 && collateralTokens.length > 0 ? sql`EXISTS (
|
|
7746
|
+
SELECT 1 FROM ${obligationCollateralsV2} oc
|
|
7747
|
+
WHERE oc.obligation_id = ${obligations.obligationId}
|
|
7748
|
+
AND (${sql.join(collateralTokens.map((token) => sql`LOWER(oc.asset) = ${token.toLowerCase()}`), sql` OR `)})
|
|
7749
|
+
)` : void 0;
|
|
7750
|
+
const bestAskTick = db.select({ askTick: offers.tick }).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(eq(offers.obligationId, obligations.obligationId), eq(offers.buy, false), gte(offers.expiry, now$3), gte(offers.maturity, now$3), lte(offers.start, now$3), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(desc(offers.tick)).limit(1).as("best_ask_tick");
|
|
7751
|
+
const bestBidTick = db.select({ bidTick: offers.tick }).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(eq(offers.obligationId, obligations.obligationId), eq(offers.buy, true), gte(offers.expiry, now$3), gte(offers.maturity, now$3), lte(offers.start, now$3), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(asc(offers.tick)).limit(1).as("best_bid_tick");
|
|
7752
|
+
const obligationsWithQuotes = db.select({
|
|
7753
|
+
obligationId: obligations.obligationId,
|
|
7754
|
+
chainId: obligations.chainId,
|
|
7755
|
+
loanToken: obligations.loanToken,
|
|
7756
|
+
collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${oracles$1.address}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
7757
|
+
maturity: obligations.maturity,
|
|
7758
|
+
askTick: sql`MAX(${bestAskTick.askTick})`.as("ask_tick"),
|
|
7759
|
+
bidTick: sql`MAX(${bestBidTick.bidTick})`.as("bid_tick"),
|
|
7760
|
+
ask: sql`COALESCE(MAX(${bestAskTick.askTick}) + 1, 0)`.as("ask"),
|
|
7761
|
+
bid: sql`COALESCE(MAX(${bestBidTick.bidTick}) + 1, 0)`.as("bid")
|
|
7762
|
+
}).from(obligations).innerJoin(obligationCollateralsV2, eq(obligations.obligationId, obligationCollateralsV2.obligationId)).innerJoin(oracles$1, sql`${obligationCollateralsV2.oracleChainId} = ${oracles$1.chainId}
|
|
7763
|
+
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).leftJoinLateral(bestAskTick, sql`true`).leftJoinLateral(bestBidTick, sql`true`).groupBy(obligations.obligationId).where(and(ids !== void 0 && ids.length > 0 ? inArray(obligations.obligationId, ids) : void 0, chainIds !== void 0 && chainIds.length > 0 ? inArray(obligations.chainId, chainIds) : void 0, loanTokenFilter, maturities !== void 0 && maturities.length > 0 ? inArray(obligations.maturity, maturities) : gte(obligations.maturity, now$3), collateralFilter)).as("obligations_with_quotes");
|
|
7764
|
+
const sortColumns = {
|
|
7765
|
+
id: obligationsWithQuotes.obligationId,
|
|
7766
|
+
ask: obligationsWithQuotes.ask,
|
|
7767
|
+
bid: obligationsWithQuotes.bid,
|
|
7768
|
+
maturity: obligationsWithQuotes.maturity
|
|
7769
|
+
};
|
|
7770
|
+
const rows = await db.select({
|
|
7771
|
+
obligationId: obligationsWithQuotes.obligationId,
|
|
7772
|
+
chainId: obligationsWithQuotes.chainId,
|
|
7773
|
+
loanToken: obligationsWithQuotes.loanToken,
|
|
7774
|
+
collaterals: obligationsWithQuotes.collaterals,
|
|
7775
|
+
maturity: obligationsWithQuotes.maturity,
|
|
7776
|
+
askTick: obligationsWithQuotes.askTick,
|
|
7777
|
+
bidTick: obligationsWithQuotes.bidTick,
|
|
7778
|
+
ask: obligationsWithQuotes.ask,
|
|
7779
|
+
bid: obligationsWithQuotes.bid
|
|
7780
|
+
}).from(obligationsWithQuotes).where(buildCursorFilter(sortColumns, sort, cursorValues)).orderBy(...buildOrderBy(sortColumns, sort)).limit(limit + 1);
|
|
7781
|
+
const hasMore = rows.length > limit;
|
|
7782
|
+
const listedRows = (hasMore ? rows.slice(0, limit) : rows).map((row) => {
|
|
7783
|
+
return {
|
|
7784
|
+
obligation: from$15({
|
|
7785
|
+
chainId: row.chainId,
|
|
7786
|
+
loanToken: row.loanToken,
|
|
7787
|
+
collaterals: row.collaterals.sort((left, right) => left.asset.localeCompare(right.asset)).map((collateral) => from$17({
|
|
7788
|
+
asset: collateral.asset,
|
|
7789
|
+
oracle: collateral.oracle,
|
|
7790
|
+
lltv: from$18(BigInt(collateral.lltv))
|
|
7791
|
+
})),
|
|
7792
|
+
maturity: row.maturity
|
|
7793
|
+
}),
|
|
7794
|
+
quote: from$11({
|
|
7795
|
+
obligationId: row.obligationId,
|
|
7796
|
+
ask: { tick: row.askTick },
|
|
7797
|
+
bid: { tick: row.bidTick }
|
|
7798
|
+
}),
|
|
7799
|
+
cursorValues: {
|
|
7800
|
+
id: row.obligationId,
|
|
7801
|
+
ask: toBigInt(row.ask),
|
|
7802
|
+
bid: toBigInt(row.bid),
|
|
7803
|
+
maturity: row.maturity
|
|
7804
|
+
}
|
|
7805
|
+
};
|
|
7806
|
+
});
|
|
7807
|
+
const nextCursor = hasMore && listedRows.length > 0 ? encodeCursorPayload({
|
|
7808
|
+
sort: sortToTokens(sort),
|
|
7809
|
+
id: listedRows[listedRows.length - 1].cursorValues.id,
|
|
7810
|
+
ask: listedRows[listedRows.length - 1].cursorValues.ask.toString(),
|
|
7811
|
+
bid: listedRows[listedRows.length - 1].cursorValues.bid.toString(),
|
|
7812
|
+
maturity: listedRows[listedRows.length - 1].cursorValues.maturity
|
|
7813
|
+
}) : null;
|
|
7814
|
+
return {
|
|
7815
|
+
obligations: listedRows.map((row) => ({
|
|
7816
|
+
obligation: row.obligation,
|
|
7817
|
+
quote: row.quote
|
|
7818
|
+
})),
|
|
7819
|
+
nextCursor
|
|
7820
|
+
};
|
|
7821
|
+
} };
|
|
7822
|
+
}
|
|
7823
|
+
function isSortField(value) {
|
|
7824
|
+
return SORT_FIELDS.includes(value);
|
|
7825
|
+
}
|
|
7826
|
+
function parseSortToken(token) {
|
|
7827
|
+
const direction = token.startsWith("-") ? "desc" : "asc";
|
|
7828
|
+
const rawField = token.startsWith("-") ? token.slice(1) : token;
|
|
7829
|
+
if (!isSortField(rawField)) throw new BadRequestError(`Invalid sort field: ${rawField}`);
|
|
7830
|
+
return {
|
|
7831
|
+
field: rawField,
|
|
7832
|
+
direction
|
|
7833
|
+
};
|
|
7834
|
+
}
|
|
7835
|
+
function normalizeSort(sortTokens) {
|
|
7836
|
+
const parsed = sortTokens?.length ? sortTokens.map(parseSortToken) : [{
|
|
7837
|
+
field: "id",
|
|
7838
|
+
direction: "asc"
|
|
7839
|
+
}];
|
|
7840
|
+
return parsed.some((entry) => entry.field === "id") ? parsed : [...parsed, {
|
|
7841
|
+
field: "id",
|
|
7842
|
+
direction: "asc"
|
|
7843
|
+
}];
|
|
7844
|
+
}
|
|
7845
|
+
function sortToTokens(sortEntries) {
|
|
7846
|
+
return sortEntries.map((entry) => entry.direction === "desc" ? `-${entry.field}` : entry.field);
|
|
7847
|
+
}
|
|
7848
|
+
function hasSameSort(left, right) {
|
|
7849
|
+
if (left.length !== right.length) return false;
|
|
7850
|
+
return left.every((sortEntry, index) => sortEntry.field === right[index]?.field && sortEntry.direction === right[index]?.direction);
|
|
7851
|
+
}
|
|
7852
|
+
function decodeCursorPayload(cursor) {
|
|
7853
|
+
let decoded;
|
|
7854
|
+
try {
|
|
7855
|
+
decoded = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
7856
|
+
} catch {
|
|
7857
|
+
throw new BadRequestError("Invalid cursor format");
|
|
7858
|
+
}
|
|
7859
|
+
if (decoded === null || typeof decoded !== "object") throw new BadRequestError("Invalid cursor payload");
|
|
7860
|
+
const payload = decoded;
|
|
7861
|
+
const sortTokens = parseCursorSortTokens(payload.sort);
|
|
7862
|
+
if (typeof payload.id !== "string" || !CURSOR_ID_REGEX.test(payload.id)) throw new BadRequestError("Invalid cursor obligation id");
|
|
7863
|
+
const ask = parseCursorNonNegativeInt32(payload.ask, "ask");
|
|
7864
|
+
const bid = parseCursorNonNegativeInt32(payload.bid, "bid");
|
|
7865
|
+
if (!isInt32(payload.maturity)) throw new BadRequestError("Invalid cursor maturity value");
|
|
7866
|
+
return {
|
|
7867
|
+
sort: sortTokens,
|
|
7868
|
+
id: payload.id,
|
|
7869
|
+
ask,
|
|
7870
|
+
bid,
|
|
7871
|
+
maturity: payload.maturity
|
|
7872
|
+
};
|
|
7873
|
+
}
|
|
7874
|
+
function parseCursorSortTokens(value) {
|
|
7875
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > MAX_CURSOR_SORT_FIELDS) throw new BadRequestError("Invalid cursor sort");
|
|
7876
|
+
const sortEntries = value.map((token) => {
|
|
7877
|
+
if (typeof token !== "string") throw new BadRequestError("Invalid cursor sort");
|
|
7878
|
+
try {
|
|
7879
|
+
return parseSortToken(token);
|
|
7880
|
+
} catch {
|
|
7881
|
+
throw new BadRequestError("Invalid cursor sort");
|
|
7882
|
+
}
|
|
7883
|
+
});
|
|
7884
|
+
if (new Set(sortEntries.map((entry) => entry.field)).size !== sortEntries.length) throw new BadRequestError("Invalid cursor sort");
|
|
7885
|
+
return sortToTokens(sortEntries);
|
|
7886
|
+
}
|
|
7887
|
+
function parseCursorNonNegativeInt32(value, field) {
|
|
7888
|
+
if (typeof value !== "string" || !/^\d+$/.test(value)) throw new BadRequestError(`Invalid cursor ${field} value`);
|
|
7889
|
+
if (BigInt(value) > INT32_MAX_BIGINT) throw new BadRequestError(`Invalid cursor ${field} value`);
|
|
7890
|
+
return value;
|
|
7891
|
+
}
|
|
7892
|
+
function isInt32(value) {
|
|
7893
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= INT32_MIN && value <= INT32_MAX;
|
|
7894
|
+
}
|
|
7895
|
+
function encodeCursorPayload(payload) {
|
|
7896
|
+
return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
7897
|
+
}
|
|
7898
|
+
function cursorValuesFromPayload(payload) {
|
|
7899
|
+
return {
|
|
7900
|
+
id: payload.id,
|
|
7901
|
+
ask: BigInt(payload.ask),
|
|
7902
|
+
bid: BigInt(payload.bid),
|
|
7903
|
+
maturity: payload.maturity
|
|
7904
|
+
};
|
|
7905
|
+
}
|
|
7906
|
+
function cursorComparisonValue(cursorValues, field) {
|
|
7907
|
+
switch (field) {
|
|
7908
|
+
case "id": return cursorValues.id;
|
|
7909
|
+
case "maturity": return cursorValues.maturity;
|
|
7910
|
+
case "ask": return cursorValues.ask.toString();
|
|
7911
|
+
case "bid": return cursorValues.bid.toString();
|
|
7912
|
+
}
|
|
7913
|
+
}
|
|
7914
|
+
function buildCursorFilter(columns, sortEntries, cursorValues) {
|
|
7915
|
+
if (cursorValues === void 0) return void 0;
|
|
7916
|
+
const comparisons = sortEntries.map((sortEntry, index) => {
|
|
7917
|
+
const equals = sortEntries.slice(0, index).map((previous) => {
|
|
7918
|
+
return sql`${columns[previous.field]} = ${cursorComparisonValue(cursorValues, previous.field)}`;
|
|
7919
|
+
});
|
|
7920
|
+
const comparison = sortEntry.direction === "asc" ? sql`${columns[sortEntry.field]} > ${cursorComparisonValue(cursorValues, sortEntry.field)}` : sql`${columns[sortEntry.field]} < ${cursorComparisonValue(cursorValues, sortEntry.field)}`;
|
|
7921
|
+
return equals.length > 0 ? sql`(${sql.join([...equals, comparison], sql` AND `)})` : sql`(${comparison})`;
|
|
7922
|
+
});
|
|
7923
|
+
return comparisons.length > 0 ? sql`(${sql.join(comparisons, sql` OR `)})` : void 0;
|
|
7924
|
+
}
|
|
7925
|
+
function buildOrderBy(columns, sortEntries) {
|
|
7926
|
+
return sortEntries.map((sortEntry) => sortEntry.direction === "asc" ? asc(columns[sortEntry.field]) : desc(columns[sortEntry.field]));
|
|
7927
|
+
}
|
|
7928
|
+
function toBigInt(value) {
|
|
7929
|
+
if (typeof value === "bigint") return value;
|
|
7930
|
+
if (typeof value === "number") return BigInt(value);
|
|
7931
|
+
return BigInt(value.split(".")[0] ?? "0");
|
|
7932
|
+
}
|
|
7933
|
+
|
|
7466
7934
|
//#endregion
|
|
7467
7935
|
//#region src/api/Controllers/getObligation.ts
|
|
7936
|
+
function toPayloadError$1(err) {
|
|
7937
|
+
if (err instanceof BadRequestError) return new BadRequestError$1(err.message);
|
|
7938
|
+
return err;
|
|
7939
|
+
}
|
|
7468
7940
|
async function getObligation(params, db) {
|
|
7469
7941
|
const logger = getLogger();
|
|
7470
7942
|
const result = safeParse("get_obligation", params, (issue) => issue.message);
|
|
7471
7943
|
if (!result.success) return failure(result.error);
|
|
7472
7944
|
const query = result.data;
|
|
7473
7945
|
try {
|
|
7474
|
-
const
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7946
|
+
const listing = await db.readers.obligations.list({
|
|
7947
|
+
ids: [query.obligation_id],
|
|
7948
|
+
limit: 1
|
|
7949
|
+
});
|
|
7950
|
+
if (listing.obligations.length === 0) return failure(new NotFoundError("Obligation not found"));
|
|
7951
|
+
const obligation = listing.obligations[0];
|
|
7478
7952
|
return success({
|
|
7479
|
-
data: from$4(obligation, quote
|
|
7480
|
-
obligationId: id(obligation),
|
|
7481
|
-
ask: { price: 0n },
|
|
7482
|
-
bid: { price: 0n }
|
|
7483
|
-
}),
|
|
7953
|
+
data: from$4(obligation.obligation, obligation.quote),
|
|
7484
7954
|
cursor: null
|
|
7485
7955
|
});
|
|
7486
7956
|
} catch (err) {
|
|
7957
|
+
const payloadError = toPayloadError$1(err);
|
|
7487
7958
|
logger.error({
|
|
7488
|
-
err,
|
|
7959
|
+
err: payloadError,
|
|
7489
7960
|
msg: "Error get obligation",
|
|
7490
|
-
errorMessage:
|
|
7491
|
-
errorStack:
|
|
7961
|
+
errorMessage: payloadError instanceof Error ? payloadError.message : String(payloadError),
|
|
7962
|
+
errorStack: payloadError instanceof Error ? payloadError.stack : void 0
|
|
7492
7963
|
});
|
|
7493
|
-
return failure(
|
|
7964
|
+
return failure(payloadError);
|
|
7494
7965
|
}
|
|
7495
7966
|
}
|
|
7496
7967
|
|
|
7497
7968
|
//#endregion
|
|
7498
7969
|
//#region src/api/Controllers/getObligations.ts
|
|
7970
|
+
function toPayloadError(err) {
|
|
7971
|
+
if (err instanceof BadRequestError) return new BadRequestError$1(err.message);
|
|
7972
|
+
return err;
|
|
7973
|
+
}
|
|
7499
7974
|
async function getObligations$1(queryParameters, db) {
|
|
7500
7975
|
const logger = getLogger();
|
|
7501
7976
|
const result = safeParse("get_obligations", queryParameters, (issue) => issue.message);
|
|
@@ -7506,31 +7981,28 @@ async function getObligations$1(queryParameters, db) {
|
|
|
7506
7981
|
const loanTokens = query.loan_tokens?.length ? query.loan_tokens : void 0;
|
|
7507
7982
|
const collateralTokens = query.collateral_tokens?.length ? query.collateral_tokens : void 0;
|
|
7508
7983
|
const maturities = query.maturities?.length ? query.maturities : void 0;
|
|
7509
|
-
const
|
|
7510
|
-
cursor: query.cursor,
|
|
7511
|
-
limit: query.limit,
|
|
7984
|
+
const listing = await db.readers.obligations.list({
|
|
7512
7985
|
chainId: chainIds,
|
|
7513
7986
|
loanToken: loanTokens,
|
|
7514
7987
|
collateralToken: collateralTokens,
|
|
7515
|
-
maturity: maturities
|
|
7988
|
+
maturity: maturities,
|
|
7989
|
+
sort: query.sort,
|
|
7990
|
+
cursor: query.cursor,
|
|
7991
|
+
limit: query.limit
|
|
7516
7992
|
});
|
|
7517
|
-
const quotes = await db.offers.getQuotes({ obligationIds: obligations.map((o) => id(o)) });
|
|
7518
7993
|
return success({
|
|
7519
|
-
data: obligations.map((
|
|
7520
|
-
|
|
7521
|
-
ask: { price: 0n },
|
|
7522
|
-
bid: { price: 0n }
|
|
7523
|
-
})),
|
|
7524
|
-
cursor: nextCursor ?? null
|
|
7994
|
+
data: listing.obligations.map((item) => from$4(item.obligation, item.quote)),
|
|
7995
|
+
cursor: listing.nextCursor
|
|
7525
7996
|
});
|
|
7526
7997
|
} catch (err) {
|
|
7998
|
+
const payloadError = toPayloadError(err);
|
|
7527
7999
|
logger.error({
|
|
7528
|
-
err,
|
|
8000
|
+
err: payloadError,
|
|
7529
8001
|
msg: "Error get obligations",
|
|
7530
|
-
errorMessage:
|
|
7531
|
-
errorStack:
|
|
8002
|
+
errorMessage: payloadError instanceof Error ? payloadError.message : String(payloadError),
|
|
8003
|
+
errorStack: payloadError instanceof Error ? payloadError.stack : void 0
|
|
7532
8004
|
});
|
|
7533
|
-
return failure(
|
|
8005
|
+
return failure(payloadError);
|
|
7534
8006
|
}
|
|
7535
8007
|
}
|
|
7536
8008
|
|
|
@@ -7564,6 +8036,7 @@ function create$15(config) {
|
|
|
7564
8036
|
groupMaker: offer.maker.toLowerCase(),
|
|
7565
8037
|
callbackAddress: offer.callback.address.toLowerCase(),
|
|
7566
8038
|
callbackData: offer.callback.data,
|
|
8039
|
+
receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller.toLowerCase(),
|
|
7567
8040
|
blockNumber
|
|
7568
8041
|
})));
|
|
7569
8042
|
if (offersRows.length === 0) return [];
|
|
@@ -7615,7 +8088,7 @@ function create$15(config) {
|
|
|
7615
8088
|
assets: offers.assets,
|
|
7616
8089
|
obligationUnits: offers.obligationUnits,
|
|
7617
8090
|
obligationShares: offers.obligationShares,
|
|
7618
|
-
|
|
8091
|
+
tick: offers.tick,
|
|
7619
8092
|
maturity: offers.maturity,
|
|
7620
8093
|
expiry: offers.expiry,
|
|
7621
8094
|
start: offers.start,
|
|
@@ -7626,16 +8099,18 @@ function create$15(config) {
|
|
|
7626
8099
|
loanToken: obligations.loanToken,
|
|
7627
8100
|
callbackAddress: offers.callbackAddress,
|
|
7628
8101
|
callbackData: offers.callbackData,
|
|
8102
|
+
receiverIfMakerIsSeller: offers.receiverIfMakerIsSeller,
|
|
7629
8103
|
collaterals: collateralsLateral.collaterals,
|
|
7630
8104
|
blockNumber: offers.blockNumber
|
|
7631
8105
|
}).from(offers).innerJoin(obligations, eq(offers.obligationId, obligations.obligationId)).innerJoinLateral(collateralsLateral, sql`true`).where(and(cursor !== null && cursor !== void 0 ? gt(offers.hash, cursor) : void 0, maker !== void 0 ? eq(offers.groupMaker, maker.toLowerCase()) : void 0)).orderBy(asc(offers.hash)).limit(limit)).map((row) => {
|
|
8106
|
+
const receiverIfMakerIsSeller = (row.receiverIfMakerIsSeller ?? row.maker).toLowerCase();
|
|
7632
8107
|
return {
|
|
7633
8108
|
hash: row.hash,
|
|
7634
8109
|
maker: row.maker,
|
|
7635
8110
|
assets: BigInt(row.assets),
|
|
7636
8111
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7637
8112
|
obligationShares: BigInt(row.obligationShares),
|
|
7638
|
-
|
|
8113
|
+
tick: row.tick,
|
|
7639
8114
|
maturity: from$16(row.maturity),
|
|
7640
8115
|
expiry: row.expiry,
|
|
7641
8116
|
start: row.start,
|
|
@@ -7653,6 +8128,7 @@ function create$15(config) {
|
|
|
7653
8128
|
address: row.callbackAddress,
|
|
7654
8129
|
data: row.callbackData
|
|
7655
8130
|
},
|
|
8131
|
+
receiverIfMakerIsSeller,
|
|
7656
8132
|
consumed: 0n,
|
|
7657
8133
|
available: 0n,
|
|
7658
8134
|
takeable: 0n,
|
|
@@ -7677,64 +8153,30 @@ function create$15(config) {
|
|
|
7677
8153
|
}
|
|
7678
8154
|
throw new Error("Invalid parameters");
|
|
7679
8155
|
},
|
|
7680
|
-
getObligations: async (parameters) => {
|
|
7681
|
-
const { ids, chainId: chainIds, loanToken: loanTokens, collateralToken: collateralTokens, maturity: maturities, cursor, limit = DEFAULT_LIMIT$3 } = parameters ?? {};
|
|
7682
|
-
const now$1 = now();
|
|
7683
|
-
const loanTokenFilter = loanTokens !== void 0 && loanTokens.length > 0 ? sql`(${sql.join(loanTokens.map((token) => sql`LOWER(${obligations.loanToken}) = ${token.toLowerCase()}`), sql` OR `)})` : void 0;
|
|
7684
|
-
const collateralFilter = collateralTokens !== void 0 && collateralTokens.length > 0 ? sql`EXISTS (
|
|
7685
|
-
SELECT 1 FROM ${obligationCollateralsV2} oc
|
|
7686
|
-
WHERE oc.obligation_id = ${obligations.obligationId}
|
|
7687
|
-
AND (${sql.join(collateralTokens.map((token) => sql`LOWER(oc.asset) = ${token.toLowerCase()}`), sql` OR `)})
|
|
7688
|
-
)` : void 0;
|
|
7689
|
-
const result = await db.select({
|
|
7690
|
-
obligationId: obligations.obligationId,
|
|
7691
|
-
chainId: obligations.chainId,
|
|
7692
|
-
loanToken: obligations.loanToken,
|
|
7693
|
-
collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${oracles$1.address}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
7694
|
-
maturity: obligations.maturity
|
|
7695
|
-
}).from(obligations).innerJoin(obligationCollateralsV2, eq(obligations.obligationId, obligationCollateralsV2.obligationId)).innerJoin(oracles$1, sql`${obligationCollateralsV2.oracleChainId} = ${oracles$1.chainId}
|
|
7696
|
-
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).groupBy(obligations.obligationId).where(and(cursor !== null && cursor !== void 0 ? gt(obligations.obligationId, cursor) : sql`true`, ids !== void 0 && ids.length > 0 ? inArray(obligations.obligationId, ids) : void 0, chainIds !== void 0 && chainIds.length > 0 ? inArray(obligations.chainId, chainIds) : void 0, loanTokenFilter, maturities !== void 0 && maturities.length > 0 ? inArray(obligations.maturity, maturities) : gte(obligations.maturity, now$1), collateralFilter)).orderBy(asc(obligations.obligationId)).limit(limit);
|
|
7697
|
-
const items = [];
|
|
7698
|
-
for (const row of result) items.push(from$15({
|
|
7699
|
-
chainId: row.chainId,
|
|
7700
|
-
loanToken: row.loanToken,
|
|
7701
|
-
collaterals: row.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)).map((c) => from$17({
|
|
7702
|
-
asset: c.asset,
|
|
7703
|
-
oracle: c.oracle,
|
|
7704
|
-
lltv: from$18(BigInt(c.lltv))
|
|
7705
|
-
})),
|
|
7706
|
-
maturity: row.maturity
|
|
7707
|
-
}));
|
|
7708
|
-
const returnedItems = Array.from(items.values());
|
|
7709
|
-
return {
|
|
7710
|
-
obligations: returnedItems,
|
|
7711
|
-
nextCursor: returnedItems.length === limit && returnedItems.length > 0 ? result[result.length - 1].obligationId : null
|
|
7712
|
-
};
|
|
7713
|
-
},
|
|
7714
8156
|
getQuotes: async (parameters) => {
|
|
7715
8157
|
const { obligationIds } = parameters;
|
|
7716
8158
|
if (obligationIds.length === 0) return [];
|
|
7717
8159
|
const now$2 = now();
|
|
7718
8160
|
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
7719
8161
|
obligationId: offers.obligationId,
|
|
7720
|
-
|
|
7721
|
-
}).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(inArray(offers.obligationId, obligationIds), eq(offers.buy, side === "buy"), gte(offers.expiry, now$2), gte(offers.maturity, now$2), lte(offers.start, now$2), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? sql`${offers.
|
|
8162
|
+
tick: offers.tick
|
|
8163
|
+
}).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(inArray(offers.obligationId, obligationIds), eq(offers.buy, side === "buy"), gte(offers.expiry, now$2), gte(offers.maturity, now$2), lte(offers.start, now$2), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? sql`${offers.tick} ASC` : sql`${offers.tick} DESC`);
|
|
7722
8164
|
const [bestBuys, bestSells] = await Promise.all([query({ side: "buy" }), query({ side: "sell" })]);
|
|
7723
8165
|
const quotes = /* @__PURE__ */ new Map();
|
|
7724
8166
|
for (const row of bestSells) quotes.set(row.obligationId, {
|
|
7725
|
-
ask: {
|
|
7726
|
-
bid: {
|
|
8167
|
+
ask: { tick: row.tick },
|
|
8168
|
+
bid: { tick: null }
|
|
7727
8169
|
});
|
|
7728
8170
|
for (const row of bestBuys) {
|
|
7729
8171
|
const quote = quotes.get(row.obligationId);
|
|
7730
8172
|
if (!quote) {
|
|
7731
8173
|
quotes.set(row.obligationId, {
|
|
7732
|
-
ask: {
|
|
7733
|
-
bid: {
|
|
8174
|
+
ask: { tick: null },
|
|
8175
|
+
bid: { tick: row.tick }
|
|
7734
8176
|
});
|
|
7735
8177
|
continue;
|
|
7736
8178
|
}
|
|
7737
|
-
quote.bid = {
|
|
8179
|
+
quote.bid = { tick: row.tick };
|
|
7738
8180
|
}
|
|
7739
8181
|
return Array.from(quotes.entries()).map(([id, quote]) => {
|
|
7740
8182
|
return from$11({
|
|
@@ -7834,7 +8276,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7834
8276
|
obligationUnits: offers.obligationUnits,
|
|
7835
8277
|
obligationShares: offers.obligationShares,
|
|
7836
8278
|
consumed: groups.consumed,
|
|
7837
|
-
|
|
8279
|
+
tick: offers.tick,
|
|
7838
8280
|
maturity: offers.maturity,
|
|
7839
8281
|
expiry: offers.expiry,
|
|
7840
8282
|
start: offers.start,
|
|
@@ -7845,6 +8287,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7845
8287
|
loanToken: obligations.loanToken,
|
|
7846
8288
|
callbackAddress: offers.callbackAddress,
|
|
7847
8289
|
callbackData: offers.callbackData,
|
|
8290
|
+
receiverIfMakerIsSeller: offers.receiverIfMakerIsSeller,
|
|
7848
8291
|
collaterals: collateralsLateral.collaterals,
|
|
7849
8292
|
blockNumber: offers.blockNumber,
|
|
7850
8293
|
available: sql`${availableExpr}::numeric`.as("available"),
|
|
@@ -7866,13 +8309,14 @@ async function getOffersQuery(db, parameters) {
|
|
|
7866
8309
|
)
|
|
7867
8310
|
END
|
|
7868
8311
|
) > 0` : void 0)).orderBy(asc(offers.hash)).limit(limit)).map((row) => {
|
|
8312
|
+
const receiverIfMakerIsSeller = (row.receiverIfMakerIsSeller ?? row.maker).toLowerCase();
|
|
7869
8313
|
return {
|
|
7870
8314
|
hash: row.hash,
|
|
7871
8315
|
maker: row.maker,
|
|
7872
8316
|
assets: BigInt(row.assets),
|
|
7873
8317
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7874
8318
|
obligationShares: BigInt(row.obligationShares),
|
|
7875
|
-
|
|
8319
|
+
tick: row.tick,
|
|
7876
8320
|
maturity: from$16(row.maturity),
|
|
7877
8321
|
expiry: row.expiry,
|
|
7878
8322
|
start: row.start,
|
|
@@ -7890,6 +8334,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7890
8334
|
address: row.callbackAddress,
|
|
7891
8335
|
data: row.callbackData
|
|
7892
8336
|
},
|
|
8337
|
+
receiverIfMakerIsSeller,
|
|
7893
8338
|
consumed: BigInt(row.consumed),
|
|
7894
8339
|
available: BigInt(String(row.available ?? "0").split(".")[0] ?? "0"),
|
|
7895
8340
|
takeable: BigInt(String(row.takeable ?? "0").split(".")[0] ?? "0"),
|
|
@@ -7980,7 +8425,7 @@ async function getUserPositions(queryParameters, db) {
|
|
|
7980
8425
|
async function validateOffers(body, gatekeeper) {
|
|
7981
8426
|
const logger = getLogger();
|
|
7982
8427
|
const result = safeParse("validate_offers", body, (issue) => issue.message);
|
|
7983
|
-
if (!result.success) return failure(new BadRequestError(result.error.issues[0]?.message ?? "Invalid request body"));
|
|
8428
|
+
if (!result.success) return failure(new BadRequestError$1(result.error.issues[0]?.message ?? "Invalid request body"));
|
|
7984
8429
|
const { offers: rawOffers } = result.data;
|
|
7985
8430
|
const parsedOffers = [];
|
|
7986
8431
|
const offerIndexByHash = /* @__PURE__ */ new Map();
|
|
@@ -7996,7 +8441,7 @@ async function validateOffers(body, gatekeeper) {
|
|
|
7996
8441
|
} catch (err) {
|
|
7997
8442
|
let message = err instanceof Error ? err.message : String(err);
|
|
7998
8443
|
if (err instanceof InvalidOfferError) message = err.formattedMessage;
|
|
7999
|
-
return failure(new BadRequestError(`Offer at index ${i} failed to parse: ${message}`));
|
|
8444
|
+
return failure(new BadRequestError$1(`Offer at index ${i} failed to parse: ${message}`));
|
|
8000
8445
|
}
|
|
8001
8446
|
}
|
|
8002
8447
|
try {
|
|
@@ -8271,7 +8716,7 @@ async function getOffers(apiClient, parameters) {
|
|
|
8271
8716
|
assets: offerData.assets,
|
|
8272
8717
|
obligation_units: offerData.obligation_units,
|
|
8273
8718
|
obligation_shares: offerData.obligation_shares,
|
|
8274
|
-
|
|
8719
|
+
tick: offerData.tick,
|
|
8275
8720
|
maturity: from$16(offerData.obligation.maturity),
|
|
8276
8721
|
expiry: offerData.expiry,
|
|
8277
8722
|
start: offerData.start,
|
|
@@ -8288,7 +8733,8 @@ async function getOffers(apiClient, parameters) {
|
|
|
8288
8733
|
callback: {
|
|
8289
8734
|
address: offerData.callback,
|
|
8290
8735
|
data: offerData.callback_data
|
|
8291
|
-
}
|
|
8736
|
+
},
|
|
8737
|
+
receiver_if_maker_is_seller: offerData.receiver_if_maker_is_seller
|
|
8292
8738
|
}),
|
|
8293
8739
|
hash: item.offer_hash,
|
|
8294
8740
|
consumed: BigInt(item.consumed),
|
|
@@ -8305,13 +8751,15 @@ async function getOffers(apiClient, parameters) {
|
|
|
8305
8751
|
};
|
|
8306
8752
|
}
|
|
8307
8753
|
async function getObligations(apiClient, parameters) {
|
|
8754
|
+
const sort = parameters?.sort?.length ? parameters.sort.join(",") : void 0;
|
|
8308
8755
|
const { data, error, response } = await apiClient.GET("/v1/obligations", { params: { query: {
|
|
8309
8756
|
cursor: parameters?.cursor,
|
|
8310
8757
|
limit: parameters?.limit,
|
|
8311
8758
|
chains: parameters?.chainIds,
|
|
8312
8759
|
loan_tokens: parameters?.loanTokens,
|
|
8313
8760
|
collateral_tokens: parameters?.collateralTokens,
|
|
8314
|
-
maturities: parameters?.maturities
|
|
8761
|
+
maturities: parameters?.maturities,
|
|
8762
|
+
sort
|
|
8315
8763
|
} } });
|
|
8316
8764
|
if (error !== void 0) {
|
|
8317
8765
|
switch (response.status) {
|
|
@@ -8335,10 +8783,10 @@ async function getObligations(apiClient, parameters) {
|
|
|
8335
8783
|
const { obligationId: _, ...returned } = {
|
|
8336
8784
|
id: () => id(obligation),
|
|
8337
8785
|
...obligation,
|
|
8338
|
-
...
|
|
8339
|
-
|
|
8340
|
-
ask: item.ask,
|
|
8341
|
-
bid: item.bid
|
|
8786
|
+
...from$11({
|
|
8787
|
+
obligationId: item.id,
|
|
8788
|
+
ask: { tick: item.ask.tick },
|
|
8789
|
+
bid: { tick: item.bid.tick }
|
|
8342
8790
|
})
|
|
8343
8791
|
};
|
|
8344
8792
|
return returned;
|
|
@@ -8630,6 +9078,7 @@ function create$12(config) {
|
|
|
8630
9078
|
return {
|
|
8631
9079
|
get: async (parameters) => {
|
|
8632
9080
|
const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT$2 } = parameters;
|
|
9081
|
+
const tickSortDirection = side === "sell" ? "asc" : "desc";
|
|
8633
9082
|
const inputCursor = LevelCursor.decode(cursorString, logger);
|
|
8634
9083
|
if (cursorString != null && inputCursor === null) return {
|
|
8635
9084
|
levels: [],
|
|
@@ -8644,23 +9093,23 @@ function create$12(config) {
|
|
|
8644
9093
|
cursor: inputCursor?.offersCursor ?? void 0,
|
|
8645
9094
|
limit: fetchLimit
|
|
8646
9095
|
});
|
|
8647
|
-
const
|
|
9096
|
+
const tickMap = /* @__PURE__ */ new Map();
|
|
8648
9097
|
for (const row of rows) {
|
|
8649
|
-
const
|
|
8650
|
-
const existing = priceMap.get(priceKey);
|
|
9098
|
+
const existing = tickMap.get(row.tick);
|
|
8651
9099
|
if (existing) {
|
|
8652
9100
|
existing.assets += row.takeable;
|
|
8653
9101
|
existing.count += 1;
|
|
8654
|
-
} else
|
|
9102
|
+
} else tickMap.set(row.tick, {
|
|
8655
9103
|
assets: row.takeable,
|
|
8656
9104
|
count: 1
|
|
8657
9105
|
});
|
|
8658
9106
|
}
|
|
8659
|
-
const levels = Array.from(
|
|
8660
|
-
|
|
8661
|
-
assets:
|
|
8662
|
-
count:
|
|
9107
|
+
const levels = Array.from(tickMap.entries()).map(([tick, level]) => ({
|
|
9108
|
+
tick,
|
|
9109
|
+
assets: level.assets,
|
|
9110
|
+
count: level.count
|
|
8663
9111
|
}));
|
|
9112
|
+
levels.sort((a, b) => tickSortDirection === "asc" ? a.tick - b.tick : b.tick - a.tick);
|
|
8664
9113
|
const paginatedLevels = levels.slice(0, limit);
|
|
8665
9114
|
const hasMore = levels.length > limit || offersNextCursor !== null;
|
|
8666
9115
|
const lastLevel = paginatedLevels[paginatedLevels.length - 1];
|
|
@@ -8706,14 +9155,14 @@ async function _getOffers(db, params) {
|
|
|
8706
9155
|
AND (s.code IS NULL OR s.code = ${Status.VALID})
|
|
8707
9156
|
ORDER BY
|
|
8708
9157
|
o.group_chain_id, o.group_maker, o."group_group",
|
|
8709
|
-
o.
|
|
9158
|
+
o.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`}, o.block_number ASC, o.assets DESC, o.hash ASC
|
|
8710
9159
|
),
|
|
8711
9160
|
enriched AS (
|
|
8712
9161
|
SELECT
|
|
8713
9162
|
w.*,
|
|
8714
9163
|
g.consumed, g.chain_id, obl.loan_token,
|
|
8715
9164
|
CASE WHEN ${priceSortDirection === "asc" ? sql`TRUE` : sql`FALSE`}
|
|
8716
|
-
THEN w.
|
|
9165
|
+
THEN w.tick ELSE -w.tick END AS tick_norm,
|
|
8717
9166
|
w.block_number AS block_norm,
|
|
8718
9167
|
-w.assets AS assets_norm,
|
|
8719
9168
|
w.hash AS hash_norm
|
|
@@ -8730,33 +9179,35 @@ async function _getOffers(db, params) {
|
|
|
8730
9179
|
FROM enriched e
|
|
8731
9180
|
${cursor != null ? sql`
|
|
8732
9181
|
WHERE
|
|
8733
|
-
(e.
|
|
9182
|
+
(e.tick_norm, e.block_norm, e.assets_norm, e.hash_norm)
|
|
8734
9183
|
> (
|
|
8735
9184
|
CASE WHEN ${priceSortDirection === "asc" ? sql`TRUE` : sql`FALSE`}
|
|
8736
|
-
THEN ${cursor.
|
|
9185
|
+
THEN ${cursor.tick}::integer ELSE -${cursor.tick}::integer END,
|
|
8737
9186
|
${cursor.blockNumber},
|
|
8738
9187
|
-${cursor.assets}::numeric,
|
|
8739
9188
|
${cursor.hash}
|
|
8740
9189
|
)` : sql``}
|
|
8741
|
-
ORDER BY e.
|
|
9190
|
+
ORDER BY e.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`}, e.block_number ASC, e.assets DESC, e.hash ASC
|
|
8742
9191
|
LIMIT ${limit}
|
|
8743
9192
|
),
|
|
8744
|
-
-- Compute sum of offsets per position
|
|
9193
|
+
-- Compute sum of offsets per position and obligation
|
|
8745
9194
|
position_offsets AS (
|
|
8746
9195
|
SELECT
|
|
8747
9196
|
chain_id,
|
|
8748
9197
|
"user",
|
|
8749
9198
|
contract,
|
|
9199
|
+
obligation_id,
|
|
8750
9200
|
SUM(value::numeric) AS total_offset
|
|
8751
9201
|
FROM ${offsets}
|
|
8752
|
-
GROUP BY chain_id, "user", contract
|
|
9202
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
8753
9203
|
),
|
|
8754
|
-
-- Compute position_consumed: sum of consumed from all groups with lots on each position (converted to lot terms)
|
|
9204
|
+
-- Compute position_consumed: sum of consumed from all groups with lots on each position+obligation (converted to lot terms)
|
|
8755
9205
|
position_consumed AS (
|
|
8756
9206
|
SELECT
|
|
8757
9207
|
l.chain_id,
|
|
8758
9208
|
l.contract,
|
|
8759
9209
|
l."user",
|
|
9210
|
+
l.obligation_id,
|
|
8760
9211
|
SUM(
|
|
8761
9212
|
CASE
|
|
8762
9213
|
WHEN wo.assets::numeric > 0
|
|
@@ -8773,7 +9224,7 @@ async function _getOffers(db, params) {
|
|
|
8773
9224
|
ON wo.group_chain_id = g.chain_id
|
|
8774
9225
|
AND LOWER(wo.group_maker) = LOWER(g.maker)
|
|
8775
9226
|
AND wo.group_group = g."group"
|
|
8776
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
9227
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
8777
9228
|
),
|
|
8778
9229
|
-- Compute callback contributions with lot balance
|
|
8779
9230
|
callback_contributions AS (
|
|
@@ -8781,7 +9232,7 @@ async function _getOffers(db, params) {
|
|
|
8781
9232
|
p.hash,
|
|
8782
9233
|
p.obligation_id,
|
|
8783
9234
|
p.assets,
|
|
8784
|
-
p.
|
|
9235
|
+
p.tick,
|
|
8785
9236
|
p.obligation_units,
|
|
8786
9237
|
p.obligation_shares,
|
|
8787
9238
|
p.maturity,
|
|
@@ -8791,6 +9242,7 @@ async function _getOffers(db, params) {
|
|
|
8791
9242
|
p.buy,
|
|
8792
9243
|
p.callback_address,
|
|
8793
9244
|
p.callback_data,
|
|
9245
|
+
p.receiver_if_maker_is_seller,
|
|
8794
9246
|
p.block_number,
|
|
8795
9247
|
p.group_chain_id,
|
|
8796
9248
|
p.group_maker,
|
|
@@ -8826,6 +9278,7 @@ async function _getOffers(db, params) {
|
|
|
8826
9278
|
AND LOWER(l.contract) = LOWER(c.position_contract)
|
|
8827
9279
|
AND LOWER(l."user") = LOWER(c.position_user)
|
|
8828
9280
|
AND l."group" = p.group_group
|
|
9281
|
+
AND l.obligation_id = p.obligation_id
|
|
8829
9282
|
LEFT JOIN ${positions} pos
|
|
8830
9283
|
ON pos.chain_id = c.position_chain_id
|
|
8831
9284
|
AND LOWER(pos.contract) = LOWER(c.position_contract)
|
|
@@ -8834,10 +9287,12 @@ async function _getOffers(db, params) {
|
|
|
8834
9287
|
ON pos_offsets.chain_id = c.position_chain_id
|
|
8835
9288
|
AND LOWER(pos_offsets.contract) = LOWER(c.position_contract)
|
|
8836
9289
|
AND LOWER(pos_offsets."user") = LOWER(c.position_user)
|
|
9290
|
+
AND pos_offsets.obligation_id = p.obligation_id
|
|
8837
9291
|
LEFT JOIN position_consumed pc
|
|
8838
9292
|
ON pc.chain_id = c.position_chain_id
|
|
8839
9293
|
AND LOWER(pc.contract) = LOWER(c.position_contract)
|
|
8840
9294
|
AND LOWER(pc."user") = LOWER(c.position_user)
|
|
9295
|
+
AND pc.obligation_id = p.obligation_id
|
|
8841
9296
|
),
|
|
8842
9297
|
-- Compute contribution per callback in loan terms (loan token only — collateral positions are not indexed)
|
|
8843
9298
|
callback_loan_contribution AS (
|
|
@@ -8855,7 +9310,7 @@ async function _getOffers(db, params) {
|
|
|
8855
9310
|
hash,
|
|
8856
9311
|
obligation_id,
|
|
8857
9312
|
assets,
|
|
8858
|
-
|
|
9313
|
+
tick,
|
|
8859
9314
|
obligation_units,
|
|
8860
9315
|
obligation_shares,
|
|
8861
9316
|
maturity,
|
|
@@ -8865,6 +9320,7 @@ async function _getOffers(db, params) {
|
|
|
8865
9320
|
buy,
|
|
8866
9321
|
callback_address,
|
|
8867
9322
|
callback_data,
|
|
9323
|
+
receiver_if_maker_is_seller,
|
|
8868
9324
|
block_number,
|
|
8869
9325
|
group_chain_id,
|
|
8870
9326
|
group_maker,
|
|
@@ -8881,16 +9337,17 @@ async function _getOffers(db, params) {
|
|
|
8881
9337
|
WHERE clc.callback_id IS NOT NULL
|
|
8882
9338
|
ORDER BY clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user, clc.contribution_in_loan DESC
|
|
8883
9339
|
) deduped
|
|
8884
|
-
GROUP BY hash, obligation_id, assets,
|
|
8885
|
-
|
|
8886
|
-
consumed, chain_id, loan_token, session
|
|
9340
|
+
GROUP BY hash, obligation_id, assets, tick, obligation_units, obligation_shares, maturity, expiry, start, group_group, buy,
|
|
9341
|
+
callback_address, callback_data, block_number, group_chain_id, group_maker,
|
|
9342
|
+
consumed, chain_id, loan_token, session, receiver_if_maker_is_seller
|
|
8887
9343
|
UNION ALL
|
|
8888
9344
|
-- Sell offers without callbacks: collateral positions not indexed, takeable = assets - consumed
|
|
8889
9345
|
SELECT
|
|
8890
|
-
p.hash, p.obligation_id, p.assets, p.
|
|
9346
|
+
p.hash, p.obligation_id, p.assets, p.tick,
|
|
8891
9347
|
p.obligation_units, p.obligation_shares,
|
|
8892
9348
|
p.maturity, p.expiry, p.start, p.group_group,
|
|
8893
9349
|
p.buy, p.callback_address, p.callback_data,
|
|
9350
|
+
p.receiver_if_maker_is_seller,
|
|
8894
9351
|
p.block_number, p.group_chain_id, p.group_maker,
|
|
8895
9352
|
p.consumed, p.chain_id, p.loan_token, p.session,
|
|
8896
9353
|
0 AS total_available
|
|
@@ -8909,7 +9366,7 @@ async function _getOffers(db, params) {
|
|
|
8909
9366
|
oc.obligation_units,
|
|
8910
9367
|
oc.obligation_shares,
|
|
8911
9368
|
oc.consumed,
|
|
8912
|
-
oc.
|
|
9369
|
+
oc.tick,
|
|
8913
9370
|
oc.maturity,
|
|
8914
9371
|
oc.expiry,
|
|
8915
9372
|
oc.start,
|
|
@@ -8919,6 +9376,7 @@ async function _getOffers(db, params) {
|
|
|
8919
9376
|
oc.loan_token,
|
|
8920
9377
|
oc.callback_address,
|
|
8921
9378
|
oc.callback_data,
|
|
9379
|
+
oc.receiver_if_maker_is_seller,
|
|
8922
9380
|
oc.block_number,
|
|
8923
9381
|
oc.session,
|
|
8924
9382
|
COALESCE(oc.total_available, 0) AS available,
|
|
@@ -8941,20 +9399,21 @@ async function _getOffers(db, params) {
|
|
|
8941
9399
|
))
|
|
8942
9400
|
END > 0
|
|
8943
9401
|
ORDER BY
|
|
8944
|
-
oc.
|
|
9402
|
+
oc.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`},
|
|
8945
9403
|
oc.block_number ASC,
|
|
8946
9404
|
oc.assets DESC,
|
|
8947
9405
|
oc.hash ASC;
|
|
8948
9406
|
`);
|
|
8949
9407
|
return {
|
|
8950
9408
|
rows: raw.rows.map((row) => {
|
|
9409
|
+
const receiverIfMakerIsSeller = (row.receiver_if_maker_is_seller ?? row.group_maker).toLowerCase();
|
|
8951
9410
|
return {
|
|
8952
9411
|
hash: row.hash,
|
|
8953
9412
|
maker: row.group_maker,
|
|
8954
9413
|
assets: BigInt(row.assets),
|
|
8955
9414
|
obligationUnits: BigInt(row.obligation_units ?? 0),
|
|
8956
9415
|
obligationShares: BigInt(row.obligation_shares ?? 0),
|
|
8957
|
-
|
|
9416
|
+
tick: row.tick,
|
|
8958
9417
|
maturity: row.maturity,
|
|
8959
9418
|
expiry: row.expiry,
|
|
8960
9419
|
start: row.start,
|
|
@@ -8972,6 +9431,7 @@ async function _getOffers(db, params) {
|
|
|
8972
9431
|
address: row.callback_address,
|
|
8973
9432
|
data: row.callback_data
|
|
8974
9433
|
},
|
|
9434
|
+
receiverIfMakerIsSeller,
|
|
8975
9435
|
blockNumber: row.block_number,
|
|
8976
9436
|
consumed: BigInt(row.consumed ?? 0),
|
|
8977
9437
|
available: BigInt(String(row.available ?? "0").split(".")[0] ?? "0"),
|
|
@@ -8986,7 +9446,7 @@ let Cursor;
|
|
|
8986
9446
|
function encode(row, totalReturned, now, side) {
|
|
8987
9447
|
return Buffer.from(JSON.stringify({
|
|
8988
9448
|
side,
|
|
8989
|
-
|
|
9449
|
+
tick: row.tick,
|
|
8990
9450
|
blockNumber: row.blockNumber,
|
|
8991
9451
|
assets: row.assets.toString(),
|
|
8992
9452
|
hash: row.hash,
|
|
@@ -8997,10 +9457,9 @@ let Cursor;
|
|
|
8997
9457
|
_Cursor.encode = encode;
|
|
8998
9458
|
function decode(cursorString, logger) {
|
|
8999
9459
|
if (cursorString == null) return null;
|
|
9000
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
9001
9460
|
try {
|
|
9002
9461
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
9003
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
9462
|
+
if ((v?.side === "buy" || v?.side === "sell") && typeof v?.tick === "number" && Number.isInteger(v.tick) && typeof v?.blockNumber === "number" && Number.isInteger(v.blockNumber) && typeof v?.assets === "string" && /^-?\d+$/.test(v.assets) && isHex(v?.hash) && typeof v?.totalReturned === "number" && Number.isInteger(v.totalReturned) && typeof v?.now === "number" && Number.isInteger(v.now)) return v;
|
|
9004
9463
|
throw new Error("Invalid cursor");
|
|
9005
9464
|
} catch {
|
|
9006
9465
|
logger.error({
|
|
@@ -9018,7 +9477,7 @@ let LevelCursor;
|
|
|
9018
9477
|
function encode(lastLevel, offersCursor, side, now) {
|
|
9019
9478
|
return Buffer.from(JSON.stringify({
|
|
9020
9479
|
side,
|
|
9021
|
-
|
|
9480
|
+
lastTick: lastLevel.tick,
|
|
9022
9481
|
now,
|
|
9023
9482
|
offersCursor
|
|
9024
9483
|
})).toString("base64url");
|
|
@@ -9026,10 +9485,9 @@ let LevelCursor;
|
|
|
9026
9485
|
_LevelCursor.encode = encode;
|
|
9027
9486
|
function decode(cursorString, logger) {
|
|
9028
9487
|
if (cursorString == null) return null;
|
|
9029
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
9030
9488
|
try {
|
|
9031
9489
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
9032
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
9490
|
+
if ((v?.side === "buy" || v?.side === "sell") && typeof v?.lastTick === "number" && Number.isInteger(v.lastTick) && typeof v?.now === "number" && Number.isInteger(v.now) && (v?.offersCursor === null || typeof v?.offersCursor === "string")) return v;
|
|
9033
9491
|
throw new Error("Invalid book cursor");
|
|
9034
9492
|
} catch {
|
|
9035
9493
|
logger.error({
|
|
@@ -9172,31 +9630,33 @@ function create$9(db) {
|
|
|
9172
9630
|
function create$8(db) {
|
|
9173
9631
|
return {
|
|
9174
9632
|
get: async (parameters) => {
|
|
9175
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9633
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9176
9634
|
const conditions = [];
|
|
9177
9635
|
if (chainId !== void 0) conditions.push(eq(lots.chainId, chainId));
|
|
9178
9636
|
if (user !== void 0) conditions.push(eq(lots.user, user.toLowerCase()));
|
|
9179
9637
|
if (contract !== void 0) conditions.push(eq(lots.contract, contract.toLowerCase()));
|
|
9180
9638
|
if (group !== void 0) conditions.push(eq(lots.group, group));
|
|
9639
|
+
if (obligationId !== void 0) conditions.push(eq(lots.obligationId, obligationId));
|
|
9181
9640
|
return (await db.select().from(lots).where(conditions.length > 0 ? and(...conditions) : void 0)).map((row) => ({
|
|
9182
9641
|
chainId: row.chainId,
|
|
9183
9642
|
user: row.user,
|
|
9184
9643
|
contract: row.contract,
|
|
9185
9644
|
group: row.group,
|
|
9645
|
+
obligationId: row.obligationId,
|
|
9186
9646
|
lower: BigInt(row.lower),
|
|
9187
9647
|
upper: BigInt(row.upper)
|
|
9188
9648
|
}));
|
|
9189
9649
|
},
|
|
9190
9650
|
create: async (parameters) => {
|
|
9191
9651
|
if (parameters.length === 0) return;
|
|
9192
|
-
const
|
|
9652
|
+
const lotsByKey = /* @__PURE__ */ new Map();
|
|
9193
9653
|
for (const offer of parameters) {
|
|
9194
|
-
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}`.toLowerCase();
|
|
9195
|
-
const existing =
|
|
9196
|
-
if (!existing || offer.size > existing.size)
|
|
9654
|
+
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}-${offer.obligationId}`.toLowerCase();
|
|
9655
|
+
const existing = lotsByKey.get(key);
|
|
9656
|
+
if (!existing || offer.size > existing.size) lotsByKey.set(key, offer);
|
|
9197
9657
|
}
|
|
9198
|
-
for (const offer of
|
|
9199
|
-
const maxUpperResult = await db.select({ maxUpper: sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase())));
|
|
9658
|
+
for (const offer of lotsByKey.values()) if ((await db.select().from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase()), eq(lots.group, offer.group.toLowerCase()), eq(lots.obligationId, offer.obligationId.toLowerCase()))).limit(1)).length === 0) {
|
|
9659
|
+
const maxUpperResult = await db.select({ maxUpper: sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase()), eq(lots.obligationId, offer.obligationId.toLowerCase())));
|
|
9200
9660
|
const newLower = BigInt(maxUpperResult[0]?.maxUpper ?? "0");
|
|
9201
9661
|
const newUpper = newLower + offer.size;
|
|
9202
9662
|
await db.insert(lots).values({
|
|
@@ -9204,6 +9664,7 @@ function create$8(db) {
|
|
|
9204
9664
|
user: offer.positionUser.toLowerCase(),
|
|
9205
9665
|
contract: offer.positionContract.toLowerCase(),
|
|
9206
9666
|
group: offer.group.toLowerCase(),
|
|
9667
|
+
obligationId: offer.obligationId.toLowerCase(),
|
|
9207
9668
|
lower: newLower.toString(),
|
|
9208
9669
|
upper: newUpper.toString()
|
|
9209
9670
|
});
|
|
@@ -9220,55 +9681,79 @@ function create$8(db) {
|
|
|
9220
9681
|
* @returns Obligations domain. {@link ObligationsDomain}
|
|
9221
9682
|
*/
|
|
9222
9683
|
function create$7(db) {
|
|
9223
|
-
return {
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
|
|
9235
|
-
|
|
9236
|
-
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9684
|
+
return {
|
|
9685
|
+
get: async (parameters) => {
|
|
9686
|
+
const chainIds = parameters?.chainId;
|
|
9687
|
+
const now$1 = now();
|
|
9688
|
+
return (await db.select({
|
|
9689
|
+
chainId: obligations.chainId,
|
|
9690
|
+
loanToken: obligations.loanToken,
|
|
9691
|
+
collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${oracles$1.address}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
9692
|
+
maturity: obligations.maturity
|
|
9693
|
+
}).from(obligations).innerJoin(obligationCollateralsV2, eq(obligations.obligationId, obligationCollateralsV2.obligationId)).innerJoin(oracles$1, sql`${obligationCollateralsV2.oracleChainId} = ${oracles$1.chainId}
|
|
9694
|
+
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).groupBy(obligations.obligationId).where(and(chainIds !== void 0 && chainIds.length > 0 ? inArray(obligations.chainId, chainIds) : void 0, gte(obligations.maturity, now$1))).orderBy(asc(obligations.obligationId))).map((row) => from$15({
|
|
9695
|
+
chainId: row.chainId,
|
|
9696
|
+
loanToken: row.loanToken,
|
|
9697
|
+
collaterals: row.collaterals.sort((left, right) => left.asset.localeCompare(right.asset)).map((collateral) => from$17({
|
|
9698
|
+
asset: collateral.asset,
|
|
9699
|
+
oracle: collateral.oracle,
|
|
9700
|
+
lltv: from$18(BigInt(collateral.lltv))
|
|
9701
|
+
})),
|
|
9702
|
+
maturity: row.maturity
|
|
9703
|
+
}));
|
|
9704
|
+
},
|
|
9705
|
+
create: async (obligations$1) => {
|
|
9706
|
+
if (obligations$1.length === 0) return;
|
|
9707
|
+
const obligationsById = /* @__PURE__ */ new Map();
|
|
9708
|
+
for (const obligation of obligations$1) {
|
|
9709
|
+
const id$1 = id(obligation).toLowerCase();
|
|
9710
|
+
if (!obligationsById.get(id$1)) obligationsById.set(id$1, obligation);
|
|
9711
|
+
}
|
|
9712
|
+
try {
|
|
9713
|
+
await db.transaction(async (dbTx) => {
|
|
9714
|
+
const obligationRows = obligations$1.map((obligation) => ({
|
|
9241
9715
|
obligationId: id(obligation),
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
lltv: collateral.lltv
|
|
9716
|
+
chainId: obligation.chainId,
|
|
9717
|
+
loanToken: obligation.loanToken.toLowerCase(),
|
|
9718
|
+
maturity: obligation.maturity
|
|
9246
9719
|
}));
|
|
9720
|
+
for (const batch of batch$1(obligationRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(obligations).values(batch).onConflictDoNothing();
|
|
9721
|
+
const collateralRows = obligations$1.flatMap((obligation) => {
|
|
9722
|
+
return obligation.collaterals.map((collateral) => ({
|
|
9723
|
+
obligationId: id(obligation),
|
|
9724
|
+
asset: collateral.asset.toLowerCase(),
|
|
9725
|
+
oracleChainId: obligation.chainId,
|
|
9726
|
+
oracleAddress: collateral.oracle.toLowerCase(),
|
|
9727
|
+
lltv: collateral.lltv
|
|
9728
|
+
}));
|
|
9729
|
+
});
|
|
9730
|
+
for (const batch of batch$1(collateralRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(obligationCollateralsV2).values(batch).onConflictDoNothing();
|
|
9247
9731
|
});
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
throw new Error("Obligations.create failed. Ensure oracles exist before inserting obligations.", { cause: error });
|
|
9732
|
+
} catch (err) {
|
|
9733
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
9734
|
+
throw new Error("Obligations.create failed. Ensure oracles exist before inserting obligations.", { cause: error });
|
|
9735
|
+
}
|
|
9253
9736
|
}
|
|
9254
|
-
}
|
|
9737
|
+
};
|
|
9255
9738
|
}
|
|
9256
9739
|
|
|
9257
9740
|
//#endregion
|
|
9258
9741
|
//#region src/database/domains/Offsets.ts
|
|
9259
9742
|
function create$6(db) {
|
|
9260
9743
|
return { get: async (parameters) => {
|
|
9261
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9744
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9262
9745
|
const conditions = [];
|
|
9263
9746
|
if (chainId !== void 0) conditions.push(eq(offsets.chainId, chainId));
|
|
9264
9747
|
if (user !== void 0) conditions.push(eq(offsets.user, user.toLowerCase()));
|
|
9265
9748
|
if (contract !== void 0) conditions.push(eq(offsets.contract, contract.toLowerCase()));
|
|
9266
9749
|
if (group !== void 0) conditions.push(eq(offsets.group, group));
|
|
9750
|
+
if (obligationId !== void 0) conditions.push(eq(offsets.obligationId, obligationId));
|
|
9267
9751
|
return (await db.select().from(offsets).where(conditions.length > 0 ? and(...conditions) : void 0)).map((row) => ({
|
|
9268
9752
|
chainId: row.chainId,
|
|
9269
9753
|
user: row.user,
|
|
9270
9754
|
contract: row.contract,
|
|
9271
9755
|
group: row.group,
|
|
9756
|
+
obligationId: row.obligationId,
|
|
9272
9757
|
value: BigInt(row.value)
|
|
9273
9758
|
}));
|
|
9274
9759
|
} };
|
|
@@ -9418,7 +9903,8 @@ const create$4 = (db) => {
|
|
|
9418
9903
|
if (!parsed.chainId || !parsed.contract) throw new Error("Invalid cursor format");
|
|
9419
9904
|
cursor = {
|
|
9420
9905
|
chainId: parsed.chainId,
|
|
9421
|
-
contract: parsed.contract
|
|
9906
|
+
contract: parsed.contract,
|
|
9907
|
+
obligationId: parsed.obligationId ?? null
|
|
9422
9908
|
};
|
|
9423
9909
|
}
|
|
9424
9910
|
const raw = await db.execute(sql`
|
|
@@ -9427,16 +9913,18 @@ const create$4 = (db) => {
|
|
|
9427
9913
|
chain_id,
|
|
9428
9914
|
"user",
|
|
9429
9915
|
contract,
|
|
9916
|
+
obligation_id,
|
|
9430
9917
|
SUM(value::numeric) AS total_offset
|
|
9431
9918
|
FROM ${offsets}
|
|
9432
9919
|
WHERE LOWER("user") = LOWER(${user})
|
|
9433
|
-
GROUP BY chain_id, "user", contract
|
|
9920
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
9434
9921
|
),
|
|
9435
9922
|
position_consumed AS (
|
|
9436
9923
|
SELECT
|
|
9437
9924
|
l.chain_id,
|
|
9438
9925
|
l.contract,
|
|
9439
9926
|
l."user",
|
|
9927
|
+
l.obligation_id,
|
|
9440
9928
|
SUM(
|
|
9441
9929
|
CASE
|
|
9442
9930
|
WHEN offer_agg.assets > 0
|
|
@@ -9462,50 +9950,64 @@ const create$4 = (db) => {
|
|
|
9462
9950
|
AND LOWER(offer_agg.group_maker) = LOWER(g.maker)
|
|
9463
9951
|
AND offer_agg."group_group" = g."group"
|
|
9464
9952
|
WHERE LOWER(l."user") = LOWER(${user})
|
|
9465
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
9953
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
9466
9954
|
),
|
|
9467
9955
|
position_max_lot AS (
|
|
9468
9956
|
SELECT
|
|
9469
9957
|
chain_id,
|
|
9470
9958
|
contract,
|
|
9471
9959
|
"user",
|
|
9960
|
+
obligation_id,
|
|
9472
9961
|
MAX(upper::numeric) AS max_upper
|
|
9473
9962
|
FROM ${lots}
|
|
9474
9963
|
WHERE LOWER("user") = LOWER(${user})
|
|
9475
|
-
GROUP BY chain_id, contract, "user"
|
|
9964
|
+
GROUP BY chain_id, contract, "user", obligation_id
|
|
9965
|
+
),
|
|
9966
|
+
per_obligation AS (
|
|
9967
|
+
SELECT
|
|
9968
|
+
pml.chain_id,
|
|
9969
|
+
pml.contract,
|
|
9970
|
+
pml."user",
|
|
9971
|
+
pml.obligation_id,
|
|
9972
|
+
GREATEST(0,
|
|
9973
|
+
COALESCE(pml.max_upper, 0)
|
|
9974
|
+
- COALESCE(po.total_offset, 0)
|
|
9975
|
+
- COALESCE(pc.consumed, 0)
|
|
9976
|
+
)::text AS reserved_balance
|
|
9977
|
+
FROM position_max_lot pml
|
|
9978
|
+
LEFT JOIN position_offsets po
|
|
9979
|
+
ON po.chain_id = pml.chain_id
|
|
9980
|
+
AND LOWER(po.contract) = LOWER(pml.contract)
|
|
9981
|
+
AND LOWER(po."user") = LOWER(pml."user")
|
|
9982
|
+
AND po.obligation_id = pml.obligation_id
|
|
9983
|
+
LEFT JOIN position_consumed pc
|
|
9984
|
+
ON pc.chain_id = pml.chain_id
|
|
9985
|
+
AND LOWER(pc.contract) = LOWER(pml.contract)
|
|
9986
|
+
AND LOWER(pc."user") = LOWER(pml."user")
|
|
9987
|
+
AND pc.obligation_id = pml.obligation_id
|
|
9476
9988
|
)
|
|
9477
9989
|
SELECT
|
|
9478
9990
|
p.chain_id,
|
|
9479
9991
|
p.contract,
|
|
9480
9992
|
p."user",
|
|
9481
9993
|
p.block_number,
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
- COALESCE(po.total_offset, 0)
|
|
9485
|
-
- COALESCE(pc.consumed, 0)
|
|
9486
|
-
)::text AS reserved_balance
|
|
9994
|
+
po.obligation_id,
|
|
9995
|
+
COALESCE(po.reserved_balance, '0') AS reserved_balance
|
|
9487
9996
|
FROM ${positions} p
|
|
9488
|
-
LEFT JOIN
|
|
9997
|
+
LEFT JOIN per_obligation po
|
|
9489
9998
|
ON po.chain_id = p.chain_id
|
|
9490
9999
|
AND LOWER(po.contract) = LOWER(p.contract)
|
|
9491
10000
|
AND LOWER(po."user") = LOWER(p."user")
|
|
9492
|
-
LEFT JOIN position_consumed pc
|
|
9493
|
-
ON pc.chain_id = p.chain_id
|
|
9494
|
-
AND LOWER(pc.contract) = LOWER(p.contract)
|
|
9495
|
-
AND LOWER(pc."user") = LOWER(p."user")
|
|
9496
|
-
LEFT JOIN position_max_lot pml
|
|
9497
|
-
ON pml.chain_id = p.chain_id
|
|
9498
|
-
AND LOWER(pml.contract) = LOWER(p.contract)
|
|
9499
|
-
AND LOWER(pml."user") = LOWER(p."user")
|
|
9500
10001
|
WHERE LOWER(p."user") = LOWER(${user})
|
|
9501
10002
|
AND p."user" != ${zeroAddress}
|
|
9502
|
-
${cursor !== null ? sql`AND (p.chain_id, p.contract) > (${cursor.chainId}, ${cursor.contract})` : sql``}
|
|
9503
|
-
ORDER BY p.chain_id ASC, p.contract ASC
|
|
10003
|
+
${cursor !== null ? sql`AND (p.chain_id, p.contract, COALESCE(po.obligation_id, '')) > (${cursor.chainId}, ${cursor.contract}, ${cursor.obligationId ?? ""})` : sql``}
|
|
10004
|
+
ORDER BY p.chain_id ASC, p.contract ASC, po.obligation_id ASC NULLS FIRST
|
|
9504
10005
|
LIMIT ${limit}
|
|
9505
10006
|
`);
|
|
9506
10007
|
const nextCursor = raw.rows.length === limit ? Buffer.from(JSON.stringify({
|
|
9507
10008
|
chainId: raw.rows[raw.rows.length - 1].chain_id.toString(),
|
|
9508
|
-
contract: raw.rows[raw.rows.length - 1].contract
|
|
10009
|
+
contract: raw.rows[raw.rows.length - 1].contract,
|
|
10010
|
+
obligationId: raw.rows[raw.rows.length - 1].obligation_id
|
|
9509
10011
|
})).toString("base64url") : null;
|
|
9510
10012
|
return {
|
|
9511
10013
|
positions: raw.rows.map((row) => ({
|
|
@@ -9513,6 +10015,7 @@ const create$4 = (db) => {
|
|
|
9513
10015
|
contract: row.contract,
|
|
9514
10016
|
user: row.user,
|
|
9515
10017
|
blockNumber: row.block_number,
|
|
10018
|
+
obligationId: row.obligation_id,
|
|
9516
10019
|
reserved: BigInt(row.reserved_balance.split(".")[0] ?? "0")
|
|
9517
10020
|
})),
|
|
9518
10021
|
nextCursor
|
|
@@ -9791,7 +10294,10 @@ function create$1(db) {
|
|
|
9791
10294
|
|
|
9792
10295
|
//#endregion
|
|
9793
10296
|
//#region src/database/Database.ts
|
|
9794
|
-
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
10297
|
+
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
10298
|
+
connect: () => connect$1,
|
|
10299
|
+
getSchemaNamesForMigration: () => getSchemaNamesForMigration
|
|
10300
|
+
});
|
|
9795
10301
|
function createDomains(core, chainRegistry) {
|
|
9796
10302
|
return {
|
|
9797
10303
|
book: create$12({ db: core }),
|
|
@@ -9813,6 +10319,9 @@ function createDomains(core, chainRegistry) {
|
|
|
9813
10319
|
transfers: create$3(core)
|
|
9814
10320
|
};
|
|
9815
10321
|
}
|
|
10322
|
+
function createReaders(core) {
|
|
10323
|
+
return { obligations: create$16({ db: core }) };
|
|
10324
|
+
}
|
|
9816
10325
|
const AUGMENT_CACHE = /* @__PURE__ */ new WeakMap();
|
|
9817
10326
|
function augmentWithDomains(base, chainRegistry) {
|
|
9818
10327
|
const cached = AUGMENT_CACHE.get(base)?.get(chainRegistry);
|
|
@@ -9824,6 +10333,7 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9824
10333
|
});
|
|
9825
10334
|
};
|
|
9826
10335
|
const dms = createDomains(wrapped, chainRegistry);
|
|
10336
|
+
const readers = createReaders(wrapped);
|
|
9827
10337
|
Object.defineProperties(wrapped, {
|
|
9828
10338
|
book: {
|
|
9829
10339
|
value: dms.book,
|
|
@@ -9880,6 +10390,10 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9880
10390
|
transfers: {
|
|
9881
10391
|
value: dms.transfers,
|
|
9882
10392
|
enumerable: true
|
|
10393
|
+
},
|
|
10394
|
+
readers: {
|
|
10395
|
+
value: readers,
|
|
10396
|
+
enumerable: true
|
|
9883
10397
|
}
|
|
9884
10398
|
});
|
|
9885
10399
|
const chainRegistryMap = AUGMENT_CACHE.get(base);
|
|
@@ -9888,6 +10402,7 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9888
10402
|
return wrapped;
|
|
9889
10403
|
}
|
|
9890
10404
|
const InMemoryDbMap = /* @__PURE__ */ new Map();
|
|
10405
|
+
const LEGACY_SCHEMA_START_MINOR = 7;
|
|
9891
10406
|
/**
|
|
9892
10407
|
* Connect to the database.
|
|
9893
10408
|
* @notice If no connection string is provided, an in-process PGLite database is created.
|
|
@@ -9942,9 +10457,26 @@ function applyMigrations(kind, driver) {
|
|
|
9942
10457
|
async function preMigrate(driver) {
|
|
9943
10458
|
const tracer = getTracer("db.preMigrate");
|
|
9944
10459
|
await startActiveSpan(tracer, "db.preMigrate", async () => {
|
|
9945
|
-
|
|
10460
|
+
const schemaNames = getSchemaNamesForMigration(VERSION);
|
|
10461
|
+
for (const schemaName of schemaNames) await driver.execute(`create schema if not exists "${schemaName}"`);
|
|
9946
10462
|
});
|
|
9947
10463
|
}
|
|
10464
|
+
/**
|
|
10465
|
+
* Build the list of router schemas that should exist before running migrations.
|
|
10466
|
+
* @param version - Current schema version (e.g. `router_v1.8`).
|
|
10467
|
+
* @returns Ordered schema names from `router_v1.7` to current, or just current if parsing fails.
|
|
10468
|
+
*/
|
|
10469
|
+
function getSchemaNamesForMigration(version) {
|
|
10470
|
+
const parsed = /^router_v(?<major>\d+)\.(?<minor>\d+)$/.exec(version);
|
|
10471
|
+
if (!parsed?.groups?.major || !parsed.groups.minor) return [version];
|
|
10472
|
+
const major = Number.parseInt(parsed.groups.major, 10);
|
|
10473
|
+
const currentMinor = Number.parseInt(parsed.groups.minor, 10);
|
|
10474
|
+
if (!Number.isInteger(major) || !Number.isInteger(currentMinor)) return [version];
|
|
10475
|
+
if (currentMinor < LEGACY_SCHEMA_START_MINOR) return [version];
|
|
10476
|
+
const schemaNames = [];
|
|
10477
|
+
for (let minor = LEGACY_SCHEMA_START_MINOR; minor <= currentMinor; minor += 1) schemaNames.push(`router_v${major}.${minor}`);
|
|
10478
|
+
return schemaNames;
|
|
10479
|
+
}
|
|
9948
10480
|
async function postMigrate(driver) {
|
|
9949
10481
|
const tracer = getTracer("db.postMigrate");
|
|
9950
10482
|
await startActiveSpan(tracer, "db.postMigrate", async () => {
|
|
@@ -10214,15 +10746,16 @@ async function postMigrate(driver) {
|
|
|
10214
10746
|
RETURNS trigger
|
|
10215
10747
|
LANGUAGE plpgsql AS $$
|
|
10216
10748
|
BEGIN
|
|
10217
|
-
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", value)
|
|
10749
|
+
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", obligation_id, value)
|
|
10218
10750
|
VALUES (
|
|
10219
10751
|
OLD.chain_id,
|
|
10220
10752
|
OLD."user",
|
|
10221
10753
|
OLD.contract,
|
|
10222
10754
|
OLD."group",
|
|
10755
|
+
OLD.obligation_id,
|
|
10223
10756
|
OLD.upper::numeric - OLD.lower::numeric
|
|
10224
10757
|
)
|
|
10225
|
-
ON CONFLICT (chain_id, "user", contract, "group") DO NOTHING;
|
|
10758
|
+
ON CONFLICT (chain_id, "user", contract, "group", obligation_id) DO NOTHING;
|
|
10226
10759
|
RETURN OLD;
|
|
10227
10760
|
END;
|
|
10228
10761
|
$$;
|
|
@@ -10476,10 +11009,11 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
|
10476
11009
|
amountMutualExclusivity: () => amountMutualExclusivity,
|
|
10477
11010
|
callback: () => callback,
|
|
10478
11011
|
chains: () => chains,
|
|
11012
|
+
collateralToken: () => collateralToken,
|
|
11013
|
+
loanToken: () => loanToken,
|
|
10479
11014
|
maturity: () => maturity,
|
|
10480
11015
|
oracle: () => oracle,
|
|
10481
11016
|
sameMaker: () => sameMaker,
|
|
10482
|
-
token: () => token,
|
|
10483
11017
|
validity: () => validity
|
|
10484
11018
|
});
|
|
10485
11019
|
/**
|
|
@@ -10499,7 +11033,7 @@ const chains = ({ chains }) => single("chain_ids", `Validates that offer chain i
|
|
|
10499
11033
|
});
|
|
10500
11034
|
const maturity = ({ maturities }) => single("maturity", `Validates that offer maturity is one of: [${maturities.join(", ")}]`, (offer) => {
|
|
10501
11035
|
const allowedMaturities = maturities.map((m) => from$16(m));
|
|
10502
|
-
if (!allowedMaturities.includes(offer.maturity)) return { message: `Maturity must be
|
|
11036
|
+
if (!allowedMaturities.includes(offer.maturity)) return { message: `Maturity must be one of (${allowedMaturities.join(", ")}). Got: ${offer.maturity}` };
|
|
10503
11037
|
});
|
|
10504
11038
|
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) => {
|
|
10505
11039
|
if (!isEmptyCallback(offer)) return { message: "Non-empty callbacks are not supported." };
|
|
@@ -10507,15 +11041,25 @@ const callback = ({ callbacks }) => single("callback", `Validates callbacks: buy
|
|
|
10507
11041
|
if (isEmptyCallback(offer) && !offer.buy && !callbacks.includes(Type$1.SellWithEmptyCallback)) return { message: "Sell offers with empty callback not allowed." };
|
|
10508
11042
|
});
|
|
10509
11043
|
/**
|
|
10510
|
-
* A validation rule that checks if the offer's
|
|
10511
|
-
* @param assetsByChainId - Allowed
|
|
11044
|
+
* A validation rule that checks if the offer's loan token is allowed for its chain.
|
|
11045
|
+
* @param assetsByChainId - Allowed loan tokens indexed by chain id.
|
|
11046
|
+
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
11047
|
+
*/
|
|
11048
|
+
const loanToken = ({ assetsByChainId }) => single("loan_token", "Validates that offer loan token is in the allowed token list for the offer chain", (offer) => {
|
|
11049
|
+
const allowedLoanTokens = assetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase());
|
|
11050
|
+
if (!allowedLoanTokens || allowedLoanTokens.length === 0) return { message: `No allowed loan tokens for chain ${offer.chainId}` };
|
|
11051
|
+
if (!allowedLoanTokens.includes(offer.loanToken.toLowerCase())) return { message: "Loan token is not allowed" };
|
|
11052
|
+
});
|
|
11053
|
+
/**
|
|
11054
|
+
* A validation rule that checks if the offer's collateral tokens are allowed for its chain.
|
|
11055
|
+
* @param collateralAssetsByChainId - Allowed collateral tokens indexed by chain id.
|
|
10512
11056
|
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
10513
11057
|
*/
|
|
10514
|
-
const
|
|
10515
|
-
const
|
|
10516
|
-
if (
|
|
10517
|
-
if (
|
|
10518
|
-
if (offer.collaterals.some((collateral) => !
|
|
11058
|
+
const collateralToken = ({ collateralAssetsByChainId }) => single("collateral_token", "Validates that offer collateral tokens are in the allowed token list for the offer chain", (offer) => {
|
|
11059
|
+
const allowedCollateralTokens = collateralAssetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase()) ?? [];
|
|
11060
|
+
if (allowedCollateralTokens.length === 0) return { message: `No allowed collateral tokens for chain ${offer.chainId}` };
|
|
11061
|
+
if (offer.collaterals.length === 0) return { message: "At least one collateral token is required" };
|
|
11062
|
+
if (offer.collaterals.some((collateral) => !allowedCollateralTokens.includes(collateral.asset.toLowerCase()))) return { message: "Collateral token is not allowed" };
|
|
10519
11063
|
});
|
|
10520
11064
|
/**
|
|
10521
11065
|
* A validation rule that checks if the offer's oracle addresses are allowed for its chain.
|
|
@@ -10558,21 +11102,24 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
|
|
|
10558
11102
|
//#region src/gatekeeper/morphoRules.ts
|
|
10559
11103
|
const morphoRules = (chains$3) => {
|
|
10560
11104
|
const assetsByChainId = {};
|
|
11105
|
+
const collateralAssetsByChainId = {};
|
|
10561
11106
|
const oraclesByChainId = {};
|
|
10562
11107
|
for (const chain of chains$3) {
|
|
10563
11108
|
assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
|
|
11109
|
+
collateralAssetsByChainId[chain.id] = collateralAssets[chain.id.toString()] ?? [];
|
|
10564
11110
|
oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
|
|
10565
11111
|
}
|
|
10566
11112
|
return [
|
|
10567
11113
|
sameMaker(),
|
|
10568
11114
|
amountMutualExclusivity(),
|
|
10569
11115
|
chains({ chains: chains$3 }),
|
|
10570
|
-
maturity({ maturities: [MaturityType.
|
|
11116
|
+
maturity({ maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek] }),
|
|
10571
11117
|
callback({
|
|
10572
11118
|
callbacks: [Type$1.BuyWithEmptyCallback, Type$1.SellWithEmptyCallback],
|
|
10573
11119
|
allowedAddresses: []
|
|
10574
11120
|
}),
|
|
10575
|
-
|
|
11121
|
+
loanToken({ assetsByChainId }),
|
|
11122
|
+
collateralToken({ collateralAssetsByChainId }),
|
|
10576
11123
|
oracle({ oraclesByChainId })
|
|
10577
11124
|
];
|
|
10578
11125
|
};
|
|
@@ -10755,5 +11302,5 @@ var mempool_exports = /* @__PURE__ */ __exportAll({
|
|
|
10755
11302
|
});
|
|
10756
11303
|
|
|
10757
11304
|
//#endregion
|
|
10758
|
-
export { Abi_exports as Abi, BookResponse_exports as BookResponse, BooksController, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainHealth, ChainRegistry_exports as ChainRegistry, ChainsHealthResponse, Collateral_exports as Collateral, CollectorHealth, CollectorsHealthResponse, ConfigContractsController, ConfigRulesController, Database_exports as Database, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, Gatekeeper_exports as Gatekeeper, Client_exports as GatekeeperClient, Health_exports as Health, HealthController, Indexer_exports as Indexer, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Logger_exports as Logger, Maturity_exports as Maturity, mempool_exports as Mempool, Obligation_exports as Obligation, ObligationResponse_exports as ObligationResponse, ObligationsController, Offer_exports as Offer, OfferResponse_exports as OfferResponse, OffersController, drizzle_exports as OffersSchema, OpenApi, Oracle_exports as Oracle, Position_exports as Position, PositionResponse_exports as PositionResponse, Quote_exports as Quote, RouterApi_exports as RouterApi, Client_exports$1 as RouterClient, RouterStatusResponse, Rules_exports as Rules, time_exports as Time, TradingFee_exports as TradingFee, Transfer_exports as Transfer, Tree_exports as Tree, UsersController, utils_exports as Utils, ValidateController, Gate_exports as Validation, morphoRules, parse, safeParse };
|
|
11305
|
+
export { Abi_exports as Abi, BookResponse_exports as BookResponse, BooksController, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainHealth, ChainRegistry_exports as ChainRegistry, ChainsHealthResponse, Collateral_exports as Collateral, CollectorHealth, CollectorsHealthResponse, ConfigContractsController, ConfigRulesController, Database_exports as Database, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, Gatekeeper_exports as Gatekeeper, Client_exports as GatekeeperClient, Health_exports as Health, HealthController, Indexer_exports as Indexer, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Logger_exports as Logger, Maturity_exports as Maturity, mempool_exports as Mempool, Obligation_exports as Obligation, ObligationResponse_exports as ObligationResponse, ObligationsController, Offer_exports as Offer, OfferResponse_exports as OfferResponse, OffersController, drizzle_exports as OffersSchema, OpenApi, Oracle_exports as Oracle, Position_exports as Position, PositionResponse_exports as PositionResponse, Quote_exports as Quote, RouterApi_exports as RouterApi, Client_exports$1 as RouterClient, RouterStatusResponse, Rules_exports as Rules, Tick_exports as Tick, time_exports as Time, TradingFee_exports as TradingFee, Transfer_exports as Transfer, Tree_exports as Tree, UsersController, utils_exports as Utils, ValidateController, Gate_exports as Validation, morphoRules, parse, safeParse };
|
|
10759
11306
|
//# sourceMappingURL=index.node.mjs.map
|