@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/cli.js
CHANGED
|
@@ -152,7 +152,7 @@ function startActiveSpan(tracer, name, fn) {
|
|
|
152
152
|
//#endregion
|
|
153
153
|
//#region package.json
|
|
154
154
|
var name = "@morpho-dev/router";
|
|
155
|
-
var version = "0.
|
|
155
|
+
var version = "0.8.0";
|
|
156
156
|
var description = "Router package for Morpho protocol";
|
|
157
157
|
|
|
158
158
|
//#endregion
|
|
@@ -331,8 +331,8 @@ const chains$2 = {
|
|
|
331
331
|
name: "ethereum-virtual-testnet",
|
|
332
332
|
custom: {
|
|
333
333
|
morpho: {
|
|
334
|
-
address: "
|
|
335
|
-
blockCreated:
|
|
334
|
+
address: "0x634b095371e4e45feed94c1a45c37798e173ea50",
|
|
335
|
+
blockCreated: 23226700
|
|
336
336
|
},
|
|
337
337
|
morphoBlue: {
|
|
338
338
|
address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
@@ -561,7 +561,7 @@ async function deployContract(client, account, bytecode, name) {
|
|
|
561
561
|
*/
|
|
562
562
|
async function startAnvil(parameters) {
|
|
563
563
|
const args = buildAnvilArgs(parameters);
|
|
564
|
-
const logFd = fs.openSync(parameters.logPath, "
|
|
564
|
+
const logFd = fs.openSync(parameters.logPath, "w");
|
|
565
565
|
const subprocess = spawn("anvil", args, {
|
|
566
566
|
detached: true,
|
|
567
567
|
stdio: [
|
|
@@ -1640,6 +1640,33 @@ const assets = {
|
|
|
1640
1640
|
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
1641
1641
|
]
|
|
1642
1642
|
};
|
|
1643
|
+
const collateralAssets = {
|
|
1644
|
+
[ChainId.ETHEREUM.toString()]: [
|
|
1645
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
1646
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
1647
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
1648
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
1649
|
+
],
|
|
1650
|
+
[ChainId.BASE.toString()]: [
|
|
1651
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
1652
|
+
"0x4200000000000000000000000000000000000006",
|
|
1653
|
+
"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
|
|
1654
|
+
"0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
|
|
1655
|
+
"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
|
|
1656
|
+
],
|
|
1657
|
+
[ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
|
|
1658
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
1659
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
1660
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
1661
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
1662
|
+
],
|
|
1663
|
+
[ChainId.ANVIL.toString()]: [
|
|
1664
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
1665
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
1666
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
1667
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
1668
|
+
]
|
|
1669
|
+
};
|
|
1643
1670
|
const oracles$1 = {
|
|
1644
1671
|
[ChainId.ETHEREUM.toString()]: [
|
|
1645
1672
|
"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
|
|
@@ -1714,6 +1741,61 @@ const MetaMorpho = parseAbi([
|
|
|
1714
1741
|
//#region src/core/Abi/MetaMorphoFactory.ts
|
|
1715
1742
|
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)"]);
|
|
1716
1743
|
|
|
1744
|
+
//#endregion
|
|
1745
|
+
//#region src/core/Abi/MorphoV2.ts
|
|
1746
|
+
const MorphoV2 = parseAbi([
|
|
1747
|
+
"constructor()",
|
|
1748
|
+
"function collateralOf(bytes32 id, address user, address collateralToken) view returns (uint256)",
|
|
1749
|
+
"function consume(bytes32 group, uint256 amount)",
|
|
1750
|
+
"function consumed(address user, bytes32 group) view returns (uint256)",
|
|
1751
|
+
"function debtOf(bytes32 id, address user) view returns (uint256)",
|
|
1752
|
+
"function defaultFees(address loanToken, uint256 index) view returns (uint16)",
|
|
1753
|
+
"function feeSetter() view returns (address)",
|
|
1754
|
+
"function fees(bytes32 id) view returns (uint16[6])",
|
|
1755
|
+
"function flashLoan(address token, uint256 assets, address callback, bytes data)",
|
|
1756
|
+
"function isHealthy((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bytes32 id, address borrower) view returns (bool)",
|
|
1757
|
+
"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)[])",
|
|
1758
|
+
"function multicall(bytes[] calls)",
|
|
1759
|
+
"function obligationCreated(bytes32 id) view returns (bool)",
|
|
1760
|
+
"function obligationState(bytes32 id) view returns (uint128 totalUnits, uint128 totalShares, uint256 withdrawable, bool created)",
|
|
1761
|
+
"function owner() view returns (address)",
|
|
1762
|
+
"function repay((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, address onBehalf)",
|
|
1763
|
+
"function session(address user) view returns (bytes32)",
|
|
1764
|
+
"function setDefaultTradingFee(address loanToken, uint256 index, uint256 newTradingFee)",
|
|
1765
|
+
"function setFeeSetter(address newFeeSetter)",
|
|
1766
|
+
"function setObligationTradingFee(bytes32 id, uint256 index, uint256 newTradingFee)",
|
|
1767
|
+
"function setOwner(address newOwner)",
|
|
1768
|
+
"function setTradingFeeRecipient(address recipient)",
|
|
1769
|
+
"function sharesOf(bytes32 id, address user) view returns (uint256)",
|
|
1770
|
+
"function shuffleSession()",
|
|
1771
|
+
"function supplyCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)",
|
|
1772
|
+
"function take(uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, address taker, ((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, bool buy, address maker, uint256 assets, uint256 obligationUnits, uint256 obligationShares, uint256 start, uint256 expiry, uint256 tick, bytes32 group, bytes32 session, address callback, bytes callbackData) offer, (uint8 v, bytes32 r, bytes32 s) sig, bytes32 root, bytes32[] proof, address takerCallback, bytes takerCallbackData) returns (uint256, uint256, uint256, uint256)",
|
|
1773
|
+
"function totalShares(bytes32 id) view returns (uint256)",
|
|
1774
|
+
"function totalUnits(bytes32 id) view returns (uint256)",
|
|
1775
|
+
"function touchObligation((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation) returns (bytes32)",
|
|
1776
|
+
"function tradingFee(bytes32 id, uint256 timeToMaturity) view returns (uint256)",
|
|
1777
|
+
"function tradingFeeRecipient() view returns (address)",
|
|
1778
|
+
"function withdraw((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, uint256 obligationUnits, uint256 shares, address onBehalf) returns (uint256, uint256)",
|
|
1779
|
+
"function withdrawCollateral((address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation, address collateral, uint256 assets, address onBehalf)",
|
|
1780
|
+
"function withdrawable(bytes32 id) view returns (uint256)",
|
|
1781
|
+
"event Constructor(address indexed owner)",
|
|
1782
|
+
"event Consume(address indexed user, bytes32 indexed group, uint256 amount)",
|
|
1783
|
+
"event FlashLoan(address indexed caller, address indexed token, uint256 assets)",
|
|
1784
|
+
"event Liquidate(address indexed caller, bytes32 indexed id, (uint256 collateralIndex, uint256 repaid, uint256 seized)[] seizures, address indexed borrower, uint256 totalRepaid, uint256 badDebt)",
|
|
1785
|
+
"event ObligationCreated(bytes32 indexed id, (address loanToken, (address token, uint256 lltv, address oracle)[] collaterals, uint256 maturity) obligation)",
|
|
1786
|
+
"event Repay(address indexed caller, bytes32 indexed id, uint256 obligationUnits, address indexed onBehalf)",
|
|
1787
|
+
"event SetDefaultTradingFee(address indexed loanToken, uint256 indexed index, uint256 newTradingFee)",
|
|
1788
|
+
"event SetFeeSetter(address indexed feeSetter)",
|
|
1789
|
+
"event SetObligationTradingFee(bytes32 indexed id, uint256 indexed index, uint256 newTradingFee)",
|
|
1790
|
+
"event SetOwner(address indexed owner)",
|
|
1791
|
+
"event SetTradingFeeRecipient(address indexed recipient)",
|
|
1792
|
+
"event ShuffleSession(address indexed user, bytes32 session)",
|
|
1793
|
+
"event SupplyCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)",
|
|
1794
|
+
"event Take(address caller, bytes32 indexed id, address indexed maker, address indexed taker, bool offerIsBuy, uint256 buyerAssets, uint256 sellerAssets, uint256 obligationUnits, uint256 obligationShares, bool buyerIsLender, bool sellerIsBorrower, bytes32 group, uint256 consumed)",
|
|
1795
|
+
"event Withdraw(address indexed caller, bytes32 indexed id, uint256 obligationUnits, uint256 shares, address indexed onBehalf)",
|
|
1796
|
+
"event WithdrawCollateral(address caller, bytes32 indexed id, address indexed collateral, uint256 assets, address indexed onBehalf)"
|
|
1797
|
+
]);
|
|
1798
|
+
|
|
1717
1799
|
//#endregion
|
|
1718
1800
|
//#region src/core/Abi/index.ts
|
|
1719
1801
|
const Oracle = [{
|
|
@@ -2071,7 +2153,7 @@ const OfferSchema = () => {
|
|
|
2071
2153
|
assets: z$2.bigint({ coerce: true }).min(0n).max(maxUint256),
|
|
2072
2154
|
obligationUnits: z$2.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
|
|
2073
2155
|
obligationShares: z$2.bigint({ coerce: true }).min(0n).max(maxUint256).optional().default(0n),
|
|
2074
|
-
|
|
2156
|
+
tick: z$2.coerce.number().int().min(0).max(990),
|
|
2075
2157
|
maturity: MaturitySchema,
|
|
2076
2158
|
expiry: z$2.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
2077
2159
|
start: z$2.number().int().max(Number.MAX_SAFE_INTEGER),
|
|
@@ -2143,7 +2225,7 @@ const serialize = (offer) => ({
|
|
|
2143
2225
|
assets: offer.assets.toString(),
|
|
2144
2226
|
obligationUnits: offer.obligationUnits.toString(),
|
|
2145
2227
|
obligationShares: offer.obligationShares.toString(),
|
|
2146
|
-
|
|
2228
|
+
tick: offer.tick,
|
|
2147
2229
|
maturity: Number(offer.maturity),
|
|
2148
2230
|
expiry: Number(offer.expiry),
|
|
2149
2231
|
start: Number(offer.start),
|
|
@@ -2188,14 +2270,13 @@ function random(config) {
|
|
|
2188
2270
|
[.98, 2]
|
|
2189
2271
|
]));
|
|
2190
2272
|
const buy = config?.buy !== void 0 ? config.buy : bool();
|
|
2191
|
-
const
|
|
2192
|
-
const
|
|
2193
|
-
const
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
return [BigInt(q) * (ONE / 4n), buy ? 1 + idx : 1 + (len - 1 - idx)];
|
|
2273
|
+
const tickMin = buy ? 0 : 495;
|
|
2274
|
+
const len = (buy ? 495 : 990) - tickMin + 1;
|
|
2275
|
+
const tickPairs = Array.from({ length: len }, (_, idx) => {
|
|
2276
|
+
const weight = buy ? 1 + idx : 1 + (len - 1 - idx);
|
|
2277
|
+
return [tickMin + idx, weight];
|
|
2197
2278
|
});
|
|
2198
|
-
const
|
|
2279
|
+
const tick = config?.tick ?? weightedChoice(tickPairs);
|
|
2199
2280
|
const loanTokenDecimals = config?.assetsDecimals?.[loanToken] ?? 18;
|
|
2200
2281
|
const unit = BigInt(10) ** BigInt(loanTokenDecimals);
|
|
2201
2282
|
const amountBase = BigInt(100 + int(999901));
|
|
@@ -2209,7 +2290,7 @@ function random(config) {
|
|
|
2209
2290
|
assets: assetsScaled,
|
|
2210
2291
|
obligationUnits: config?.obligationUnits ?? 0n,
|
|
2211
2292
|
obligationShares: config?.obligationShares ?? 0n,
|
|
2212
|
-
|
|
2293
|
+
tick,
|
|
2213
2294
|
maturity,
|
|
2214
2295
|
expiry: config?.expiry ?? maturity - 1,
|
|
2215
2296
|
start: config?.start ?? maturity - 10,
|
|
@@ -2274,7 +2355,7 @@ const types = {
|
|
|
2274
2355
|
type: "uint256"
|
|
2275
2356
|
},
|
|
2276
2357
|
{
|
|
2277
|
-
name: "
|
|
2358
|
+
name: "tick",
|
|
2278
2359
|
type: "uint256"
|
|
2279
2360
|
},
|
|
2280
2361
|
{
|
|
@@ -2342,7 +2423,7 @@ function hash(offer) {
|
|
|
2342
2423
|
assets: offer.assets,
|
|
2343
2424
|
obligationUnits: offer.obligationUnits,
|
|
2344
2425
|
obligationShares: offer.obligationShares,
|
|
2345
|
-
|
|
2426
|
+
tick: BigInt(offer.tick),
|
|
2346
2427
|
maturity: BigInt(offer.maturity),
|
|
2347
2428
|
expiry: BigInt(offer.expiry),
|
|
2348
2429
|
group: offer.group,
|
|
@@ -2607,6 +2688,49 @@ var InvalidQuoteError = class extends BaseError {
|
|
|
2607
2688
|
}
|
|
2608
2689
|
};
|
|
2609
2690
|
|
|
2691
|
+
//#endregion
|
|
2692
|
+
//#region src/core/Tick.ts
|
|
2693
|
+
/** ln(1 + 0.025), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2694
|
+
const LN_ONE_PLUS_DELTA = 24692612590371501n;
|
|
2695
|
+
/** ln(2), scaled by 1e18. Matches TickLib onchain constant. */
|
|
2696
|
+
const LN2 = 693147180559945309n;
|
|
2697
|
+
const WAD$1 = 10n ** 18n;
|
|
2698
|
+
const WAD_SQUARED = 10n ** 36n;
|
|
2699
|
+
const PRICE_STEP = 10n ** 13n;
|
|
2700
|
+
const HALF_TICK_RANGE = 495n;
|
|
2701
|
+
/** Tick domain supported by Morpho V2. */
|
|
2702
|
+
const TICK_RANGE = 990;
|
|
2703
|
+
/**
|
|
2704
|
+
* Converts a tick to a wad price using the same approximation and rounding as TickLib.
|
|
2705
|
+
* @param tick - Tick value in the inclusive range [0, 990].
|
|
2706
|
+
* @returns The price in wad units.
|
|
2707
|
+
* @throws {@link InvalidTickError} If tick is not an integer in range [0, 990].
|
|
2708
|
+
*/
|
|
2709
|
+
function tickToPrice(tick) {
|
|
2710
|
+
assertTick(tick);
|
|
2711
|
+
return divHalfDownUnchecked(divHalfDownUnchecked(WAD_SQUARED, WAD$1 + wExp(LN_ONE_PLUS_DELTA * (HALF_TICK_RANGE - BigInt(tick)))), PRICE_STEP) * PRICE_STEP;
|
|
2712
|
+
}
|
|
2713
|
+
function divHalfDownUnchecked(x, d) {
|
|
2714
|
+
return (x + (d - 1n) / 2n) / d;
|
|
2715
|
+
}
|
|
2716
|
+
function wExp(x) {
|
|
2717
|
+
if (x < 0n) return WAD_SQUARED / wExp(-x);
|
|
2718
|
+
const q = (x + LN2 / 2n) / LN2;
|
|
2719
|
+
const r = x - q * LN2;
|
|
2720
|
+
const secondTerm = r * r / (2n * WAD$1);
|
|
2721
|
+
const thirdTerm = secondTerm * r / (3n * WAD$1);
|
|
2722
|
+
return WAD$1 + r + secondTerm + thirdTerm << q;
|
|
2723
|
+
}
|
|
2724
|
+
function assertTick(tick) {
|
|
2725
|
+
if (!Number.isInteger(tick) || tick < 0 || tick > TICK_RANGE) throw new InvalidTickError(tick);
|
|
2726
|
+
}
|
|
2727
|
+
var InvalidTickError = class extends BaseError {
|
|
2728
|
+
name = "Tick.InvalidTickError";
|
|
2729
|
+
constructor(tick) {
|
|
2730
|
+
super(`Invalid tick: ${tick}. Tick must be an integer between 0 and ${TICK_RANGE}.`);
|
|
2731
|
+
}
|
|
2732
|
+
};
|
|
2733
|
+
|
|
2610
2734
|
//#endregion
|
|
2611
2735
|
//#region src/core/TradingFee.ts
|
|
2612
2736
|
/** WAD constant (1e18) for fee scaling. */
|
|
@@ -2895,15 +3019,25 @@ const callback = ({ callbacks }) => single("callback", `Validates callbacks: buy
|
|
|
2895
3019
|
if (isEmptyCallback(offer) && !offer.buy && !callbacks.includes(Type$1.SellWithEmptyCallback)) return { message: "Sell offers with empty callback not allowed." };
|
|
2896
3020
|
});
|
|
2897
3021
|
/**
|
|
2898
|
-
* A validation rule that checks if the offer's
|
|
2899
|
-
* @param assetsByChainId - Allowed
|
|
3022
|
+
* A validation rule that checks if the offer's loan token is allowed for its chain.
|
|
3023
|
+
* @param assetsByChainId - Allowed loan tokens indexed by chain id.
|
|
2900
3024
|
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
2901
3025
|
*/
|
|
2902
|
-
const
|
|
2903
|
-
const
|
|
2904
|
-
if (!
|
|
2905
|
-
if (!
|
|
2906
|
-
|
|
3026
|
+
const loanToken = ({ assetsByChainId }) => single("loan_token", "Validates that offer loan token is in the allowed token list for the offer chain", (offer) => {
|
|
3027
|
+
const allowedLoanTokens = assetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase());
|
|
3028
|
+
if (!allowedLoanTokens || allowedLoanTokens.length === 0) return { message: `No allowed loan tokens for chain ${offer.chainId}` };
|
|
3029
|
+
if (!allowedLoanTokens.includes(offer.loanToken.toLowerCase())) return { message: "Loan token is not allowed" };
|
|
3030
|
+
});
|
|
3031
|
+
/**
|
|
3032
|
+
* A validation rule that checks if the offer's collateral tokens are allowed for its chain.
|
|
3033
|
+
* @param collateralAssetsByChainId - Allowed collateral tokens indexed by chain id.
|
|
3034
|
+
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
3035
|
+
*/
|
|
3036
|
+
const collateralToken = ({ collateralAssetsByChainId }) => single("collateral_token", "Validates that offer collateral tokens are in the allowed token list for the offer chain", (offer) => {
|
|
3037
|
+
const allowedCollateralTokens = collateralAssetsByChainId[offer.chainId]?.map((asset) => asset.toLowerCase()) ?? [];
|
|
3038
|
+
if (allowedCollateralTokens.length === 0) return { message: `No allowed collateral tokens for chain ${offer.chainId}` };
|
|
3039
|
+
if (offer.collaterals.length === 0) return { message: "At least one collateral token is required" };
|
|
3040
|
+
if (offer.collaterals.some((collateral) => !allowedCollateralTokens.includes(collateral.asset.toLowerCase()))) return { message: "Collateral token is not allowed" };
|
|
2907
3041
|
});
|
|
2908
3042
|
/**
|
|
2909
3043
|
* A validation rule that checks if the offer's oracle addresses are allowed for its chain.
|
|
@@ -2946,9 +3080,11 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
|
|
|
2946
3080
|
//#region src/gatekeeper/morphoRules.ts
|
|
2947
3081
|
const morphoRules = (chains) => {
|
|
2948
3082
|
const assetsByChainId = {};
|
|
3083
|
+
const collateralAssetsByChainId = {};
|
|
2949
3084
|
const oraclesByChainId = {};
|
|
2950
3085
|
for (const chain of chains) {
|
|
2951
3086
|
assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
|
|
3087
|
+
collateralAssetsByChainId[chain.id] = collateralAssets[chain.id.toString()] ?? [];
|
|
2952
3088
|
oraclesByChainId[chain.id] = oracles$1[chain.id.toString()] ?? [];
|
|
2953
3089
|
}
|
|
2954
3090
|
return [
|
|
@@ -2960,7 +3096,8 @@ const morphoRules = (chains) => {
|
|
|
2960
3096
|
callbacks: [Type$1.BuyWithEmptyCallback, Type$1.SellWithEmptyCallback],
|
|
2961
3097
|
allowedAddresses: []
|
|
2962
3098
|
}),
|
|
2963
|
-
|
|
3099
|
+
loanToken({ assetsByChainId }),
|
|
3100
|
+
collateralToken({ collateralAssetsByChainId }),
|
|
2964
3101
|
oracle({ oraclesByChainId })
|
|
2965
3102
|
];
|
|
2966
3103
|
};
|
|
@@ -2968,7 +3105,7 @@ const morphoRules = (chains) => {
|
|
|
2968
3105
|
//#endregion
|
|
2969
3106
|
//#region src/gatekeeper/ConfigRules.ts
|
|
2970
3107
|
/**
|
|
2971
|
-
* Build the configured rules (maturities + callback addresses + loan tokens + oracles) for the provided chains.
|
|
3108
|
+
* Build the configured rules (maturities + callback addresses + loan tokens + collateral tokens + oracles) for the provided chains.
|
|
2972
3109
|
* @param chains - Chains to include in the configured rules.
|
|
2973
3110
|
* @returns Sorted list of config rules.
|
|
2974
3111
|
*/
|
|
@@ -2988,6 +3125,12 @@ function buildConfigRules(chains) {
|
|
|
2988
3125
|
chain_id: chain.id,
|
|
2989
3126
|
address: normalizeAddress(address)
|
|
2990
3127
|
});
|
|
3128
|
+
const collateralTokens = collateralAssets[chain.id.toString()] ?? [];
|
|
3129
|
+
for (const address of collateralTokens) rules.push({
|
|
3130
|
+
type: "collateral_token",
|
|
3131
|
+
chain_id: chain.id,
|
|
3132
|
+
address: normalizeAddress(address)
|
|
3133
|
+
});
|
|
2991
3134
|
const oracles = oracles$1[chain.id.toString()] ?? [];
|
|
2992
3135
|
for (const address of oracles) rules.push({
|
|
2993
3136
|
type: "oracle",
|
|
@@ -3015,6 +3158,10 @@ function buildConfigRulesChecksum(rules) {
|
|
|
3015
3158
|
hash.update(`callback:${rule.chain_id}:${rule.callback_type}:${rule.address}\n`);
|
|
3016
3159
|
continue;
|
|
3017
3160
|
}
|
|
3161
|
+
if (rule.type === "collateral_token") {
|
|
3162
|
+
hash.update(`collateral_token:${rule.chain_id}:${rule.address}\n`);
|
|
3163
|
+
continue;
|
|
3164
|
+
}
|
|
3018
3165
|
if (rule.type === "oracle") {
|
|
3019
3166
|
hash.update(`oracle:${rule.chain_id}:${rule.address}\n`);
|
|
3020
3167
|
continue;
|
|
@@ -3035,6 +3182,7 @@ function compareConfigRules(left, right) {
|
|
|
3035
3182
|
return left.address.localeCompare(right.address);
|
|
3036
3183
|
}
|
|
3037
3184
|
if (left.type === "loan_token" && right.type === "loan_token") return left.address.localeCompare(right.address);
|
|
3185
|
+
if (left.type === "collateral_token" && right.type === "collateral_token") return left.address.localeCompare(right.address);
|
|
3038
3186
|
if (left.type === "oracle" && right.type === "oracle") return left.address.localeCompare(right.address);
|
|
3039
3187
|
return 0;
|
|
3040
3188
|
}
|
|
@@ -3042,8 +3190,10 @@ function compareConfigRules(left, right) {
|
|
|
3042
3190
|
//#endregion
|
|
3043
3191
|
//#region src/api/Schema/BookResponse.ts
|
|
3044
3192
|
function from$6(level) {
|
|
3193
|
+
const price = tickToPrice(level.tick);
|
|
3045
3194
|
return {
|
|
3046
|
-
|
|
3195
|
+
tick: level.tick,
|
|
3196
|
+
price: price.toString(),
|
|
3047
3197
|
assets: level.assets.toString(),
|
|
3048
3198
|
count: level.count
|
|
3049
3199
|
};
|
|
@@ -3109,6 +3259,16 @@ function from$5(obligation, quote) {
|
|
|
3109
3259
|
|
|
3110
3260
|
//#endregion
|
|
3111
3261
|
//#region src/api/Schema/OfferResponse.ts
|
|
3262
|
+
function normalizeChainId(chainId) {
|
|
3263
|
+
const parsedChainId = Number(chainId);
|
|
3264
|
+
if (!Number.isInteger(parsedChainId) || parsedChainId <= 0) throw new Error(`Invalid chain id: ${String(chainId)}`);
|
|
3265
|
+
return parsedChainId;
|
|
3266
|
+
}
|
|
3267
|
+
function normalizeBlockNumber(blockNumber) {
|
|
3268
|
+
const parsedBlockNumber = Number(blockNumber);
|
|
3269
|
+
if (!Number.isInteger(parsedBlockNumber) || parsedBlockNumber < 0) throw new Error(`Invalid block number: ${String(blockNumber)}`);
|
|
3270
|
+
return parsedBlockNumber;
|
|
3271
|
+
}
|
|
3112
3272
|
/**
|
|
3113
3273
|
* Creates an `OfferResponse` matching the Solidity Offer struct layout.
|
|
3114
3274
|
* @constructor
|
|
@@ -3116,6 +3276,8 @@ function from$5(obligation, quote) {
|
|
|
3116
3276
|
* @returns The created `OfferResponse`. {@link OfferResponse}
|
|
3117
3277
|
*/
|
|
3118
3278
|
function from$4(input) {
|
|
3279
|
+
const chainId = normalizeChainId(input.chainId);
|
|
3280
|
+
const blockNumber = normalizeBlockNumber(input.blockNumber);
|
|
3119
3281
|
const base = {
|
|
3120
3282
|
offer: {
|
|
3121
3283
|
obligation: {
|
|
@@ -3134,7 +3296,7 @@ function from$4(input) {
|
|
|
3134
3296
|
obligation_shares: input.obligationShares.toString(),
|
|
3135
3297
|
start: input.start,
|
|
3136
3298
|
expiry: input.expiry,
|
|
3137
|
-
|
|
3299
|
+
tick: input.tick,
|
|
3138
3300
|
group: input.group,
|
|
3139
3301
|
session: input.session,
|
|
3140
3302
|
callback: input.callback.address,
|
|
@@ -3142,15 +3304,15 @@ function from$4(input) {
|
|
|
3142
3304
|
},
|
|
3143
3305
|
offer_hash: input.hash,
|
|
3144
3306
|
obligation_id: id({
|
|
3145
|
-
chainId
|
|
3307
|
+
chainId,
|
|
3146
3308
|
loanToken: input.loanToken,
|
|
3147
3309
|
collaterals: [...input.collaterals],
|
|
3148
3310
|
maturity: input.maturity
|
|
3149
3311
|
}),
|
|
3150
|
-
chain_id:
|
|
3312
|
+
chain_id: chainId,
|
|
3151
3313
|
consumed: input.consumed.toString(),
|
|
3152
3314
|
takeable: input.takeable.toString(),
|
|
3153
|
-
block_number:
|
|
3315
|
+
block_number: blockNumber
|
|
3154
3316
|
};
|
|
3155
3317
|
if (!input.proof || !input.root || !input.signature) return {
|
|
3156
3318
|
...base,
|
|
@@ -3296,7 +3458,7 @@ const offerExample = {
|
|
|
3296
3458
|
obligation_shares: "0",
|
|
3297
3459
|
start: 1761922790,
|
|
3298
3460
|
expiry: 1761922799,
|
|
3299
|
-
|
|
3461
|
+
tick: 495,
|
|
3300
3462
|
group: "0x000000000000000000000000000000000000000000000000000000000008b8f4",
|
|
3301
3463
|
session: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
3302
3464
|
callback: "0x0000000000000000000000000000000000000000",
|
|
@@ -3337,7 +3499,7 @@ const validateOfferExample = {
|
|
|
3337
3499
|
assets: "369216000000000000000000",
|
|
3338
3500
|
obligation_units: "0",
|
|
3339
3501
|
obligation_shares: "0",
|
|
3340
|
-
|
|
3502
|
+
tick: 495,
|
|
3341
3503
|
maturity: 1761922799,
|
|
3342
3504
|
expiry: 1761922799,
|
|
3343
3505
|
start: 1761922790,
|
|
@@ -3481,9 +3643,11 @@ __decorate([ApiProperty({
|
|
|
3481
3643
|
example: offerExample.offer.expiry
|
|
3482
3644
|
})], OfferDataResponse.prototype, "expiry", void 0);
|
|
3483
3645
|
__decorate([ApiProperty({
|
|
3484
|
-
type: "
|
|
3485
|
-
example: offerExample.offer.
|
|
3486
|
-
|
|
3646
|
+
type: "number",
|
|
3647
|
+
example: offerExample.offer.tick,
|
|
3648
|
+
minimum: 0,
|
|
3649
|
+
maximum: 990
|
|
3650
|
+
})], OfferDataResponse.prototype, "tick", void 0);
|
|
3487
3651
|
__decorate([ApiProperty({
|
|
3488
3652
|
type: "string",
|
|
3489
3653
|
example: offerExample.offer.group
|
|
@@ -3724,9 +3888,11 @@ __decorate([ApiProperty({
|
|
|
3724
3888
|
required: false
|
|
3725
3889
|
})], ValidateOfferRequest.prototype, "obligation_shares", void 0);
|
|
3726
3890
|
__decorate([ApiProperty({
|
|
3727
|
-
type: "
|
|
3728
|
-
example: validateOfferExample.
|
|
3729
|
-
|
|
3891
|
+
type: "number",
|
|
3892
|
+
example: validateOfferExample.tick,
|
|
3893
|
+
minimum: 0,
|
|
3894
|
+
maximum: 990
|
|
3895
|
+
})], ValidateOfferRequest.prototype, "tick", void 0);
|
|
3730
3896
|
__decorate([ApiProperty({
|
|
3731
3897
|
type: "number",
|
|
3732
3898
|
example: validateOfferExample.maturity
|
|
@@ -3826,9 +3992,16 @@ __decorate([ApiProperty({
|
|
|
3826
3992
|
description: "List of validation issues. Returned when any offer fails validation."
|
|
3827
3993
|
})], ValidationFailureResponse.prototype, "data", void 0);
|
|
3828
3994
|
var BookLevelResponse = class {};
|
|
3995
|
+
__decorate([ApiProperty({
|
|
3996
|
+
type: "number",
|
|
3997
|
+
example: 495,
|
|
3998
|
+
minimum: 0,
|
|
3999
|
+
maximum: 990
|
|
4000
|
+
})], BookLevelResponse.prototype, "tick", void 0);
|
|
3829
4001
|
__decorate([ApiProperty({
|
|
3830
4002
|
type: "string",
|
|
3831
|
-
example: "
|
|
4003
|
+
example: "500000000000000000",
|
|
4004
|
+
description: "Price derived from tick, scaled by 1e18."
|
|
3832
4005
|
})], BookLevelResponse.prototype, "price", void 0);
|
|
3833
4006
|
__decorate([ApiProperty({
|
|
3834
4007
|
type: "string",
|
|
@@ -3842,6 +4015,7 @@ const positionExample = {
|
|
|
3842
4015
|
chain_id: 1,
|
|
3843
4016
|
contract: "0xC9A9C45C0eB717f8b5F193Af6bAa05A1c0Ac5078",
|
|
3844
4017
|
user: "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
|
|
4018
|
+
obligation_id: "0x12590ae1aee324a005be565f3bcdd16dbf8daf7969b26c181c8b8f467dad9f67",
|
|
3845
4019
|
reserved: "200000000000000000000",
|
|
3846
4020
|
block_number: 21345678
|
|
3847
4021
|
};
|
|
@@ -3858,6 +4032,12 @@ __decorate([ApiProperty({
|
|
|
3858
4032
|
type: "string",
|
|
3859
4033
|
example: positionExample.user
|
|
3860
4034
|
})], PositionListItemResponse.prototype, "user", void 0);
|
|
4035
|
+
__decorate([ApiProperty({
|
|
4036
|
+
type: "string",
|
|
4037
|
+
nullable: true,
|
|
4038
|
+
example: positionExample.obligation_id,
|
|
4039
|
+
description: "Obligation id this reserved amount belongs to, or null if no lots exist."
|
|
4040
|
+
})], PositionListItemResponse.prototype, "obligation_id", void 0);
|
|
3861
4041
|
__decorate([ApiProperty({
|
|
3862
4042
|
type: "string",
|
|
3863
4043
|
example: positionExample.reserved
|
|
@@ -3885,7 +4065,7 @@ __decorate([ApiProperty({
|
|
|
3885
4065
|
})], BookListResponse.prototype, "cursor", void 0);
|
|
3886
4066
|
__decorate([ApiProperty({
|
|
3887
4067
|
type: () => [BookLevelResponse],
|
|
3888
|
-
description: "Aggregated book levels grouped by
|
|
4068
|
+
description: "Aggregated book levels grouped by offer tick."
|
|
3889
4069
|
})], BookListResponse.prototype, "data", void 0);
|
|
3890
4070
|
let BooksController = class BooksController {
|
|
3891
4071
|
async getBook() {}
|
|
@@ -3895,7 +4075,7 @@ __decorate([
|
|
|
3895
4075
|
methods: ["get"],
|
|
3896
4076
|
path: "/v1/books/{obligationId}/{side}",
|
|
3897
4077
|
summary: "Get aggregated book",
|
|
3898
|
-
description: "Returns aggregated book data for a given obligation and side. Offers are grouped by
|
|
4078
|
+
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)."
|
|
3899
4079
|
}),
|
|
3900
4080
|
ApiParam({
|
|
3901
4081
|
name: "obligationId",
|
|
@@ -3920,7 +4100,7 @@ __decorate([
|
|
|
3920
4100
|
name: "limit",
|
|
3921
4101
|
type: "number",
|
|
3922
4102
|
example: 10,
|
|
3923
|
-
description: "Maximum number of
|
|
4103
|
+
description: "Maximum number of tick levels to return."
|
|
3924
4104
|
}),
|
|
3925
4105
|
ApiResponse({
|
|
3926
4106
|
status: 200,
|
|
@@ -4114,6 +4294,11 @@ const configRulesLoanTokenExample = {
|
|
|
4114
4294
|
chain_id: 1,
|
|
4115
4295
|
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
4116
4296
|
};
|
|
4297
|
+
const configRulesCollateralTokenExample = {
|
|
4298
|
+
type: "collateral_token",
|
|
4299
|
+
chain_id: 1,
|
|
4300
|
+
address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
4301
|
+
};
|
|
4117
4302
|
const configRulesOracleExample = {
|
|
4118
4303
|
type: "oracle",
|
|
4119
4304
|
chain_id: 1,
|
|
@@ -4123,6 +4308,7 @@ const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
|
|
|
4123
4308
|
const configRulesPayloadExample = [
|
|
4124
4309
|
configRulesMaturityExample,
|
|
4125
4310
|
configRulesLoanTokenExample,
|
|
4311
|
+
configRulesCollateralTokenExample,
|
|
4126
4312
|
configRulesOracleExample
|
|
4127
4313
|
];
|
|
4128
4314
|
const configContractNames = [
|
|
@@ -4249,7 +4435,7 @@ __decorate([
|
|
|
4249
4435
|
methods: ["get"],
|
|
4250
4436
|
path: "/v1/config/rules",
|
|
4251
4437
|
summary: "Get config rules",
|
|
4252
|
-
description: "Returns configured rules (maturities, loan tokens, oracles) for supported chains."
|
|
4438
|
+
description: "Returns configured rules (maturities, loan tokens, collateral tokens, oracles) for supported chains."
|
|
4253
4439
|
}),
|
|
4254
4440
|
ApiQuery({
|
|
4255
4441
|
name: "cursor",
|
|
@@ -4269,7 +4455,7 @@ __decorate([
|
|
|
4269
4455
|
name: "types",
|
|
4270
4456
|
type: ["string"],
|
|
4271
4457
|
required: false,
|
|
4272
|
-
example: "maturity,loan_token,oracle",
|
|
4458
|
+
example: "maturity,loan_token,collateral_token,oracle",
|
|
4273
4459
|
description: "Filter by rule types (comma-separated).",
|
|
4274
4460
|
style: "form",
|
|
4275
4461
|
explode: false
|
|
@@ -4387,7 +4573,7 @@ __decorate([
|
|
|
4387
4573
|
methods: ["get"],
|
|
4388
4574
|
path: "/v1/users/{userAddress}/positions",
|
|
4389
4575
|
summary: "Get user positions",
|
|
4390
|
-
description: "Returns positions for a user with reserved balance.
|
|
4576
|
+
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."
|
|
4391
4577
|
}),
|
|
4392
4578
|
ApiParam({
|
|
4393
4579
|
name: "userAddress",
|
|
@@ -4474,6 +4660,7 @@ function from$3(position) {
|
|
|
4474
4660
|
chain_id: position.chainId,
|
|
4475
4661
|
contract: position.contract,
|
|
4476
4662
|
user: position.user,
|
|
4663
|
+
obligation_id: position.obligationId,
|
|
4477
4664
|
reserved: position.reserved.toString(),
|
|
4478
4665
|
block_number: position.blockNumber
|
|
4479
4666
|
};
|
|
@@ -4527,10 +4714,11 @@ const ConfigRuleTypes = z$2.enum([
|
|
|
4527
4714
|
"maturity",
|
|
4528
4715
|
"callback",
|
|
4529
4716
|
"loan_token",
|
|
4717
|
+
"collateral_token",
|
|
4530
4718
|
"oracle"
|
|
4531
4719
|
]);
|
|
4532
4720
|
const GetConfigRulesQueryParams = z$2.object({
|
|
4533
|
-
cursor: z$2.string().regex(/^(maturity|callback|loan_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
4721
|
+
cursor: z$2.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({
|
|
4534
4722
|
description: "Pagination cursor in type:chain_id:<value> format",
|
|
4535
4723
|
example: "maturity:1:1730415600:end_of_next_month"
|
|
4536
4724
|
}),
|
|
@@ -4540,7 +4728,7 @@ const GetConfigRulesQueryParams = z$2.object({
|
|
|
4540
4728
|
}),
|
|
4541
4729
|
types: csvArray(ConfigRuleTypes).meta({
|
|
4542
4730
|
description: "Filter by rule types (comma-separated).",
|
|
4543
|
-
example: "maturity,loan_token,oracle"
|
|
4731
|
+
example: "maturity,loan_token,collateral_token,oracle"
|
|
4544
4732
|
}),
|
|
4545
4733
|
chains: csvArray(z$2.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
4546
4734
|
description: "Filter by chain IDs (comma-separated).",
|
|
@@ -4640,12 +4828,11 @@ const GetObligationParams = z$2.object({ obligation_id: z$2.string({ error: "Obl
|
|
|
4640
4828
|
description: "Obligation id",
|
|
4641
4829
|
example: "0x1234567890123456789012345678901234567890123456789012345678901234"
|
|
4642
4830
|
}) });
|
|
4643
|
-
/** Validate a book cursor format: {side,
|
|
4831
|
+
/** Validate a book cursor format: {side, lastTick, offersCursor} */
|
|
4644
4832
|
function isValidBookCursor(cursorString) {
|
|
4645
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
4646
4833
|
try {
|
|
4647
4834
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
4648
|
-
return (v?.side === "buy" || v?.side === "sell") &&
|
|
4835
|
+
return (v?.side === "buy" || v?.side === "sell") && typeof v?.lastTick === "number" && Number.isInteger(v.lastTick) && (v?.offersCursor === null || typeof v?.offersCursor === "string");
|
|
4649
4836
|
} catch {
|
|
4650
4837
|
return false;
|
|
4651
4838
|
}
|
|
@@ -4750,6 +4937,7 @@ function formatCursor$1(rule) {
|
|
|
4750
4937
|
if (rule.type === "maturity") return `maturity:${rule.chain_id}:${rule.timestamp}:${rule.name}`;
|
|
4751
4938
|
if (rule.type === "callback") return `callback:${rule.chain_id}:${rule.callback_type}:${rule.address.toLowerCase()}`;
|
|
4752
4939
|
if (rule.type === "oracle") return `oracle:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
4940
|
+
if (rule.type === "collateral_token") return `collateral_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
4753
4941
|
return `loan_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
4754
4942
|
}
|
|
4755
4943
|
function parseCursor$1(cursor) {
|
|
@@ -4782,7 +4970,7 @@ function parseCursor$1(cursor) {
|
|
|
4782
4970
|
address: parseAddress(addressValue, "Cursor address")
|
|
4783
4971
|
};
|
|
4784
4972
|
}
|
|
4785
|
-
if (type === "loan_token" || type === "oracle") {
|
|
4973
|
+
if (type === "loan_token" || type === "collateral_token" || type === "oracle") {
|
|
4786
4974
|
const addressValue = rest.join(":");
|
|
4787
4975
|
if (!addressValue) throw new BadRequestError(`Cursor must be in the format ${type}:chain_id:address`);
|
|
4788
4976
|
return {
|
|
@@ -4809,7 +4997,7 @@ function parseAddress(address, label) {
|
|
|
4809
4997
|
return address.toLowerCase();
|
|
4810
4998
|
}
|
|
4811
4999
|
function isConfigRuleType(value) {
|
|
4812
|
-
return value === "maturity" || value === "callback" || value === "loan_token" || value === "oracle";
|
|
5000
|
+
return value === "maturity" || value === "callback" || value === "loan_token" || value === "collateral_token" || value === "oracle";
|
|
4813
5001
|
}
|
|
4814
5002
|
function isMaturityType(value) {
|
|
4815
5003
|
return Object.values(MaturityType).includes(value);
|
|
@@ -5082,7 +5270,7 @@ function now() {
|
|
|
5082
5270
|
|
|
5083
5271
|
//#endregion
|
|
5084
5272
|
//#region src/database/drizzle/VERSION.ts
|
|
5085
|
-
const VERSION = "router_v1.
|
|
5273
|
+
const VERSION = "router_v1.8";
|
|
5086
5274
|
|
|
5087
5275
|
//#endregion
|
|
5088
5276
|
//#region src/database/drizzle/schema.ts
|
|
@@ -5234,10 +5422,7 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
5234
5422
|
precision: 78,
|
|
5235
5423
|
scale: 0
|
|
5236
5424
|
}).notNull().default("0"),
|
|
5237
|
-
|
|
5238
|
-
precision: 78,
|
|
5239
|
-
scale: 0
|
|
5240
|
-
}).notNull(),
|
|
5425
|
+
tick: integer("tick").notNull(),
|
|
5241
5426
|
maturity: integer("maturity").notNull(),
|
|
5242
5427
|
expiry: integer("expiry").notNull(),
|
|
5243
5428
|
start: integer("start").notNull(),
|
|
@@ -5302,6 +5487,7 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
5302
5487
|
user: varchar("user", { length: 42 }).notNull(),
|
|
5303
5488
|
contract: varchar("contract", { length: 42 }).notNull(),
|
|
5304
5489
|
group: varchar("group", { length: 66 }).notNull(),
|
|
5490
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
5305
5491
|
lower: numeric("lower", {
|
|
5306
5492
|
precision: 78,
|
|
5307
5493
|
scale: 0
|
|
@@ -5316,7 +5502,8 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
5316
5502
|
table.chainId,
|
|
5317
5503
|
table.user,
|
|
5318
5504
|
table.contract,
|
|
5319
|
-
table.group
|
|
5505
|
+
table.group,
|
|
5506
|
+
table.obligationId
|
|
5320
5507
|
],
|
|
5321
5508
|
name: "lots_pk"
|
|
5322
5509
|
}),
|
|
@@ -5352,6 +5539,7 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
5352
5539
|
user: varchar("user", { length: 42 }).notNull(),
|
|
5353
5540
|
contract: varchar("contract", { length: 42 }).notNull(),
|
|
5354
5541
|
group: varchar("group", { length: 66 }).notNull(),
|
|
5542
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
5355
5543
|
value: numeric("value", {
|
|
5356
5544
|
precision: 78,
|
|
5357
5545
|
scale: 0
|
|
@@ -5361,7 +5549,8 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
5361
5549
|
table.chainId,
|
|
5362
5550
|
table.user,
|
|
5363
5551
|
table.contract,
|
|
5364
|
-
table.group
|
|
5552
|
+
table.group,
|
|
5553
|
+
table.obligationId
|
|
5365
5554
|
],
|
|
5366
5555
|
name: "offsets_pk"
|
|
5367
5556
|
}), foreignKey({
|
|
@@ -5952,6 +6141,7 @@ function decodeCallbacks(parameters) {
|
|
|
5952
6141
|
positionContract: loanToken,
|
|
5953
6142
|
positionUser: offer.maker,
|
|
5954
6143
|
group: offer.group,
|
|
6144
|
+
obligationId: obligationId(offer),
|
|
5955
6145
|
size: offer.assets
|
|
5956
6146
|
});
|
|
5957
6147
|
callbacks.push({
|
|
@@ -7354,6 +7544,7 @@ function create$14(config) {
|
|
|
7354
7544
|
return {
|
|
7355
7545
|
get: async (parameters) => {
|
|
7356
7546
|
const { side, obligationId, cursor: cursorString, limit = DEFAULT_LIMIT$3 } = parameters;
|
|
7547
|
+
const tickSortDirection = side === "sell" ? "asc" : "desc";
|
|
7357
7548
|
const inputCursor = LevelCursor.decode(cursorString, logger);
|
|
7358
7549
|
if (cursorString != null && inputCursor === null) return {
|
|
7359
7550
|
levels: [],
|
|
@@ -7368,23 +7559,23 @@ function create$14(config) {
|
|
|
7368
7559
|
cursor: inputCursor?.offersCursor ?? void 0,
|
|
7369
7560
|
limit: fetchLimit
|
|
7370
7561
|
});
|
|
7371
|
-
const
|
|
7562
|
+
const tickMap = /* @__PURE__ */ new Map();
|
|
7372
7563
|
for (const row of rows) {
|
|
7373
|
-
const
|
|
7374
|
-
const existing = priceMap.get(priceKey);
|
|
7564
|
+
const existing = tickMap.get(row.tick);
|
|
7375
7565
|
if (existing) {
|
|
7376
7566
|
existing.assets += row.takeable;
|
|
7377
7567
|
existing.count += 1;
|
|
7378
|
-
} else
|
|
7568
|
+
} else tickMap.set(row.tick, {
|
|
7379
7569
|
assets: row.takeable,
|
|
7380
7570
|
count: 1
|
|
7381
7571
|
});
|
|
7382
7572
|
}
|
|
7383
|
-
const levels = Array.from(
|
|
7384
|
-
|
|
7385
|
-
assets:
|
|
7386
|
-
count:
|
|
7573
|
+
const levels = Array.from(tickMap.entries()).map(([tick, level]) => ({
|
|
7574
|
+
tick,
|
|
7575
|
+
assets: level.assets,
|
|
7576
|
+
count: level.count
|
|
7387
7577
|
}));
|
|
7578
|
+
levels.sort((a, b) => tickSortDirection === "asc" ? a.tick - b.tick : b.tick - a.tick);
|
|
7388
7579
|
const paginatedLevels = levels.slice(0, limit);
|
|
7389
7580
|
const hasMore = levels.length > limit || offersNextCursor !== null;
|
|
7390
7581
|
const lastLevel = paginatedLevels[paginatedLevels.length - 1];
|
|
@@ -7430,14 +7621,14 @@ async function _getOffers(db, params) {
|
|
|
7430
7621
|
AND (s.code IS NULL OR s.code = ${Status.VALID})
|
|
7431
7622
|
ORDER BY
|
|
7432
7623
|
o.group_chain_id, o.group_maker, o."group_group",
|
|
7433
|
-
o.
|
|
7624
|
+
o.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`}, o.block_number ASC, o.assets DESC, o.hash ASC
|
|
7434
7625
|
),
|
|
7435
7626
|
enriched AS (
|
|
7436
7627
|
SELECT
|
|
7437
7628
|
w.*,
|
|
7438
7629
|
g.consumed, g.chain_id, obl.loan_token,
|
|
7439
7630
|
CASE WHEN ${priceSortDirection === "asc" ? sql`TRUE` : sql`FALSE`}
|
|
7440
|
-
THEN w.
|
|
7631
|
+
THEN w.tick ELSE -w.tick END AS tick_norm,
|
|
7441
7632
|
w.block_number AS block_norm,
|
|
7442
7633
|
-w.assets AS assets_norm,
|
|
7443
7634
|
w.hash AS hash_norm
|
|
@@ -7454,33 +7645,35 @@ async function _getOffers(db, params) {
|
|
|
7454
7645
|
FROM enriched e
|
|
7455
7646
|
${cursor != null ? sql`
|
|
7456
7647
|
WHERE
|
|
7457
|
-
(e.
|
|
7648
|
+
(e.tick_norm, e.block_norm, e.assets_norm, e.hash_norm)
|
|
7458
7649
|
> (
|
|
7459
7650
|
CASE WHEN ${priceSortDirection === "asc" ? sql`TRUE` : sql`FALSE`}
|
|
7460
|
-
THEN ${cursor.
|
|
7651
|
+
THEN ${cursor.tick}::integer ELSE -${cursor.tick}::integer END,
|
|
7461
7652
|
${cursor.blockNumber},
|
|
7462
7653
|
-${cursor.assets}::numeric,
|
|
7463
7654
|
${cursor.hash}
|
|
7464
7655
|
)` : sql``}
|
|
7465
|
-
ORDER BY e.
|
|
7656
|
+
ORDER BY e.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`}, e.block_number ASC, e.assets DESC, e.hash ASC
|
|
7466
7657
|
LIMIT ${limit}
|
|
7467
7658
|
),
|
|
7468
|
-
-- Compute sum of offsets per position
|
|
7659
|
+
-- Compute sum of offsets per position and obligation
|
|
7469
7660
|
position_offsets AS (
|
|
7470
7661
|
SELECT
|
|
7471
7662
|
chain_id,
|
|
7472
7663
|
"user",
|
|
7473
7664
|
contract,
|
|
7665
|
+
obligation_id,
|
|
7474
7666
|
SUM(value::numeric) AS total_offset
|
|
7475
7667
|
FROM ${offsets}
|
|
7476
|
-
GROUP BY chain_id, "user", contract
|
|
7668
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
7477
7669
|
),
|
|
7478
|
-
-- Compute position_consumed: sum of consumed from all groups with lots on each position (converted to lot terms)
|
|
7670
|
+
-- Compute position_consumed: sum of consumed from all groups with lots on each position+obligation (converted to lot terms)
|
|
7479
7671
|
position_consumed AS (
|
|
7480
7672
|
SELECT
|
|
7481
7673
|
l.chain_id,
|
|
7482
7674
|
l.contract,
|
|
7483
7675
|
l."user",
|
|
7676
|
+
l.obligation_id,
|
|
7484
7677
|
SUM(
|
|
7485
7678
|
CASE
|
|
7486
7679
|
WHEN wo.assets::numeric > 0
|
|
@@ -7497,7 +7690,7 @@ async function _getOffers(db, params) {
|
|
|
7497
7690
|
ON wo.group_chain_id = g.chain_id
|
|
7498
7691
|
AND LOWER(wo.group_maker) = LOWER(g.maker)
|
|
7499
7692
|
AND wo.group_group = g."group"
|
|
7500
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
7693
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
7501
7694
|
),
|
|
7502
7695
|
-- Compute callback contributions with lot balance
|
|
7503
7696
|
callback_contributions AS (
|
|
@@ -7505,7 +7698,7 @@ async function _getOffers(db, params) {
|
|
|
7505
7698
|
p.hash,
|
|
7506
7699
|
p.obligation_id,
|
|
7507
7700
|
p.assets,
|
|
7508
|
-
p.
|
|
7701
|
+
p.tick,
|
|
7509
7702
|
p.obligation_units,
|
|
7510
7703
|
p.obligation_shares,
|
|
7511
7704
|
p.maturity,
|
|
@@ -7550,6 +7743,7 @@ async function _getOffers(db, params) {
|
|
|
7550
7743
|
AND LOWER(l.contract) = LOWER(c.position_contract)
|
|
7551
7744
|
AND LOWER(l."user") = LOWER(c.position_user)
|
|
7552
7745
|
AND l."group" = p.group_group
|
|
7746
|
+
AND l.obligation_id = p.obligation_id
|
|
7553
7747
|
LEFT JOIN ${positions} pos
|
|
7554
7748
|
ON pos.chain_id = c.position_chain_id
|
|
7555
7749
|
AND LOWER(pos.contract) = LOWER(c.position_contract)
|
|
@@ -7558,10 +7752,12 @@ async function _getOffers(db, params) {
|
|
|
7558
7752
|
ON pos_offsets.chain_id = c.position_chain_id
|
|
7559
7753
|
AND LOWER(pos_offsets.contract) = LOWER(c.position_contract)
|
|
7560
7754
|
AND LOWER(pos_offsets."user") = LOWER(c.position_user)
|
|
7755
|
+
AND pos_offsets.obligation_id = p.obligation_id
|
|
7561
7756
|
LEFT JOIN position_consumed pc
|
|
7562
7757
|
ON pc.chain_id = c.position_chain_id
|
|
7563
7758
|
AND LOWER(pc.contract) = LOWER(c.position_contract)
|
|
7564
7759
|
AND LOWER(pc."user") = LOWER(c.position_user)
|
|
7760
|
+
AND pc.obligation_id = p.obligation_id
|
|
7565
7761
|
),
|
|
7566
7762
|
-- Compute contribution per callback in loan terms (loan token only — collateral positions are not indexed)
|
|
7567
7763
|
callback_loan_contribution AS (
|
|
@@ -7579,7 +7775,7 @@ async function _getOffers(db, params) {
|
|
|
7579
7775
|
hash,
|
|
7580
7776
|
obligation_id,
|
|
7581
7777
|
assets,
|
|
7582
|
-
|
|
7778
|
+
tick,
|
|
7583
7779
|
obligation_units,
|
|
7584
7780
|
obligation_shares,
|
|
7585
7781
|
maturity,
|
|
@@ -7605,13 +7801,13 @@ async function _getOffers(db, params) {
|
|
|
7605
7801
|
WHERE clc.callback_id IS NOT NULL
|
|
7606
7802
|
ORDER BY clc.hash, clc.position_chain_id, clc.position_contract, clc.position_user, clc.contribution_in_loan DESC
|
|
7607
7803
|
) deduped
|
|
7608
|
-
GROUP BY hash, obligation_id, assets,
|
|
7804
|
+
GROUP BY hash, obligation_id, assets, tick, obligation_units, obligation_shares, maturity, expiry, start, group_group, buy,
|
|
7609
7805
|
callback_address, callback_data, block_number, group_chain_id, group_maker,
|
|
7610
7806
|
consumed, chain_id, loan_token, session
|
|
7611
7807
|
UNION ALL
|
|
7612
7808
|
-- Sell offers without callbacks: collateral positions not indexed, takeable = assets - consumed
|
|
7613
7809
|
SELECT
|
|
7614
|
-
p.hash, p.obligation_id, p.assets, p.
|
|
7810
|
+
p.hash, p.obligation_id, p.assets, p.tick,
|
|
7615
7811
|
p.obligation_units, p.obligation_shares,
|
|
7616
7812
|
p.maturity, p.expiry, p.start, p.group_group,
|
|
7617
7813
|
p.buy, p.callback_address, p.callback_data,
|
|
@@ -7633,7 +7829,7 @@ async function _getOffers(db, params) {
|
|
|
7633
7829
|
oc.obligation_units,
|
|
7634
7830
|
oc.obligation_shares,
|
|
7635
7831
|
oc.consumed,
|
|
7636
|
-
oc.
|
|
7832
|
+
oc.tick,
|
|
7637
7833
|
oc.maturity,
|
|
7638
7834
|
oc.expiry,
|
|
7639
7835
|
oc.start,
|
|
@@ -7665,7 +7861,7 @@ async function _getOffers(db, params) {
|
|
|
7665
7861
|
))
|
|
7666
7862
|
END > 0
|
|
7667
7863
|
ORDER BY
|
|
7668
|
-
oc.
|
|
7864
|
+
oc.tick ${priceSortDirection === "asc" ? sql`ASC` : sql`DESC`},
|
|
7669
7865
|
oc.block_number ASC,
|
|
7670
7866
|
oc.assets DESC,
|
|
7671
7867
|
oc.hash ASC;
|
|
@@ -7678,7 +7874,7 @@ async function _getOffers(db, params) {
|
|
|
7678
7874
|
assets: BigInt(row.assets),
|
|
7679
7875
|
obligationUnits: BigInt(row.obligation_units ?? 0),
|
|
7680
7876
|
obligationShares: BigInt(row.obligation_shares ?? 0),
|
|
7681
|
-
|
|
7877
|
+
tick: row.tick,
|
|
7682
7878
|
maturity: row.maturity,
|
|
7683
7879
|
expiry: row.expiry,
|
|
7684
7880
|
start: row.start,
|
|
@@ -7710,7 +7906,7 @@ let Cursor;
|
|
|
7710
7906
|
function encode(row, totalReturned, now, side) {
|
|
7711
7907
|
return Buffer.from(JSON.stringify({
|
|
7712
7908
|
side,
|
|
7713
|
-
|
|
7909
|
+
tick: row.tick,
|
|
7714
7910
|
blockNumber: row.blockNumber,
|
|
7715
7911
|
assets: row.assets.toString(),
|
|
7716
7912
|
hash: row.hash,
|
|
@@ -7721,10 +7917,9 @@ let Cursor;
|
|
|
7721
7917
|
_Cursor.encode = encode;
|
|
7722
7918
|
function decode(cursorString, logger) {
|
|
7723
7919
|
if (cursorString == null) return null;
|
|
7724
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
7725
7920
|
try {
|
|
7726
7921
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
7727
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
7922
|
+
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;
|
|
7728
7923
|
throw new Error("Invalid cursor");
|
|
7729
7924
|
} catch {
|
|
7730
7925
|
logger.error({
|
|
@@ -7742,7 +7937,7 @@ let LevelCursor;
|
|
|
7742
7937
|
function encode(lastLevel, offersCursor, side, now) {
|
|
7743
7938
|
return Buffer.from(JSON.stringify({
|
|
7744
7939
|
side,
|
|
7745
|
-
|
|
7940
|
+
lastTick: lastLevel.tick,
|
|
7746
7941
|
now,
|
|
7747
7942
|
offersCursor
|
|
7748
7943
|
})).toString("base64url");
|
|
@@ -7750,10 +7945,9 @@ let LevelCursor;
|
|
|
7750
7945
|
_LevelCursor.encode = encode;
|
|
7751
7946
|
function decode(cursorString, logger) {
|
|
7752
7947
|
if (cursorString == null) return null;
|
|
7753
|
-
const isNumericString = (value) => typeof value === "string" && /^-?\d+$/.test(value);
|
|
7754
7948
|
try {
|
|
7755
7949
|
const v = JSON.parse(Buffer.from(cursorString, "base64url").toString("utf8"));
|
|
7756
|
-
if ((v?.side === "buy" || v?.side === "sell") &&
|
|
7950
|
+
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;
|
|
7757
7951
|
throw new Error("Invalid book cursor");
|
|
7758
7952
|
} catch {
|
|
7759
7953
|
logger.error({
|
|
@@ -7911,31 +8105,33 @@ function create$11(db) {
|
|
|
7911
8105
|
function create$10(db) {
|
|
7912
8106
|
return {
|
|
7913
8107
|
get: async (parameters) => {
|
|
7914
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
8108
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
7915
8109
|
const conditions = [];
|
|
7916
8110
|
if (chainId !== void 0) conditions.push(eq(lots.chainId, chainId));
|
|
7917
8111
|
if (user !== void 0) conditions.push(eq(lots.user, user.toLowerCase()));
|
|
7918
8112
|
if (contract !== void 0) conditions.push(eq(lots.contract, contract.toLowerCase()));
|
|
7919
8113
|
if (group !== void 0) conditions.push(eq(lots.group, group));
|
|
8114
|
+
if (obligationId !== void 0) conditions.push(eq(lots.obligationId, obligationId));
|
|
7920
8115
|
return (await db.select().from(lots).where(conditions.length > 0 ? and(...conditions) : void 0)).map((row) => ({
|
|
7921
8116
|
chainId: row.chainId,
|
|
7922
8117
|
user: row.user,
|
|
7923
8118
|
contract: row.contract,
|
|
7924
8119
|
group: row.group,
|
|
8120
|
+
obligationId: row.obligationId,
|
|
7925
8121
|
lower: BigInt(row.lower),
|
|
7926
8122
|
upper: BigInt(row.upper)
|
|
7927
8123
|
}));
|
|
7928
8124
|
},
|
|
7929
8125
|
create: async (parameters) => {
|
|
7930
8126
|
if (parameters.length === 0) return;
|
|
7931
|
-
const
|
|
8127
|
+
const lotsByKey = /* @__PURE__ */ new Map();
|
|
7932
8128
|
for (const offer of parameters) {
|
|
7933
|
-
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}`.toLowerCase();
|
|
7934
|
-
const existing =
|
|
7935
|
-
if (!existing || offer.size > existing.size)
|
|
8129
|
+
const key = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}-${offer.group}-${offer.obligationId}`.toLowerCase();
|
|
8130
|
+
const existing = lotsByKey.get(key);
|
|
8131
|
+
if (!existing || offer.size > existing.size) lotsByKey.set(key, offer);
|
|
7936
8132
|
}
|
|
7937
|
-
for (const offer of
|
|
7938
|
-
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())));
|
|
8133
|
+
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) {
|
|
8134
|
+
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())));
|
|
7939
8135
|
const newLower = BigInt(maxUpperResult[0]?.maxUpper ?? "0");
|
|
7940
8136
|
const newUpper = newLower + offer.size;
|
|
7941
8137
|
await db.insert(lots).values({
|
|
@@ -7943,6 +8139,7 @@ function create$10(db) {
|
|
|
7943
8139
|
user: offer.positionUser.toLowerCase(),
|
|
7944
8140
|
contract: offer.positionContract.toLowerCase(),
|
|
7945
8141
|
group: offer.group.toLowerCase(),
|
|
8142
|
+
obligationId: offer.obligationId.toLowerCase(),
|
|
7946
8143
|
lower: newLower.toString(),
|
|
7947
8144
|
upper: newUpper.toString()
|
|
7948
8145
|
});
|
|
@@ -8059,7 +8256,7 @@ function create$8(config) {
|
|
|
8059
8256
|
assets: offers.assets,
|
|
8060
8257
|
obligationUnits: offers.obligationUnits,
|
|
8061
8258
|
obligationShares: offers.obligationShares,
|
|
8062
|
-
|
|
8259
|
+
tick: offers.tick,
|
|
8063
8260
|
maturity: offers.maturity,
|
|
8064
8261
|
expiry: offers.expiry,
|
|
8065
8262
|
start: offers.start,
|
|
@@ -8079,7 +8276,7 @@ function create$8(config) {
|
|
|
8079
8276
|
assets: BigInt(row.assets),
|
|
8080
8277
|
obligationUnits: BigInt(row.obligationUnits),
|
|
8081
8278
|
obligationShares: BigInt(row.obligationShares),
|
|
8082
|
-
|
|
8279
|
+
tick: row.tick,
|
|
8083
8280
|
maturity: from$16(row.maturity),
|
|
8084
8281
|
expiry: row.expiry,
|
|
8085
8282
|
start: row.start,
|
|
@@ -8161,8 +8358,8 @@ function create$8(config) {
|
|
|
8161
8358
|
const now$2 = now();
|
|
8162
8359
|
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
8163
8360
|
obligationId: offers.obligationId,
|
|
8164
|
-
price: offers.
|
|
8165
|
-
}).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.
|
|
8361
|
+
price: offers.tick
|
|
8362
|
+
}).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`);
|
|
8166
8363
|
const [bestBuys, bestSells] = await Promise.all([query({ side: "buy" }), query({ side: "sell" })]);
|
|
8167
8364
|
const quotes = /* @__PURE__ */ new Map();
|
|
8168
8365
|
for (const row of bestSells) quotes.set(row.obligationId, {
|
|
@@ -8197,17 +8394,19 @@ function create$8(config) {
|
|
|
8197
8394
|
//#region src/database/domains/Offsets.ts
|
|
8198
8395
|
function create$7(db) {
|
|
8199
8396
|
return { get: async (parameters) => {
|
|
8200
|
-
const { chainId, user, contract, group } = parameters ?? {};
|
|
8397
|
+
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
8201
8398
|
const conditions = [];
|
|
8202
8399
|
if (chainId !== void 0) conditions.push(eq(offsets.chainId, chainId));
|
|
8203
8400
|
if (user !== void 0) conditions.push(eq(offsets.user, user.toLowerCase()));
|
|
8204
8401
|
if (contract !== void 0) conditions.push(eq(offsets.contract, contract.toLowerCase()));
|
|
8205
8402
|
if (group !== void 0) conditions.push(eq(offsets.group, group));
|
|
8403
|
+
if (obligationId !== void 0) conditions.push(eq(offsets.obligationId, obligationId));
|
|
8206
8404
|
return (await db.select().from(offsets).where(conditions.length > 0 ? and(...conditions) : void 0)).map((row) => ({
|
|
8207
8405
|
chainId: row.chainId,
|
|
8208
8406
|
user: row.user,
|
|
8209
8407
|
contract: row.contract,
|
|
8210
8408
|
group: row.group,
|
|
8409
|
+
obligationId: row.obligationId,
|
|
8211
8410
|
value: BigInt(row.value)
|
|
8212
8411
|
}));
|
|
8213
8412
|
} };
|
|
@@ -8357,7 +8556,8 @@ const create$5 = (db) => {
|
|
|
8357
8556
|
if (!parsed.chainId || !parsed.contract) throw new Error("Invalid cursor format");
|
|
8358
8557
|
cursor = {
|
|
8359
8558
|
chainId: parsed.chainId,
|
|
8360
|
-
contract: parsed.contract
|
|
8559
|
+
contract: parsed.contract,
|
|
8560
|
+
obligationId: parsed.obligationId ?? null
|
|
8361
8561
|
};
|
|
8362
8562
|
}
|
|
8363
8563
|
const raw = await db.execute(sql`
|
|
@@ -8366,16 +8566,18 @@ const create$5 = (db) => {
|
|
|
8366
8566
|
chain_id,
|
|
8367
8567
|
"user",
|
|
8368
8568
|
contract,
|
|
8569
|
+
obligation_id,
|
|
8369
8570
|
SUM(value::numeric) AS total_offset
|
|
8370
8571
|
FROM ${offsets}
|
|
8371
8572
|
WHERE LOWER("user") = LOWER(${user})
|
|
8372
|
-
GROUP BY chain_id, "user", contract
|
|
8573
|
+
GROUP BY chain_id, "user", contract, obligation_id
|
|
8373
8574
|
),
|
|
8374
8575
|
position_consumed AS (
|
|
8375
8576
|
SELECT
|
|
8376
8577
|
l.chain_id,
|
|
8377
8578
|
l.contract,
|
|
8378
8579
|
l."user",
|
|
8580
|
+
l.obligation_id,
|
|
8379
8581
|
SUM(
|
|
8380
8582
|
CASE
|
|
8381
8583
|
WHEN offer_agg.assets > 0
|
|
@@ -8401,50 +8603,64 @@ const create$5 = (db) => {
|
|
|
8401
8603
|
AND LOWER(offer_agg.group_maker) = LOWER(g.maker)
|
|
8402
8604
|
AND offer_agg."group_group" = g."group"
|
|
8403
8605
|
WHERE LOWER(l."user") = LOWER(${user})
|
|
8404
|
-
GROUP BY l.chain_id, l.contract, l."user"
|
|
8606
|
+
GROUP BY l.chain_id, l.contract, l."user", l.obligation_id
|
|
8405
8607
|
),
|
|
8406
8608
|
position_max_lot AS (
|
|
8407
8609
|
SELECT
|
|
8408
8610
|
chain_id,
|
|
8409
8611
|
contract,
|
|
8410
8612
|
"user",
|
|
8613
|
+
obligation_id,
|
|
8411
8614
|
MAX(upper::numeric) AS max_upper
|
|
8412
8615
|
FROM ${lots}
|
|
8413
8616
|
WHERE LOWER("user") = LOWER(${user})
|
|
8414
|
-
GROUP BY chain_id, contract, "user"
|
|
8617
|
+
GROUP BY chain_id, contract, "user", obligation_id
|
|
8618
|
+
),
|
|
8619
|
+
per_obligation AS (
|
|
8620
|
+
SELECT
|
|
8621
|
+
pml.chain_id,
|
|
8622
|
+
pml.contract,
|
|
8623
|
+
pml."user",
|
|
8624
|
+
pml.obligation_id,
|
|
8625
|
+
GREATEST(0,
|
|
8626
|
+
COALESCE(pml.max_upper, 0)
|
|
8627
|
+
- COALESCE(po.total_offset, 0)
|
|
8628
|
+
- COALESCE(pc.consumed, 0)
|
|
8629
|
+
)::text AS reserved_balance
|
|
8630
|
+
FROM position_max_lot pml
|
|
8631
|
+
LEFT JOIN position_offsets po
|
|
8632
|
+
ON po.chain_id = pml.chain_id
|
|
8633
|
+
AND LOWER(po.contract) = LOWER(pml.contract)
|
|
8634
|
+
AND LOWER(po."user") = LOWER(pml."user")
|
|
8635
|
+
AND po.obligation_id = pml.obligation_id
|
|
8636
|
+
LEFT JOIN position_consumed pc
|
|
8637
|
+
ON pc.chain_id = pml.chain_id
|
|
8638
|
+
AND LOWER(pc.contract) = LOWER(pml.contract)
|
|
8639
|
+
AND LOWER(pc."user") = LOWER(pml."user")
|
|
8640
|
+
AND pc.obligation_id = pml.obligation_id
|
|
8415
8641
|
)
|
|
8416
8642
|
SELECT
|
|
8417
8643
|
p.chain_id,
|
|
8418
8644
|
p.contract,
|
|
8419
8645
|
p."user",
|
|
8420
8646
|
p.block_number,
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
- COALESCE(po.total_offset, 0)
|
|
8424
|
-
- COALESCE(pc.consumed, 0)
|
|
8425
|
-
)::text AS reserved_balance
|
|
8647
|
+
po.obligation_id,
|
|
8648
|
+
COALESCE(po.reserved_balance, '0') AS reserved_balance
|
|
8426
8649
|
FROM ${positions} p
|
|
8427
|
-
LEFT JOIN
|
|
8650
|
+
LEFT JOIN per_obligation po
|
|
8428
8651
|
ON po.chain_id = p.chain_id
|
|
8429
8652
|
AND LOWER(po.contract) = LOWER(p.contract)
|
|
8430
8653
|
AND LOWER(po."user") = LOWER(p."user")
|
|
8431
|
-
LEFT JOIN position_consumed pc
|
|
8432
|
-
ON pc.chain_id = p.chain_id
|
|
8433
|
-
AND LOWER(pc.contract) = LOWER(p.contract)
|
|
8434
|
-
AND LOWER(pc."user") = LOWER(p."user")
|
|
8435
|
-
LEFT JOIN position_max_lot pml
|
|
8436
|
-
ON pml.chain_id = p.chain_id
|
|
8437
|
-
AND LOWER(pml.contract) = LOWER(p.contract)
|
|
8438
|
-
AND LOWER(pml."user") = LOWER(p."user")
|
|
8439
8654
|
WHERE LOWER(p."user") = LOWER(${user})
|
|
8440
8655
|
AND p."user" != ${zeroAddress}
|
|
8441
|
-
${cursor !== null ? sql`AND (p.chain_id, p.contract) > (${cursor.chainId}, ${cursor.contract})` : sql``}
|
|
8442
|
-
ORDER BY p.chain_id ASC, p.contract ASC
|
|
8656
|
+
${cursor !== null ? sql`AND (p.chain_id, p.contract, COALESCE(po.obligation_id, '')) > (${cursor.chainId}, ${cursor.contract}, ${cursor.obligationId ?? ""})` : sql``}
|
|
8657
|
+
ORDER BY p.chain_id ASC, p.contract ASC, po.obligation_id ASC NULLS FIRST
|
|
8443
8658
|
LIMIT ${limit}
|
|
8444
8659
|
`);
|
|
8445
8660
|
const nextCursor = raw.rows.length === limit ? Buffer.from(JSON.stringify({
|
|
8446
8661
|
chainId: raw.rows[raw.rows.length - 1].chain_id.toString(),
|
|
8447
|
-
contract: raw.rows[raw.rows.length - 1].contract
|
|
8662
|
+
contract: raw.rows[raw.rows.length - 1].contract,
|
|
8663
|
+
obligationId: raw.rows[raw.rows.length - 1].obligation_id
|
|
8448
8664
|
})).toString("base64url") : null;
|
|
8449
8665
|
return {
|
|
8450
8666
|
positions: raw.rows.map((row) => ({
|
|
@@ -8452,6 +8668,7 @@ const create$5 = (db) => {
|
|
|
8452
8668
|
contract: row.contract,
|
|
8453
8669
|
user: row.user,
|
|
8454
8670
|
blockNumber: row.block_number,
|
|
8671
|
+
obligationId: row.obligation_id,
|
|
8455
8672
|
reserved: BigInt(row.reserved_balance.split(".")[0] ?? "0")
|
|
8456
8673
|
})),
|
|
8457
8674
|
nextCursor
|
|
@@ -8826,6 +9043,7 @@ function augmentWithDomains(base, chainRegistry) {
|
|
|
8826
9043
|
return wrapped;
|
|
8827
9044
|
}
|
|
8828
9045
|
const InMemoryDbMap = /* @__PURE__ */ new Map();
|
|
9046
|
+
const LEGACY_SCHEMA_START_MINOR = 7;
|
|
8829
9047
|
/**
|
|
8830
9048
|
* Connect to the database.
|
|
8831
9049
|
* @notice If no connection string is provided, an in-process PGLite database is created.
|
|
@@ -8880,9 +9098,26 @@ function applyMigrations(kind, driver) {
|
|
|
8880
9098
|
async function preMigrate(driver) {
|
|
8881
9099
|
const tracer = getTracer("db.preMigrate");
|
|
8882
9100
|
await startActiveSpan(tracer, "db.preMigrate", async () => {
|
|
8883
|
-
|
|
9101
|
+
const schemaNames = getSchemaNamesForMigration(VERSION);
|
|
9102
|
+
for (const schemaName of schemaNames) await driver.execute(`create schema if not exists "${schemaName}"`);
|
|
8884
9103
|
});
|
|
8885
9104
|
}
|
|
9105
|
+
/**
|
|
9106
|
+
* Build the list of router schemas that should exist before running migrations.
|
|
9107
|
+
* @param version - Current schema version (e.g. `router_v1.8`).
|
|
9108
|
+
* @returns Ordered schema names from `router_v1.7` to current, or just current if parsing fails.
|
|
9109
|
+
*/
|
|
9110
|
+
function getSchemaNamesForMigration(version) {
|
|
9111
|
+
const parsed = /^router_v(?<major>\d+)\.(?<minor>\d+)$/.exec(version);
|
|
9112
|
+
if (!parsed?.groups?.major || !parsed.groups.minor) return [version];
|
|
9113
|
+
const major = Number.parseInt(parsed.groups.major, 10);
|
|
9114
|
+
const currentMinor = Number.parseInt(parsed.groups.minor, 10);
|
|
9115
|
+
if (!Number.isInteger(major) || !Number.isInteger(currentMinor)) return [version];
|
|
9116
|
+
if (currentMinor < LEGACY_SCHEMA_START_MINOR) return [version];
|
|
9117
|
+
const schemaNames = [];
|
|
9118
|
+
for (let minor = LEGACY_SCHEMA_START_MINOR; minor <= currentMinor; minor += 1) schemaNames.push(`router_v${major}.${minor}`);
|
|
9119
|
+
return schemaNames;
|
|
9120
|
+
}
|
|
8886
9121
|
async function postMigrate(driver) {
|
|
8887
9122
|
const tracer = getTracer("db.postMigrate");
|
|
8888
9123
|
await startActiveSpan(tracer, "db.postMigrate", async () => {
|
|
@@ -9152,15 +9387,16 @@ async function postMigrate(driver) {
|
|
|
9152
9387
|
RETURNS trigger
|
|
9153
9388
|
LANGUAGE plpgsql AS $$
|
|
9154
9389
|
BEGIN
|
|
9155
|
-
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", value)
|
|
9390
|
+
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", obligation_id, value)
|
|
9156
9391
|
VALUES (
|
|
9157
9392
|
OLD.chain_id,
|
|
9158
9393
|
OLD."user",
|
|
9159
9394
|
OLD.contract,
|
|
9160
9395
|
OLD."group",
|
|
9396
|
+
OLD.obligation_id,
|
|
9161
9397
|
OLD.upper::numeric - OLD.lower::numeric
|
|
9162
9398
|
)
|
|
9163
|
-
ON CONFLICT (chain_id, "user", contract, "group") DO NOTHING;
|
|
9399
|
+
ON CONFLICT (chain_id, "user", contract, "group", obligation_id) DO NOTHING;
|
|
9164
9400
|
RETURN OLD;
|
|
9165
9401
|
END;
|
|
9166
9402
|
$$;
|
|
@@ -9542,12 +9778,34 @@ async function getBook(params, db) {
|
|
|
9542
9778
|
if (!result.success) return failure(result.error);
|
|
9543
9779
|
const query = result.data;
|
|
9544
9780
|
try {
|
|
9781
|
+
logger.debug({
|
|
9782
|
+
service: "api_controller",
|
|
9783
|
+
endpoint: "get_book",
|
|
9784
|
+
msg: "Loading book levels",
|
|
9785
|
+
obligation_id: query.obligation_id,
|
|
9786
|
+
side: query.side,
|
|
9787
|
+
limit: query.limit ?? null,
|
|
9788
|
+
has_cursor: query.cursor != null
|
|
9789
|
+
});
|
|
9545
9790
|
const { levels, nextCursor } = await db.book.get({
|
|
9546
9791
|
side: query.side,
|
|
9547
9792
|
obligationId: query.obligation_id,
|
|
9548
9793
|
cursor: query.cursor,
|
|
9549
9794
|
limit: query.limit
|
|
9550
9795
|
});
|
|
9796
|
+
const firstLevel = levels[0];
|
|
9797
|
+
logger.debug({
|
|
9798
|
+
service: "api_controller",
|
|
9799
|
+
endpoint: "get_book",
|
|
9800
|
+
msg: "Loaded book levels",
|
|
9801
|
+
obligation_id: query.obligation_id,
|
|
9802
|
+
side: query.side,
|
|
9803
|
+
levels_count: levels.length,
|
|
9804
|
+
has_next_cursor: nextCursor != null,
|
|
9805
|
+
first_level_tick: firstLevel?.tick ?? null,
|
|
9806
|
+
first_level_assets: firstLevel?.assets.toString() ?? null,
|
|
9807
|
+
first_level_count: firstLevel?.count ?? null
|
|
9808
|
+
});
|
|
9551
9809
|
return success({
|
|
9552
9810
|
data: levels.map(from$6),
|
|
9553
9811
|
cursor: nextCursor
|
|
@@ -10049,16 +10307,57 @@ async function getOffersQuery(db, parameters) {
|
|
|
10049
10307
|
'[]'::jsonb
|
|
10050
10308
|
)`.as("collaterals") }).from(obligationCollateralsV2).innerJoin(oracles, sql`${obligationCollateralsV2.oracleChainId} = ${oracles.chainId}
|
|
10051
10309
|
AND ${obligationCollateralsV2.oracleAddress} = ${oracles.address}`).where(eq(obligationCollateralsV2.obligationId, offers.obligationId)).as("collaterals_lateral");
|
|
10052
|
-
const
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
|
|
10310
|
+
const lotBalanceExpr = sql`GREATEST(0, LEAST(
|
|
10311
|
+
COALESCE(${positions.balance}, 0)::numeric
|
|
10312
|
+
+ COALESCE((
|
|
10313
|
+
SELECT SUM(${offsets.value}::numeric)
|
|
10314
|
+
FROM ${offsets}
|
|
10315
|
+
WHERE ${offsets.chainId} = ${callbacks.positionChainId}
|
|
10316
|
+
AND LOWER(${offsets.contract}) = LOWER(${callbacks.positionContract})
|
|
10317
|
+
AND LOWER(${offsets.user}) = LOWER(${callbacks.positionUser})
|
|
10318
|
+
), 0)
|
|
10319
|
+
- COALESCE(${lots.lower}::numeric, 0),
|
|
10320
|
+
(COALESCE(${lots.upper}::numeric, 0) - COALESCE(${lots.lower}::numeric, 0))
|
|
10321
|
+
- CASE
|
|
10322
|
+
WHEN ${offers.assets}::numeric > 0
|
|
10323
|
+
THEN COALESCE(${groups.consumed}::numeric, 0)
|
|
10324
|
+
* (COALESCE(${lots.upper}::numeric, 0) - COALESCE(${lots.lower}::numeric, 0))
|
|
10325
|
+
/ ${offers.assets}::numeric
|
|
10326
|
+
ELSE 0
|
|
10327
|
+
END
|
|
10328
|
+
))`;
|
|
10329
|
+
const contributionExpr = sql`CASE
|
|
10330
|
+
WHEN ${positions.asset} IS NULL OR ${lots.lower} IS NULL THEN 0
|
|
10331
|
+
ELSE LEAST(COALESCE(${callbacks.amount}::numeric, ${lotBalanceExpr}), ${lotBalanceExpr})
|
|
10332
|
+
END`;
|
|
10333
|
+
const availableExpr = sql`COALESCE((
|
|
10334
|
+
SELECT SUM(deduped.contribution)
|
|
10335
|
+
FROM (
|
|
10336
|
+
SELECT DISTINCT ON (
|
|
10337
|
+
${callbacks.positionChainId},
|
|
10338
|
+
LOWER(${callbacks.positionContract}),
|
|
10339
|
+
LOWER(${callbacks.positionUser})
|
|
10340
|
+
)
|
|
10341
|
+
${contributionExpr} AS contribution
|
|
10342
|
+
FROM ${offersCallbacks}
|
|
10343
|
+
INNER JOIN ${callbacks} ON ${offersCallbacks.callbackId} = ${callbacks.id}
|
|
10344
|
+
LEFT JOIN ${positions}
|
|
10345
|
+
ON ${positions.chainId} = ${callbacks.positionChainId}
|
|
10346
|
+
AND LOWER(${positions.contract}) = LOWER(${callbacks.positionContract})
|
|
10347
|
+
AND LOWER(${positions.user}) = LOWER(${callbacks.positionUser})
|
|
10348
|
+
LEFT JOIN ${lots}
|
|
10349
|
+
ON ${lots.chainId} = ${callbacks.positionChainId}
|
|
10350
|
+
AND LOWER(${lots.contract}) = LOWER(${callbacks.positionContract})
|
|
10351
|
+
AND LOWER(${lots.user}) = LOWER(${callbacks.positionUser})
|
|
10352
|
+
AND LOWER(${lots.group}) = LOWER(${offers.group})
|
|
10353
|
+
WHERE ${offersCallbacks.offerHash} = ${offers.hash}
|
|
10354
|
+
ORDER BY
|
|
10355
|
+
${callbacks.positionChainId},
|
|
10356
|
+
LOWER(${callbacks.positionContract}),
|
|
10357
|
+
LOWER(${callbacks.positionUser}),
|
|
10358
|
+
${contributionExpr} DESC
|
|
10359
|
+
) deduped
|
|
10360
|
+
), 0)`;
|
|
10062
10361
|
const rows = (await db.select({
|
|
10063
10362
|
hash: offers.hash,
|
|
10064
10363
|
maker: offers.groupMaker,
|
|
@@ -10066,7 +10365,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
10066
10365
|
obligationUnits: offers.obligationUnits,
|
|
10067
10366
|
obligationShares: offers.obligationShares,
|
|
10068
10367
|
consumed: groups.consumed,
|
|
10069
|
-
|
|
10368
|
+
tick: offers.tick,
|
|
10070
10369
|
maturity: offers.maturity,
|
|
10071
10370
|
expiry: offers.expiry,
|
|
10072
10371
|
start: offers.start,
|
|
@@ -10079,22 +10378,22 @@ async function getOffersQuery(db, parameters) {
|
|
|
10079
10378
|
callbackData: offers.callbackData,
|
|
10080
10379
|
collaterals: collateralsLateral.collaterals,
|
|
10081
10380
|
blockNumber: offers.blockNumber,
|
|
10082
|
-
available: sql
|
|
10381
|
+
available: sql`${availableExpr}::numeric`.as("available"),
|
|
10083
10382
|
takeable: sql`FLOOR(GREATEST(0,
|
|
10084
10383
|
CASE WHEN ${offers.buy} = false
|
|
10085
10384
|
THEN ${offers.assets}::numeric - ${groups.consumed}::numeric
|
|
10086
10385
|
ELSE LEAST(
|
|
10087
10386
|
${offers.assets}::numeric - ${groups.consumed}::numeric,
|
|
10088
|
-
|
|
10387
|
+
${availableExpr}::numeric
|
|
10089
10388
|
)
|
|
10090
10389
|
END
|
|
10091
10390
|
))`.as("takeable")
|
|
10092
|
-
}).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`).
|
|
10391
|
+
}).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,
|
|
10093
10392
|
CASE WHEN ${offers.buy} = false
|
|
10094
10393
|
THEN ${offers.assets}::numeric - ${groups.consumed}::numeric
|
|
10095
10394
|
ELSE LEAST(
|
|
10096
10395
|
${offers.assets}::numeric - ${groups.consumed}::numeric,
|
|
10097
|
-
|
|
10396
|
+
${availableExpr}::numeric
|
|
10098
10397
|
)
|
|
10099
10398
|
END
|
|
10100
10399
|
) > 0` : void 0)).orderBy(asc(offers.hash)).limit(limit)).map((row) => {
|
|
@@ -10104,7 +10403,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
10104
10403
|
assets: BigInt(row.assets),
|
|
10105
10404
|
obligationUnits: BigInt(row.obligationUnits),
|
|
10106
10405
|
obligationShares: BigInt(row.obligationShares),
|
|
10107
|
-
|
|
10406
|
+
tick: row.tick,
|
|
10108
10407
|
maturity: from$16(row.maturity),
|
|
10109
10408
|
expiry: row.expiry,
|
|
10110
10409
|
start: row.start,
|
|
@@ -10761,6 +11060,7 @@ function buildOfferAssociationsFromOffers(parameters) {
|
|
|
10761
11060
|
positionContract: loanToken,
|
|
10762
11061
|
positionUser: offer.maker,
|
|
10763
11062
|
group: offer.group,
|
|
11063
|
+
obligationId: obligationId(offer),
|
|
10764
11064
|
size: offer.assets
|
|
10765
11065
|
});
|
|
10766
11066
|
}
|