Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pool Detail: Fix bond duration cards #1076

Merged
merged 1 commit into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions packages/stores/src/ui-config/manage-liquidity/bond-liquidity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import { ObservableQueryPoolFeesMetrics } from "../../queries-external";
import { IPriceStore } from "../../price";
import { UserConfig } from "../user-config";

export type BondableDuration = {
export type BondDuration = {
duration: Duration;
/** Bondable if there's any active gauges for this duration. */
bondable: boolean;
userShares: CoinPretty;
userUnlockingShares?: { shares: CoinPretty; endTime?: Date };
aggregateApr: RatePretty;
Expand Down Expand Up @@ -63,23 +65,23 @@ export class ObservableBondLiquidityConfig extends UserConfig {
* 2. Liquidity needs to be bonded
*/
readonly calculateBondLevel = computedFn(
(bondableDurations: BondableDuration[]): 1 | 2 | undefined => {
(bondDurations: BondDuration[]): 1 | 2 | undefined => {
if (
this.poolDetails?.userAvailableValue.toDec().gt(new Dec(0)) &&
bondableDurations.length > 0
bondDurations.some((duration) => duration.bondable)
)
return 2;

if (this.poolDetails?.userAvailableValue.toDec().isZero()) return 1;
}
);

/** Gets all available durations for user to bond in, with a breakdown of the assets incentivizing the duration. Internal OSMO incentives & swap fees included in breakdown. */
readonly getBondableAllowedDurations = computedFn(
/** Gets all durations for user to bond in, or has locked tokens for, with a breakdown of the assets incentivizing the duration. Internal OSMO incentives & swap fees included in breakdown. */
readonly getAllowedBondDurations = computedFn(
(
findCurrency: (denom: string) => AppCurrency | undefined,
allowedGauges: { gaugeId: string; denom: string }[] | undefined
): BondableDuration[] => {
): BondDuration[] => {
const poolId = this.poolDetails.pool.id;
const gauges = this.superfluidPool.gaugesWithSuperfluidApr;

Expand Down Expand Up @@ -144,6 +146,7 @@ export class ObservableBondLiquidityConfig extends UserConfig {
this.poolDetails.poolShareCurrency,
curDuration
).amount;

const unlockingUserShares =
queryLockedCoin.getUnlockingCoinWithDuration(
this.poolDetails.poolShareCurrency,
Expand All @@ -160,8 +163,7 @@ export class ObservableBondLiquidityConfig extends UserConfig {
}
: undefined;

const incentivesBreakdown: BondableDuration["incentivesBreakdown"] =
[];
const incentivesBreakdown: BondDuration["incentivesBreakdown"] = [];

// push single internal incentive for current duration
if (internalGaugeOfDuration) {
Expand Down Expand Up @@ -219,7 +221,7 @@ export class ObservableBondLiquidityConfig extends UserConfig {

// add superfluid data if highest duration
const sfsDuration = this.poolDetails.longestDuration;
let superfluid: BondableDuration["superfluid"] | undefined;
let superfluid: BondDuration["superfluid"] | undefined;
if (
this.superfluidPool.isSuperfluid &&
this.superfluidPool.superfluid &&
Expand Down Expand Up @@ -263,6 +265,9 @@ export class ObservableBondLiquidityConfig extends UserConfig {

return {
duration: curDuration,
bondable:
internalGaugeOfDuration !== undefined ||
externalGaugesOfDuration.length > 0,
userShares: lockedUserShares,
userUnlockingShares,
aggregateApr,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { ObservableQueryPoolDetails, ObservableQuerySuperfluidPool, ObservableQu
import { ObservableQueryPoolFeesMetrics } from "../../queries-external";
import { IPriceStore } from "../../price";
import { UserConfig } from "../user-config";
export declare type BondableDuration = {
export declare type BondDuration = {
duration: Duration;
/** Bondable if there's any active gauges for this duration. */
bondable: boolean;
userShares: CoinPretty;
userUnlockingShares?: {
shares: CoinPretty;
Expand Down Expand Up @@ -52,10 +54,10 @@ export declare class ObservableBondLiquidityConfig extends UserConfig {
* 1. Liquidity needs to be added
* 2. Liquidity needs to be bonded
*/
readonly calculateBondLevel: (bondableDurations: BondableDuration[]) => 1 | 2 | undefined;
/** Gets all available durations for user to bond in, with a breakdown of the assets incentivizing the duration. Internal OSMO incentives & swap fees included in breakdown. */
readonly getBondableAllowedDurations: (findCurrency: (denom: string) => AppCurrency | undefined, allowedGauges: {
readonly calculateBondLevel: (bondDurations: BondDuration[]) => 1 | 2 | undefined;
/** Gets all durations for user to bond in, or has locked tokens for, with a breakdown of the assets incentivizing the duration. Internal OSMO incentives & swap fees included in breakdown. */
readonly getAllowedBondDurations: (findCurrency: (denom: string) => AppCurrency | undefined, allowedGauges: {
gaugeId: string;
denom: string;
}[] | undefined) => BondableDuration[];
}[] | undefined) => BondDuration[];
}
179 changes: 84 additions & 95 deletions packages/web/components/cards/bond-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import classNames from "classnames";
import moment from "dayjs";
import { Duration } from "dayjs/plugin/duration";
import { CoinPretty, Dec, PricePretty, RatePretty } from "@keplr-wallet/unit";
import { BondableDuration } from "@osmosis-labs/stores";
import { BondDuration } from "@osmosis-labs/stores";
import { FallbackImg } from "../assets";
import { ArrowButton } from "../buttons";
import { useTranslation } from "react-multi-lang";

export const BondCard: FunctionComponent<
BondableDuration & {
BondDuration & {
onUnbond: () => void;
onGoSuperfluid: () => void;
splashImageSrc?: string;
Expand Down Expand Up @@ -142,8 +142,8 @@ const Drawer: FunctionComponent<{
swapFeeApr: RatePretty;
swapFeeDailyReward: PricePretty;
userShares: CoinPretty;
incentivesBreakdown: BondableDuration["incentivesBreakdown"];
superfluid: BondableDuration["superfluid"];
incentivesBreakdown: BondDuration["incentivesBreakdown"];
superfluid: BondDuration["superfluid"];
drawerUp: boolean;
toggleDetailsVisible: () => void;
onGoSuperfluid: () => void;
Expand Down Expand Up @@ -180,114 +180,103 @@ const Drawer: FunctionComponent<{
>
<div
className={classNames(
"absolute w-full h-[320px] -bottom-[234px] left-1/2 -translate-x-1/2 flex flex-col transition-all duration-300 ease-inOutBack z-50",
"flex items-end place-content-between transition-all py-4 px-8 md:px-[10px]",
{
"-translate-y-[220px] bg-osmoverse-700 rounded-t-[18px]": drawerUp,
"border-b border-osmoverse-600": drawerUp,
}
)}
>
<div
<div className="flex flex-col">
<span className="subtitle1 text-osmoverse-200">
{t("pool.incentives")}
</span>
<div className="flex items-center gap-2 md:gap-1.5">
<h5
className={classNames(
superfluid ? "text-superfluid-gradient" : "text-bullish-400"
)}
>
{aggregateApr.maxDecimals(0).toString()} {t("pool.APR")}
</h5>
<div
className={classNames(
"flex items-center gap-1 transition-opacity duration-300",
drawerUp ? "opacity-0" : "opacity-100"
)}
>
{uniqueCoinImages.map((coinImageUrl, index) => (
<div key={index}>
{index === 2 && incentivesBreakdown.length > 3 ? (
<span className="caption text-osmoverse-400">
+{incentivesBreakdown.length - 2}
</span>
) : index < 2 ? (
<Image
alt="incentive icon"
src={coinImageUrl}
height={24}
width={24}
/>
) : null}
</div>
))}
</div>
</div>
</div>
<button
className={classNames(
"flex items-end place-content-between transition-all py-4 px-8 md:px-[10px]",
"flex items-center cursor-pointer transition-transform",
{
"border-b border-osmoverse-600": drawerUp,
"-translate-y-[28px]": drawerUp,
}
)}
onClick={toggleDetailsVisible}
>
<div className="flex flex-col">
<span className="subtitle1 text-osmoverse-200">
{t("pool.incentives")}
</span>
<div className="flex items-center gap-2 md:gap-1.5">
<h5
className={classNames(
superfluid ? "text-superfluid-gradient" : "text-bullish-400"
)}
>
{aggregateApr.maxDecimals(0).toString()} {t("pool.APR")}
</h5>
<div
className={classNames(
"flex items-center gap-1 transition-opacity duration-300",
drawerUp ? "opacity-0" : "opacity-100"
)}
>
{uniqueCoinImages.map((coinImageUrl, index) => (
<div key={index}>
{index === 2 && incentivesBreakdown.length > 3 ? (
<span className="caption text-osmoverse-400">
+{incentivesBreakdown.length - 2}
</span>
) : index < 2 ? (
<Image
alt="incentive icon"
src={coinImageUrl}
height={24}
width={24}
/>
) : null}
</div>
))}
</div>
</div>
</div>
<button
className={classNames(
"flex items-center cursor-pointer transition-transform",
{
"-translate-y-[28px]": drawerUp,
}
)}
onClick={toggleDetailsVisible}
<span className="xs:hidden caption text-osmoverse-400">
{t("pool.details")}
</span>
<div
className={classNames("flex items-center transition-transform", {
"rotate-180": drawerUp,
})}
>
<span className="xs:hidden caption text-osmoverse-400">
{t("pool.details")}
</span>
<div
className={classNames("flex items-center transition-transform", {
"rotate-180": drawerUp,
})}
>
<Image
alt="details"
src="/icons/chevron-up-osmoverse-400.svg"
height={30}
width={30}
/>
</div>
</button>
</div>
<div
className={classNames("flex flex-col gap-1.5 h-full", {
"bg-osmoverse-700": drawerUp,
})}
>
<div className="flex flex-col h-[180px] gap-5 py-6 px-8 md:px-[10px] overflow-y-auto">
{superfluid &&
superfluid.duration.asMilliseconds() ===
duration.asMilliseconds() && (
<SuperfluidBreakdownRow {...superfluid} />
)}
{incentivesBreakdown.map((breakdown, index) => (
<IncentiveBreakdownRow key={index} {...breakdown} />
))}
<SwapFeeBreakdownRow
swapFeeApr={swapFeeApr}
swapFeeDailyReward={swapFeeDailyReward}
<Image
alt="details"
src="/icons/chevron-up-osmoverse-400.svg"
height={30}
width={30}
/>
</div>
<span className="caption text-center text-osmoverse-400">
{t("pool.rewardDistribution")}
</span>
</button>
</div>
<div
className={classNames("flex flex-col gap-1.5 h-full", {
"bg-osmoverse-700": drawerUp,
})}
>
<div className="flex flex-col h-[180px] gap-5 py-6 px-8 md:px-[10px] overflow-y-auto">
{superfluid &&
superfluid.duration.asMilliseconds() ===
duration.asMilliseconds() && (
<SuperfluidBreakdownRow {...superfluid} />
)}
{incentivesBreakdown.map((breakdown, index) => (
<IncentiveBreakdownRow key={index} {...breakdown} />
))}
<SwapFeeBreakdownRow
swapFeeApr={swapFeeApr}
swapFeeDailyReward={swapFeeDailyReward}
/>
</div>
<span className="caption text-center text-osmoverse-400">
{t("pool.rewardDistribution")}
</span>
</div>
</div>
);
};

const SuperfluidBreakdownRow: FunctionComponent<
BondableDuration["superfluid"]
> = ({
const SuperfluidBreakdownRow: FunctionComponent<BondDuration["superfluid"]> = ({
apr,
commission,
delegated,
Expand Down Expand Up @@ -351,7 +340,7 @@ const SuperfluidBreakdownRow: FunctionComponent<
};

const IncentiveBreakdownRow: FunctionComponent<
BondableDuration["incentivesBreakdown"][0]
BondDuration["incentivesBreakdown"][0]
> = ({ dailyPoolReward, apr, numDaysRemaining }) => {
const t = useTranslation();
return (
Expand Down
2 changes: 1 addition & 1 deletion packages/web/modals/lock-tokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const LockTokensModal: FunctionComponent<
const bondLiquidityConfig = useBondLiquidityConfig(bech32Address, poolId);

const bondableDurations =
bondLiquidityConfig?.getBondableAllowedDurations(
bondLiquidityConfig?.getAllowedBondDurations(
(denom) => chainStore.getChain(chainId).forceFindCurrency(denom),
ExternalIncentiveGaugeAllowList[poolId]
) ?? [];
Expand Down
Loading