@moonwell-fi/moonwell-sdk
Version:
TypeScript Interface for Moonwell
407 lines • 18.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getMorphoMarketsData = getMorphoMarketsData;
const amount_js_1 = require("../../../common/amount.js");
const graphql_js_1 = require("../utils/graphql.js");
async function getMorphoMarketsData(params) {
const { environments } = params;
const environmentsWithMarkets = environments.filter((environment) => Object.keys(environment.config.morphoMarkets).length > 0 &&
environment.contracts.morphoViews);
const environmentsMarketsInfo = await Promise.all(environmentsWithMarkets.map((environment) => {
const marketsIds = Object.values(environment.config.morphoMarkets)
.map((item) => item.id)
.filter((id) => params.markets
? params.markets
.map((id) => id.toLowerCase())
.includes(id.toLowerCase())
: true);
return environment.contracts.morphoViews?.read.getMorphoBlueMarketsInfo([
marketsIds,
]);
}));
const environmentPublicAllocatorSharedLiquidity = await Promise.all(environmentsWithMarkets.map((environment) => {
const marketsIds = Object.values(environment.config.morphoMarkets)
.map((item) => item.id)
.filter((id) => params.markets
? params.markets
.map((id) => id.toLowerCase())
.includes(id.toLowerCase())
: true);
return getMorphoMarketPublicAllocatorSharedLiquidity(environment, marketsIds);
}));
const result = environmentsWithMarkets.reduce((aggregator, environment, environmentIndex) => {
const environmentMarketsInfo = environmentsMarketsInfo[environmentIndex];
const markets = environmentMarketsInfo.map((marketInfo) => {
const marketKey = Object.keys(environment.config.morphoMarkets).find((item) => environment.config.morphoMarkets[item].id.toLowerCase() ===
marketInfo.marketId.toLowerCase());
const marketConfig = Object.values(environment.config.morphoMarkets).find((item) => item.id.toLowerCase() === marketInfo.marketId.toLowerCase());
const loanToken = environment.config.tokens[marketConfig.loanToken];
const collateralToken = environment.config.tokens[marketConfig.collateralToken];
const oraclePrice = new amount_js_1.Amount(BigInt(marketInfo.oraclePrice), 36 + loanToken.decimals - collateralToken.decimals).value;
let collateralTokenPrice = new amount_js_1.Amount(marketInfo.collateralPrice, 18)
.value;
let loanTokenPrice = new amount_js_1.Amount(marketInfo.loanPrice, 18).value;
if (collateralTokenPrice === 0 && loanTokenPrice > 0) {
collateralTokenPrice = loanTokenPrice * oraclePrice;
}
if (loanTokenPrice === 0 && collateralTokenPrice > 0) {
loanTokenPrice = collateralTokenPrice / oraclePrice;
}
const publicAllocatorSharedLiquidity = environmentPublicAllocatorSharedLiquidity[environmentIndex]?.find((item) => item.marketId === marketInfo.marketId);
const performanceFee = new amount_js_1.Amount(marketInfo.fee, 18).value;
const loanToValue = new amount_js_1.Amount(marketInfo.lltv, 18).value;
const totalSupplyInLoanToken = new amount_js_1.Amount(BigInt(marketInfo.totalSupplyAssets), loanToken.decimals);
const totalSupply = new amount_js_1.Amount(Number(totalSupplyInLoanToken.value / oraclePrice), collateralToken.decimals);
const totalBorrows = new amount_js_1.Amount(marketInfo.totalBorrowAssets, loanToken.decimals);
const borrowApy = new amount_js_1.Amount(marketInfo.borrowApy, 18).value * 100;
const availableLiquidity = publicAllocatorSharedLiquidity?.reallocatableLiquidityAssets ||
new amount_js_1.Amount(0, 18);
const availableLiquidityUsd = availableLiquidity?.value * loanTokenPrice;
const collateralAssets = publicAllocatorSharedLiquidity?.collateralAssets || new amount_js_1.Amount(0, 18);
const mapping = {
chainId: environment.chainId,
marketId: marketInfo.marketId,
marketKey,
deprecated: marketConfig.deprecated === true,
loanToValue,
performanceFee,
loanToken,
loanTokenPrice,
collateralToken,
collateralTokenPrice,
collateralAssets,
totalSupply,
totalSupplyUsd: totalSupply.value * collateralTokenPrice,
totalSupplyInLoanToken,
totalBorrows,
totalBorrowsUsd: totalBorrows.value * loanTokenPrice,
baseBorrowApy: borrowApy,
totalBorrowApr: borrowApy,
baseSupplyApy: 0,
totalSupplyApr: 0,
rewardsSupplyApy: 0,
rewardsBorrowApy: 0,
availableLiquidity,
availableLiquidityUsd,
marketParams: {
loanToken: marketInfo.loanToken,
collateralToken: marketInfo.collateralToken,
irm: marketInfo.irm,
lltv: marketInfo.lltv,
oracle: marketInfo.oracle,
},
rewards: [],
publicAllocatorSharedLiquidity: publicAllocatorSharedLiquidity?.publicAllocatorSharedLiquidity ||
[],
};
return mapping;
});
return {
...aggregator,
[environment.chainId]: markets,
};
}, {});
if (params.includeRewards) {
const markets = Object.values(result)
.flat()
.filter((market) => {
const environment = params.environments.find((environment) => environment.chainId === market.chainId);
return environment?.custom.morpho?.minimalDeployment === false;
});
const rewards = await getMorphoMarketRewards(markets);
markets.forEach((market) => {
const marketReward = rewards.find((reward) => reward.marketId === market.marketId &&
reward.chainId === market.chainId);
if (marketReward) {
market.rewards = marketReward.rewards;
}
market.rewardsSupplyApy = market.rewards.reduce((acc, curr) => acc + curr.supplyApr, 0);
market.rewardsBorrowApy = market.rewards.reduce((acc, curr) => acc + curr.borrowApr, 0);
market.totalSupplyApr = market.rewardsSupplyApy + market.baseSupplyApy;
market.totalBorrowApr = market.rewardsBorrowApy + market.baseBorrowApy;
});
}
return environments.flatMap((environment) => {
return result[environment.chainId] || [];
});
}
async function getMorphoMarketPublicAllocatorSharedLiquidity(environment, markets) {
if (markets.length === 0) {
return [];
}
const query = `
{
metaMorphos(
where: {hasPublicAllocator: true, markets_: {market_in: [${markets.map((market) => `"${market.toLowerCase()}"`).join(",")}]}}
) {
id
name
lastTotalAssets
markets {
market {
id
}
enabled
cap
}
publicAllocator {
id
fee
markets {
id
flowCapIn
flowCapOut
market {
market {
id
oracle {
oracleAddress
}
irm
lltv
totalBorrow
totalSupply
totalCollateral
inputToken {
symbol
decimals
id
}
borrowedToken {
symbol
decimals
id
}
}
}
}
}
account {
positions(where:{side:SUPPLIER}) {
market {
id
}
balance
}
}
}
}
`;
const result = await (0, graphql_js_1.getSubgraph)(environment, query);
if (result) {
const returnValue = [];
for (const market of markets) {
let inputTokenDecimals = 0;
let outputTokenDecimals = 0;
let collateralAssets = 0;
let reallocatableLiquidityAssets = 0;
const r = [];
const marketRemainingLiquidity = {};
const vaults = result.metaMorphos.filter((item) => item.publicAllocator.markets.some((vaultMarket) => vaultMarket.market.market.id.toLowerCase() ===
market.toLowerCase()) &&
item.account.positions.some((position) => position.market.id.toLowerCase() === market.toLowerCase() &&
Number(position.balance) > 0));
for (const vault of vaults) {
const otherMarkets = vault.publicAllocator.markets.filter((publicAllocatorMarket) => publicAllocatorMarket.market.market.id.toLowerCase() !==
market.toLowerCase());
const thisMarket = vault.publicAllocator.markets.find((publicAllocatorMarket) => publicAllocatorMarket.market.market.id.toLowerCase() ===
market.toLowerCase());
const thisMarketCaps = vault.markets.find((marketCaps) => marketCaps.market.id.toLowerCase() === market.toLowerCase());
const thisMarketCap = Number(thisMarketCaps?.cap || 0);
const suppliedToMarket = vault.account.positions.find((position) => position.market.id.toLowerCase() === market.toLowerCase());
const suppliedToMarketAmount = Number(suppliedToMarket?.balance || 0);
const thisMarketCapRemaining = thisMarketCap - suppliedToMarketAmount;
let maxIn = Math.min(Number(thisMarket?.flowCapIn), thisMarketCapRemaining);
collateralAssets = Number(thisMarket?.market.market.totalCollateral || 0);
inputTokenDecimals = thisMarket?.market.market.inputToken.decimals || 0;
outputTokenDecimals =
thisMarket?.market.market.borrowedToken.decimals || 0;
const otherMarketsLiquidity = [];
for (const otherMarket of otherMarkets) {
const vaultSuppliedToMarket = vault.account.positions.find((position) => position.market.id.toLowerCase() ===
otherMarket.market.market.id.toLowerCase());
if (vaultSuppliedToMarket) {
const vaultSuppliedAmount = Number(vaultSuppliedToMarket.balance);
const maxOut = Number(otherMarket.flowCapOut);
const liquidity = Number(otherMarket.market.market.totalSupply) -
Number(otherMarket.market.market.totalBorrow);
if (vaultSuppliedAmount > 0 && maxOut > 0 && liquidity > 0) {
otherMarketsLiquidity.push({
marketId: otherMarket.market.market.id,
amount: Math.min(liquidity, vaultSuppliedAmount, maxOut),
liquidity,
vault: {
address: vault.id,
name: vault.name,
publicAllocatorConfig: {
fee: Number(vault.publicAllocator.fee),
flowCaps: vault.publicAllocator.markets.map((publicAllocatorMarket) => ({
maxIn: Number(publicAllocatorMarket.flowCapIn),
maxOut: Number(publicAllocatorMarket.flowCapOut),
market: {
uniqueKey: publicAllocatorMarket.market.market.id,
},
})),
},
},
allocationMarket: {
uniqueKey: otherMarket.market.market.id,
loanAsset: {
address: otherMarket.market.market.borrowedToken.id,
},
collateralAsset: {
address: otherMarket.market.market.inputToken.id,
},
oracleAddress: otherMarket.market.market.oracle.oracleAddress,
irmAddress: otherMarket.market.market.irm,
lltv: otherMarket.market.market.lltv,
},
});
}
}
}
for (const otherMarket of otherMarketsLiquidity
.filter((item) => item.amount > 0)
.sort((a, b) => b.amount - a.amount)) {
const marketLiquidity = marketRemainingLiquidity[otherMarket.marketId] ||
otherMarket.liquidity;
if (maxIn > 0 && marketLiquidity > 0) {
const assets = Math.min(marketLiquidity, otherMarket.amount, maxIn);
maxIn = maxIn - assets;
marketRemainingLiquidity[otherMarket.marketId] =
marketLiquidity - assets;
reallocatableLiquidityAssets += assets;
r.push({
assets,
vault: otherMarket.vault,
allocationMarket: otherMarket.allocationMarket,
});
}
}
}
returnValue.push({
chainId: environment.chainId,
marketId: market.toLowerCase(),
collateralAssets: new amount_js_1.Amount(BigInt(collateralAssets), inputTokenDecimals),
reallocatableLiquidityAssets: new amount_js_1.Amount(BigInt(reallocatableLiquidityAssets), outputTokenDecimals),
publicAllocatorSharedLiquidity: r,
});
}
return returnValue;
}
else {
return [];
}
}
async function getMorphoMarketRewards(markets) {
if (markets.length === 0) {
return [];
}
const query = `
{
markets(where: { uniqueKey_in: [${markets.map((market) => `"${market.marketId.toLowerCase()}"`).join(",")}], chainId_in: [${markets.map((market) => market.chainId).join(",")}] })
{
items {
morphoBlue {
chain {
id
}
}
reallocatableLiquidityAssets
publicAllocatorSharedLiquidity {
assets
vault {
address
name
publicAllocatorConfig {
fee
flowCaps {
maxIn
maxOut
market {
uniqueKey
}
}
}
}
allocationMarket {
uniqueKey
loanAsset {
address
}
collateralAsset {
address
}
oracleAddress
irmAddress
lltv
}
}
collateralAsset {
decimals
}
loanAsset {
decimals
priceUsd
}
state {
collateralAssets
rewards {
asset {
address
symbol
decimals
name
}
supplyApr
borrowApr
amountPerBorrowedToken
amountPerSuppliedToken
}
}
uniqueKey
}
}
} `;
const result = await (0, graphql_js_1.getGraphQL)(query);
if (result) {
const markets = result.markets.items.map((item) => {
const mapping = {
chainId: item.morphoBlue.chain.id,
marketId: item.uniqueKey,
reallocatableLiquidityAssets: new amount_js_1.Amount(BigInt(item.reallocatableLiquidityAssets), item.loanAsset.decimals),
collateralAssets: new amount_js_1.Amount(BigInt(item.state.collateralAssets), item.collateralAsset.decimals),
publicAllocatorSharedLiquidity: item.publicAllocatorSharedLiquidity.map((item) => ({
assets: Number(item.assets),
vault: {
address: item.vault.address,
name: item.vault.name,
publicAllocatorConfig: item.vault.publicAllocatorConfig,
},
allocationMarket: item.allocationMarket,
})),
rewards: item.state?.rewards.map((reward) => {
const tokenDecimals = 10 ** reward.asset.decimals;
const borrowTokenAmountPer1000 = (Number.parseFloat(reward.amountPerBorrowedToken) /
item.loanAsset.priceUsd) *
1000;
const borrowAmount = borrowTokenAmountPer1000 / tokenDecimals;
return {
marketId: item.uniqueKey,
asset: reward.asset,
supplyApr: 0,
supplyAmount: 0,
borrowApr: (reward.borrowApr || 0) * 100 * -1,
borrowAmount: borrowAmount,
};
}),
};
return mapping;
});
return markets;
}
else {
return [];
}
}
//# sourceMappingURL=common.js.map