diff --git a/components/CreditManager/index.tsx b/components/CreditManager/index.tsx index 461f3d64..20121620 100644 --- a/components/CreditManager/index.tsx +++ b/components/CreditManager/index.tsx @@ -128,7 +128,7 @@ const CreditManager = () => { })}
- {(Number(marketsData?.[coin.denom].borrow_rate) * 100).toFixed(1)}% + -{(Number(marketsData?.[coin.denom].borrow_rate) * 100).toFixed(1)}%
))} diff --git a/config/contracts.ts b/config/contracts.ts index 08df9365..8377ae26 100644 --- a/config/contracts.ts +++ b/config/contracts.ts @@ -1,8 +1,13 @@ // https://github.com/mars-protocol/rover/blob/master/scripts/deploy/addresses/osmo-test-4.json -export const contractAddresses = { +export const roverContracts = { accountNft: 'osmo1dravtyd0425fkdmkysc3ns7zud05clf5uhj6qqsnkdtrpkewu73q9f3f02', mockVault: 'osmo1emcckulm2mkx36xeanhsn3z3zjeql6pgd8yf8a5cf03ccvy7a4dqjw9tl7', marsOracleAdapter: 'osmo1cw6pv97g7fmhqykrn0gc9ngrx5tnky75rmlwkzxuqhsk58u0n8asz036g0', swapper: 'osmo1w2552km2u9w4k2gjw4n8drmuz5yxw8x4qzy6dl3da824km5cjlys00x3qp', creditManager: 'osmo18dt5y0ecyd5qg8nqwzrgxuljfejglyh2fjd984s8cy7fcx8mxh9qfl3hwq', } + +export const contractAddresses = { + ...roverContracts, + redBank: 'osmo1w5rqrdhut890jplmsqnr8gj3uf0wq6lj5rfdnhrtl63lpf6e7v6qalrhhn', +} diff --git a/hooks/useBorrowFunds.tsx b/hooks/useBorrowFunds.tsx index e873e9d2..d91d5d98 100644 --- a/hooks/useBorrowFunds.tsx +++ b/hooks/useBorrowFunds.tsx @@ -10,6 +10,7 @@ import { contractAddresses } from 'config/contracts' import { hardcodedFee } from 'utils/contants' import useCreditManagerStore from 'stores/useCreditManagerStore' import { queryKeys } from 'types/query-keys-factory' +import { getTokenDecimals } from 'utils/tokens' const useBorrowFunds = ( amount: string | number, @@ -36,6 +37,8 @@ const useBorrowFunds = ( }, [address]) const executeMsg = useMemo(() => { + const tokenDecimals = getTokenDecimals(denom) + if (!withdraw) { return { update_credit_account: { @@ -45,7 +48,7 @@ const useBorrowFunds = ( borrow: { denom: denom, amount: BigNumber(amount) - .times(10 ** 6) + .times(10 ** tokenDecimals) .toString(), }, }, @@ -62,7 +65,7 @@ const useBorrowFunds = ( borrow: { denom: denom, amount: BigNumber(amount) - .times(10 ** 6) + .times(10 ** tokenDecimals) .toString(), }, }, @@ -70,14 +73,14 @@ const useBorrowFunds = ( withdraw: { denom: denom, amount: BigNumber(amount) - .times(10 ** 6) + .times(10 ** tokenDecimals) .toString(), }, }, ], }, } - }, [amount, denom, withdraw, selectedAccount]) + }, [withdraw, selectedAccount, denom, amount]) return useMutation( async () => @@ -90,6 +93,7 @@ const useBorrowFunds = ( { onSettled: () => { queryClient.invalidateQueries(queryKeys.creditAccountsPositions(selectedAccount ?? '')) + queryClient.invalidateQueries(queryKeys.redbankBalances()) // if withdrawing to wallet, need to explicility invalidate balances queries if (withdraw) { diff --git a/hooks/useCalculateMaxBorrowAmount.tsx b/hooks/useCalculateMaxBorrowAmount.tsx index 6d3b0c4c..3e89abf3 100644 --- a/hooks/useCalculateMaxBorrowAmount.tsx +++ b/hooks/useCalculateMaxBorrowAmount.tsx @@ -6,6 +6,7 @@ import { getTokenDecimals } from 'utils/tokens' import useCreditAccountPositions from './useCreditAccountPositions' import useMarkets from './useMarkets' import useTokenPrices from './useTokenPrices' +import useRedbankBalances from './useRedbankBalances' const useCalculateMaxBorrowAmount = (denom: string, isUnderCollateralized: boolean) => { const selectedAccount = useCreditManagerStore((s) => s.selectedAccount) @@ -13,9 +14,10 @@ const useCalculateMaxBorrowAmount = (denom: string, isUnderCollateralized: boole const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '') const { data: marketsData } = useMarkets() const { data: tokenPrices } = useTokenPrices() + const { data: redbankBalances } = useRedbankBalances() return useMemo(() => { - if (!marketsData || !tokenPrices || !positionsData) return 0 + if (!marketsData || !tokenPrices || !positionsData || !redbankBalances) return 0 const getTokenTotalUSDValue = (amount: string, denom: string) => { // early return if prices are not fetched yet @@ -27,6 +29,7 @@ const useCalculateMaxBorrowAmount = (denom: string, isUnderCollateralized: boole .toNumber() } + // max ltv adjusted collateral const totalWeightedPositions = positionsData?.coins.reduce((acc, coin) => { const tokenWeightedValue = BigNumber(getTokenTotalUSDValue(coin.amount, coin.denom)).times( Number(marketsData[coin.denom].max_loan_to_value) @@ -35,6 +38,7 @@ const useCalculateMaxBorrowAmount = (denom: string, isUnderCollateralized: boole return tokenWeightedValue.plus(acc).toNumber() }, 0) + // total debt value const totalLiabilitiesValue = positionsData?.debts.reduce((acc, coin) => { const tokenUSDValue = BigNumber(getTokenTotalUSDValue(coin.amount, coin.denom)) @@ -44,20 +48,31 @@ const useCalculateMaxBorrowAmount = (denom: string, isUnderCollateralized: boole const borrowTokenPrice = tokenPrices[denom] const tokenDecimals = getTokenDecimals(denom) + let maxValue if (isUnderCollateralized) { - return BigNumber(totalLiabilitiesValue) + // MAX TO CREDIT ACCOUNT + maxValue = BigNumber(totalLiabilitiesValue) .minus(totalWeightedPositions) .div(borrowTokenPrice * Number(marketsData[denom].max_loan_to_value) - borrowTokenPrice) .decimalPlaces(tokenDecimals) .toNumber() } else { - return BigNumber(totalWeightedPositions) + // MAX TO WALLET + maxValue = BigNumber(totalWeightedPositions) .minus(totalLiabilitiesValue) .div(borrowTokenPrice) .decimalPlaces(tokenDecimals) .toNumber() } - }, [denom, isUnderCollateralized, marketsData, positionsData, tokenPrices]) + + const marketLiquidity = BigNumber(redbankBalances?.[denom] ?? '') + .div(10 ** getTokenDecimals(denom)) + .toNumber() + + if (marketLiquidity < maxValue) return marketLiquidity + + return maxValue > 0 ? maxValue : 0 + }, [denom, isUnderCollateralized, marketsData, positionsData, redbankBalances, tokenPrices]) } export default useCalculateMaxBorrowAmount diff --git a/hooks/useMarkets.tsx b/hooks/useMarkets.tsx index 164c1a8b..bf42ecde 100644 --- a/hooks/useMarkets.tsx +++ b/hooks/useMarkets.tsx @@ -38,8 +38,8 @@ const useMarkets = () => { wasm: { uosmo: { denom: 'uosmo', - max_loan_to_value: '0.65', - liquidation_threshold: '0.7', + max_loan_to_value: '0.55', + liquidation_threshold: '0.65', liquidation_bonus: '0.1', reserve_factor: '0.2', interest_rate_model: { @@ -61,8 +61,8 @@ const useMarkets = () => { }, 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2': { denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2', - max_loan_to_value: '0.77', - liquidation_threshold: '0.8', + max_loan_to_value: '0.65', + liquidation_threshold: '0.7', liquidation_bonus: '0.1', reserve_factor: '0.2', interest_rate_model: { diff --git a/hooks/useRedbankBalances.tsx b/hooks/useRedbankBalances.tsx new file mode 100644 index 00000000..4fb96a58 --- /dev/null +++ b/hooks/useRedbankBalances.tsx @@ -0,0 +1,59 @@ +import { useMemo } from 'react' +import { useQuery } from '@tanstack/react-query' +import { Coin } from '@cosmjs/stargate' + +import { contractAddresses } from 'config/contracts' +import { queryKeys } from 'types/query-keys-factory' +import { chain } from 'utils/chains' + +interface Result { + data: { + bank: { + balance: Coin[] + } + } +} + +const fetchBalances = () => { + return fetch(chain.hive, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query: ` + query RedbankBalances { + bank { + balance( + address: "${contractAddresses.redBank}" + ) { + amount + denom + } + } + } + `, + }), + }).then((res) => res.json()) +} + +const useRedbankBalances = () => { + const result = useQuery(queryKeys.redbankBalances(), fetchBalances) + + return { + ...result, + data: useMemo(() => { + if (!result.data) return + + return result.data?.data.bank.balance.reduce( + (acc, coin) => ({ + ...acc, + [coin.denom]: coin.amount, + }), + {} + ) as { [key in string]: string } + }, [result.data]), + } +} + +export default useRedbankBalances diff --git a/hooks/useRepayFunds.tsx b/hooks/useRepayFunds.tsx index 6ffee088..13e59b89 100644 --- a/hooks/useRepayFunds.tsx +++ b/hooks/useRepayFunds.tsx @@ -10,6 +10,7 @@ import { contractAddresses } from 'config/contracts' import { hardcodedFee } from 'utils/contants' import useCreditManagerStore from 'stores/useCreditManagerStore' import { queryKeys } from 'types/query-keys-factory' +import { getTokenDecimals } from 'utils/tokens' const useRepayFunds = ( amount: string | number, @@ -34,23 +35,33 @@ const useRepayFunds = ( })() }, [address]) + const tokenDecimals = getTokenDecimals(denom) + const executeMsg = useMemo(() => { return { update_credit_account: { account_id: selectedAccount, actions: [ + { + deposit: { + denom: denom, + amount: BigNumber(amount) + .times(10 ** tokenDecimals) + .toString(), + }, + }, { repay: { denom: denom, amount: BigNumber(amount) - .times(10 ** 6) + .times(10 ** tokenDecimals) .toString(), }, }, ], }, } - }, [amount, denom, selectedAccount]) + }, [amount, denom, selectedAccount, tokenDecimals]) return useMutation( async () => @@ -58,13 +69,23 @@ const useRepayFunds = ( address, contractAddresses.creditManager, executeMsg, - hardcodedFee + hardcodedFee, + undefined, + [ + { + denom, + amount: BigNumber(amount) + .times(10 ** tokenDecimals) + .toString(), + }, + ] ), { onSettled: () => { queryClient.invalidateQueries(queryKeys.creditAccountsPositions(selectedAccount ?? '')) queryClient.invalidateQueries(queryKeys.tokenBalance(address, denom)) queryClient.invalidateQueries(queryKeys.allBalances(address)) + queryClient.invalidateQueries(queryKeys.redbankBalances()) }, onError: (err: Error) => { toast.error(err.message) diff --git a/hooks/useTokenPrices.tsx b/hooks/useTokenPrices.tsx index 71b5b79c..e4f56b49 100644 --- a/hooks/useTokenPrices.tsx +++ b/hooks/useTokenPrices.tsx @@ -4,8 +4,8 @@ const useTokenPrices = () => { return useQuery<{ [key in string]: number }>( ['tokenPrices'], () => ({ - uosmo: 1.1, - 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2': 11, + uosmo: 1, + 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2': 1.5, }), { staleTime: Infinity, diff --git a/pages/borrow.tsx b/pages/borrow.tsx index 66dae478..0b157a38 100644 --- a/pages/borrow.tsx +++ b/pages/borrow.tsx @@ -10,6 +10,7 @@ import useMarkets from 'hooks/useMarkets' import useTokenPrices from 'hooks/useTokenPrices' import { BorrowFunds, RepayFunds } from 'components/Borrow' import BorrowTable from 'components/Borrow/BorrowTable' +import useRedbankBalances from 'hooks/useRedbankBalances' type ModuleState = | { @@ -35,6 +36,7 @@ const Borrow = () => { const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '') const { data: marketsData } = useMarkets() const { data: tokenPrices } = useTokenPrices() + const { data: redbankBalances } = useRedbankBalances() const borrowedAssetsMap = useMemo(() => { let borrowedAssetsMap: Map = new Map() @@ -54,7 +56,7 @@ const Borrow = () => { .map((denom) => { const { symbol, chain, icon } = getTokenInfo(denom) const borrowRate = Number(marketsData?.[denom].borrow_rate) || 0 - const marketLiquidity = BigNumber(marketsData?.[denom].deposit_cap ?? '') + const marketLiquidity = BigNumber(redbankBalances?.[denom] ?? '') .div(10 ** getTokenDecimals(denom)) .toNumber() @@ -84,7 +86,7 @@ const Borrow = () => { .map((denom) => { const { symbol, chain, icon } = getTokenInfo(denom) const borrowRate = Number(marketsData?.[denom].borrow_rate) || 0 - const marketLiquidity = BigNumber(marketsData?.[denom].deposit_cap ?? '') + const marketLiquidity = BigNumber(redbankBalances?.[denom] ?? '') .div(10 ** getTokenDecimals(denom)) .toNumber() @@ -101,7 +103,7 @@ const Borrow = () => { return rowData }) ?? [], } - }, [allowedCoinsData, borrowedAssetsMap, marketsData, tokenPrices]) + }, [allowedCoinsData, borrowedAssetsMap, marketsData, redbankBalances, tokenPrices]) const handleBorrowClick = (denom: string) => { setModuleState({ show: 'borrow', data: { tokenDenom: denom } }) diff --git a/types/query-keys-factory.ts b/types/query-keys-factory.ts index 9494ab23..523ad14a 100644 --- a/types/query-keys-factory.ts +++ b/types/query-keys-factory.ts @@ -1,6 +1,7 @@ export const queryKeys = { allBalances: (address: string) => ['allBalances', address], allowedCoins: () => ['allowedCoins'], + redbankBalances: () => ['redbankBalances'], creditAccounts: (address: string) => ['creditAccounts', address], creditAccountsPositions: (accountId: string) => ['creditAccountPositions', accountId], tokenBalance: (address: string, denom: string) => ['tokenBalance', address, denom], diff --git a/utils/chains.ts b/utils/chains.ts index 001554e5..c042274a 100644 --- a/utils/chains.ts +++ b/utils/chains.ts @@ -42,6 +42,7 @@ export const chainsInfo = { chainId: 'osmo-test-4', rpc: 'https://osmosis-delphi-testnet-1.simply-vc.com.mt/XF32UOOU55CX/osmosis-rpc', rest: 'https://osmosis-delphi-testnet-1.simply-vc.com.mt/XF32UOOU55CX/osmosis-lcd', + hive: 'https://osmosis-delphi-testnet-1.simply-vc.com.mt/XF32UOOU55CX/osmosis-hive/graphql', stakeCurrency: { coinDenom: 'OSMO', coinMinimalDenom: 'uosmo',