Skip to content

Commit 29516b0

Browse files
authored
feat(rewards): fixing morpho rewards on vault positions (#1699)
1 parent 855a05a commit 29516b0

File tree

1 file changed

+76
-37
lines changed

1 file changed

+76
-37
lines changed

src/adaptors/morpho-blue/index.js

Lines changed: 76 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
const { request, gql } = require('graphql-request');
22

33
const GRAPH_URL = 'https://blue-api.morpho.org/graphql';
4-
const MORPHO_TOKEN_ADDRESS = '0x9994E35Db50125E0DF82e4c2dde62496CE330999';
54
const CHAINS = {
65
ethereum: 1,
76
base: 8453,
87
};
98

109
const gqlQueries = {
1110
marketsData: gql`
12-
query GetYieldsData($chainId: Int!) {
11+
query GetYieldsData($chainId: Int!, $skip: Int!) {
1312
markets(
14-
first: 800
13+
first: 100
14+
skip: $skip
1515
orderBy: SupplyAssetsUsd
1616
orderDirection: Desc
1717
where: { chainId_in: [$chainId] }
@@ -43,6 +43,7 @@ const gqlQueries = {
4343
supplyAssetsUsd
4444
borrowAssetsUsd
4545
rewards {
46+
borrowApr
4647
asset {
4748
address
4849
}
@@ -53,9 +54,10 @@ const gqlQueries = {
5354
}
5455
`,
5556
metaMorphoVaults: gql`
56-
query GetVaultsData($chainId: Int!) {
57+
query GetVaultsData($chainId: Int!, $skip: Int!) {
5758
vaults(
5859
first: 100
60+
skip: $skip
5961
orderBy: TotalAssetsUsd
6062
orderDirection: Desc
6163
where: { chainId_in: [$chainId] }
@@ -78,10 +80,18 @@ const gqlQueries = {
7880
fee
7981
totalSupply
8082
allocation {
83+
supplyAssetsUsd
8184
market {
8285
uniqueKey
86+
state {
87+
rewards {
88+
asset {
89+
address
90+
}
91+
supplyApr
92+
}
93+
}
8394
}
84-
supplyAssetsUsd
8595
}
8696
}
8797
}
@@ -98,42 +108,59 @@ const apy = async () => {
98108
let pools = [];
99109

100110
for (const [chain, chainId] of Object.entries(CHAINS)) {
101-
const data = await Promise.all([
102-
request(GRAPH_URL, gqlQueries.metaMorphoVaults, { chainId }),
103-
request(GRAPH_URL, gqlQueries.marketsData, { chainId }),
104-
]);
111+
// Fetch vaults data with pagination
112+
let allVaults = [];
113+
let skip = 0;
114+
while (true) {
115+
const { vaults } = await request(GRAPH_URL, gqlQueries.metaMorphoVaults, {
116+
chainId,
117+
skip,
118+
});
119+
120+
if (!vaults.items.length) break;
121+
122+
allVaults = [...allVaults, ...vaults.items];
123+
skip += 100;
124+
}
125+
126+
// Fetch markets data with pagination
127+
let allMarkets = [];
128+
skip = 0;
129+
while (true) {
130+
const { markets } = await request(GRAPH_URL, gqlQueries.marketsData, {
131+
chainId,
132+
skip,
133+
});
105134

106-
const earn = data[0].vaults.items;
107-
const borrow = data[1].markets.items;
135+
if (!markets.items.length) break;
136+
137+
allMarkets = [...allMarkets, ...markets.items];
138+
skip += 100;
139+
}
140+
141+
const earn = allVaults;
142+
const borrow = allMarkets;
108143

109144
const earnPools = earn.map((vault) => {
110-
// fetch reward token addresses from borrow data
111-
let additionalRewardTokens = [];
145+
// fetch reward token addresses from allocation data
146+
let additionalRewardTokens = new Set();
112147
vault.state.allocation.forEach((allocatedMarket) => {
113-
if (allocatedMarket.supplyAssetsUsd !== 0) {
114-
const marketRewards = borrow.find(
115-
(market) =>
116-
market.pool === `morpho-blue-${allocatedMarket.market.uniqueKey}`
117-
);
118-
if (marketRewards) {
119-
additionalRewardTokens = additionalRewardTokens.concat(
120-
marketRewards.rewardTokens
121-
);
122-
}
148+
const allocationUsd = allocatedMarket.supplyAssetsUsd;
149+
if (allocationUsd > 0) {
150+
// For each reward from the allocated market
151+
allocatedMarket.market.state.rewards?.forEach((rw) => {
152+
if (rw.supplyApr > 0) {
153+
additionalRewardTokens.add(rw.asset.address.toLowerCase());
154+
}
155+
});
123156
}
124157
});
125158

126159
// net = including rewards, apy = baseApy
127-
const rewardsApy = vault.state.netApy - vault.state.apy;
128-
const isNegligibleApy = isNegligible(rewardsApy, vault.state.apy);
129-
const apyReward =
130-
isNegligibleApy || additionalRewardTokens.length === 0
131-
? 0
132-
: rewardsApy * 100;
133-
const rewardTokens =
134-
isNegligibleApy || additionalRewardTokens.length === 0
135-
? []
136-
: [...new Set(additionalRewardTokens)];
160+
const rewardsApy = Math.max(vault.state.netApy - vault.state.apy, 0);
161+
const isNegligibleApy = isNegligible(rewardsApy, vault.state.netApy);
162+
const rewardTokens = isNegligibleApy ? [] : [...additionalRewardTokens];
163+
const apyReward = rewardTokens.length === 0 ? 0 : rewardsApy * 100;
137164

138165
return {
139166
pool: `morpho-blue-${vault.address}-${chain}`,
@@ -153,10 +180,9 @@ const apy = async () => {
153180

154181
const borrowPools = borrow.map((market) => {
155182
if (!market.collateralAsset?.symbol) return null;
156-
157183
const rewardTokens = market.state.rewards
158-
.map((reward) => reward.asset.address)
159-
.filter((address) => address !== MORPHO_TOKEN_ADDRESS);
184+
.filter((reward) => reward.borrowApr > 0)
185+
.map((reward) => reward.asset.address);
160186

161187
const apyRewardBorrow =
162188
Math.max(
@@ -190,7 +216,20 @@ const apy = async () => {
190216
pools = [...pools, ...earnPools, ...borrowPools];
191217
}
192218

193-
return pools.filter(Boolean);
219+
const uniquePools = Array.from(
220+
pools
221+
.reduce((map, pool) => {
222+
if (!pool) return map;
223+
const key = `morpho-blue-${pool.pool}-${pool.chain}`;
224+
if (!map.has(key) || pool.tvlUsd > map.get(key).tvlUsd) {
225+
map.set(key, pool);
226+
}
227+
return map;
228+
}, new Map())
229+
.values()
230+
);
231+
232+
return uniquePools.filter(Boolean);
194233
};
195234

196235
module.exports = {

0 commit comments

Comments
 (0)