diff --git a/contracts/loan_manager/src/contract.rs b/contracts/loan_manager/src/contract.rs index 0b7ec88d..ef22dcca 100644 --- a/contracts/loan_manager/src/contract.rs +++ b/contracts/loan_manager/src/contract.rs @@ -15,7 +15,7 @@ mod loan_pool { // This is the real address of the Reflector Oracle in testnet. // We use the same adress to mock it for testing. -const REFLECTOR_ADDRESS: &str = "CBKZFI26PDCZUJ5HYYKVB5BWCNYUSNA5LVL4R2JTRVSOB4XEP7Y34OPN"; +const REFLECTOR_ADDRESS: &str = "CCYOZJCOPG34LLQQ7N24YXBM7LL62R7ONMZ3G6WZAAYPB5OYKOMJRN63"; #[allow(dead_code)] pub trait LoansTrait { @@ -36,6 +36,7 @@ pub trait LoansTrait { token_collateral_amount: i128, ) -> i128; fn get_loan(e: &Env, addr: Address) -> Loan; + fn get_price(e: &Env, token: Symbol) -> i128; } #[allow(dead_code)] @@ -210,6 +211,16 @@ impl LoansTrait for LoansContract { panic!() // TODO: It should be panic_with_error or something and give out detailed error. } } + + fn get_price(e: &Env, token: Symbol) -> i128 { + let reflector_address = Address::from_string(&String::from_str(e, REFLECTOR_ADDRESS)); + let reflector_contract = oracle::Client::new(e, &reflector_address); + + let asset = Asset::Other(token); + + let asset_pricedata = reflector_contract.lastprice(&asset).unwrap(); + asset_pricedata.price + } } #[cfg(test)] diff --git a/contracts/loan_pool/src/contract.rs b/contracts/loan_pool/src/contract.rs index ef63a7e2..1c470bb9 100644 --- a/contracts/loan_pool/src/contract.rs +++ b/contracts/loan_pool/src/contract.rs @@ -14,7 +14,7 @@ contractmeta!( ); // TODO: get this dynamically when creating the contract. -const LOAN_MANAGER_ADDRESS: &str = "CDIK5MXMF5F3TRW7XHPMUXGHDKBH2SESVDSG2RFGOP2GHXOPCDHTC7VO"; +const LOAN_MANAGER_ADDRESS: &str = "CBCAJ6EHX4NEDXLLIZEVOTNMXOBMOGJMMX6X7ARVNTUGJX5DTXAGZM3R"; #[allow(dead_code)] pub trait LoanPoolTrait { @@ -64,7 +64,7 @@ impl LoanPoolTrait for LoanPoolContract { // TODO: these need to be replaced with increase rather than write so that it wont overwrite the values. pool::write_available_balance(&e, amount); pool::write_total_shares(&e, amount); - pool::write_total_balance(&e, amount); + pool::increase_total_balance(&e, amount); // Increase users position in pool as they deposit // as this is deposit amount is added to receivables and diff --git a/contracts/loan_pool/src/pool.rs b/contracts/loan_pool/src/pool.rs index c919ee7f..9b5a65ee 100644 --- a/contracts/loan_pool/src/pool.rs +++ b/contracts/loan_pool/src/pool.rs @@ -54,3 +54,9 @@ pub fn read_available_balance(e: &Env) -> i128 { e.storage().persistent().get(&key).unwrap() } + +pub fn increase_total_balance(e: &Env, amount: i128) { + let current_balance = read_total_balance(e); + + write_total_balance(e, amount + current_balance); +} diff --git a/src/pages/_borrow/BorrowableAssetCard.tsx b/src/pages/_borrow/BorrowableAssetCard.tsx index 9ee7f88f..24558ee2 100644 --- a/src/pages/_borrow/BorrowableAssetCard.tsx +++ b/src/pages/_borrow/BorrowableAssetCard.tsx @@ -5,7 +5,7 @@ import type { Currency } from 'src/currencies'; import { useWallet } from 'src/stellar-wallet'; // Temporary hack to use XLM pool for all loans and collaterals. -const XLM_LOAN_POOL_ID = 'CCME5C2PJFCWGW5O5MCO4O6X3AUJLD6XHVH3ZJHC7SD7XK5OTPJRPHF7'; +const XLM_LOAN_POOL_ID = 'CCRWVENKGBUX7EP273GOUMY542VWRFEEIHUICTTDDG5ESLSDNENCH6AT'; interface BorrowableAssetCardProps { currency: Currency; diff --git a/src/pages/_lend/LendableAssetCard.tsx b/src/pages/_lend/LendableAssetCard.tsx index 94202491..c0e0c0f2 100644 --- a/src/pages/_lend/LendableAssetCard.tsx +++ b/src/pages/_lend/LendableAssetCard.tsx @@ -1,5 +1,7 @@ import { Button } from '@components/Button'; import { Card } from '@components/Card'; +import loanManager from '@contracts/loan_manager'; +import { useCallback, useEffect, useState } from 'react'; import type { Currency } from 'src/currencies'; import { useWallet } from 'src/stellar-wallet'; @@ -11,6 +13,88 @@ export const LendableAssetCard = ({ currency }: LendableAssetCardProps) => { const { icon, name, symbol, loanPoolContract } = currency; const { wallet, signTransaction } = useWallet(); + const [totalSupplied, setTotalSupplied] = useState(null); + const [totalSuppliedPrice, setTotalSuppliedPrice] = useState(null); + const [supplyAPY, setSupplyAPY] = useState('0.00%'); + + const fetchAvailableContractBalance = useCallback(async () => { + if (!loanPoolContract) return; + + try { + const supplied = await loanPoolContract.get_contract_balance(); + const supplied_hi = BigInt(supplied.simulation.result.retval._value._attributes.hi); + const supplied_lo = BigInt(supplied.simulation.result.retval._value._attributes.lo); + const supplied_combined = (supplied_hi << BigInt(64)) + supplied_lo; + + setTotalSupplied(supplied_combined); + // const apy = await loanPoolContract.getSupplyAPY(); + // setSupplyAPY(formatAPY(apy)); + } catch (error) { + console.error('Error fetching contract data:', error); + } + }, [loanPoolContract]); // Dependency on loanPoolContract + + const formatSuppliedAmount = useCallback((amount: bigint | null) => { + if (amount === BigInt(0)) return '0'; + if (!amount) return 'Loading'; + + const ten_k = BigInt(10_000 * 10_000_000); + const one_m = BigInt(1_000_000 * 10_000_000); + switch (true) { + case amount > one_m: + return `${(Number(amount) / (1_000_000 * 10_000_000)).toFixed(2)}M`; + case amount > ten_k: + return `${(Number(amount) / (1_000 * 10_000_000)).toFixed(1)}K`; + default: + return `${(Number(amount) / 10_000_000).toFixed(1)}`; + } + }, []); + + const fetchPriceData = useCallback(async () => { + if (!loanManager) return; + + try { + const currentPrice = await loanManager.get_price({ token: currency.symbol }); + const price_hi = BigInt(currentPrice.simulation.result.retval._value._attributes.hi); + const price_lo = BigInt(currentPrice.simulation.result.retval._value._attributes.lo); + const price_combined = (price_hi << BigInt(64)) + price_lo; + + setTotalSuppliedPrice(price_combined); + } catch (error) { + console.error('Error fetchin price data:', error); + } + }, [currency.symbol]); + + const formatSuppliedAmountPrice = useCallback( + (price: bigint | null) => { + if (totalSupplied === BigInt(0)) return '$0'; + if (!totalSupplied || !price) return 'Loading'; + + const ten_k = BigInt(10_000 * 10_000_000); + const one_m = BigInt(1_000_000 * 10_000_000); + const total_price = ((price / BigInt(10_000_000)) * totalSupplied) / BigInt(10_000_000); + switch (true) { + case total_price > one_m: + return `$${(Number(total_price) / (1_000_000 * 10_000_000)).toFixed(2)}M`; + case total_price > ten_k: + return `$${(Number(total_price) / (1_000 * 10_000_000)).toFixed(1)}K`; + default: + return `$${(Number(total_price) / 10_000_000).toFixed(1)}`; + } + }, + [totalSupplied], + ); + + useEffect(() => { + // Fetch contract data immediately and set an interval to run every 6 seconds + fetchAvailableContractBalance(); + fetchPriceData(); + const intervalId = setInterval(fetchAvailableContractBalance, 6000); + + // Cleanup function to clear the interval on component unmount + return () => clearInterval(intervalId); + }, [fetchAvailableContractBalance, fetchPriceData]); // Now dependent on the memoized function + const handleDepositClick = async () => { if (!wallet) { alert('Please connect your wallet first!'); @@ -19,7 +103,7 @@ export const LendableAssetCard = ({ currency }: LendableAssetCardProps) => { loanPoolContract.options.publicKey = wallet.address; - const amount = BigInt(1000000); + const amount = BigInt(2000000); const tx = await loanPoolContract.deposit({ user: wallet.address, amount }); try { @@ -28,6 +112,7 @@ export const LendableAssetCard = ({ currency }: LendableAssetCardProps) => { } catch (err) { alert(`Error depositing: ${JSON.stringify(err)}`); } + fetchAvailableContractBalance(); }; return ( @@ -41,13 +126,13 @@ export const LendableAssetCard = ({ currency }: LendableAssetCardProps) => {

Total Supplied

-

5.82M

-

$5.82M

+

{formatSuppliedAmount(totalSupplied)}

+

{formatSuppliedAmountPrice(totalSuppliedPrice)}

Supply APY

-

12.34%

+

{supplyAPY}

{wallet && }