44from typing import Optional , Union
55
66from .resources .abi_reference import *
7- from .util import ContractInstanceFunc , cov_from
7+ from .util import ContractInstanceFunc , cov_from , get_token_info_from_ref
88from .spell import SpellClient , PangolinV2Client , TraderJoeV1Client
99from .oracle import get_token_price
1010
@@ -123,18 +123,17 @@ def get_rewards_value(self) -> tuple[float, float, str, str]:
123123 :return:
124124 - reward_amount (float) (in the native reward token)
125125 - reward_value (float) (in USD)
126- - reward_token_address (address str)
126+ - reward_token_address (str)
127127 - reward_token_symbol (str)
128128 """
129+ if self .dex != "Pangolin V2" :
130+ raise NotImplementedError ("This feature is currently only available for positions on the Pangolin V2 DEX" )
131+
129132 owner , coll_token , coll_id , collateral_size = self .get_position_info ()
130- print ("Untouched Collateral Size:" , collateral_size )
131133
132134 pool_info = self .platform .get_pool_info (coll_id )
133- if self .dex == "Pangolin V2" :
134- entryRewardPerShare = pool_info ['entryRewardPerShare' ] / 1e18
135- accRewardPerShare = pool_info ['accRewardPerShare' ] / 1e18
136- else :
137- raise NotImplementedError ("Currently this feature is only available for positions on the Pangolin V2 DEX" )
135+ entryRewardPerShare = pool_info ['entryRewardPerShare' ] / 1e18
136+ accRewardPerShare = pool_info ['accRewardPerShare' ] / 1e18
138137
139138 if accRewardPerShare >= entryRewardPerShare :
140139 reward_amount = collateral_size * (accRewardPerShare - entryRewardPerShare ) / 1e12
@@ -155,10 +154,130 @@ def get_debt_ratio(self) -> float:
155154
156155 return borrow_credit / collateral_credit
157156
158- def get_position_value (self ) -> tuple :
159- """Returns the value of the position in USD and AVAX"""
160- raise NotImplementedError
161-
157+ def get_position_value (self ):
158+ """
159+ Get equity, debt, and total position value in AVAX and USD.
160+
161+ :return: (dict)
162+ - equity_avax (float)
163+ - equity_usd (float)
164+ - debt_avax (float)
165+ - debt_usd (float)
166+ - position_avax (float)
167+ - position_usd (float)
168+ """
169+ # Get pool info & underlying token metadata
170+ pool_info = self .get_pool_info ()
171+ underlying_token_data = [get_token_info_from_ref (token ) for token in self .get_pool_info ()['tokens' ]]
172+
173+ # Get AVAX price once since operation is heavily reliant on this value
174+ avax_price = get_token_price ("AVAX" )
175+
176+ # Get token pair liquidity pool data:
177+ pool_instance = self .platform .get_lp_contract (pool_info ['lpTokenAddress' ])
178+ collateral_size = self .get_position_info ()[- 1 ]
179+ r0 , r1 , last_block_time = pool_instance .functions .getReserves ().call ()
180+ supply = pool_instance .functions .totalSupply ().call ()
181+
182+ # Process values by token to get full totals:
183+ debt_value_usd = 0
184+ debt_value_avax = 0
185+ position_value_usd = 0
186+ position_value_avax = 0
187+ for i , token_reserve_amt in enumerate ([r0 , r1 ]):
188+ token_price_usd = get_token_price (underlying_token_data [i ]["symbol" ])
189+ precision = int (underlying_token_data [i ]['precision' ])
190+
191+ owned_reserve_amt = (token_reserve_amt * collateral_size // supply ) / 10 ** precision
192+ owned_reserve_amt_usd = owned_reserve_amt * token_price_usd
193+ # print(f"{underlying_token_data[i]['symbol']} owned_reserve_amt_usd:", owned_reserve_amt_usd)
194+
195+ # Get & calculate token debt for underlying token:
196+ borrow_bal = self .homora_bank .functions .\
197+ borrowBalanceCurrent (self .pos_id , Web3 .toChecksumAddress (underlying_token_data [i ]['address' ])).call ()
198+ token_debt = borrow_bal / 10 ** precision
199+ token_debt_usd = token_debt * token_price_usd
200+ token_debt_avax = token_debt_usd / avax_price
201+
202+ # Add debt values to total debt valye count
203+ debt_value_usd += token_debt_usd
204+ debt_value_avax += token_debt_avax
205+
206+ # Add owned reserve values to total position value count
207+ position_value_usd += owned_reserve_amt_usd
208+ position_value_avax += owned_reserve_amt_usd * (1 / avax_price )
209+
210+ # Derive equity values from position and debt:
211+ total_equity_avax = position_value_avax - debt_value_avax
212+ total_equity_usd = position_value_usd - debt_value_usd
213+
214+ return {"equity_avax" : total_equity_avax , "equity_usd" : total_equity_usd ,
215+ "debt_avax" : debt_value_avax , "debt_usd" : debt_value_usd ,
216+ "position_avax" : position_value_avax , "position_usd" : position_value_usd }
217+
218+ # Deprecated but left temporarily for backup and reference:
219+ # def get_position_value(self):
220+ # """
221+ # Get equity value, debt value, and total position value in AVAX and USD.
222+ #
223+ # :return: (dict)
224+ # - equity_avax (float)
225+ # - equity_usd (float)
226+ # - debt_avax (float)
227+ # - debt_usd (float)
228+ # - position_avax (float)
229+ # - position_usd (float)
230+ # """
231+ # pool_info = self.get_pool_info()
232+ # underlying_token_data = [get_token_info_from_ref(token) for token in self.get_pool_info()['tokens']]
233+ # lp_address = pool_info['lpTokenAddress']
234+ # avax_price = get_token_price("AVAX")
235+ #
236+ # pool_instance = self.platform.get_lp_contract(lp_address)
237+ #
238+ # collateral_size = self.get_position_info()[-1]
239+ #
240+ # r0, r1, last_block_time = pool_instance.functions.getReserves().call()
241+ # supply = pool_instance.functions.totalSupply().call()
242+ #
243+ # token0_amount = (r0 * collateral_size / supply) / 10 ** int(underlying_token_data[0]['precision'])
244+ # token1_amount = (r1 * collateral_size / supply) / 10 ** int(underlying_token_data[1]['precision'])
245+
246+ # position_value_usd = token0_amount + (token1_amount * avax_price)
247+ # position_value_avax = position_value_usd * (1 / avax_price)
248+ #
249+ # print("Position Value:", position_value_usd)
250+ #
251+ # # Get debts for underlying tokens:
252+ # total_debt_usd = 0.0
253+ # total_debt_avax = 0.0
254+ # for i, token in enumerate(pool_info['tokens']):
255+ # borrow_bal = self.homora_bank.functions.borrowBalanceCurrent(self.pos_id,
256+ # Web3.toChecksumAddress(token)).call()
257+ # mtd = get_token_info_from_ref(token)
258+ # if mtd is None:
259+ # raise ValueError(f"Could not locate token metadata for {token}")
260+ #
261+ # token_price_usd = get_token_price(mtd['symbol'])
262+ #
263+ # bbal_in_token = borrow_bal / 10 ** int(mtd['precision'])
264+ # bbal_in_usd = bbal_in_token * token_price_usd
265+ # bbal_in_avax = bbal_in_token / get_token_price('AVAX')
266+ #
267+ # total_debt_usd += bbal_in_usd
268+ # total_debt_avax += bbal_in_avax
269+ #
270+ # print(f"{mtd['symbol']} | "
271+ # f"token{i}_amount: {[token0_amount, token1_amount][i]} | "
272+ # f"r{i}: {[r0, r1][i]}")
273+ #
274+ # equity_avax = position_value_avax - total_debt_avax
275+ # equity_usd = position_value_usd - total_debt_usd
276+ #
277+ # return {"equity_avax": equity_avax, "equity_usd": equity_usd,
278+ # "debt_avax": total_debt_avax, "debt_usd": total_debt_usd,
279+ # "position_avax": position_value_avax, "position_usd": position_value_usd}
280+
162281 """ ------------------------------------------ UTILITY ------------------------------------------ """
163282 def get_platform (self , identifier : str ) -> SpellClient :
164283 """Determine what dex the position is on (i.e. Trader Joe, Pangolin V2, Sushiswap, etc)"""
0 commit comments