Skip to content

Commit

Permalink
Merge pull request #28 from Laina-Protocol/feat/get-balance-and-ui-ba…
Browse files Browse the repository at this point in the history
…lances

feat: add lending pool balances to UI
  • Loading branch information
Teolhyn authored Sep 10, 2024
2 parents 9dad934 + 95af5a0 commit 62dbec6
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 8 deletions.
13 changes: 12 additions & 1 deletion contracts/loan_manager/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)]
Expand Down Expand Up @@ -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)]
Expand Down
4 changes: 2 additions & 2 deletions contracts/loan_pool/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions contracts/loan_pool/src/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 1 addition & 1 deletion src/pages/_borrow/BorrowableAssetCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
93 changes: 89 additions & 4 deletions src/pages/_lend/LendableAssetCard.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -11,6 +13,88 @@ export const LendableAssetCard = ({ currency }: LendableAssetCardProps) => {
const { icon, name, symbol, loanPoolContract } = currency;
const { wallet, signTransaction } = useWallet();

const [totalSupplied, setTotalSupplied] = useState<bigint | null>(null);
const [totalSuppliedPrice, setTotalSuppliedPrice] = useState<bigint | null>(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!');
Expand All @@ -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 {
Expand All @@ -28,6 +112,7 @@ export const LendableAssetCard = ({ currency }: LendableAssetCardProps) => {
} catch (err) {
alert(`Error depositing: ${JSON.stringify(err)}`);
}
fetchAvailableContractBalance();
};

return (
Expand All @@ -41,13 +126,13 @@ export const LendableAssetCard = ({ currency }: LendableAssetCardProps) => {

<div className="w-64">
<p className="text-grey">Total Supplied</p>
<p className="text-xl font-bold leading-6">5.82M</p>
<p>$5.82M</p>
<p className="text-xl font-bold leading-6">{formatSuppliedAmount(totalSupplied)}</p>
<p>{formatSuppliedAmountPrice(totalSuppliedPrice)}</p>
</div>

<div className="w-64">
<p className="text-grey">Supply APY</p>
<p className="text-xl font-bold leading-6">12.34%</p>
<p className="text-xl font-bold leading-6">{supplyAPY}</p>
</div>

{wallet && <Button onClick={handleDepositClick}>Deposit</Button>}
Expand Down

0 comments on commit 62dbec6

Please sign in to comment.