11const { request, gql } = require ( 'graphql-request' ) ;
22
33const GRAPH_URL = 'https://blue-api.morpho.org/graphql' ;
4- const MORPHO_TOKEN_ADDRESS = '0x9994E35Db50125E0DF82e4c2dde62496CE330999' ;
54const CHAINS = {
65 ethereum : 1 ,
76 base : 8453 ,
87} ;
98
109const 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
196235module . exports = {
0 commit comments