Skip to content

Commit

Permalink
Show tooltips when estimations are infinite. Show warning when taking…
Browse files Browse the repository at this point in the history
… out a bond if bonding bLUSD is not profitable
  • Loading branch information
edmulraney committed Jan 17, 2023
1 parent e55aa07 commit a25a194
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 38 deletions.
22 changes: 16 additions & 6 deletions packages/dev-frontend/src/components/Bonds/BondsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import * as lexicon from "./lexicon";
import { Empty } from "./views/idle/Empty";
import { Link } from "../Link";
import { useBondView } from "./context/BondViewContext";
import { Decimal } from "@liquity/lib-base";
import { InfiniteEstimate } from "./views/InfiniteEstimation";

const {
BONDS,
Expand Down Expand Up @@ -34,6 +36,8 @@ const formatDays = (days: number) =>
? "Now"
: parseFloat(days.toFixed(1)) < 1
? `${days.toFixed(1)} days`
: days > 10000
? Decimal.INFINITY.toString()
: `${days.toFixed(0)} days`;

const Line = (columns: number) =>
Expand Down Expand Up @@ -107,17 +111,23 @@ export const BondsTable: React.FC = () => {
{Line(5)}

{pendingBonds.map((bond, idx) => {
const breakEvenDays =
(bond.breakEvenTime.getTime() - Date.now()) / 1000 / 60 / 60 / 24;
const rebondDays = (bond.rebondTime.getTime() - Date.now()) / 1000 / 60 / 60 / 24;
const breakEvenDays = formatDays(
(bond.breakEvenTime.getTime() - Date.now()) / 1000 / 60 / 60 / 24
);
const rebondDays = formatDays(
(bond.rebondTime.getTime() - Date.now()) / 1000 / 60 / 60 / 24
);
return (
<React.Fragment key={idx}>
<Text>{bond.deposit.shorten()} LUSD</Text>
<Text>{bond.accrued.shorten()} bLUSD</Text>
<Text>{bond.marketValue.shorten()} LUSD</Text>
<Text>{formatDays(breakEvenDays)}</Text>
<Text>{formatDays(rebondDays)}</Text>

<Text>
<InfiniteEstimate estimate={breakEvenDays} />
</Text>
<Text>
<InfiniteEstimate estimate={rebondDays} />
</Text>
{Line(5)}
</React.Fragment>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/dev-frontend/src/components/Bonds/context/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ const getProtocolInfo = async (
rebondPeriodInDays
} = _getProtocolInfo(marketPrice, floorPrice, claimBondFee, alphaAccrualFactor);

const simulatedMarketPrice = hasMarketPremium ? marketPrice : floorPrice.mul(1.1);
const simulatedMarketPrice = marketPrice;

const controllerTargetAge = Decimal.from(
(await chickenBondManager.targetAverageAgeSeconds()).toString()
Expand Down
5 changes: 5 additions & 0 deletions packages/dev-frontend/src/components/Bonds/lexicon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,8 @@ export const TREASURY_PERMANENT = {
export const ESTIMATES_ONLY_NOTICE = {
description: "These metrics are estimations based on the current bLUSD market price"
};

export const INFINITE_ESTIMATION = {
description:
"The market price premium is currently too low to make bonding profitable. Bonds will be profitable again if the premium returns."
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Decimal, Decimalish } from "@liquity/lib-base";
import { InfoIcon } from "../../InfoIcon";
import { Card } from "theme-ui";
import * as l from "../lexicon";

type InfiniteEstimateProps = {
estimate: Decimalish;
};

export const InfiniteEstimate: React.FC<InfiniteEstimateProps> = ({ estimate, children }) => {
if (estimate.toString() !== Decimal.INFINITY.toString()) return <>{children ?? estimate}</>;

return (
<>
{Decimal.INFINITY.toString()}
<InfoIcon
size="xs"
tooltip={<Card variant="tooltip">{l.INFINITE_ESTIMATION.description}</Card>}
/>
&nbsp;
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Warning } from "../../../Warning";
import { ReactModal } from "../../../ReactModal";
import { percentify } from "../../utils";
import { Decimal } from "@liquity/lib-base";
import { InfiniteEstimate } from "../InfiniteEstimation";

export const Actioning: React.FC = () => {
const { dispatchEvent, view, selectedBond: bond } = useBondView();
Expand Down Expand Up @@ -49,7 +50,11 @@ export const Actioning: React.FC = () => {
label: (
<>
<Label description={l.BREAK_EVEN_TIME.description}>{l.BREAK_EVEN_TIME.term}</Label>
<SubLabel>{`${bond.breakEvenAccrual.prettify(2)} bLUSD`}</SubLabel>
<SubLabel>
<InfiniteEstimate estimate={bond.breakEvenAccrual}>
{bond.breakEvenAccrual.prettify(2)} bLUSD
</InfiniteEstimate>
</SubLabel>
</>
)
},
Expand All @@ -58,7 +63,11 @@ export const Actioning: React.FC = () => {
label: (
<>
<Label description={l.OPTIMUM_REBOND_TIME.description}>{l.OPTIMUM_REBOND_TIME.term}</Label>
<SubLabel>{`${bond.rebondAccrual.prettify(2)} bLUSD`}</SubLabel>
<SubLabel>
<InfiniteEstimate estimate={bond.rebondAccrual}>
{bond.rebondAccrual.prettify(2)} bLUSD
</InfiniteEstimate>
</SubLabel>
</>
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { EditableRow } from "../../../Trove/Editor";
import { Record } from "../../Record";
import { InfoIcon } from "../../../InfoIcon";
import { useBondView } from "../../context/BondViewContext";
import { HorizontalTimeline, Label, SubLabel } from "../../../HorizontalTimeline";
import { HorizontalTimeline, Label, SubLabel, UNKNOWN_DATE } from "../../../HorizontalTimeline";
import { EXAMPLE_NFT } from "../../context/BondViewProvider";
import * as l from "../../lexicon";
import { useWizard } from "../../../Wizard/Context";
Expand All @@ -25,6 +25,7 @@ import {
import { HorizontalSlider } from "../../../HorizontalSlider";
import { ErrorDescription } from "../../../ErrorDescription";
import { Amount } from "../../../ActionDescription";
import { InfiniteEstimate } from "../InfiniteEstimation";

type DetailsProps = { onBack?: () => void };

Expand Down Expand Up @@ -70,14 +71,15 @@ export const Details: React.FC<DetailsProps> = ({ onBack }) => {
if (protocolInfo === undefined || simulatedProtocolInfo === undefined || lusdBalance === undefined)
return null;

const hasMarketPremium = simulatedProtocolInfo.hasMarketPremium;
const depositMinusClaimBondFee = Decimal.ONE.sub(protocolInfo.claimBondFee).mul(deposit);
const rebondReturn = getReturn(
depositMinusClaimBondFee.mul(simulatedProtocolInfo.rebondAccrualFactor),
deposit,
simulatedProtocolInfo.simulatedMarketPrice
);
const rebondRoi = rebondReturn / toFloat(deposit) || 0;
const marketPriceMin = protocolInfo.floorPrice.add(0.015).prettify(2); // Add 0.015 to prevent market_price=floor_price infinity issues
const marketPriceMin = protocolInfo.floorPrice.mul(1.025).prettify(2); // Enough to display what happens below the 3% chicken in fee
const marketPriceMax = Decimal.max(
protocolInfo.marketPrice.mul(1.1),
protocolInfo.floorPrice.mul(1.5)
Expand All @@ -102,19 +104,31 @@ export const Details: React.FC<DetailsProps> = ({ onBack }) => {
protocolInfo.claimBondFee
);

const breakEvenTime = getRebondOrBreakEvenTimeWithControllerAdjustment(
Decimal.ZERO,
simulatedProtocolInfo.controllerTargetAge,
simulatedProtocolInfo.averageBondAge,
Decimal.from(breakEvenDays)
);
const breakEvenTime = breakEvenDays.eq(Decimal.INFINITY)
? UNKNOWN_DATE
: getRebondOrBreakEvenTimeWithControllerAdjustment(
Decimal.ZERO,
simulatedProtocolInfo.controllerTargetAge,
simulatedProtocolInfo.averageBondAge,
breakEvenDays
);

const rebondTime = getRebondOrBreakEvenTimeWithControllerAdjustment(
Decimal.ZERO,
simulatedProtocolInfo.controllerTargetAge,
simulatedProtocolInfo.averageBondAge,
Decimal.from(rebondDays)
);
const rebondTime = rebondDays.eq(Decimal.INFINITY)
? UNKNOWN_DATE
: getRebondOrBreakEvenTimeWithControllerAdjustment(
Decimal.ZERO,
simulatedProtocolInfo.controllerTargetAge,
simulatedProtocolInfo.averageBondAge,
rebondDays
);

const breakEvenAccrual = hasMarketPremium
? depositMinusClaimBondFee.mul(simulatedProtocolInfo.breakEvenAccrualFactor)
: Decimal.INFINITY;

const rebondAccrual = hasMarketPremium
? depositMinusClaimBondFee.mul(simulatedProtocolInfo.rebondAccrualFactor)
: Decimal.INFINITY;

return (
<>
Expand Down Expand Up @@ -169,9 +183,11 @@ export const Details: React.FC<DetailsProps> = ({ onBack }) => {
label: (
<>
<Label description={l.BREAK_EVEN_TIME.description}>{l.BREAK_EVEN_TIME.term}</Label>
<SubLabel>{`${depositMinusClaimBondFee
.mul(simulatedProtocolInfo.breakEvenAccrualFactor)
.prettify(2)} bLUSD`}</SubLabel>
<SubLabel>
<InfiniteEstimate estimate={breakEvenAccrual}>
{breakEvenAccrual.prettify(2)} bLUSD
</InfiniteEstimate>
</SubLabel>
</>
)
},
Expand All @@ -182,9 +198,11 @@ export const Details: React.FC<DetailsProps> = ({ onBack }) => {
<Label description={l.OPTIMUM_REBOND_TIME.description}>
{l.OPTIMUM_REBOND_TIME.term}
</Label>
<SubLabel>{`${depositMinusClaimBondFee
.mul(simulatedProtocolInfo.rebondAccrualFactor)
.prettify(2)} bLUSD`}</SubLabel>
<SubLabel>
<InfiniteEstimate estimate={rebondAccrual}>
{rebondAccrual.prettify(2)} bLUSD
</InfiniteEstimate>
</SubLabel>
</>
)
}
Expand All @@ -207,21 +225,25 @@ export const Details: React.FC<DetailsProps> = ({ onBack }) => {
<Grid sx={{ my: 1, mb: 3, justifyItems: "center", pl: 2 }} gap="20px" columns={3}>
<Record
name={l.REBOND_RETURN.term}
value={rebondReturn.toFixed(2)}
value={hasMarketPremium ? rebondReturn.toFixed(2) : "N/A"}
type="LUSD"
description={l.REBOND_RETURN.description}
/>

<Record
name={l.REBOND_TIME_ROI.term}
value={percentify(rebondRoi).toFixed(2) + "%"}
value={hasMarketPremium ? percentify(rebondRoi).toFixed(2) + "%" : "N/A"}
type=""
description={l.REBOND_TIME_ROI.description}
/>

<Record
name={l.OPTIMUM_APY.term}
value={percentify(rebondRoi * (365 / controllerAdjustedRebondDays)).toFixed(2) + "%"}
value={
hasMarketPremium
? percentify(rebondRoi * (365 / controllerAdjustedRebondDays)).toFixed(2) + "%"
: "N/A"
}
type=""
description={l.OPTIMUM_APY.description}
/>
Expand All @@ -235,11 +257,18 @@ export const Details: React.FC<DetailsProps> = ({ onBack }) => {
max={marketPriceMax}
type="LUSD"
onSliderChange={value => setSimulatedMarketPrice(value)}
onReset={() => setSimulatedMarketPrice(protocolInfo.marketPrice)}
onReset={() => resetSimulatedMarketPrice()}
/>

{statuses.CREATE === "FAILED" && <Warning>Failed to create bond. Please try again.</Warning>}

{!protocolInfo.hasMarketPremium && (
<Warning>
When the market price is less than 3% above the floor price, it's not profitable to bond.
Buying bLUSD from the market currently generates a higher return than bonding.
</Warning>
)}

{!isDepositEnough && <ErrorDescription>The minimum bond amount is 100 LUSD.</ErrorDescription>}
{doesDepositExceedBalance && (
<ErrorDescription>
Expand Down
17 changes: 12 additions & 5 deletions packages/dev-frontend/src/components/Bonds/views/idle/Bond.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@ import { Label, SubLabel } from "../../../HorizontalTimeline";
import * as l from "../../lexicon";
import { statuses, useBondView } from "../../context/BondViewContext";
import { useBondAddresses } from "../../context/BondAddressesContext";
import { InfiniteEstimate } from "../InfiniteEstimation";

const getBondEvents = (bond: BondType): EventType[] => {
const events = [
{
date: new Date(bond.startTime),
label: (
<>
<Label description="bLUSD accrual starts off at 0 and increases over time.">
{l.BOND_CREATED.term}
</Label>
<Label description={l.BOND_CREATED.description}>{l.BOND_CREATED.term}</Label>
<SubLabel>{`0.00 bLUSD`}</SubLabel>
</>
)
Expand Down Expand Up @@ -55,7 +54,11 @@ const getBondEvents = (bond: BondType): EventType[] => {
label: (
<>
<Label description={l.BREAK_EVEN_TIME.description}>{l.BREAK_EVEN_TIME.term}</Label>
<SubLabel>{`${bond?.breakEvenAccrual?.prettify(2) ?? "?"} bLUSD`}</SubLabel>
<SubLabel>
<InfiniteEstimate estimate={bond?.breakEvenAccrual}>
{bond?.breakEvenAccrual?.prettify(2) ?? "?"} bLUSD
</InfiniteEstimate>
</SubLabel>
</>
)
});
Expand All @@ -65,7 +68,11 @@ const getBondEvents = (bond: BondType): EventType[] => {
label: (
<>
<Label description={l.OPTIMUM_REBOND_TIME.description}>{l.OPTIMUM_REBOND_TIME.term}</Label>
<SubLabel>{`${bond?.rebondAccrual?.prettify(2) ?? "?"} bLUSD`}</SubLabel>
<SubLabel>
<InfiniteEstimate estimate={bond?.rebondAccrual}>
{bond?.rebondAccrual?.prettify(2) ?? "?"} bLUSD
</InfiniteEstimate>
</SubLabel>
</>
)
});
Expand Down

0 comments on commit a25a194

Please sign in to comment.