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

Display external incentive APR #886

Merged
merged 14 commits into from
Oct 21, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
ObservableQueryEpochProvisions,
ObservableQueryMintParmas,
} from "../mint";
import { ObservableQueryPools } from "../pools";
import { ObservableQueryPools, ExternalGauge } from "../pools";
import { IPriceStore } from "../../price";
import { ObservableQueryDistrInfo } from "./distr-info";
import { ObservableQueryLockableDurations } from "./lockable-durations";
Expand Down Expand Up @@ -118,6 +118,47 @@ export class ObservableQueryIncentivizedPools extends ObservableChainQuery<Incen
}
);

/**
* Computes external incentive APY for the given duration
*/
readonly computeExternalIncentiveAPYForSpecificDuration = computedFn(
(duration: Duration, allowedGauges: ExternalGauge[]): RatePretty => {
if (!allowedGauges.length) {
return new RatePretty(new Dec(0));
}

const externalGauge = allowedGauges.find((externalGauge) => {
return (
duration.asMilliseconds() === externalGauge.duration.asMilliseconds()
);
});

if (!externalGauge?.rewardAmount) {
return new RatePretty(new Dec(0));
}

const mintDenom = this.queryMintParmas.mintDenom;

if (!mintDenom) {
return new RatePretty(new Dec(0));
}

const chainInfo = this.chainGetter.getChain(this.chainId);

const mintCurrency = chainInfo.findCurrency(mintDenom);

if (!mintCurrency) {
return new RatePretty(new Dec(0));
}

return new RatePretty(
externalGauge.rewardAmount
.moveDecimalPointLeft(mintCurrency.coinDecimals)
.toDec()
);
}
);

/**
* 리워드를 받을 수 있는 풀의 연당 이익률을 반환한다.
* 리워드를 받을 수 없는 풀일 경우 0를 리턴한다.
Expand Down Expand Up @@ -157,6 +198,7 @@ export class ObservableQueryIncentivizedPools extends ObservableChainQuery<Incen
priceStore,
fiatCurrency
);

for (const lockableDuration of lockableDurations) {
// 인센티브는 unlock 기간보다 짧은 모든 팟에 분배된다.
// 그러므로 apy를 계산하기 위해서는 제시된 duration보다 짧은 모든 duration에 대한 apy를 더해줘야 한다.
Expand Down Expand Up @@ -205,6 +247,7 @@ export class ObservableQueryIncentivizedPools extends ObservableChainQuery<Incen
mintCurrency.coinGeckoId,
fiatCurrency.currency
);

const poolTVL = pool.computeTotalValueLocked(priceStore);
if (
totalWeight.gt(new Int(0)) &&
Expand Down
9 changes: 1 addition & 8 deletions packages/stores/src/queries/pools/pool-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,7 @@ import {
ObservableQueryAccountUnlockingCoins,
} from "../lockup";
import { ObservableQueryPool } from "./pool";

/** Non OSMO gauge. */
export type ExternalGauge = {
id: string;
duration: Duration;
rewardAmount?: CoinPretty;
remainingEpochs: number;
};
import { ExternalGauge } from "./types";

/** Convenience store for getting common details of a pool via many other query stores. */
export class ObservableQueryPoolDetails {
Expand Down
10 changes: 10 additions & 0 deletions packages/stores/src/queries/pools/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { WeightedPoolRaw } from "@osmosis-labs/pools";
import { Duration } from "dayjs/plugin/duration";
import { CoinPretty } from "@keplr-wallet/unit";

export type Pools = {
pools: WeightedPoolRaw[];
Expand All @@ -7,3 +9,11 @@ export type Pools = {
export type NumPools = {
num_pools: string;
};

/** Non OSMO gauge. */
export type ExternalGauge = {
id: string;
duration: Duration;
rewardAmount?: CoinPretty;
remainingEpochs: number;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { RatePretty } from "@keplr-wallet/unit";
import { Duration } from "dayjs/plugin/duration";
import { ObservableQueryEpochs } from "../epochs";
import { ObservableQueryEpochProvisions, ObservableQueryMintParmas } from "../mint";
import { ObservableQueryPools } from "../pools";
import { ObservableQueryPools, ExternalGauge } from "../pools";
import { IPriceStore } from "../../price";
import { ObservableQueryDistrInfo } from "./distr-info";
import { ObservableQueryLockableDurations } from "./lockable-durations";
Expand All @@ -28,6 +28,10 @@ export declare class ObservableQueryIncentivizedPools extends ObservableChainQue
* 가장 긴 lockable duration의 apy를 반환한다.
*/
readonly computeMostAPY: (poolId: string, priceStore: IPriceStore) => RatePretty;
/**
* Computes external incentive APY for the given duration
*/
readonly computeExternalIncentiveAPYForSpecificDuration: (duration: Duration, allowedGauges: ExternalGauge[]) => RatePretty;
/**
* 리워드를 받을 수 있는 풀의 연당 이익률을 반환한다.
* 리워드를 받을 수 없는 풀일 경우 0를 리턴한다.
Expand Down
8 changes: 1 addition & 7 deletions packages/stores/types/queries/pools/pool-details.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,7 @@ import { ObservableQueryIncentivizedPools, ObservableQueryLockableDurations, Obs
import { ObservableQueryGuage } from "../incentives";
import { ObservableQueryAccountLocked, ObservableQueryAccountLockedCoins, ObservableQueryAccountUnlockingCoins } from "../lockup";
import { ObservableQueryPool } from "./pool";
/** Non OSMO gauge. */
export declare type ExternalGauge = {
id: string;
duration: Duration;
rewardAmount?: CoinPretty;
remainingEpochs: number;
};
import { ExternalGauge } from "./types";
/** Convenience store for getting common details of a pool via many other query stores. */
export declare class ObservableQueryPoolDetails {
protected readonly bech32Address: string;
Expand Down
9 changes: 9 additions & 0 deletions packages/stores/types/queries/pools/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { WeightedPoolRaw } from "@osmosis-labs/pools";
import { Duration } from "dayjs/plugin/duration";
import { CoinPretty } from "@keplr-wallet/unit";
export declare type Pools = {
pools: WeightedPoolRaw[];
};
export declare type NumPools = {
num_pools: string;
};
/** Non OSMO gauge. */
export declare type ExternalGauge = {
id: string;
duration: Duration;
rewardAmount?: CoinPretty;
remainingEpochs: number;
};
31 changes: 26 additions & 5 deletions packages/web/pages/pool/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { DepoolingTable } from "../../components/table/depooling-table";
import { truncateString } from "../../components/utils";
import {
ExternalIncentiveGaugeAllowList,
MergesInternalAndExternalIncentiveGaugeList,
UnPoolWhitelistedPoolIds,
EventName,
PromotedLBPPoolIds,
Expand Down Expand Up @@ -191,6 +192,29 @@ const Pool: FunctionComponent = observer(() => {
gaugeDurationMap.set(gauge.duration.asSeconds(), gauge);
});

// Compute combined APR (internal gauge + white-listed external gauge)
gaugeDurationMap.forEach((gauge) => {
const baseApy = queryOsmosis.queryIncentivizedPools.computeAPY(
pool.id,
gauge.duration,
priceStore,
fiat
);

const externalApy =
queryOsmosis.queryIncentivizedPools.computeExternalIncentiveAPYForSpecificDuration(
gauge.duration,
allowedGauges
);

const totalApr = baseApy.add(externalApy);

gaugeDurationMap.set(gauge.duration.asSeconds(), {
...gauge,
apr: totalApr,
});
});

return Array.from(gaugeDurationMap.values()).sort(
(a, b) => a.duration.asSeconds() - b.duration.asSeconds()
);
Expand Down Expand Up @@ -823,14 +847,11 @@ const Pool: FunctionComponent = observer(() => {
)}
{allowedLockupGauges && pool && (
<div className="flex lg:flex-col md:gap-3 gap-9 place-content-between md:pt-8 pt-10">
{allowedLockupGauges.map(({ duration, superfluidApr }) => (
{allowedLockupGauges.map(({ duration, apr, superfluidApr }) => (
<PoolGaugeCard
key={duration.humanize()}
days={duration.humanize()}
apr={queryOsmosis.queryIncentivizedPools
.computeAPY(pool.id, duration, priceStore, fiat)
.maxDecimals(2)
.toString()}
apr={apr?.maxDecimals?.(2).toString() ?? "0"}
superfluidApr={superfluidApr?.maxDecimals(2).toString()}
isMobile={isMobile}
/>
Expand Down