11const ADDRESSES = require ( '../helper/coreAssets.json' )
22const { treasuryExports } = require ( "../helper/treasury" ) ;
33
4+ const bUSD0 = "0x35d8949372d46b7a3d5a56006ae77b215fc69bc0" ;
45const tokens = [
56 '0x259338656198ec7a76c729514d3cb45dfbf768a1' , // Resolv
67 '0xd001f0a15d272542687b2677ba627f48a4333b5d' , // e-USD0
7- '0xF8094570485B124b4f2aBE98909A87511489C162' , // PENDLE-LPT
8- '0x67ec31a47a4126A66C7bb2fE017308cf5832A4Db' , // usUSDS++
9- '0xb4cd5c5440eb69edb6db878ca2acd7c6b97b2ba5' , // YT-USD0++-27NOV2025
10- '0xD2245ee5C3099d65a3d0fdCecA0f71Cc4aA8f0FF' , // fSL23
11- '0x8092cA384D44260ea4feaf7457B629B8DC6f88F0' , // ustUSR++
12- '0x8245FD9Ae99A482dFe76576dd4298f799c041D61' , // uUSCC++
13- '0x28d24D4380B26A1Ef305Ad8D8DB258159E472F33' , // Usual_MV
14- '0x35D8949372D46B7a3D5A56006AE77B215fc69bC0' , // USD0++
15- '0x2e7fC02bE94BC7f0cD69DcAB572F64bcC173cd81' , // USD0a
8+ '0xf8094570485b124b4f2abe98909a87511489c162' , // PENDLE-LPT
9+ '0xb4cd5c5440eb69edb6db878ca2acd7c6b97b2ba5' , // YT-USD0++-27NOV2025
10+ '0xd2245ee5c3099d65a3d0fdceca0f71cc4aa8f0ff' , // fSL23
11+ '0x8092ca384d44260ea4feaf7457b629b8dc6f88f0' , // ustUSR++
12+ '0x28d24d4380b26a1ef305ad8d8db258159e472f33' , // Usual_MV
13+ bUSD0 , // formerlyUSD0++
14+ '0x2e7fc02be94bc7f0cd69dcab572f64bcc173cd81' , // USD0a
1615 ADDRESSES . ethereum . USD0 , // USD0
1716 ADDRESSES . ethereum . USDC , // USDC
1817 ADDRESSES . ethereum . WETH , // WETH
1918 '0x58d97b57bb95320f9a05dc918aef65434969c2b2' , // morpho
20- '0x734eec7930bc84eC5732022B9EB949A81fB89AbE ' , // ETH0
19+ '0x734eec7930bc84ec5732022b9eb949a81fb89abe ' , // ETH0
2120 '0x3c89cd1884e7bef73ca3ef08d2ef6ec338fd8e49' , // EUR0
22- '0xC4441c2BE5d8fA8126822B9929CA0b81Ea0DE38E ' , // USUAL
23- '0x437cc33344a0B27A429f795ff6B469C72698B291 ' , // wM
24- '0xC139190F447e929f090Edeb554D95AbB8b18aC1C ' , // USDtb
25- '0xAF87B90E8a3035905697E07Bb813d2d59D2b0951 ' , // uTac
26- '0x77633305032b6bDf3eBdB373b3bADcCb2786ce2f ' , // EVK Vault eUSD0-6
27- '0x5Cd97d97D311F9dE388C1C110b10BF81AAD7CAf0 ' , // Bunni USD0 - USD0++
28- '0x749794E985Af5a9A384B9cEe6D88DaB4CE1576A1 ' , // MEVCapital USD0
29- '0xa0769f7A8fC65e47dE93797b4e21C073c117Fc80 ' , // euTBL
30- '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c ' , // EURC
21+ '0xc4441c2be5d8fa8126822b9929ca0b81ea0de38e ' , // USUAL
22+ '0x437cc33344a0b27a429f795ff6b469c72698b291 ' , // wM
23+ '0xc139190f447e929f090edeb554d95abb8b18ac1c ' , // USDtb
24+ '0xaf87b90e8a3035905697e07bb813d2d59d2b0951 ' , // uTac
25+ '0x77633305032b6bdf3ebdb373b3badccb2786ce2f ' , // EVK Vault eUSD0-6
26+ '0x5cd97d97d311f9de388c1c110b10bf81aad7caf0 ' , // Bunni USD0 - USD0++
27+ '0x749794e985af5a9a384b9cee6d88dab4ce1576a1 ' , // MEVCapital USD0
28+ '0xa0769f7a8fc65e47de93797b4e21c073c117fc80 ' , // euTBL
29+ '0x1abaea1f7c830bd89acc67ec4af516284b1bc33c ' , // EURC
3130 ADDRESSES . ethereum . WSTETH // wstEth
3231]
3332
3433const owners = [
35- '0x81ad394C0Fa87e99Ca46E1aca093BEe020f203f4' , // Yield Treasury
3634 '0xF3D913De4B23ddB9CfdFAF955BAC5634CbAE95F4' , // longterm Treasury
3735 '0xc32e2a2F03d41768095e67b62C9c739f2C2Bc4aA' , // Treasury 1
36+ '0x81ad394C0Fa87e99Ca46E1aca093BEe020f203f4' , // Yield Treasury
3837 '0xe3FD5A2cA538904A9e967CBd9e64518369e5a03f' , // Treasury 2
39- '0xcbf85D44178c01765Ab32Af72D5E291dcd39A06B' , // Treasury 3
38+ '0xcbf85D44178c01765Ab32Af72D5E291dcd39A06B' , // Treasury 3
39+ // '0x28E52d338Aa22Ab3e2331b65291C871B6fd6e517', // LP Holdings
4040]
41+ const lendingMarketGetUserPositionAbi = "function getUserPosition(tuple(address, address,address, address,uint256,uint256,address), address) view returns (uint256 supplyAssets, uint256 supplyShares, uint256 borrowAssets, uint256 borrowShares, uint256 collateralAssets)" ;
42+ const firaLendingMarket = "0xa428723ee8ffd87088c36121d72100b43f11fb6a" ;
43+ const UZRMarketParams = [
44+ "0x73A15FeD60Bf67631dC6cd7Bc5B6e8da8190aCF5" , // loanToken
45+ "0x35D8949372D46B7a3D5A56006AE77B215fc69bC0" , // collateralToken (bUSD0)
46+ "0x30Da78355FcEA04D1fa34AF3c318BE203C6F2145" , // oracle
47+ "0xdfCF197B0B65066183b04B88d50ACDC0C4b01385" , // irm
48+ "880000000000000000" , // lltv
49+ "999900000000000000" , // param6
50+ "0xFE7C47895eDb12a990b311Df33B90Cfea1D44c24" , // Fira UZR vault
51+ ] ;
52+
53+ // Vaults that need to be priced via convertToAssets
54+ const VAULTS = [
55+ "0xBEEf050ecd6a16c4e7bfFbB52Ebba7846C4b8cD4" , // Steakhouse ETH
56+ "0x67ec31a47a4126A66C7bb2fE017308cf5832A4Db" , // usUSDS++
57+ "0x8245FD9Ae99A482dFe76576dd4298f799c041D61" , // uUSCC++
58+ "0xFE7C47895eDb12a990b311Df33B90Cfea1D44c24" , // Fira UZR
59+ "0xd001f0a15d272542687b2677ba627f48a4333b5d" , // e-USD0
60+ ]
61+
62+
63+ // Aave HORIZON V3 addresses (Ethereum mainnet)
64+ const AAVE_HORIZON_POOL = "0xAe05Cd22df81871bc7cC2a04BeCfb516bFe332C8" ; // Aave Horizon Pool
65+ const aaveUserReserveDataAbi = "function getUserAccountData(address user) view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)" ;
66+
67+
4168
42- module . exports = treasuryExports ( {
69+ const base = treasuryExports ( {
4370 ethereum : {
4471 tokens,
4572 owners,
4673 ownTokens : [ "0x06B964d96f5dCF7Eae9d7C559B09EDCe244d4B8E" , "0xC4441c2BE5d8fA8126822B9929CA0b81Ea0DE38E" ] , // USUALX and USUAL
74+ blacklistedTokens : [
75+ "0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c" , // aEthUSDC
76+ "0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8" , // aEthWETH
77+ "0x23878914efe38d27c4d67ab83ed1b93a74d4086a" // aEthUSDT
78+ ] ,
79+ resolveUniV3 : true ,
80+ resolveLP : true ,
81+ fetchCoValentTokens : true ,
4782 }
48- } )
83+ } ) ;
84+ const baseTvl = base . ethereum . tvl
85+
86+
87+ base . ethereum . tvl = async ( api ) => {
88+ // 1. Run existing treasury logic (standard ERC20 + LPs + UniV3)
89+ await baseTvl ( api )
90+
91+ // 2. Add Fira position
92+ let calls = [ ]
93+ owners . forEach ( owner => {
94+ calls . push ( { target : firaLendingMarket , params : [ UZRMarketParams , owner ] } )
95+ } )
96+ // add collateral and subtract borrowed amount
97+ const positions = await api . multiCall ( { abi : lendingMarketGetUserPositionAbi , calls : calls } )
98+ positions . forEach ( position => {
99+ api . add ( bUSD0 , position . collateralAssets )
100+ api . add ( ADDRESSES . ethereum . USD0 , - BigInt ( position . borrowAssets ) )
101+ } )
102+
103+
104+ // 3. Handle unpriced vaults (Morpho/ERC4626)
105+ // Step A: Get balances of vault tokens across all owners
106+ calls = [ ]
107+ owners . forEach ( owner => {
108+ VAULTS . forEach ( vault => {
109+ calls . push ( { target : vault , params : owner } )
110+ } )
111+ } )
112+ const vaultBalances = await api . multiCall ( { abi : 'erc20:balanceOf' , calls, permitFailure : true } )
113+ const vaultAssets = await api . multiCall ( { abi : 'function asset() view returns (address)' , calls : VAULTS . map ( vault => ( { target : vault } ) ) , permitFailure : true } )
114+ // it needs to be an object with the vault as the key and the asset as the value
115+ const vaultToAsset = Object . fromEntries ( vaultAssets . map ( ( asset , i ) => [ VAULTS [ i ] , asset ] ) )
116+ // add vaultAssets to calls
117+ calls . forEach ( ( call , i ) => {
118+ call . asset = vaultToAsset [ call . target ]
119+ } )
120+
121+ // Step B: Filter for non-zero balances to query convertToAssets
122+ const activeVaultCalls = [ ]
123+ vaultBalances . forEach ( ( bal , i ) => {
124+ if ( bal > 0 ) {
125+ activeVaultCalls . push ( {
126+ target : calls [ i ] . target ,
127+ params : bal , // convertToAssets takes the share amount as input
128+ asset : calls [ i ] . asset
129+ } )
130+ }
131+ } )
132+ // Step C: Convert shares to assets (ETH)
133+ if ( activeVaultCalls . length > 0 ) {
134+ const underlyingAssets = await api . multiCall ( {
135+ abi : 'function convertToAssets(uint256) view returns (uint256)' ,
136+ calls : activeVaultCalls ,
137+ permitFailure : true
138+ } )
139+ underlyingAssets . forEach ( ( amount , i ) => {
140+ const asset = activeVaultCalls [ i ] . asset
141+ if ( amount != null && asset != null && amount > 0 ) api . add ( asset , amount )
142+ } )
143+ }
144+
145+ // 4. Add Aave position
146+ calls = [ ]
147+ owners . forEach ( owner => {
148+ calls . push ( { target : AAVE_HORIZON_POOL , params : owner } )
149+ } )
150+
151+ // Get all Aave positions
152+ const aavePositions = await api . multiCall ( { abi : aaveUserReserveDataAbi , calls : calls , permitFailure : true } )
153+
154+ // Process positions: add supplied assets, subtract borrowed assets
155+ // NOTE: Aave returns values in USD base currency with 8 decimals
156+ // Convert from 8 decimals to actual USD value and add directly
157+ aavePositions . forEach ( ( position ) => {
158+ if ( ! position ) return
159+ const supplied = BigInt ( position . totalCollateralBase )
160+ const borrowed = BigInt ( position . totalDebtBase )
161+
162+ if ( supplied > 0 ) {
163+ // Convert from 8 decimals to USD value
164+ api . addUSDValue ( Number ( supplied ) / 1e8 )
165+ }
166+ if ( borrowed > 0 ) {
167+ api . addUSDValue ( - Number ( borrowed ) / 1e8 )
168+ }
169+ } )
170+ }
171+
172+ module . exports = base ;
0 commit comments