@morpho-dev/router 0.9.0 → 0.10.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 +1896 -784
- package/dist/drizzle/migrations/0027_debt-to-transfers.sql +239 -0
- package/dist/drizzle/migrations/0028_obligation_id_and_keys.sql +247 -0
- package/dist/drizzle/migrations/0029_collateral-positions.sql +248 -0
- package/dist/drizzle/migrations/0030_remove_chain_id_from_offer.sql +37 -0
- package/dist/drizzle/migrations/meta/0027_snapshot.json +1581 -0
- package/dist/drizzle/migrations/meta/0028_snapshot.json +1632 -0
- package/dist/drizzle/migrations/meta/0029_snapshot.json +1619 -0
- package/dist/drizzle/migrations/meta/0030_snapshot.json +1652 -0
- package/dist/drizzle/migrations/meta/_journal.json +28 -0
- package/dist/index.browser.d.mts +464 -279
- package/dist/index.browser.d.mts.map +1 -1
- package/dist/index.browser.d.ts +460 -275
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +3965 -3845
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +3964 -3850
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.mts +920 -409
- package/dist/index.node.d.mts.map +1 -1
- package/dist/index.node.d.ts +920 -409
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +1952 -1019
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +1949 -1022
- package/dist/index.node.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.node.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-Bo1DHCg-.mjs";
|
|
2
2
|
import { getBlock, getBlockNumber, getLogs, multicall } from "viem/actions";
|
|
3
3
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
-
import { bytesToHex, decodeAbiParameters, encodeAbiParameters, erc20Abi, getAddress, hashTypedData, hexToBytes, isAddress, isHex, keccak256, maxUint256, numberToHex, pad, parseAbi, parseEventLogs, publicActions, recoverAddress, stringify, zeroAddress } from "viem";
|
|
4
|
+
import { bytesToHex, concatHex, decodeAbiParameters, encodeAbiParameters, erc20Abi, getAddress, hashTypedData, hexToBytes, isAddress, isHex, keccak256, maxUint256, numberToHex, pad, parseAbi, parseEventLogs, publicActions, recoverAddress, stringify, zeroAddress } from "viem";
|
|
5
5
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
6
6
|
import "@opentelemetry/exporter-trace-otlp-proto";
|
|
7
7
|
import "@opentelemetry/id-generator-aws-xray";
|
|
@@ -12,7 +12,7 @@ import "@opentelemetry/propagator-aws-xray";
|
|
|
12
12
|
import "@opentelemetry/resources";
|
|
13
13
|
import "@opentelemetry/sdk-trace-node";
|
|
14
14
|
import "@opentelemetry/semantic-conventions";
|
|
15
|
-
import { and, asc, desc, eq, gt, gte, inArray, lte, ne, sql } from "drizzle-orm";
|
|
15
|
+
import { and, asc, desc, eq, gt, gte, inArray, lte, ne, or, sql } from "drizzle-orm";
|
|
16
16
|
import { anvil, base, mainnet } from "viem/chains";
|
|
17
17
|
import * as z$1 from "zod";
|
|
18
18
|
import { StandardMerkleTree } from "@openzeppelin/merkle-tree";
|
|
@@ -802,7 +802,7 @@ const reconcile = async (parameters) => {
|
|
|
802
802
|
//#region src/indexer/collectors/Collector.ts
|
|
803
803
|
const names = [
|
|
804
804
|
"offers",
|
|
805
|
-
"
|
|
805
|
+
"morpho_v2",
|
|
806
806
|
"positions",
|
|
807
807
|
"prices"
|
|
808
808
|
];
|
|
@@ -1179,7 +1179,7 @@ var Chain_exports = /* @__PURE__ */ __exportAll({
|
|
|
1179
1179
|
MissingBlockNumberError: () => MissingBlockNumberError,
|
|
1180
1180
|
chainIds: () => chainIds,
|
|
1181
1181
|
chainNames: () => chainNames,
|
|
1182
|
-
chains: () => chains$
|
|
1182
|
+
chains: () => chains$1,
|
|
1183
1183
|
getChain: () => getChain,
|
|
1184
1184
|
getWhitelistedChains: () => getWhitelistedChains,
|
|
1185
1185
|
streamLogs: () => streamLogs
|
|
@@ -1196,17 +1196,17 @@ const chainNameLookup = new Map(Object.entries(ChainId).map(([key, value]) => [v
|
|
|
1196
1196
|
function getChain(chainId) {
|
|
1197
1197
|
const chainName = chainNameLookup.get(chainId);
|
|
1198
1198
|
if (!chainName) return void 0;
|
|
1199
|
-
return chains$
|
|
1199
|
+
return chains$1[chainName];
|
|
1200
1200
|
}
|
|
1201
1201
|
const getWhitelistedChains = () => {
|
|
1202
1202
|
return [
|
|
1203
|
-
chains$
|
|
1204
|
-
chains$
|
|
1205
|
-
chains$
|
|
1206
|
-
chains$
|
|
1203
|
+
chains$1.ethereum,
|
|
1204
|
+
chains$1.base,
|
|
1205
|
+
chains$1["ethereum-virtual-testnet"],
|
|
1206
|
+
chains$1.anvil
|
|
1207
1207
|
];
|
|
1208
1208
|
};
|
|
1209
|
-
const chains$
|
|
1209
|
+
const chains$1 = {
|
|
1210
1210
|
ethereum: {
|
|
1211
1211
|
...mainnet,
|
|
1212
1212
|
id: ChainId.ETHEREUM,
|
|
@@ -1243,16 +1243,16 @@ const chains$2 = {
|
|
|
1243
1243
|
name: "base",
|
|
1244
1244
|
custom: {
|
|
1245
1245
|
morpho: {
|
|
1246
|
-
address: "
|
|
1247
|
-
blockCreated:
|
|
1246
|
+
address: "0x3F067BC9D8898F6ec02D6480c3fF1026E512BcBF",
|
|
1247
|
+
blockCreated: 41799989
|
|
1248
1248
|
},
|
|
1249
1249
|
morphoBlue: {
|
|
1250
1250
|
address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
1251
1251
|
blockCreated: 0
|
|
1252
1252
|
},
|
|
1253
1253
|
mempool: {
|
|
1254
|
-
address: "
|
|
1255
|
-
blockCreated:
|
|
1254
|
+
address: "0xd25c7512EA5035bef4F18c708C0862E1B6151765",
|
|
1255
|
+
blockCreated: 41800226
|
|
1256
1256
|
},
|
|
1257
1257
|
vaults: { factories: {
|
|
1258
1258
|
v1_0: {
|
|
@@ -1576,9 +1576,24 @@ const LLTVSchema = z$1.bigint({ coerce: true }).refine((lltv) => {
|
|
|
1576
1576
|
var Collateral_exports = /* @__PURE__ */ __exportAll({
|
|
1577
1577
|
CollateralSchema: () => CollateralSchema,
|
|
1578
1578
|
CollateralsSchema: () => CollateralsSchema,
|
|
1579
|
+
abi: () => abi$1,
|
|
1579
1580
|
from: () => from$17,
|
|
1580
1581
|
random: () => random$3
|
|
1581
1582
|
});
|
|
1583
|
+
const abi$1 = [
|
|
1584
|
+
{
|
|
1585
|
+
type: "address",
|
|
1586
|
+
name: "token"
|
|
1587
|
+
},
|
|
1588
|
+
{
|
|
1589
|
+
type: "uint256",
|
|
1590
|
+
name: "lltv"
|
|
1591
|
+
},
|
|
1592
|
+
{
|
|
1593
|
+
type: "address",
|
|
1594
|
+
name: "oracle"
|
|
1595
|
+
}
|
|
1596
|
+
];
|
|
1582
1597
|
const CollateralSchema = z$1.object({
|
|
1583
1598
|
asset: z$1.string().transform(transformAddress),
|
|
1584
1599
|
oracle: z$1.string().transform(transformAddress),
|
|
@@ -1683,80 +1698,6 @@ var DenominatorIsZeroError = class extends BaseError {
|
|
|
1683
1698
|
}
|
|
1684
1699
|
};
|
|
1685
1700
|
|
|
1686
|
-
//#endregion
|
|
1687
|
-
//#region src/core/Liquidity.ts
|
|
1688
|
-
var Liquidity_exports = /* @__PURE__ */ __exportAll({
|
|
1689
|
-
calculateMaxDebt: () => calculateMaxDebt,
|
|
1690
|
-
generateAllowancePoolId: () => generateAllowancePoolId,
|
|
1691
|
-
generateBalancePoolId: () => generateBalancePoolId,
|
|
1692
|
-
generateDebtPoolId: () => generateDebtPoolId,
|
|
1693
|
-
generateMarketLiquidityPoolId: () => generateMarketLiquidityPoolId,
|
|
1694
|
-
generateObligationCollateralPoolId: () => generateObligationCollateralPoolId,
|
|
1695
|
-
generateUserVaultPositionPoolId: () => generateUserVaultPositionPoolId,
|
|
1696
|
-
generateVaultPositionPoolId: () => generateVaultPositionPoolId
|
|
1697
|
-
});
|
|
1698
|
-
/**
|
|
1699
|
-
* Calculate maximum debt capacity from collateral amount.
|
|
1700
|
-
* @param amount - Collateral amount
|
|
1701
|
-
* @param oraclePrice - Oracle price (scaled to 36 decimals)
|
|
1702
|
-
* @param lltv - Loan-to-value ratio (scaled to 18 decimals)
|
|
1703
|
-
* @returns Maximum debt capacity
|
|
1704
|
-
*/
|
|
1705
|
-
function calculateMaxDebt(amount, oraclePrice, lltv) {
|
|
1706
|
-
return amount * oraclePrice / 10n ** 36n * lltv / 10n ** 18n;
|
|
1707
|
-
}
|
|
1708
|
-
/**
|
|
1709
|
-
* Generate pool ID for balance pools.
|
|
1710
|
-
*/
|
|
1711
|
-
function generateBalancePoolId(parameters) {
|
|
1712
|
-
const { user, chainId, token } = parameters;
|
|
1713
|
-
return `${user}-${chainId.toString()}-${token}-balance`.toLowerCase();
|
|
1714
|
-
}
|
|
1715
|
-
/**
|
|
1716
|
-
* Generate pool ID for allowance pools.
|
|
1717
|
-
*/
|
|
1718
|
-
function generateAllowancePoolId(parameters) {
|
|
1719
|
-
const { user, chainId, token } = parameters;
|
|
1720
|
-
return `${user}-${chainId.toString()}-${token}-allowance`.toLowerCase();
|
|
1721
|
-
}
|
|
1722
|
-
/**
|
|
1723
|
-
* Generate pool ID for obligation collateral pools.
|
|
1724
|
-
* Obligation collateral pools represent collateral already deposited in the obligation.
|
|
1725
|
-
* These pools are shared across all offers with the same obligation.
|
|
1726
|
-
*/
|
|
1727
|
-
function generateObligationCollateralPoolId(parameters) {
|
|
1728
|
-
const { user, chainId, obligationId, token } = parameters;
|
|
1729
|
-
return `${user}-${chainId.toString()}-${obligationId}-${token}-obligation-collateral`.toLowerCase();
|
|
1730
|
-
}
|
|
1731
|
-
/**
|
|
1732
|
-
* Generate pool ID for debt pools.
|
|
1733
|
-
*/
|
|
1734
|
-
function generateDebtPoolId(parameters) {
|
|
1735
|
-
const { user, chainId, obligationId } = parameters;
|
|
1736
|
-
return `${user}-${chainId.toString()}-${obligationId}-debt`.toLowerCase();
|
|
1737
|
-
}
|
|
1738
|
-
/**
|
|
1739
|
-
* Generate pool ID for user position in a vault.
|
|
1740
|
-
*/
|
|
1741
|
-
function generateUserVaultPositionPoolId(parameters) {
|
|
1742
|
-
const { user, chainId, vault } = parameters;
|
|
1743
|
-
return `${user}-${chainId.toString()}-${vault}-user-vault-position`.toLowerCase();
|
|
1744
|
-
}
|
|
1745
|
-
/**
|
|
1746
|
-
* Generate pool ID for vault position in a market.
|
|
1747
|
-
*/
|
|
1748
|
-
function generateVaultPositionPoolId(parameters) {
|
|
1749
|
-
const { vault, chainId, marketId } = parameters;
|
|
1750
|
-
return `${vault}-${chainId.toString()}-${marketId}-vault-position`.toLowerCase();
|
|
1751
|
-
}
|
|
1752
|
-
/**
|
|
1753
|
-
* Generate pool ID for market total liquidity.
|
|
1754
|
-
*/
|
|
1755
|
-
function generateMarketLiquidityPoolId(parameters) {
|
|
1756
|
-
const { chainId, marketId } = parameters;
|
|
1757
|
-
return `${chainId.toString()}-${marketId}-market-liquidity`.toLowerCase();
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
1701
|
//#endregion
|
|
1761
1702
|
//#region src/core/Maturity.ts
|
|
1762
1703
|
var Maturity_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1889,18 +1830,38 @@ var Obligation_exports = /* @__PURE__ */ __exportAll({
|
|
|
1889
1830
|
CollateralsAreNotSortedError: () => CollateralsAreNotSortedError,
|
|
1890
1831
|
InvalidObligationError: () => InvalidObligationError,
|
|
1891
1832
|
ObligationSchema: () => ObligationSchema,
|
|
1833
|
+
abi: () => abi,
|
|
1892
1834
|
from: () => from$15,
|
|
1893
1835
|
fromOffer: () => fromOffer$1,
|
|
1894
1836
|
fromSnakeCase: () => fromSnakeCase$2,
|
|
1895
|
-
|
|
1896
|
-
random: () => random$2
|
|
1837
|
+
key: () => key,
|
|
1838
|
+
random: () => random$2,
|
|
1839
|
+
tupleAbi: () => tupleAbi
|
|
1897
1840
|
});
|
|
1898
1841
|
const ObligationSchema = z$1.object({
|
|
1899
|
-
chainId: z$1.number().min(0).max(Number.MAX_SAFE_INTEGER),
|
|
1900
1842
|
loanToken: z$1.string().transform(transformAddress),
|
|
1901
1843
|
collaterals: CollateralsSchema,
|
|
1902
1844
|
maturity: MaturitySchema
|
|
1903
1845
|
});
|
|
1846
|
+
const abi = [
|
|
1847
|
+
{
|
|
1848
|
+
type: "address",
|
|
1849
|
+
name: "loanToken"
|
|
1850
|
+
},
|
|
1851
|
+
{
|
|
1852
|
+
type: "tuple[]",
|
|
1853
|
+
name: "collaterals",
|
|
1854
|
+
components: abi$1
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
type: "uint256",
|
|
1858
|
+
name: "maturity"
|
|
1859
|
+
}
|
|
1860
|
+
];
|
|
1861
|
+
const tupleAbi = [{
|
|
1862
|
+
type: "tuple",
|
|
1863
|
+
components: abi
|
|
1864
|
+
}];
|
|
1904
1865
|
/**
|
|
1905
1866
|
* Creates an obligation from the given parameters.
|
|
1906
1867
|
* @constructor
|
|
@@ -1911,7 +1872,6 @@ const ObligationSchema = z$1.object({
|
|
|
1911
1872
|
* @example
|
|
1912
1873
|
* ```ts
|
|
1913
1874
|
* const obligation = Obligation.from({
|
|
1914
|
-
* chainId: 1,
|
|
1915
1875
|
* loanToken: privateKeyToAccount(generatePrivateKey()).address,
|
|
1916
1876
|
* collaterals: [
|
|
1917
1877
|
* Collateral.from({
|
|
@@ -1931,7 +1891,6 @@ function from$15(parameters) {
|
|
|
1931
1891
|
maturity: from$16(parameters.maturity)
|
|
1932
1892
|
});
|
|
1933
1893
|
return {
|
|
1934
|
-
chainId: parsedObligation.chainId,
|
|
1935
1894
|
loanToken: parsedObligation.loanToken.toLowerCase(),
|
|
1936
1895
|
collaterals: parsedObligation.collaterals.sort((a, b) => a.asset.localeCompare(b.asset)),
|
|
1937
1896
|
maturity: parsedObligation.maturity
|
|
@@ -1950,49 +1909,27 @@ function fromSnakeCase$2(input) {
|
|
|
1950
1909
|
return from$15(fromSnakeCase$3(input));
|
|
1951
1910
|
}
|
|
1952
1911
|
/**
|
|
1953
|
-
* Calculates
|
|
1954
|
-
* The
|
|
1912
|
+
* Calculates a canonical key for an obligation payload.
|
|
1913
|
+
* The key is computed as keccak256(abi.encode(loanToken, collaterals, maturity)).
|
|
1955
1914
|
* @throws If the collaterals are not sorted alphabetically by address. {@link CollateralsAreNotSortedError}
|
|
1956
|
-
* @param parameters - {@link
|
|
1957
|
-
* @returns The obligation
|
|
1915
|
+
* @param parameters - {@link key.Parameters}
|
|
1916
|
+
* @returns The obligation key as a 32-byte hex string. {@link key.ReturnType}
|
|
1958
1917
|
*
|
|
1959
1918
|
* @example
|
|
1960
1919
|
* ```ts
|
|
1961
1920
|
* const obligation = Obligation.random();
|
|
1962
|
-
* const
|
|
1963
|
-
* console.log(
|
|
1921
|
+
* const key = Obligation.key(obligation);
|
|
1922
|
+
* console.log(key); // 0x1234567890123456789012345678901234567890123456789012345678901234
|
|
1964
1923
|
* ```
|
|
1965
1924
|
*/
|
|
1966
|
-
function
|
|
1925
|
+
function key(parameters) {
|
|
1967
1926
|
let lastAsset = "";
|
|
1968
1927
|
for (const collateral of parameters.collaterals) {
|
|
1969
1928
|
const newAsset = collateral.asset.toLowerCase();
|
|
1970
1929
|
if (newAsset.localeCompare(lastAsset) < 0) throw new CollateralsAreNotSortedError();
|
|
1971
1930
|
lastAsset = newAsset;
|
|
1972
1931
|
}
|
|
1973
|
-
return keccak256(encodeAbiParameters([
|
|
1974
|
-
{ type: "uint256" },
|
|
1975
|
-
{ type: "address" },
|
|
1976
|
-
{
|
|
1977
|
-
type: "tuple[]",
|
|
1978
|
-
components: [
|
|
1979
|
-
{
|
|
1980
|
-
type: "address",
|
|
1981
|
-
name: "token"
|
|
1982
|
-
},
|
|
1983
|
-
{
|
|
1984
|
-
type: "uint256",
|
|
1985
|
-
name: "lltv"
|
|
1986
|
-
},
|
|
1987
|
-
{
|
|
1988
|
-
type: "address",
|
|
1989
|
-
name: "oracle"
|
|
1990
|
-
}
|
|
1991
|
-
]
|
|
1992
|
-
},
|
|
1993
|
-
{ type: "uint256" }
|
|
1994
|
-
], [
|
|
1995
|
-
BigInt(parameters.chainId),
|
|
1932
|
+
return keccak256(encodeAbiParameters(abi, [
|
|
1996
1933
|
parameters.loanToken.toLowerCase(),
|
|
1997
1934
|
parameters.collaterals.map((c) => ({
|
|
1998
1935
|
token: c.asset.toLowerCase(),
|
|
@@ -2013,7 +1950,6 @@ function id(parameters) {
|
|
|
2013
1950
|
*/
|
|
2014
1951
|
function random$2() {
|
|
2015
1952
|
return from$15({
|
|
2016
|
-
chainId: 1,
|
|
2017
1953
|
loanToken: address(),
|
|
2018
1954
|
collaterals: [random$3()],
|
|
2019
1955
|
maturity: from$16("end_of_next_quarter")
|
|
@@ -2028,7 +1964,6 @@ function random$2() {
|
|
|
2028
1964
|
*/
|
|
2029
1965
|
function fromOffer$1(offer) {
|
|
2030
1966
|
return from$15({
|
|
2031
|
-
chainId: offer.chainId,
|
|
2032
1967
|
loanToken: offer.loanToken,
|
|
2033
1968
|
collaterals: offer.collaterals,
|
|
2034
1969
|
maturity: offer.maturity
|
|
@@ -2047,6 +1982,121 @@ var CollateralsAreNotSortedError = class extends BaseError {
|
|
|
2047
1982
|
}
|
|
2048
1983
|
};
|
|
2049
1984
|
|
|
1985
|
+
//#endregion
|
|
1986
|
+
//#region src/core/Id.ts
|
|
1987
|
+
var Id_exports = /* @__PURE__ */ __exportAll({
|
|
1988
|
+
creationCode: () => creationCode,
|
|
1989
|
+
toId: () => toId
|
|
1990
|
+
});
|
|
1991
|
+
const CREATION_CODE_PREFIX = "0x603f380380603f5f395ff3";
|
|
1992
|
+
/**
|
|
1993
|
+
* Builds the same creation code as `IdLib.creationCode` in Solidity.
|
|
1994
|
+
*
|
|
1995
|
+
* Layout: `prefix (11 bytes) + chainId (32 bytes) + morphoV2 (20 bytes) + abi.encode(obligation)`.
|
|
1996
|
+
*
|
|
1997
|
+
* @param parameters - {@link creationCode.Parameters}
|
|
1998
|
+
* @returns The CREATE2 init code bytes. {@link creationCode.ReturnType}
|
|
1999
|
+
*/
|
|
2000
|
+
function creationCode(parameters) {
|
|
2001
|
+
const encodedObligation = encodeAbiParameters(tupleAbi, [{
|
|
2002
|
+
loanToken: parameters.obligation.loanToken.toLowerCase(),
|
|
2003
|
+
collaterals: parameters.obligation.collaterals.map((collateral) => ({
|
|
2004
|
+
token: collateral.asset.toLowerCase(),
|
|
2005
|
+
lltv: collateral.lltv,
|
|
2006
|
+
oracle: collateral.oracle.toLowerCase()
|
|
2007
|
+
})),
|
|
2008
|
+
maturity: BigInt(parameters.obligation.maturity)
|
|
2009
|
+
}]);
|
|
2010
|
+
return concatHex([
|
|
2011
|
+
CREATION_CODE_PREFIX,
|
|
2012
|
+
numberToHex(BigInt(parameters.chainId), { size: 32 }),
|
|
2013
|
+
parameters.morphoV2.toLowerCase(),
|
|
2014
|
+
encodedObligation
|
|
2015
|
+
]);
|
|
2016
|
+
}
|
|
2017
|
+
/**
|
|
2018
|
+
* Computes the same id as `IdLib.toId` in Solidity.
|
|
2019
|
+
* @param parameters - {@link toId.Parameters}
|
|
2020
|
+
* @returns The obligation id. {@link toId.ReturnType}
|
|
2021
|
+
*/
|
|
2022
|
+
function toId(parameters) {
|
|
2023
|
+
return keccak256(creationCode(parameters));
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
//#endregion
|
|
2027
|
+
//#region src/core/Liquidity.ts
|
|
2028
|
+
var Liquidity_exports = /* @__PURE__ */ __exportAll({
|
|
2029
|
+
calculateMaxDebt: () => calculateMaxDebt,
|
|
2030
|
+
generateAllowancePoolId: () => generateAllowancePoolId,
|
|
2031
|
+
generateBalancePoolId: () => generateBalancePoolId,
|
|
2032
|
+
generateDebtPoolId: () => generateDebtPoolId,
|
|
2033
|
+
generateMarketLiquidityPoolId: () => generateMarketLiquidityPoolId,
|
|
2034
|
+
generateObligationCollateralPoolId: () => generateObligationCollateralPoolId,
|
|
2035
|
+
generateUserVaultPositionPoolId: () => generateUserVaultPositionPoolId,
|
|
2036
|
+
generateVaultPositionPoolId: () => generateVaultPositionPoolId
|
|
2037
|
+
});
|
|
2038
|
+
/**
|
|
2039
|
+
* Calculate maximum debt capacity from collateral amount.
|
|
2040
|
+
* @param amount - Collateral amount
|
|
2041
|
+
* @param oraclePrice - Oracle price (scaled to 36 decimals)
|
|
2042
|
+
* @param lltv - Loan-to-value ratio (scaled to 18 decimals)
|
|
2043
|
+
* @returns Maximum debt capacity
|
|
2044
|
+
*/
|
|
2045
|
+
function calculateMaxDebt(amount, oraclePrice, lltv) {
|
|
2046
|
+
return amount * oraclePrice / 10n ** 36n * lltv / 10n ** 18n;
|
|
2047
|
+
}
|
|
2048
|
+
/**
|
|
2049
|
+
* Generate pool ID for balance pools.
|
|
2050
|
+
*/
|
|
2051
|
+
function generateBalancePoolId(parameters) {
|
|
2052
|
+
const { user, chainId, token } = parameters;
|
|
2053
|
+
return `${user}-${chainId.toString()}-${token}-balance`.toLowerCase();
|
|
2054
|
+
}
|
|
2055
|
+
/**
|
|
2056
|
+
* Generate pool ID for allowance pools.
|
|
2057
|
+
*/
|
|
2058
|
+
function generateAllowancePoolId(parameters) {
|
|
2059
|
+
const { user, chainId, token } = parameters;
|
|
2060
|
+
return `${user}-${chainId.toString()}-${token}-allowance`.toLowerCase();
|
|
2061
|
+
}
|
|
2062
|
+
/**
|
|
2063
|
+
* Generate pool ID for obligation collateral pools.
|
|
2064
|
+
* Obligation collateral pools represent collateral already deposited in the obligation.
|
|
2065
|
+
* These pools are shared across all offers with the same obligation.
|
|
2066
|
+
*/
|
|
2067
|
+
function generateObligationCollateralPoolId(parameters) {
|
|
2068
|
+
const { user, chainId, obligationId, token } = parameters;
|
|
2069
|
+
return `${user}-${chainId.toString()}-${obligationId}-${token}-obligation-collateral`.toLowerCase();
|
|
2070
|
+
}
|
|
2071
|
+
/**
|
|
2072
|
+
* Generate pool ID for debt pools.
|
|
2073
|
+
*/
|
|
2074
|
+
function generateDebtPoolId(parameters) {
|
|
2075
|
+
const { user, chainId, obligationId } = parameters;
|
|
2076
|
+
return `${user}-${chainId.toString()}-${obligationId}-debt`.toLowerCase();
|
|
2077
|
+
}
|
|
2078
|
+
/**
|
|
2079
|
+
* Generate pool ID for user position in a vault.
|
|
2080
|
+
*/
|
|
2081
|
+
function generateUserVaultPositionPoolId(parameters) {
|
|
2082
|
+
const { user, chainId, vault } = parameters;
|
|
2083
|
+
return `${user}-${chainId.toString()}-${vault}-user-vault-position`.toLowerCase();
|
|
2084
|
+
}
|
|
2085
|
+
/**
|
|
2086
|
+
* Generate pool ID for vault position in a market.
|
|
2087
|
+
*/
|
|
2088
|
+
function generateVaultPositionPoolId(parameters) {
|
|
2089
|
+
const { vault, chainId, marketId } = parameters;
|
|
2090
|
+
return `${vault}-${chainId.toString()}-${marketId}-vault-position`.toLowerCase();
|
|
2091
|
+
}
|
|
2092
|
+
/**
|
|
2093
|
+
* Generate pool ID for market total liquidity.
|
|
2094
|
+
*/
|
|
2095
|
+
function generateMarketLiquidityPoolId(parameters) {
|
|
2096
|
+
const { chainId, marketId } = parameters;
|
|
2097
|
+
return `${chainId.toString()}-${marketId}-market-liquidity`.toLowerCase();
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2050
2100
|
//#endregion
|
|
2051
2101
|
//#region src/core/Offer.ts
|
|
2052
2102
|
var Offer_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -2055,17 +2105,19 @@ var Offer_exports = /* @__PURE__ */ __exportAll({
|
|
|
2055
2105
|
Status: () => Status,
|
|
2056
2106
|
consumedEvent: () => consumedEvent,
|
|
2057
2107
|
decode: () => decode$1,
|
|
2058
|
-
domain: () => domain,
|
|
2059
2108
|
encode: () => encode$1,
|
|
2060
2109
|
from: () => from$14,
|
|
2061
2110
|
fromSnakeCase: () => fromSnakeCase$1,
|
|
2062
2111
|
hash: () => hash,
|
|
2112
|
+
liquidateEvent: () => liquidateEvent,
|
|
2063
2113
|
obligationId: () => obligationId,
|
|
2064
2114
|
random: () => random$1,
|
|
2115
|
+
repayEvent: () => repayEvent,
|
|
2065
2116
|
serialize: () => serialize,
|
|
2117
|
+
supplyCollateralEvent: () => supplyCollateralEvent,
|
|
2066
2118
|
takeEvent: () => takeEvent,
|
|
2067
2119
|
toSnakeCase: () => toSnakeCase,
|
|
2068
|
-
|
|
2120
|
+
withdrawCollateralEvent: () => withdrawCollateralEvent
|
|
2069
2121
|
});
|
|
2070
2122
|
/** Internal symbol for caching the computed hash. */
|
|
2071
2123
|
const HASH_CACHE = Symbol("offer.hash");
|
|
@@ -2095,7 +2147,6 @@ const OfferSchema = () => {
|
|
|
2095
2147
|
z$1.bigint()
|
|
2096
2148
|
]).optional().default("0x0000000000000000000000000000000000000000000000000000000000000000").transform(transformBytes32),
|
|
2097
2149
|
buy: z$1.boolean(),
|
|
2098
|
-
chainId: z$1.number().min(0).max(Number.MAX_SAFE_INTEGER),
|
|
2099
2150
|
loanToken: z$1.string().transform(transformAddress),
|
|
2100
2151
|
collaterals: CollateralsSchema,
|
|
2101
2152
|
callback: z$1.object({
|
|
@@ -2164,7 +2215,6 @@ const serialize = (offer) => ({
|
|
|
2164
2215
|
group: offer.group,
|
|
2165
2216
|
session: offer.session,
|
|
2166
2217
|
buy: offer.buy,
|
|
2167
|
-
chainId: offer.chainId,
|
|
2168
2218
|
loanToken: offer.loanToken,
|
|
2169
2219
|
collaterals: offer.collaterals.map((c) => ({
|
|
2170
2220
|
asset: c.asset,
|
|
@@ -2185,7 +2235,6 @@ const serialize = (offer) => ({
|
|
|
2185
2235
|
* @returns {Offer} A randomly generated Offer object.
|
|
2186
2236
|
*/
|
|
2187
2237
|
function random$1(config) {
|
|
2188
|
-
const chain = config?.chains ? config.chains[int(config.chains.length)] : chains$2.ethereum;
|
|
2189
2238
|
const loanToken = config?.loanTokens ? config.loanTokens[int(config.loanTokens.length)] : address();
|
|
2190
2239
|
const collateralCandidates = config?.collateralTokens ? config.collateralTokens.filter((a) => a !== loanToken) : [address()];
|
|
2191
2240
|
collateralCandidates[int(collateralCandidates.length)];
|
|
@@ -2231,7 +2280,6 @@ function random$1(config) {
|
|
|
2231
2280
|
group: config?.group ?? hex(32),
|
|
2232
2281
|
session: config?.session ?? hex(32),
|
|
2233
2282
|
buy,
|
|
2234
|
-
chainId: chain.id,
|
|
2235
2283
|
loanToken,
|
|
2236
2284
|
collaterals: config?.collaterals ?? Array.from({ length: int(3) + 1 }, () => ({
|
|
2237
2285
|
...random$3(),
|
|
@@ -2251,150 +2299,36 @@ const weightedChoice = (pairs) => {
|
|
|
2251
2299
|
return pairs[0][0];
|
|
2252
2300
|
};
|
|
2253
2301
|
/**
|
|
2254
|
-
*
|
|
2255
|
-
*
|
|
2256
|
-
*
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
chainId: BigInt(chainId),
|
|
2260
|
-
verifyingContract: zeroAddress
|
|
2261
|
-
});
|
|
2262
|
-
/**
|
|
2263
|
-
* The EIP-712 types for the offer.
|
|
2264
|
-
* @warning The ordering of the types should NEVER be changed. The offer hash is computed based on the order of the types.
|
|
2265
|
-
* @returns The EIP-712 types.
|
|
2302
|
+
* Computes the canonical chain-agnostic offer hash.
|
|
2303
|
+
* The hash is `keccak256(abi.encode(offer))` using {@link encode}.
|
|
2304
|
+
*
|
|
2305
|
+
* @param offer - Offer payload to hash.
|
|
2306
|
+
* @returns 32-byte offer hash.
|
|
2266
2307
|
*/
|
|
2267
|
-
const types = {
|
|
2268
|
-
EIP712Domain: [{
|
|
2269
|
-
name: "chainId",
|
|
2270
|
-
type: "uint256"
|
|
2271
|
-
}, {
|
|
2272
|
-
name: "verifyingContract",
|
|
2273
|
-
type: "address"
|
|
2274
|
-
}],
|
|
2275
|
-
Offer: [
|
|
2276
|
-
{
|
|
2277
|
-
name: "maker",
|
|
2278
|
-
type: "address"
|
|
2279
|
-
},
|
|
2280
|
-
{
|
|
2281
|
-
name: "assets",
|
|
2282
|
-
type: "uint256"
|
|
2283
|
-
},
|
|
2284
|
-
{
|
|
2285
|
-
name: "obligationUnits",
|
|
2286
|
-
type: "uint256"
|
|
2287
|
-
},
|
|
2288
|
-
{
|
|
2289
|
-
name: "obligationShares",
|
|
2290
|
-
type: "uint256"
|
|
2291
|
-
},
|
|
2292
|
-
{
|
|
2293
|
-
name: "tick",
|
|
2294
|
-
type: "uint256"
|
|
2295
|
-
},
|
|
2296
|
-
{
|
|
2297
|
-
name: "maturity",
|
|
2298
|
-
type: "uint256"
|
|
2299
|
-
},
|
|
2300
|
-
{
|
|
2301
|
-
name: "expiry",
|
|
2302
|
-
type: "uint256"
|
|
2303
|
-
},
|
|
2304
|
-
{
|
|
2305
|
-
name: "group",
|
|
2306
|
-
type: "bytes32"
|
|
2307
|
-
},
|
|
2308
|
-
{
|
|
2309
|
-
name: "session",
|
|
2310
|
-
type: "bytes32"
|
|
2311
|
-
},
|
|
2312
|
-
{
|
|
2313
|
-
name: "buy",
|
|
2314
|
-
type: "bool"
|
|
2315
|
-
},
|
|
2316
|
-
{
|
|
2317
|
-
name: "loanToken",
|
|
2318
|
-
type: "address"
|
|
2319
|
-
},
|
|
2320
|
-
{
|
|
2321
|
-
name: "collaterals",
|
|
2322
|
-
type: "Collateral[]"
|
|
2323
|
-
},
|
|
2324
|
-
{
|
|
2325
|
-
name: "callback",
|
|
2326
|
-
type: "Callback"
|
|
2327
|
-
},
|
|
2328
|
-
{
|
|
2329
|
-
name: "receiverIfMakerIsSeller",
|
|
2330
|
-
type: "address"
|
|
2331
|
-
}
|
|
2332
|
-
],
|
|
2333
|
-
Collateral: [
|
|
2334
|
-
{
|
|
2335
|
-
name: "asset",
|
|
2336
|
-
type: "address"
|
|
2337
|
-
},
|
|
2338
|
-
{
|
|
2339
|
-
name: "oracle",
|
|
2340
|
-
type: "address"
|
|
2341
|
-
},
|
|
2342
|
-
{
|
|
2343
|
-
name: "lltv",
|
|
2344
|
-
type: "uint256"
|
|
2345
|
-
}
|
|
2346
|
-
],
|
|
2347
|
-
Callback: [{
|
|
2348
|
-
name: "address",
|
|
2349
|
-
type: "address"
|
|
2350
|
-
}, {
|
|
2351
|
-
name: "data",
|
|
2352
|
-
type: "bytes"
|
|
2353
|
-
}]
|
|
2354
|
-
};
|
|
2355
2308
|
function hash(offer) {
|
|
2356
2309
|
const cached = offer[HASH_CACHE];
|
|
2357
2310
|
if (cached) return cached;
|
|
2358
|
-
const computed =
|
|
2359
|
-
domain: domain(offer.chainId),
|
|
2360
|
-
message: {
|
|
2361
|
-
maker: offer.maker.toLowerCase(),
|
|
2362
|
-
assets: offer.assets,
|
|
2363
|
-
obligationUnits: offer.obligationUnits,
|
|
2364
|
-
obligationShares: offer.obligationShares,
|
|
2365
|
-
tick: BigInt(offer.tick),
|
|
2366
|
-
maturity: BigInt(offer.maturity),
|
|
2367
|
-
expiry: BigInt(offer.expiry),
|
|
2368
|
-
group: offer.group,
|
|
2369
|
-
session: offer.session,
|
|
2370
|
-
buy: offer.buy,
|
|
2371
|
-
loanToken: offer.loanToken.toLowerCase(),
|
|
2372
|
-
collaterals: offer.collaterals,
|
|
2373
|
-
callback: {
|
|
2374
|
-
address: offer.callback.address.toLowerCase(),
|
|
2375
|
-
data: offer.callback.data
|
|
2376
|
-
},
|
|
2377
|
-
receiverIfMakerIsSeller: offer.receiverIfMakerIsSeller.toLowerCase()
|
|
2378
|
-
},
|
|
2379
|
-
primaryType: "Offer",
|
|
2380
|
-
types
|
|
2381
|
-
});
|
|
2311
|
+
const computed = keccak256(encode$1(offer));
|
|
2382
2312
|
offer[HASH_CACHE] = computed;
|
|
2383
2313
|
return computed;
|
|
2384
2314
|
}
|
|
2385
2315
|
/**
|
|
2386
|
-
* Calculates the obligation id for an offer
|
|
2387
|
-
* The id is computed
|
|
2316
|
+
* Calculates the onchain obligation id for an offer.
|
|
2317
|
+
* The id is computed with {@link Id.toId}.
|
|
2388
2318
|
* @param offer - The offer to calculate the obligation id for.
|
|
2319
|
+
* @param parameters - The chain context used by the onchain id function.
|
|
2389
2320
|
* @returns The obligation id as a 32-byte hex string.
|
|
2390
2321
|
*/
|
|
2391
|
-
function obligationId(offer) {
|
|
2392
|
-
return
|
|
2393
|
-
chainId:
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2322
|
+
function obligationId(offer, parameters) {
|
|
2323
|
+
return toId({
|
|
2324
|
+
chainId: parameters.chainId,
|
|
2325
|
+
morphoV2: parameters.morphoV2,
|
|
2326
|
+
obligation: from$15({
|
|
2327
|
+
loanToken: offer.loanToken,
|
|
2328
|
+
collaterals: offer.collaterals,
|
|
2329
|
+
maturity: offer.maturity
|
|
2330
|
+
})
|
|
2331
|
+
});
|
|
2398
2332
|
}
|
|
2399
2333
|
const OfferAbi = [
|
|
2400
2334
|
{
|
|
@@ -2437,10 +2371,6 @@ const OfferAbi = [
|
|
|
2437
2371
|
name: "buy",
|
|
2438
2372
|
type: "bool"
|
|
2439
2373
|
},
|
|
2440
|
-
{
|
|
2441
|
-
name: "chainId",
|
|
2442
|
-
type: "uint256"
|
|
2443
|
-
},
|
|
2444
2374
|
{
|
|
2445
2375
|
name: "loanToken",
|
|
2446
2376
|
type: "address"
|
|
@@ -2495,7 +2425,6 @@ function encode$1(offer) {
|
|
|
2495
2425
|
offer.group,
|
|
2496
2426
|
offer.session,
|
|
2497
2427
|
offer.buy,
|
|
2498
|
-
BigInt(offer.chainId),
|
|
2499
2428
|
offer.loanToken,
|
|
2500
2429
|
BigInt(offer.start),
|
|
2501
2430
|
offer.collaterals,
|
|
@@ -2521,10 +2450,9 @@ function decode$1(data) {
|
|
|
2521
2450
|
group: decoded[7],
|
|
2522
2451
|
session: decoded[8],
|
|
2523
2452
|
buy: decoded[9],
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
collaterals: decoded[13].map((c) => {
|
|
2453
|
+
loanToken: decoded[10],
|
|
2454
|
+
start: Number(decoded[11]),
|
|
2455
|
+
collaterals: decoded[12].map((c) => {
|
|
2528
2456
|
return from$17({
|
|
2529
2457
|
asset: c.asset,
|
|
2530
2458
|
oracle: c.oracle,
|
|
@@ -2532,23 +2460,145 @@ function decode$1(data) {
|
|
|
2532
2460
|
});
|
|
2533
2461
|
}),
|
|
2534
2462
|
callback: {
|
|
2535
|
-
address: decoded[
|
|
2536
|
-
data: decoded[
|
|
2463
|
+
address: decoded[13].address,
|
|
2464
|
+
data: decoded[13].data
|
|
2465
|
+
},
|
|
2466
|
+
receiverIfMakerIsSeller: decoded[14]
|
|
2467
|
+
});
|
|
2468
|
+
}
|
|
2469
|
+
/**
|
|
2470
|
+
* ABI for the Take event emitted by the Morpho V2 contract.
|
|
2471
|
+
*/
|
|
2472
|
+
const takeEvent = {
|
|
2473
|
+
type: "event",
|
|
2474
|
+
name: "Take",
|
|
2475
|
+
inputs: [
|
|
2476
|
+
{
|
|
2477
|
+
name: "caller",
|
|
2478
|
+
type: "address",
|
|
2479
|
+
indexed: false,
|
|
2480
|
+
internalType: "address"
|
|
2481
|
+
},
|
|
2482
|
+
{
|
|
2483
|
+
name: "id",
|
|
2484
|
+
type: "bytes32",
|
|
2485
|
+
indexed: true,
|
|
2486
|
+
internalType: "bytes32"
|
|
2487
|
+
},
|
|
2488
|
+
{
|
|
2489
|
+
name: "maker",
|
|
2490
|
+
type: "address",
|
|
2491
|
+
indexed: true,
|
|
2492
|
+
internalType: "address"
|
|
2493
|
+
},
|
|
2494
|
+
{
|
|
2495
|
+
name: "taker",
|
|
2496
|
+
type: "address",
|
|
2497
|
+
indexed: true,
|
|
2498
|
+
internalType: "address"
|
|
2499
|
+
},
|
|
2500
|
+
{
|
|
2501
|
+
name: "offerIsBuy",
|
|
2502
|
+
type: "bool",
|
|
2503
|
+
indexed: false,
|
|
2504
|
+
internalType: "bool"
|
|
2505
|
+
},
|
|
2506
|
+
{
|
|
2507
|
+
name: "buyerAssets",
|
|
2508
|
+
type: "uint256",
|
|
2509
|
+
indexed: false,
|
|
2510
|
+
internalType: "uint256"
|
|
2511
|
+
},
|
|
2512
|
+
{
|
|
2513
|
+
name: "sellerAssets",
|
|
2514
|
+
type: "uint256",
|
|
2515
|
+
indexed: false,
|
|
2516
|
+
internalType: "uint256"
|
|
2517
|
+
},
|
|
2518
|
+
{
|
|
2519
|
+
name: "obligationUnits",
|
|
2520
|
+
type: "uint256",
|
|
2521
|
+
indexed: false,
|
|
2522
|
+
internalType: "uint256"
|
|
2523
|
+
},
|
|
2524
|
+
{
|
|
2525
|
+
name: "obligationShares",
|
|
2526
|
+
type: "uint256",
|
|
2527
|
+
indexed: false,
|
|
2528
|
+
internalType: "uint256"
|
|
2529
|
+
},
|
|
2530
|
+
{
|
|
2531
|
+
name: "buyerIsLender",
|
|
2532
|
+
type: "bool",
|
|
2533
|
+
indexed: false,
|
|
2534
|
+
internalType: "bool"
|
|
2535
|
+
},
|
|
2536
|
+
{
|
|
2537
|
+
name: "sellerIsBorrower",
|
|
2538
|
+
type: "bool",
|
|
2539
|
+
indexed: false,
|
|
2540
|
+
internalType: "bool"
|
|
2541
|
+
},
|
|
2542
|
+
{
|
|
2543
|
+
name: "sellerReceiver",
|
|
2544
|
+
type: "address",
|
|
2545
|
+
indexed: false,
|
|
2546
|
+
internalType: "address"
|
|
2547
|
+
},
|
|
2548
|
+
{
|
|
2549
|
+
name: "group",
|
|
2550
|
+
type: "bytes32",
|
|
2551
|
+
indexed: false,
|
|
2552
|
+
internalType: "bytes32"
|
|
2553
|
+
},
|
|
2554
|
+
{
|
|
2555
|
+
name: "consumed",
|
|
2556
|
+
type: "uint256",
|
|
2557
|
+
indexed: false,
|
|
2558
|
+
internalType: "uint256"
|
|
2559
|
+
}
|
|
2560
|
+
],
|
|
2561
|
+
anonymous: false
|
|
2562
|
+
};
|
|
2563
|
+
/**
|
|
2564
|
+
* ABI for the Consume event emitted by the Obligation contract.
|
|
2565
|
+
*/
|
|
2566
|
+
const consumedEvent = {
|
|
2567
|
+
type: "event",
|
|
2568
|
+
name: "Consume",
|
|
2569
|
+
inputs: [
|
|
2570
|
+
{
|
|
2571
|
+
name: "user",
|
|
2572
|
+
type: "address",
|
|
2573
|
+
indexed: true,
|
|
2574
|
+
internalType: "address"
|
|
2537
2575
|
},
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2576
|
+
{
|
|
2577
|
+
name: "group",
|
|
2578
|
+
type: "bytes32",
|
|
2579
|
+
indexed: true,
|
|
2580
|
+
internalType: "bytes32"
|
|
2581
|
+
},
|
|
2582
|
+
{
|
|
2583
|
+
name: "amount",
|
|
2584
|
+
type: "uint256",
|
|
2585
|
+
indexed: false,
|
|
2586
|
+
internalType: "uint256"
|
|
2587
|
+
}
|
|
2588
|
+
],
|
|
2589
|
+
anonymous: false
|
|
2590
|
+
};
|
|
2541
2591
|
/**
|
|
2542
|
-
* ABI for the
|
|
2592
|
+
* ABI for the Repay event emitted by the MorphoV2 contract.
|
|
2543
2593
|
*/
|
|
2544
|
-
const
|
|
2594
|
+
const repayEvent = {
|
|
2545
2595
|
type: "event",
|
|
2546
|
-
name: "
|
|
2596
|
+
name: "Repay",
|
|
2547
2597
|
inputs: [
|
|
2548
2598
|
{
|
|
2549
2599
|
name: "caller",
|
|
2550
2600
|
type: "address",
|
|
2551
|
-
indexed:
|
|
2601
|
+
indexed: true,
|
|
2552
2602
|
internalType: "address"
|
|
2553
2603
|
},
|
|
2554
2604
|
{
|
|
@@ -2558,104 +2608,165 @@ const takeEvent = {
|
|
|
2558
2608
|
internalType: "bytes32"
|
|
2559
2609
|
},
|
|
2560
2610
|
{
|
|
2561
|
-
name: "
|
|
2611
|
+
name: "obligationUnits",
|
|
2612
|
+
type: "uint256",
|
|
2613
|
+
indexed: false,
|
|
2614
|
+
internalType: "uint256"
|
|
2615
|
+
},
|
|
2616
|
+
{
|
|
2617
|
+
name: "onBehalf",
|
|
2562
2618
|
type: "address",
|
|
2563
2619
|
indexed: true,
|
|
2564
2620
|
internalType: "address"
|
|
2565
|
-
}
|
|
2621
|
+
}
|
|
2622
|
+
],
|
|
2623
|
+
anonymous: false
|
|
2624
|
+
};
|
|
2625
|
+
/**
|
|
2626
|
+
* ABI for the Liquidate event emitted by the MorphoV2 contract.
|
|
2627
|
+
*/
|
|
2628
|
+
const liquidateEvent = {
|
|
2629
|
+
type: "event",
|
|
2630
|
+
name: "Liquidate",
|
|
2631
|
+
inputs: [
|
|
2566
2632
|
{
|
|
2567
|
-
name: "
|
|
2633
|
+
name: "caller",
|
|
2568
2634
|
type: "address",
|
|
2569
2635
|
indexed: true,
|
|
2570
2636
|
internalType: "address"
|
|
2571
2637
|
},
|
|
2572
2638
|
{
|
|
2573
|
-
name: "
|
|
2574
|
-
type: "
|
|
2575
|
-
indexed:
|
|
2576
|
-
internalType: "
|
|
2639
|
+
name: "id",
|
|
2640
|
+
type: "bytes32",
|
|
2641
|
+
indexed: true,
|
|
2642
|
+
internalType: "bytes32"
|
|
2577
2643
|
},
|
|
2578
2644
|
{
|
|
2579
|
-
name: "
|
|
2580
|
-
type: "
|
|
2645
|
+
name: "seizures",
|
|
2646
|
+
type: "tuple[]",
|
|
2581
2647
|
indexed: false,
|
|
2582
|
-
internalType: "
|
|
2648
|
+
internalType: "struct IMorphoV2.Seizure[]",
|
|
2649
|
+
components: [
|
|
2650
|
+
{
|
|
2651
|
+
name: "collateralIndex",
|
|
2652
|
+
type: "uint256",
|
|
2653
|
+
internalType: "uint256"
|
|
2654
|
+
},
|
|
2655
|
+
{
|
|
2656
|
+
name: "repaid",
|
|
2657
|
+
type: "uint256",
|
|
2658
|
+
internalType: "uint256"
|
|
2659
|
+
},
|
|
2660
|
+
{
|
|
2661
|
+
name: "seized",
|
|
2662
|
+
type: "uint256",
|
|
2663
|
+
internalType: "uint256"
|
|
2664
|
+
}
|
|
2665
|
+
]
|
|
2583
2666
|
},
|
|
2584
2667
|
{
|
|
2585
|
-
name: "
|
|
2586
|
-
type: "
|
|
2587
|
-
indexed:
|
|
2588
|
-
internalType: "
|
|
2668
|
+
name: "borrower",
|
|
2669
|
+
type: "address",
|
|
2670
|
+
indexed: true,
|
|
2671
|
+
internalType: "address"
|
|
2589
2672
|
},
|
|
2590
2673
|
{
|
|
2591
|
-
name: "
|
|
2674
|
+
name: "totalRepaid",
|
|
2592
2675
|
type: "uint256",
|
|
2593
2676
|
indexed: false,
|
|
2594
2677
|
internalType: "uint256"
|
|
2595
2678
|
},
|
|
2596
2679
|
{
|
|
2597
|
-
name: "
|
|
2680
|
+
name: "badDebt",
|
|
2598
2681
|
type: "uint256",
|
|
2599
2682
|
indexed: false,
|
|
2600
2683
|
internalType: "uint256"
|
|
2601
|
-
}
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
internalType: "bool"
|
|
2613
|
-
},
|
|
2684
|
+
}
|
|
2685
|
+
],
|
|
2686
|
+
anonymous: false
|
|
2687
|
+
};
|
|
2688
|
+
/**
|
|
2689
|
+
* ABI for the SupplyCollateral event emitted by the MorphoV2 contract.
|
|
2690
|
+
*/
|
|
2691
|
+
const supplyCollateralEvent = {
|
|
2692
|
+
type: "event",
|
|
2693
|
+
name: "SupplyCollateral",
|
|
2694
|
+
inputs: [
|
|
2614
2695
|
{
|
|
2615
|
-
name: "
|
|
2696
|
+
name: "caller",
|
|
2616
2697
|
type: "address",
|
|
2617
2698
|
indexed: false,
|
|
2618
2699
|
internalType: "address"
|
|
2619
2700
|
},
|
|
2620
2701
|
{
|
|
2621
|
-
name: "
|
|
2702
|
+
name: "id",
|
|
2622
2703
|
type: "bytes32",
|
|
2623
|
-
indexed:
|
|
2704
|
+
indexed: true,
|
|
2624
2705
|
internalType: "bytes32"
|
|
2625
2706
|
},
|
|
2626
2707
|
{
|
|
2627
|
-
name: "
|
|
2708
|
+
name: "collateral",
|
|
2709
|
+
type: "address",
|
|
2710
|
+
indexed: true,
|
|
2711
|
+
internalType: "address"
|
|
2712
|
+
},
|
|
2713
|
+
{
|
|
2714
|
+
name: "assets",
|
|
2628
2715
|
type: "uint256",
|
|
2629
2716
|
indexed: false,
|
|
2630
2717
|
internalType: "uint256"
|
|
2718
|
+
},
|
|
2719
|
+
{
|
|
2720
|
+
name: "onBehalf",
|
|
2721
|
+
type: "address",
|
|
2722
|
+
indexed: true,
|
|
2723
|
+
internalType: "address"
|
|
2631
2724
|
}
|
|
2632
2725
|
],
|
|
2633
2726
|
anonymous: false
|
|
2634
2727
|
};
|
|
2635
2728
|
/**
|
|
2636
|
-
* ABI for the
|
|
2729
|
+
* ABI for the WithdrawCollateral event emitted by the MorphoV2 contract.
|
|
2637
2730
|
*/
|
|
2638
|
-
const
|
|
2731
|
+
const withdrawCollateralEvent = {
|
|
2639
2732
|
type: "event",
|
|
2640
|
-
name: "
|
|
2733
|
+
name: "WithdrawCollateral",
|
|
2641
2734
|
inputs: [
|
|
2642
2735
|
{
|
|
2643
|
-
name: "
|
|
2736
|
+
name: "caller",
|
|
2644
2737
|
type: "address",
|
|
2645
|
-
indexed:
|
|
2738
|
+
indexed: false,
|
|
2646
2739
|
internalType: "address"
|
|
2647
2740
|
},
|
|
2648
2741
|
{
|
|
2649
|
-
name: "
|
|
2742
|
+
name: "id",
|
|
2650
2743
|
type: "bytes32",
|
|
2651
2744
|
indexed: true,
|
|
2652
2745
|
internalType: "bytes32"
|
|
2653
2746
|
},
|
|
2654
2747
|
{
|
|
2655
|
-
name: "
|
|
2748
|
+
name: "collateral",
|
|
2749
|
+
type: "address",
|
|
2750
|
+
indexed: true,
|
|
2751
|
+
internalType: "address"
|
|
2752
|
+
},
|
|
2753
|
+
{
|
|
2754
|
+
name: "assets",
|
|
2656
2755
|
type: "uint256",
|
|
2657
2756
|
indexed: false,
|
|
2658
2757
|
internalType: "uint256"
|
|
2758
|
+
},
|
|
2759
|
+
{
|
|
2760
|
+
name: "onBehalf",
|
|
2761
|
+
type: "address",
|
|
2762
|
+
indexed: true,
|
|
2763
|
+
internalType: "address"
|
|
2764
|
+
},
|
|
2765
|
+
{
|
|
2766
|
+
name: "receiver",
|
|
2767
|
+
type: "address",
|
|
2768
|
+
indexed: false,
|
|
2769
|
+
internalType: "address"
|
|
2659
2770
|
}
|
|
2660
2771
|
],
|
|
2661
2772
|
anonymous: false
|
|
@@ -2731,8 +2842,9 @@ function fromCollateral(parameters) {
|
|
|
2731
2842
|
* @returns The created oracles. {@link fromOffer.ReturnType}
|
|
2732
2843
|
*/
|
|
2733
2844
|
function fromOffer(parameters) {
|
|
2734
|
-
const { offer, blockNumber, price = null } = parameters;
|
|
2845
|
+
const { chainId, offer, blockNumber, price = null } = parameters;
|
|
2735
2846
|
return fromOffers({
|
|
2847
|
+
chainId,
|
|
2736
2848
|
offers: [offer],
|
|
2737
2849
|
blockNumber,
|
|
2738
2850
|
price
|
|
@@ -2746,13 +2858,13 @@ function fromOffer(parameters) {
|
|
|
2746
2858
|
* @returns The created oracles. {@link fromOffers.ReturnType}
|
|
2747
2859
|
*/
|
|
2748
2860
|
function fromOffers(parameters) {
|
|
2749
|
-
const { offers, blockNumber, price = null } = parameters;
|
|
2861
|
+
const { chainId, offers, blockNumber, price = null } = parameters;
|
|
2750
2862
|
const rowsByKey = /* @__PURE__ */ new Map();
|
|
2751
2863
|
for (const offer of offers) for (const collateral of offer.collaterals) {
|
|
2752
|
-
const key = `${
|
|
2864
|
+
const key = `${chainId}-${collateral.oracle}`.toLowerCase();
|
|
2753
2865
|
if (rowsByKey.has(key)) continue;
|
|
2754
2866
|
rowsByKey.set(key, fromCollateral({
|
|
2755
|
-
chainId
|
|
2867
|
+
chainId,
|
|
2756
2868
|
collateral,
|
|
2757
2869
|
blockNumber,
|
|
2758
2870
|
price
|
|
@@ -2777,11 +2889,14 @@ let Conversion;
|
|
|
2777
2889
|
//#region src/core/Position.ts
|
|
2778
2890
|
var Position_exports = /* @__PURE__ */ __exportAll({
|
|
2779
2891
|
Type: () => Type,
|
|
2780
|
-
from: () => from$12
|
|
2892
|
+
from: () => from$12,
|
|
2893
|
+
positionTypeId: () => positionTypeId
|
|
2781
2894
|
});
|
|
2782
2895
|
let Type = /* @__PURE__ */ function(Type) {
|
|
2783
2896
|
Type["ERC20"] = "erc20";
|
|
2784
2897
|
Type["VAULT_V1"] = "vault_v1";
|
|
2898
|
+
Type["DEBT_OF"] = "debtOf";
|
|
2899
|
+
Type["COLLATERAL_OF"] = "collateralOf";
|
|
2785
2900
|
return Type;
|
|
2786
2901
|
}({});
|
|
2787
2902
|
/**
|
|
@@ -2797,10 +2912,16 @@ function from$12(parameters) {
|
|
|
2797
2912
|
user: parameters.user.toLowerCase(),
|
|
2798
2913
|
type: parameters.type,
|
|
2799
2914
|
balance: parameters.balance,
|
|
2800
|
-
|
|
2915
|
+
asset: parameters.asset.toLowerCase(),
|
|
2801
2916
|
blockNumber: parameters.blockNumber
|
|
2802
2917
|
};
|
|
2803
2918
|
}
|
|
2919
|
+
/**
|
|
2920
|
+
* Maps a {@link Type} enum value to its 1-based integer ID used in the database.
|
|
2921
|
+
* @param type - The position type.
|
|
2922
|
+
* @returns The 1-based integer ID.
|
|
2923
|
+
*/
|
|
2924
|
+
const positionTypeId = (type) => Object.values(Type).indexOf(type) + 1;
|
|
2804
2925
|
|
|
2805
2926
|
//#endregion
|
|
2806
2927
|
//#region src/core/Tick.ts
|
|
@@ -2939,7 +3060,7 @@ function fromSnakeCase(snake) {
|
|
|
2939
3060
|
*/
|
|
2940
3061
|
function random() {
|
|
2941
3062
|
return from$11({
|
|
2942
|
-
obligationId:
|
|
3063
|
+
obligationId: hex(32),
|
|
2943
3064
|
ask: { tick: int(TICK_RANGE + 1) },
|
|
2944
3065
|
bid: { tick: int(TICK_RANGE + 1) }
|
|
2945
3066
|
});
|
|
@@ -3129,6 +3250,8 @@ function from$9(parameters) {
|
|
|
3129
3250
|
from: parameters.from.toLowerCase(),
|
|
3130
3251
|
to: parameters.to.toLowerCase(),
|
|
3131
3252
|
value: parameters.value,
|
|
3253
|
+
type: parameters.type,
|
|
3254
|
+
asset: parameters.asset.toLowerCase(),
|
|
3132
3255
|
blockNumber: parameters.blockNumber
|
|
3133
3256
|
};
|
|
3134
3257
|
}
|
|
@@ -3310,7 +3433,7 @@ const verifySignatureAndRecoverAddress = async (params) => {
|
|
|
3310
3433
|
const encode = async (tree, signature, domain) => {
|
|
3311
3434
|
const errorFactory = (reason) => new EncodeError(reason);
|
|
3312
3435
|
const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
|
|
3313
|
-
validateTreeForEncoding(tree
|
|
3436
|
+
validateTreeForEncoding(tree);
|
|
3314
3437
|
await verifySignatureAndRecoverAddress({
|
|
3315
3438
|
root: tree.root,
|
|
3316
3439
|
signature,
|
|
@@ -3342,14 +3465,10 @@ const encodeUnsigned = (tree) => {
|
|
|
3342
3465
|
validateTreeForEncoding(tree);
|
|
3343
3466
|
return bytesToHex(encodeUnsignedBytes(tree));
|
|
3344
3467
|
};
|
|
3345
|
-
const validateTreeForEncoding = (tree
|
|
3468
|
+
const validateTreeForEncoding = (tree) => {
|
|
3346
3469
|
if (VERSION$1 > 255) throw new EncodeError(`version overflow: ${VERSION$1} exceeds 255`);
|
|
3347
3470
|
const computed = from$8(tree.offers);
|
|
3348
3471
|
if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
|
|
3349
|
-
if (domain) {
|
|
3350
|
-
const mismatched = tree.offers.find((offer) => BigInt(offer.chainId) !== domain.chainId);
|
|
3351
|
-
if (mismatched) throw new EncodeError(`chainId mismatch: expected ${domain.chainId}, got ${mismatched.chainId}`);
|
|
3352
|
-
}
|
|
3353
3472
|
};
|
|
3354
3473
|
const encodeUnsignedBytes = (tree) => {
|
|
3355
3474
|
const offersPayload = tree.offers.map(serialize);
|
|
@@ -3416,8 +3535,6 @@ const decode = async (encoded, domain) => {
|
|
|
3416
3535
|
}
|
|
3417
3536
|
const tree = from$8(rawOffers.map((o) => OfferSchema().parse(o)));
|
|
3418
3537
|
if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
|
|
3419
|
-
const chainIdMismatch = tree.offers.find((offer) => BigInt(offer.chainId) !== normalizedDomain.chainId);
|
|
3420
|
-
if (chainIdMismatch) throw new DecodeError(`chainId mismatch: expected ${normalizedDomain.chainId}, got ${chainIdMismatch.chainId}`);
|
|
3421
3538
|
return {
|
|
3422
3539
|
tree,
|
|
3423
3540
|
signature,
|
|
@@ -3470,7 +3587,7 @@ const BrandTypeId = Symbol.for("mempool/Brand");
|
|
|
3470
3587
|
|
|
3471
3588
|
//#endregion
|
|
3472
3589
|
//#region src/database/drizzle/VERSION.ts
|
|
3473
|
-
const VERSION = "router_v1.
|
|
3590
|
+
const VERSION = "router_v1.11";
|
|
3474
3591
|
|
|
3475
3592
|
//#endregion
|
|
3476
3593
|
//#region src/database/drizzle/schema.ts
|
|
@@ -3480,13 +3597,15 @@ var schema_exports = /* @__PURE__ */ __exportAll({
|
|
|
3480
3597
|
TABLE_NAMES: () => TABLE_NAMES,
|
|
3481
3598
|
VERSIONED_TABLE_NAMES: () => VERSIONED_TABLE_NAMES,
|
|
3482
3599
|
callbacks: () => callbacks,
|
|
3483
|
-
chains: () => chains
|
|
3600
|
+
chains: () => chains,
|
|
3484
3601
|
collectors: () => collectors,
|
|
3485
3602
|
consumedEvents: () => consumedEvents,
|
|
3486
3603
|
groups: () => groups,
|
|
3487
3604
|
lots: () => lots,
|
|
3605
|
+
lotsPositions: () => lotsPositions,
|
|
3488
3606
|
merklePaths: () => merklePaths,
|
|
3489
3607
|
obligationCollateralsV2: () => obligationCollateralsV2,
|
|
3608
|
+
obligationIdKeys: () => obligationIdKeys,
|
|
3490
3609
|
obligations: () => obligations,
|
|
3491
3610
|
offers: () => offers,
|
|
3492
3611
|
offersCallbacks: () => offersCallbacks,
|
|
@@ -3502,6 +3621,7 @@ var schema_exports = /* @__PURE__ */ __exportAll({
|
|
|
3502
3621
|
const s = pgSchema(VERSION);
|
|
3503
3622
|
var EnumTableName = /* @__PURE__ */ function(EnumTableName) {
|
|
3504
3623
|
EnumTableName["OBLIGATIONS"] = "obligations";
|
|
3624
|
+
EnumTableName["OBLIGATION_ID_KEYS"] = "obligation_id_keys";
|
|
3505
3625
|
EnumTableName["GROUPS"] = "groups";
|
|
3506
3626
|
EnumTableName["CONSUMED_EVENTS"] = "consumed_events";
|
|
3507
3627
|
EnumTableName["OBLIGATION_COLLATERALS_V2"] = "obligation_collaterals_v2";
|
|
@@ -3515,6 +3635,7 @@ var EnumTableName = /* @__PURE__ */ function(EnumTableName) {
|
|
|
3515
3635
|
EnumTableName["COLLECTORS"] = "collectors";
|
|
3516
3636
|
EnumTableName["CHAINS"] = "chains";
|
|
3517
3637
|
EnumTableName["LOTS"] = "lots";
|
|
3638
|
+
EnumTableName["LOTS_POSITIONS"] = "lots_positions";
|
|
3518
3639
|
EnumTableName["OFFSETS"] = "offsets";
|
|
3519
3640
|
EnumTableName["TREES"] = "trees";
|
|
3520
3641
|
EnumTableName["MERKLE_PATHS"] = "merkle_paths";
|
|
@@ -3523,11 +3644,16 @@ var EnumTableName = /* @__PURE__ */ function(EnumTableName) {
|
|
|
3523
3644
|
const TABLE_NAMES = Object.values(EnumTableName);
|
|
3524
3645
|
const VERSIONED_TABLE_NAMES = TABLE_NAMES.map((table) => `"${VERSION}"."${table}"`);
|
|
3525
3646
|
const obligations = s.table(EnumTableName.OBLIGATIONS, {
|
|
3526
|
-
|
|
3527
|
-
chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
|
|
3647
|
+
obligationKey: varchar("obligation_key", { length: 66 }).primaryKey(),
|
|
3528
3648
|
loanToken: varchar("loan_token", { length: 42 }).notNull(),
|
|
3529
3649
|
maturity: integer("maturity").notNull()
|
|
3530
3650
|
});
|
|
3651
|
+
const obligationIdKeys = s.table(EnumTableName.OBLIGATION_ID_KEYS, {
|
|
3652
|
+
obligationId: varchar("obligation_id", { length: 66 }).primaryKey(),
|
|
3653
|
+
obligationKey: varchar("obligation_key", { length: 66 }).notNull().references(() => obligations.obligationKey, { onDelete: "cascade" }),
|
|
3654
|
+
chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
|
|
3655
|
+
morphoV2: varchar("morpho_v2", { length: 42 }).notNull()
|
|
3656
|
+
}, (table) => [index("obligation_id_keys_obligation_key_idx").on(table.obligationKey), index("obligation_id_keys_chain_id_idx").on(table.chainId)]);
|
|
3531
3657
|
const groups = s.table(EnumTableName.GROUPS, {
|
|
3532
3658
|
chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
|
|
3533
3659
|
maker: varchar("maker", { length: 42 }).notNull(),
|
|
@@ -3575,24 +3701,19 @@ const consumedEvents = s.table(EnumTableName.CONSUMED_EVENTS, {
|
|
|
3575
3701
|
index("consumed_events_block_number_idx").on(t.blockNumber)
|
|
3576
3702
|
]);
|
|
3577
3703
|
const obligationCollateralsV2 = s.table(EnumTableName.OBLIGATION_COLLATERALS_V2, {
|
|
3578
|
-
|
|
3704
|
+
obligationKey: varchar("obligation_key", { length: 66 }).notNull().references(() => obligations.obligationKey, { onDelete: "cascade" }),
|
|
3579
3705
|
asset: varchar("asset", { length: 42 }).notNull(),
|
|
3580
|
-
oracleChainId: bigint("oracle_chain_id", { mode: "number" }).$type().notNull(),
|
|
3581
3706
|
oracleAddress: varchar("oracle_address", { length: 42 }).notNull(),
|
|
3582
3707
|
lltv: bigint("lltv", { mode: "bigint" }).notNull(),
|
|
3708
|
+
collateralIndex: integer("collateral_index").notNull(),
|
|
3583
3709
|
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
3584
3710
|
}, (table) => [
|
|
3585
3711
|
primaryKey({
|
|
3586
|
-
columns: [table.
|
|
3712
|
+
columns: [table.obligationKey, table.asset],
|
|
3587
3713
|
name: "obligation_collaterals_v2_pk"
|
|
3588
3714
|
}),
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
foreignColumns: [oracles$1.chainId, oracles$1.address],
|
|
3592
|
-
name: "obligation_collaterals_v2_oracles_fk"
|
|
3593
|
-
}),
|
|
3594
|
-
index("obligation_collaterals_v2_obligation_id_idx").on(table.obligationId),
|
|
3595
|
-
index("obligation_collaterals_v2_oracle_fk_idx").on(table.oracleChainId, table.oracleAddress)
|
|
3715
|
+
index("obligation_collaterals_v2_obligation_key_idx").on(table.obligationKey),
|
|
3716
|
+
index("obligation_collaterals_v2_oracle_address_idx").on(table.oracleAddress)
|
|
3596
3717
|
]);
|
|
3597
3718
|
const oracles$1 = s.table(EnumTableName.ORACLES, {
|
|
3598
3719
|
chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
|
|
@@ -3608,8 +3729,8 @@ const oracles$1 = s.table(EnumTableName.ORACLES, {
|
|
|
3608
3729
|
name: "oracles_pk"
|
|
3609
3730
|
})]);
|
|
3610
3731
|
const offers = s.table(EnumTableName.OFFERS, {
|
|
3611
|
-
hash: varchar("hash", { length: 66 }).
|
|
3612
|
-
obligationId: varchar("obligation_id", { length: 66 }).notNull().references(() =>
|
|
3732
|
+
hash: varchar("hash", { length: 66 }).notNull(),
|
|
3733
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull().references(() => obligationIdKeys.obligationId, { onDelete: "cascade" }),
|
|
3613
3734
|
assets: numeric("assets", {
|
|
3614
3735
|
precision: 78,
|
|
3615
3736
|
scale: 0
|
|
@@ -3637,6 +3758,10 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
3637
3758
|
blockNumber: bigint("block_number", { mode: "number" }).notNull(),
|
|
3638
3759
|
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
3639
3760
|
}, (table) => [
|
|
3761
|
+
primaryKey({
|
|
3762
|
+
columns: [table.hash, table.obligationId],
|
|
3763
|
+
name: "offers_pk"
|
|
3764
|
+
}),
|
|
3640
3765
|
foreignKey({
|
|
3641
3766
|
columns: [
|
|
3642
3767
|
table.groupChainId,
|
|
@@ -3655,10 +3780,19 @@ const offers = s.table(EnumTableName.OFFERS, {
|
|
|
3655
3780
|
index("offers_obligation_id_side_idx").on(table.obligationId, table.buy)
|
|
3656
3781
|
]);
|
|
3657
3782
|
const offersCallbacks = s.table(EnumTableName.OFFERS_CALLBACKS, {
|
|
3658
|
-
offerHash: varchar("offer_hash", { length: 66 }).notNull()
|
|
3783
|
+
offerHash: varchar("offer_hash", { length: 66 }).notNull(),
|
|
3784
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
3659
3785
|
callbackId: varchar("callback_id", { length: 66 })
|
|
3660
|
-
}, (table) => [
|
|
3661
|
-
columns: [table.offerHash, table.
|
|
3786
|
+
}, (table) => [foreignKey({
|
|
3787
|
+
columns: [table.offerHash, table.obligationId],
|
|
3788
|
+
foreignColumns: [offers.hash, offers.obligationId],
|
|
3789
|
+
name: "offers_callbacks_offer_fk"
|
|
3790
|
+
}).onDelete("cascade"), primaryKey({
|
|
3791
|
+
columns: [
|
|
3792
|
+
table.offerHash,
|
|
3793
|
+
table.obligationId,
|
|
3794
|
+
table.callbackId
|
|
3795
|
+
],
|
|
3662
3796
|
name: "offers_callbacks_pk"
|
|
3663
3797
|
})]);
|
|
3664
3798
|
const callbacks = s.table(EnumTableName.CALLBACKS, {
|
|
@@ -3666,23 +3800,25 @@ const callbacks = s.table(EnumTableName.CALLBACKS, {
|
|
|
3666
3800
|
positionChainId: bigint("position_chain_id", { mode: "number" }).$type().notNull(),
|
|
3667
3801
|
positionContract: varchar("position_contract", { length: 42 }).notNull(),
|
|
3668
3802
|
positionUser: varchar("position_user", { length: 42 }).notNull(),
|
|
3803
|
+
positionTypeId: integer("position_type_id").notNull().references(() => positionTypes.id, { onDelete: "no action" }),
|
|
3669
3804
|
amount: numeric("amount", {
|
|
3670
3805
|
precision: 78,
|
|
3671
3806
|
scale: 0
|
|
3672
3807
|
})
|
|
3673
|
-
}
|
|
3808
|
+
});
|
|
3809
|
+
const lotsPositions = s.table(EnumTableName.LOTS_POSITIONS, {
|
|
3810
|
+
chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
|
|
3811
|
+
contract: varchar("contract", { length: 42 }).notNull(),
|
|
3812
|
+
user: varchar("user", { length: 42 }).notNull(),
|
|
3813
|
+
positionTypeId: integer("position_type_id").notNull().references(() => positionTypes.id, { onDelete: "no action" })
|
|
3814
|
+
}, (table) => [primaryKey({
|
|
3674
3815
|
columns: [
|
|
3675
|
-
table.
|
|
3676
|
-
table.
|
|
3677
|
-
table.
|
|
3678
|
-
],
|
|
3679
|
-
foreignColumns: [
|
|
3680
|
-
positions.chainId,
|
|
3681
|
-
positions.contract,
|
|
3682
|
-
positions.user
|
|
3816
|
+
table.chainId,
|
|
3817
|
+
table.contract,
|
|
3818
|
+
table.user
|
|
3683
3819
|
],
|
|
3684
|
-
name: "
|
|
3685
|
-
})
|
|
3820
|
+
name: "lots_positions_pk"
|
|
3821
|
+
})]);
|
|
3686
3822
|
const lots = s.table(EnumTableName.LOTS, {
|
|
3687
3823
|
chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
|
|
3688
3824
|
user: varchar("user", { length: 42 }).notNull(),
|
|
@@ -3715,11 +3851,11 @@ const lots = s.table(EnumTableName.LOTS, {
|
|
|
3715
3851
|
table.user
|
|
3716
3852
|
],
|
|
3717
3853
|
foreignColumns: [
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3854
|
+
lotsPositions.chainId,
|
|
3855
|
+
lotsPositions.contract,
|
|
3856
|
+
lotsPositions.user
|
|
3721
3857
|
],
|
|
3722
|
-
name: "
|
|
3858
|
+
name: "lots_lots_positions_fk"
|
|
3723
3859
|
}).onDelete("cascade"),
|
|
3724
3860
|
foreignKey({
|
|
3725
3861
|
columns: [
|
|
@@ -3761,11 +3897,11 @@ const offsets = s.table(EnumTableName.OFFSETS, {
|
|
|
3761
3897
|
table.user
|
|
3762
3898
|
],
|
|
3763
3899
|
foreignColumns: [
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3900
|
+
lotsPositions.chainId,
|
|
3901
|
+
lotsPositions.contract,
|
|
3902
|
+
lotsPositions.user
|
|
3767
3903
|
],
|
|
3768
|
-
name: "
|
|
3904
|
+
name: "offsets_lots_positions_fk"
|
|
3769
3905
|
}).onDelete("cascade")]);
|
|
3770
3906
|
const PositionTypes = s.enum("position_type", Object.values(Type));
|
|
3771
3907
|
const positionTypes = s.table("position_types", {
|
|
@@ -3774,34 +3910,38 @@ const positionTypes = s.table("position_types", {
|
|
|
3774
3910
|
});
|
|
3775
3911
|
const positions = s.table(EnumTableName.POSITIONS, {
|
|
3776
3912
|
chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
|
|
3777
|
-
contract: varchar("contract", { length:
|
|
3913
|
+
contract: varchar("contract", { length: 66 }).notNull(),
|
|
3778
3914
|
user: varchar("user", { length: 42 }).notNull(),
|
|
3779
3915
|
positionTypeId: integer("position_type_id").notNull().references(() => positionTypes.id, { onDelete: "no action" }),
|
|
3780
3916
|
balance: numeric("balance", {
|
|
3781
3917
|
precision: 78,
|
|
3782
3918
|
scale: 0
|
|
3783
3919
|
}),
|
|
3784
|
-
asset: varchar("asset", { length: 42 }),
|
|
3920
|
+
asset: varchar("asset", { length: 42 }).notNull(),
|
|
3785
3921
|
blockNumber: bigint("block_number", { mode: "number" }).notNull(),
|
|
3786
3922
|
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
3787
3923
|
}, (table) => [primaryKey({
|
|
3788
3924
|
columns: [
|
|
3789
3925
|
table.chainId,
|
|
3790
3926
|
table.contract,
|
|
3791
|
-
table.user
|
|
3927
|
+
table.user,
|
|
3928
|
+
table.positionTypeId,
|
|
3929
|
+
table.asset
|
|
3792
3930
|
],
|
|
3793
3931
|
name: "positions_pk"
|
|
3794
3932
|
})]);
|
|
3795
3933
|
const transfers = s.table(EnumTableName.TRANSFERS, {
|
|
3796
3934
|
eventId: varchar("event_id", { length: 128 }).primaryKey(),
|
|
3797
3935
|
chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
|
|
3798
|
-
contract: varchar("contract", { length:
|
|
3936
|
+
contract: varchar("contract", { length: 66 }).notNull(),
|
|
3799
3937
|
from: varchar("from", { length: 42 }).notNull(),
|
|
3800
3938
|
to: varchar("to", { length: 42 }).notNull(),
|
|
3801
3939
|
value: numeric("value", {
|
|
3802
3940
|
precision: 78,
|
|
3803
3941
|
scale: 0
|
|
3804
3942
|
}).notNull(),
|
|
3943
|
+
positionTypeId: integer("position_type_id").notNull().references(() => positionTypes.id, { onDelete: "no action" }),
|
|
3944
|
+
asset: varchar("asset", { length: 42 }).notNull(),
|
|
3805
3945
|
blockNumber: bigint("block_number", { mode: "number" }).notNull(),
|
|
3806
3946
|
createdAt: timestamp("created_at").defaultNow().notNull()
|
|
3807
3947
|
}, (table) => [
|
|
@@ -3809,12 +3949,16 @@ const transfers = s.table(EnumTableName.TRANSFERS, {
|
|
|
3809
3949
|
columns: [
|
|
3810
3950
|
table.chainId,
|
|
3811
3951
|
table.contract,
|
|
3812
|
-
table.from
|
|
3952
|
+
table.from,
|
|
3953
|
+
table.positionTypeId,
|
|
3954
|
+
table.asset
|
|
3813
3955
|
],
|
|
3814
3956
|
foreignColumns: [
|
|
3815
3957
|
positions.chainId,
|
|
3816
3958
|
positions.contract,
|
|
3817
|
-
positions.user
|
|
3959
|
+
positions.user,
|
|
3960
|
+
positions.positionTypeId,
|
|
3961
|
+
positions.asset
|
|
3818
3962
|
],
|
|
3819
3963
|
name: "transfers_positions_from_fk"
|
|
3820
3964
|
}).onDelete("cascade"),
|
|
@@ -3822,16 +3966,21 @@ const transfers = s.table(EnumTableName.TRANSFERS, {
|
|
|
3822
3966
|
columns: [
|
|
3823
3967
|
table.chainId,
|
|
3824
3968
|
table.contract,
|
|
3825
|
-
table.to
|
|
3969
|
+
table.to,
|
|
3970
|
+
table.positionTypeId,
|
|
3971
|
+
table.asset
|
|
3826
3972
|
],
|
|
3827
3973
|
foreignColumns: [
|
|
3828
3974
|
positions.chainId,
|
|
3829
3975
|
positions.contract,
|
|
3830
|
-
positions.user
|
|
3976
|
+
positions.user,
|
|
3977
|
+
positions.positionTypeId,
|
|
3978
|
+
positions.asset
|
|
3831
3979
|
],
|
|
3832
3980
|
name: "transfers_positions_to_fk"
|
|
3833
3981
|
}).onDelete("cascade"),
|
|
3834
|
-
index("transfers_chain_contract_user_idx").on(table.chainId, table.contract, table.from, table.to, table.blockNumber)
|
|
3982
|
+
index("transfers_chain_contract_user_idx").on(table.chainId, table.contract, table.from, table.to, table.blockNumber),
|
|
3983
|
+
index("transfers_chain_type_block_idx").on(table.chainId, table.positionTypeId, table.blockNumber)
|
|
3835
3984
|
]);
|
|
3836
3985
|
const StatusCode = s.enum("status_code", Object.values(Status));
|
|
3837
3986
|
const status = s.table("status", {
|
|
@@ -3839,12 +3988,20 @@ const status = s.table("status", {
|
|
|
3839
3988
|
code: StatusCode("code").unique()
|
|
3840
3989
|
});
|
|
3841
3990
|
const validations = s.table("validations", {
|
|
3842
|
-
offerHash: varchar("offer_hash", { length: 66 }).
|
|
3991
|
+
offerHash: varchar("offer_hash", { length: 66 }).notNull(),
|
|
3992
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
3843
3993
|
statusId: integer("status_id").notNull().references(() => status.id, { onDelete: "no action" }),
|
|
3844
3994
|
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
3845
|
-
})
|
|
3995
|
+
}, (table) => [primaryKey({
|
|
3996
|
+
columns: [table.offerHash, table.obligationId],
|
|
3997
|
+
name: "validations_pk"
|
|
3998
|
+
}), foreignKey({
|
|
3999
|
+
columns: [table.offerHash, table.obligationId],
|
|
4000
|
+
foreignColumns: [offers.hash, offers.obligationId],
|
|
4001
|
+
name: "validations_offer_fk"
|
|
4002
|
+
}).onDelete("cascade")]);
|
|
3846
4003
|
const collectors = s.table(EnumTableName.COLLECTORS, {
|
|
3847
|
-
chainId: bigint("chain_id", { mode: "number" }).$type().notNull().references(() => chains
|
|
4004
|
+
chainId: bigint("chain_id", { mode: "number" }).$type().notNull().references(() => chains.chainId, { onDelete: "no action" }),
|
|
3848
4005
|
name: text("name").$type().notNull(),
|
|
3849
4006
|
blockNumber: bigint("block_number", { mode: "number" }).notNull(),
|
|
3850
4007
|
epoch: numeric("epoch", {
|
|
@@ -3853,7 +4010,7 @@ const collectors = s.table(EnumTableName.COLLECTORS, {
|
|
|
3853
4010
|
}).default("0").notNull(),
|
|
3854
4011
|
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
3855
4012
|
}, (table) => [uniqueIndex("collectors_chain_name_idx").on(table.chainId, table.name)]);
|
|
3856
|
-
const chains
|
|
4013
|
+
const chains = s.table(EnumTableName.CHAINS, {
|
|
3857
4014
|
chainId: bigint("chain_id", { mode: "number" }).$type().notNull(),
|
|
3858
4015
|
blockNumber: bigint("block_number", { mode: "number" }).notNull(),
|
|
3859
4016
|
epoch: numeric("epoch", {
|
|
@@ -3868,18 +4025,352 @@ const trees = s.table(EnumTableName.TREES, {
|
|
|
3868
4025
|
createdAt: timestamp("created_at").defaultNow().notNull()
|
|
3869
4026
|
});
|
|
3870
4027
|
const merklePaths = s.table(EnumTableName.MERKLE_PATHS, {
|
|
3871
|
-
offerHash: varchar("offer_hash", { length: 66 }).
|
|
4028
|
+
offerHash: varchar("offer_hash", { length: 66 }).notNull(),
|
|
4029
|
+
obligationId: varchar("obligation_id", { length: 66 }).notNull(),
|
|
3872
4030
|
treeRoot: varchar("tree_root", { length: 66 }).notNull().references(() => trees.root, { onDelete: "cascade" }),
|
|
3873
4031
|
proofNodes: text("proof_nodes").notNull(),
|
|
3874
4032
|
createdAt: timestamp("created_at").defaultNow().notNull()
|
|
3875
|
-
}, (table) => [
|
|
4033
|
+
}, (table) => [
|
|
4034
|
+
primaryKey({
|
|
4035
|
+
columns: [table.offerHash, table.obligationId],
|
|
4036
|
+
name: "merkle_paths_pk"
|
|
4037
|
+
}),
|
|
4038
|
+
foreignKey({
|
|
4039
|
+
columns: [table.offerHash, table.obligationId],
|
|
4040
|
+
foreignColumns: [offers.hash, offers.obligationId],
|
|
4041
|
+
name: "merkle_paths_offer_fk"
|
|
4042
|
+
}).onDelete("cascade"),
|
|
4043
|
+
index("merkle_paths_tree_root_idx").on(table.treeRoot)
|
|
4044
|
+
]);
|
|
4045
|
+
|
|
4046
|
+
//#endregion
|
|
4047
|
+
//#region src/indexer/collectors/CollectFunctions/processors/processCollateralSeizures.ts
|
|
4048
|
+
/**
|
|
4049
|
+
* Parse raw MorphoV2 liquidate logs and compute collateral seizures.
|
|
4050
|
+
*
|
|
4051
|
+
* Seizures only expose `(obligationId, collateralIndex)` and must be resolved
|
|
4052
|
+
* to collateral token addresses before creating transfer rows.
|
|
4053
|
+
*
|
|
4054
|
+
* @param parameters - The parsed event logs and chain ID.
|
|
4055
|
+
* @param parameters.logs - Parsed event logs from MorphoV2.
|
|
4056
|
+
* @param parameters.chainId - Chain ID for event attribution.
|
|
4057
|
+
* @returns Seizure events pending collateral address resolution.
|
|
4058
|
+
*/
|
|
4059
|
+
function processCollateralSeizures(parameters) {
|
|
4060
|
+
const { logs, chainId } = parameters;
|
|
4061
|
+
const logger = getLogger();
|
|
4062
|
+
const seizureEvents = [];
|
|
4063
|
+
for (const rawLog of logs) {
|
|
4064
|
+
if (rawLog.blockNumber === null || rawLog.logIndex === null || rawLog.transactionHash === null) {
|
|
4065
|
+
logger.debug({
|
|
4066
|
+
chainId,
|
|
4067
|
+
msg: "Skipping collateral log because it is missing required fields"
|
|
4068
|
+
});
|
|
4069
|
+
continue;
|
|
4070
|
+
}
|
|
4071
|
+
if (rawLog.eventName !== liquidateEvent.name) continue;
|
|
4072
|
+
const args = rawLog.args;
|
|
4073
|
+
if (args?.id === void 0 || args?.borrower === void 0 || args?.seizures === void 0) {
|
|
4074
|
+
logger.debug({
|
|
4075
|
+
chainId,
|
|
4076
|
+
msg: "Skipping Liquidate log for collateral because it is missing required args"
|
|
4077
|
+
});
|
|
4078
|
+
continue;
|
|
4079
|
+
}
|
|
4080
|
+
const baseId = `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${chainId}-${rawLog.transactionHash}`;
|
|
4081
|
+
for (let seizureIndex = 0; seizureIndex < args.seizures.length; seizureIndex++) {
|
|
4082
|
+
const seizure = args.seizures[seizureIndex];
|
|
4083
|
+
if (seizure.seized === 0n) continue;
|
|
4084
|
+
seizureEvents.push({
|
|
4085
|
+
id: `${baseId}-collateral-liquidate-${seizureIndex}`,
|
|
4086
|
+
chainId,
|
|
4087
|
+
obligationId: args.id,
|
|
4088
|
+
collateralIndex: Number(seizure.collateralIndex),
|
|
4089
|
+
user: args.borrower,
|
|
4090
|
+
amount: seizure.seized,
|
|
4091
|
+
blockNumber: Number(rawLog.blockNumber)
|
|
4092
|
+
});
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
return seizureEvents;
|
|
4096
|
+
}
|
|
4097
|
+
|
|
4098
|
+
//#endregion
|
|
4099
|
+
//#region src/indexer/collectors/CollectFunctions/processors/processCollateralTransfers.ts
|
|
4100
|
+
/**
|
|
4101
|
+
* Parse raw MorphoV2 logs and compute collateral transfers.
|
|
4102
|
+
*
|
|
4103
|
+
* A collateral position uses `contract = obligationId` and `asset = collateral token address`.
|
|
4104
|
+
* The 5-col PK `(chainId, contract, user, positionTypeId, asset)` distinguishes per-token positions.
|
|
4105
|
+
*
|
|
4106
|
+
* **SupplyCollateral**: Transfer from zeroAddress to onBehalf (supply)
|
|
4107
|
+
* **WithdrawCollateral**: Transfer from onBehalf to zeroAddress (withdrawal)
|
|
4108
|
+
*
|
|
4109
|
+
* @param parameters - The parsed event logs and chain ID.
|
|
4110
|
+
* @param parameters.logs - Parsed event logs from MorphoV2.
|
|
4111
|
+
* @param parameters.chainId - Chain ID for event attribution.
|
|
4112
|
+
* @returns Collateral transfers from SupplyCollateral/WithdrawCollateral.
|
|
4113
|
+
*/
|
|
4114
|
+
function processCollateralTransfers(parameters) {
|
|
4115
|
+
const { logs, chainId } = parameters;
|
|
4116
|
+
const logger = getLogger();
|
|
4117
|
+
const transfers = [];
|
|
4118
|
+
for (const rawLog of logs) {
|
|
4119
|
+
if (rawLog.blockNumber === null || rawLog.logIndex === null || rawLog.transactionHash === null) {
|
|
4120
|
+
logger.debug({
|
|
4121
|
+
chainId,
|
|
4122
|
+
msg: "Skipping collateral log because it is missing required fields"
|
|
4123
|
+
});
|
|
4124
|
+
continue;
|
|
4125
|
+
}
|
|
4126
|
+
const eventName = rawLog.eventName;
|
|
4127
|
+
const baseId = `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${chainId}-${rawLog.transactionHash}`;
|
|
4128
|
+
if (eventName === supplyCollateralEvent.name) {
|
|
4129
|
+
const args = rawLog.args;
|
|
4130
|
+
if (args?.id === void 0 || args?.collateral === void 0 || args?.assets === void 0 || args?.onBehalf === void 0) {
|
|
4131
|
+
logger.debug({
|
|
4132
|
+
chainId,
|
|
4133
|
+
msg: "Skipping SupplyCollateral log because it is missing required args"
|
|
4134
|
+
});
|
|
4135
|
+
continue;
|
|
4136
|
+
}
|
|
4137
|
+
if (args.assets === 0n) continue;
|
|
4138
|
+
transfers.push(from$9({
|
|
4139
|
+
id: `${baseId}-collateral-supply`,
|
|
4140
|
+
chainId,
|
|
4141
|
+
contract: args.id,
|
|
4142
|
+
from: zeroAddress,
|
|
4143
|
+
to: args.onBehalf,
|
|
4144
|
+
value: args.assets,
|
|
4145
|
+
type: Type.COLLATERAL_OF,
|
|
4146
|
+
asset: args.collateral,
|
|
4147
|
+
blockNumber: Number(rawLog.blockNumber)
|
|
4148
|
+
}));
|
|
4149
|
+
continue;
|
|
4150
|
+
}
|
|
4151
|
+
if (eventName === withdrawCollateralEvent.name) {
|
|
4152
|
+
const args = rawLog.args;
|
|
4153
|
+
if (args?.id === void 0 || args?.collateral === void 0 || args?.assets === void 0 || args?.onBehalf === void 0) {
|
|
4154
|
+
logger.debug({
|
|
4155
|
+
chainId,
|
|
4156
|
+
msg: "Skipping WithdrawCollateral log because it is missing required args"
|
|
4157
|
+
});
|
|
4158
|
+
continue;
|
|
4159
|
+
}
|
|
4160
|
+
if (args.assets === 0n) continue;
|
|
4161
|
+
transfers.push(from$9({
|
|
4162
|
+
id: `${baseId}-collateral-withdraw`,
|
|
4163
|
+
chainId,
|
|
4164
|
+
contract: args.id,
|
|
4165
|
+
from: args.onBehalf,
|
|
4166
|
+
to: zeroAddress,
|
|
4167
|
+
value: args.assets,
|
|
4168
|
+
type: Type.COLLATERAL_OF,
|
|
4169
|
+
asset: args.collateral,
|
|
4170
|
+
blockNumber: Number(rawLog.blockNumber)
|
|
4171
|
+
}));
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
return transfers;
|
|
4175
|
+
}
|
|
3876
4176
|
|
|
3877
4177
|
//#endregion
|
|
3878
|
-
//#region src/indexer/collectors/CollectFunctions/
|
|
4178
|
+
//#region src/indexer/collectors/CollectFunctions/processors/processConsumedLogs.ts
|
|
3879
4179
|
const buildGroupKey = (parameters) => {
|
|
3880
4180
|
return `${parameters.chainId}-${parameters.maker.toLowerCase()}-${parameters.group.toLowerCase()}`;
|
|
3881
4181
|
};
|
|
3882
|
-
|
|
4182
|
+
/** Parse raw MorphoV2 logs and produce normalized consumed events.
|
|
4183
|
+
* @param parameters - The parsed event logs and chain ID.
|
|
4184
|
+
* @param parameters.logs - Parsed event logs from MorphoV2 (Consume and Take events).
|
|
4185
|
+
* @param parameters.chainId - Chain ID for event attribution.
|
|
4186
|
+
* @returns Flat array of consumed events.
|
|
4187
|
+
*/
|
|
4188
|
+
function processConsumedLogs(parameters) {
|
|
4189
|
+
const { logs, chainId } = parameters;
|
|
4190
|
+
const logger = getLogger();
|
|
4191
|
+
const consumedEvents = [];
|
|
4192
|
+
for (const rawLog of logs) {
|
|
4193
|
+
if (rawLog.blockNumber === null || rawLog.logIndex === null || rawLog.transactionHash === null) {
|
|
4194
|
+
logger.debug({
|
|
4195
|
+
chainId,
|
|
4196
|
+
msg: "Skipping log because it is missing required fields"
|
|
4197
|
+
});
|
|
4198
|
+
continue;
|
|
4199
|
+
}
|
|
4200
|
+
const eventName = rawLog.eventName;
|
|
4201
|
+
if (eventName === consumedEvent.name) {
|
|
4202
|
+
const consumeArgs = rawLog.args;
|
|
4203
|
+
if (consumeArgs?.user === void 0 || consumeArgs?.group === void 0 || consumeArgs?.amount === void 0) {
|
|
4204
|
+
logger.debug({
|
|
4205
|
+
chainId,
|
|
4206
|
+
msg: "Skipping Consume log because it is missing required args"
|
|
4207
|
+
});
|
|
4208
|
+
continue;
|
|
4209
|
+
}
|
|
4210
|
+
consumedEvents.push({
|
|
4211
|
+
kind: "consume",
|
|
4212
|
+
id: `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${chainId}-${rawLog.transactionHash}`,
|
|
4213
|
+
chainId,
|
|
4214
|
+
maker: consumeArgs.user,
|
|
4215
|
+
group: consumeArgs.group,
|
|
4216
|
+
amount: consumeArgs.amount,
|
|
4217
|
+
blockNumber: Number(rawLog.blockNumber)
|
|
4218
|
+
});
|
|
4219
|
+
continue;
|
|
4220
|
+
}
|
|
4221
|
+
if (eventName === takeEvent.name) {
|
|
4222
|
+
const takeArgs = rawLog.args;
|
|
4223
|
+
if (takeArgs?.maker === void 0 || takeArgs?.group === void 0 || takeArgs?.consumed === void 0) {
|
|
4224
|
+
logger.debug({
|
|
4225
|
+
chainId,
|
|
4226
|
+
msg: "Skipping Take log because it is missing required args for consumed"
|
|
4227
|
+
});
|
|
4228
|
+
continue;
|
|
4229
|
+
}
|
|
4230
|
+
consumedEvents.push({
|
|
4231
|
+
kind: "take",
|
|
4232
|
+
id: `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${chainId}-${rawLog.transactionHash}`,
|
|
4233
|
+
chainId,
|
|
4234
|
+
maker: takeArgs.maker,
|
|
4235
|
+
group: takeArgs.group,
|
|
4236
|
+
consumed: takeArgs.consumed,
|
|
4237
|
+
blockNumber: Number(rawLog.blockNumber)
|
|
4238
|
+
});
|
|
4239
|
+
}
|
|
4240
|
+
}
|
|
4241
|
+
return consumedEvents;
|
|
4242
|
+
}
|
|
4243
|
+
|
|
4244
|
+
//#endregion
|
|
4245
|
+
//#region src/indexer/collectors/CollectFunctions/processors/processDebtTransfers.ts
|
|
4246
|
+
/**
|
|
4247
|
+
* Parse raw MorphoV2 logs and compute debt transfers.
|
|
4248
|
+
*
|
|
4249
|
+
* A debt is modeled as a negative position: borrowing = transfer FROM user TO zeroAddress,
|
|
4250
|
+
* repayment = FROM zeroAddress TO user. The contract field is the obligationId.
|
|
4251
|
+
*
|
|
4252
|
+
* Applies the 4-case Take matrix, Repay, and Liquidate attribution rules:
|
|
4253
|
+
*
|
|
4254
|
+
* **Take event** — Buyer = maker if offerIsBuy, taker otherwise. Seller = the other.
|
|
4255
|
+
* | buyerIsLender | sellerIsBorrower | Buyer transfer | Seller transfer |
|
|
4256
|
+
* |---------------|------------------|------------------------------|------------------------------|
|
|
4257
|
+
* | true | true | none | from: seller → to: 0x0 |
|
|
4258
|
+
* | true | false | none | none |
|
|
4259
|
+
* | false | true | from: 0x0 → to: buyer | from: seller → to: 0x0 |
|
|
4260
|
+
* | false | false | from: 0x0 → to: buyer | none |
|
|
4261
|
+
*
|
|
4262
|
+
* **Repay**: from: 0x0 → to: onBehalf
|
|
4263
|
+
* **Liquidate**: from: 0x0 → to: borrower (value = totalRepaid + badDebt)
|
|
4264
|
+
*
|
|
4265
|
+
* @param parameters - The parsed event logs and chain ID.
|
|
4266
|
+
* @param parameters.logs - Parsed event logs from MorphoV2 (Take, Repay, Liquidate events).
|
|
4267
|
+
* @param parameters.chainId - Chain ID for event attribution.
|
|
4268
|
+
* @returns Transfer events ready for DB insertion.
|
|
4269
|
+
*/
|
|
4270
|
+
function processDebtTransfers(parameters) {
|
|
4271
|
+
const { logs, chainId } = parameters;
|
|
4272
|
+
const logger = getLogger();
|
|
4273
|
+
const transfers = [];
|
|
4274
|
+
for (const rawLog of logs) {
|
|
4275
|
+
if (rawLog.blockNumber === null || rawLog.logIndex === null || rawLog.transactionHash === null) {
|
|
4276
|
+
logger.debug({
|
|
4277
|
+
chainId,
|
|
4278
|
+
msg: "Skipping debt log because it is missing required fields"
|
|
4279
|
+
});
|
|
4280
|
+
continue;
|
|
4281
|
+
}
|
|
4282
|
+
const eventName = rawLog.eventName;
|
|
4283
|
+
const baseId = `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${chainId}-${rawLog.transactionHash}`;
|
|
4284
|
+
if (eventName === takeEvent.name) {
|
|
4285
|
+
const args = rawLog.args;
|
|
4286
|
+
if (args?.id === void 0 || args?.maker === void 0 || args?.taker === void 0 || args?.offerIsBuy === void 0 || args?.obligationUnits === void 0 || args?.buyerIsLender === void 0 || args?.sellerIsBorrower === void 0) {
|
|
4287
|
+
logger.debug({
|
|
4288
|
+
chainId,
|
|
4289
|
+
msg: "Skipping Take log because it is missing required args for debt"
|
|
4290
|
+
});
|
|
4291
|
+
continue;
|
|
4292
|
+
}
|
|
4293
|
+
if (args.obligationUnits === 0n) continue;
|
|
4294
|
+
const buyer = args.offerIsBuy ? args.maker : args.taker;
|
|
4295
|
+
const seller = args.offerIsBuy ? args.taker : args.maker;
|
|
4296
|
+
const blockNumber = Number(rawLog.blockNumber);
|
|
4297
|
+
if (!args.buyerIsLender) transfers.push(from$9({
|
|
4298
|
+
id: `${baseId}-debt-buyer`,
|
|
4299
|
+
chainId,
|
|
4300
|
+
contract: args.id,
|
|
4301
|
+
from: zeroAddress,
|
|
4302
|
+
to: buyer,
|
|
4303
|
+
value: args.obligationUnits,
|
|
4304
|
+
type: Type.DEBT_OF,
|
|
4305
|
+
asset: zeroAddress,
|
|
4306
|
+
blockNumber
|
|
4307
|
+
}));
|
|
4308
|
+
if (args.sellerIsBorrower) transfers.push(from$9({
|
|
4309
|
+
id: `${baseId}-debt-seller`,
|
|
4310
|
+
chainId,
|
|
4311
|
+
contract: args.id,
|
|
4312
|
+
from: seller,
|
|
4313
|
+
to: zeroAddress,
|
|
4314
|
+
value: args.obligationUnits,
|
|
4315
|
+
type: Type.DEBT_OF,
|
|
4316
|
+
asset: zeroAddress,
|
|
4317
|
+
blockNumber
|
|
4318
|
+
}));
|
|
4319
|
+
continue;
|
|
4320
|
+
}
|
|
4321
|
+
if (eventName === repayEvent.name) {
|
|
4322
|
+
const args = rawLog.args;
|
|
4323
|
+
if (args?.id === void 0 || args?.obligationUnits === void 0 || args?.onBehalf === void 0) {
|
|
4324
|
+
logger.debug({
|
|
4325
|
+
chainId,
|
|
4326
|
+
msg: "Skipping Repay log because it is missing required args"
|
|
4327
|
+
});
|
|
4328
|
+
continue;
|
|
4329
|
+
}
|
|
4330
|
+
if (args.obligationUnits === 0n) continue;
|
|
4331
|
+
transfers.push(from$9({
|
|
4332
|
+
id: `${baseId}-debt-repay`,
|
|
4333
|
+
chainId,
|
|
4334
|
+
contract: args.id,
|
|
4335
|
+
from: zeroAddress,
|
|
4336
|
+
to: args.onBehalf,
|
|
4337
|
+
value: args.obligationUnits,
|
|
4338
|
+
type: Type.DEBT_OF,
|
|
4339
|
+
asset: zeroAddress,
|
|
4340
|
+
blockNumber: Number(rawLog.blockNumber)
|
|
4341
|
+
}));
|
|
4342
|
+
continue;
|
|
4343
|
+
}
|
|
4344
|
+
if (eventName === liquidateEvent.name) {
|
|
4345
|
+
const args = rawLog.args;
|
|
4346
|
+
if (args?.id === void 0 || args?.borrower === void 0 || args?.totalRepaid === void 0 || args?.badDebt === void 0) {
|
|
4347
|
+
logger.debug({
|
|
4348
|
+
chainId,
|
|
4349
|
+
msg: "Skipping Liquidate log because it is missing required args"
|
|
4350
|
+
});
|
|
4351
|
+
continue;
|
|
4352
|
+
}
|
|
4353
|
+
const totalReduction = args.totalRepaid + args.badDebt;
|
|
4354
|
+
if (totalReduction === 0n) continue;
|
|
4355
|
+
transfers.push(from$9({
|
|
4356
|
+
id: `${baseId}-debt-liquidate`,
|
|
4357
|
+
chainId,
|
|
4358
|
+
contract: args.id,
|
|
4359
|
+
from: zeroAddress,
|
|
4360
|
+
to: args.borrower,
|
|
4361
|
+
value: totalReduction,
|
|
4362
|
+
type: Type.DEBT_OF,
|
|
4363
|
+
asset: zeroAddress,
|
|
4364
|
+
blockNumber: Number(rawLog.blockNumber)
|
|
4365
|
+
}));
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
return transfers;
|
|
4369
|
+
}
|
|
4370
|
+
|
|
4371
|
+
//#endregion
|
|
4372
|
+
//#region src/indexer/collectors/CollectFunctions/collectMorphoV2.ts
|
|
4373
|
+
async function* collectMorphoV2(parameters) {
|
|
3883
4374
|
let { db, collector, client, lastBlockNumber: blockNumber, epoch, options: { maxBatchSize = 1e3, blockWindow } = {} } = parameters;
|
|
3884
4375
|
const logger = getLogger();
|
|
3885
4376
|
let startBlock = blockNumber;
|
|
@@ -3898,179 +4389,63 @@ async function* collectConsumedEvents(parameters) {
|
|
|
3898
4389
|
});
|
|
3899
4390
|
for await (const { logs, blockNumber: lastStreamBlockNumber } of stream) {
|
|
3900
4391
|
const parsedLogs = parseEventLogs({
|
|
3901
|
-
abi: [
|
|
4392
|
+
abi: [
|
|
4393
|
+
consumedEvent,
|
|
4394
|
+
takeEvent,
|
|
4395
|
+
repayEvent,
|
|
4396
|
+
liquidateEvent,
|
|
4397
|
+
supplyCollateralEvent,
|
|
4398
|
+
withdrawCollateralEvent
|
|
4399
|
+
],
|
|
3902
4400
|
logs,
|
|
3903
4401
|
strict: false
|
|
3904
4402
|
});
|
|
3905
|
-
const
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
};
|
|
3922
|
-
for (const rawLog of parsedLogs) {
|
|
3923
|
-
if (rawLog.blockNumber === null || rawLog.logIndex === null || rawLog.transactionHash === null) {
|
|
3924
|
-
logger.debug({
|
|
3925
|
-
collector,
|
|
3926
|
-
chainId: client.chain.id,
|
|
3927
|
-
msg: "Skipping log because it is missing required fields"
|
|
3928
|
-
});
|
|
3929
|
-
continue;
|
|
3930
|
-
}
|
|
3931
|
-
if (rawLog.eventName === consumedEvent.name) {
|
|
3932
|
-
const consumeArgs = rawLog.args;
|
|
3933
|
-
if (consumeArgs.user === void 0 || consumeArgs.group === void 0 || consumeArgs.amount === void 0) {
|
|
3934
|
-
logger.debug({
|
|
3935
|
-
collector,
|
|
3936
|
-
chainId: client.chain.id,
|
|
3937
|
-
msg: "Skipping Consume log because it is missing required args"
|
|
3938
|
-
});
|
|
3939
|
-
continue;
|
|
3940
|
-
}
|
|
3941
|
-
recordLog({
|
|
3942
|
-
kind: "consume",
|
|
3943
|
-
id: `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${client.chain.id}-${rawLog.transactionHash}`,
|
|
3944
|
-
chainId: client.chain.id,
|
|
3945
|
-
maker: consumeArgs.user,
|
|
3946
|
-
group: consumeArgs.group,
|
|
3947
|
-
amount: consumeArgs.amount,
|
|
3948
|
-
blockNumber: Number(rawLog.blockNumber)
|
|
3949
|
-
});
|
|
3950
|
-
continue;
|
|
3951
|
-
}
|
|
3952
|
-
if (rawLog.eventName === takeEvent.name) {
|
|
3953
|
-
const takeArgs = rawLog.args;
|
|
3954
|
-
if (takeArgs.maker === void 0 || takeArgs.group === void 0 || takeArgs.consumed === void 0) {
|
|
3955
|
-
logger.debug({
|
|
3956
|
-
collector,
|
|
3957
|
-
chainId: client.chain.id,
|
|
3958
|
-
msg: "Skipping Take log because it is missing required args"
|
|
3959
|
-
});
|
|
3960
|
-
continue;
|
|
3961
|
-
}
|
|
3962
|
-
recordLog({
|
|
3963
|
-
kind: "take",
|
|
3964
|
-
id: `${rawLog.blockNumber.toString()}-${rawLog.logIndex.toString()}-${client.chain.id}-${rawLog.transactionHash}`,
|
|
3965
|
-
chainId: client.chain.id,
|
|
3966
|
-
maker: takeArgs.maker,
|
|
3967
|
-
group: takeArgs.group,
|
|
3968
|
-
consumed: takeArgs.consumed,
|
|
3969
|
-
blockNumber: Number(rawLog.blockNumber)
|
|
3970
|
-
});
|
|
3971
|
-
}
|
|
3972
|
-
}
|
|
4403
|
+
const consumedEvents = processConsumedLogs({
|
|
4404
|
+
logs: parsedLogs,
|
|
4405
|
+
chainId: client.chain.id
|
|
4406
|
+
});
|
|
4407
|
+
const debtTransfers = processDebtTransfers({
|
|
4408
|
+
logs: parsedLogs,
|
|
4409
|
+
chainId: client.chain.id
|
|
4410
|
+
});
|
|
4411
|
+
const collateralTransfers = processCollateralTransfers({
|
|
4412
|
+
logs: parsedLogs,
|
|
4413
|
+
chainId: client.chain.id
|
|
4414
|
+
});
|
|
4415
|
+
const seizureEvents = processCollateralSeizures({
|
|
4416
|
+
logs: parsedLogs,
|
|
4417
|
+
chainId: client.chain.id
|
|
4418
|
+
});
|
|
3973
4419
|
await db.transaction(async (dbTx) => {
|
|
3974
|
-
const
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
const consumedByGroup = /* @__PURE__ */ new Map();
|
|
3988
|
-
if (groups$3.size > 0) {
|
|
3989
|
-
const groupList = Array.from(groups$3.values());
|
|
3990
|
-
for (let index = 0; index < groupList.length; index += 500) {
|
|
3991
|
-
const slice = groupList.slice(index, index + 500);
|
|
3992
|
-
const { rows } = await dbTx.execute(sql`
|
|
3993
|
-
WITH targets(chain_id, maker, "group") AS (
|
|
3994
|
-
VALUES ${sql.join(slice.map((group) => sql`(${group.chainId}::bigint, ${group.maker.toLowerCase()}::varchar(42), ${group.group.toLowerCase()}::varchar(66))`), sql`,`)}
|
|
3995
|
-
)
|
|
3996
|
-
SELECT
|
|
3997
|
-
targets.chain_id,
|
|
3998
|
-
targets.maker,
|
|
3999
|
-
targets."group",
|
|
4000
|
-
COALESCE(g.consumed, 0)::numeric AS consumed
|
|
4001
|
-
FROM targets
|
|
4002
|
-
LEFT JOIN ${groups} g
|
|
4003
|
-
ON g.chain_id = targets.chain_id
|
|
4004
|
-
AND g.maker = targets.maker
|
|
4005
|
-
AND g."group" = targets."group";
|
|
4006
|
-
`);
|
|
4007
|
-
for (const row of rows) {
|
|
4008
|
-
const groupKey = buildGroupKey({
|
|
4009
|
-
chainId: Number(row.chain_id),
|
|
4010
|
-
maker: row.maker,
|
|
4011
|
-
group: row.group
|
|
4012
|
-
});
|
|
4013
|
-
consumedByGroup.set(groupKey, BigInt(row.consumed ?? "0"));
|
|
4014
|
-
}
|
|
4015
|
-
}
|
|
4016
|
-
}
|
|
4017
|
-
const events = [];
|
|
4018
|
-
for (const log of normalizedLogs) {
|
|
4019
|
-
if (existingEventIds.has(log.id)) continue;
|
|
4020
|
-
const groupKey = buildGroupKey({
|
|
4021
|
-
chainId: log.chainId,
|
|
4022
|
-
maker: log.maker,
|
|
4023
|
-
group: log.group
|
|
4024
|
-
});
|
|
4025
|
-
const previousConsumed = consumedByGroup.get(groupKey) ?? 0n;
|
|
4026
|
-
if (log.kind === "consume") {
|
|
4027
|
-
events.push({
|
|
4028
|
-
id: log.id,
|
|
4029
|
-
chainId: log.chainId,
|
|
4030
|
-
maker: log.maker,
|
|
4031
|
-
group: log.group,
|
|
4032
|
-
amount: log.amount,
|
|
4033
|
-
blockNumber: log.blockNumber
|
|
4034
|
-
});
|
|
4035
|
-
consumedByGroup.set(groupKey, previousConsumed + log.amount);
|
|
4036
|
-
continue;
|
|
4037
|
-
}
|
|
4038
|
-
const delta = log.consumed - previousConsumed;
|
|
4039
|
-
if (delta <= 0n) {
|
|
4040
|
-
logger.debug({
|
|
4041
|
-
collector,
|
|
4042
|
-
chainId: client.chain.id,
|
|
4043
|
-
msg: "Skipping Take log because consumed did not increase",
|
|
4044
|
-
previous_consumed: previousConsumed.toString(),
|
|
4045
|
-
consumed: log.consumed.toString()
|
|
4046
|
-
});
|
|
4047
|
-
continue;
|
|
4048
|
-
}
|
|
4049
|
-
events.push({
|
|
4050
|
-
id: log.id,
|
|
4051
|
-
chainId: log.chainId,
|
|
4052
|
-
maker: log.maker,
|
|
4053
|
-
group: log.group,
|
|
4054
|
-
amount: delta,
|
|
4055
|
-
blockNumber: log.blockNumber
|
|
4056
|
-
});
|
|
4057
|
-
consumedByGroup.set(groupKey, log.consumed);
|
|
4420
|
+
const [resolvedSeizureTransfers, resolvedConsumedEvents] = await Promise.all([resolveSeizureTransfers({
|
|
4421
|
+
dbTx,
|
|
4422
|
+
seizureEvents
|
|
4423
|
+
}), resolveConsumedEvents({
|
|
4424
|
+
dbTx,
|
|
4425
|
+
consumedEvents,
|
|
4426
|
+
chainId: client.chain.id,
|
|
4427
|
+
collector,
|
|
4428
|
+
logger
|
|
4429
|
+
})]);
|
|
4430
|
+
if (debtTransfers.length > 0) {
|
|
4431
|
+
await dbTx.positions.upsert(transfersToPositions(debtTransfers));
|
|
4432
|
+
await dbTx.transfers.create(debtTransfers);
|
|
4058
4433
|
}
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
collector,
|
|
4064
|
-
count: events.length,
|
|
4065
|
-
chain_id: client.chain.id,
|
|
4066
|
-
block_range: [startBlock, lastStreamBlockNumber]
|
|
4067
|
-
});
|
|
4068
|
-
} catch (err) {
|
|
4069
|
-
logger.error({
|
|
4070
|
-
err,
|
|
4071
|
-
msg: "Failed to process consumed events"
|
|
4072
|
-
});
|
|
4434
|
+
const allCollateralTransfers = [...resolvedSeizureTransfers, ...collateralTransfers];
|
|
4435
|
+
if (allCollateralTransfers.length > 0) {
|
|
4436
|
+
await dbTx.positions.upsert(transfersToPositions(allCollateralTransfers));
|
|
4437
|
+
await dbTx.transfers.create(allCollateralTransfers);
|
|
4073
4438
|
}
|
|
4439
|
+
await dbTx.consumed.create(resolvedConsumedEvents);
|
|
4440
|
+
if (resolvedConsumedEvents.length > 0) logger.info({
|
|
4441
|
+
msg: "Events indexed",
|
|
4442
|
+
collector,
|
|
4443
|
+
consumed_count: resolvedConsumedEvents.length,
|
|
4444
|
+
debt_transfer_count: debtTransfers.length,
|
|
4445
|
+
collateral_transfer_count: allCollateralTransfers.length,
|
|
4446
|
+
chain_id: client.chain.id,
|
|
4447
|
+
block_range: [startBlock, lastStreamBlockNumber]
|
|
4448
|
+
});
|
|
4074
4449
|
blockNumber = lastStreamBlockNumber;
|
|
4075
4450
|
try {
|
|
4076
4451
|
await dbTx.blocks.advanceCollector({
|
|
@@ -4086,15 +4461,27 @@ async function* collectConsumedEvents(parameters) {
|
|
|
4086
4461
|
chainId: client.chain.id
|
|
4087
4462
|
});
|
|
4088
4463
|
blockNumber = ancestor.blockNumber;
|
|
4089
|
-
const
|
|
4464
|
+
const deletedConsumed = await dbTx.consumed.delete({
|
|
4090
4465
|
chainId: client.chain.id,
|
|
4091
4466
|
blockNumberGte: blockNumber + 1
|
|
4092
4467
|
});
|
|
4468
|
+
const deletedDebtTransfers = await dbTx.transfers.delete({
|
|
4469
|
+
chainId: client.chain.id,
|
|
4470
|
+
blockNumberGte: blockNumber + 1,
|
|
4471
|
+
positionTypeId: positionTypeId(Type.DEBT_OF)
|
|
4472
|
+
});
|
|
4473
|
+
const deletedCollateralTransfers = await dbTx.transfers.delete({
|
|
4474
|
+
chainId: client.chain.id,
|
|
4475
|
+
blockNumberGte: blockNumber + 1,
|
|
4476
|
+
positionTypeId: positionTypeId(Type.COLLATERAL_OF)
|
|
4477
|
+
});
|
|
4093
4478
|
logger.info({
|
|
4094
4479
|
collector,
|
|
4095
4480
|
chain_id: client.chain.id,
|
|
4096
|
-
msg:
|
|
4097
|
-
|
|
4481
|
+
msg: "Reorg detected, events deleted",
|
|
4482
|
+
consumed_deleted: deletedConsumed,
|
|
4483
|
+
debt_transfers_deleted: deletedDebtTransfers,
|
|
4484
|
+
collateral_transfers_deleted: deletedCollateralTransfers,
|
|
4098
4485
|
block_number: blockNumber
|
|
4099
4486
|
});
|
|
4100
4487
|
await dbTx.blocks.advanceCollector({
|
|
@@ -4105,7 +4492,7 @@ async function* collectConsumedEvents(parameters) {
|
|
|
4105
4492
|
});
|
|
4106
4493
|
reorgDetected = true;
|
|
4107
4494
|
} catch (err) {
|
|
4108
|
-
const msg = "Failed to delete
|
|
4495
|
+
const msg = "Failed to delete events when handling reorg.";
|
|
4109
4496
|
logger.error({
|
|
4110
4497
|
collector,
|
|
4111
4498
|
chainId: client.chain.id,
|
|
@@ -4120,10 +4507,210 @@ async function* collectConsumedEvents(parameters) {
|
|
|
4120
4507
|
yield blockNumber;
|
|
4121
4508
|
startBlock = blockNumber;
|
|
4122
4509
|
}
|
|
4510
|
+
if (!reorgDetected) await db.transaction(async (dbTx) => {
|
|
4511
|
+
const collectorState = await dbTx.blocks.getCollector({
|
|
4512
|
+
collectorName: collector,
|
|
4513
|
+
chainId: client.chain.id
|
|
4514
|
+
});
|
|
4515
|
+
const deletedConsumed = await dbTx.consumed.delete({
|
|
4516
|
+
chainId: client.chain.id,
|
|
4517
|
+
blockNumberGte: collectorState.blockNumber + 1
|
|
4518
|
+
});
|
|
4519
|
+
const deletedDebtTransfers = await dbTx.transfers.delete({
|
|
4520
|
+
chainId: client.chain.id,
|
|
4521
|
+
blockNumberGte: collectorState.blockNumber + 1,
|
|
4522
|
+
positionTypeId: positionTypeId(Type.DEBT_OF)
|
|
4523
|
+
});
|
|
4524
|
+
const deletedCollateralTransfers = await dbTx.transfers.delete({
|
|
4525
|
+
chainId: client.chain.id,
|
|
4526
|
+
blockNumberGte: collectorState.blockNumber + 1,
|
|
4527
|
+
positionTypeId: positionTypeId(Type.COLLATERAL_OF)
|
|
4528
|
+
});
|
|
4529
|
+
if (deletedConsumed > 0 || deletedDebtTransfers > 0 || deletedCollateralTransfers > 0) logger.info({
|
|
4530
|
+
collector,
|
|
4531
|
+
chain_id: client.chain.id,
|
|
4532
|
+
msg: "Reorg detected, events deleted",
|
|
4533
|
+
consumed_deleted: deletedConsumed,
|
|
4534
|
+
debt_transfers_deleted: deletedDebtTransfers,
|
|
4535
|
+
collateral_transfers_deleted: deletedCollateralTransfers,
|
|
4536
|
+
block_number: collectorState.blockNumber
|
|
4537
|
+
});
|
|
4538
|
+
});
|
|
4539
|
+
}
|
|
4540
|
+
async function resolveSeizureTransfers(parameters) {
|
|
4541
|
+
const { dbTx, seizureEvents } = parameters;
|
|
4542
|
+
if (seizureEvents.length === 0) return [];
|
|
4543
|
+
const uniqueObligationIds = [...new Set(seizureEvents.map((event) => event.obligationId.toLowerCase()))];
|
|
4544
|
+
const rows = await dbTx.select({
|
|
4545
|
+
obligationId: obligationIdKeys.obligationId,
|
|
4546
|
+
collateralIndex: obligationCollateralsV2.collateralIndex,
|
|
4547
|
+
asset: obligationCollateralsV2.asset
|
|
4548
|
+
}).from(obligationIdKeys).innerJoin(obligationCollateralsV2, eq(obligationIdKeys.obligationKey, obligationCollateralsV2.obligationKey)).where(inArray(obligationIdKeys.obligationId, uniqueObligationIds));
|
|
4549
|
+
const resolutionMap = /* @__PURE__ */ new Map();
|
|
4550
|
+
for (const row of rows) resolutionMap.set(`${row.obligationId.toLowerCase()}-${row.collateralIndex}`, row.asset);
|
|
4551
|
+
const resolvedSeizureTransfers = [];
|
|
4552
|
+
for (const seizure of seizureEvents) {
|
|
4553
|
+
const key = `${seizure.obligationId.toLowerCase()}-${seizure.collateralIndex}`;
|
|
4554
|
+
const asset = resolutionMap.get(key);
|
|
4555
|
+
if (asset === void 0) throw new Error(`Unresolvable Liquidate seizure: obligationId=${seizure.obligationId}, collateralIndex=${seizure.collateralIndex}, chainId=${seizure.chainId}, blockNumber=${seizure.blockNumber}`);
|
|
4556
|
+
resolvedSeizureTransfers.push(from$9({
|
|
4557
|
+
id: seizure.id,
|
|
4558
|
+
chainId: seizure.chainId,
|
|
4559
|
+
contract: seizure.obligationId,
|
|
4560
|
+
from: seizure.user,
|
|
4561
|
+
to: zeroAddress,
|
|
4562
|
+
value: seizure.amount,
|
|
4563
|
+
type: Type.COLLATERAL_OF,
|
|
4564
|
+
asset,
|
|
4565
|
+
blockNumber: seizure.blockNumber
|
|
4566
|
+
}));
|
|
4567
|
+
}
|
|
4568
|
+
return resolvedSeizureTransfers;
|
|
4569
|
+
}
|
|
4570
|
+
async function resolveConsumedEvents(parameters) {
|
|
4571
|
+
const { dbTx, consumedEvents, chainId, collector, logger } = parameters;
|
|
4572
|
+
if (consumedEvents.length === 0) return [];
|
|
4573
|
+
const [existingConsumedIds, consumedByGroup] = await Promise.all([getExistingConsumedIds({
|
|
4574
|
+
dbTx,
|
|
4575
|
+
consumedEvents
|
|
4576
|
+
}), getConsumedByGroup({
|
|
4577
|
+
dbTx,
|
|
4578
|
+
consumedEvents
|
|
4579
|
+
})]);
|
|
4580
|
+
const resolvedEvents = [];
|
|
4581
|
+
for (const log of consumedEvents) {
|
|
4582
|
+
if (existingConsumedIds.has(log.id)) continue;
|
|
4583
|
+
const groupKey = buildGroupKey({
|
|
4584
|
+
chainId: log.chainId,
|
|
4585
|
+
maker: log.maker,
|
|
4586
|
+
group: log.group
|
|
4587
|
+
});
|
|
4588
|
+
const previousConsumed = consumedByGroup.get(groupKey) ?? 0n;
|
|
4589
|
+
if (log.kind === "consume") {
|
|
4590
|
+
resolvedEvents.push({
|
|
4591
|
+
id: log.id,
|
|
4592
|
+
chainId: log.chainId,
|
|
4593
|
+
maker: log.maker,
|
|
4594
|
+
group: log.group,
|
|
4595
|
+
amount: log.amount,
|
|
4596
|
+
blockNumber: log.blockNumber
|
|
4597
|
+
});
|
|
4598
|
+
consumedByGroup.set(groupKey, previousConsumed + log.amount);
|
|
4599
|
+
continue;
|
|
4600
|
+
}
|
|
4601
|
+
const delta = log.consumed - previousConsumed;
|
|
4602
|
+
if (delta <= 0n) {
|
|
4603
|
+
logger.debug({
|
|
4604
|
+
collector,
|
|
4605
|
+
chainId,
|
|
4606
|
+
msg: "Skipping Take log because consumed did not increase",
|
|
4607
|
+
previous_consumed: previousConsumed.toString(),
|
|
4608
|
+
consumed: log.consumed.toString()
|
|
4609
|
+
});
|
|
4610
|
+
continue;
|
|
4611
|
+
}
|
|
4612
|
+
resolvedEvents.push({
|
|
4613
|
+
id: log.id,
|
|
4614
|
+
chainId: log.chainId,
|
|
4615
|
+
maker: log.maker,
|
|
4616
|
+
group: log.group,
|
|
4617
|
+
amount: delta,
|
|
4618
|
+
blockNumber: log.blockNumber
|
|
4619
|
+
});
|
|
4620
|
+
consumedByGroup.set(groupKey, log.consumed);
|
|
4621
|
+
}
|
|
4622
|
+
return resolvedEvents;
|
|
4623
|
+
}
|
|
4624
|
+
async function getExistingConsumedIds(parameters) {
|
|
4625
|
+
const { dbTx, consumedEvents: consumedEvents$1 } = parameters;
|
|
4626
|
+
const existingConsumedIds = /* @__PURE__ */ new Set();
|
|
4627
|
+
const ids = Array.from(new Set(consumedEvents$1.map((event) => event.id)));
|
|
4628
|
+
for (let index = 0; index < ids.length; index += 500) {
|
|
4629
|
+
const slice = ids.slice(index, index + 500);
|
|
4630
|
+
const { rows } = await dbTx.execute(sql`
|
|
4631
|
+
SELECT event_id
|
|
4632
|
+
FROM ${consumedEvents}
|
|
4633
|
+
WHERE event_id IN (${sql.join(slice.map((id) => sql`${id}`), sql`,`)});
|
|
4634
|
+
`);
|
|
4635
|
+
for (const row of rows) existingConsumedIds.add(row.event_id);
|
|
4636
|
+
}
|
|
4637
|
+
return existingConsumedIds;
|
|
4638
|
+
}
|
|
4639
|
+
async function getConsumedByGroup(parameters) {
|
|
4640
|
+
const { dbTx, consumedEvents } = parameters;
|
|
4641
|
+
const groups$3 = /* @__PURE__ */ new Map();
|
|
4642
|
+
for (const event of consumedEvents) {
|
|
4643
|
+
const key = buildGroupKey({
|
|
4644
|
+
chainId: event.chainId,
|
|
4645
|
+
maker: event.maker,
|
|
4646
|
+
group: event.group
|
|
4647
|
+
});
|
|
4648
|
+
if (!groups$3.has(key)) groups$3.set(key, {
|
|
4649
|
+
chainId: event.chainId,
|
|
4650
|
+
maker: event.maker,
|
|
4651
|
+
group: event.group
|
|
4652
|
+
});
|
|
4653
|
+
}
|
|
4654
|
+
const consumedByGroup = /* @__PURE__ */ new Map();
|
|
4655
|
+
const groupList = Array.from(groups$3.values());
|
|
4656
|
+
for (let index = 0; index < groupList.length; index += 500) {
|
|
4657
|
+
const slice = groupList.slice(index, index + 500);
|
|
4658
|
+
const { rows } = await dbTx.execute(sql`
|
|
4659
|
+
WITH targets(chain_id, maker, "group") AS (
|
|
4660
|
+
VALUES ${sql.join(slice.map((group) => sql`(${group.chainId}::bigint, ${group.maker.toLowerCase()}::varchar(42), ${group.group.toLowerCase()}::varchar(66))`), sql`,`)}
|
|
4661
|
+
)
|
|
4662
|
+
SELECT
|
|
4663
|
+
targets.chain_id,
|
|
4664
|
+
targets.maker,
|
|
4665
|
+
targets."group",
|
|
4666
|
+
COALESCE(g.consumed, 0)::numeric AS consumed
|
|
4667
|
+
FROM targets
|
|
4668
|
+
LEFT JOIN ${groups} g
|
|
4669
|
+
ON g.chain_id = targets.chain_id
|
|
4670
|
+
AND g.maker = targets.maker
|
|
4671
|
+
AND g."group" = targets."group";
|
|
4672
|
+
`);
|
|
4673
|
+
for (const row of rows) {
|
|
4674
|
+
const groupKey = buildGroupKey({
|
|
4675
|
+
chainId: Number(row.chain_id),
|
|
4676
|
+
maker: row.maker,
|
|
4677
|
+
group: row.group
|
|
4678
|
+
});
|
|
4679
|
+
consumedByGroup.set(groupKey, BigInt(row.consumed ?? "0"));
|
|
4680
|
+
}
|
|
4681
|
+
}
|
|
4682
|
+
return consumedByGroup;
|
|
4683
|
+
}
|
|
4684
|
+
function transfersToPositions(transfers) {
|
|
4685
|
+
if (transfers.length === 0) return [];
|
|
4686
|
+
const transferType = transfers[0].type;
|
|
4687
|
+
if (transfers.some((transfer) => transfer.type !== transferType)) throw new Error("Cannot map transfers with mixed position types to positions.");
|
|
4688
|
+
const positionKeys = /* @__PURE__ */ new Map();
|
|
4689
|
+
for (const transfer of transfers) for (const user of [transfer.from, transfer.to]) {
|
|
4690
|
+
const key = `${transfer.chainId}-${transfer.contract}-${user}-${transfer.asset}`.toLowerCase();
|
|
4691
|
+
const existing = positionKeys.get(key);
|
|
4692
|
+
if (!existing || transfer.blockNumber < existing.blockNumber) positionKeys.set(key, {
|
|
4693
|
+
chainId: transfer.chainId,
|
|
4694
|
+
contract: transfer.contract,
|
|
4695
|
+
user,
|
|
4696
|
+
asset: transfer.asset,
|
|
4697
|
+
blockNumber: transfer.blockNumber
|
|
4698
|
+
});
|
|
4699
|
+
}
|
|
4700
|
+
return Array.from(positionKeys.values()).map((position) => from$12({
|
|
4701
|
+
chainId: position.chainId,
|
|
4702
|
+
contract: position.contract,
|
|
4703
|
+
user: position.user,
|
|
4704
|
+
type: transferType,
|
|
4705
|
+
balance: 0n,
|
|
4706
|
+
asset: position.asset,
|
|
4707
|
+
blockNumber: position.blockNumber
|
|
4708
|
+
}));
|
|
4123
4709
|
}
|
|
4124
4710
|
|
|
4125
4711
|
//#endregion
|
|
4126
4712
|
//#region src/indexer/collectors/CollectFunctions/collectOffers.ts
|
|
4713
|
+
const ERC20_TYPE_ID = Object.values(Type).indexOf(Type.ERC20) + 1;
|
|
4127
4714
|
async function* collectOffersV2(parameters) {
|
|
4128
4715
|
let { db, collector, client, lastBlockNumber: blockNumber, gatekeeper, options: { maxBatchSize = 1e3, blockWindow } = {} } = parameters;
|
|
4129
4716
|
const logger = getLogger();
|
|
@@ -4137,9 +4724,10 @@ async function* collectOffersV2(parameters) {
|
|
|
4137
4724
|
});
|
|
4138
4725
|
throw new Error(msg);
|
|
4139
4726
|
}
|
|
4727
|
+
const morphoV2 = client.chain.custom.morpho.address;
|
|
4140
4728
|
const signatureDomain = {
|
|
4141
4729
|
chainId: client.chain.id,
|
|
4142
|
-
verifyingContract:
|
|
4730
|
+
verifyingContract: morphoV2
|
|
4143
4731
|
};
|
|
4144
4732
|
const { blockNumber: latestBlockNumberChain } = await db.blocks.getChain(client.chain.id);
|
|
4145
4733
|
const stream = streamLogs({
|
|
@@ -4202,10 +4790,14 @@ async function* collectOffersV2(parameters) {
|
|
|
4202
4790
|
await db.transaction(async (dbTx) => {
|
|
4203
4791
|
const { epoch, blockNumber: latestBlockNumber } = await dbTx.blocks.getChain(client.chain.id);
|
|
4204
4792
|
const treesToInsert = [];
|
|
4793
|
+
const pathsToInsert = [];
|
|
4205
4794
|
let totalValidOffers = 0;
|
|
4206
4795
|
const offersWithBlock = [];
|
|
4207
4796
|
for (const { tree, signature, blockNumber: treeBlockNumber } of decodedTrees) try {
|
|
4208
|
-
const allowedResults = await gatekeeper.isAllowed(
|
|
4797
|
+
const allowedResults = await gatekeeper.isAllowed({
|
|
4798
|
+
offers: tree.offers,
|
|
4799
|
+
chainId: client.chain.id
|
|
4800
|
+
});
|
|
4209
4801
|
const hasBlockWindowViolation = treeBlockNumber > latestBlockNumber;
|
|
4210
4802
|
if (!(allowedResults.issues.length === 0 && allowedResults.valid.length === tree.offers.length) || hasBlockWindowViolation) {
|
|
4211
4803
|
if (allowedResults.issues.length > 0) {
|
|
@@ -4224,14 +4816,35 @@ async function* collectOffersV2(parameters) {
|
|
|
4224
4816
|
continue;
|
|
4225
4817
|
}
|
|
4226
4818
|
treesToInsert.push({
|
|
4227
|
-
tree,
|
|
4819
|
+
root: tree.root,
|
|
4228
4820
|
signature
|
|
4229
4821
|
});
|
|
4230
4822
|
totalValidOffers += tree.offers.length;
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4823
|
+
const obligationIdsByOfferHash = /* @__PURE__ */ new Map();
|
|
4824
|
+
for (const offer of tree.offers) {
|
|
4825
|
+
const offerHash = hash(offer).toLowerCase();
|
|
4826
|
+
const obligationId$1 = obligationId(offer, {
|
|
4827
|
+
chainId: client.chain.id,
|
|
4828
|
+
morphoV2
|
|
4829
|
+
}).toLowerCase();
|
|
4830
|
+
offersWithBlock.push({
|
|
4831
|
+
offer,
|
|
4832
|
+
blockNumber: treeBlockNumber,
|
|
4833
|
+
obligationId: obligationId$1
|
|
4834
|
+
});
|
|
4835
|
+
obligationIdsByOfferHash.set(offerHash, obligationId$1);
|
|
4836
|
+
}
|
|
4837
|
+
for (const proof of proofs(tree)) {
|
|
4838
|
+
const offerHash = hash(proof.offer).toLowerCase();
|
|
4839
|
+
const obligationId = obligationIdsByOfferHash.get(offerHash);
|
|
4840
|
+
if (obligationId === void 0) continue;
|
|
4841
|
+
pathsToInsert.push({
|
|
4842
|
+
offerHash,
|
|
4843
|
+
obligationId,
|
|
4844
|
+
treeRoot: tree.root,
|
|
4845
|
+
proof: proof.path
|
|
4846
|
+
});
|
|
4847
|
+
}
|
|
4235
4848
|
} catch (err) {
|
|
4236
4849
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
4237
4850
|
logger.error({
|
|
@@ -4241,19 +4854,23 @@ async function* collectOffersV2(parameters) {
|
|
|
4241
4854
|
});
|
|
4242
4855
|
throw new Error("Gatekeeper validation failed", { cause: error });
|
|
4243
4856
|
}
|
|
4244
|
-
const dependencies = buildOfferDependencies(
|
|
4857
|
+
const dependencies = buildOfferDependencies({
|
|
4858
|
+
offers: offersWithBlock,
|
|
4859
|
+
chainId: client.chain.id,
|
|
4860
|
+
morphoV2
|
|
4861
|
+
});
|
|
4245
4862
|
await dbTx.oracles.upsert(dependencies.oracles);
|
|
4246
4863
|
await dbTx.obligations.create(dependencies.obligations);
|
|
4247
4864
|
await dbTx.groups.create(dependencies.groups);
|
|
4248
|
-
const
|
|
4249
|
-
if (treesToInsert.length > 0) await dbTx.trees.
|
|
4250
|
-
|
|
4251
|
-
offers: offersWithBlock,
|
|
4252
|
-
hashes: insertedHashes
|
|
4253
|
-
});
|
|
4865
|
+
const insertedReferences = await dbTx.offers.create(dependencies.offerBatches);
|
|
4866
|
+
if (treesToInsert.length > 0) await dbTx.trees.upsert(treesToInsert);
|
|
4867
|
+
if (pathsToInsert.length > 0) await dbTx.trees.upsertPaths(pathsToInsert);
|
|
4254
4868
|
const { callbacks, positions, lots } = decodeCallbacks({
|
|
4255
|
-
|
|
4256
|
-
|
|
4869
|
+
offers: filterInsertedOffers({
|
|
4870
|
+
offers: offersWithBlock,
|
|
4871
|
+
references: insertedReferences
|
|
4872
|
+
}),
|
|
4873
|
+
chainId: client.chain.id
|
|
4257
4874
|
});
|
|
4258
4875
|
if (positions.length > 0) await dbTx.positions.upsert(positions);
|
|
4259
4876
|
if (callbacks.length > 0) await dbTx.callbacks.upsert(callbacks);
|
|
@@ -4316,7 +4933,7 @@ async function* collectOffersV2(parameters) {
|
|
|
4316
4933
|
}
|
|
4317
4934
|
}
|
|
4318
4935
|
function decodeCallbacks(parameters) {
|
|
4319
|
-
const { offers } = parameters;
|
|
4936
|
+
const { offers, chainId } = parameters;
|
|
4320
4937
|
if (offers.length === 0) return {
|
|
4321
4938
|
callbacks: [],
|
|
4322
4939
|
positions: [],
|
|
@@ -4325,12 +4942,12 @@ function decodeCallbacks(parameters) {
|
|
|
4325
4942
|
const callbacks = [];
|
|
4326
4943
|
const positions = [];
|
|
4327
4944
|
const lots = [];
|
|
4328
|
-
for (const { offer, blockNumber: offerBlockNumber } of offers) {
|
|
4945
|
+
for (const { offer, blockNumber: offerBlockNumber, obligationId } of offers) {
|
|
4329
4946
|
if (!offer.buy) continue;
|
|
4330
4947
|
if (!isEmptyCallback(offer)) continue;
|
|
4331
4948
|
const loanToken = offer.loanToken.toLowerCase();
|
|
4332
4949
|
positions.push(from$12({
|
|
4333
|
-
chainId
|
|
4950
|
+
chainId,
|
|
4334
4951
|
contract: loanToken,
|
|
4335
4952
|
user: offer.maker,
|
|
4336
4953
|
type: Type.ERC20,
|
|
@@ -4338,20 +4955,23 @@ function decodeCallbacks(parameters) {
|
|
|
4338
4955
|
blockNumber: offerBlockNumber
|
|
4339
4956
|
}));
|
|
4340
4957
|
lots.push({
|
|
4341
|
-
positionChainId:
|
|
4958
|
+
positionChainId: chainId,
|
|
4342
4959
|
positionContract: loanToken,
|
|
4343
4960
|
positionUser: offer.maker,
|
|
4961
|
+
positionTypeId: ERC20_TYPE_ID,
|
|
4344
4962
|
group: offer.group,
|
|
4345
|
-
obligationId
|
|
4963
|
+
obligationId,
|
|
4346
4964
|
size: offer.assets
|
|
4347
4965
|
});
|
|
4348
4966
|
callbacks.push({
|
|
4349
4967
|
offerHash: hash(offer),
|
|
4968
|
+
obligationId,
|
|
4350
4969
|
callbacks: [{
|
|
4351
|
-
chainId
|
|
4970
|
+
chainId,
|
|
4352
4971
|
contract: loanToken,
|
|
4353
4972
|
user: offer.maker,
|
|
4354
|
-
amount: offer.assets
|
|
4973
|
+
amount: offer.assets,
|
|
4974
|
+
positionTypeId: ERC20_TYPE_ID
|
|
4355
4975
|
}]
|
|
4356
4976
|
});
|
|
4357
4977
|
}
|
|
@@ -4361,34 +4981,42 @@ function decodeCallbacks(parameters) {
|
|
|
4361
4981
|
lots
|
|
4362
4982
|
};
|
|
4363
4983
|
}
|
|
4364
|
-
function buildOfferDependencies(
|
|
4984
|
+
function buildOfferDependencies(parameters) {
|
|
4985
|
+
const { offers, chainId, morphoV2 } = parameters;
|
|
4365
4986
|
const obligationsById = /* @__PURE__ */ new Map();
|
|
4366
4987
|
const oraclesByKey = /* @__PURE__ */ new Map();
|
|
4367
4988
|
const groupsByKey = /* @__PURE__ */ new Map();
|
|
4368
4989
|
const offersByBlock = /* @__PURE__ */ new Map();
|
|
4369
|
-
for (const { offer, blockNumber } of offers) {
|
|
4990
|
+
for (const { offer, blockNumber, obligationId } of offers) {
|
|
4370
4991
|
const list = offersByBlock.get(blockNumber) ?? [];
|
|
4371
|
-
list.push(
|
|
4992
|
+
list.push({
|
|
4993
|
+
offer,
|
|
4994
|
+
obligationId,
|
|
4995
|
+
chainId
|
|
4996
|
+
});
|
|
4372
4997
|
offersByBlock.set(blockNumber, list);
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
chainId
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4998
|
+
if (!obligationsById.get(obligationId)) obligationsById.set(obligationId, {
|
|
4999
|
+
obligationId,
|
|
5000
|
+
chainId,
|
|
5001
|
+
morphoV2,
|
|
5002
|
+
obligation: from$15({
|
|
5003
|
+
loanToken: offer.loanToken,
|
|
5004
|
+
maturity: offer.maturity,
|
|
5005
|
+
collaterals: offer.collaterals
|
|
5006
|
+
})
|
|
5007
|
+
});
|
|
4380
5008
|
for (const collateral of offer.collaterals) {
|
|
4381
|
-
const oracleKey = `${
|
|
5009
|
+
const oracleKey = `${chainId}-${collateral.oracle}`.toLowerCase();
|
|
4382
5010
|
if (!oraclesByKey.has(oracleKey)) oraclesByKey.set(oracleKey, from$13({
|
|
4383
|
-
chainId
|
|
5011
|
+
chainId,
|
|
4384
5012
|
address: collateral.oracle,
|
|
4385
5013
|
price: null,
|
|
4386
5014
|
blockNumber
|
|
4387
5015
|
}));
|
|
4388
5016
|
}
|
|
4389
|
-
const groupKey = `${
|
|
5017
|
+
const groupKey = `${chainId}-${offer.maker}-${offer.group}`.toLowerCase();
|
|
4390
5018
|
if (!groupsByKey.has(groupKey)) groupsByKey.set(groupKey, {
|
|
4391
|
-
chainId
|
|
5019
|
+
chainId,
|
|
4392
5020
|
maker: offer.maker,
|
|
4393
5021
|
group: offer.group,
|
|
4394
5022
|
blockNumber
|
|
@@ -4405,15 +5033,22 @@ function buildOfferDependencies(offers) {
|
|
|
4405
5033
|
};
|
|
4406
5034
|
}
|
|
4407
5035
|
function filterInsertedOffers(parameters) {
|
|
4408
|
-
if (parameters.
|
|
4409
|
-
const
|
|
5036
|
+
if (parameters.references.length === 0) return [];
|
|
5037
|
+
const keyOf = (input) => `${input.hash.toLowerCase()}:${input.obligationId.toLowerCase()}`;
|
|
5038
|
+
const inserted = new Set(parameters.references.map((offer) => keyOf({
|
|
5039
|
+
hash: offer.hash,
|
|
5040
|
+
obligationId: offer.obligationId
|
|
5041
|
+
})));
|
|
4410
5042
|
const seen = /* @__PURE__ */ new Set();
|
|
4411
5043
|
const filtered = [];
|
|
4412
5044
|
for (const entry of parameters.offers) {
|
|
4413
|
-
const
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
5045
|
+
const key = keyOf({
|
|
5046
|
+
hash: hash(entry.offer),
|
|
5047
|
+
obligationId: entry.obligationId
|
|
5048
|
+
});
|
|
5049
|
+
if (!inserted.has(key)) continue;
|
|
5050
|
+
if (seen.has(key)) continue;
|
|
5051
|
+
seen.add(key);
|
|
4417
5052
|
filtered.push(entry);
|
|
4418
5053
|
}
|
|
4419
5054
|
return filtered;
|
|
@@ -4528,7 +5163,7 @@ async function snapshotVaultPositions(parameters) {
|
|
|
4528
5163
|
convertToAssets: (shares) => {
|
|
4529
5164
|
const contract = contracts.get(position.contract.toLowerCase());
|
|
4530
5165
|
if (!contract) return;
|
|
4531
|
-
if (contract.decimalsOffset === void 0 || contract.totalAssets === void 0 || contract.totalSupply === void 0) return;
|
|
5166
|
+
if (contract.decimalsOffset === void 0 || contract.totalAssets === void 0 || contract.totalSupply === void 0 || contract.asset === void 0) return;
|
|
4532
5167
|
try {
|
|
4533
5168
|
position.balance = convertToAssets({
|
|
4534
5169
|
shares,
|
|
@@ -4683,12 +5318,15 @@ async function* collectPositions(parameters) {
|
|
|
4683
5318
|
from: log.args.from,
|
|
4684
5319
|
to: log.args.to,
|
|
4685
5320
|
value: log.args.value,
|
|
5321
|
+
type: Type.ERC20,
|
|
5322
|
+
asset: log.address,
|
|
4686
5323
|
blockNumber: Number(log.blockNumber)
|
|
4687
5324
|
}));
|
|
4688
5325
|
}
|
|
4689
5326
|
const { positions } = await db.positions.get({
|
|
4690
5327
|
chainId: client.chain.id,
|
|
4691
|
-
filled: false
|
|
5328
|
+
filled: false,
|
|
5329
|
+
type: Type.ERC20
|
|
4692
5330
|
});
|
|
4693
5331
|
const newPositions = [];
|
|
4694
5332
|
try {
|
|
@@ -4811,7 +5449,8 @@ async function* collectPositions(parameters) {
|
|
|
4811
5449
|
blockNumber = ancestor.blockNumber;
|
|
4812
5450
|
const emptied = await dbTx.positions.setEmptyAfter({
|
|
4813
5451
|
chainId: client.chain.id,
|
|
4814
|
-
blockNumber: blockNumber + 1
|
|
5452
|
+
blockNumber: blockNumber + 1,
|
|
5453
|
+
type: Type.ERC20
|
|
4815
5454
|
});
|
|
4816
5455
|
logger.info({
|
|
4817
5456
|
msg: "Reorg detected, positions set to empty",
|
|
@@ -5038,10 +5677,10 @@ function createBuilder(parameters) {
|
|
|
5038
5677
|
}
|
|
5039
5678
|
}));
|
|
5040
5679
|
},
|
|
5041
|
-
|
|
5042
|
-
return createCollector("
|
|
5680
|
+
buildMorphoV2Collector: ({ options: { maxBatchSize = 1e3 } = {} } = {}) => {
|
|
5681
|
+
return createCollector("morpho_v2", (p) => collectMorphoV2({
|
|
5043
5682
|
...p,
|
|
5044
|
-
collector: "
|
|
5683
|
+
collector: "morpho_v2",
|
|
5045
5684
|
options: {
|
|
5046
5685
|
maxBatchSize,
|
|
5047
5686
|
blockWindow
|
|
@@ -5090,7 +5729,7 @@ const from$7 = (parameters) => {
|
|
|
5090
5729
|
});
|
|
5091
5730
|
return {
|
|
5092
5731
|
offersCollector: collectorBuilder.buildOffersCollector({ options: { maxBatchSize } }),
|
|
5093
|
-
|
|
5732
|
+
morphoV2Collector: collectorBuilder.buildMorphoV2Collector({ options: { maxBatchSize } }),
|
|
5094
5733
|
pricesCollector: collectorBuilder.buildPricesCollector({ options: {
|
|
5095
5734
|
maxBatchSize,
|
|
5096
5735
|
retryAttempts,
|
|
@@ -5112,7 +5751,7 @@ var Indexer_exports = /* @__PURE__ */ __exportAll({
|
|
|
5112
5751
|
});
|
|
5113
5752
|
function from$6(config) {
|
|
5114
5753
|
const { client, gatekeeper, db, interval = 1e4, maxBatchSize = 1e3, maxBlockNumber, blockWindow, retryAttempts, retryDelayMs } = config;
|
|
5115
|
-
const { offersCollector,
|
|
5754
|
+
const { offersCollector, morphoV2Collector, positionsCollector, pricesCollector } = from$7({
|
|
5116
5755
|
client,
|
|
5117
5756
|
db,
|
|
5118
5757
|
gatekeeper,
|
|
@@ -5127,7 +5766,7 @@ function from$6(config) {
|
|
|
5127
5766
|
client,
|
|
5128
5767
|
collectors: [
|
|
5129
5768
|
offersCollector,
|
|
5130
|
-
|
|
5769
|
+
morphoV2Collector,
|
|
5131
5770
|
positionsCollector,
|
|
5132
5771
|
pricesCollector
|
|
5133
5772
|
]
|
|
@@ -5332,12 +5971,13 @@ var ObligationResponse_exports = /* @__PURE__ */ __exportAll({ from: () => from$
|
|
|
5332
5971
|
* @constructor
|
|
5333
5972
|
* @param obligation - {@link Obligation}
|
|
5334
5973
|
* @param quote - {@link Quote}
|
|
5974
|
+
* @param chainId - The chain id used to compute `id`.
|
|
5335
5975
|
* @returns The created `ObligationResponse`. {@link ObligationResponse}
|
|
5336
5976
|
*/
|
|
5337
|
-
function from$4(obligation, quote) {
|
|
5977
|
+
function from$4(obligation, quote, chainId) {
|
|
5338
5978
|
return {
|
|
5339
5979
|
id: quote.obligationId,
|
|
5340
|
-
chain_id:
|
|
5980
|
+
chain_id: chainId,
|
|
5341
5981
|
loan_token: obligation.loanToken,
|
|
5342
5982
|
collaterals: obligation.collaterals.map((c) => ({
|
|
5343
5983
|
token: c.asset,
|
|
@@ -5404,12 +6044,7 @@ function from$3(input) {
|
|
|
5404
6044
|
receiver_if_maker_is_seller: input.receiverIfMakerIsSeller
|
|
5405
6045
|
},
|
|
5406
6046
|
offer_hash: input.hash,
|
|
5407
|
-
obligation_id:
|
|
5408
|
-
chainId,
|
|
5409
|
-
loanToken: input.loanToken,
|
|
5410
|
-
collaterals: [...input.collaterals],
|
|
5411
|
-
maturity: input.maturity
|
|
5412
|
-
}),
|
|
6047
|
+
obligation_id: input.obligationId,
|
|
5413
6048
|
chain_id: chainId,
|
|
5414
6049
|
consumed: input.consumed.toString(),
|
|
5415
6050
|
takeable: input.takeable.toString(),
|
|
@@ -6036,10 +6671,6 @@ __decorate([ApiProperty({
|
|
|
6036
6671
|
type: "boolean",
|
|
6037
6672
|
example: validateOfferExample.buy
|
|
6038
6673
|
})], ValidateOfferRequest.prototype, "buy", void 0);
|
|
6039
|
-
__decorate([ApiProperty({
|
|
6040
|
-
type: "number",
|
|
6041
|
-
example: validateOfferExample.chain_id
|
|
6042
|
-
})], ValidateOfferRequest.prototype, "chain_id", void 0);
|
|
6043
6674
|
__decorate([ApiProperty({
|
|
6044
6675
|
type: "string",
|
|
6045
6676
|
example: validateOfferExample.loan_token
|
|
@@ -6057,6 +6688,11 @@ __decorate([ApiProperty({
|
|
|
6057
6688
|
example: validateOfferExample.receiver_if_maker_is_seller
|
|
6058
6689
|
})], ValidateOfferRequest.prototype, "receiver_if_maker_is_seller", void 0);
|
|
6059
6690
|
var ValidateOffersRequest = class {};
|
|
6691
|
+
__decorate([ApiProperty({
|
|
6692
|
+
type: "number",
|
|
6693
|
+
description: "Chain id used for chain-scoped validation rules.",
|
|
6694
|
+
example: validateOfferExample.chain_id
|
|
6695
|
+
})], ValidateOffersRequest.prototype, "chain_id", void 0);
|
|
6060
6696
|
__decorate([ApiProperty({
|
|
6061
6697
|
type: () => [ValidateOfferRequest],
|
|
6062
6698
|
description: "Array of offers in snake_case format. Required, non-empty.",
|
|
@@ -6823,6 +7459,12 @@ function isValidBase64urlJson(val) {
|
|
|
6823
7459
|
function isValidOfferHashCursor(val) {
|
|
6824
7460
|
return /^0x[a-f0-9]{64}$/i.test(val);
|
|
6825
7461
|
}
|
|
7462
|
+
function isValidOfferCursor(val) {
|
|
7463
|
+
const [hash, obligationId, ...rest] = val.split(":");
|
|
7464
|
+
if (rest.length !== 0) return false;
|
|
7465
|
+
if (!hash || !obligationId) return false;
|
|
7466
|
+
return isValidOfferHashCursor(hash) && isValidOfferHashCursor(obligationId);
|
|
7467
|
+
}
|
|
6826
7468
|
const csvArray = (schema) => z$1.preprocess((value) => {
|
|
6827
7469
|
if (value === void 0) return void 0;
|
|
6828
7470
|
if (Array.isArray(value)) {
|
|
@@ -6886,7 +7528,7 @@ const GetConfigContractsQueryParams = z$1.object({
|
|
|
6886
7528
|
});
|
|
6887
7529
|
const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend({
|
|
6888
7530
|
cursor: z$1.string().optional().meta({
|
|
6889
|
-
description: "Pagination cursor. Use offer hash
|
|
7531
|
+
description: "Pagination cursor. Use offer hash:obligation_id for maker queries, base64url for obligation queries.",
|
|
6890
7532
|
example: "eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ"
|
|
6891
7533
|
}),
|
|
6892
7534
|
side: z$1.enum(["buy", "sell"]).optional().meta({
|
|
@@ -6913,10 +7555,10 @@ const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend
|
|
|
6913
7555
|
return;
|
|
6914
7556
|
}
|
|
6915
7557
|
if (hasMaker) {
|
|
6916
|
-
if (val.cursor !== void 0 && !
|
|
7558
|
+
if (val.cursor !== void 0 && !isValidOfferCursor(val.cursor)) ctx.addIssue({
|
|
6917
7559
|
code: "custom",
|
|
6918
7560
|
path: ["cursor"],
|
|
6919
|
-
message: "Cursor must be
|
|
7561
|
+
message: "Cursor must be in the offer hash:obligation_id format when filtering by maker"
|
|
6920
7562
|
});
|
|
6921
7563
|
return;
|
|
6922
7564
|
}
|
|
@@ -7026,7 +7668,13 @@ const GetBookParams = z$1.object({
|
|
|
7026
7668
|
example: "buy"
|
|
7027
7669
|
})
|
|
7028
7670
|
});
|
|
7029
|
-
const ValidateOffersBody = z$1.object({
|
|
7671
|
+
const ValidateOffersBody = z$1.object({
|
|
7672
|
+
chain_id: z$1.number().int().positive("chain_id must be a positive integer").meta({
|
|
7673
|
+
description: "Chain id used for chain-scoped validation rules.",
|
|
7674
|
+
example: 1
|
|
7675
|
+
}),
|
|
7676
|
+
offers: z$1.array(z$1.unknown()).min(1, { message: "'offers' must contain at least 1 offer" })
|
|
7677
|
+
}).strict();
|
|
7030
7678
|
const GetUserPositionsParams = z$1.object({
|
|
7031
7679
|
...PaginationQueryParams.shape,
|
|
7032
7680
|
user_address: z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "User address must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).meta({
|
|
@@ -7165,19 +7813,19 @@ async function getConfigContracts(query, chainRegistry) {
|
|
|
7165
7813
|
});
|
|
7166
7814
|
let cursorContract = null;
|
|
7167
7815
|
if (cursor) try {
|
|
7168
|
-
cursorContract = parseCursor$
|
|
7816
|
+
cursorContract = parseCursor$3(cursor);
|
|
7169
7817
|
} catch (err) {
|
|
7170
7818
|
return failure(err);
|
|
7171
7819
|
}
|
|
7172
7820
|
const startIndex = cursorContract ? findStartIndex$1(contracts, cursorContract) : 0;
|
|
7173
7821
|
const page = contracts.slice(startIndex, startIndex + limit);
|
|
7174
|
-
const nextCursor = startIndex + limit < contracts.length && page.length > 0 ? formatCursor$
|
|
7822
|
+
const nextCursor = startIndex + limit < contracts.length && page.length > 0 ? formatCursor$3(page.at(-1)) : null;
|
|
7175
7823
|
return success({
|
|
7176
7824
|
data: page,
|
|
7177
7825
|
cursor: nextCursor
|
|
7178
7826
|
});
|
|
7179
7827
|
}
|
|
7180
|
-
function parseCursor$
|
|
7828
|
+
function parseCursor$3(cursor) {
|
|
7181
7829
|
const [chain, address] = cursor.split(":", 2);
|
|
7182
7830
|
if (!chain || !address) throw new BadRequestError$1("Cursor must be in the format chain_id:0x...");
|
|
7183
7831
|
return {
|
|
@@ -7185,7 +7833,7 @@ function parseCursor$1(cursor) {
|
|
|
7185
7833
|
address: address.toLowerCase()
|
|
7186
7834
|
};
|
|
7187
7835
|
}
|
|
7188
|
-
function formatCursor$
|
|
7836
|
+
function formatCursor$3(contract) {
|
|
7189
7837
|
return `${contract.chain_id}:${contract.address.toLowerCase()}`;
|
|
7190
7838
|
}
|
|
7191
7839
|
function findStartIndex$1(contracts, cursor) {
|
|
@@ -7428,7 +8076,7 @@ async function getConfigRules(query, chains) {
|
|
|
7428
8076
|
const checksum = buildConfigRulesChecksum(filteredRules);
|
|
7429
8077
|
let cursorRule = null;
|
|
7430
8078
|
if (cursor) try {
|
|
7431
|
-
cursorRule = parseCursor(cursor);
|
|
8079
|
+
cursorRule = parseCursor$2(cursor);
|
|
7432
8080
|
} catch (err) {
|
|
7433
8081
|
return failure(err);
|
|
7434
8082
|
}
|
|
@@ -7436,7 +8084,7 @@ async function getConfigRules(query, chains) {
|
|
|
7436
8084
|
if (cursorRule && chainFilter && !chainFilter.has(cursorRule.chain_id)) return failure(new BadRequestError$1("Cursor chain_id must match requested chains"));
|
|
7437
8085
|
const startIndex = cursorRule ? findStartIndex(filteredRules, cursorRule) : 0;
|
|
7438
8086
|
const page = filteredRules.slice(startIndex, startIndex + limit);
|
|
7439
|
-
const nextCursor = startIndex + limit < filteredRules.length && page.length > 0 ? formatCursor(page.at(-1)) : null;
|
|
8087
|
+
const nextCursor = startIndex + limit < filteredRules.length && page.length > 0 ? formatCursor$2(page.at(-1)) : null;
|
|
7440
8088
|
const response = success({
|
|
7441
8089
|
data: page,
|
|
7442
8090
|
cursor: nextCursor
|
|
@@ -7444,14 +8092,14 @@ async function getConfigRules(query, chains) {
|
|
|
7444
8092
|
response.body.meta.checksum = checksum;
|
|
7445
8093
|
return response;
|
|
7446
8094
|
}
|
|
7447
|
-
function formatCursor(rule) {
|
|
8095
|
+
function formatCursor$2(rule) {
|
|
7448
8096
|
if (rule.type === "maturity") return `maturity:${rule.chain_id}:${rule.timestamp}:${rule.name}`;
|
|
7449
8097
|
if (rule.type === "callback") return `callback:${rule.chain_id}:${rule.callback_type}:${rule.address.toLowerCase()}`;
|
|
7450
8098
|
if (rule.type === "oracle") return `oracle:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7451
8099
|
if (rule.type === "collateral_token") return `collateral_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7452
8100
|
return `loan_token:${rule.chain_id}:${rule.address.toLowerCase()}`;
|
|
7453
8101
|
}
|
|
7454
|
-
function parseCursor(cursor) {
|
|
8102
|
+
function parseCursor$2(cursor) {
|
|
7455
8103
|
const [type, chain, ...rest] = cursor.split(":");
|
|
7456
8104
|
if (!type || !chain || rest.length === 0) throw new BadRequestError$1("Cursor must be in the format type:chain_id:<value>");
|
|
7457
8105
|
if (!isConfigRuleType(type)) throw new BadRequestError$1("Cursor has an invalid rule type");
|
|
@@ -7744,23 +8392,22 @@ function create$16(parameters) {
|
|
|
7744
8392
|
const loanTokenFilter = loanTokens !== void 0 && loanTokens.length > 0 ? sql`(${sql.join(loanTokens.map((token) => sql`LOWER(${obligations.loanToken}) = ${token.toLowerCase()}`), sql` OR `)})` : void 0;
|
|
7745
8393
|
const collateralFilter = collateralTokens !== void 0 && collateralTokens.length > 0 ? sql`EXISTS (
|
|
7746
8394
|
SELECT 1 FROM ${obligationCollateralsV2} oc
|
|
7747
|
-
WHERE oc.
|
|
8395
|
+
WHERE oc.obligation_key = ${obligations.obligationKey}
|
|
7748
8396
|
AND (${sql.join(collateralTokens.map((token) => sql`LOWER(oc.asset) = ${token.toLowerCase()}`), sql` OR `)})
|
|
7749
8397
|
)` : void 0;
|
|
7750
|
-
const bestAskTick = db.select({ askTick: offers.tick }).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(eq(offers.obligationId,
|
|
7751
|
-
const bestBidTick = db.select({ bidTick: offers.tick }).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(eq(offers.obligationId,
|
|
8398
|
+
const bestAskTick = db.select({ askTick: offers.tick }).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, and(eq(offers.hash, validations.offerHash), eq(offers.obligationId, validations.obligationId))).leftJoin(status, eq(validations.statusId, status.id)).where(and(eq(offers.obligationId, obligationIdKeys.obligationId), eq(offers.buy, false), gte(offers.expiry, now$3), gte(offers.maturity, now$3), lte(offers.start, now$3), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(desc(offers.tick)).limit(1).as("best_ask_tick");
|
|
8399
|
+
const bestBidTick = db.select({ bidTick: offers.tick }).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, and(eq(offers.hash, validations.offerHash), eq(offers.obligationId, validations.obligationId))).leftJoin(status, eq(validations.statusId, status.id)).where(and(eq(offers.obligationId, obligationIdKeys.obligationId), eq(offers.buy, true), gte(offers.expiry, now$3), gte(offers.maturity, now$3), lte(offers.start, now$3), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(asc(offers.tick)).limit(1).as("best_bid_tick");
|
|
7752
8400
|
const obligationsWithQuotes = db.select({
|
|
7753
|
-
obligationId:
|
|
7754
|
-
chainId:
|
|
8401
|
+
obligationId: obligationIdKeys.obligationId,
|
|
8402
|
+
chainId: obligationIdKeys.chainId,
|
|
7755
8403
|
loanToken: obligations.loanToken,
|
|
7756
|
-
collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${
|
|
8404
|
+
collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${obligationCollateralsV2.oracleAddress}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
7757
8405
|
maturity: obligations.maturity,
|
|
7758
8406
|
askTick: sql`MAX(${bestAskTick.askTick})`.as("ask_tick"),
|
|
7759
8407
|
bidTick: sql`MAX(${bestBidTick.bidTick})`.as("bid_tick"),
|
|
7760
8408
|
ask: sql`COALESCE(MAX(${bestAskTick.askTick}) + 1, 0)`.as("ask"),
|
|
7761
8409
|
bid: sql`COALESCE(MAX(${bestBidTick.bidTick}) + 1, 0)`.as("bid")
|
|
7762
|
-
}).from(obligations).innerJoin(obligationCollateralsV2, eq(obligations.
|
|
7763
|
-
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).leftJoinLateral(bestAskTick, sql`true`).leftJoinLateral(bestBidTick, sql`true`).groupBy(obligations.obligationId).where(and(ids !== void 0 && ids.length > 0 ? inArray(obligations.obligationId, ids) : void 0, chainIds !== void 0 && chainIds.length > 0 ? inArray(obligations.chainId, chainIds) : void 0, loanTokenFilter, maturities !== void 0 && maturities.length > 0 ? inArray(obligations.maturity, maturities) : gte(obligations.maturity, now$3), collateralFilter)).as("obligations_with_quotes");
|
|
8410
|
+
}).from(obligationIdKeys).innerJoin(obligations, eq(obligationIdKeys.obligationKey, obligations.obligationKey)).innerJoin(obligationCollateralsV2, eq(obligations.obligationKey, obligationCollateralsV2.obligationKey)).leftJoinLateral(bestAskTick, sql`true`).leftJoinLateral(bestBidTick, sql`true`).groupBy(obligationIdKeys.obligationId, obligationIdKeys.chainId, obligations.loanToken, obligations.maturity).where(and(ids !== void 0 && ids.length > 0 ? inArray(obligationIdKeys.obligationId, ids) : void 0, chainIds !== void 0 && chainIds.length > 0 ? inArray(obligationIdKeys.chainId, chainIds) : void 0, loanTokenFilter, maturities !== void 0 && maturities.length > 0 ? inArray(obligations.maturity, maturities) : gte(obligations.maturity, now$3), collateralFilter)).as("obligations_with_quotes");
|
|
7764
8411
|
const sortColumns = {
|
|
7765
8412
|
id: obligationsWithQuotes.obligationId,
|
|
7766
8413
|
ask: obligationsWithQuotes.ask,
|
|
@@ -7780,22 +8427,25 @@ function create$16(parameters) {
|
|
|
7780
8427
|
}).from(obligationsWithQuotes).where(buildCursorFilter(sortColumns, sort, cursorValues)).orderBy(...buildOrderBy(sortColumns, sort)).limit(limit + 1);
|
|
7781
8428
|
const hasMore = rows.length > limit;
|
|
7782
8429
|
const listedRows = (hasMore ? rows.slice(0, limit) : rows).map((row) => {
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
8430
|
+
const obligation = from$15({
|
|
8431
|
+
loanToken: row.loanToken,
|
|
8432
|
+
collaterals: row.collaterals.sort((left, right) => left.asset.localeCompare(right.asset)).map((collateral) => from$17({
|
|
8433
|
+
asset: collateral.asset,
|
|
8434
|
+
oracle: collateral.oracle,
|
|
8435
|
+
lltv: from$18(BigInt(collateral.lltv))
|
|
8436
|
+
})),
|
|
8437
|
+
maturity: row.maturity
|
|
8438
|
+
});
|
|
8439
|
+
const quote = from$11({
|
|
8440
|
+
obligationId: row.obligationId,
|
|
8441
|
+
ask: { tick: row.askTick },
|
|
8442
|
+
bid: { tick: row.bidTick }
|
|
8443
|
+
});
|
|
8444
|
+
return {
|
|
8445
|
+
obligationId: row.obligationId,
|
|
8446
|
+
chainId: row.chainId,
|
|
8447
|
+
obligation,
|
|
8448
|
+
quote,
|
|
7799
8449
|
cursorValues: {
|
|
7800
8450
|
id: row.obligationId,
|
|
7801
8451
|
ask: toBigInt(row.ask),
|
|
@@ -7813,6 +8463,8 @@ function create$16(parameters) {
|
|
|
7813
8463
|
}) : null;
|
|
7814
8464
|
return {
|
|
7815
8465
|
obligations: listedRows.map((row) => ({
|
|
8466
|
+
obligationId: row.obligationId,
|
|
8467
|
+
chainId: row.chainId,
|
|
7816
8468
|
obligation: row.obligation,
|
|
7817
8469
|
quote: row.quote
|
|
7818
8470
|
})),
|
|
@@ -7950,7 +8602,7 @@ async function getObligation(params, db) {
|
|
|
7950
8602
|
if (listing.obligations.length === 0) return failure(new NotFoundError("Obligation not found"));
|
|
7951
8603
|
const obligation = listing.obligations[0];
|
|
7952
8604
|
return success({
|
|
7953
|
-
data: from$4(obligation.obligation, obligation.quote),
|
|
8605
|
+
data: from$4(obligation.obligation, obligation.quote, obligation.chainId),
|
|
7954
8606
|
cursor: null
|
|
7955
8607
|
});
|
|
7956
8608
|
} catch (err) {
|
|
@@ -7991,7 +8643,7 @@ async function getObligations$1(queryParameters, db) {
|
|
|
7991
8643
|
limit: query.limit
|
|
7992
8644
|
});
|
|
7993
8645
|
return success({
|
|
7994
|
-
data: listing.obligations.map((item) => from$4(item.obligation, item.quote)),
|
|
8646
|
+
data: listing.obligations.map((item) => from$4(item.obligation, item.quote, item.chainId)),
|
|
7995
8647
|
cursor: listing.nextCursor
|
|
7996
8648
|
});
|
|
7997
8649
|
} catch (err) {
|
|
@@ -8029,10 +8681,10 @@ function create$15(config) {
|
|
|
8029
8681
|
return {
|
|
8030
8682
|
create: async (batches) => {
|
|
8031
8683
|
if (batches.length === 0) return [];
|
|
8032
|
-
const offersRows = batches.flatMap(({ blockNumber, offers }) => offers.map((offer) => ({
|
|
8684
|
+
const offersRows = batches.flatMap(({ blockNumber, offers }) => offers.map(({ offer, obligationId, chainId }) => ({
|
|
8033
8685
|
...serialize(offer),
|
|
8034
|
-
obligationId: obligationId(
|
|
8035
|
-
groupChainId:
|
|
8686
|
+
obligationId: obligationId.toLowerCase(),
|
|
8687
|
+
groupChainId: chainId,
|
|
8036
8688
|
groupMaker: offer.maker.toLowerCase(),
|
|
8037
8689
|
callbackAddress: offer.callback.address.toLowerCase(),
|
|
8038
8690
|
callbackData: offer.callback.data,
|
|
@@ -8042,48 +8694,67 @@ function create$15(config) {
|
|
|
8042
8694
|
if (offersRows.length === 0) return [];
|
|
8043
8695
|
try {
|
|
8044
8696
|
return await db.transaction(async (dbTx) => {
|
|
8045
|
-
const
|
|
8046
|
-
|
|
8697
|
+
const keyOf = (input) => `${input.hash.toLowerCase()}:${input.obligationId.toLowerCase()}`;
|
|
8698
|
+
const selectExisting = async (offers$1) => {
|
|
8699
|
+
if (offers$1.length === 0) return /* @__PURE__ */ new Set();
|
|
8700
|
+
const expected = new Set(offers$1.map((offer) => keyOf({
|
|
8701
|
+
hash: offer.hash,
|
|
8702
|
+
obligationId: offer.obligationId
|
|
8703
|
+
})));
|
|
8047
8704
|
const existing = /* @__PURE__ */ new Set();
|
|
8705
|
+
const hashes = [...new Set(offers$1.map((offer) => offer.hash.toLowerCase()))];
|
|
8048
8706
|
for (const batch of batch$1(hashes, DEFAULT_BATCH_SIZE$1)) {
|
|
8049
|
-
const rows = await dbTx.select({
|
|
8050
|
-
|
|
8707
|
+
const rows = await dbTx.select({
|
|
8708
|
+
hash: offers.hash,
|
|
8709
|
+
obligationId: offers.obligationId
|
|
8710
|
+
}).from(offers).where(inArray(offers.hash, batch));
|
|
8711
|
+
for (const row of rows) {
|
|
8712
|
+
const key = keyOf({
|
|
8713
|
+
hash: String(row.hash),
|
|
8714
|
+
obligationId: String(row.obligationId)
|
|
8715
|
+
});
|
|
8716
|
+
if (expected.has(key)) existing.add(key);
|
|
8717
|
+
}
|
|
8051
8718
|
}
|
|
8052
8719
|
return existing;
|
|
8053
8720
|
};
|
|
8054
8721
|
const inserted = [];
|
|
8055
8722
|
for (const batch of batch$1(offersRows, DEFAULT_BATCH_SIZE$1)) {
|
|
8056
8723
|
const rows = await dbTx.insert(offers).values(batch).onConflictDoNothing().returning();
|
|
8057
|
-
inserted.push(...rows.map((row) =>
|
|
8724
|
+
inserted.push(...rows.map((row) => ({
|
|
8725
|
+
hash: row.hash,
|
|
8726
|
+
obligationId: row.obligationId
|
|
8727
|
+
})));
|
|
8058
8728
|
}
|
|
8059
8729
|
const existing = await selectExisting(inserted);
|
|
8060
|
-
return inserted.filter((
|
|
8730
|
+
return inserted.filter((offer) => existing.has(keyOf({
|
|
8731
|
+
hash: offer.hash,
|
|
8732
|
+
obligationId: offer.obligationId
|
|
8733
|
+
})));
|
|
8061
8734
|
});
|
|
8062
8735
|
} catch (err) {
|
|
8063
8736
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
8064
|
-
throw new Error("Offers.create failed. Ensure
|
|
8737
|
+
throw new Error("Offers.create failed. Ensure obligation id keys and groups exist before inserting offers.", { cause: error });
|
|
8065
8738
|
}
|
|
8066
8739
|
},
|
|
8067
8740
|
get: async (parameters) => {
|
|
8068
8741
|
const limit = parameters?.limit ?? DEFAULT_LIMIT$3;
|
|
8069
|
-
const
|
|
8742
|
+
const rawCursor = parameters?.cursor;
|
|
8070
8743
|
const maker = parameters?.maker;
|
|
8071
|
-
|
|
8072
|
-
if (!cursor.startsWith("0x") || cursor.length !== 66) throw new Error("Invalid cursor format");
|
|
8073
|
-
}
|
|
8744
|
+
const cursor = rawCursor !== null && rawCursor !== void 0 ? parseCursor$1(rawCursor) : void 0;
|
|
8074
8745
|
const collateralsLateral = db.select({ collaterals: sql`COALESCE(
|
|
8075
8746
|
jsonb_agg(
|
|
8076
8747
|
jsonb_build_object(
|
|
8077
8748
|
'asset', ${obligationCollateralsV2.asset},
|
|
8078
|
-
'oracle', ${
|
|
8749
|
+
'oracle', ${obligationCollateralsV2.oracleAddress},
|
|
8079
8750
|
'lltv', ${obligationCollateralsV2.lltv}
|
|
8080
8751
|
)
|
|
8081
8752
|
),
|
|
8082
8753
|
'[]'::jsonb
|
|
8083
|
-
)`.as("collaterals") }).from(obligationCollateralsV2).
|
|
8084
|
-
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).where(eq(obligationCollateralsV2.obligationId, offers.obligationId)).as("collaterals_lateral");
|
|
8754
|
+
)`.as("collaterals") }).from(obligationCollateralsV2).where(eq(obligationCollateralsV2.obligationKey, obligationIdKeys.obligationKey)).as("collaterals_lateral");
|
|
8085
8755
|
const rows = (await db.select({
|
|
8086
8756
|
hash: offers.hash,
|
|
8757
|
+
obligationId: offers.obligationId,
|
|
8087
8758
|
maker: offers.groupMaker,
|
|
8088
8759
|
assets: offers.assets,
|
|
8089
8760
|
obligationUnits: offers.obligationUnits,
|
|
@@ -8095,17 +8766,18 @@ function create$15(config) {
|
|
|
8095
8766
|
group: offers.group,
|
|
8096
8767
|
session: offers.session,
|
|
8097
8768
|
buy: offers.buy,
|
|
8098
|
-
chainId:
|
|
8769
|
+
chainId: obligationIdKeys.chainId,
|
|
8099
8770
|
loanToken: obligations.loanToken,
|
|
8100
8771
|
callbackAddress: offers.callbackAddress,
|
|
8101
8772
|
callbackData: offers.callbackData,
|
|
8102
8773
|
receiverIfMakerIsSeller: offers.receiverIfMakerIsSeller,
|
|
8103
8774
|
collaterals: collateralsLateral.collaterals,
|
|
8104
8775
|
blockNumber: offers.blockNumber
|
|
8105
|
-
}).from(offers).innerJoin(
|
|
8776
|
+
}).from(offers).innerJoin(obligationIdKeys, eq(offers.obligationId, obligationIdKeys.obligationId)).innerJoin(obligations, eq(obligationIdKeys.obligationKey, obligations.obligationKey)).innerJoinLateral(collateralsLateral, sql`true`).where(and(cursor !== void 0 ? or(gt(offers.hash, cursor.hash), and(eq(offers.hash, cursor.hash), gt(offers.obligationId, cursor.obligationId))) : void 0, maker !== void 0 ? eq(offers.groupMaker, maker.toLowerCase()) : void 0)).orderBy(asc(offers.hash), asc(offers.obligationId)).limit(limit)).map((row) => {
|
|
8106
8777
|
const receiverIfMakerIsSeller = (row.receiverIfMakerIsSeller ?? row.maker).toLowerCase();
|
|
8107
8778
|
return {
|
|
8108
8779
|
hash: row.hash,
|
|
8780
|
+
obligationId: row.obligationId,
|
|
8109
8781
|
maker: row.maker,
|
|
8110
8782
|
assets: BigInt(row.assets),
|
|
8111
8783
|
obligationUnits: BigInt(row.obligationUnits),
|
|
@@ -8137,7 +8809,10 @@ function create$15(config) {
|
|
|
8137
8809
|
});
|
|
8138
8810
|
return {
|
|
8139
8811
|
rows,
|
|
8140
|
-
nextCursor: rows.length === limit ?
|
|
8812
|
+
nextCursor: rows.length === limit ? formatCursor$1({
|
|
8813
|
+
hash: rows[rows.length - 1].hash,
|
|
8814
|
+
obligationId: rows[rows.length - 1].obligationId
|
|
8815
|
+
}) : null
|
|
8141
8816
|
};
|
|
8142
8817
|
},
|
|
8143
8818
|
delete: async (parameters) => {
|
|
@@ -8160,7 +8835,7 @@ function create$15(config) {
|
|
|
8160
8835
|
const query = ({ side }) => db.selectDistinctOn([offers.obligationId], {
|
|
8161
8836
|
obligationId: offers.obligationId,
|
|
8162
8837
|
tick: offers.tick
|
|
8163
|
-
}).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, eq(offers.hash, validations.offerHash)).leftJoin(status, eq(validations.statusId, status.id)).where(and(inArray(offers.obligationId, obligationIds), eq(offers.buy, side === "buy"), gte(offers.expiry, now$2), gte(offers.maturity, now$2), lte(offers.start, now$2), sql`(${status.code} IS NULL OR ${status.code} = ${Status.VALID})`)).orderBy(offers.obligationId, side === "buy" ? sql`${offers.tick} ASC` : sql`${offers.tick} DESC`);
|
|
8838
|
+
}).from(offers).innerJoin(groups, and(eq(offers.groupChainId, groups.chainId), eq(offers.groupMaker, groups.maker), eq(offers.group, groups.group))).leftJoin(validations, and(eq(offers.hash, validations.offerHash), eq(offers.obligationId, validations.obligationId))).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`);
|
|
8164
8839
|
const [bestBuys, bestSells] = await Promise.all([query({ side: "buy" }), query({ side: "sell" })]);
|
|
8165
8840
|
const quotes = /* @__PURE__ */ new Map();
|
|
8166
8841
|
for (const row of bestSells) quotes.set(row.obligationId, {
|
|
@@ -8190,6 +8865,134 @@ function create$15(config) {
|
|
|
8190
8865
|
}
|
|
8191
8866
|
};
|
|
8192
8867
|
}
|
|
8868
|
+
const HEX_32$2 = /^0x[a-fA-F0-9]{64}$/;
|
|
8869
|
+
function parseCursor$1(cursor) {
|
|
8870
|
+
const [hash, obligationId] = cursor.split(":");
|
|
8871
|
+
if (!hash || !obligationId || !HEX_32$2.test(hash) || !HEX_32$2.test(obligationId)) throw new Error("Invalid cursor format");
|
|
8872
|
+
return {
|
|
8873
|
+
hash: hash.toLowerCase(),
|
|
8874
|
+
obligationId: obligationId.toLowerCase()
|
|
8875
|
+
};
|
|
8876
|
+
}
|
|
8877
|
+
function formatCursor$1(input) {
|
|
8878
|
+
return `${input.hash.toLowerCase()}:${input.obligationId.toLowerCase()}`;
|
|
8879
|
+
}
|
|
8880
|
+
|
|
8881
|
+
//#endregion
|
|
8882
|
+
//#region src/database/domains/Trees.ts
|
|
8883
|
+
/**
|
|
8884
|
+
* Creates a Trees domain instance for managing merkle tree metadata.
|
|
8885
|
+
*
|
|
8886
|
+
* @param config - Configuration with database instance
|
|
8887
|
+
* @returns TreesDomain instance
|
|
8888
|
+
*/
|
|
8889
|
+
function create$14(config) {
|
|
8890
|
+
const db = config.db;
|
|
8891
|
+
return {
|
|
8892
|
+
upsert: async (trees$1) => {
|
|
8893
|
+
if (trees$1.length === 0) return [];
|
|
8894
|
+
try {
|
|
8895
|
+
return await db.transaction(async (dbTx) => {
|
|
8896
|
+
const roots = [];
|
|
8897
|
+
for (const { root, signature } of trees$1) {
|
|
8898
|
+
const normalizedRoot = root.toLowerCase();
|
|
8899
|
+
const normalizedSignature = signature.toLowerCase();
|
|
8900
|
+
roots.push(normalizedRoot);
|
|
8901
|
+
await dbTx.insert(trees).values({
|
|
8902
|
+
root: normalizedRoot,
|
|
8903
|
+
rootSignature: normalizedSignature
|
|
8904
|
+
}).onConflictDoUpdate({
|
|
8905
|
+
target: [trees.root],
|
|
8906
|
+
set: {
|
|
8907
|
+
rootSignature: normalizedSignature,
|
|
8908
|
+
createdAt: sql`NOW()`
|
|
8909
|
+
}
|
|
8910
|
+
});
|
|
8911
|
+
}
|
|
8912
|
+
return roots;
|
|
8913
|
+
});
|
|
8914
|
+
} catch (err) {
|
|
8915
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
8916
|
+
throw new Error("Trees.upsert failed. Ensure obligations and offers exist before upserting roots.", { cause: error });
|
|
8917
|
+
}
|
|
8918
|
+
},
|
|
8919
|
+
upsertPaths: async (paths) => {
|
|
8920
|
+
if (paths.length === 0) return;
|
|
8921
|
+
const rows = paths.map((path) => ({
|
|
8922
|
+
offerHash: path.offerHash.toLowerCase(),
|
|
8923
|
+
obligationId: path.obligationId.toLowerCase(),
|
|
8924
|
+
treeRoot: path.treeRoot.toLowerCase(),
|
|
8925
|
+
proofNodes: concatenateProofs(path.proof)
|
|
8926
|
+
}));
|
|
8927
|
+
try {
|
|
8928
|
+
for (const batch of batch$1(rows, DEFAULT_BATCH_SIZE$1)) await db.insert(merklePaths).values(batch).onConflictDoUpdate({
|
|
8929
|
+
target: [merklePaths.offerHash, merklePaths.obligationId],
|
|
8930
|
+
set: {
|
|
8931
|
+
treeRoot: sql`excluded.tree_root`,
|
|
8932
|
+
proofNodes: sql`excluded.proof_nodes`,
|
|
8933
|
+
createdAt: sql`NOW()`
|
|
8934
|
+
}
|
|
8935
|
+
});
|
|
8936
|
+
} catch (err) {
|
|
8937
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
8938
|
+
throw new Error("Trees.upsertPaths failed. Ensure offers and roots exist before inserting merkle paths.", { cause: error });
|
|
8939
|
+
}
|
|
8940
|
+
},
|
|
8941
|
+
getAttestations: async (references) => {
|
|
8942
|
+
if (references.length === 0) return /* @__PURE__ */ new Map();
|
|
8943
|
+
const normalizedReferences = references.map((reference) => ({
|
|
8944
|
+
offerHash: reference.offerHash.toLowerCase(),
|
|
8945
|
+
obligationId: reference.obligationId.toLowerCase()
|
|
8946
|
+
}));
|
|
8947
|
+
const hashes = [...new Set(normalizedReferences.map((reference) => reference.offerHash))];
|
|
8948
|
+
const obligationIds = [...new Set(normalizedReferences.map((reference) => reference.obligationId))];
|
|
8949
|
+
const results = await db.select({
|
|
8950
|
+
offerHash: merklePaths.offerHash,
|
|
8951
|
+
obligationId: merklePaths.obligationId,
|
|
8952
|
+
treeRoot: merklePaths.treeRoot,
|
|
8953
|
+
proofNodes: merklePaths.proofNodes,
|
|
8954
|
+
rootSignature: trees.rootSignature
|
|
8955
|
+
}).from(merklePaths).innerJoin(trees, eq(merklePaths.treeRoot, trees.root)).where(sql`${inArray(merklePaths.offerHash, hashes)} AND ${inArray(merklePaths.obligationId, obligationIds)}`);
|
|
8956
|
+
const expectedKeys = new Set(normalizedReferences.map(toAttestationKey));
|
|
8957
|
+
const attestationMap = /* @__PURE__ */ new Map();
|
|
8958
|
+
for (const row of results) {
|
|
8959
|
+
const key = toAttestationKey({
|
|
8960
|
+
offerHash: row.offerHash,
|
|
8961
|
+
obligationId: row.obligationId
|
|
8962
|
+
});
|
|
8963
|
+
if (!expectedKeys.has(key)) continue;
|
|
8964
|
+
attestationMap.set(key, {
|
|
8965
|
+
root: row.treeRoot.toLowerCase(),
|
|
8966
|
+
signature: row.rootSignature.toLowerCase(),
|
|
8967
|
+
proof: splitProofs(row.proofNodes)
|
|
8968
|
+
});
|
|
8969
|
+
}
|
|
8970
|
+
return attestationMap;
|
|
8971
|
+
}
|
|
8972
|
+
};
|
|
8973
|
+
}
|
|
8974
|
+
/**
|
|
8975
|
+
* Concatenates an array of 32-byte hex hashes into a single hex string.
|
|
8976
|
+
* Empty arrays return "0x".
|
|
8977
|
+
*/
|
|
8978
|
+
function concatenateProofs(proofs) {
|
|
8979
|
+
if (proofs.length === 0) return "0x";
|
|
8980
|
+
return `0x${proofs.map((proof) => proof.toLowerCase().slice(2)).join("")}`;
|
|
8981
|
+
}
|
|
8982
|
+
/**
|
|
8983
|
+
* Splits a concatenated hex string back into an array of 32-byte hex hashes.
|
|
8984
|
+
* Returns empty array for "0x" or empty string.
|
|
8985
|
+
*/
|
|
8986
|
+
function splitProofs(concatenated) {
|
|
8987
|
+
if (!concatenated || concatenated === "0x" || concatenated.length <= 2) return [];
|
|
8988
|
+
const hex = concatenated.slice(2);
|
|
8989
|
+
const proofs = [];
|
|
8990
|
+
for (let i = 0; i < hex.length; i += 64) proofs.push(`0x${hex.slice(i, i + 64).toLowerCase()}`);
|
|
8991
|
+
return proofs;
|
|
8992
|
+
}
|
|
8993
|
+
function toAttestationKey(offer) {
|
|
8994
|
+
return `${offer.offerHash.toLowerCase()}:${offer.obligationId.toLowerCase()}`;
|
|
8995
|
+
}
|
|
8193
8996
|
|
|
8194
8997
|
//#endregion
|
|
8195
8998
|
//#region src/api/Controllers/getOffers.ts
|
|
@@ -8201,23 +9004,20 @@ function create$15(config) {
|
|
|
8201
9004
|
*/
|
|
8202
9005
|
async function getOffersQuery(db, parameters) {
|
|
8203
9006
|
const limit = parameters?.limit ?? DEFAULT_LIMIT$3;
|
|
8204
|
-
const
|
|
9007
|
+
const rawCursor = parameters?.cursor;
|
|
8205
9008
|
const maker = parameters?.maker;
|
|
8206
|
-
|
|
8207
|
-
if (!cursor.startsWith("0x") || cursor.length !== 66) throw new Error("Invalid cursor format");
|
|
8208
|
-
}
|
|
9009
|
+
const cursor = maker && rawCursor !== void 0 && rawCursor !== null ? parseMakerCursor(rawCursor) : void 0;
|
|
8209
9010
|
const now = Math.floor((Date.now() - 1) / 1e3);
|
|
8210
9011
|
const collateralsLateral = db.select({ collaterals: sql`COALESCE(
|
|
8211
9012
|
jsonb_agg(
|
|
8212
9013
|
jsonb_build_object(
|
|
8213
9014
|
'asset', ${obligationCollateralsV2.asset},
|
|
8214
|
-
'oracle', ${
|
|
9015
|
+
'oracle', ${obligationCollateralsV2.oracleAddress},
|
|
8215
9016
|
'lltv', ${obligationCollateralsV2.lltv}
|
|
8216
9017
|
)
|
|
8217
9018
|
),
|
|
8218
9019
|
'[]'::jsonb
|
|
8219
|
-
)`.as("collaterals") }).from(obligationCollateralsV2).
|
|
8220
|
-
AND ${obligationCollateralsV2.oracleAddress} = ${oracles$1.address}`).where(eq(obligationCollateralsV2.obligationId, offers.obligationId)).as("collaterals_lateral");
|
|
9020
|
+
)`.as("collaterals") }).from(obligationCollateralsV2).where(eq(obligationCollateralsV2.obligationKey, obligationIdKeys.obligationKey)).as("collaterals_lateral");
|
|
8221
9021
|
const lotBalanceExpr = sql`GREATEST(0, LEAST(
|
|
8222
9022
|
COALESCE(${positions.balance}, 0)::numeric
|
|
8223
9023
|
+ COALESCE((
|
|
@@ -8262,6 +9062,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
8262
9062
|
AND LOWER(${lots.user}) = LOWER(${callbacks.positionUser})
|
|
8263
9063
|
AND LOWER(${lots.group}) = LOWER(${offers.group})
|
|
8264
9064
|
WHERE ${offersCallbacks.offerHash} = ${offers.hash}
|
|
9065
|
+
AND ${offersCallbacks.obligationId} = ${offers.obligationId}
|
|
8265
9066
|
ORDER BY
|
|
8266
9067
|
${callbacks.positionChainId},
|
|
8267
9068
|
LOWER(${callbacks.positionContract}),
|
|
@@ -8271,6 +9072,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
8271
9072
|
), 0)`;
|
|
8272
9073
|
const rows = (await db.select({
|
|
8273
9074
|
hash: offers.hash,
|
|
9075
|
+
obligationId: offers.obligationId,
|
|
8274
9076
|
maker: offers.groupMaker,
|
|
8275
9077
|
assets: offers.assets,
|
|
8276
9078
|
obligationUnits: offers.obligationUnits,
|
|
@@ -8283,7 +9085,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
8283
9085
|
group: offers.group,
|
|
8284
9086
|
session: offers.session,
|
|
8285
9087
|
buy: offers.buy,
|
|
8286
|
-
chainId:
|
|
9088
|
+
chainId: obligationIdKeys.chainId,
|
|
8287
9089
|
loanToken: obligations.loanToken,
|
|
8288
9090
|
callbackAddress: offers.callbackAddress,
|
|
8289
9091
|
callbackData: offers.callbackData,
|
|
@@ -8300,7 +9102,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
8300
9102
|
)
|
|
8301
9103
|
END
|
|
8302
9104
|
))`.as("takeable")
|
|
8303
|
-
}).from(offers).innerJoin(
|
|
9105
|
+
}).from(offers).innerJoin(obligationIdKeys, eq(offers.obligationId, obligationIdKeys.obligationId)).innerJoin(obligations, eq(obligationIdKeys.obligationKey, obligations.obligationKey)).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 !== void 0 ? cursor.obligationId === void 0 ? gt(offers.hash, cursor.hash) : or(gt(offers.hash, cursor.hash), and(eq(offers.hash, cursor.hash), gt(offers.obligationId, cursor.obligationId))) : 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,
|
|
8304
9106
|
CASE WHEN ${offers.buy} = false
|
|
8305
9107
|
THEN ${offers.assets}::numeric - ${groups.consumed}::numeric
|
|
8306
9108
|
ELSE LEAST(
|
|
@@ -8308,10 +9110,11 @@ async function getOffersQuery(db, parameters) {
|
|
|
8308
9110
|
${availableExpr}::numeric
|
|
8309
9111
|
)
|
|
8310
9112
|
END
|
|
8311
|
-
) > 0` : void 0)).orderBy(asc(offers.hash)).limit(limit)).map((row) => {
|
|
9113
|
+
) > 0` : void 0)).orderBy(asc(offers.hash), asc(offers.obligationId)).limit(limit)).map((row) => {
|
|
8312
9114
|
const receiverIfMakerIsSeller = (row.receiverIfMakerIsSeller ?? row.maker).toLowerCase();
|
|
8313
9115
|
return {
|
|
8314
9116
|
hash: row.hash,
|
|
9117
|
+
obligationId: row.obligationId,
|
|
8315
9118
|
maker: row.maker,
|
|
8316
9119
|
assets: BigInt(row.assets),
|
|
8317
9120
|
obligationUnits: BigInt(row.obligationUnits),
|
|
@@ -8343,7 +9146,7 @@ async function getOffersQuery(db, parameters) {
|
|
|
8343
9146
|
});
|
|
8344
9147
|
return {
|
|
8345
9148
|
rows,
|
|
8346
|
-
nextCursor: rows.length === limit ? rows[rows.length - 1].hash : null
|
|
9149
|
+
nextCursor: rows.length === limit ? maker === void 0 ? rows[rows.length - 1].hash : formatOfferCursor(rows[rows.length - 1]) : null
|
|
8347
9150
|
};
|
|
8348
9151
|
}
|
|
8349
9152
|
async function getOffers$1(queryParameters, db) {
|
|
@@ -8362,12 +9165,18 @@ async function getOffers$1(queryParameters, db) {
|
|
|
8362
9165
|
cursor: query.cursor,
|
|
8363
9166
|
limit: query.limit
|
|
8364
9167
|
});
|
|
8365
|
-
const
|
|
8366
|
-
|
|
9168
|
+
const offers = rows.map((row) => ({
|
|
9169
|
+
offerHash: row.hash,
|
|
9170
|
+
obligationId: row.obligationId
|
|
9171
|
+
}));
|
|
9172
|
+
const attestationMap = await db.trees.getAttestations(offers);
|
|
8367
9173
|
return success({
|
|
8368
9174
|
data: rows.map((row) => {
|
|
8369
|
-
const
|
|
8370
|
-
|
|
9175
|
+
const key = toAttestationKey({
|
|
9176
|
+
offerHash: row.hash,
|
|
9177
|
+
obligationId: row.obligationId
|
|
9178
|
+
});
|
|
9179
|
+
const attestation = attestationMap.get(key);
|
|
8371
9180
|
return from$3({
|
|
8372
9181
|
...row,
|
|
8373
9182
|
...attestation
|
|
@@ -8385,6 +9194,19 @@ async function getOffers$1(queryParameters, db) {
|
|
|
8385
9194
|
return failure(err);
|
|
8386
9195
|
}
|
|
8387
9196
|
}
|
|
9197
|
+
function parseMakerCursor(cursor) {
|
|
9198
|
+
const [rawHash, rawObligationId, ...tail] = cursor.split(":");
|
|
9199
|
+
if (tail.length > 0) throw new Error("Invalid cursor format");
|
|
9200
|
+
if (!rawHash || !rawObligationId || !HEX_32$1.test(rawHash) || !HEX_32$1.test(rawObligationId)) throw new Error("Invalid cursor format");
|
|
9201
|
+
return {
|
|
9202
|
+
hash: rawHash.toLowerCase(),
|
|
9203
|
+
obligationId: rawObligationId.toLowerCase()
|
|
9204
|
+
};
|
|
9205
|
+
}
|
|
9206
|
+
function formatOfferCursor(row) {
|
|
9207
|
+
return `${row.hash.toLowerCase()}:${row.obligationId.toLowerCase()}`;
|
|
9208
|
+
}
|
|
9209
|
+
const HEX_32$1 = /^0x[a-fA-F0-9]{64}$/;
|
|
8388
9210
|
|
|
8389
9211
|
//#endregion
|
|
8390
9212
|
//#region src/api/Controllers/getUserPositions.ts
|
|
@@ -8426,7 +9248,8 @@ async function validateOffers(body, gatekeeper) {
|
|
|
8426
9248
|
const logger = getLogger();
|
|
8427
9249
|
const result = safeParse("validate_offers", body, (issue) => issue.message);
|
|
8428
9250
|
if (!result.success) return failure(new BadRequestError$1(result.error.issues[0]?.message ?? "Invalid request body"));
|
|
8429
|
-
const { offers: rawOffers } = result.data;
|
|
9251
|
+
const { offers: rawOffers, chain_id: rawChainId } = result.data;
|
|
9252
|
+
const chainId = rawChainId;
|
|
8430
9253
|
const parsedOffers = [];
|
|
8431
9254
|
const offerIndexByHash = /* @__PURE__ */ new Map();
|
|
8432
9255
|
for (let i = 0; i < rawOffers.length; i++) {
|
|
@@ -8445,7 +9268,10 @@ async function validateOffers(body, gatekeeper) {
|
|
|
8445
9268
|
}
|
|
8446
9269
|
}
|
|
8447
9270
|
try {
|
|
8448
|
-
const { issues } = await gatekeeper.isAllowed(
|
|
9271
|
+
const { issues } = await gatekeeper.isAllowed({
|
|
9272
|
+
offers: parsedOffers,
|
|
9273
|
+
chainId
|
|
9274
|
+
});
|
|
8449
9275
|
if (issues.length > 0) {
|
|
8450
9276
|
const mappedIssues = issues.map((issue) => {
|
|
8451
9277
|
const index = offerIndexByHash.get(hash(issue.item));
|
|
@@ -8506,14 +9332,14 @@ var Controllers_exports = /* @__PURE__ */ __exportAll({
|
|
|
8506
9332
|
//#region src/api/Api.ts
|
|
8507
9333
|
function from$1(config) {
|
|
8508
9334
|
const { db, gatekeeper, port, chainRegistry } = config;
|
|
8509
|
-
return create$
|
|
9335
|
+
return create$13({
|
|
8510
9336
|
port,
|
|
8511
9337
|
db,
|
|
8512
9338
|
gatekeeper,
|
|
8513
9339
|
chainRegistry
|
|
8514
9340
|
});
|
|
8515
9341
|
}
|
|
8516
|
-
function create$
|
|
9342
|
+
function create$13(params) {
|
|
8517
9343
|
return { serve: () => serve$1(params) };
|
|
8518
9344
|
}
|
|
8519
9345
|
/**
|
|
@@ -8640,7 +9466,7 @@ var RouterApi_exports = /* @__PURE__ */ __exportAll({
|
|
|
8640
9466
|
RouterStatusResponse: () => RouterStatusResponse,
|
|
8641
9467
|
UsersController: () => UsersController,
|
|
8642
9468
|
ValidateController: () => ValidateController,
|
|
8643
|
-
create: () => create$
|
|
9469
|
+
create: () => create$13,
|
|
8644
9470
|
from: () => from$1,
|
|
8645
9471
|
parse: () => parse,
|
|
8646
9472
|
safeParse: () => safeParse
|
|
@@ -8723,7 +9549,6 @@ async function getOffers(apiClient, parameters) {
|
|
|
8723
9549
|
group: offerData.group,
|
|
8724
9550
|
session: offerData.session,
|
|
8725
9551
|
buy: offerData.buy,
|
|
8726
|
-
chain_id: item.chain_id,
|
|
8727
9552
|
loan_token: offerData.obligation.loan_token,
|
|
8728
9553
|
collaterals: offerData.obligation.collaterals.map((collateral) => ({
|
|
8729
9554
|
asset: collateral.token,
|
|
@@ -8771,7 +9596,6 @@ async function getObligations(apiClient, parameters) {
|
|
|
8771
9596
|
}
|
|
8772
9597
|
const obligations = data?.data.map((item) => {
|
|
8773
9598
|
const obligation = fromSnakeCase$2({
|
|
8774
|
-
chain_id: item.chain_id,
|
|
8775
9599
|
loan_token: item.loan_token,
|
|
8776
9600
|
collaterals: item.collaterals.map((collateral) => ({
|
|
8777
9601
|
asset: collateral.token,
|
|
@@ -8780,16 +9604,17 @@ async function getObligations(apiClient, parameters) {
|
|
|
8780
9604
|
})),
|
|
8781
9605
|
maturity: from$16(item.maturity)
|
|
8782
9606
|
});
|
|
8783
|
-
const { obligationId: _, ...
|
|
8784
|
-
|
|
9607
|
+
const { obligationId: _, ...quote } = from$11({
|
|
9608
|
+
obligationId: item.id,
|
|
9609
|
+
ask: { tick: item.ask.tick },
|
|
9610
|
+
bid: { tick: item.bid.tick }
|
|
9611
|
+
});
|
|
9612
|
+
return {
|
|
9613
|
+
id: item.id,
|
|
9614
|
+
chainId: item.chain_id,
|
|
8785
9615
|
...obligation,
|
|
8786
|
-
...
|
|
8787
|
-
obligationId: item.id,
|
|
8788
|
-
ask: { tick: item.ask.tick },
|
|
8789
|
-
bid: { tick: item.bid.tick }
|
|
8790
|
-
})
|
|
9616
|
+
...quote
|
|
8791
9617
|
};
|
|
8792
|
-
return returned;
|
|
8793
9618
|
}) ?? [];
|
|
8794
9619
|
return {
|
|
8795
9620
|
cursor: data?.cursor ?? null,
|
|
@@ -8836,13 +9661,15 @@ var drizzle_exports = /* @__PURE__ */ __exportAll({
|
|
|
8836
9661
|
VERSION: () => VERSION,
|
|
8837
9662
|
VERSIONED_TABLE_NAMES: () => VERSIONED_TABLE_NAMES,
|
|
8838
9663
|
callbacks: () => callbacks,
|
|
8839
|
-
chains: () => chains
|
|
9664
|
+
chains: () => chains,
|
|
8840
9665
|
collectors: () => collectors,
|
|
8841
9666
|
consumedEvents: () => consumedEvents,
|
|
8842
9667
|
groups: () => groups,
|
|
8843
9668
|
lots: () => lots,
|
|
9669
|
+
lotsPositions: () => lotsPositions,
|
|
8844
9670
|
merklePaths: () => merklePaths,
|
|
8845
9671
|
obligationCollateralsV2: () => obligationCollateralsV2,
|
|
9672
|
+
obligationIdKeys: () => obligationIdKeys,
|
|
8846
9673
|
obligations: () => obligations,
|
|
8847
9674
|
offers: () => offers,
|
|
8848
9675
|
offersCallbacks: () => offersCallbacks,
|
|
@@ -8859,14 +9686,14 @@ var drizzle_exports = /* @__PURE__ */ __exportAll({
|
|
|
8859
9686
|
//#endregion
|
|
8860
9687
|
//#region src/database/domains/Blocks.ts
|
|
8861
9688
|
/** Postgres implementation. */
|
|
8862
|
-
const create$
|
|
9689
|
+
const create$12 = (config) => {
|
|
8863
9690
|
const { db, chainRegistry } = config;
|
|
8864
9691
|
const getChain = async (chainId) => {
|
|
8865
9692
|
const rows = await db.select({
|
|
8866
|
-
chainId: chains
|
|
8867
|
-
blockNumber: chains
|
|
8868
|
-
epoch: chains
|
|
8869
|
-
}).from(chains
|
|
9693
|
+
chainId: chains.chainId,
|
|
9694
|
+
blockNumber: chains.blockNumber,
|
|
9695
|
+
epoch: chains.epoch
|
|
9696
|
+
}).from(chains).where(eq(chains.chainId, chainId)).limit(1);
|
|
8870
9697
|
if (rows.length === 0) throw new Error(`Chain state not initialized for chain ${chainId}. Call blocks.init first.`);
|
|
8871
9698
|
const row = rows[0];
|
|
8872
9699
|
return {
|
|
@@ -8894,11 +9721,11 @@ const create$13 = (config) => {
|
|
|
8894
9721
|
};
|
|
8895
9722
|
const getChains = async (parameters) => {
|
|
8896
9723
|
return (await db.select({
|
|
8897
|
-
chainId: chains
|
|
8898
|
-
blockNumber: chains
|
|
8899
|
-
epoch: chains
|
|
8900
|
-
updatedAt: chains
|
|
8901
|
-
}).from(chains
|
|
9724
|
+
chainId: chains.chainId,
|
|
9725
|
+
blockNumber: chains.blockNumber,
|
|
9726
|
+
epoch: chains.epoch,
|
|
9727
|
+
updatedAt: chains.updatedAt
|
|
9728
|
+
}).from(chains).where(parameters?.chainId !== void 0 ? eq(chains.chainId, parameters.chainId) : sql`TRUE`).orderBy(asc(chains.chainId))).map((row) => ({
|
|
8902
9729
|
chainId: row.chainId,
|
|
8903
9730
|
blockNumber: Number(row.blockNumber),
|
|
8904
9731
|
epoch: BigInt(row.epoch),
|
|
@@ -8924,14 +9751,14 @@ const create$13 = (config) => {
|
|
|
8924
9751
|
const name = parameters.collectorName.toLowerCase();
|
|
8925
9752
|
const deploymentBlock = chainRegistry.getById(parameters.chainId)?.custom?.mempool.blockCreated ?? 0;
|
|
8926
9753
|
const { chain, collector } = await db.transaction(async (dbTx) => {
|
|
8927
|
-
const chainRows = await dbTx.insert(chains
|
|
9754
|
+
const chainRows = await dbTx.insert(chains).values({
|
|
8928
9755
|
chainId: parameters.chainId,
|
|
8929
9756
|
blockNumber: deploymentBlock
|
|
8930
9757
|
}).onConflictDoUpdate({
|
|
8931
|
-
target: chains
|
|
9758
|
+
target: chains.chainId,
|
|
8932
9759
|
set: {
|
|
8933
|
-
blockNumber: sql`${chains
|
|
8934
|
-
epoch: sql`${chains
|
|
9760
|
+
blockNumber: sql`${chains.blockNumber}`,
|
|
9761
|
+
epoch: sql`${chains.epoch}`
|
|
8935
9762
|
}
|
|
8936
9763
|
}).returning();
|
|
8937
9764
|
if (chainRows.length === 0) throw new Error(`Failed to initialize chain state for chain ${parameters.chainId}`);
|
|
@@ -8971,28 +9798,28 @@ const create$13 = (config) => {
|
|
|
8971
9798
|
const advanceChain = async (parameters) => {
|
|
8972
9799
|
if (parameters.blockNumber < 0) throw new Error("Block number cannot be negative");
|
|
8973
9800
|
if (parameters.epoch < 0n) throw new Error("Epoch cannot be negative");
|
|
8974
|
-
if ((await db.update(chains
|
|
9801
|
+
if ((await db.update(chains).set({
|
|
8975
9802
|
blockNumber: parameters.blockNumber,
|
|
8976
9803
|
epoch: parameters.epoch.toString(),
|
|
8977
9804
|
updatedAt: sql`now()`
|
|
8978
|
-
}).where(eq(chains
|
|
9805
|
+
}).where(eq(chains.chainId, parameters.chainId)).returning()).length === 0) throw new Error(`Chain state not initialized for chain ${parameters.chainId}. Call blocks.init first.`);
|
|
8979
9806
|
};
|
|
8980
9807
|
const advanceCollector = async (parameters) => {
|
|
8981
9808
|
if (parameters.blockNumber < 0) throw new Error("Block number cannot be negative");
|
|
8982
9809
|
if (parameters.epoch < 0n) throw new Error("Epoch cannot be negative");
|
|
8983
9810
|
const name = parameters.collectorName.toLowerCase();
|
|
8984
9811
|
const chain = db.select({
|
|
8985
|
-
chainId: chains
|
|
8986
|
-
currentEpoch: chains
|
|
8987
|
-
currentBlockNumber: chains
|
|
8988
|
-
}).from(chains
|
|
9812
|
+
chainId: chains.chainId,
|
|
9813
|
+
currentEpoch: chains.epoch,
|
|
9814
|
+
currentBlockNumber: chains.blockNumber
|
|
9815
|
+
}).from(chains).where(eq(chains.chainId, parameters.chainId)).as("chain");
|
|
8989
9816
|
const hasReorgHappened = (await db.select().from(collectors).leftJoin(chain, eq(collectors.chainId, chain.chainId)).where(and(eq(collectors.chainId, parameters.chainId), eq(collectors.name, name), gt(chain.currentEpoch, collectors.epoch), eq(chain.currentEpoch, parameters.epoch.toString()), gte(collectors.blockNumber, parameters.blockNumber))).limit(1)).length > 0;
|
|
8990
9817
|
if ((await db.update(collectors).set({
|
|
8991
9818
|
blockNumber: parameters.blockNumber,
|
|
8992
9819
|
epoch: parameters.epoch.toString(),
|
|
8993
9820
|
updatedAt: sql`now()`
|
|
8994
9821
|
}).from(chain).where(and(eq(collectors.chainId, parameters.chainId), eq(collectors.name, name), eq(chain.currentEpoch, parameters.epoch.toString()), gte(chain.currentBlockNumber, parameters.blockNumber), ...hasReorgHappened ? [] : [lte(collectors.blockNumber, parameters.blockNumber)])).returning()).length > 0) return;
|
|
8995
|
-
if ((await db.select({ chainId: chains
|
|
9822
|
+
if ((await db.select({ chainId: chains.chainId }).from(chains).where(eq(chains.chainId, parameters.chainId)).limit(1)).length === 0) throw new Error(`Chain state not initialized for chain ${parameters.chainId}. Call blocks.init first.`);
|
|
8996
9823
|
if ((await db.select({ chainId: collectors.chainId }).from(collectors).where(and(eq(collectors.chainId, parameters.chainId), eq(collectors.name, name))).limit(1)).length === 0) throw new Error(`Collector state not initialized for ${name} on chain ${parameters.chainId}. Call blocks.init first.`);
|
|
8997
9824
|
throw new Error(`A chain reorg has happened on chain ${parameters.chainId}, update of the collector ${name} is aborted`);
|
|
8998
9825
|
};
|
|
@@ -9040,7 +9867,7 @@ const create$13 = (config) => {
|
|
|
9040
9867
|
//#region src/database/domains/Book.ts
|
|
9041
9868
|
const DEFAULT_LIMIT$2 = 100;
|
|
9042
9869
|
const MAX_TOTAL_OFFERS = 500;
|
|
9043
|
-
function create$
|
|
9870
|
+
function create$11(config) {
|
|
9044
9871
|
const db = config.db;
|
|
9045
9872
|
const logger = getLogger();
|
|
9046
9873
|
const getOffers = async (parameters) => {
|
|
@@ -9126,18 +9953,17 @@ async function _getOffers(db, params) {
|
|
|
9126
9953
|
const { obligationId, side, now, priceSortDirection, cursor, limit } = params;
|
|
9127
9954
|
const raw = await db.execute(sql`
|
|
9128
9955
|
WITH collats AS MATERIALIZED (
|
|
9129
|
-
SELECT
|
|
9956
|
+
SELECT oia.obligation_id,
|
|
9130
9957
|
COALESCE(jsonb_agg(jsonb_build_object(
|
|
9131
9958
|
'asset', oc.asset,
|
|
9132
|
-
'oracle',
|
|
9959
|
+
'oracle', oc.oracle_address,
|
|
9133
9960
|
'lltv', oc.lltv
|
|
9134
9961
|
) ORDER BY oc.asset), '[]'::jsonb) AS collaterals
|
|
9135
|
-
FROM ${
|
|
9136
|
-
JOIN ${
|
|
9137
|
-
ON
|
|
9138
|
-
|
|
9139
|
-
|
|
9140
|
-
GROUP BY oc.obligation_id
|
|
9962
|
+
FROM ${obligationIdKeys} oia
|
|
9963
|
+
JOIN ${obligationCollateralsV2} oc
|
|
9964
|
+
ON oc.obligation_key = oia.obligation_key
|
|
9965
|
+
WHERE oia.obligation_id = ${obligationId}
|
|
9966
|
+
GROUP BY oia.obligation_id
|
|
9141
9967
|
),
|
|
9142
9968
|
winners AS (
|
|
9143
9969
|
SELECT DISTINCT ON (o.group_chain_id, o.group_maker, o."group_group")
|
|
@@ -9145,6 +9971,7 @@ async function _getOffers(db, params) {
|
|
|
9145
9971
|
FROM ${offers} o
|
|
9146
9972
|
LEFT JOIN ${validations} v
|
|
9147
9973
|
ON v.offer_hash = o.hash
|
|
9974
|
+
AND v.obligation_id = o.obligation_id
|
|
9148
9975
|
LEFT JOIN ${status} s
|
|
9149
9976
|
ON s.id = v.status_id
|
|
9150
9977
|
WHERE o.obligation_id = ${obligationId}
|
|
@@ -9171,8 +9998,10 @@ async function _getOffers(db, params) {
|
|
|
9171
9998
|
ON g.chain_id = w.group_chain_id
|
|
9172
9999
|
AND g.maker = w.group_maker
|
|
9173
10000
|
AND g."group" = w."group_group"
|
|
10001
|
+
JOIN ${obligationIdKeys} oia
|
|
10002
|
+
ON oia.obligation_id = w.obligation_id
|
|
9174
10003
|
JOIN ${obligations} obl
|
|
9175
|
-
ON obl.
|
|
10004
|
+
ON obl.obligation_key = oia.obligation_key
|
|
9176
10005
|
),
|
|
9177
10006
|
paged AS (
|
|
9178
10007
|
SELECT e.*
|
|
@@ -9271,7 +10100,9 @@ async function _getOffers(db, params) {
|
|
|
9271
10100
|
END
|
|
9272
10101
|
)) AS lot_balance
|
|
9273
10102
|
FROM paged p
|
|
9274
|
-
LEFT JOIN ${offersCallbacks} oc
|
|
10103
|
+
LEFT JOIN ${offersCallbacks} oc
|
|
10104
|
+
ON oc.offer_hash = p.hash
|
|
10105
|
+
AND oc.obligation_id = p.obligation_id
|
|
9275
10106
|
LEFT JOIN ${callbacks} c ON c.id = oc.callback_id
|
|
9276
10107
|
LEFT JOIN ${lots} l
|
|
9277
10108
|
ON l.chain_id = c.position_chain_id
|
|
@@ -9356,11 +10187,13 @@ async function _getOffers(db, params) {
|
|
|
9356
10187
|
AND NOT EXISTS (
|
|
9357
10188
|
SELECT 1 FROM ${offersCallbacks} oc2
|
|
9358
10189
|
WHERE oc2.offer_hash = p.hash
|
|
10190
|
+
AND oc2.obligation_id = p.obligation_id
|
|
9359
10191
|
)
|
|
9360
10192
|
)
|
|
9361
10193
|
-- Final SELECT with inline takeable computation
|
|
9362
10194
|
SELECT
|
|
9363
10195
|
oc.hash,
|
|
10196
|
+
oc.obligation_id,
|
|
9364
10197
|
oc.group_maker,
|
|
9365
10198
|
oc.assets,
|
|
9366
10199
|
oc.obligation_units,
|
|
@@ -9409,6 +10242,7 @@ async function _getOffers(db, params) {
|
|
|
9409
10242
|
const receiverIfMakerIsSeller = (row.receiver_if_maker_is_seller ?? row.group_maker).toLowerCase();
|
|
9410
10243
|
return {
|
|
9411
10244
|
hash: row.hash,
|
|
10245
|
+
obligationId: row.obligation_id,
|
|
9412
10246
|
maker: row.group_maker,
|
|
9413
10247
|
assets: BigInt(row.assets),
|
|
9414
10248
|
obligationUnits: BigInt(row.obligation_units ?? 0),
|
|
@@ -9508,7 +10342,7 @@ let LevelCursor;
|
|
|
9508
10342
|
* @param db - Database core instance.
|
|
9509
10343
|
* @returns Callbacks domain. {@link CallbacksDomain}
|
|
9510
10344
|
*/
|
|
9511
|
-
function create$
|
|
10345
|
+
function create$10(db) {
|
|
9512
10346
|
return {
|
|
9513
10347
|
upsert: async (inputs) => {
|
|
9514
10348
|
if (inputs.length === 0) return;
|
|
@@ -9522,18 +10356,21 @@ function create$11(db) {
|
|
|
9522
10356
|
idCache.set(preimage, id);
|
|
9523
10357
|
return id;
|
|
9524
10358
|
};
|
|
9525
|
-
for (const { offerHash, callbacks } of inputs) {
|
|
10359
|
+
for (const { offerHash, obligationId, callbacks } of inputs) {
|
|
9526
10360
|
const normalizedOfferHash = offerHash.toLowerCase();
|
|
10361
|
+
const normalizedObligationId = obligationId.toLowerCase();
|
|
9527
10362
|
for (const callback of callbacks) {
|
|
9528
10363
|
const normalized = {
|
|
9529
10364
|
chainId: callback.chainId,
|
|
9530
10365
|
contract: callback.contract.toLowerCase(),
|
|
9531
10366
|
user: callback.user.toLowerCase(),
|
|
9532
|
-
amount: callback.amount
|
|
10367
|
+
amount: callback.amount,
|
|
10368
|
+
positionTypeId: callback.positionTypeId
|
|
9533
10369
|
};
|
|
9534
10370
|
const id = callbackId(normalized);
|
|
9535
10371
|
offersCallbacksRows.push({
|
|
9536
10372
|
offerHash: normalizedOfferHash,
|
|
10373
|
+
obligationId: normalizedObligationId,
|
|
9537
10374
|
callbackId: id
|
|
9538
10375
|
});
|
|
9539
10376
|
if (seenCallbackIds.has(id)) continue;
|
|
@@ -9543,6 +10380,7 @@ function create$11(db) {
|
|
|
9543
10380
|
positionChainId: normalized.chainId,
|
|
9544
10381
|
positionContract: normalized.contract,
|
|
9545
10382
|
positionUser: normalized.user,
|
|
10383
|
+
positionTypeId: normalized.positionTypeId,
|
|
9546
10384
|
amount: normalized.amount.toString()
|
|
9547
10385
|
});
|
|
9548
10386
|
}
|
|
@@ -9563,7 +10401,7 @@ function create$11(db) {
|
|
|
9563
10401
|
|
|
9564
10402
|
//#endregion
|
|
9565
10403
|
//#region src/database/domains/Consumed.ts
|
|
9566
|
-
function create$
|
|
10404
|
+
function create$9(db) {
|
|
9567
10405
|
return {
|
|
9568
10406
|
create: async (events) => {
|
|
9569
10407
|
if (events.length === 0) return;
|
|
@@ -9611,7 +10449,7 @@ function create$10(db) {
|
|
|
9611
10449
|
* @param db - Database core instance.
|
|
9612
10450
|
* @returns Groups domain. {@link GroupsDomain}
|
|
9613
10451
|
*/
|
|
9614
|
-
function create$
|
|
10452
|
+
function create$8(db) {
|
|
9615
10453
|
return { create: async (groups$1) => {
|
|
9616
10454
|
if (groups$1.length === 0) return;
|
|
9617
10455
|
const rows = groups$1.map((group) => ({
|
|
@@ -9627,7 +10465,7 @@ function create$9(db) {
|
|
|
9627
10465
|
|
|
9628
10466
|
//#endregion
|
|
9629
10467
|
//#region src/database/domains/Lots.ts
|
|
9630
|
-
function create$
|
|
10468
|
+
function create$7(db) {
|
|
9631
10469
|
return {
|
|
9632
10470
|
get: async (parameters) => {
|
|
9633
10471
|
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
@@ -9655,6 +10493,17 @@ function create$8(db) {
|
|
|
9655
10493
|
const existing = lotsByKey.get(key);
|
|
9656
10494
|
if (!existing || offer.size > existing.size) lotsByKey.set(key, offer);
|
|
9657
10495
|
}
|
|
10496
|
+
const positionsByKey = /* @__PURE__ */ new Map();
|
|
10497
|
+
for (const offer of lotsByKey.values()) {
|
|
10498
|
+
const posKey = `${offer.positionChainId}-${offer.positionContract}-${offer.positionUser}`.toLowerCase();
|
|
10499
|
+
if (!positionsByKey.has(posKey)) positionsByKey.set(posKey, {
|
|
10500
|
+
chainId: offer.positionChainId,
|
|
10501
|
+
contract: offer.positionContract.toLowerCase(),
|
|
10502
|
+
user: offer.positionUser.toLowerCase(),
|
|
10503
|
+
positionTypeId: offer.positionTypeId
|
|
10504
|
+
});
|
|
10505
|
+
}
|
|
10506
|
+
for (const row of positionsByKey.values()) await db.insert(lotsPositions).values(row).onConflictDoNothing();
|
|
9658
10507
|
for (const offer of lotsByKey.values()) if ((await db.select().from(lots).where(and(eq(lots.chainId, offer.positionChainId), eq(lots.contract, offer.positionContract.toLowerCase()), eq(lots.user, offer.positionUser.toLowerCase()), eq(lots.group, offer.group.toLowerCase()), eq(lots.obligationId, offer.obligationId.toLowerCase()))).limit(1)).length === 0) {
|
|
9659
10508
|
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())));
|
|
9660
10509
|
const newLower = BigInt(maxUpperResult[0]?.maxUpper ?? "0");
|
|
@@ -9680,58 +10529,72 @@ function create$8(db) {
|
|
|
9680
10529
|
* @param db - Database core instance.
|
|
9681
10530
|
* @returns Obligations domain. {@link ObligationsDomain}
|
|
9682
10531
|
*/
|
|
9683
|
-
function create$
|
|
10532
|
+
function create$6(db) {
|
|
9684
10533
|
return {
|
|
9685
10534
|
get: async (parameters) => {
|
|
9686
10535
|
const chainIds = parameters?.chainId;
|
|
9687
10536
|
const now$1 = now();
|
|
9688
10537
|
return (await db.select({
|
|
9689
|
-
|
|
10538
|
+
obligationId: obligationIdKeys.obligationId,
|
|
10539
|
+
chainId: obligationIdKeys.chainId,
|
|
10540
|
+
morphoV2: obligationIdKeys.morphoV2,
|
|
9690
10541
|
loanToken: obligations.loanToken,
|
|
9691
|
-
collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${
|
|
10542
|
+
collaterals: sql`ARRAY_AGG(jsonb_build_object('asset', ${obligationCollateralsV2.asset}, 'oracle', ${obligationCollateralsV2.oracleAddress}, 'lltv', ${obligationCollateralsV2.lltv}))`.as("collaterals"),
|
|
9692
10543
|
maturity: obligations.maturity
|
|
9693
|
-
}).from(obligations).innerJoin(obligationCollateralsV2, eq(obligations.
|
|
9694
|
-
|
|
10544
|
+
}).from(obligationIdKeys).innerJoin(obligations, eq(obligationIdKeys.obligationKey, obligations.obligationKey)).innerJoin(obligationCollateralsV2, eq(obligations.obligationKey, obligationCollateralsV2.obligationKey)).groupBy(obligationIdKeys.obligationId, obligationIdKeys.chainId, obligationIdKeys.morphoV2, obligations.loanToken, obligations.maturity).where(and(chainIds !== void 0 && chainIds.length > 0 ? inArray(obligationIdKeys.chainId, chainIds) : void 0, gte(obligations.maturity, now$1))).orderBy(asc(obligationIdKeys.obligationId))).map((row) => ({
|
|
10545
|
+
obligationId: row.obligationId,
|
|
9695
10546
|
chainId: row.chainId,
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
10547
|
+
morphoV2: row.morphoV2,
|
|
10548
|
+
obligation: from$15({
|
|
10549
|
+
loanToken: row.loanToken,
|
|
10550
|
+
collaterals: row.collaterals.sort((left, right) => left.asset.localeCompare(right.asset)).map((collateral) => from$17({
|
|
10551
|
+
asset: collateral.asset,
|
|
10552
|
+
oracle: collateral.oracle,
|
|
10553
|
+
lltv: from$18(BigInt(collateral.lltv))
|
|
10554
|
+
})),
|
|
10555
|
+
maturity: row.maturity
|
|
10556
|
+
})
|
|
9703
10557
|
}));
|
|
9704
10558
|
},
|
|
9705
10559
|
create: async (obligations$1) => {
|
|
9706
10560
|
if (obligations$1.length === 0) return;
|
|
9707
|
-
const
|
|
9708
|
-
|
|
9709
|
-
|
|
9710
|
-
|
|
10561
|
+
const obligationsByKey = /* @__PURE__ */ new Map();
|
|
10562
|
+
const obligationIdKeysById = /* @__PURE__ */ new Map();
|
|
10563
|
+
for (const input of obligations$1) {
|
|
10564
|
+
const obligationKey = key(input.obligation).toLowerCase();
|
|
10565
|
+
if (!obligationsByKey.has(obligationKey)) obligationsByKey.set(obligationKey, input.obligation);
|
|
10566
|
+
const obligationId = input.obligationId.toLowerCase();
|
|
10567
|
+
if (!obligationIdKeysById.has(obligationId)) obligationIdKeysById.set(obligationId, input);
|
|
9711
10568
|
}
|
|
9712
10569
|
try {
|
|
9713
10570
|
await db.transaction(async (dbTx) => {
|
|
9714
|
-
const obligationRows =
|
|
9715
|
-
|
|
9716
|
-
|
|
9717
|
-
|
|
9718
|
-
maturity: obligation.maturity
|
|
10571
|
+
const obligationRows = Array.from(obligationsByKey.entries()).map(([obligationKey, item]) => ({
|
|
10572
|
+
obligationKey,
|
|
10573
|
+
loanToken: item.loanToken.toLowerCase(),
|
|
10574
|
+
maturity: item.maturity
|
|
9719
10575
|
}));
|
|
9720
10576
|
for (const batch of batch$1(obligationRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(obligations).values(batch).onConflictDoNothing();
|
|
9721
|
-
const
|
|
9722
|
-
|
|
9723
|
-
|
|
10577
|
+
const obligationIdKeyRows = Array.from(obligationIdKeysById.entries()).map(([obligationId, input]) => ({
|
|
10578
|
+
obligationId,
|
|
10579
|
+
obligationKey: key(input.obligation).toLowerCase(),
|
|
10580
|
+
chainId: input.chainId,
|
|
10581
|
+
morphoV2: input.morphoV2.toLowerCase()
|
|
10582
|
+
}));
|
|
10583
|
+
for (const batch of batch$1(obligationIdKeyRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(obligationIdKeys).values(batch).onConflictDoNothing();
|
|
10584
|
+
const collateralRows = Array.from(obligationsByKey.entries()).flatMap(([obligationKey, item]) => {
|
|
10585
|
+
return [...item.collaterals].sort((a, b) => a.asset.toLowerCase().localeCompare(b.asset.toLowerCase())).map((collateral, collateralIndex) => ({
|
|
10586
|
+
obligationKey,
|
|
9724
10587
|
asset: collateral.asset.toLowerCase(),
|
|
9725
|
-
oracleChainId: obligation.chainId,
|
|
9726
10588
|
oracleAddress: collateral.oracle.toLowerCase(),
|
|
9727
|
-
lltv: collateral.lltv
|
|
10589
|
+
lltv: collateral.lltv,
|
|
10590
|
+
collateralIndex
|
|
9728
10591
|
}));
|
|
9729
10592
|
});
|
|
9730
10593
|
for (const batch of batch$1(collateralRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(obligationCollateralsV2).values(batch).onConflictDoNothing();
|
|
9731
10594
|
});
|
|
9732
10595
|
} catch (err) {
|
|
9733
10596
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
9734
|
-
throw new Error("Obligations.create failed. Ensure
|
|
10597
|
+
throw new Error("Obligations.create failed. Ensure obligation id keys are valid before inserting offers.", { cause: error });
|
|
9735
10598
|
}
|
|
9736
10599
|
}
|
|
9737
10600
|
};
|
|
@@ -9739,7 +10602,7 @@ function create$7(db) {
|
|
|
9739
10602
|
|
|
9740
10603
|
//#endregion
|
|
9741
10604
|
//#region src/database/domains/Offsets.ts
|
|
9742
|
-
function create$
|
|
10605
|
+
function create$5(db) {
|
|
9743
10606
|
return { get: async (parameters) => {
|
|
9744
10607
|
const { chainId, user, contract, group, obligationId } = parameters ?? {};
|
|
9745
10608
|
const conditions = [];
|
|
@@ -9761,7 +10624,7 @@ function create$6(db) {
|
|
|
9761
10624
|
|
|
9762
10625
|
//#endregion
|
|
9763
10626
|
//#region src/database/domains/Oracles.ts
|
|
9764
|
-
function create$
|
|
10627
|
+
function create$4(db) {
|
|
9765
10628
|
return {
|
|
9766
10629
|
get: async ({ chainId }) => {
|
|
9767
10630
|
return (await db.select({
|
|
@@ -9804,19 +10667,20 @@ function create$5(db) {
|
|
|
9804
10667
|
//#endregion
|
|
9805
10668
|
//#region src/database/domains/Positions.ts
|
|
9806
10669
|
const DEFAULT_LIMIT$1 = 100;
|
|
9807
|
-
const create$
|
|
10670
|
+
const create$3 = (db) => {
|
|
9808
10671
|
return {
|
|
9809
10672
|
upsert: async (positions$1) => {
|
|
9810
10673
|
const positionsMap = /* @__PURE__ */ new Map();
|
|
9811
10674
|
for (const p of positions$1) {
|
|
9812
|
-
const key = `${p.chainId}-${p.contract}-${p.user}`.toLowerCase();
|
|
9813
|
-
const zeroKey = `${p.chainId}-${p.contract}-${zeroAddress}`.toLowerCase();
|
|
10675
|
+
const key = `${p.chainId}-${p.contract}-${p.user}-${p.asset}`.toLowerCase();
|
|
10676
|
+
const zeroKey = `${p.chainId}-${p.contract}-${zeroAddress}-${p.asset}`.toLowerCase();
|
|
9814
10677
|
if (!positionsMap.has(zeroKey)) positionsMap.set(zeroKey, {
|
|
9815
10678
|
chainId: p.chainId,
|
|
9816
10679
|
contract: p.contract,
|
|
9817
10680
|
user: zeroAddress,
|
|
9818
10681
|
balance: 0n,
|
|
9819
10682
|
type: p.type,
|
|
10683
|
+
asset: p.asset,
|
|
9820
10684
|
blockNumber: p.blockNumber
|
|
9821
10685
|
});
|
|
9822
10686
|
if (!positionsMap.has(key)) {
|
|
@@ -9827,14 +10691,14 @@ const create$4 = (db) => {
|
|
|
9827
10691
|
}
|
|
9828
10692
|
if (positionsMap.size === 0) return 0;
|
|
9829
10693
|
const rows = Array.from(positionsMap.values()).map((p) => {
|
|
9830
|
-
const positionTypeId =
|
|
10694
|
+
const positionTypeId$1 = positionTypeId(p.type);
|
|
9831
10695
|
return {
|
|
9832
10696
|
chainId: p.chainId,
|
|
9833
10697
|
contract: p.contract.toLowerCase(),
|
|
9834
10698
|
user: p.user.toLowerCase(),
|
|
9835
|
-
positionTypeId,
|
|
10699
|
+
positionTypeId: positionTypeId$1,
|
|
9836
10700
|
...p.balance !== void 0 ? { balance: p.balance.toString() } : {},
|
|
9837
|
-
|
|
10701
|
+
asset: p.asset.toLowerCase(),
|
|
9838
10702
|
blockNumber: p.blockNumber
|
|
9839
10703
|
};
|
|
9840
10704
|
});
|
|
@@ -9844,11 +10708,12 @@ const create$4 = (db) => {
|
|
|
9844
10708
|
target: [
|
|
9845
10709
|
positions.chainId,
|
|
9846
10710
|
positions.contract,
|
|
9847
|
-
positions.user
|
|
10711
|
+
positions.user,
|
|
10712
|
+
positions.positionTypeId,
|
|
10713
|
+
positions.asset
|
|
9848
10714
|
],
|
|
9849
10715
|
set: {
|
|
9850
10716
|
balance: sql`EXCLUDED.balance`,
|
|
9851
|
-
asset: sql`COALESCE(EXCLUDED.asset, ${positions.asset})`,
|
|
9852
10717
|
blockNumber: sql`EXCLUDED.block_number`,
|
|
9853
10718
|
updatedAt: sql`NOW()`
|
|
9854
10719
|
},
|
|
@@ -9867,20 +10732,23 @@ const create$4 = (db) => {
|
|
|
9867
10732
|
cursor = {
|
|
9868
10733
|
chainId: parsed.chainId,
|
|
9869
10734
|
contract: parsed.contract,
|
|
9870
|
-
user: parsed.user
|
|
10735
|
+
user: parsed.user,
|
|
10736
|
+
positionTypeId: parsed.positionTypeId ?? 0,
|
|
10737
|
+
asset: parsed.asset ?? ""
|
|
9871
10738
|
};
|
|
9872
10739
|
}
|
|
9873
|
-
const positions$2 = await db.select().from(positions).where(and(ne(positions.user, zeroAddress), filled === void 0 ? sql`true` : sql`${positions.balance} IS ${filled === true ? sql`NOT` : sql``} NULL`, type !== void 0 ? eq(positions.positionTypeId,
|
|
10740
|
+
const positions$2 = await db.select().from(positions).where(and(ne(positions.user, zeroAddress), filled === void 0 ? sql`true` : sql`${positions.balance} IS ${filled === true ? sql`NOT` : sql``} NULL`, type !== void 0 ? eq(positions.positionTypeId, positionTypeId(type)) : sql`true`, chainId !== void 0 ? eq(positions.chainId, chainId) : sql`true`, (() => {
|
|
9874
10741
|
if (cursor === null || cursor === void 0) return sql`true`;
|
|
9875
10742
|
return sql`
|
|
9876
|
-
(${chainId === void 0 ? sql`"chain_id", ` : sql``}"contract", "user") > (${chainId === void 0 ? sql`${cursor.chainId}, ` : sql``}${cursor.contract}, ${cursor.user})
|
|
10743
|
+
(${chainId === void 0 ? sql`"chain_id", ` : sql``}"contract", "user", "position_type_id", "asset") > (${chainId === void 0 ? sql`${cursor.chainId}, ` : sql``}${cursor.contract}, ${cursor.user}, ${cursor.positionTypeId}, ${cursor.asset})
|
|
9877
10744
|
`;
|
|
9878
|
-
})())).orderBy(asc(positions.chainId), asc(positions.contract), asc(positions.user), asc(positions.
|
|
10745
|
+
})())).orderBy(asc(positions.chainId), asc(positions.contract), asc(positions.user), asc(positions.positionTypeId), asc(positions.asset)).limit(limit);
|
|
9879
10746
|
const nextCursor = positions$2.length === limit ? Buffer.from(JSON.stringify({
|
|
9880
10747
|
chainId: positions$2[positions$2.length - 1].chainId.toString(),
|
|
9881
10748
|
contract: positions$2[positions$2.length - 1].contract,
|
|
9882
10749
|
user: positions$2[positions$2.length - 1].user,
|
|
9883
|
-
|
|
10750
|
+
positionTypeId: positions$2[positions$2.length - 1].positionTypeId,
|
|
10751
|
+
asset: positions$2[positions$2.length - 1].asset
|
|
9884
10752
|
})).toString("base64url") : null;
|
|
9885
10753
|
return {
|
|
9886
10754
|
positions: positions$2.map((p) => ({
|
|
@@ -9889,14 +10757,14 @@ const create$4 = (db) => {
|
|
|
9889
10757
|
user: p.user,
|
|
9890
10758
|
type: Object.values(Type)[p.positionTypeId - 1],
|
|
9891
10759
|
balance: p.balance !== null ? BigInt(p.balance) : void 0,
|
|
9892
|
-
|
|
10760
|
+
asset: p.asset,
|
|
9893
10761
|
blockNumber: p.blockNumber
|
|
9894
10762
|
})),
|
|
9895
10763
|
nextCursor
|
|
9896
10764
|
};
|
|
9897
10765
|
},
|
|
9898
10766
|
getByUser: async (parameters) => {
|
|
9899
|
-
const { user, limit = DEFAULT_LIMIT$1, cursor: encodedCursor } = parameters;
|
|
10767
|
+
const { user, type, limit = DEFAULT_LIMIT$1, cursor: encodedCursor } = parameters;
|
|
9900
10768
|
let cursor = null;
|
|
9901
10769
|
if (encodedCursor !== null && encodedCursor !== void 0) {
|
|
9902
10770
|
const parsed = JSON.parse(Buffer.from(encodedCursor, "base64url").toString("utf8"));
|
|
@@ -9904,6 +10772,8 @@ const create$4 = (db) => {
|
|
|
9904
10772
|
cursor = {
|
|
9905
10773
|
chainId: parsed.chainId,
|
|
9906
10774
|
contract: parsed.contract,
|
|
10775
|
+
positionTypeId: parsed.positionTypeId ?? 0,
|
|
10776
|
+
asset: parsed.asset ?? "",
|
|
9907
10777
|
obligationId: parsed.obligationId ?? null
|
|
9908
10778
|
};
|
|
9909
10779
|
}
|
|
@@ -9991,6 +10861,8 @@ const create$4 = (db) => {
|
|
|
9991
10861
|
p.contract,
|
|
9992
10862
|
p."user",
|
|
9993
10863
|
p.block_number,
|
|
10864
|
+
p.position_type_id,
|
|
10865
|
+
p.asset,
|
|
9994
10866
|
po.obligation_id,
|
|
9995
10867
|
COALESCE(po.reserved_balance, '0') AS reserved_balance
|
|
9996
10868
|
FROM ${positions} p
|
|
@@ -10000,14 +10872,18 @@ const create$4 = (db) => {
|
|
|
10000
10872
|
AND LOWER(po."user") = LOWER(p."user")
|
|
10001
10873
|
WHERE LOWER(p."user") = LOWER(${user})
|
|
10002
10874
|
AND p."user" != ${zeroAddress}
|
|
10003
|
-
${
|
|
10004
|
-
|
|
10875
|
+
${type !== void 0 ? sql`AND p.position_type_id = ${positionTypeId(type)}` : sql``}
|
|
10876
|
+
${cursor !== null ? sql`AND (p.chain_id, p.contract, p.position_type_id, p.asset, COALESCE(po.obligation_id, '')) > (${cursor.chainId}, ${cursor.contract}, ${cursor.positionTypeId}, ${cursor.asset}, ${cursor.obligationId ?? ""})` : sql``}
|
|
10877
|
+
ORDER BY p.chain_id ASC, p.contract ASC, p.position_type_id ASC, p.asset ASC, po.obligation_id ASC NULLS FIRST
|
|
10005
10878
|
LIMIT ${limit}
|
|
10006
10879
|
`);
|
|
10007
|
-
const
|
|
10008
|
-
|
|
10009
|
-
|
|
10010
|
-
|
|
10880
|
+
const lastRow = raw.rows[raw.rows.length - 1];
|
|
10881
|
+
const nextCursor = raw.rows.length === limit && lastRow !== void 0 ? Buffer.from(JSON.stringify({
|
|
10882
|
+
chainId: lastRow.chain_id.toString(),
|
|
10883
|
+
contract: lastRow.contract,
|
|
10884
|
+
positionTypeId: lastRow.position_type_id,
|
|
10885
|
+
asset: lastRow.asset,
|
|
10886
|
+
obligationId: lastRow.obligation_id
|
|
10011
10887
|
})).toString("base64url") : null;
|
|
10012
10888
|
return {
|
|
10013
10889
|
positions: raw.rows.map((row) => ({
|
|
@@ -10022,21 +10898,23 @@ const create$4 = (db) => {
|
|
|
10022
10898
|
};
|
|
10023
10899
|
},
|
|
10024
10900
|
setEmptyAfter: async (parameters) => {
|
|
10025
|
-
const { chainId, blockNumber } = parameters;
|
|
10901
|
+
const { chainId, blockNumber, type } = parameters;
|
|
10902
|
+
const typeId = positionTypeId(type);
|
|
10026
10903
|
return await db.transaction(async (tx) => {
|
|
10027
10904
|
const updatedPositions = await tx.update(positions).set({
|
|
10028
10905
|
balance: null,
|
|
10029
10906
|
blockNumber,
|
|
10030
10907
|
updatedAt: sql`NOW()`
|
|
10031
|
-
}).where(and(eq(positions.chainId, chainId), sql`${positions.blockNumber} >= ${blockNumber}
|
|
10908
|
+
}).where(and(eq(positions.chainId, chainId), sql`${positions.blockNumber} >= ${blockNumber}`, eq(positions.positionTypeId, typeId))).returning();
|
|
10032
10909
|
if (updatedPositions.length === 0) return 0;
|
|
10033
10910
|
await tx.execute(sql`
|
|
10034
10911
|
DELETE FROM ${transfers} t
|
|
10035
|
-
USING (VALUES ${sql.join(updatedPositions.map((u) => sql`(${u.chainId}::bigint, ${u.contract}::varchar(
|
|
10912
|
+
USING (VALUES ${sql.join(updatedPositions.map((u) => sql`(${u.chainId}::bigint, ${u.contract}::varchar(66), ${u.user}::varchar(42))`), sql`,`)}) AS s(chain_id, "contract", "user")
|
|
10036
10913
|
WHERE
|
|
10037
10914
|
t.chain_id = s.chain_id
|
|
10038
10915
|
AND t."contract" = s."contract"
|
|
10039
10916
|
AND (t."from" = s."user" OR t."to" = s."user")
|
|
10917
|
+
AND t.position_type_id = ${typeId}
|
|
10040
10918
|
`);
|
|
10041
10919
|
return updatedPositions.length;
|
|
10042
10920
|
});
|
|
@@ -10046,33 +10924,35 @@ const create$4 = (db) => {
|
|
|
10046
10924
|
|
|
10047
10925
|
//#endregion
|
|
10048
10926
|
//#region src/database/domains/Transfers.ts
|
|
10049
|
-
const create$
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10927
|
+
const create$2 = (db) => ({
|
|
10928
|
+
create: async (transfers$1) => {
|
|
10929
|
+
if (transfers$1.length === 0) return 0;
|
|
10930
|
+
const typeId = positionTypeId(transfers$1[0].type);
|
|
10931
|
+
return await db.transaction(async (dbTx) => {
|
|
10932
|
+
let totalInserted = 0;
|
|
10933
|
+
for (const transfersBatch of batch$1(transfers$1, DEFAULT_BATCH_SIZE$1)) {
|
|
10934
|
+
const { rows: inserted } = await dbTx.execute(sql`
|
|
10935
|
+
INSERT INTO ${transfers} (event_id, chain_id, "contract", "from", "to", "value", position_type_id, asset, block_number)
|
|
10936
|
+
SELECT * FROM (VALUES ${sql.join(transfersBatch.map((transfer) => sql`(${transfer.id}::varchar(128), ${transfer.chainId}::bigint, ${transfer.contract.toLowerCase()}::varchar(66), ${transfer.from.toLowerCase()}::varchar(42), ${transfer.to.toLowerCase()}::varchar(42), ${transfer.value.toString()}::numeric(78, 0), ${typeId}::integer, ${transfer.asset.toLowerCase()}::varchar(42), ${transfer.blockNumber}::bigint)`), sql`,`)}) AS v(event_id, chain_id, "contract", "from", "to", "value", position_type_id, asset, block_number)
|
|
10057
10937
|
WHERE
|
|
10058
10938
|
EXISTS (
|
|
10059
10939
|
SELECT 1 FROM ${positions} p
|
|
10060
|
-
WHERE p.chain_id = v.chain_id AND p."contract" = v."contract" AND p."user" = v."from" AND p.balance IS NOT NULL
|
|
10940
|
+
WHERE p.chain_id = v.chain_id AND p."contract" = v."contract" AND p."user" = v."from" AND p.position_type_id = v.position_type_id AND p.asset = v.asset AND p.balance IS NOT NULL
|
|
10061
10941
|
)
|
|
10062
10942
|
AND
|
|
10063
10943
|
EXISTS (
|
|
10064
10944
|
SELECT 1 FROM ${positions} p
|
|
10065
|
-
WHERE p.chain_id = v.chain_id AND p."contract" = v."contract" AND p."user" = v."to" AND p.balance IS NOT NULL
|
|
10945
|
+
WHERE p.chain_id = v.chain_id AND p."contract" = v."contract" AND p."user" = v."to" AND p.position_type_id = v.position_type_id AND p.asset = v.asset AND p.balance IS NOT NULL
|
|
10066
10946
|
)
|
|
10067
10947
|
ON CONFLICT DO NOTHING
|
|
10068
10948
|
RETURNING *;
|
|
10069
10949
|
`);
|
|
10070
|
-
|
|
10071
|
-
|
|
10950
|
+
if (inserted.length === 0) continue;
|
|
10951
|
+
await dbTx.execute(sql`
|
|
10072
10952
|
WITH inserted AS (
|
|
10073
10953
|
VALUES ${sql.join(inserted.map((t) => {
|
|
10074
|
-
|
|
10075
|
-
|
|
10954
|
+
return sql`(${t.chain_id}::bigint, ${t.contract}::varchar(66), ${t.from}::varchar(42), ${t.to}::varchar(42), ${t.value}::numeric(78, 0), ${t.asset}::varchar(42), ${t.block_number}::bigint)`;
|
|
10955
|
+
}), sql`,`)}
|
|
10076
10956
|
),
|
|
10077
10957
|
new_transfers AS (
|
|
10078
10958
|
SELECT
|
|
@@ -10081,7 +10961,8 @@ const create$3 = (db) => ({ create: async (transfers$1) => {
|
|
|
10081
10961
|
column3 AS "from",
|
|
10082
10962
|
column4 AS "to",
|
|
10083
10963
|
column5 AS "value",
|
|
10084
|
-
column6 AS
|
|
10964
|
+
column6 AS asset,
|
|
10965
|
+
column7 AS block_number
|
|
10085
10966
|
FROM inserted
|
|
10086
10967
|
),
|
|
10087
10968
|
diffs AS (
|
|
@@ -10090,6 +10971,7 @@ const create$3 = (db) => ({ create: async (transfers$1) => {
|
|
|
10090
10971
|
nt."contract",
|
|
10091
10972
|
nt."from" AS "user",
|
|
10092
10973
|
-nt."value" AS delta,
|
|
10974
|
+
nt.asset,
|
|
10093
10975
|
nt.block_number
|
|
10094
10976
|
FROM new_transfers nt
|
|
10095
10977
|
UNION ALL
|
|
@@ -10098,6 +10980,7 @@ const create$3 = (db) => ({ create: async (transfers$1) => {
|
|
|
10098
10980
|
nt."contract",
|
|
10099
10981
|
nt."to" AS "user",
|
|
10100
10982
|
nt."value" AS delta,
|
|
10983
|
+
nt.asset,
|
|
10101
10984
|
nt.block_number
|
|
10102
10985
|
FROM new_transfers nt
|
|
10103
10986
|
),
|
|
@@ -10107,12 +10990,15 @@ const create$3 = (db) => ({ create: async (transfers$1) => {
|
|
|
10107
10990
|
d."contract",
|
|
10108
10991
|
d."user",
|
|
10109
10992
|
d.delta,
|
|
10993
|
+
d.asset,
|
|
10110
10994
|
d.block_number
|
|
10111
10995
|
FROM diffs d
|
|
10112
10996
|
JOIN ${positions} p
|
|
10113
10997
|
ON p.chain_id = d.chain_id
|
|
10114
10998
|
AND p."contract" = d."contract"
|
|
10115
10999
|
AND p."user" = d."user"
|
|
11000
|
+
AND p.position_type_id = ${typeId}
|
|
11001
|
+
AND p.asset = d.asset
|
|
10116
11002
|
-- Only keep per-event diffs that are at or after the current position block
|
|
10117
11003
|
WHERE d.block_number >= p.block_number
|
|
10118
11004
|
),
|
|
@@ -10121,10 +11007,11 @@ const create$3 = (db) => ({ create: async (transfers$1) => {
|
|
|
10121
11007
|
chain_id,
|
|
10122
11008
|
"contract",
|
|
10123
11009
|
"user",
|
|
11010
|
+
asset,
|
|
10124
11011
|
SUM(delta) AS sum_delta,
|
|
10125
11012
|
MAX(block_number) AS max_block
|
|
10126
11013
|
FROM valid_diffs
|
|
10127
|
-
GROUP BY 1,2,3
|
|
11014
|
+
GROUP BY 1,2,3,4
|
|
10128
11015
|
)
|
|
10129
11016
|
UPDATE ${positions} AS p
|
|
10130
11017
|
SET
|
|
@@ -10136,101 +11023,109 @@ const create$3 = (db) => ({ create: async (transfers$1) => {
|
|
|
10136
11023
|
p.chain_id = a.chain_id
|
|
10137
11024
|
AND p."contract" = a."contract"
|
|
10138
11025
|
AND p."user" = a."user"
|
|
11026
|
+
AND p.asset = a.asset
|
|
11027
|
+
AND p.position_type_id = ${typeId}
|
|
10139
11028
|
`);
|
|
10140
|
-
|
|
10141
|
-
}
|
|
10142
|
-
return totalInserted;
|
|
10143
|
-
});
|
|
10144
|
-
} });
|
|
10145
|
-
|
|
10146
|
-
//#endregion
|
|
10147
|
-
//#region src/database/domains/Trees.ts
|
|
10148
|
-
/**
|
|
10149
|
-
* Creates a Trees domain instance for managing merkle tree metadata.
|
|
10150
|
-
*
|
|
10151
|
-
* @param config - Configuration with database instance
|
|
10152
|
-
* @returns TreesDomain instance
|
|
10153
|
-
*/
|
|
10154
|
-
function create$2(config) {
|
|
10155
|
-
const db = config.db;
|
|
10156
|
-
return {
|
|
10157
|
-
create: async (trees$1) => {
|
|
10158
|
-
if (trees$1.length === 0) return [];
|
|
10159
|
-
try {
|
|
10160
|
-
return await db.transaction(async (dbTx) => {
|
|
10161
|
-
const roots = [];
|
|
10162
|
-
for (const { tree, signature } of trees$1) {
|
|
10163
|
-
const root = tree.root.toLowerCase();
|
|
10164
|
-
roots.push(root);
|
|
10165
|
-
await dbTx.insert(trees).values({
|
|
10166
|
-
root,
|
|
10167
|
-
rootSignature: signature.toLowerCase()
|
|
10168
|
-
}).onConflictDoUpdate({
|
|
10169
|
-
target: [trees.root],
|
|
10170
|
-
set: {
|
|
10171
|
-
rootSignature: signature.toLowerCase(),
|
|
10172
|
-
createdAt: sql`NOW()`
|
|
10173
|
-
}
|
|
10174
|
-
});
|
|
10175
|
-
const pathRows = proofs(tree).map((proof) => ({
|
|
10176
|
-
offerHash: hash(proof.offer).toLowerCase(),
|
|
10177
|
-
treeRoot: root,
|
|
10178
|
-
proofNodes: concatenateProofs(proof.path)
|
|
10179
|
-
}));
|
|
10180
|
-
for (const batch of batch$1(pathRows, DEFAULT_BATCH_SIZE$1)) await dbTx.insert(merklePaths).values(batch).onConflictDoUpdate({
|
|
10181
|
-
target: [merklePaths.offerHash],
|
|
10182
|
-
set: {
|
|
10183
|
-
treeRoot: sql`excluded.tree_root`,
|
|
10184
|
-
proofNodes: sql`excluded.proof_nodes`,
|
|
10185
|
-
createdAt: sql`NOW()`
|
|
10186
|
-
}
|
|
10187
|
-
});
|
|
10188
|
-
}
|
|
10189
|
-
return roots;
|
|
10190
|
-
});
|
|
10191
|
-
} catch (err) {
|
|
10192
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
10193
|
-
throw new Error("Trees.create failed. Ensure offers exist before inserting merkle paths.", { cause: error });
|
|
11029
|
+
totalInserted += inserted.length;
|
|
10194
11030
|
}
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10202
|
-
|
|
10203
|
-
|
|
10204
|
-
|
|
10205
|
-
|
|
10206
|
-
|
|
10207
|
-
|
|
10208
|
-
|
|
10209
|
-
|
|
10210
|
-
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
11031
|
+
return totalInserted;
|
|
11032
|
+
});
|
|
11033
|
+
},
|
|
11034
|
+
delete: async (parameters) => {
|
|
11035
|
+
const { chainId, blockNumberGte, positionTypeId } = parameters;
|
|
11036
|
+
return await db.transaction(async (dbTx) => {
|
|
11037
|
+
const { rows: toDelete } = await dbTx.execute(sql`
|
|
11038
|
+
SELECT event_id, chain_id, "contract", "from", "to", "value"::text, asset, block_number
|
|
11039
|
+
FROM ${transfers}
|
|
11040
|
+
WHERE chain_id = ${chainId}
|
|
11041
|
+
AND position_type_id = ${positionTypeId}
|
|
11042
|
+
AND block_number >= ${blockNumberGte}
|
|
11043
|
+
`);
|
|
11044
|
+
if (toDelete.length === 0) return 0;
|
|
11045
|
+
await dbTx.execute(sql`
|
|
11046
|
+
WITH to_delete AS (
|
|
11047
|
+
VALUES ${sql.join(toDelete.map((t) => sql`(${t.chain_id}::bigint, ${t.contract}::varchar(66), ${t.from}::varchar(42), ${t.to}::varchar(42), ${t.value}::numeric(78, 0), ${t.asset}::varchar(42))`), sql`,`)}
|
|
11048
|
+
),
|
|
11049
|
+
reverse_diffs AS (
|
|
11050
|
+
SELECT column1 AS chain_id, column2 AS "contract", column3 AS "user", column5 AS delta, column6 AS asset
|
|
11051
|
+
FROM to_delete
|
|
11052
|
+
UNION ALL
|
|
11053
|
+
SELECT column1 AS chain_id, column2 AS "contract", column4 AS "user", -column5 AS delta, column6 AS asset
|
|
11054
|
+
FROM to_delete
|
|
11055
|
+
),
|
|
11056
|
+
aggregated AS (
|
|
11057
|
+
SELECT chain_id, "contract", "user", asset, SUM(delta) AS sum_delta
|
|
11058
|
+
FROM reverse_diffs
|
|
11059
|
+
GROUP BY 1,2,3,4
|
|
11060
|
+
),
|
|
11061
|
+
remaining_max AS (
|
|
11062
|
+
SELECT t.chain_id, t."contract",
|
|
11063
|
+
CASE WHEN t."from" = a."user" THEN t."from" ELSE t."to" END AS "user",
|
|
11064
|
+
t.asset,
|
|
11065
|
+
MAX(t.block_number) AS max_block
|
|
11066
|
+
FROM ${transfers} t
|
|
11067
|
+
JOIN aggregated a
|
|
11068
|
+
ON t.chain_id = a.chain_id AND t."contract" = a."contract"
|
|
11069
|
+
AND t.asset = a.asset
|
|
11070
|
+
AND (t."from" = a."user" OR t."to" = a."user")
|
|
11071
|
+
WHERE t.position_type_id = ${positionTypeId}
|
|
11072
|
+
AND t.block_number < ${blockNumberGte}
|
|
11073
|
+
GROUP BY t.chain_id, t."contract",
|
|
11074
|
+
CASE WHEN t."from" = a."user" THEN t."from" ELSE t."to" END,
|
|
11075
|
+
t.asset
|
|
11076
|
+
)
|
|
11077
|
+
UPDATE ${positions} AS p
|
|
11078
|
+
SET
|
|
11079
|
+
balance = COALESCE(p.balance, 0) + a.sum_delta,
|
|
11080
|
+
block_number = COALESCE(rm.max_block, p.block_number),
|
|
11081
|
+
updated_at = NOW()
|
|
11082
|
+
FROM aggregated a
|
|
11083
|
+
LEFT JOIN remaining_max rm
|
|
11084
|
+
ON rm.chain_id = a.chain_id AND rm."contract" = a."contract" AND rm."user" = a."user" AND rm.asset = a.asset
|
|
11085
|
+
WHERE p.chain_id = a.chain_id
|
|
11086
|
+
AND p."contract" = a."contract"
|
|
11087
|
+
AND p."user" = a."user"
|
|
11088
|
+
AND p.asset = a.asset
|
|
11089
|
+
AND p.position_type_id = ${positionTypeId}
|
|
11090
|
+
`);
|
|
11091
|
+
await dbTx.execute(sql`
|
|
11092
|
+
DELETE FROM ${transfers}
|
|
11093
|
+
WHERE chain_id = ${chainId}
|
|
11094
|
+
AND position_type_id = ${positionTypeId}
|
|
11095
|
+
AND block_number >= ${blockNumberGte}
|
|
11096
|
+
`);
|
|
11097
|
+
await dbTx.execute(sql`
|
|
11098
|
+
DELETE FROM ${positions} p
|
|
11099
|
+
USING (
|
|
11100
|
+
SELECT DISTINCT chain_id, "contract", "user", asset
|
|
11101
|
+
FROM (
|
|
11102
|
+
SELECT chain_id, "contract", "from" AS "user", asset FROM (
|
|
11103
|
+
VALUES ${sql.join(toDelete.map((t) => sql`(${t.chain_id}::bigint, ${t.contract}::varchar(66), ${t.from}::varchar(42), ${t.asset}::varchar(42))`), sql`,`)}
|
|
11104
|
+
) AS d(chain_id, "contract", "from", asset)
|
|
11105
|
+
UNION
|
|
11106
|
+
SELECT chain_id, "contract", "to" AS "user", asset FROM (
|
|
11107
|
+
VALUES ${sql.join(toDelete.map((t) => sql`(${t.chain_id}::bigint, ${t.contract}::varchar(66), ${t.to}::varchar(42), ${t.asset}::varchar(42))`), sql`,`)}
|
|
11108
|
+
) AS d(chain_id, "contract", "to", asset)
|
|
11109
|
+
) AS combined
|
|
11110
|
+
) AS affected
|
|
11111
|
+
WHERE p.chain_id = affected.chain_id
|
|
11112
|
+
AND p."contract" = affected."contract"
|
|
11113
|
+
AND p."user" = affected."user"
|
|
11114
|
+
AND p.asset = affected.asset
|
|
11115
|
+
AND p.position_type_id = ${positionTypeId}
|
|
11116
|
+
AND NOT EXISTS (
|
|
11117
|
+
SELECT 1 FROM ${transfers} t
|
|
11118
|
+
WHERE t.chain_id = p.chain_id
|
|
11119
|
+
AND t."contract" = p."contract"
|
|
11120
|
+
AND t.asset = p.asset
|
|
11121
|
+
AND t.position_type_id = ${positionTypeId}
|
|
11122
|
+
AND (t."from" = p."user" OR t."to" = p."user")
|
|
11123
|
+
)
|
|
11124
|
+
`);
|
|
11125
|
+
return toDelete.length;
|
|
11126
|
+
});
|
|
11127
|
+
}
|
|
11128
|
+
});
|
|
10234
11129
|
|
|
10235
11130
|
//#endregion
|
|
10236
11131
|
//#region src/database/domains/Validations.ts
|
|
@@ -10239,26 +11134,26 @@ function create$1(db) {
|
|
|
10239
11134
|
return {
|
|
10240
11135
|
get: async (params) => {
|
|
10241
11136
|
const { status: status$1, cursor, limit = DEFAULT_LIMIT } = params ?? {};
|
|
10242
|
-
|
|
10243
|
-
if (!cursor.startsWith("0x") || cursor.length !== 66) throw new Error("Invalid cursor format");
|
|
10244
|
-
}
|
|
11137
|
+
const parsedCursor = cursor !== null && cursor !== void 0 ? parseCursor(cursor) : void 0;
|
|
10245
11138
|
let query = db.select({
|
|
10246
11139
|
offerHash: validations.offerHash,
|
|
11140
|
+
obligationId: validations.obligationId,
|
|
10247
11141
|
code: status.code
|
|
10248
11142
|
}).from(validations).innerJoin(status, eq(validations.statusId, status.id));
|
|
10249
11143
|
if (status$1 !== void 0) query = query.where(eq(status.code, status$1));
|
|
10250
|
-
if (
|
|
10251
|
-
const cursorCondition = gt(validations.offerHash,
|
|
11144
|
+
if (parsedCursor !== void 0) {
|
|
11145
|
+
const cursorCondition = or(gt(validations.offerHash, parsedCursor.offerHash), and(eq(validations.offerHash, parsedCursor.offerHash), gt(validations.obligationId, parsedCursor.obligationId)));
|
|
10252
11146
|
if (status$1 !== void 0) query = query.where(and(eq(status.code, status$1), cursorCondition));
|
|
10253
11147
|
else query = query.where(cursorCondition);
|
|
10254
11148
|
}
|
|
10255
|
-
const mapped = (await query.orderBy(asc(validations.offerHash)).limit(limit)).map((row) => ({
|
|
11149
|
+
const mapped = (await query.orderBy(asc(validations.offerHash), asc(validations.obligationId)).limit(limit)).map((row) => ({
|
|
10256
11150
|
offerHash: row.offerHash,
|
|
11151
|
+
obligationId: row.obligationId,
|
|
10257
11152
|
status: row.code
|
|
10258
11153
|
}));
|
|
10259
11154
|
return {
|
|
10260
11155
|
validations: mapped,
|
|
10261
|
-
nextCursor: mapped.length === limit ? mapped[mapped.length - 1]
|
|
11156
|
+
nextCursor: mapped.length === limit ? formatCursor(mapped[mapped.length - 1]) : null
|
|
10262
11157
|
};
|
|
10263
11158
|
},
|
|
10264
11159
|
upsert: async (results) => {
|
|
@@ -10268,6 +11163,7 @@ function create$1(db) {
|
|
|
10268
11163
|
if (invalidStatuses.length > 0) throw new Error(`Unknown validation status: ${invalidStatuses.join(", ")}`);
|
|
10269
11164
|
const normalized = results.map((r) => ({
|
|
10270
11165
|
offerHash: r.offerHash.toLowerCase(),
|
|
11166
|
+
obligationId: r.obligationId.toLowerCase(),
|
|
10271
11167
|
status: r.status
|
|
10272
11168
|
}));
|
|
10273
11169
|
const uniqueStatuses = Array.from(new Set(normalized.map((r) => r.status)));
|
|
@@ -10279,10 +11175,11 @@ function create$1(db) {
|
|
|
10279
11175
|
for (const status of uniqueStatuses) if (!statusMap.has(status)) throw new Error(`Unknown validation status: ${status}`);
|
|
10280
11176
|
const values = normalized.map((row) => ({
|
|
10281
11177
|
offerHash: row.offerHash,
|
|
11178
|
+
obligationId: row.obligationId,
|
|
10282
11179
|
statusId: statusMap.get(row.status)
|
|
10283
11180
|
}));
|
|
10284
11181
|
for (const batch of batch$1(values, DEFAULT_BATCH_SIZE$1)) await db.insert(validations).values(batch).onConflictDoUpdate({
|
|
10285
|
-
target: [validations.offerHash],
|
|
11182
|
+
target: [validations.offerHash, validations.obligationId],
|
|
10286
11183
|
set: {
|
|
10287
11184
|
statusId: sql`excluded.status_id`,
|
|
10288
11185
|
updatedAt: sql`NOW()`
|
|
@@ -10291,6 +11188,18 @@ function create$1(db) {
|
|
|
10291
11188
|
}
|
|
10292
11189
|
};
|
|
10293
11190
|
}
|
|
11191
|
+
const HEX_32 = /^0x[a-fA-F0-9]{64}$/;
|
|
11192
|
+
function parseCursor(cursor) {
|
|
11193
|
+
const [offerHash, obligationId] = cursor.split(":");
|
|
11194
|
+
if (!offerHash || !obligationId || !HEX_32.test(offerHash) || !HEX_32.test(obligationId)) throw new Error("Invalid cursor format");
|
|
11195
|
+
return {
|
|
11196
|
+
offerHash: offerHash.toLowerCase(),
|
|
11197
|
+
obligationId: obligationId.toLowerCase()
|
|
11198
|
+
};
|
|
11199
|
+
}
|
|
11200
|
+
function formatCursor(input) {
|
|
11201
|
+
return `${input.offerHash.toLowerCase()}:${input.obligationId.toLowerCase()}`;
|
|
11202
|
+
}
|
|
10294
11203
|
|
|
10295
11204
|
//#endregion
|
|
10296
11205
|
//#region src/database/Database.ts
|
|
@@ -10300,23 +11209,23 @@ var Database_exports = /* @__PURE__ */ __exportAll({
|
|
|
10300
11209
|
});
|
|
10301
11210
|
function createDomains(core, chainRegistry) {
|
|
10302
11211
|
return {
|
|
10303
|
-
book: create$
|
|
10304
|
-
blocks: create$
|
|
11212
|
+
book: create$11({ db: core }),
|
|
11213
|
+
blocks: create$12({
|
|
10305
11214
|
db: core,
|
|
10306
11215
|
chainRegistry
|
|
10307
11216
|
}),
|
|
10308
|
-
callbacks: create$
|
|
11217
|
+
callbacks: create$10(core),
|
|
10309
11218
|
offers: create$15({ db: core }),
|
|
10310
|
-
consumed: create$
|
|
10311
|
-
groups: create$
|
|
10312
|
-
lots: create$
|
|
10313
|
-
obligations: create$
|
|
10314
|
-
offsets: create$
|
|
10315
|
-
oracles: create$
|
|
10316
|
-
trees: create$
|
|
11219
|
+
consumed: create$9(core),
|
|
11220
|
+
groups: create$8(core),
|
|
11221
|
+
lots: create$7(core),
|
|
11222
|
+
obligations: create$6(core),
|
|
11223
|
+
offsets: create$5(core),
|
|
11224
|
+
oracles: create$4(core),
|
|
11225
|
+
trees: create$14({ db: core }),
|
|
10317
11226
|
validations: create$1(core),
|
|
10318
|
-
positions: create$
|
|
10319
|
-
transfers: create$
|
|
11227
|
+
positions: create$3(core),
|
|
11228
|
+
transfers: create$2(core)
|
|
10320
11229
|
};
|
|
10321
11230
|
}
|
|
10322
11231
|
function createReaders(core) {
|
|
@@ -10481,7 +11390,7 @@ async function postMigrate(driver) {
|
|
|
10481
11390
|
const tracer = getTracer("db.postMigrate");
|
|
10482
11391
|
await startActiveSpan(tracer, "db.postMigrate", async () => {
|
|
10483
11392
|
await driver.execute(`INSERT INTO "${VERSION}"."status" ("code") VALUES ('${Status.VALID}'), ('${Status.SIMULATION_ERROR}') ON CONFLICT DO NOTHING;`);
|
|
10484
|
-
await driver.execute(`INSERT INTO "${VERSION}"."position_types" ("type") VALUES ('${Type.ERC20}'), ('${Type.VAULT_V1}') ON CONFLICT DO NOTHING;`);
|
|
11393
|
+
await driver.execute(`INSERT INTO "${VERSION}"."position_types" ("type") VALUES ('${Type.ERC20}'), ('${Type.VAULT_V1}'), ('${Type.DEBT_OF}'), ('${Type.COLLATERAL_OF}') ON CONFLICT DO NOTHING;`);
|
|
10485
11394
|
await driver.execute(`
|
|
10486
11395
|
CREATE OR REPLACE FUNCTION apply_group_consumed_stmt_ins()
|
|
10487
11396
|
RETURNS trigger
|
|
@@ -10635,19 +11544,23 @@ async function postMigrate(driver) {
|
|
|
10635
11544
|
BEGIN
|
|
10636
11545
|
DELETE FROM "${VERSION}"."positions" p
|
|
10637
11546
|
USING (
|
|
10638
|
-
SELECT DISTINCT c.position_chain_id, c.position_contract, c.position_user
|
|
11547
|
+
SELECT DISTINCT c.position_chain_id, c.position_contract, c.position_user, c.position_type_id
|
|
10639
11548
|
FROM deleted_rows d
|
|
10640
11549
|
JOIN "${VERSION}"."callbacks" c ON c.id = d.callback_id
|
|
10641
11550
|
) AS affected
|
|
11551
|
+
JOIN "${VERSION}"."position_types" pt ON pt.id = affected.position_type_id
|
|
10642
11552
|
WHERE p.chain_id = affected.position_chain_id
|
|
10643
11553
|
AND p.contract = affected.position_contract
|
|
10644
11554
|
AND p."user" = affected.position_user
|
|
11555
|
+
AND p.position_type_id = affected.position_type_id
|
|
11556
|
+
AND pt.type = 'erc20'
|
|
10645
11557
|
AND NOT EXISTS (
|
|
10646
11558
|
SELECT 1 FROM "${VERSION}"."callbacks" c2
|
|
10647
11559
|
JOIN "${VERSION}"."offers_callbacks" oc ON oc.callback_id = c2.id
|
|
10648
11560
|
WHERE c2.position_chain_id = p.chain_id
|
|
10649
11561
|
AND c2.position_contract = p.contract
|
|
10650
11562
|
AND c2.position_user = p."user"
|
|
11563
|
+
AND c2.position_type_id = p.position_type_id
|
|
10651
11564
|
);
|
|
10652
11565
|
RETURN NULL;
|
|
10653
11566
|
END;
|
|
@@ -10694,7 +11607,7 @@ async function postMigrate(driver) {
|
|
|
10694
11607
|
RETURNS TRIGGER AS $$
|
|
10695
11608
|
DECLARE
|
|
10696
11609
|
orphan_obligation_ids TEXT[];
|
|
10697
|
-
|
|
11610
|
+
orphan_obligation_keys TEXT[];
|
|
10698
11611
|
BEGIN
|
|
10699
11612
|
-- 1. Find orphan obligation IDs
|
|
10700
11613
|
SELECT ARRAY_AGG(DISTINCT obligation_id) INTO orphan_obligation_ids
|
|
@@ -10702,33 +11615,39 @@ async function postMigrate(driver) {
|
|
|
10702
11615
|
WHERE NOT EXISTS (
|
|
10703
11616
|
SELECT 1 FROM "${VERSION}"."offers" ov
|
|
10704
11617
|
WHERE ov.obligation_id = d.obligation_id
|
|
11618
|
+
)
|
|
11619
|
+
AND NOT EXISTS (
|
|
11620
|
+
SELECT 1 FROM "${VERSION}"."positions" p
|
|
11621
|
+
JOIN "${VERSION}"."position_types" pt ON pt.id = p.position_type_id
|
|
11622
|
+
WHERE p."contract" = d.obligation_id
|
|
11623
|
+
AND pt.type IN ('debtOf', 'collateralOf')
|
|
10705
11624
|
);
|
|
10706
11625
|
|
|
10707
|
-
-- 2. If no orphan
|
|
11626
|
+
-- 2. If no orphan obligation IDs, exit early
|
|
10708
11627
|
IF orphan_obligation_ids IS NULL OR array_length(orphan_obligation_ids, 1) IS NULL THEN
|
|
10709
11628
|
RETURN NULL;
|
|
10710
11629
|
END IF;
|
|
10711
11630
|
|
|
10712
|
-
-- 3.
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
FROM "${VERSION}"."obligation_collaterals_v2" oc
|
|
10716
|
-
WHERE oc.obligation_id = ANY(orphan_obligation_ids);
|
|
11631
|
+
-- 3. Delete orphan obligation id keys
|
|
11632
|
+
DELETE FROM "${VERSION}"."obligation_id_keys" oia
|
|
11633
|
+
WHERE oia.obligation_id = ANY(orphan_obligation_ids);
|
|
10717
11634
|
|
|
10718
|
-
-- 4.
|
|
10719
|
-
|
|
10720
|
-
|
|
11635
|
+
-- 4. Find canonical obligation keys with no remaining obligation id keys
|
|
11636
|
+
SELECT ARRAY_AGG(ob.obligation_key) INTO orphan_obligation_keys
|
|
11637
|
+
FROM "${VERSION}"."obligations" ob
|
|
11638
|
+
WHERE NOT EXISTS (
|
|
11639
|
+
SELECT 1 FROM "${VERSION}"."obligation_id_keys" oia
|
|
11640
|
+
WHERE oia.obligation_key = ob.obligation_key
|
|
11641
|
+
);
|
|
10721
11642
|
|
|
10722
|
-
-- 5.
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
AND oc.oracle_address = o.address
|
|
10731
|
-
);
|
|
11643
|
+
-- 5. If no orphan canonical obligations, exit early
|
|
11644
|
+
IF orphan_obligation_keys IS NULL OR array_length(orphan_obligation_keys, 1) IS NULL THEN
|
|
11645
|
+
RETURN NULL;
|
|
11646
|
+
END IF;
|
|
11647
|
+
|
|
11648
|
+
-- 6. Delete orphan canonical obligations (cascades to collaterals)
|
|
11649
|
+
DELETE FROM "${VERSION}"."obligations" ob
|
|
11650
|
+
WHERE ob.obligation_key = ANY(orphan_obligation_keys);
|
|
10732
11651
|
|
|
10733
11652
|
RETURN NULL;
|
|
10734
11653
|
END;
|
|
@@ -10746,16 +11665,21 @@ async function postMigrate(driver) {
|
|
|
10746
11665
|
RETURNS trigger
|
|
10747
11666
|
LANGUAGE plpgsql AS $$
|
|
10748
11667
|
BEGIN
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
|
|
10758
|
-
|
|
11668
|
+
BEGIN
|
|
11669
|
+
INSERT INTO "${VERSION}"."offsets" (chain_id, "user", contract, "group", obligation_id, value)
|
|
11670
|
+
VALUES (
|
|
11671
|
+
OLD.chain_id,
|
|
11672
|
+
OLD."user",
|
|
11673
|
+
OLD.contract,
|
|
11674
|
+
OLD."group",
|
|
11675
|
+
OLD.obligation_id,
|
|
11676
|
+
OLD.upper::numeric - OLD.lower::numeric
|
|
11677
|
+
)
|
|
11678
|
+
ON CONFLICT (chain_id, "user", contract, "group", obligation_id) DO NOTHING;
|
|
11679
|
+
EXCEPTION WHEN foreign_key_violation THEN
|
|
11680
|
+
-- lots_positions may be gone during cascaded deletes
|
|
11681
|
+
NULL;
|
|
11682
|
+
END;
|
|
10759
11683
|
RETURN OLD;
|
|
10760
11684
|
END;
|
|
10761
11685
|
$$;
|
|
@@ -10778,11 +11702,26 @@ async function postMigrate(driver) {
|
|
|
10778
11702
|
AND l.contract = OLD.contract
|
|
10779
11703
|
AND l."user" = OLD."user"
|
|
10780
11704
|
) THEN
|
|
10781
|
-
-- No lots remain, delete
|
|
11705
|
+
-- No lots remain, delete erc20 positions and their lots_positions bridge rows.
|
|
11706
|
+
-- debtOf/collateralOf positions live independently of offers and must not be deleted here.
|
|
11707
|
+
-- First delete the position (for ERC20, asset = contract).
|
|
10782
11708
|
DELETE FROM "${VERSION}"."positions" p
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
11709
|
+
USING "${VERSION}"."lots_positions" lp
|
|
11710
|
+
JOIN "${VERSION}"."position_types" pt ON pt.id = lp.position_type_id
|
|
11711
|
+
WHERE lp.chain_id = OLD.chain_id
|
|
11712
|
+
AND lp.contract = OLD.contract
|
|
11713
|
+
AND lp."user" = OLD."user"
|
|
11714
|
+
AND p.chain_id = lp.chain_id
|
|
11715
|
+
AND p.contract = lp.contract
|
|
11716
|
+
AND p."user" = lp."user"
|
|
11717
|
+
AND p.position_type_id = lp.position_type_id
|
|
11718
|
+
AND pt.type = 'erc20';
|
|
11719
|
+
|
|
11720
|
+
-- Delete the lots_positions bridge row (cascades to offsets via offsets_lots_positions_fk).
|
|
11721
|
+
DELETE FROM "${VERSION}"."lots_positions" lp
|
|
11722
|
+
WHERE lp.chain_id = OLD.chain_id
|
|
11723
|
+
AND lp.contract = OLD.contract
|
|
11724
|
+
AND lp."user" = OLD."user";
|
|
10786
11725
|
END IF;
|
|
10787
11726
|
RETURN NULL;
|
|
10788
11727
|
END;
|
|
@@ -10851,8 +11790,12 @@ function createHttpClient(config) {
|
|
|
10851
11790
|
body: json
|
|
10852
11791
|
};
|
|
10853
11792
|
};
|
|
10854
|
-
const isAllowed = async (
|
|
10855
|
-
const {
|
|
11793
|
+
const isAllowed = async (parameters) => {
|
|
11794
|
+
const { offers, chainId } = parameters;
|
|
11795
|
+
const { statusCode, body } = await validate({
|
|
11796
|
+
chain_id: chainId,
|
|
11797
|
+
offers: offers.map((offer) => toSnakeCase(offer))
|
|
11798
|
+
});
|
|
10856
11799
|
if (statusCode !== 200) {
|
|
10857
11800
|
const errorMessage = extractErrorMessage(body);
|
|
10858
11801
|
throw new Error(`Gatekeeper validation failed: ${errorMessage ?? `status ${statusCode}`}`);
|
|
@@ -10994,11 +11937,12 @@ var Gatekeeper_exports = /* @__PURE__ */ __exportAll({ create: () => create });
|
|
|
10994
11937
|
* @returns Gatekeeper instance. {@link Gatekeeper}
|
|
10995
11938
|
*/
|
|
10996
11939
|
function create(parameters) {
|
|
10997
|
-
const { rules } = parameters;
|
|
10998
|
-
return { isAllowed: async (
|
|
11940
|
+
const { rules: rulesFactory } = parameters;
|
|
11941
|
+
return { isAllowed: async (parameters) => {
|
|
11942
|
+
const { offers, chainId } = parameters;
|
|
10999
11943
|
return await run({
|
|
11000
11944
|
items: offers,
|
|
11001
|
-
rules
|
|
11945
|
+
rules: rulesFactory(chainId)
|
|
11002
11946
|
});
|
|
11003
11947
|
} };
|
|
11004
11948
|
}
|
|
@@ -11008,28 +11952,11 @@ function create(parameters) {
|
|
|
11008
11952
|
var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
11009
11953
|
amountMutualExclusivity: () => amountMutualExclusivity,
|
|
11010
11954
|
callback: () => callback,
|
|
11011
|
-
chains: () => chains,
|
|
11012
11955
|
collateralToken: () => collateralToken,
|
|
11013
11956
|
loanToken: () => loanToken,
|
|
11014
11957
|
maturity: () => maturity,
|
|
11015
11958
|
oracle: () => oracle,
|
|
11016
|
-
sameMaker: () => sameMaker
|
|
11017
|
-
validity: () => validity
|
|
11018
|
-
});
|
|
11019
|
-
/**
|
|
11020
|
-
* set of rules to validate offers.
|
|
11021
|
-
*
|
|
11022
|
-
* @param _parameters - Validity parameters with chain and client
|
|
11023
|
-
* @returns Array of validation rules to evaluate against offers
|
|
11024
|
-
*/
|
|
11025
|
-
function validity(_parameters) {
|
|
11026
|
-
return [single("expiry", "Validates that offer has not expired", (offer) => {
|
|
11027
|
-
if (offer.expiry < Math.floor(Date.now() / 1e3)) return { message: "Expiry mismatch" };
|
|
11028
|
-
})];
|
|
11029
|
-
}
|
|
11030
|
-
const chains = ({ chains }) => single("chain_ids", `Validates that offer chain is one of: [${chains.map((c) => c.id).join(", ")}]`, (offer) => {
|
|
11031
|
-
const allowedChainIds = chains.map((c) => c.id);
|
|
11032
|
-
if (!allowedChainIds.some((id) => id === offer.chainId)) return { message: `Chain ID ${offer.chainId} is not in the allowed chains (${allowedChainIds.join(", ")})` };
|
|
11959
|
+
sameMaker: () => sameMaker
|
|
11033
11960
|
});
|
|
11034
11961
|
const maturity = ({ maturities }) => single("maturity", `Validates that offer maturity is one of: [${maturities.join(", ")}]`, (offer) => {
|
|
11035
11962
|
const allowedMaturities = maturities.map((m) => from$16(m));
|
|
@@ -11045,9 +11972,9 @@ const callback = ({ callbacks }) => single("callback", `Validates callbacks: buy
|
|
|
11045
11972
|
* @param assetsByChainId - Allowed loan tokens indexed by chain id.
|
|
11046
11973
|
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
11047
11974
|
*/
|
|
11048
|
-
const loanToken = ({ assetsByChainId }) => single("loan_token", "Validates that offer loan token is in the allowed token list for the
|
|
11049
|
-
const allowedLoanTokens = assetsByChainId[
|
|
11050
|
-
if (!allowedLoanTokens || allowedLoanTokens.length === 0) return { message: `No allowed loan tokens for chain ${
|
|
11975
|
+
const loanToken = ({ assetsByChainId, chainId }) => single("loan_token", "Validates that offer loan token is in the allowed token list for the request chain", (offer) => {
|
|
11976
|
+
const allowedLoanTokens = assetsByChainId[chainId]?.map((asset) => asset.toLowerCase());
|
|
11977
|
+
if (!allowedLoanTokens || allowedLoanTokens.length === 0) return { message: `No allowed loan tokens for chain ${chainId}` };
|
|
11051
11978
|
if (!allowedLoanTokens.includes(offer.loanToken.toLowerCase())) return { message: "Loan token is not allowed" };
|
|
11052
11979
|
});
|
|
11053
11980
|
/**
|
|
@@ -11055,9 +11982,9 @@ const loanToken = ({ assetsByChainId }) => single("loan_token", "Validates that
|
|
|
11055
11982
|
* @param collateralAssetsByChainId - Allowed collateral tokens indexed by chain id.
|
|
11056
11983
|
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
11057
11984
|
*/
|
|
11058
|
-
const collateralToken = ({ collateralAssetsByChainId }) => single("collateral_token", "Validates that offer collateral tokens are in the allowed token list for the
|
|
11059
|
-
const allowedCollateralTokens = collateralAssetsByChainId[
|
|
11060
|
-
if (allowedCollateralTokens.length === 0) return { message: `No allowed collateral tokens for chain ${
|
|
11985
|
+
const collateralToken = ({ collateralAssetsByChainId, chainId }) => single("collateral_token", "Validates that offer collateral tokens are in the allowed token list for the request chain", (offer) => {
|
|
11986
|
+
const allowedCollateralTokens = collateralAssetsByChainId[chainId]?.map((asset) => asset.toLowerCase()) ?? [];
|
|
11987
|
+
if (allowedCollateralTokens.length === 0) return { message: `No allowed collateral tokens for chain ${chainId}` };
|
|
11061
11988
|
if (offer.collaterals.length === 0) return { message: "At least one collateral token is required" };
|
|
11062
11989
|
if (offer.collaterals.some((collateral) => !allowedCollateralTokens.includes(collateral.asset.toLowerCase()))) return { message: "Collateral token is not allowed" };
|
|
11063
11990
|
});
|
|
@@ -11066,9 +11993,9 @@ const collateralToken = ({ collateralAssetsByChainId }) => single("collateral_to
|
|
|
11066
11993
|
* @param oraclesByChainId - Allowed oracles indexed by chain id.
|
|
11067
11994
|
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
11068
11995
|
*/
|
|
11069
|
-
const oracle = ({ oraclesByChainId }) => single("oracle", "Validates that offer collateral oracles are in the allowed oracle list for the
|
|
11070
|
-
const allowedOracles = oraclesByChainId[
|
|
11071
|
-
if (!allowedOracles || allowedOracles.length === 0) return { message: `No allowed oracles for chain ${
|
|
11996
|
+
const oracle = ({ oraclesByChainId, chainId }) => single("oracle", "Validates that offer collateral oracles are in the allowed oracle list for the request chain", (offer) => {
|
|
11997
|
+
const allowedOracles = oraclesByChainId[chainId]?.map((oracle) => oracle.toLowerCase());
|
|
11998
|
+
if (!allowedOracles || allowedOracles.length === 0) return { message: `No allowed oracles for chain ${chainId}` };
|
|
11072
11999
|
if (offer.collaterals.some((collateral) => !allowedOracles.includes(collateral.oracle.toLowerCase()))) return { message: "Oracle is not allowed" };
|
|
11073
12000
|
});
|
|
11074
12001
|
/**
|
|
@@ -11100,11 +12027,12 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
|
|
|
11100
12027
|
|
|
11101
12028
|
//#endregion
|
|
11102
12029
|
//#region src/gatekeeper/morphoRules.ts
|
|
11103
|
-
const morphoRules = (
|
|
12030
|
+
const morphoRules = (parameters) => {
|
|
12031
|
+
const { chains, chainId } = parameters;
|
|
11104
12032
|
const assetsByChainId = {};
|
|
11105
12033
|
const collateralAssetsByChainId = {};
|
|
11106
12034
|
const oraclesByChainId = {};
|
|
11107
|
-
for (const chain of chains
|
|
12035
|
+
for (const chain of chains) {
|
|
11108
12036
|
assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
|
|
11109
12037
|
collateralAssetsByChainId[chain.id] = collateralAssets[chain.id.toString()] ?? [];
|
|
11110
12038
|
oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
|
|
@@ -11112,15 +12040,23 @@ const morphoRules = (chains$3) => {
|
|
|
11112
12040
|
return [
|
|
11113
12041
|
sameMaker(),
|
|
11114
12042
|
amountMutualExclusivity(),
|
|
11115
|
-
chains({ chains: chains$3 }),
|
|
11116
12043
|
maturity({ maturities: [MaturityType.EndOfWeek, MaturityType.EndOfNextWeek] }),
|
|
11117
12044
|
callback({
|
|
11118
12045
|
callbacks: [Type$1.BuyWithEmptyCallback, Type$1.SellWithEmptyCallback],
|
|
11119
12046
|
allowedAddresses: []
|
|
11120
12047
|
}),
|
|
11121
|
-
loanToken({
|
|
11122
|
-
|
|
11123
|
-
|
|
12048
|
+
loanToken({
|
|
12049
|
+
assetsByChainId,
|
|
12050
|
+
chainId
|
|
12051
|
+
}),
|
|
12052
|
+
collateralToken({
|
|
12053
|
+
collateralAssetsByChainId,
|
|
12054
|
+
chainId
|
|
12055
|
+
}),
|
|
12056
|
+
oracle({
|
|
12057
|
+
oraclesByChainId,
|
|
12058
|
+
chainId
|
|
12059
|
+
})
|
|
11124
12060
|
];
|
|
11125
12061
|
};
|
|
11126
12062
|
|
|
@@ -11150,9 +12086,7 @@ function from(parameters) {
|
|
|
11150
12086
|
async function add(config, offers) {
|
|
11151
12087
|
if (!config.client.account) throw new WalletAccountNotSetError();
|
|
11152
12088
|
const tree = from$8(offers.map((o) => from$14(o)));
|
|
11153
|
-
const
|
|
11154
|
-
for (const offer of tree.offers) if (chainId !== offer.chainId) throw new ChainIdMismatchError(offer.chainId, chainId);
|
|
11155
|
-
const signatureDomain$1 = resolveSignatureDomain(config, chainId);
|
|
12089
|
+
const signatureDomain$1 = resolveSignatureDomain(config, await getChainId(config.client));
|
|
11156
12090
|
const signature = await config.client.signTypedData({
|
|
11157
12091
|
account: config.client.account,
|
|
11158
12092
|
domain: signatureDomain(signatureDomain$1),
|
|
@@ -11257,12 +12191,6 @@ var WalletAccountNotSetError = class extends BaseError {
|
|
|
11257
12191
|
var ViemClientError = class extends BaseError {
|
|
11258
12192
|
name = "Mempool.ViemClientError";
|
|
11259
12193
|
};
|
|
11260
|
-
var ChainIdMismatchError = class extends BaseError {
|
|
11261
|
-
name = "Mempool.ChainIdMismatchError";
|
|
11262
|
-
constructor(expected, actual) {
|
|
11263
|
-
super(`Chain ID mismatch. Offer chain ID is ${expected}, network chain ID is ${actual}.`);
|
|
11264
|
-
}
|
|
11265
|
-
};
|
|
11266
12194
|
const resolveSignatureDomain = (config, chainId) => {
|
|
11267
12195
|
const chain = config.client.chain;
|
|
11268
12196
|
const verifyingContract = config.morphoAddress ?? chain?.custom?.morpho?.address ?? getChain(chainId)?.custom.morpho.address;
|
|
@@ -11291,7 +12219,6 @@ function connect(parameters) {
|
|
|
11291
12219
|
//#endregion
|
|
11292
12220
|
//#region src/mempool/index.ts
|
|
11293
12221
|
var mempool_exports = /* @__PURE__ */ __exportAll({
|
|
11294
|
-
ChainIdMismatchError: () => ChainIdMismatchError,
|
|
11295
12222
|
MissingMorphoAddressError: () => MissingMorphoAddressError,
|
|
11296
12223
|
ViemClientError: () => ViemClientError,
|
|
11297
12224
|
WalletAccountNotSetError: () => WalletAccountNotSetError,
|
|
@@ -11302,5 +12229,5 @@ var mempool_exports = /* @__PURE__ */ __exportAll({
|
|
|
11302
12229
|
});
|
|
11303
12230
|
|
|
11304
12231
|
//#endregion
|
|
11305
|
-
export { Abi_exports as Abi, BookResponse_exports as BookResponse, BooksController, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainHealth, ChainRegistry_exports as ChainRegistry, ChainsHealthResponse, Collateral_exports as Collateral, CollectorHealth, CollectorsHealthResponse, ConfigContractsController, ConfigRulesController, Database_exports as Database, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, Gatekeeper_exports as Gatekeeper, Client_exports as GatekeeperClient, Health_exports as Health, HealthController, Indexer_exports as Indexer, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Logger_exports as Logger, Maturity_exports as Maturity, mempool_exports as Mempool, Obligation_exports as Obligation, ObligationResponse_exports as ObligationResponse, ObligationsController, Offer_exports as Offer, OfferResponse_exports as OfferResponse, OffersController, drizzle_exports as OffersSchema, OpenApi, Oracle_exports as Oracle, Position_exports as Position, PositionResponse_exports as PositionResponse, Quote_exports as Quote, RouterApi_exports as RouterApi, Client_exports$1 as RouterClient, RouterStatusResponse, Rules_exports as Rules, Tick_exports as Tick, time_exports as Time, TradingFee_exports as TradingFee, Transfer_exports as Transfer, Tree_exports as Tree, UsersController, utils_exports as Utils, ValidateController, Gate_exports as Validation, morphoRules, parse, safeParse };
|
|
12232
|
+
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, Id_exports as Id, 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 };
|
|
11306
12233
|
//# sourceMappingURL=index.node.mjs.map
|