1+ import { request } from "graphql-request" ;
12import { FetchOptions , FetchV2 , SimpleAdapter } from "../../adapters/types" ;
23import { CHAIN } from "../../helpers/chains" ;
34import { METRIC } from "../../helpers/metrics" ;
@@ -11,22 +12,38 @@ const CONFIG = {
1112const methodology = {
1213 Fees : "Total borrow interest paid by borrowers + liquidation bonuses earned by liquidators." ,
1314 SupplySideRevenue : "Total interests are distributed to suppliers/lenders + liquidation bonuses to liquidators." ,
14- Revenue : "Total fees paid by borrowers from all markets and part of performance fee retained from all vaults ." ,
15- ProtocolRevenue : "No revenue for Bend protocol." ,
15+ Revenue : "Total interest paid by borrowers and part of performance fees share for Bend protocol ." ,
16+ ProtocolRevenue : "Total interest paid by borrowers and part of performance fees share for Bend protocol." ,
1617}
1718
18- const MorphoBlueAbis = {
19- AccrueInterest : "event AccrueInterest(bytes32 indexed id, uint256 prevBorrowRate, uint256 interest, uint256 feeShares)" ,
20- Liquidate : "event Liquidate(bytes32 indexed id,address indexed caller,address indexed borrower,uint256 repaidAssets,uint256 repaidShares,uint256 seizedAssets,uint256 badDebtAssets,uint256 badDebtShares)" ,
21- CreateMarket : "event CreateMarket(bytes32 indexed id, tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams)" ,
22- } ;
19+ const abi = {
20+ morphoBlueFunctions : {
21+ market : "function market(bytes32 input) returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)" ,
22+ feeRecipient : "function feeRecipient() returns(address feeRecipient)"
23+ } ,
24+ metaMorphoFunctions : {
25+ withdrawQueueLength : "function withdrawQueueLength() view returns (uint256)" ,
26+ withdrawQueue : "function withdrawQueue(uint256 index) view returns (bytes32)" ,
27+ asset : "function asset() view returns (address)" ,
28+ convertToAssets : "function convertToAssets(uint256 shares) view returns (uint256)"
29+ } ,
30+ morphoBlueEvents : {
31+ AccrueInterest : "event AccrueInterest(bytes32 indexed id, uint256 prevBorrowRate, uint256 interest, uint256 feeShares)" ,
32+ CreateMarket : "event CreateMarket(bytes32 indexed id, tuple(address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams)" ,
33+ Liquidate : "event Liquidate(bytes32 indexed id,address indexed caller,address indexed borrower,uint256 repaidAssets,uint256 repaidShares,uint256 seizedAssets,uint256 badDebtAssets,uint256 badDebtShares)"
34+ } ,
35+ metaMorphoEvents : {
36+ Transfer : "event Transfer(address indexed from, address indexed to, uint256 value)"
37+ }
38+ }
2339
2440type MorphoMarket = {
2541 marketId : string ;
2642 loanAsset : string ;
2743 collateralAsset ?: string ;
2844 lltv : bigint ;
2945 lif : bigint ;
46+ fee : bigint ;
3047} ;
3148
3249type MorphoBlueAccrueInterestEvent = {
@@ -41,12 +58,26 @@ type MorphoBlueLiquidateEvent = {
4158 seizedAmount : bigint ;
4259} ;
4360
61+ type PerformanceFee = {
62+ token : string ,
63+ amount : bigint
64+ }
65+
66+ type RewardVault = {
67+ stakingTokenAddress : string
68+ }
69+
70+ const BERACHAIN_API = "https://api.berachain.com" ;
71+
72+
4473const toLowerKey = ( id : string ) => id . toLowerCase ( ) ;
4574
4675const ONE = 10n ** 18n ;
4776
4877const wMul = ( x : bigint , y : bigint ) : bigint => ( x * y / ONE ) ;
4978
79+ const ZERO_ADDRESS = '0x' + '0' . repeat ( 40 ) ;
80+
5081// https://docs.morpho.org/learn/concepts/liquidation/#liquidation-incentive-factor-lif
5182function _getLIFFromLLTV ( lltv : bigint ) : bigint {
5283 const B = BigInt ( 3e17 ) // 0.3
@@ -55,24 +86,46 @@ function _getLIFFromLLTV(lltv: bigint): bigint {
5586 return LIF > M ? M : LIF
5687}
5788
89+ const _getWhitelistedVaults = async ( ) => {
90+ const data = await request ( BERACHAIN_API , `
91+ {
92+ polGetRewardVaults(where: {protocolsIn: ["Bend"], includeNonWhitelisted: false}) {
93+ vaults {
94+ stakingTokenAddress
95+ }
96+ }
97+ }
98+ ` ) ;
99+ return data . polGetRewardVaults . vaults . map ( ( v : RewardVault ) => v . stakingTokenAddress ) ;
100+ }
101+
58102const fetchMarketsFromLogs = async ( options : FetchOptions ) : Promise < Array < MorphoMarket > > => {
59103 const markets : Array < MorphoMarket > = [ ] ;
60104
61105 const events = await options . getLogs ( {
62106 target : CONFIG . blue ,
63- eventAbi : MorphoBlueAbis . CreateMarket ,
107+ eventAbi : abi . morphoBlueEvents . CreateMarket ,
64108 fromBlock : CONFIG . fromBlock ,
65109 } ) ;
66110
67- for ( const event of events ) {
111+ const marketIds = events . map ( event => event . id )
112+
113+ const marketsInfo = await options . api . multiCall ( {
114+ target : CONFIG . blue ,
115+ calls : marketIds ,
116+ abi : abi . morphoBlueFunctions . market ,
117+ } ) ;
118+
119+ events . forEach ( ( event , idx ) => {
68120 markets . push ( {
69121 marketId : event . id ,
70122 loanAsset : event . marketParams . loanToken ,
71123 collateralAsset : event . marketParams . collateralToken ,
72124 lltv : BigInt ( event . marketParams . lltv ) ,
73125 lif : _getLIFFromLLTV ( BigInt ( event . marketParams . lltv ) ) ,
126+ fee : BigInt ( marketsInfo [ idx ] ?. fee )
74127 } )
75- }
128+ } )
76129
77130 return markets ;
78131}
@@ -82,23 +135,24 @@ const fetchEvents = async (
82135) : Promise < { interests : Array < MorphoBlueAccrueInterestEvent > , liquidations : Array < MorphoBlueLiquidateEvent > } > => {
83136 let markets : Array < MorphoMarket > = await fetchMarketsFromLogs ( options )
84137
85-
86138 const marketMap = { } as { [ key : string ] : MorphoMarket } ;
87139 markets . forEach ( ( item ) => {
88140 marketMap [ item . marketId . toLowerCase ( ) ] = item ;
89141 } ) ;
90142
91143 const interests : Array < MorphoBlueAccrueInterestEvent > = (
92144 await options . getLogs ( {
93- eventAbi : MorphoBlueAbis . AccrueInterest ,
145+ eventAbi : abi . morphoBlueEvents . AccrueInterest ,
94146 target : CONFIG . blue ,
95147 } )
96148 ) . map ( ( log : any ) => {
97149 const key = toLowerKey ( String ( log . id ) ) ;
98150 const market = marketMap [ key ] ;
99151
100152 const interest = BigInt ( log . interest ) ;
101- const feeAmount = BigInt ( log . feeShares ) ;
153+ const feeParam = market ?. fee ?? 0n ;
154+
155+ const feeAmount = wMul ( interest , feeParam ) ;
102156
103157 return {
104158 token : market ?. loanAsset ?? null ,
@@ -110,7 +164,7 @@ const fetchEvents = async (
110164
111165 const liquidations : Array < MorphoBlueLiquidateEvent > = (
112166 await options . getLogs ( {
113- eventAbi : MorphoBlueAbis . Liquidate ,
167+ eventAbi : abi . morphoBlueEvents . Liquidate ,
114168 target : CONFIG . blue ,
115169 } )
116170 ) . map ( ( log ) => {
@@ -129,12 +183,52 @@ const fetchEvents = async (
129183 return { interests, liquidations }
130184} ;
131185
186+
187+ const fetchPerformanceFees = async ( options : FetchOptions ) : Promise < Array < PerformanceFee > > => {
188+ const vaults = await _getWhitelistedVaults ( ) ;
189+
190+ const [ feeRecipient , underlyingAssets ] = await Promise . all (
191+ [
192+ options . api . call ( {
193+ abi : abi . morphoBlueFunctions . feeRecipient ,
194+ target : CONFIG . blue ,
195+ } ) ,
196+ options . api . multiCall ( {
197+ abi : abi . metaMorphoFunctions . asset ,
198+ calls : vaults ,
199+ }
200+ )
201+ ] )
202+
203+ return Promise . all ( vaults . map ( async ( v : string , idx : number ) => {
204+ const sharesAmount = ( await options . getLogs ( {
205+ target : v ,
206+ eventAbi : abi . metaMorphoEvents . Transfer ,
207+ } ) )
208+ . filter ( log => log [ 0 ] == ZERO_ADDRESS && log [ 1 ] == feeRecipient )
209+ . map ( log => log [ 2 ] )
210+ . reduce ( ( totalAmount : bigint , value : bigint ) => totalAmount + value , 0n ) ;
211+
212+ const assetAmount = await options . api . call ( {
213+ target : v ,
214+ abi : abi . metaMorphoFunctions . convertToAssets ,
215+ params : [ sharesAmount ]
216+ } )
217+
218+ return {
219+ token : underlyingAssets [ idx ] ,
220+ amount : assetAmount
221+ } as PerformanceFee
222+ } ) )
223+ }
224+
132225const fetch : FetchV2 = async ( options : FetchOptions ) => {
133226 const dailyFees = options . createBalances ( ) ;
134227 const dailyRevenue = options . createBalances ( ) ;
135228 const dailySupplySideRevenue = options . createBalances ( ) ;
136229
137230 const { interests, liquidations } = await fetchEvents ( options ) ;
231+ const performanceFees = await fetchPerformanceFees ( options )
138232
139233 for ( const event of interests ) {
140234 if ( ! event . token ) continue ;
@@ -154,6 +248,11 @@ const fetch: FetchV2 = async (options: FetchOptions) => {
154248 dailySupplySideRevenue . add ( event . token , bonus , METRIC . LIQUIDATION_FEES ) ;
155249 }
156250
251+ for ( const performanceFee of performanceFees ) {
252+ dailyFees . add ( performanceFee . token , performanceFee . amount , METRIC . PERFORMANCE_FEES )
253+ dailyRevenue . add ( performanceFee . token , performanceFee . amount , METRIC . PERFORMANCE_FEES )
254+ }
255+
157256 return {
158257 dailyFees : dailyFees ,
159258 dailySupplySideRevenue,
@@ -168,17 +267,20 @@ const adapter: SimpleAdapter = {
168267 breakdownMethodology : {
169268 Fees : {
170269 [ METRIC . BORROW_INTEREST ] : 'All interest paid by borrowers from all markets.' ,
270+ [ METRIC . PERFORMANCE_FEES ] : 'Share of interest for Bend protocol paid by Vault curator.' ,
171271 [ METRIC . LIQUIDATION_FEES ] : 'All bonuses earned by liquidators from liquidations.' ,
172272 } ,
173273 Revenue : {
174274 [ METRIC . BORROW_INTEREST ] : 'Share of interest for Bend protocol.' ,
275+ [ METRIC . PERFORMANCE_FEES ] : 'Share of interest for Bend protocol paid by Vault curator.' ,
175276 } ,
176277 SupplySideRevenue : {
177278 [ METRIC . BORROW_INTEREST ] : 'All interests paid are distributedd to vaults suppliers, lenders.' ,
178279 [ METRIC . LIQUIDATION_FEES ] : 'All bonuses earned by liquidators from liquidations.' ,
179280 } ,
180281 ProtocolRevenue : {
181282 [ METRIC . BORROW_INTEREST ] : 'Share of interest for Bend protocol.' ,
283+ [ METRIC . PERFORMANCE_FEES ] : 'Share of interest for Bend protocol paid by Vault curator.' ,
182284 } ,
183285 } ,
184286 fetch : fetch ,
0 commit comments