APY of two growth rates
This commit is contained in:
parent
f264c31994
commit
4a37c9072f
|
@ -138,11 +138,11 @@ const PositionItem = ({
|
|||
|
||||
console.log('liq price change percentage', liqPriceChangePercentage)
|
||||
|
||||
const { estimatedNetAPY, stakeBankDepositRate } = useBankRates(
|
||||
const { financialMetrics, stakeBankDepositRate } = useBankRates(
|
||||
bank.name,
|
||||
leverage,
|
||||
)
|
||||
const uiRate = bank.name == 'USDC' ? stakeBankDepositRate : estimatedNetAPY
|
||||
const uiRate = bank.name == 'USDC' ? stakeBankDepositRate : financialMetrics.APY
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border-2 border-th-fgd-1 bg-th-bkg-1 p-6">
|
||||
|
@ -188,7 +188,7 @@ const PositionItem = ({
|
|||
<div>
|
||||
<p className="mb-1 text-th-fgd-4">Est. APY</p>
|
||||
<span className="text-xl font-bold text-th-fgd-1">
|
||||
<FormatNumericValue value={uiRate} decimals={2} />%
|
||||
<FormatNumericValue value={Number(uiRate)} decimals={2} />%
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
@ -102,10 +102,8 @@ function StakeForm({ token: selectedToken }: StakeFormProps) {
|
|||
const { group } = useMangoGroup()
|
||||
const groupLoaded = mangoStore((s) => s.groupLoaded)
|
||||
const {
|
||||
financialMetrics,
|
||||
borrowBankBorrowRate,
|
||||
leveragedAPY,
|
||||
estimatedNetAPY,
|
||||
collateralFeeAPY,
|
||||
} = useBankRates(selectedToken, leverage)
|
||||
const leverageMax = useLeverageMax(selectedToken) * 0.9 // Multiplied by 0.975 becuase you cant actually get to the end of the inifinite geometric series?
|
||||
|
||||
|
@ -406,13 +404,13 @@ function StakeForm({ token: selectedToken }: StakeFormProps) {
|
|||
<p className="font-medium">Est. Net APY</p>
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-lg font-bold text-th-success">
|
||||
{estimatedNetAPY >= 0
|
||||
{financialMetrics.APY >= 0
|
||||
? '+'
|
||||
: estimatedNetAPY === 0
|
||||
: financialMetrics.APY === 0
|
||||
? ''
|
||||
: '-'}
|
||||
<FormatNumericValue
|
||||
value={estimatedNetAPY}
|
||||
value={financialMetrics.APY}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
|
@ -426,77 +424,8 @@ function StakeForm({ token: selectedToken }: StakeFormProps) {
|
|||
</div>
|
||||
</Disclosure.Button>
|
||||
<Disclosure.Panel className="space-y-2 rounded-xl rounded-t-none border-2 border-t-0 border-th-bkg-3 px-4 pb-3">
|
||||
<div className="flex justify-between">
|
||||
<p className="text-th-fgd-4">
|
||||
{formatTokenSymbol(selectedToken)} Leveraged APY
|
||||
</p>
|
||||
<span className="font-bold text-th-success">
|
||||
{leveragedAPY > 0.01 ? '+' : ''}
|
||||
<FormatNumericValue
|
||||
value={leveragedAPY}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<p className="text-th-fgd-4">
|
||||
{formatTokenSymbol(selectedToken)} Collateral Fee APY
|
||||
</p>
|
||||
<span
|
||||
className={`font-bold ${
|
||||
collateralFeeAPY > 0.01
|
||||
? 'text-th-error'
|
||||
: 'text-th-bkg-4'
|
||||
}`}
|
||||
>
|
||||
{collateralFeeAPY > 0.01 ? '-' : ''}
|
||||
<FormatNumericValue
|
||||
value={collateralFeeAPY?.toString()}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
{borrowBank ? (
|
||||
<>
|
||||
<div className="flex justify-between">
|
||||
<p className="text-th-fgd-4">{`${borrowBank?.name} Borrow Rate`}</p>
|
||||
<span
|
||||
className={`font-bold ${
|
||||
borrowBankBorrowRate > 0.01
|
||||
? 'text-th-error'
|
||||
: 'text-th-bkg-4'
|
||||
}`}
|
||||
>
|
||||
-
|
||||
<FormatNumericValue
|
||||
value={borrowBankBorrowRate}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<p className="text-th-fgd-4">{`${borrowBank.name} Borrowed`}</p>
|
||||
<span
|
||||
className={`font-bold ${
|
||||
amountToBorrow > 0.001
|
||||
? 'text-th-fgd-1'
|
||||
: 'text-th-bkg-4'
|
||||
}`}
|
||||
>
|
||||
<FormatNumericValue
|
||||
value={amountToBorrow}
|
||||
decimals={3}
|
||||
/>
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{' '}
|
||||
{borrowBank.name}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
|
||||
<div className="flex justify-between">
|
||||
<p className="text-th-fgd-4">{`${stakeBank.name} Position`}</p>
|
||||
<span
|
||||
className={`font-bold ${
|
||||
|
@ -528,6 +457,76 @@ function StakeForm({ token: selectedToken }: StakeFormProps) {
|
|||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<p className="text-th-fgd-4">{`${borrowBank.name} Borrowed`}</p>
|
||||
<span
|
||||
className={`font-bold ${
|
||||
amountToBorrow > 0.001
|
||||
? 'text-th-fgd-1'
|
||||
: 'text-th-bkg-4'
|
||||
}`}
|
||||
>
|
||||
<FormatNumericValue
|
||||
value={amountToBorrow}
|
||||
decimals={3}
|
||||
/>
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{' '}
|
||||
{borrowBank.name}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<p className="text-th-fgd-4">
|
||||
{formatTokenSymbol(selectedToken)} Returns APY
|
||||
</p>
|
||||
<span className="font-bold text-th-success">
|
||||
{financialMetrics.collectedReturnsAPY > 0.01 ? '+' : ''}
|
||||
<FormatNumericValue
|
||||
value={financialMetrics.collectedReturnsAPY}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<p className="text-th-fgd-4">
|
||||
{formatTokenSymbol(selectedToken)} Collateral Fee APY
|
||||
</p>
|
||||
<span
|
||||
className={`font-bold ${
|
||||
financialMetrics?.collateralFeeAPY > 0.01
|
||||
? 'text-th-error'
|
||||
: 'text-th-bkg-4'
|
||||
}`}
|
||||
>
|
||||
{financialMetrics?.collateralFeeAPY > 0.01 ? '-' : ''}
|
||||
<FormatNumericValue
|
||||
value={financialMetrics?.collateralFeeAPY?.toString()}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
{borrowBank ? (
|
||||
<>
|
||||
<div className="flex justify-between">
|
||||
<p className="text-th-fgd-4">{`${borrowBank?.name} Borrow APY Rate`}</p>
|
||||
<span
|
||||
className={`font-bold ${
|
||||
borrowBankBorrowRate > 0.01
|
||||
? 'text-th-error'
|
||||
: 'text-th-bkg-4'
|
||||
}`}
|
||||
>
|
||||
-
|
||||
<FormatNumericValue
|
||||
value={financialMetrics.borrowsAPY}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<p className="text-th-fgd-4">{`Liquidation Price`}</p>
|
||||
<span
|
||||
|
|
|
@ -14,12 +14,12 @@ const TokenButton = ({
|
|||
}) => {
|
||||
const leverage = useLeverageMax(tokenName) * 0.9
|
||||
|
||||
const { stakeBankDepositRate, estimatedNetAPY } = useBankRates(
|
||||
const { stakeBankDepositRate, financialMetrics } = useBankRates(
|
||||
tokenName,
|
||||
leverage,
|
||||
)
|
||||
|
||||
const { estimatedNetAPY: estimatedNetAPYFor1xLev } = useBankRates(
|
||||
const { financialMetrics: estimatedNetAPYFor1xLev } = useBankRates(
|
||||
tokenName,
|
||||
1,
|
||||
)
|
||||
|
@ -27,7 +27,7 @@ const TokenButton = ({
|
|||
const UiRate =
|
||||
tokenName === 'USDC'
|
||||
? stakeBankDepositRate
|
||||
: Math.max(estimatedNetAPYFor1xLev, estimatedNetAPY)
|
||||
: Math.max(estimatedNetAPYFor1xLev.APY, financialMetrics.APY)
|
||||
|
||||
return (
|
||||
<button
|
||||
|
|
|
@ -22,56 +22,77 @@ export default function useBankRates(selectedToken: string, leverage: number) {
|
|||
}, [group])
|
||||
|
||||
const stakeBankDepositRate = useMemo(() => {
|
||||
return stakeBank ? stakeBank.getDepositRateUi() : 0
|
||||
return stakeBank ? stakeBank.getDepositRate() : 0
|
||||
}, [stakeBank])
|
||||
|
||||
const borrowBankBorrowRate = useMemo(() => {
|
||||
return borrowBank ? borrowBank.getBorrowRateUi() : 0
|
||||
return borrowBank ? Number(borrowBank.getBorrowRate()) : 0
|
||||
}, [borrowBank])
|
||||
|
||||
const borrowBankStakeRate = useMemo(() => {
|
||||
return stakeRates ? stakeRates[selectedToken.toLowerCase()] * 100 : 0
|
||||
const jlpStakeRateAPY = useMemo(() => {
|
||||
return stakeRates ? stakeRates[selectedToken.toLowerCase()] : 0
|
||||
}, [stakeRates, selectedToken])
|
||||
|
||||
const leveragedAPY = useMemo(() => {
|
||||
return borrowBankStakeRate ? borrowBankStakeRate * leverage : 0
|
||||
}, [borrowBankStakeRate, leverage])
|
||||
const financialMetrics = useMemo(() => {
|
||||
let borrowMultiplier = leverage - 1;
|
||||
let depositMultiplier = leverage;
|
||||
|
||||
let collectedCollateralFees = 0
|
||||
let collectedReturns = 0
|
||||
|
||||
const collateralFeeAPY = useMemo(() => {
|
||||
if (!stakeBank) return 0
|
||||
const borrowedAmount = leverage - 1
|
||||
const assetsCovered = borrowedAmount / Number(stakeBank?.maintAssetWeight)
|
||||
return stakeBank?.collateralFeePerDay * 365 * 100 * assetsCovered
|
||||
}, [stakeBank, leverage])
|
||||
const maintAssetWeight = Number(stakeBank?.maintAssetWeight);
|
||||
const collateralFeePerDay = Number(stakeBank?.collateralFeePerDay);
|
||||
const borrowFeeRatePerDay = Number(borrowBankBorrowRate) / 365;
|
||||
const jlpStakeRatePerDay = (jlpStakeRateAPY ** (1 / 365)) - 1;
|
||||
|
||||
const estimatedNetAPY = useMemo(() => {
|
||||
return (
|
||||
borrowBankStakeRate * leverage - borrowBankBorrowRate * (leverage - 1) - collateralFeeAPY
|
||||
)
|
||||
}, [borrowBankStakeRate, leverage, borrowBankBorrowRate, collateralFeeAPY])
|
||||
for (let day = 1; day <= 365; day++) {
|
||||
|
||||
// Collateral Fee Multiplier
|
||||
const collateralFeeMultiplier = borrowMultiplier / (depositMultiplier * maintAssetWeight);
|
||||
const collateralFeeRate = collateralFeeMultiplier * collateralFeePerDay;
|
||||
|
||||
// useEffect(() => {
|
||||
// set((s) => {
|
||||
// s.estimatedMaxAPY.current =
|
||||
// borrowBankStakeRate * leverageMax -
|
||||
// borrowBankBorrowRate * (leverageMax - 1)
|
||||
// })
|
||||
// }, [borrowBankStakeRate, borrowBankBorrowRate, leverageMax])
|
||||
// USDC Liabilities Multiplier
|
||||
borrowMultiplier *= (1 + borrowFeeRatePerDay);
|
||||
|
||||
// Daily Collateral Fees
|
||||
const dailyCollateralFee = depositMultiplier * collateralFeeRate;
|
||||
const collectedReturnsDaily = depositMultiplier * jlpStakeRatePerDay;
|
||||
collectedCollateralFees += dailyCollateralFee;
|
||||
collectedReturns += collectedReturnsDaily
|
||||
depositMultiplier += collectedReturnsDaily - dailyCollateralFee;
|
||||
}
|
||||
|
||||
// APY's for the calculation
|
||||
const depositAPY = 100 * leverage * (((depositMultiplier + 1) / leverage) - 1); // Composed of the below two
|
||||
const collateralFeeAPY = leverage * (collectedCollateralFees / leverage) * 100;
|
||||
const collectedReturnsAPY = leverage * ((collectedReturns + 1) / leverage) * 100;
|
||||
|
||||
// Interest Fee APY: Reflecting borrowing cost as an annual percentage yield
|
||||
const interestCost = (borrowMultiplier - (leverage - 1)); // APY on interest
|
||||
const borrowsAPY = 100 * interestCost;
|
||||
|
||||
// Total APY taking into account interest, collateral fees and returns
|
||||
const APY = 100 * (depositMultiplier - borrowMultiplier)
|
||||
|
||||
// Comparisons to outside
|
||||
const nonMangoAPY = jlpStakeRateAPY * leverage * 100;
|
||||
const diffToNonMango = (depositAPY - nonMangoAPY);
|
||||
const diffToNonLeveraged = (depositAPY - (jlpStakeRateAPY * 100));
|
||||
|
||||
return { APY, depositAPY, collectedReturnsAPY, collateralFeeAPY, borrowsAPY, nonMangoAPY, diffToNonMango, diffToNonLeveraged };
|
||||
}, [leverage, borrowBankBorrowRate, jlpStakeRateAPY, stakeBank?.collateralFeePerDay, stakeBank?.maintAssetWeight ]);
|
||||
|
||||
const estimatedMaxAPY = useMemo(() => {
|
||||
return (
|
||||
borrowBankStakeRate * leverageMax - borrowBankBorrowRate * (leverageMax - 1)
|
||||
jlpStakeRateAPY * leverageMax - Number(borrowBankBorrowRate) * (leverageMax - 1)
|
||||
)
|
||||
}, [borrowBankStakeRate, borrowBankBorrowRate, leverageMax])
|
||||
}, [jlpStakeRateAPY, borrowBankBorrowRate, leverageMax])
|
||||
|
||||
return {
|
||||
financialMetrics,
|
||||
stakeBankDepositRate,
|
||||
borrowBankBorrowRate,
|
||||
borrowBankStakeRate,
|
||||
leveragedAPY,
|
||||
estimatedNetAPY,
|
||||
jlpStakeRateAPY,
|
||||
estimatedMaxAPY,
|
||||
collateralFeeAPY
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue