@morpho-dev/router 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +441 -141
- package/dist/drizzle/migrations/0000_setup_single_migration_folder.sql +64 -64
- package/dist/drizzle/migrations/0001_add-trigger-for-consumed-events.sql +5 -5
- package/dist/drizzle/migrations/0002_insert-status-code.sql +1 -1
- package/dist/drizzle/migrations/0003_update-triggers-for-consumed-events.sql +1 -1
- package/dist/drizzle/migrations/0004_drop-status-offers-foreign-key-constraint.sql +1 -1
- package/dist/drizzle/migrations/0005_add-index-to-boost-group-query-and-offer-hash.sql +1 -1
- package/dist/drizzle/migrations/0006_add-callbacks-and-positions-relations.sql +11 -11
- package/dist/drizzle/migrations/0008_validation.sql +10 -10
- package/dist/drizzle/migrations/0009_add-transfers-table.sql +4 -4
- package/dist/drizzle/migrations/0010_add-price.sql +1 -1
- package/dist/drizzle/migrations/0011_nullable-callback-amount.sql +1 -1
- package/dist/drizzle/migrations/0012_add-position-asset.sql +1 -1
- package/dist/drizzle/migrations/0013_remove-depecrated-domains.sql +13 -13
- package/dist/drizzle/migrations/0014_rename-offers-v2-into-offers.sql +19 -19
- package/dist/drizzle/migrations/0015_add-lots-table.sql +3 -3
- package/dist/drizzle/migrations/0016_merkle-metadata.sql +7 -7
- package/dist/drizzle/migrations/0017_dusty_the_hunter.sql +1 -1
- package/dist/drizzle/migrations/0018_add_chain_collector_constraints.sql +3 -3
- package/dist/drizzle/migrations/0019_add-obligation-units-shares.sql +2 -2
- package/dist/drizzle/migrations/0020_add-session.sql +1 -1
- package/dist/drizzle/migrations/0021_drop_chain_collector_epoch_indexes.sql +2 -2
- package/dist/drizzle/migrations/0021_migrate-rate-to-price.sql +6 -6
- package/dist/drizzle/migrations/0022_consolidate-price.sql +5 -5
- package/dist/drizzle/migrations/0023_remove-block-number-for-collaterals.sql +1 -1
- package/dist/drizzle/migrations/0024_add-obligation-id-to-lots.sql +8 -0
- package/dist/drizzle/migrations/0025_rename-price-to-tick.sql +202 -0
- package/dist/drizzle/migrations/meta/0000_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0001_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0002_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0003_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0004_snapshot.json +47 -47
- package/dist/drizzle/migrations/meta/0005_snapshot.json +47 -47
- package/dist/drizzle/migrations/meta/0006_snapshot.json +61 -61
- package/dist/drizzle/migrations/meta/0008_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0009_snapshot.json +66 -66
- package/dist/drizzle/migrations/meta/0010_snapshot.json +66 -66
- package/dist/drizzle/migrations/meta/0013_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0014_snapshot.json +48 -48
- package/dist/drizzle/migrations/meta/0015_snapshot.json +52 -52
- package/dist/drizzle/migrations/meta/0016_snapshot.json +61 -61
- package/dist/drizzle/migrations/meta/0017_snapshot.json +61 -61
- package/dist/drizzle/migrations/meta/0018_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0019_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0023_snapshot.json +62 -62
- package/dist/drizzle/migrations/meta/0024_snapshot.json +1448 -0
- package/dist/drizzle/migrations/meta/0025_snapshot.json +1448 -0
- package/dist/drizzle/migrations/meta/_journal.json +14 -0
- package/dist/evm/bytecode/erc20.txt +1 -1
- package/dist/evm/bytecode/morpho.txt +1 -1
- package/dist/evm/bytecode/multicall3.txt +1 -1
- package/dist/evm/bytecode/oracle.txt +1 -1
- package/dist/evm/bytecode/vault.txt +1 -1
- package/dist/index.browser.d.mts +1157 -81
- package/dist/index.browser.d.mts.map +1 -1
- package/dist/index.browser.d.ts +1157 -81
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +371 -151
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +366 -152
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.mts +1196 -70
- package/dist/index.node.d.mts.map +1 -1
- package/dist/index.node.d.ts +1196 -70
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +491 -145
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +486 -146
- package/dist/index.node.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.node.mjs
CHANGED
|
@@ -949,6 +949,61 @@ const MetaMorpho = parseAbi([
|
|
|
949
949
|
//#region src/core/Abi/MetaMorphoFactory.ts
|
|
950
950
|
const MetaMorphoFactory = parseAbi(["event CreateMetaMorpho(address indexed metaMorpho,address indexed caller,address initialOwner,uint256 initialTimelock,address indexed asset,string name,string symbol,bytes32 salt)", "function isMetaMorpho(address) view returns (bool)"]);
|
|
951
951
|
|
|
952
|
+
//#endregion
|
|
953
|
+
//#region src/core/Abi/MorphoV2.ts
|
|
954
|
+
const MorphoV2 = parseAbi([
|
|
955
|
+
"constructor()",
|
|
956
|
+
"function collateralOf(bytes32 id, address user, address collateralToken) view returns (uint256)",
|
|
957
|
+
"function consume(bytes32 group, uint256 amount)",
|
|
958
|
+
"function consumed(address user, bytes32 group) view returns (uint256)",
|
|
959
|
+
"function debtOf(bytes32 id, address user) view returns (uint256)",
|
|
960
|
+
"function defaultFees(address loanToken, uint256 index) view returns (uint16)",
|
|
961
|
+
"function feeSetter() view returns (address)",
|
|
962
|
+
"function fees(bytes32 id) view returns (uint16[6])",
|
|
963
|
+
"function flashLoan(address token, uint256 assets, address callback, bytes data)",
|
|
964
|
+
"function isHealthy((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bytes32 id, address borrower) view returns (bool)",
|
|
965
|
+
"function liquidate((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, (uint256 collateralIndex, uint256 repaid, uint256 seized)[] seizures, address borrower, bytes data) returns ((uint256 collateralIndex, uint256 repaid, uint256 seized)[])",
|
|
966
|
+
"function multicall(bytes[] calls)",
|
|
967
|
+
"function obligationCreated(bytes32 id) view returns (bool)",
|
|
968
|
+
"function obligationState(bytes32 id) view returns (uint128 totalUnits, uint128 totalShares, uint256 withdrawable, bool created)",
|
|
969
|
+
"function owner() view returns (address)",
|
|
970
|
+
"function repay((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, address onBehalf)",
|
|
971
|
+
"function session(address user) view returns (bytes32)",
|
|
972
|
+
"function setDefaultTradingFee(address loanToken, uint256 index, uint256 newTradingFee)",
|
|
973
|
+
"function setFeeSetter(address newFeeSetter)",
|
|
974
|
+
"function setObligationTradingFee(bytes32 id, uint256 index, uint256 newTradingFee)",
|
|
975
|
+
"function setOwner(address newOwner)",
|
|
976
|
+
"function setTradingFeeRecipient(address recipient)",
|
|
977
|
+
"function sharesOf(bytes32 id, address user) view returns (uint256)",
|
|
978
|
+
"function shuffleSession()",
|
|
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, address takerCallback, bytes takerCallbackData) returns (uint256, uint256, uint256, uint256)",
|
|
981
|
+
"function totalShares(bytes32 id) view returns (uint256)",
|
|
982
|
+
"function totalUnits(bytes32 id) view returns (uint256)",
|
|
983
|
+
"function touchObligation((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation) returns (bytes32)",
|
|
984
|
+
"function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)",
|
|
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)",
|
|
988
|
+
"function withdrawable(bytes32 id) view returns (uint256)",
|
|
989
|
+
"event Constructor(address indexed owner)",
|
|
990
|
+
"event Consume(address indexed user, bytes32 indexed group, uint256 amount)",
|
|
991
|
+
"event FlashLoan(address indexed caller, address indexed token, uint256 assets)",
|
|
992
|
+
"event Liquidate(address indexed caller, bytes32 indexed id, (uint256 collateralIndex, uint256 repaid, uint256 seized)[] seizures, address indexed borrower, uint256 totalRepaid, uint256 badDebt)",
|
|
993
|
+
"event ObligationCreated(bytes32 indexed id, (address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation)",
|
|
994
|
+
"event Repay(address indexed caller, bytes32 indexed id, uint256 obligationUnits, address indexed onBehalf)",
|
|
995
|
+
"event SetDefaultTradingFee(address indexed loanToken, uint256 indexed index, uint256 newTradingFee)",
|
|
996
|
+
"event SetFeeSetter(address indexed feeSetter)",
|
|
997
|
+
"event SetObligationTradingFee(bytes32 indexed id, uint256 indexed index, uint256 newTradingFee)",
|
|
998
|
+
"event SetOwner(address indexed owner)",
|
|
999
|
+
"event SetTradingFeeRecipient(address indexed recipient)",
|
|
1000
|
+
"event ShuffleSession(address indexed user, bytes32 session)",
|
|
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 indexed caller, bytes32 indexed id, uint256 obligationUnits, uint256 shares, address indexed onBehalf)",
|
|
1004
|
+
"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)"
|
|
1005
|
+
]);
|
|
1006
|
+
|
|
952
1007
|
//#endregion
|
|
953
1008
|
//#region src/core/Abi/index.ts
|
|
954
1009
|
var Abi_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -956,6 +1011,7 @@ var Abi_exports = /* @__PURE__ */ __exportAll({
|
|
|
956
1011
|
MetaMorpho: () => MetaMorpho,
|
|
957
1012
|
MetaMorphoFactory: () => MetaMorphoFactory,
|
|
958
1013
|
Morpho: () => Morpho,
|
|
1014
|
+
MorphoV2: () => MorphoV2,
|
|
959
1015
|
Oracle: () => Oracle
|
|
960
1016
|
});
|
|
961
1017
|
const Oracle = [{
|
|
@@ -1217,8 +1273,8 @@ const chains$2 = {
|
|
|
1217
1273
|
name: "ethereum-virtual-testnet",
|
|
1218
1274
|
custom: {
|
|
1219
1275
|
morpho: {
|
|
1220
|
-
address: "
|
|
1221
|
-
blockCreated:
|
|
1276
|
+
address: "0x634b095371e4e45feed94c1a45c37798e173ea50",
|
|
1277
|
+
blockCreated: 23226700
|
|
1222
1278
|
},
|
|
1223
1279
|
morphoBlue: {
|
|
1224
1280
|
address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
@@ -2024,7 +2080,7 @@ const OfferSchema = () => {
|
|
|
2024
2080
|
assets: z$1.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
2025
2081
|
obligationUnits: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
|
|
2026
2082
|
obligationShares: z$1.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
|
|
2027
|
-
|
|
2083
|
+
tick: z$1.coerce.number().int().min(0).max(990),
|
|
2028
2084
|
maturity: MaturitySchema,
|
|
2029
2085
|
expiry: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
2030
2086
|
start: z$1.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
@@ -2096,7 +2152,7 @@ const serialize = (offer) => ({
|
|
|
2096
2152
|
assets: offer.assets.toString(),
|
|
2097
2153
|
obligationUnits: offer.obligationUnits.toString(),
|
|
2098
2154
|
obligationShares: offer.obligationShares.toString(),
|
|
2099
|
-
|
|
2155
|
+
tick: offer.tick,
|
|
2100
2156
|
maturity: Number(offer.maturity),
|
|
2101
2157
|
expiry: Number(offer.expiry),
|
|
2102
2158
|
start: Number(offer.start),
|
|
@@ -2141,14 +2197,13 @@ function random$1(config) {
|
|
|
2141
2197
|
[.98, 2]
|
|
2142
2198
|
]));
|
|
2143
2199
|
const buy = config?.buy !== void 0 ? config.buy : bool();
|
|
2144
|
-
const
|
|
2145
|
-
const
|
|
2146
|
-
const
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
return [BigInt(q) * (ONE / 4n), buy ? 1 + idx : 1 + (len - 1 - idx)];
|
|
2200
|
+
const tickMin = buy ? 0 : 495;
|
|
2201
|
+
const len = (buy ? 495 : 990) - tickMin + 1;
|
|
2202
|
+
const tickPairs = Array.from({ length: len }, (_, idx) => {
|
|
2203
|
+
const weight = buy ? 1 + idx : 1 + (len - 1 - idx);
|
|
2204
|
+
return [tickMin + idx, weight];
|
|
2150
2205
|
});
|
|
2151
|
-
const
|
|
2206
|
+
const tick = config?.tick ?? weightedChoice(tickPairs);
|
|
2152
2207
|
const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
|
|
2153
2208
|
const unit = BigInt(10) ** BigInt(loanTokenDecimals);
|
|
2154
2209
|
const amountBase = BigInt(100 + int(999901));
|
|
@@ -2162,7 +2217,7 @@ function random$1(config) {
|
|
|
2162
2217
|
assets: assetsScaled,
|
|
2163
2218
|
obligationUnits: config?.obligationUnits ?? 0n,
|
|
2164
2219
|
obligationShares: config?.obligationShares ?? 0n,
|
|
2165
|
-
|
|
2220
|
+
tick,
|
|
2166
2221
|
maturity,
|
|
2167
2222
|
expiry: config?.expiry ?? maturity - 1,
|
|
2168
2223
|
start: config?.start ?? maturity - 10,
|
|
@@ -2227,7 +2282,7 @@ const types = {
|
|
|
2227
2282
|
type: "uint256"
|
|
2228
2283
|
},
|
|
2229
2284
|
{
|
|
2230
|
-
name: "
|
|
2285
|
+
name: "tick",
|
|
2231
2286
|
type: "uint256"
|
|
2232
2287
|
},
|
|
2233
2288
|
{
|
|
@@ -2295,7 +2350,7 @@ function hash(offer) {
|
|
|
2295
2350
|
assets: offer.assets,
|
|
2296
2351
|
obligationUnits: offer.obligationUnits,
|
|
2297
2352
|
obligationShares: offer.obligationShares,
|
|
2298
|
-
|
|
2353
|
+
tick: BigInt(offer.tick),
|
|
2299
2354
|
maturity: BigInt(offer.maturity),
|
|
2300
2355
|
expiry: BigInt(offer.expiry),
|
|
2301
2356
|
group: offer.group,
|
|
@@ -2346,7 +2401,7 @@ const OfferAbi = [
|
|
|
2346
2401
|
type: "uint256"
|
|
2347
2402
|
},
|
|
2348
2403
|
{
|
|
2349
|
-
name: "
|
|
2404
|
+
name: "tick",
|
|
2350
2405
|
type: "uint256"
|
|
2351
2406
|
},
|
|
2352
2407
|
{
|
|
@@ -2417,7 +2472,7 @@ function encode$1(offer) {
|
|
|
2417
2472
|
offer.assets,
|
|
2418
2473
|
offer.obligationUnits,
|
|
2419
2474
|
offer.obligationShares,
|
|
2420
|
-
offer.
|
|
2475
|
+
BigInt(offer.tick),
|
|
2421
2476
|
BigInt(offer.maturity),
|
|
2422
2477
|
BigInt(offer.expiry),
|
|
2423
2478
|
offer.group,
|
|
@@ -2442,7 +2497,7 @@ function decode$1(data) {
|
|
|
2442
2497
|
assets: decoded[1],
|
|
2443
2498
|
obligationUnits: decoded[2],
|
|
2444
2499
|
obligationShares: decoded[3],
|
|
2445
|
-
|
|
2500
|
+
tick: Number(decoded[4]),
|
|
2446
2501
|
maturity: from$16(Number(decoded[5])),
|
|
2447
2502
|
expiry: Number(decoded[6]),
|
|
2448
2503
|
group: decoded[7],
|
|
@@ -2792,6 +2847,85 @@ var InvalidQuoteError = class extends BaseError {
|
|
|
2792
2847
|
}
|
|
2793
2848
|
};
|
|
2794
2849
|
|
|
2850
|
+
//#endregion
|
|
2851
|
+
//#region src/core/Tick.ts
|
|
2852
|
+
var Tick_exports = /* @__PURE__ */ __exportAll({
|
|
2853
|
+
InvalidPriceError: () => InvalidPriceError,
|
|
2854
|
+
InvalidTickError: () => InvalidTickError,
|
|
2855
|
+
MAX_PRICE: () => MAX_PRICE,
|
|
2856
|
+
TICK_RANGE: () => TICK_RANGE,
|
|
2857
|
+
priceToTick: () => priceToTick,
|
|
2858
|
+
tickToPrice: () => tickToPrice
|
|
2859
|
+
});
|
|
2860
|
+
/** ln(1 + 0.025), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2861
|
+
const LN_ONE_PLUS_DELTA = 24692612590371501n;
|
|
2862
|
+
/** ln(2), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2863
|
+
const LN2 = 693147180559945309n;
|
|
2864
|
+
const WAD$1 = 10n ** 18n;
|
|
2865
|
+
const WAD_SQUARED = 10n ** 36n;
|
|
2866
|
+
const PRICE_STEP = 10n ** 13n;
|
|
2867
|
+
const HALF_TICK_RANGE = 495n;
|
|
2868
|
+
/** Tick domain supported by Morpho V2. */
|
|
2869
|
+
const TICK_RANGE = 990;
|
|
2870
|
+
/** Max allowed price (1e18 in wad). */
|
|
2871
|
+
const MAX_PRICE = WAD$1;
|
|
2872
|
+
/**
|
|
2873
|
+
* Converts a tick to a wad price using the same approximation and rounding as TickLib.
|
|
2874
|
+
* @param tick - Tick value in the inclusive range [0, 990].
|
|
2875
|
+
* @returns The price in wad units.
|
|
2876
|
+
* @throws {@link InvalidTickError} If tick is not an integer in range [0, 990].
|
|
2877
|
+
*/
|
|
2878
|
+
function tickToPrice(tick) {
|
|
2879
|
+
assertTick(tick);
|
|
2880
|
+
return divHalfDownUnchecked(divHalfDownUnchecked(WAD_SQUARED, WAD$1 + wExp(LN_ONE_PLUS_DELTA * (HALF_TICK_RANGE - BigInt(tick)))), PRICE_STEP) * PRICE_STEP;
|
|
2881
|
+
}
|
|
2882
|
+
/**
|
|
2883
|
+
* Returns the lowest tick with a higher-or-equal price.
|
|
2884
|
+
* @param price - Price in wad units.
|
|
2885
|
+
* @returns The first tick whose {@link tickToPrice} is greater than or equal to `price`.
|
|
2886
|
+
* @throws {@link InvalidPriceError} If price is outside [0, 1e18].
|
|
2887
|
+
*/
|
|
2888
|
+
function priceToTick(price) {
|
|
2889
|
+
assertPrice(price);
|
|
2890
|
+
let low = 0;
|
|
2891
|
+
let high = TICK_RANGE;
|
|
2892
|
+
while (low !== high) {
|
|
2893
|
+
const mid = Math.floor((low + high) / 2);
|
|
2894
|
+
if (tickToPrice(mid) < price) low = mid + 1;
|
|
2895
|
+
else high = mid;
|
|
2896
|
+
}
|
|
2897
|
+
return low;
|
|
2898
|
+
}
|
|
2899
|
+
function divHalfDownUnchecked(x, d) {
|
|
2900
|
+
return (x + (d - 1n) / 2n) / d;
|
|
2901
|
+
}
|
|
2902
|
+
function wExp(x) {
|
|
2903
|
+
if (x < 0n) return WAD_SQUARED / wExp(-x);
|
|
2904
|
+
const q = (x + LN2 / 2n) / LN2;
|
|
2905
|
+
const r = x - q * LN2;
|
|
2906
|
+
const secondTerm = r * r / (2n * WAD$1);
|
|
2907
|
+
const thirdTerm = secondTerm * r / (3n * WAD$1);
|
|
2908
|
+
return WAD$1 + r + secondTerm + thirdTerm << q;
|
|
2909
|
+
}
|
|
2910
|
+
function assertTick(tick) {
|
|
2911
|
+
if (!Number.isInteger(tick) || tick < 0 || tick > TICK_RANGE) throw new InvalidTickError(tick);
|
|
2912
|
+
}
|
|
2913
|
+
function assertPrice(price) {
|
|
2914
|
+
if (price < 0n || price > MAX_PRICE) throw new InvalidPriceError(price);
|
|
2915
|
+
}
|
|
2916
|
+
var InvalidTickError = class extends BaseError {
|
|
2917
|
+
name = "Tick.InvalidTickError";
|
|
2918
|
+
constructor(tick) {
|
|
2919
|
+
super(`Invalid tick: ${tick}. Tick must be an integer between 0 and ${TICK_RANGE}.`);
|
|
2920
|
+
}
|
|
2921
|
+
};
|
|
2922
|
+
var InvalidPriceError = class extends BaseError {
|
|
2923
|
+
name = "Tick.InvalidPriceError";
|
|
2924
|
+
constructor(price) {
|
|
2925
|
+
super(`Invalid price: ${price}. Price must be between 0 and ${MAX_PRICE}.`);
|
|
2926
|
+
}
|
|
2927
|
+
};
|
|
2928
|
+
|
|
2795
2929
|
//#endregion
|
|
2796
2930
|
//#region src/core/TradingFee.ts
|
|
2797
2931
|
var TradingFee_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -3305,7 +3439,7 @@ const BrandTypeId = Symbol.for("mempool/Brand");
|
|
|
3305
3439
|
|
|
3306
3440
|
//#endregion
|
|
3307
3441
|
//#region src/database/drizzle/VERSION.ts
|
|
3308
|
-
const VERSION = "router_v1.
|
|
3442
|
+
const VERSION = "router_v1.8";
|
|
3309
3443
|
|
|
3310
3444
|
//#endregion
|
|
3311
3445
|
//#region src/database/drizzle/schema.ts
|
|
@@ -3457,10 +3591,7 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
3457
3591
|
precision: 78,
|
|
3458
3592
|
scale: 0
|
|
3459
3593
|
}).notNull().default("0"),
|
|
3460
|
-
|
|
3461
|
-
precision: 78,
|
|
3462
|
-
scale: 0
|
|
3463
|
-
}).notNull(),
|
|
3594
|
+
tick: integer("tick").notNull(),
|
|
3464
3595
|
maturity: integer("maturity").notNull(),
|
|
3465
3596
|
expiry: integer("expiry").notNull(),
|
|
3466
3597
|
start: integer("start").notNull(),
|
|
@@ -3525,6 +3656,7 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3525
3656
|
user: varchar("user", { length: 42 }).notNull(),
|
|
3526
3657
|
contract: varchar("contract", { length: 42 }).notNull(),
|
|
3527
3658
|
group: varchar("group", { length: 66 }).notNull(),
|
|
3659
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
3528
3660
|
lower: numeric("lower", {
|
|
3529
3661
|
precision: 78,
|
|
3530
3662
|
scale: 0
|
|
@@ -3539,7 +3671,8 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3539
3671
|
table.chainId,
|
|
3540
3672
|
table.user,
|
|
3541
3673
|
table.contract,
|
|
3542
|
-
table.group
|
|
3674
|
+
table.group,
|
|
3675
|
+
table.obligationId
|
|
3543
3676
|
],
|
|
3544
3677
|
name: "lots_pk"
|
|
3545
3678
|
}),
|
|
@@ -3575,6 +3708,7 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3575
3708
|
user: varchar("user", { length: 42 }).notNull(),
|
|
3576
3709
|
contract: varchar("contract", { length: 42 }).notNull(),
|
|
3577
3710
|
group: varchar("group", { length: 66 }).notNull(),
|
|
3711
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
3578
3712
|
value: numeric("value", {
|
|
3579
3713
|
precision: 78,
|
|
3580
3714
|
scale: 0
|
|
@@ -3584,7 +3718,8 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3584
3718
|
table.chainId,
|
|
3585
3719
|
table.user,
|
|
3586
3720
|
table.contract,
|
|
3587
|
-
table.group
|
|
3721
|
+
table.group,
|
|
3722
|
+
table.obligationId
|
|
3588
3723
|
],
|
|
3589
3724
|
name: "offsets_pk"
|
|
3590
3725
|
}), foreignKey({
|
|
@@ -4175,6 +4310,7 @@ function decodeCallbacks(parameters) {
|
|
|
4175
4310
|
positionContract: loanToken,
|
|
4176
4311
|
positionUser: offer.maker,
|
|
4177
4312
|
group: offer.group,
|
|
4313
|
+
obligationId: obligationId(offer),
|
|
4178
4314
|
size: offer.assets
|
|
4179
4315
|
});
|
|
4180
4316
|
callbacks.push({
|
|
@@ -5113,8 +5249,10 @@ async function getRemoteBlockNumbers(healthClients) {
|
|
|
5113
5249
|
//#region src/api/Schema/BookResponse.ts
|
|
5114
5250
|
var BookResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$5 });
|
|
5115
5251
|
function from$5(level) {
|
|
5252
|
+
const price = tickToPrice(level.tick);
|
|
5116
5253
|
return {
|
|
5117
|
-
|
|
5254
|
+
tick: level.tick,
|
|
5255
|
+
price: price.toString(),
|
|
5118
5256
|
assets: level.assets.toString(),
|
|
5119
5257
|
count: level.count
|
|
5120
5258
|
};
|
|
@@ -5182,6 +5320,16 @@ function from$4(obligation, quote) {
|
|
|
5182
5320
|
//#endregion
|
|
5183
5321
|
//#region src/api/Schema/OfferResponse.ts
|
|
5184
5322
|
var OfferResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$3 });
|
|
5323
|
+
function normalizeChainId(chainId) {
|
|
5324
|
+
const parsedChainId = Number(chainId);
|
|
5325
|
+
if (!Number.isInteger(parsedChainId) || parsedChainId <= 0) throw new Error(`Invalid chain id: ${String(chainId)}`);
|
|
5326
|
+
return parsedChainId;
|
|
5327
|
+
}
|
|
5328
|
+
function normalizeBlockNumber(blockNumber) {
|
|
5329
|
+
const parsedBlockNumber = Number(blockNumber);
|
|
5330
|
+
if (!Number.isInteger(parsedBlockNumber) || parsedBlockNumber < 0) throw new Error(`Invalid block number: ${String(blockNumber)}`);
|
|
5331
|
+
return parsedBlockNumber;
|
|
5332
|
+
}
|
|
5185
5333
|
/**
|
|
5186
5334
|
* Creates an `OfferResponse` matching the Solidity Offer struct layout.
|
|
5187
5335
|
* @constructor
|
|
@@ -5189,6 +5337,8 @@ var OfferResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$3 });
|
|
|
5189
5337
|
* @returns The created `OfferResponse`. {@link OfferResponse}
|
|
5190
5338
|
*/
|
|
5191
5339
|
function from$3(input) {
|
|
5340
|
+
const chainId = normalizeChainId(input.chainId);
|
|
5341
|
+
const blockNumber = normalizeBlockNumber(input.blockNumber);
|
|
5192
5342
|
const base = {
|
|
5193
5343
|
offer: {
|
|
5194
5344
|
obligation: {
|
|
@@ -5207,7 +5357,7 @@ function from$3(input) {
|
|
|
5207
5357
|
obligation_shares: input.obligationShares.toString(),
|
|
5208
5358
|
start: input.start,
|
|
5209
5359
|
expiry: input.expiry,
|
|
5210
|
-
|
|
5360
|
+
tick: input.tick,
|
|
5211
5361
|
group: input.group,
|
|
5212
5362
|
session: input.session,
|
|
5213
5363
|
callback: input.callback.address,
|
|
@@ -5215,15 +5365,15 @@ function from$3(input) {
|
|
|
5215
5365
|
},
|
|
5216
5366
|
offer_hash: input.hash,
|
|
5217
5367
|
obligation_id: id({
|
|
5218
|
-
chainId
|
|
5368
|
+
chainId,
|
|
5219
5369
|
loanToken: input.loanToken,
|
|
5220
5370
|
collaterals: [...input.collaterals],
|
|
5221
5371
|
maturity: input.maturity
|
|
5222
5372
|
}),
|
|
5223
|
-
chain_id:
|
|
5373
|
+
chain_id: chainId,
|
|
5224
5374
|
consumed: input.consumed.toString(),
|
|
5225
5375
|
takeable: input.takeable.toString(),
|
|
5226
|
-
block_number:
|
|
5376
|
+
block_number: blockNumber
|
|
5227
5377
|
};
|
|
5228
5378
|
if (!input.proof || !input.root || !input.signature) return {
|
|
5229
5379
|
...base,
|
|
@@ -5369,7 +5519,7 @@ const offerExample = {
|
|
|
5369
5519
|
obligation_shares: "0",
|
|
5370
5520
|
start: 1761922790,
|
|
5371
5521
|
expiry: 1761922799,
|
|
5372
|
-
|
|
5522
|
+
tick: 495,
|
|
5373
5523
|
group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
|
|
5374
5524
|
session: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
5375
5525
|
callback: "0x0000000000000000000000000000000000000000",
|
|
@@ -5410,7 +5560,7 @@ const validateOfferExample = {
|
|
|
5410
5560
|
assets: "369216000000000000000000",
|
|
5411
5561
|
obligation_units: "0",
|
|
5412
5562
|
obligation_shares: "0",
|
|
5413
|
-
|
|
5563
|
+
tick: 495,
|
|
5414
5564
|
maturity: 1761922799,
|
|
5415
5565
|
expiry: 1761922799,
|
|
5416
5566
|
start: 1761922790,
|
|
@@ -5554,9 +5704,11 @@ __decorate([ApiProperty({
|
|
|
5554
5704
|
example: offerExample.offer.expiry
|
|
5555
5705
|
})], OfferDataResponse.prototype, "expiry", void 0);
|
|
5556
5706
|
__decorate([ApiProperty({
|
|
5557
|
-
type: "
|
|
5558
|
-
example: offerExample.offer.
|
|
5559
|
-
|
|
5707
|
+
type: "number",
|
|
5708
|
+
example: offerExample.offer.tick,
|
|
5709
|
+
minimum: 0,
|
|
5710
|
+
maximum: 990
|
|
5711
|
+
})], OfferDataResponse.prototype, "tick", void 0);
|
|
5560
5712
|
__decorate([ApiProperty({
|
|
5561
5713
|
type: "string",
|
|
5562
5714
|
example: offerExample.offer.group
|
|
@@ -5797,9 +5949,11 @@ __decorate([ApiProperty({
|
|
|
5797
5949
|
required: false
|
|
5798
5950
|
})], ValidateOfferRequest.prototype, "obligation_shares", void 0);
|
|
5799
5951
|
__decorate([ApiProperty({
|
|
5800
|
-
type: "
|
|
5801
|
-
example: validateOfferExample.
|
|
5802
|
-
|
|
5952
|
+
type: "number",
|
|
5953
|
+
example: validateOfferExample.tick,
|
|
5954
|
+
minimum: 0,
|
|
5955
|
+
maximum: 990
|
|
5956
|
+
})], ValidateOfferRequest.prototype, "tick", void 0);
|
|
5803
5957
|
__decorate([ApiProperty({
|
|
5804
5958
|
type: "number",
|
|
5805
5959
|
example: validateOfferExample.maturity
|
|
@@ -5899,9 +6053,16 @@ __decorate([ApiProperty({
|
|
|
5899
6053
|
description: "List of validation issues. Returned when any offer fails validation."
|
|
5900
6054
|
})], ValidationFailureResponse.prototype, "data", void 0);
|
|
5901
6055
|
var BookLevelResponse = class {};
|
|
6056
|
+
__decorate([ApiProperty({
|
|
6057
|
+
type: "number",
|
|
6058
|
+
example: 495,
|
|
6059
|
+
minimum: 0,
|
|
6060
|
+
maximum: 990
|
|
6061
|
+
})], BookLevelResponse.prototype, "tick", void 0);
|
|
5902
6062
|
__decorate([ApiProperty({
|
|
5903
6063
|
type: "string",
|
|
5904
|
-
example: "
|
|
6064
|
+
example: "500000000000000000",
|
|
6065
|
+
description: "Price derived from tick, scaled by 1e18."
|
|
5905
6066
|
})], BookLevelResponse.prototype, "price", void 0);
|
|
5906
6067
|
__decorate([ApiProperty({
|
|
5907
6068
|
type: "string",
|
|
@@ -5915,6 +6076,7 @@ const positionExample = {
|
|
|
5915
6076
|
chain_id: 1,
|
|
5916
6077
|
contract: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
|
|
5917
6078
|
user: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
|
|
6079
|
+
obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
|
|
5918
6080
|
reserved: "200000000000000000000",
|
|
5919
6081
|
block_number: 21345678
|
|
5920
6082
|
};
|
|
@@ -5931,6 +6093,12 @@ __decorate([ApiProperty({
|
|
|
5931
6093
|
type: "string",
|
|
5932
6094
|
example: positionExample.user
|
|
5933
6095
|
})], PositionListItemResponse.prototype, "user", void 0);
|
|
6096
|
+
__decorate([ApiProperty({
|
|
6097
|
+
type: "string",
|
|
6098
|
+
nullable: true,
|
|
6099
|
+
example: positionExample.obligation_id,
|
|
6100
|
+
description: "Obligation id this reserved amount belongs to, or null if no lots exist."
|
|
6101
|
+
})], PositionListItemResponse.prototype, "obligation_id", void 0);
|
|
5934
6102
|
__decorate([ApiProperty({
|
|
5935
6103
|
type: "string",
|
|
5936
6104
|
example: positionExample.reserved
|
|
@@ -5958,7 +6126,7 @@ __decorate([ApiProperty({
|
|
|
5958
6126
|
})], BookListResponse.prototype, "cursor", void 0);
|
|
5959
6127
|
__decorate([ApiProperty({
|
|
5960
6128
|
type: () => [BookLevelResponse],
|
|
5961
|
-
description: "Aggregated book levels grouped by
|
|
6129
|
+
description: "Aggregated book levels grouped by offer tick."
|
|
5962
6130
|
})], BookListResponse.prototype, "data", void 0);
|
|
5963
6131
|
let BooksController = class BooksController {
|
|
5964
6132
|
async getBook() {}
|
|
@@ -5968,7 +6136,7 @@ __decorate([
|
|
|
5968
6136
|
methods: ["get"],
|
|
5969
6137
|
path: "/v1/books/{obligationId}/{side}",
|
|
5970
6138
|
summary: "Get aggregated book",
|
|
5971
|
-
description: "Returns aggregated book data for a given obligation and side. Offers are grouped by
|
|
6139
|
+
description: "Returns aggregated book data for a given obligation and side. Offers are grouped by tick with summed takeable amounts, and each level includes the corresponding wad-scaled price. Book levels are sorted by tick (ascending for sell side, descending for buy side)."
|
|
5972
6140
|
}),
|
|
5973
6141
|
ApiParam({
|
|
5974
6142
|
name: "obligationId",
|
|
@@ -5993,7 +6161,7 @@ __decorate([
|
|
|
5993
6161
|
name: "limit",
|
|
5994
6162
|
type: "number",
|
|
5995
6163
|
example: 10,
|
|
5996
|
-
description: "Maximum number of
|
|
6164
|
+
description: "Maximum number of tick levels to return."
|
|
5997
6165
|
}),
|
|
5998
6166
|
ApiResponse({
|
|
5999
6167
|
status: 200,
|
|
@@ -6187,6 +6355,11 @@ const configRulesLoanTokenExample = {
|
|
|
6187
6355
|
chain_id: 1,
|
|
6188
6356
|
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
6189
6357
|
};
|
|
6358
|
+
const configRulesCollateralTokenExample = {
|
|
6359
|
+
type: "collateral_token",
|
|
6360
|
+
chain_id: 1,
|
|
6361
|
+
address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
6362
|
+
};
|
|
6190
6363
|
const configRulesOracleExample = {
|
|
6191
6364
|
type: "oracle",
|
|
6192
6365
|
chain_id: 1,
|
|
@@ -6196,6 +6369,7 @@ const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
|
|
|
6196
6369
|
const configRulesPayloadExample = [
|
|
6197
6370
|
configRulesMaturityExample,
|
|
6198
6371
|
configRulesLoanTokenExample,
|
|
6372
|
+
configRulesCollateralTokenExample,
|
|
6199
6373
|
configRulesOracleExample
|
|
6200
6374
|
];
|
|
6201
6375
|
const configContractNames = [
|
|
@@ -6322,7 +6496,7 @@ __decorate([
|
|
|
6322
6496
|
methods: ["get"],
|
|
6323
6497
|
path: "/v1/config/rules",
|
|
6324
6498
|
summary: "Get config rules",
|
|
6325
|
-
description: "Returns configured rules (maturities, loan tokens, oracles) for supported chains."
|
|
6499
|
+
description: "Returns configured rules (maturities, loan tokens, collateral tokens, oracles) for supported chains."
|
|
6326
6500
|
}),
|
|
6327
6501
|
ApiQuery({
|
|
6328
6502
|
name: "cursor",
|
|
@@ -6342,7 +6516,7 @@ __decorate([
|
|
|
6342
6516
|
name: "types",
|
|
6343
6517
|
type: ["string"],
|
|
6344
6518
|
required: false,
|
|
6345
|
-
example: "maturity,loan_token,oracle",
|
|
6519
|
+
example: "maturity,loan_token,collateral_token,oracle",
|
|
6346
6520
|
description: "Filter by rule types (comma-separated).",
|
|
6347
6521
|
style: "form",
|
|
6348
6522
|
explode: false
|
|
@@ -6460,7 +6634,7 @@ __decorate([
|
|
|
6460
6634
|
methods: ["get"],
|
|
6461
6635
|
path: "/v1/users/{userAddress}/positions",
|
|
6462
6636
|
summary: "Get user positions",
|
|
6463
|
-
description: "Returns positions for a user with reserved balance.
|
|
6637
|
+
description: "Returns positions for a user with reserved balance per obligation. Each (position, obligation) pair is returned as a separate row. Positions with no lots return a single row with obligation_id = null and reserved = 0."
|
|
6464
6638
|
}),
|
|
6465
6639
|
ApiParam({
|
|
6466
6640
|
name: "userAddress",
|
|
@@ -6548,6 +6722,7 @@ function from$2(position) {
|
|
|
6548
6722
|
chain_id: position.chainId,
|
|
6549
6723
|
contract: position.contract,
|
|
6550
6724
|
user: position.user,
|
|
6725
|
+
obligation_id: position.obligationId,
|
|
6551
6726
|
reserved: position.reserved.toString(),
|
|
6552
6727
|
block_number: position.blockNumber
|
|
6553
6728
|
};
|
|
@@ -6601,10 +6776,11 @@ const ConfigRuleTypes = z$1.enum([
|
|
|
6601
6776
|
"maturity",
|
|
6602
6777
|
"callback",
|
|
6603
6778
|
"loan_token",
|
|
6779
|
+
"collateral_token",
|
|
6604
6780
|
"oracle"
|
|
6605
6781
|
]);
|
|
6606
6782
|
const GetConfigRulesQueryParams = z$1.object({
|
|
6607
|
-
cursor: z$1.string().regex(/^(maturity|callback|loan_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
6783
|
+
cursor: z$1.string().regex(/^(maturity|callback|loan_token|collateral_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
6608
6784
|
description: "Pagination cursor in type:chain_id:<value> format",
|
|
6609
6785
|
example: "maturity:1:1730415600:end_of_next_month"
|
|
6610
6786
|
}),
|
|
@@ -6614,7 +6790,7 @@ const GetConfigRulesQueryParams = z$1.object({
|
|
|
6614
6790
|
}),
|
|
6615
6791
|
types: csvArray(ConfigRuleTypes).meta({
|
|
6616
6792
|
description: "Filter by rule types (comma-separated).",
|
|
6617
|
-
example: "maturity,loan_token,oracle"
|
|
6793
|
+
example: "maturity,loan_token,collateral_token,oracle"
|
|
6618
6794
|
}),
|
|
6619
6795
|
chains: csvArray(z$1.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
6620
6796
|
description: "Filter by chain IDs (comma-separated).",
|
|
@@ -6714,12 +6890,11 @@ const GetObligationParams = z$1.object({ obligation_id: z$1.string({ error: "Obl
|
|
|
6714
6890
|
description: "Obligation id",
|
|
6715
6891
|
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
6716
6892
|
}) });
|
|
6717
|
-
/** Validate a book cursor format: {side,
|
|
6893
|
+
/** Validate a book cursor format: {side, lastTick, offersCursor} */
|
|
6718
6894
|
function isValidBookCursor(cursorString) {
|
|
6719
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
6720
6895
|
try {
|
|
6721
6896
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
6722
|
-
return (v?.side === "buy" || v?.side === "sell") &&
|
|
6897
|
+
return (v?.side === "buy" || v?.side === "sell") && typeof v?.lastTick === "number" && Number.isInteger(v.lastTick) && (v?.offersCursor === null || typeof v?.offersCursor === "string");
|
|
6723
6898
|
} catch {
|
|
6724
6899
|
return false;
|
|
6725
6900
|
}
|
|
@@ -6793,12 +6968,34 @@ async function getBook(params, db) {
|
|
|
6793
6968
|
if (!result.success) return failure(result.error);
|
|
6794
6969
|
const query = result.data;
|
|
6795
6970
|
try {
|
|
6971
|
+
logger.debug({
|
|
6972
|
+
service: "api_controller",
|
|
6973
|
+
endpoint: "get_book",
|
|
6974
|
+
msg: "Loading book levels",
|
|
6975
|
+
obligation_id: query.obligation_id,
|
|
6976
|
+
side: query.side,
|
|
6977
|
+
limit: query.limit ?? null,
|
|
6978
|
+
has_cursor: query.cursor != null
|
|
6979
|
+
});
|
|
6796
6980
|
const { levels, nextCursor } = await db.book.get({
|
|
6797
6981
|
side: query.side,
|
|
6798
6982
|
obligationId: query.obligation_id,
|
|
6799
6983
|
cursor: query.cursor,
|
|
6800
6984
|
limit: query.limit
|
|
6801
6985
|
});
|
|
6986
|
+
const firstLevel = levels[0];
|
|
6987
|
+
logger.debug({
|
|
6988
|
+
service: "api_controller",
|
|
6989
|
+
endpoint: "get_book",
|
|
6990
|
+
msg: "Loaded book levels",
|
|
6991
|
+
obligation_id: query.obligation_id,
|
|
6992
|
+
side: query.side,
|
|
6993
|
+
levels_count: levels.length,
|
|
6994
|
+
has_next_cursor: nextCursor != null,
|
|
6995
|
+
first_level_tick: firstLevel?.tick ?? null,
|
|
6996
|
+
first_level_assets: firstLevel?.assets.toString() ?? null,
|
|
6997
|
+
first_level_count: firstLevel?.count ?? null
|
|
6998
|
+
});
|
|
6802
6999
|
return success({
|
|
6803
7000
|
data: levels.map(from$5),
|
|
6804
7001
|
cursor: nextCursor
|
|
@@ -6947,6 +7144,33 @@ const assets = {
|
|
|
6947
7144
|
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
6948
7145
|
]
|
|
6949
7146
|
};
|
|
7147
|
+
const collateralAssets = {
|
|
7148
|
+
[ChainId.ETHEREUM.toString()]: [
|
|
7149
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7150
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7151
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7152
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7153
|
+
],
|
|
7154
|
+
[ChainId.BASE.toString()]: [
|
|
7155
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
7156
|
+
"0x4200000000000000000000000000000000000006",
|
|
7157
|
+
"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
|
|
7158
|
+
"0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
|
|
7159
|
+
"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
|
|
7160
|
+
],
|
|
7161
|
+
[ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
|
|
7162
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7163
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7164
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7165
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7166
|
+
],
|
|
7167
|
+
[ChainId.ANVIL.toString()]: [
|
|
7168
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
7169
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
7170
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
7171
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
7172
|
+
]
|
|
7173
|
+
};
|
|
6950
7174
|
const oracles = {
|
|
6951
7175
|
[ChainId.ETHEREUM.toString()]: [
|
|
6952
7176
|
"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
|
|
@@ -7006,7 +7230,7 @@ const configs = {
|
|
|
7006
7230
|
//#endregion
|
|
7007
7231
|
//#region src/gatekeeper/ConfigRules.ts
|
|
7008
7232
|
/**
|
|
7009
|
-
* Build the configured rules (maturities + callback addresses + loan tokens + oracles) for the provided chains.
|
|
7233
|
+
* Build the configured rules (maturities + callback addresses + loan tokens + collateral tokens + oracles) for the provided chains.
|
|
7010
7234
|
* @param chains - Chains to include in the configured rules.
|
|
7011
7235
|
* @returns Sorted list of config rules.
|
|
7012
7236
|
*/
|
|
@@ -7026,6 +7250,12 @@ function buildConfigRules(chains) {
|
|
|
7026
7250
|
chain_id: chain.id,
|
|
7027
7251
|
address: normalizeAddress(address)
|
|
7028
7252
|
});
|
|
7253
|
+
const collateralTokens = collateralAssets[chain.id.toString()] ?? [];
|
|
7254
|
+
for (const address of collateralTokens) rules.push({
|
|
7255
|
+
type: "collateral_token",
|
|
7256
|
+
chain_id: chain.id,
|
|
7257
|
+
address: normalizeAddress(address)
|
|
7258
|
+
});
|
|
7029
7259
|
const oracles$2 = oracles[chain.id.toString()] ?? [];
|
|
7030
7260
|
for (const address of oracles$2) rules.push({
|
|
7031
7261
|
type: "oracle",
|
|
@@ -7053,6 +7283,10 @@ function buildConfigRulesChecksum(rules) {
|
|
|
7053
7283
|
hash.update(`callback:${rule.chain_id}:${rule.callback_type}:${rule.address}\n`);
|
|
7054
7284
|
continue;
|
|
7055
7285
|
}
|
|
7286
|
+
if (rule.type === "collateral_token") {
|
|
7287
|
+
hash.update(`collateral_token:${rule.chain_id}:${rule.address}\n`);
|
|
7288
|
+
continue;
|
|
7289
|
+
}
|
|
7056
7290
|
if (rule.type === "oracle") {
|
|
7057
7291
|
hash.update(`oracle:${rule.chain_id}:${rule.address}\n`);
|
|
7058
7292
|
continue;
|
|
@@ -7073,6 +7307,7 @@ function compareConfigRules(left, right) {
|
|
|
7073
7307
|
return left.address.localeCompare(right.address);
|
|
7074
7308
|
}
|
|
7075
7309
|
if (left.type === "loan_token" && right.type === "loan_token") return left.address.localeCompare(right.address);
|
|
7310
|
+
if (left.type === "collateral_token" && right.type === "collateral_token") return left.address.localeCompare(right.address);
|
|
7076
7311
|
if (left.type === "oracle" && right.type === "oracle") return left.address.localeCompare(right.address);
|
|
7077
7312
|
return 0;
|
|
7078
7313
|
}
|
|
@@ -7119,6 +7354,7 @@ function formatCursor(rule) {
|
|
|
7119
7354
|
if (rule.type === "maturity") return `maturity:${rule.chain_id}:${rule.timestamp}:${rule.name}`;
|
|
7120
7355
|
if (rule.type === "callback") return `callback:${rule.chain_id}:${rule.callback_type}:${rule.address.toLowerCase()}`;
|
|
7121
7356
|
if (rule.type === "oracle") return `oracle:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7357
|
+
if (rule.type === "collateral_token") return `collateral_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7122
7358
|
return `loan_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7123
7359
|
}
|
|
7124
7360
|
function parseCursor(cursor) {
|
|
@@ -7151,7 +7387,7 @@ function parseCursor(cursor) {
|
|
|
7151
7387
|
address: parseAddress(addressValue, "Cursor address")
|
|
7152
7388
|
};
|
|
7153
7389
|
}
|
|
7154
|
-
if (type === "loan_token" || type === "oracle") {
|
|
7390
|
+
if (type === "loan_token" || type === "collateral_token" || type === "oracle") {
|
|
7155
7391
|
const addressValue = rest.join(":");
|
|
7156
7392
|
if (!addressValue) throw new BadRequestError(`Cursor must be in the format ${type}:chain_id:address`);
|
|
7157
7393
|
return {
|
|
@@ -7178,7 +7414,7 @@ function parseAddress(address, label) {
|
|
|
7178
7414
|
return address.toLowerCase();
|
|
7179
7415
|
}
|
|
7180
7416
|
function isConfigRuleType(value) {
|
|
7181
|
-
return value === "maturity" || value === "callback" || value === "loan_token" || value === "oracle";
|
|
7417
|
+
return value === "maturity" || value === "callback" || value === "loan_token" || value === "collateral_token" || value === "oracle";
|
|
7182
7418
|
}
|
|
7183
7419
|
function isMaturityType(value) {
|
|
7184
7420
|
return Object.values(MaturityType).includes(value);
|
|
@@ -7525,7 +7761,7 @@ function create$15(config) {
|
|
|
7525
7761
|
assets: offers.assets,
|
|
7526
7762
|
obligationUnits: offers.obligationUnits,
|
|
7527
7763
|
obligationShares: offers.obligationShares,
|
|
7528
|
-
|
|
7764
|
+
tick: offers.tick,
|
|
7529
7765
|
maturity: offers.maturity,
|
|
7530
7766
|
expiry: offers.expiry,
|
|
7531
7767
|
start: offers.start,
|
|
@@ -7545,7 +7781,7 @@ function create$15(config) {
|
|
|
7545
7781
|
assets: BigInt(row.assets),
|
|
7546
7782
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7547
7783
|
obligationShares: BigInt(row.obligationShares),
|
|
7548
|
-
|
|
7784
|
+
tick: row.tick,
|
|
7549
7785
|
maturity: from$16(row.maturity),
|
|
7550
7786
|
expiry: row.expiry,
|
|
7551
7787
|
start: row.start,
|
|
@@ -7627,8 +7863,8 @@ function create$15(config) {
|
|
|
7627
7863
|
const now$2 = now();
|
|
7628
7864
|
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
7629
7865
|
obligationId: offers.obligationId,
|
|
7630
|
-
price: offers.
|
|
7631
|
-
}).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(inArray(offers.obligationId, obligationIds), eq(offers.buy, side === "buy"), gte(offers.expiry, now$2), gte(offers.maturity, now$2), lte(offers.start, now$2), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? sql`${offers.
|
|
7866
|
+
price: offers.tick
|
|
7867
|
+
}).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(inArray(offers.obligationId, obligationIds), eq(offers.buy, side === "buy"), gte(offers.expiry, now$2), gte(offers.maturity, now$2), lte(offers.start, now$2), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? sql`${offers.tick} ASC` : sql`${offers.tick} DESC`);
|
|
7632
7868
|
const [bestBuys, bestSells] = await Promise.all([query({ side: "buy" }), query({ side: "sell" })]);
|
|
7633
7869
|
const quotes = /* @__PURE__ */ new Map();
|
|
7634
7870
|
for (const row of bestSells) quotes.set(row.obligationId, {
|
|
@@ -7686,16 +7922,57 @@ async function getOffersQuery(db, parameters) {
|
|
|
7686
7922
|
'[]'::jsonb
|
|
7687
7923
|
)`.as("collaterals") }).from(obligationCollateralsV2).innerJoin(oracles$1, sql`${obligationCollateralsV2.oracleChainId} = ${oracles$1.chainId}
|
|
7688
7924
|
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).where(eq(obligationCollateralsV2.obligationId, offers.obligationId)).as("collaterals_lateral");
|
|
7689
|
-
const
|
|
7690
|
-
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7925
|
+
const lotBalanceExpr = sql`GREATEST(0, LEAST(
|
|
7926
|
+
COALESCE(${positions.balance}, 0)::numeric
|
|
7927
|
+
+ COALESCE((
|
|
7928
|
+
SELECT SUM(${offsets.value}::numeric)
|
|
7929
|
+
FROM ${offsets}
|
|
7930
|
+
WHERE ${offsets.chainId} = ${callbacks.positionChainId}
|
|
7931
|
+
AND LOWER(${offsets.contract}) = LOWER(${callbacks.positionContract})
|
|
7932
|
+
AND LOWER(${offsets.user}) = LOWER(${callbacks.positionUser})
|
|
7933
|
+
), 0)
|
|
7934
|
+
- COALESCE(${lots.lower}::numeric, 0),
|
|
7935
|
+
(COALESCE(${lots.upper}::numeric, 0) - COALESCE(${lots.lower}::numeric, 0))
|
|
7936
|
+
- CASE
|
|
7937
|
+
WHEN ${offers.assets}::numeric > 0
|
|
7938
|
+
THEN COALESCE(${groups.consumed}::numeric, 0)
|
|
7939
|
+
* (COALESCE(${lots.upper}::numeric, 0) - COALESCE(${lots.lower}::numeric, 0))
|
|
7940
|
+
/ ${offers.assets}::numeric
|
|
7941
|
+
ELSE 0
|
|
7942
|
+
END
|
|
7943
|
+
))`;
|
|
7944
|
+
const contributionExpr = sql`CASE
|
|
7945
|
+
WHEN ${positions.asset} IS NULL OR ${lots.lower} IS NULL THEN 0
|
|
7946
|
+
ELSE LEAST(COALESCE(${callbacks.amount}::numeric, ${lotBalanceExpr}), ${lotBalanceExpr})
|
|
7947
|
+
END`;
|
|
7948
|
+
const availableExpr = sql`COALESCE((
|
|
7949
|
+
SELECT SUM(deduped.contribution)
|
|
7950
|
+
FROM (
|
|
7951
|
+
SELECT DISTINCT ON (
|
|
7952
|
+
${callbacks.positionChainId},
|
|
7953
|
+
LOWER(${callbacks.positionContract}),
|
|
7954
|
+
LOWER(${callbacks.positionUser})
|
|
7955
|
+
)
|
|
7956
|
+
${contributionExpr} AS contribution
|
|
7957
|
+
FROM ${offersCallbacks}
|
|
7958
|
+
INNER JOIN ${callbacks} ON ${offersCallbacks.callbackId} = ${callbacks.id}
|
|
7959
|
+
LEFT JOIN ${positions}
|
|
7960
|
+
ON ${positions.chainId} = ${callbacks.positionChainId}
|
|
7961
|
+
AND LOWER(${positions.contract}) = LOWER(${callbacks.positionContract})
|
|
7962
|
+
AND LOWER(${positions.user}) = LOWER(${callbacks.positionUser})
|
|
7963
|
+
LEFT JOIN ${lots}
|
|
7964
|
+
ON ${lots.chainId} = ${callbacks.positionChainId}
|
|
7965
|
+
AND LOWER(${lots.contract}) = LOWER(${callbacks.positionContract})
|
|
7966
|
+
AND LOWER(${lots.user}) = LOWER(${callbacks.positionUser})
|
|
7967
|
+
AND LOWER(${lots.group}) = LOWER(${offers.group})
|
|
7968
|
+
WHERE ${offersCallbacks.offerHash} = ${offers.hash}
|
|
7969
|
+
ORDER BY
|
|
7970
|
+
${callbacks.positionChainId},
|
|
7971
|
+
LOWER(${callbacks.positionContract}),
|
|
7972
|
+
LOWER(${callbacks.positionUser}),
|
|
7973
|
+
${contributionExpr} DESC
|
|
7974
|
+
) deduped
|
|
7975
|
+
), 0)`;
|
|
7699
7976
|
const rows = (await db.select({
|
|
7700
7977
|
hash: offers.hash,
|
|
7701
7978
|
maker: offers.groupMaker,
|
|
@@ -7703,7 +7980,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7703
7980
|
obligationUnits: offers.obligationUnits,
|
|
7704
7981
|
obligationShares: offers.obligationShares,
|
|
7705
7982
|
consumed: groups.consumed,
|
|
7706
|
-
|
|
7983
|
+
tick: offers.tick,
|
|
7707
7984
|
maturity: offers.maturity,
|
|
7708
7985
|
expiry: offers.expiry,
|
|
7709
7986
|
start: offers.start,
|
|
@@ -7716,22 +7993,22 @@ async function getOffersQuery(db, parameters) {
|
|
|
7716
7993
|
callbackData: offers.callbackData,
|
|
7717
7994
|
collaterals: collateralsLateral.collaterals,
|
|
7718
7995
|
blockNumber: offers.blockNumber,
|
|
7719
|
-
available: sql
|
|
7996
|
+
available: sql`${availableExpr}::numeric`.as("available"),
|
|
7720
7997
|
takeable: sql`FLOOR(GREATEST(0,
|
|
7721
7998
|
CASE WHEN ${offers.buy} = false
|
|
7722
7999
|
THEN ${offers.assets}::numeric - ${groups.consumed}::numeric
|
|
7723
8000
|
ELSE LEAST(
|
|
7724
8001
|
${offers.assets}::numeric - ${groups.consumed}::numeric,
|
|
7725
|
-
|
|
8002
|
+
${availableExpr}::numeric
|
|
7726
8003
|
)
|
|
7727
8004
|
END
|
|
7728
8005
|
))`.as("takeable")
|
|
7729
|
-
}).from(offers).innerJoin(obligations, eq(offers.obligationId, obligations.obligationId)).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).innerJoinLateral(collateralsLateral, sql`true`).
|
|
8006
|
+
}).from(offers).innerJoin(obligations, eq(offers.obligationId, obligations.obligationId)).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).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, gte(offers.expiry, now), gte(offers.maturity, now), maker === void 0 ? sql`GREATEST(0,
|
|
7730
8007
|
CASE WHEN ${offers.buy} = false
|
|
7731
8008
|
THEN ${offers.assets}::numeric - ${groups.consumed}::numeric
|
|
7732
8009
|
ELSE LEAST(
|
|
7733
8010
|
${offers.assets}::numeric - ${groups.consumed}::numeric,
|
|
7734
|
-
|
|
8011
|
+
${availableExpr}::numeric
|
|
7735
8012
|
)
|
|
7736
8013
|
END
|
|
7737
8014
|
) > 0` : void 0)).orderBy(asc(offers.hash)).limit(limit)).map((row) => {
|
|
@@ -7741,7 +8018,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
7741
8018
|
assets: BigInt(row.assets),
|
|
7742
8019
|
obligationUnits: BigInt(row.obligationUnits),
|
|
7743
8020
|
obligationShares: BigInt(row.obligationShares),
|
|
7744
|
-
|
|
8021
|
+
tick: row.tick,
|
|
7745
8022
|
maturity: from$16(row.maturity),
|
|
7746
8023
|
expiry: row.expiry,
|
|
7747
8024
|
start: row.start,
|
|
@@ -8140,7 +8417,7 @@ async function getOffers(apiClient, parameters) {
|
|
|
8140
8417
|
assets: offerData.assets,
|
|
8141
8418
|
obligation_units: offerData.obligation_units,
|
|
8142
8419
|
obligation_shares: offerData.obligation_shares,
|
|
8143
|
-
|
|
8420
|
+
tick: offerData.tick,
|
|
8144
8421
|
maturity: from$16(offerData.obligation.maturity),
|
|
8145
8422
|
expiry: offerData.expiry,
|
|
8146
8423
|
start: offerData.start,
|
|
@@ -8499,6 +8776,7 @@ function create$12(config) {
|
|
|
8499
8776
|
return {
|
|
8500
8777
|
get: async (parameters) => {
|
|
8501
8778
|
const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT$2 } = parameters;
|
|
8779
|
+
const tickSortDirection = side === "sell" ? "asc" : "desc";
|
|
8502
8780
|
const inputCursor = LevelCursor.decode(cursorString, logger);
|
|
8503
8781
|
if (cursorString != null && inputCursor === null) return {
|
|
8504
8782
|
levels: [],
|
|
@@ -8513,23 +8791,23 @@ function create$12(config) {
|
|
|
8513
8791
|
cursor: inputCursor?.offersCursor ?? void 0,
|
|
8514
8792
|
limit: fetchLimit
|
|
8515
8793
|
});
|
|
8516
|
-
const
|
|
8794
|
+
const tickMap = /* @__PURE__ */ new Map();
|
|
8517
8795
|
for (const row of rows) {
|
|
8518
|
-
const
|
|
8519
|
-
const existing = priceMap.get(priceKey);
|
|
8796
|
+
const existing = tickMap.get(row.tick);
|
|
8520
8797
|
if (existing) {
|
|
8521
8798
|
existing.assets += row.takeable;
|
|
8522
8799
|
existing.count += 1;
|
|
8523
|
-
} else
|
|
8800
|
+
} else tickMap.set(row.tick, {
|
|
8524
8801
|
assets: row.takeable,
|
|
8525
8802
|
count: 1
|
|
8526
8803
|
});
|
|
8527
8804
|
}
|
|
8528
|
-
const levels = Array.from(
|
|
8529
|
-
|
|
8530
|
-
assets:
|
|
8531
|
-
count:
|
|
8805
|
+
const levels = Array.from(tickMap.entries()).map(([tick, level]) => ({
|
|
8806
|
+
tick,
|
|
8807
|
+
assets: level.assets,
|
|
8808
|
+
count: level.count
|
|
8532
8809
|
}));
|
|
8810
|
+
levels.sort((a, b) => tickSortDirection === "asc" ? a.tick - b.tick : b.tick - a.tick);
|
|
8533
8811
|
const paginatedLevels = levels.slice(0, limit);
|
|
8534
8812
|
const hasMore = levels.length > limit || offersNextCursor !== null;
|
|
8535
8813
|
const lastLevel = paginatedLevels[paginatedLevels.length - 1];
|
|
@@ -8575,14 +8853,14 @@ async function _getOffers(db, params) {
|
|
|
8575
8853
|
AND (s.code IS NULL OR s.code = ${Status.VALID})
|
|
8576
8854
|
ORDER BY
|
|
8577
8855
|
o.group_chain_id, o.group_maker, o."group_group",
|
|
8578
|
-
o.
|
|
8856
|
+
o.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`}, o.block_number ASC, o.assets DESC, o.hash ASC
|
|
8579
8857
|
),
|
|
8580
8858
|
enriched AS (
|
|
8581
8859
|
SELECT
|
|
8582
8860
|
w.*,
|
|
8583
8861
|
g.consumed, g.chain_id, obl.loan_token,
|
|
8584
8862
|
CASE WHEN ${priceSortDirection === "asc" ? sql`TRUE` : sql`FALSE`}
|
|
8585
|
-
THEN w.
|
|
8863
|
+
THEN w.tick ELSE -w.tick END AS tick_norm,
|
|
8586
8864
|
w.block_number AS block_norm,
|
|
8587
8865
|
-w.assets AS assets_norm,
|
|
8588
8866
|
w.hash AS hash_norm
|
|
@@ -8599,33 +8877,35 @@ async function _getOffers(db, params) {
|
|
|
8599
8877
|
FROM enriched e
|
|
8600
8878
|
${cursor != null ? sql`
|
|
8601
8879
|
WHERE
|
|
8602
|
-
(e.
|
|
8880
|
+
(e.tick_norm, e.block_norm, e.assets_norm, e.hash_norm)
|
|
8603
8881
|
> (
|
|
8604
8882
|
CASE WHEN ${priceSortDirection === "asc" ? sql`TRUE` : sql`FALSE`}
|
|
8605
|
-
THEN ${cursor.
|
|
8883
|
+
THEN ${cursor.tick}::integer ELSE -${cursor.tick}::integer END,
|
|
8606
8884
|
${cursor.blockNumber},
|
|
8607
8885
|
-${cursor.assets}::numeric,
|
|
8608
8886
|
${cursor.hash}
|
|
8609
8887
|
)` : sql``}
|
|
8610
|
-
ORDER BY e.
|
|
8888
|
+
ORDER BY e.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`}, e.block_number ASC, e.assets DESC, e.hash ASC
|
|
8611
8889
|
LIMIT ${limit}
|
|
8612
8890
|
),
|
|
8613
|
-
-- Compute sum of offsets per position
|
|
8891
|
+
-- Compute sum of offsets per position and obligation
|
|
8614
8892
|
position_offsets AS (
|
|
8615
8893
|
SELECT
|
|
8616
8894
|
chain_id,
|
|
8617
8895
|
"user",
|
|
8618
8896
|
contract,
|
|
8897
|
+
obligation_id,
|
|
8619
8898
|
SUM(value::numeric) AS total_offset
|
|
8620
8899
|
FROM ${offsets}
|
|
8621
|
-
GROUP BY chain_id, "user", contract
|
|
8900
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
8622
8901
|
),
|
|
8623
|
-
-- Compute position_consumed: sum of consumed from all groups with lots on each position (converted to lot terms)
|
|
8902
|
+
-- Compute position_consumed: sum of consumed from all groups with lots on each position+obligation (converted to lot terms)
|
|
8624
8903
|
position_consumed AS (
|
|
8625
8904
|
SELECT
|
|
8626
8905
|
l.chain_id,
|
|
8627
8906
|
l.contract,
|
|
8628
8907
|
l."user",
|
|
8908
|
+
l.obligation_id,
|
|
8629
8909
|
SUM(
|
|
8630
8910
|
CASE
|
|
8631
8911
|
WHEN wo.assets::numeric > 0
|
|
@@ -8642,7 +8922,7 @@ async function _getOffers(db, params) {
|
|
|
8642
8922
|
ON wo.group_chain_id = g.chain_id
|
|
8643
8923
|
AND LOWER(wo.group_maker) = LOWER(g.maker)
|
|
8644
8924
|
AND wo.group_group = g."group"
|
|
8645
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
8925
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
8646
8926
|
),
|
|
8647
8927
|
-- Compute callback contributions with lot balance
|
|
8648
8928
|
callback_contributions AS (
|
|
@@ -8650,7 +8930,7 @@ async function _getOffers(db, params) {
|
|
|
8650
8930
|
p.hash,
|
|
8651
8931
|
p.obligation_id,
|
|
8652
8932
|
p.assets,
|
|
8653
|
-
p.
|
|
8933
|
+
p.tick,
|
|
8654
8934
|
p.obligation_units,
|
|
8655
8935
|
p.obligation_shares,
|
|
8656
8936
|
p.maturity,
|
|
@@ -8695,6 +8975,7 @@ async function _getOffers(db, params) {
|
|
|
8695
8975
|
AND LOWER(l.contract) = LOWER(c.position_contract)
|
|
8696
8976
|
AND LOWER(l."user") = LOWER(c.position_user)
|
|
8697
8977
|
AND l."group" = p.group_group
|
|
8978
|
+
AND l.obligation_id = p.obligation_id
|
|
8698
8979
|
LEFT JOIN ${positions} pos
|
|
8699
8980
|
ON pos.chain_id = c.position_chain_id
|
|
8700
8981
|
AND LOWER(pos.contract) = LOWER(c.position_contract)
|
|
@@ -8703,10 +8984,12 @@ async function _getOffers(db, params) {
|
|
|
8703
8984
|
ON pos_offsets.chain_id = c.position_chain_id
|
|
8704
8985
|
AND LOWER(pos_offsets.contract) = LOWER(c.position_contract)
|
|
8705
8986
|
AND LOWER(pos_offsets."user") = LOWER(c.position_user)
|
|
8987
|
+
AND pos_offsets.obligation_id = p.obligation_id
|
|
8706
8988
|
LEFT JOIN position_consumed pc
|
|
8707
8989
|
ON pc.chain_id = c.position_chain_id
|
|
8708
8990
|
AND LOWER(pc.contract) = LOWER(c.position_contract)
|
|
8709
8991
|
AND LOWER(pc."user") = LOWER(c.position_user)
|
|
8992
|
+
AND pc.obligation_id = p.obligation_id
|
|
8710
8993
|
),
|
|
8711
8994
|
-- Compute contribution per callback in loan terms (loan token only — collateral positions are not indexed)
|
|
8712
8995
|
callback_loan_contribution AS (
|
|
@@ -8724,7 +9007,7 @@ async function _getOffers(db, params) {
|
|
|
8724
9007
|
hash,
|
|
8725
9008
|
obligation_id,
|
|
8726
9009
|
assets,
|
|
8727
|
-
|
|
9010
|
+
tick,
|
|
8728
9011
|
obligation_units,
|
|
8729
9012
|
obligation_shares,
|
|
8730
9013
|
maturity,
|
|
@@ -8750,13 +9033,13 @@ async function _getOffers(db, params) {
|
|
|
8750
9033
|
WHERE clc.callback_id IS NOT NULL
|
|
8751
9034
|
ORDER BY clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user, clc.contribution_in_loan DESC
|
|
8752
9035
|
) deduped
|
|
8753
|
-
GROUP BY hash, obligation_id, assets,
|
|
9036
|
+
GROUP BY hash, obligation_id, assets, tick, obligation_units, obligation_shares, maturity, expiry, start, group_group, buy,
|
|
8754
9037
|
callback_address, callback_data, block_number, group_chain_id, group_maker,
|
|
8755
9038
|
consumed, chain_id, loan_token, session
|
|
8756
9039
|
UNION ALL
|
|
8757
9040
|
-- Sell offers without callbacks: collateral positions not indexed, takeable = assets - consumed
|
|
8758
9041
|
SELECT
|
|
8759
|
-
p.hash, p.obligation_id, p.assets, p.
|
|
9042
|
+
p.hash, p.obligation_id, p.assets, p.tick,
|
|
8760
9043
|
p.obligation_units, p.obligation_shares,
|
|
8761
9044
|
p.maturity, p.expiry, p.start, p.group_group,
|
|
8762
9045
|
p.buy, p.callback_address, p.callback_data,
|
|
@@ -8778,7 +9061,7 @@ async function _getOffers(db, params) {
|
|
|
8778
9061
|
oc.obligation_units,
|
|
8779
9062
|
oc.obligation_shares,
|
|
8780
9063
|
oc.consumed,
|
|
8781
|
-
oc.
|
|
9064
|
+
oc.tick,
|
|
8782
9065
|
oc.maturity,
|
|
8783
9066
|
oc.expiry,
|
|
8784
9067
|
oc.start,
|
|
@@ -8810,7 +9093,7 @@ async function _getOffers(db, params) {
|
|
|
8810
9093
|
))
|
|
8811
9094
|
END > 0
|
|
8812
9095
|
ORDER BY
|
|
8813
|
-
oc.
|
|
9096
|
+
oc.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`},
|
|
8814
9097
|
oc.block_number ASC,
|
|
8815
9098
|
oc.assets DESC,
|
|
8816
9099
|
oc.hash ASC;
|
|
@@ -8823,7 +9106,7 @@ async function _getOffers(db, params) {
|
|
|
8823
9106
|
assets: BigInt(row.assets),
|
|
8824
9107
|
obligationUnits: BigInt(row.obligation_units ?? 0),
|
|
8825
9108
|
obligationShares: BigInt(row.obligation_shares ?? 0),
|
|
8826
|
-
|
|
9109
|
+
tick: row.tick,
|
|
8827
9110
|
maturity: row.maturity,
|
|
8828
9111
|
expiry: row.expiry,
|
|
8829
9112
|
start: row.start,
|
|
@@ -8855,7 +9138,7 @@ let Cursor;
|
|
|
8855
9138
|
function encode(row, totalReturned, now, side) {
|
|
8856
9139
|
return Buffer.from(JSON.stringify({
|
|
8857
9140
|
side,
|
|
8858
|
-
|
|
9141
|
+
tick: row.tick,
|
|
8859
9142
|
blockNumber: row.blockNumber,
|
|
8860
9143
|
assets: row.assets.toString(),
|
|
8861
9144
|
hash: row.hash,
|
|
@@ -8866,10 +9149,9 @@ let Cursor;
|
|
|
8866
9149
|
_Cursor.encode = encode;
|
|
8867
9150
|
function decode(cursorString, logger) {
|
|
8868
9151
|
if (cursorString == null) return null;
|
|
8869
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
8870
9152
|
try {
|
|
8871
9153
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
8872
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
9154
|
+
if ((v?.side === "buy" || v?.side === "sell") && typeof v?.tick === "number" && Number.isInteger(v.tick) && typeof v?.blockNumber === "number" && Number.isInteger(v.blockNumber) && typeof v?.assets === "string" && /^-?\d+$/.test(v.assets) && isHex(v?.hash) && typeof v?.totalReturned === "number" && Number.isInteger(v.totalReturned) && typeof v?.now === "number" && Number.isInteger(v.now)) return v;
|
|
8873
9155
|
throw new Error("Invalid cursor");
|
|
8874
9156
|
} catch {
|
|
8875
9157
|
logger.error({
|
|
@@ -8887,7 +9169,7 @@ let LevelCursor;
|
|
|
8887
9169
|
function encode(lastLevel, offersCursor, side, now) {
|
|
8888
9170
|
return Buffer.from(JSON.stringify({
|
|
8889
9171
|
side,
|
|
8890
|
-
|
|
9172
|
+
lastTick: lastLevel.tick,
|
|
8891
9173
|
now,
|
|
8892
9174
|
offersCursor
|
|
8893
9175
|
})).toString("base64url");
|
|
@@ -8895,10 +9177,9 @@ let LevelCursor;
|
|
|
8895
9177
|
_LevelCursor.encode = encode;
|
|
8896
9178
|
function decode(cursorString, logger) {
|
|
8897
9179
|
if (cursorString == null) return null;
|
|
8898
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
8899
9180
|
try {
|
|
8900
9181
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
8901
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
9182
|
+
if ((v?.side === "buy" || v?.side === "sell") && typeof v?.lastTick === "number" && Number.isInteger(v.lastTick) && typeof v?.now === "number" && Number.isInteger(v.now) && (v?.offersCursor === null || typeof v?.offersCursor === "string")) return v;
|
|
8902
9183
|
throw new Error("Invalid book cursor");
|
|
8903
9184
|
} catch {
|
|
8904
9185
|
logger.error({
|
|
@@ -9041,31 +9322,33 @@ function create$9(db) {
|
|
|
9041
9322
|
function create$8(db) {
|
|
9042
9323
|
return {
|
|
9043
9324
|
get: async (parameters) => {
|
|
9044
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9325
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9045
9326
|
const conditions = [];
|
|
9046
9327
|
if (chainId !== void 0) conditions.push(eq(lots.chainId, chainId));
|
|
9047
9328
|
if (user !== void 0) conditions.push(eq(lots.user, user.toLowerCase()));
|
|
9048
9329
|
if (contract !== void 0) conditions.push(eq(lots.contract, contract.toLowerCase()));
|
|
9049
9330
|
if (group !== void 0) conditions.push(eq(lots.group, group));
|
|
9331
|
+
if (obligationId !== void 0) conditions.push(eq(lots.obligationId, obligationId));
|
|
9050
9332
|
return (await db.select().from(lots).where(conditions.length > 0 ? and(...conditions) : void 0)).map((row) => ({
|
|
9051
9333
|
chainId: row.chainId,
|
|
9052
9334
|
user: row.user,
|
|
9053
9335
|
contract: row.contract,
|
|
9054
9336
|
group: row.group,
|
|
9337
|
+
obligationId: row.obligationId,
|
|
9055
9338
|
lower: BigInt(row.lower),
|
|
9056
9339
|
upper: BigInt(row.upper)
|
|
9057
9340
|
}));
|
|
9058
9341
|
},
|
|
9059
9342
|
create: async (parameters) => {
|
|
9060
9343
|
if (parameters.length === 0) return;
|
|
9061
|
-
const
|
|
9344
|
+
const lotsByKey = /* @__PURE__ */ new Map();
|
|
9062
9345
|
for (const offer of parameters) {
|
|
9063
|
-
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}`.toLowerCase();
|
|
9064
|
-
const existing =
|
|
9065
|
-
if (!existing || offer.size > existing.size)
|
|
9346
|
+
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}-${offer.obligationId}`.toLowerCase();
|
|
9347
|
+
const existing = lotsByKey.get(key);
|
|
9348
|
+
if (!existing || offer.size > existing.size) lotsByKey.set(key, offer);
|
|
9066
9349
|
}
|
|
9067
|
-
for (const offer of
|
|
9068
|
-
const maxUpperResult = await db.select({ maxUpper: sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase())));
|
|
9350
|
+
for (const offer of lotsByKey.values()) if ((await db.select().from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase()), eq(lots.group, offer.group.toLowerCase()), eq(lots.obligationId, offer.obligationId.toLowerCase()))).limit(1)).length === 0) {
|
|
9351
|
+
const maxUpperResult = await db.select({ maxUpper: sql`COALESCE(MAX(${lots.upper}::numeric), 0)` }).from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase()), eq(lots.obligationId, offer.obligationId.toLowerCase())));
|
|
9069
9352
|
const newLower = BigInt(maxUpperResult[0]?.maxUpper ?? "0");
|
|
9070
9353
|
const newUpper = newLower + offer.size;
|
|
9071
9354
|
await db.insert(lots).values({
|
|
@@ -9073,6 +9356,7 @@ function create$8(db) {
|
|
|
9073
9356
|
user: offer.positionUser.toLowerCase(),
|
|
9074
9357
|
contract: offer.positionContract.toLowerCase(),
|
|
9075
9358
|
group: offer.group.toLowerCase(),
|
|
9359
|
+
obligationId: offer.obligationId.toLowerCase(),
|
|
9076
9360
|
lower: newLower.toString(),
|
|
9077
9361
|
upper: newUpper.toString()
|
|
9078
9362
|
});
|
|
@@ -9127,17 +9411,19 @@ function create$7(db) {
|
|
|
9127
9411
|
//#region src/database/domains/Offsets.ts
|
|
9128
9412
|
function create$6(db) {
|
|
9129
9413
|
return { get: async (parameters) => {
|
|
9130
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
9414
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9131
9415
|
const conditions = [];
|
|
9132
9416
|
if (chainId !== void 0) conditions.push(eq(offsets.chainId, chainId));
|
|
9133
9417
|
if (user !== void 0) conditions.push(eq(offsets.user, user.toLowerCase()));
|
|
9134
9418
|
if (contract !== void 0) conditions.push(eq(offsets.contract, contract.toLowerCase()));
|
|
9135
9419
|
if (group !== void 0) conditions.push(eq(offsets.group, group));
|
|
9420
|
+
if (obligationId !== void 0) conditions.push(eq(offsets.obligationId, obligationId));
|
|
9136
9421
|
return (await db.select().from(offsets).where(conditions.length > 0 ? and(...conditions) : void 0)).map((row) => ({
|
|
9137
9422
|
chainId: row.chainId,
|
|
9138
9423
|
user: row.user,
|
|
9139
9424
|
contract: row.contract,
|
|
9140
9425
|
group: row.group,
|
|
9426
|
+
obligationId: row.obligationId,
|
|
9141
9427
|
value: BigInt(row.value)
|
|
9142
9428
|
}));
|
|
9143
9429
|
} };
|
|
@@ -9287,7 +9573,8 @@ const create$4 = (db) => {
|
|
|
9287
9573
|
if (!parsed.chainId || !parsed.contract) throw new Error("Invalid cursor format");
|
|
9288
9574
|
cursor = {
|
|
9289
9575
|
chainId: parsed.chainId,
|
|
9290
|
-
contract: parsed.contract
|
|
9576
|
+
contract: parsed.contract,
|
|
9577
|
+
obligationId: parsed.obligationId ?? null
|
|
9291
9578
|
};
|
|
9292
9579
|
}
|
|
9293
9580
|
const raw = await db.execute(sql`
|
|
@@ -9296,16 +9583,18 @@ const create$4 = (db) => {
|
|
|
9296
9583
|
chain_id,
|
|
9297
9584
|
"user",
|
|
9298
9585
|
contract,
|
|
9586
|
+
obligation_id,
|
|
9299
9587
|
SUM(value::numeric) AS total_offset
|
|
9300
9588
|
FROM ${offsets}
|
|
9301
9589
|
WHERE LOWER("user") = LOWER(${user})
|
|
9302
|
-
GROUP BY chain_id, "user", contract
|
|
9590
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
9303
9591
|
),
|
|
9304
9592
|
position_consumed AS (
|
|
9305
9593
|
SELECT
|
|
9306
9594
|
l.chain_id,
|
|
9307
9595
|
l.contract,
|
|
9308
9596
|
l."user",
|
|
9597
|
+
l.obligation_id,
|
|
9309
9598
|
SUM(
|
|
9310
9599
|
CASE
|
|
9311
9600
|
WHEN offer_agg.assets > 0
|
|
@@ -9331,50 +9620,64 @@ const create$4 = (db) => {
|
|
|
9331
9620
|
AND LOWER(offer_agg.group_maker) = LOWER(g.maker)
|
|
9332
9621
|
AND offer_agg."group_group" = g."group"
|
|
9333
9622
|
WHERE LOWER(l."user") = LOWER(${user})
|
|
9334
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
9623
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
9335
9624
|
),
|
|
9336
9625
|
position_max_lot AS (
|
|
9337
9626
|
SELECT
|
|
9338
9627
|
chain_id,
|
|
9339
9628
|
contract,
|
|
9340
9629
|
"user",
|
|
9630
|
+
obligation_id,
|
|
9341
9631
|
MAX(upper::numeric) AS max_upper
|
|
9342
9632
|
FROM ${lots}
|
|
9343
9633
|
WHERE LOWER("user") = LOWER(${user})
|
|
9344
|
-
GROUP BY chain_id, contract, "user"
|
|
9634
|
+
GROUP BY chain_id, contract, "user", obligation_id
|
|
9635
|
+
),
|
|
9636
|
+
per_obligation AS (
|
|
9637
|
+
SELECT
|
|
9638
|
+
pml.chain_id,
|
|
9639
|
+
pml.contract,
|
|
9640
|
+
pml."user",
|
|
9641
|
+
pml.obligation_id,
|
|
9642
|
+
GREATEST(0,
|
|
9643
|
+
COALESCE(pml.max_upper, 0)
|
|
9644
|
+
- COALESCE(po.total_offset, 0)
|
|
9645
|
+
- COALESCE(pc.consumed, 0)
|
|
9646
|
+
)::text AS reserved_balance
|
|
9647
|
+
FROM position_max_lot pml
|
|
9648
|
+
LEFT JOIN position_offsets po
|
|
9649
|
+
ON po.chain_id = pml.chain_id
|
|
9650
|
+
AND LOWER(po.contract) = LOWER(pml.contract)
|
|
9651
|
+
AND LOWER(po."user") = LOWER(pml."user")
|
|
9652
|
+
AND po.obligation_id = pml.obligation_id
|
|
9653
|
+
LEFT JOIN position_consumed pc
|
|
9654
|
+
ON pc.chain_id = pml.chain_id
|
|
9655
|
+
AND LOWER(pc.contract) = LOWER(pml.contract)
|
|
9656
|
+
AND LOWER(pc."user") = LOWER(pml."user")
|
|
9657
|
+
AND pc.obligation_id = pml.obligation_id
|
|
9345
9658
|
)
|
|
9346
9659
|
SELECT
|
|
9347
9660
|
p.chain_id,
|
|
9348
9661
|
p.contract,
|
|
9349
9662
|
p."user",
|
|
9350
9663
|
p.block_number,
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
- COALESCE(po.total_offset, 0)
|
|
9354
|
-
- COALESCE(pc.consumed, 0)
|
|
9355
|
-
)::text AS reserved_balance
|
|
9664
|
+
po.obligation_id,
|
|
9665
|
+
COALESCE(po.reserved_balance, '0') AS reserved_balance
|
|
9356
9666
|
FROM ${positions} p
|
|
9357
|
-
LEFT JOIN
|
|
9667
|
+
LEFT JOIN per_obligation po
|
|
9358
9668
|
ON po.chain_id = p.chain_id
|
|
9359
9669
|
AND LOWER(po.contract) = LOWER(p.contract)
|
|
9360
9670
|
AND LOWER(po."user") = LOWER(p."user")
|
|
9361
|
-
LEFT JOIN position_consumed pc
|
|
9362
|
-
ON pc.chain_id = p.chain_id
|
|
9363
|
-
AND LOWER(pc.contract) = LOWER(p.contract)
|
|
9364
|
-
AND LOWER(pc."user") = LOWER(p."user")
|
|
9365
|
-
LEFT JOIN position_max_lot pml
|
|
9366
|
-
ON pml.chain_id = p.chain_id
|
|
9367
|
-
AND LOWER(pml.contract) = LOWER(p.contract)
|
|
9368
|
-
AND LOWER(pml."user") = LOWER(p."user")
|
|
9369
9671
|
WHERE LOWER(p."user") = LOWER(${user})
|
|
9370
9672
|
AND p."user" != ${zeroAddress}
|
|
9371
|
-
${cursor !== null ? sql`AND (p.chain_id, p.contract) > (${cursor.chainId}, ${cursor.contract})` : sql``}
|
|
9372
|
-
ORDER BY p.chain_id ASC, p.contract ASC
|
|
9673
|
+
${cursor !== null ? sql`AND (p.chain_id, p.contract, COALESCE(po.obligation_id, '')) > (${cursor.chainId}, ${cursor.contract}, ${cursor.obligationId ?? ""})` : sql``}
|
|
9674
|
+
ORDER BY p.chain_id ASC, p.contract ASC, po.obligation_id ASC NULLS FIRST
|
|
9373
9675
|
LIMIT ${limit}
|
|
9374
9676
|
`);
|
|
9375
9677
|
const nextCursor = raw.rows.length === limit ? Buffer.from(JSON.stringify({
|
|
9376
9678
|
chainId: raw.rows[raw.rows.length - 1].chain_id.toString(),
|
|
9377
|
-
contract: raw.rows[raw.rows.length - 1].contract
|
|
9679
|
+
contract: raw.rows[raw.rows.length - 1].contract,
|
|
9680
|
+
obligationId: raw.rows[raw.rows.length - 1].obligation_id
|
|
9378
9681
|
})).toString("base64url") : null;
|
|
9379
9682
|
return {
|
|
9380
9683
|
positions: raw.rows.map((row) => ({
|
|
@@ -9382,6 +9685,7 @@ const create$4 = (db) => {
|
|
|
9382
9685
|
contract: row.contract,
|
|
9383
9686
|
user: row.user,
|
|
9384
9687
|
blockNumber: row.block_number,
|
|
9688
|
+
obligationId: row.obligation_id,
|
|
9385
9689
|
reserved: BigInt(row.reserved_balance.split(".")[0] ?? "0")
|
|
9386
9690
|
})),
|
|
9387
9691
|
nextCursor
|
|
@@ -9660,7 +9964,10 @@ function create$1(db) {
|
|
|
9660
9964
|
|
|
9661
9965
|
//#endregion
|
|
9662
9966
|
//#region src/database/Database.ts
|
|
9663
|
-
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
9967
|
+
var Database_exports = /* @__PURE__ */ __exportAll({
|
|
9968
|
+
connect: () => connect$1,
|
|
9969
|
+
getSchemaNamesForMigration: () => getSchemaNamesForMigration
|
|
9970
|
+
});
|
|
9664
9971
|
function createDomains(core, chainRegistry) {
|
|
9665
9972
|
return {
|
|
9666
9973
|
book: create$12({ db: core }),
|
|
@@ -9757,6 +10064,7 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
9757
10064
|
return wrapped;
|
|
9758
10065
|
}
|
|
9759
10066
|
const InMemoryDbMap = /* @__PURE__ */ new Map();
|
|
10067
|
+
const LEGACY_SCHEMA_START_MINOR = 7;
|
|
9760
10068
|
/**
|
|
9761
10069
|
* Connect to the database.
|
|
9762
10070
|
* @notice If no connection string is provided, an in-process PGLite database is created.
|
|
@@ -9811,9 +10119,26 @@ function applyMigrations(kind, driver) {
|
|
|
9811
10119
|
async function preMigrate(driver) {
|
|
9812
10120
|
const tracer = getTracer("db.preMigrate");
|
|
9813
10121
|
await startActiveSpan(tracer, "db.preMigrate", async () => {
|
|
9814
|
-
|
|
10122
|
+
const schemaNames = getSchemaNamesForMigration(VERSION);
|
|
10123
|
+
for (const schemaName of schemaNames) await driver.execute(`create schema if not exists "${schemaName}"`);
|
|
9815
10124
|
});
|
|
9816
10125
|
}
|
|
10126
|
+
/**
|
|
10127
|
+
* Build the list of router schemas that should exist before running migrations.
|
|
10128
|
+
* @param version - Current schema version (e.g. `router_v1.8`).
|
|
10129
|
+
* @returns Ordered schema names from `router_v1.7` to current, or just current if parsing fails.
|
|
10130
|
+
*/
|
|
10131
|
+
function getSchemaNamesForMigration(version) {
|
|
10132
|
+
const parsed = /^router_v(?<major>\d+)\.(?<minor>\d+)$/.exec(version);
|
|
10133
|
+
if (!parsed?.groups?.major || !parsed.groups.minor) return [version];
|
|
10134
|
+
const major = Number.parseInt(parsed.groups.major, 10);
|
|
10135
|
+
const currentMinor = Number.parseInt(parsed.groups.minor, 10);
|
|
10136
|
+
if (!Number.isInteger(major) || !Number.isInteger(currentMinor)) return [version];
|
|
10137
|
+
if (currentMinor < LEGACY_SCHEMA_START_MINOR) return [version];
|
|
10138
|
+
const schemaNames = [];
|
|
10139
|
+
for (let minor = LEGACY_SCHEMA_START_MINOR; minor <= currentMinor; minor += 1) schemaNames.push(`router_v${major}.${minor}`);
|
|
10140
|
+
return schemaNames;
|
|
10141
|
+
}
|
|
9817
10142
|
async function postMigrate(driver) {
|
|
9818
10143
|
const tracer = getTracer("db.postMigrate");
|
|
9819
10144
|
await startActiveSpan(tracer, "db.postMigrate", async () => {
|
|
@@ -10083,15 +10408,16 @@ async function postMigrate(driver) {
|
|
|
10083
10408
|
RETURNS trigger
|
|
10084
10409
|
LANGUAGE plpgsql AS $$
|
|
10085
10410
|
BEGIN
|
|
10086
|
-
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", value)
|
|
10411
|
+
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", obligation_id, value)
|
|
10087
10412
|
VALUES (
|
|
10088
10413
|
OLD.chain_id,
|
|
10089
10414
|
OLD."user",
|
|
10090
10415
|
OLD.contract,
|
|
10091
10416
|
OLD."group",
|
|
10417
|
+
OLD.obligation_id,
|
|
10092
10418
|
OLD.upper::numeric - OLD.lower::numeric
|
|
10093
10419
|
)
|
|
10094
|
-
ON CONFLICT (chain_id, "user", contract, "group") DO NOTHING;
|
|
10420
|
+
ON CONFLICT (chain_id, "user", contract, "group", obligation_id) DO NOTHING;
|
|
10095
10421
|
RETURN OLD;
|
|
10096
10422
|
END;
|
|
10097
10423
|
$$;
|
|
@@ -10345,10 +10671,11 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
|
10345
10671
|
amountMutualExclusivity: () => amountMutualExclusivity,
|
|
10346
10672
|
callback: () => callback,
|
|
10347
10673
|
chains: () => chains,
|
|
10674
|
+
collateralToken: () => collateralToken,
|
|
10675
|
+
loanToken: () => loanToken,
|
|
10348
10676
|
maturity: () => maturity,
|
|
10349
10677
|
oracle: () => oracle,
|
|
10350
10678
|
sameMaker: () => sameMaker,
|
|
10351
|
-
token: () => token,
|
|
10352
10679
|
validity: () => validity
|
|
10353
10680
|
});
|
|
10354
10681
|
/**
|
|
@@ -10376,15 +10703,25 @@ const callback = ({ callbacks }) => single("callback", `Validates callbacks: buy
|
|
|
10376
10703
|
if (isEmptyCallback(offer) && !offer.buy && !callbacks.includes(Type$1.SellWithEmptyCallback)) return { message: "Sell offers with empty callback not allowed." };
|
|
10377
10704
|
});
|
|
10378
10705
|
/**
|
|
10379
|
-
* A validation rule that checks if the offer's
|
|
10380
|
-
* @param assetsByChainId - Allowed
|
|
10706
|
+
* A validation rule that checks if the offer's loan token is allowed for its chain.
|
|
10707
|
+
* @param assetsByChainId - Allowed loan tokens indexed by chain id.
|
|
10708
|
+
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
10709
|
+
*/
|
|
10710
|
+
const loanToken = ({ assetsByChainId }) => single("loan_token", "Validates that offer loan token is in the allowed token list for the offer chain", (offer) => {
|
|
10711
|
+
const allowedLoanTokens = assetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase());
|
|
10712
|
+
if (!allowedLoanTokens || allowedLoanTokens.length === 0) return { message: `No allowed loan tokens for chain ${offer.chainId}` };
|
|
10713
|
+
if (!allowedLoanTokens.includes(offer.loanToken.toLowerCase())) return { message: "Loan token is not allowed" };
|
|
10714
|
+
});
|
|
10715
|
+
/**
|
|
10716
|
+
* A validation rule that checks if the offer's collateral tokens are allowed for its chain.
|
|
10717
|
+
* @param collateralAssetsByChainId - Allowed collateral tokens indexed by chain id.
|
|
10381
10718
|
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
10382
10719
|
*/
|
|
10383
|
-
const
|
|
10384
|
-
const
|
|
10385
|
-
if (
|
|
10386
|
-
if (
|
|
10387
|
-
if (offer.collaterals.some((collateral) => !
|
|
10720
|
+
const collateralToken = ({ collateralAssetsByChainId }) => single("collateral_token", "Validates that offer collateral tokens are in the allowed token list for the offer chain", (offer) => {
|
|
10721
|
+
const allowedCollateralTokens = collateralAssetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase()) ?? [];
|
|
10722
|
+
if (allowedCollateralTokens.length === 0) return { message: `No allowed collateral tokens for chain ${offer.chainId}` };
|
|
10723
|
+
if (offer.collaterals.length === 0) return { message: "At least one collateral token is required" };
|
|
10724
|
+
if (offer.collaterals.some((collateral) => !allowedCollateralTokens.includes(collateral.asset.toLowerCase()))) return { message: "Collateral token is not allowed" };
|
|
10388
10725
|
});
|
|
10389
10726
|
/**
|
|
10390
10727
|
* A validation rule that checks if the offer's oracle addresses are allowed for its chain.
|
|
@@ -10427,9 +10764,11 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
|
|
|
10427
10764
|
//#region src/gatekeeper/morphoRules.ts
|
|
10428
10765
|
const morphoRules = (chains$3) => {
|
|
10429
10766
|
const assetsByChainId = {};
|
|
10767
|
+
const collateralAssetsByChainId = {};
|
|
10430
10768
|
const oraclesByChainId = {};
|
|
10431
10769
|
for (const chain of chains$3) {
|
|
10432
10770
|
assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
|
|
10771
|
+
collateralAssetsByChainId[chain.id] = collateralAssets[chain.id.toString()] ?? [];
|
|
10433
10772
|
oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
|
|
10434
10773
|
}
|
|
10435
10774
|
return [
|
|
@@ -10441,7 +10780,8 @@ const morphoRules = (chains$3) => {
|
|
|
10441
10780
|
callbacks: [Type$1.BuyWithEmptyCallback, Type$1.SellWithEmptyCallback],
|
|
10442
10781
|
allowedAddresses: []
|
|
10443
10782
|
}),
|
|
10444
|
-
|
|
10783
|
+
loanToken({ assetsByChainId }),
|
|
10784
|
+
collateralToken({ collateralAssetsByChainId }),
|
|
10445
10785
|
oracle({ oraclesByChainId })
|
|
10446
10786
|
];
|
|
10447
10787
|
};
|
|
@@ -10624,5 +10964,5 @@ var mempool_exports = /* @__PURE__ */ __exportAll({
|
|
|
10624
10964
|
});
|
|
10625
10965
|
|
|
10626
10966
|
//#endregion
|
|
10627
|
-
export { Abi_exports as Abi, BookResponse_exports as BookResponse, BooksController, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainHealth, ChainRegistry_exports as ChainRegistry, ChainsHealthResponse, Collateral_exports as Collateral, CollectorHealth, CollectorsHealthResponse, ConfigContractsController, ConfigRulesController, Database_exports as Database, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, Gatekeeper_exports as Gatekeeper, Client_exports as GatekeeperClient, Health_exports as Health, HealthController, Indexer_exports as Indexer, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Logger_exports as Logger, Maturity_exports as Maturity, mempool_exports as Mempool, Obligation_exports as Obligation, ObligationResponse_exports as ObligationResponse, ObligationsController, Offer_exports as Offer, OfferResponse_exports as OfferResponse, OffersController, drizzle_exports as OffersSchema, OpenApi, Oracle_exports as Oracle, Position_exports as Position, PositionResponse_exports as PositionResponse, Quote_exports as Quote, RouterApi_exports as RouterApi, Client_exports$1 as RouterClient, RouterStatusResponse, Rules_exports as Rules, time_exports as Time, TradingFee_exports as TradingFee, Transfer_exports as Transfer, Tree_exports as Tree, UsersController, utils_exports as Utils, ValidateController, Gate_exports as Validation, morphoRules, parse, safeParse };
|
|
10967
|
+
export { Abi_exports as Abi, BookResponse_exports as BookResponse, BooksController, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainHealth, ChainRegistry_exports as ChainRegistry, ChainsHealthResponse, Collateral_exports as Collateral, CollectorHealth, CollectorsHealthResponse, ConfigContractsController, ConfigRulesController, Database_exports as Database, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, Gatekeeper_exports as Gatekeeper, Client_exports as GatekeeperClient, Health_exports as Health, HealthController, Indexer_exports as Indexer, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Logger_exports as Logger, Maturity_exports as Maturity, mempool_exports as Mempool, Obligation_exports as Obligation, ObligationResponse_exports as ObligationResponse, ObligationsController, Offer_exports as Offer, OfferResponse_exports as OfferResponse, OffersController, drizzle_exports as OffersSchema, OpenApi, Oracle_exports as Oracle, Position_exports as Position, PositionResponse_exports as PositionResponse, Quote_exports as Quote, RouterApi_exports as RouterApi, Client_exports$1 as RouterClient, RouterStatusResponse, Rules_exports as Rules, Tick_exports as Tick, time_exports as Time, TradingFee_exports as TradingFee, Transfer_exports as Transfer, Tree_exports as Tree, UsersController, utils_exports as Utils, ValidateController, Gate_exports as Validation, morphoRules, parse, safeParse };
|
|
10628
10968
|
//# sourceMappingURL=index.node.mjs.map
|