Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/moo-391-fix-morpho-graphql-schema.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonwell-fi/moonwell-sdk": patch
---

Fix Morpho GraphQL queries broken by upstream API schema changes. The Morpho API renamed `Market.uniqueKey` to `marketId` and replaced `PublicAllocatorSharedLiquidity.allocationMarket` with `withdrawMarket`, causing the rewards and shared-liquidity queries to fail with 400 errors that were silently swallowed — every Morpho vault reported empty rewards (MOO-391). Also migrates vault rewards to `state.allRewards` and drops the deprecated `amountPerSuppliedToken`/`amountPerBorrowedToken` fields ahead of their removal (reward token amounts are now reported as 0 since the API no longer exposes them), and logs Morpho GraphQL errors in non-browser environments so failures surface in server logs.
64 changes: 36 additions & 28 deletions src/actions/morpho/markets/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,13 +603,13 @@ async function getMorphoMarketRewards(
maxIn
maxOut
market {
uniqueKey
marketId
}
}
}
}
allocationMarket {
uniqueKey
allocationMarket: withdrawMarket {
marketId
loanAsset {
address
}
Expand Down Expand Up @@ -640,11 +640,9 @@ async function getMorphoMarketRewards(
}
supplyApr
borrowApr
amountPerBorrowedToken
amountPerSuppliedToken
}
}
uniqueKey
marketId
}
}
} `;
Expand All @@ -657,7 +655,7 @@ async function getMorphoMarketRewards(
id: number;
};
};
uniqueKey: string;
marketId: string;
reallocatableLiquidityAssets: string;
publicAllocatorSharedLiquidity: {
assets: string;
Expand All @@ -668,15 +666,15 @@ async function getMorphoMarketRewards(
fee: number;
flowCaps: {
market: {
uniqueKey: string;
marketId: string;
};
maxIn: number;
maxOut: number;
}[];
};
};
allocationMarket: {
uniqueKey: string;
marketId: string;
loanAsset: {
address: string;
};
Expand Down Expand Up @@ -706,9 +704,7 @@ async function getMorphoMarketRewards(
name: string;
};
supplyApr: number;
amountPerSuppliedToken: string;
borrowApr: number;
amountPerBorrowedToken: string;
}[];
};
}[];
Expand All @@ -720,7 +716,7 @@ async function getMorphoMarketRewards(
const loanAssetDecimals = item.loanAsset.decimals;
const mapping: GetMorphoMarketsRewardsReturnType = {
chainId: item.morphoBlue.chain.id,
marketId: item.uniqueKey,
marketId: item.marketId,
reallocatableLiquidityAssets: new Amount(
BigInt(item.reallocatableLiquidityAssets),
loanAssetDecimals,
Expand All @@ -742,31 +738,43 @@ async function getMorphoMarketRewards(
vault: {
address: item.vault.address,
name: item.vault.name,
publicAllocatorConfig: item.vault.publicAllocatorConfig,
// The Morpho API renamed Market.uniqueKey to marketId; map it
// back to keep the SDK's public types unchanged.
publicAllocatorConfig: {
fee: item.vault.publicAllocatorConfig.fee,
flowCaps: item.vault.publicAllocatorConfig.flowCaps.map(
(flowCap) => ({
market: { uniqueKey: flowCap.market.marketId },
maxIn: flowCap.maxIn,
maxOut: flowCap.maxOut,
}),
),
},
},
allocationMarket: {
uniqueKey: item.allocationMarket.marketId,
loanAsset: item.allocationMarket.loanAsset,
...(item.allocationMarket.collateralAsset
? { collateralAsset: item.allocationMarket.collateralAsset }
: {}),
oracleAddress: item.allocationMarket.oracleAddress,
irmAddress: item.allocationMarket.irmAddress,
lltv: item.allocationMarket.lltv,
},
allocationMarket: item.allocationMarket,
}),
),
rewards: item.state?.rewards.map((reward) => {
const tokenDecimals = 10 ** reward.asset.decimals;

//Supply APR is used only for vaults, zeroing it for now to avoid confusion
//const tokenAmountPer1000 = ((parseFloat(reward.amountPerSuppliedToken) / item.loanAsset.priceUsd) * 1000) || "0"
//const amount = (Number(tokenAmountPer1000) / tokenDecimals)

const borrowTokenAmountPer1000 =
(Number.parseFloat(reward.amountPerBorrowedToken) /
item.loanAsset.priceUsd) *
1000;

const borrowAmount = borrowTokenAmountPer1000 / tokenDecimals;
// Morpho removed the per-token amount fields from the API
// (MarketStateReward.amountPerBorrowedToken et al.), so reward
// amounts can no longer be computed and are reported as 0.
return {
marketId: item.uniqueKey,
marketId: item.marketId,
asset: reward.asset,
supplyApr: 0, //(reward.supplyApr || 0) * 100,
supplyAmount: 0, //amount,
supplyAmount: 0,
borrowApr: (reward.borrowApr || 0) * 100 * -1,
borrowAmount: borrowAmount,
borrowAmount: 0,
};
}),
};
Expand Down
28 changes: 10 additions & 18 deletions src/actions/morpho/utils/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,16 @@ export async function getGraphQL<T>(

const json = await response.json();
if (response.status !== 200 || json.errors) {
if (typeof window !== "undefined") {
console.debug(
`[Morpho GraphQL] Non-200 (${response.statusText}) or errors:`,
json.errors,
);
}
console.error(
`[Morpho GraphQL] Non-200 (${response.statusText}) or errors:`,
JSON.stringify(json.errors),
);
return undefined;
}

return json.data as T;
} catch (error) {
if (typeof window !== "undefined") {
console.debug("[Morpho GraphQL] Error fetching data:", error);
}
console.error("[Morpho GraphQL] Error fetching data:", error);
return undefined;
}
}
Expand Down Expand Up @@ -94,20 +90,16 @@ export async function getVaultV2Apy(

const json = await response.json();
if (response.status !== 200 || json.errors) {
if (typeof window !== "undefined") {
console.debug(
`[Morpho V2 APY] Non-200 (${response.statusText}) or errors:`,
json.errors,
);
}
console.error(
`[Morpho V2 APY] Non-200 (${response.statusText}) or errors:`,
JSON.stringify(json.errors),
);
return undefined;
}

return json.data?.vaultV2ByAddress as MorphoVaultV2ApyResponse | undefined;
} catch (error) {
if (typeof window !== "undefined") {
console.debug("[Morpho V2 APY] Error fetching data:", error);
}
console.error("[Morpho V2 APY] Error fetching data:", error);
return undefined;
}
}
49 changes: 11 additions & 38 deletions src/actions/morpho/vaults/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1372,11 +1372,8 @@ export async function getMorphoVaultsRewards(
}
id
address
asset {
priceUsd
}
state {
rewards {
allRewards {
asset {
address
symbol
Expand All @@ -1387,7 +1384,6 @@ export async function getMorphoVaultsRewards(
}
}
supplyApr
amountPerSuppliedToken
}
}
}
Expand All @@ -1405,10 +1401,7 @@ export async function getMorphoVaultsRewards(
id
}
}
uniqueKey
loanAsset {
priceUsd
}
marketId
state {
rewards {
asset {
Expand All @@ -1421,7 +1414,6 @@ export async function getMorphoVaultsRewards(
}
}
supplyApr
amountPerSuppliedToken
}
}
}
Expand All @@ -1437,11 +1429,8 @@ export async function getMorphoVaultsRewards(
};
id: string;
address: Address;
asset: {
priceUsd: number;
};
state: {
rewards: {
allRewards: {
asset: {
address: Address;
symbol: string;
Expand All @@ -1452,7 +1441,6 @@ export async function getMorphoVaultsRewards(
};
};
supplyApr: number;
amountPerSuppliedToken: string;
}[];
};
}[];
Expand All @@ -1468,10 +1456,7 @@ export async function getMorphoVaultsRewards(
id: number;
};
};
uniqueKey: string;
loanAsset: {
priceUsd: number;
};
marketId: string;
state: {
rewards: {
asset: {
Expand All @@ -1484,7 +1469,6 @@ export async function getMorphoVaultsRewards(
};
};
supplyApr: number;
amountPerSuppliedToken: string;
}[];
};
};
Expand All @@ -1494,22 +1478,18 @@ export async function getMorphoVaultsRewards(

if (result) {
try {
// Morpho removed the per-supplied-token amount fields from the API
// (VaultStateReward.amountPerSuppliedToken et al.), so reward amounts
// can no longer be computed and are reported as 0.
const marketsRewards = result.marketPositions.items.flatMap((item) => {
const rewards = (item.market.state?.rewards || []).map((reward) => {
const tokenAmountPer1000 =
(Number.parseFloat(reward.amountPerSuppliedToken) /
item.market.loanAsset.priceUsd) *
1000;
const tokenDecimals = 10 ** reward.asset.decimals;
const amount = Number(tokenAmountPer1000) / tokenDecimals;

return {
chainId: reward.asset.chain.id,
vaultId: item.user.address,
marketId: item.market.uniqueKey,
marketId: item.market.marketId,
asset: reward.asset,
supplyApr: (reward.supplyApr || 0) * 100,
supplyAmount: amount,
supplyAmount: 0,
borrowApr: 0,
borrowAmount: 0,
};
Expand All @@ -1518,21 +1498,14 @@ export async function getMorphoVaultsRewards(
});

const vaultsRewards = result.vaults.items.flatMap((item) => {
return (item.state?.rewards || []).map((reward) => {
const tokenAmountPer1000 =
(Number.parseFloat(reward.amountPerSuppliedToken) /
item.asset.priceUsd) *
1000;
const tokenDecimals = 10 ** reward.asset.decimals;
const amount = Number(tokenAmountPer1000) / tokenDecimals;

return (item.state?.allRewards || []).map((reward) => {
return {
chainId: reward.asset.chain.id,
vaultId: item.address,
marketId: undefined,
asset: reward.asset,
supplyApr: (reward.supplyApr || 0) * 100,
supplyAmount: amount,
supplyAmount: 0,
borrowApr: 0,
borrowAmount: 0,
};
Expand Down
Loading