Skip to content

Commit b6993e6

Browse files
authored
Merge pull request #2216 from keep-network/liquidity-rewards
Liquidity rewards This PR adds new Liquidity Rewards page. Main changes: - add new **Liquidity Rewards** page - add function that calculates the APY (although it is not used for now, since we are not sure about the results. All the APY results in UI are hardcoded and calculated for $1M pool ) - calculate % of the total pool for each liquidity pair - calculate KEEP tokens reward for each liquidity pair - add possibility to add more lp tokens for each liquidity pair - add possibility to withdraw rewards for each liquidity pair - santa hats for each card - **NEW** label in the left menu for **Liquidity** page - **NEW** label for the Liquidity page header
2 parents dd70cad + 97263d8 commit b6993e6

34 files changed

+1176
-19
lines changed

solidity/dashboard/package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

solidity/dashboard/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"dependencies": {
77
"@0x/subproviders": "^6.0.8",
88
"@keep-network/keep-core": "1.4.1",
9-
"@keep-network/keep-ecdsa": "1.4.0",
9+
"@keep-network/keep-ecdsa": "1.5.0",
1010
"@keep-network/tbtc": "1.1.0",
1111
"@ledgerhq/hw-app-eth": "^5.13.0",
1212
"@ledgerhq/hw-transport-u2f": "^5.13.0",

solidity/dashboard/src/actions/web3.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,34 @@ export const withdrawGroupMemberRewards = (
176176
meta,
177177
}
178178
}
179+
180+
export const withdrawAllLiquidityRewards = (
181+
liquidityPairContractName,
182+
meta
183+
) => {
184+
return {
185+
type: WEB3_SEND_TRANSACTION,
186+
payload: {
187+
contractName: liquidityPairContractName,
188+
methodName: "exit",
189+
},
190+
meta,
191+
}
192+
}
193+
194+
export const addMoreLpTokens = (
195+
amount,
196+
address,
197+
liquidityPairContractName,
198+
meta
199+
) => {
200+
return {
201+
type: "liquidity_rewards/stake_tokens",
202+
payload: {
203+
contractName: liquidityPairContractName,
204+
amount,
205+
address,
206+
},
207+
meta,
208+
}
209+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from "react"
2+
3+
const Card = ({ className, children }) => {
4+
return (
5+
<div className={`card-root ${className}`}>
6+
{children}
7+
</div>
8+
)
9+
}
10+
11+
export default Card
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from "react"
2+
3+
const CardContainer = ({ className, children }) => {
4+
return (
5+
<div className={`card-container-root ${className}`}>
6+
{children}
7+
</div>
8+
)
9+
}
10+
11+
export default CardContainer
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from "react"
2+
3+
const DoubleIcon = ({ MainIcon, SecondaryIcon, className }) => {
4+
return (
5+
<div className={`double-icon-container ${className}`}>
6+
<SecondaryIcon className={`secondary-icon`} />
7+
<MainIcon className={`main-icon`} />
8+
</div>
9+
)
10+
}
11+
12+
export default DoubleIcon

solidity/dashboard/src/components/Header.jsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ import React from "react"
22
import { NavLink } from "react-router-dom"
33
import { isEmptyArray } from "../utils/array.utils"
44
import { Web3Status } from "./Web3Status"
5+
import Chip from "./Chip";
56

6-
const Header = ({ title, subLinks, className = "" }) => {
7+
const Header = ({ title, subLinks, className = "", newPage = false }) => {
8+
console.log(newPage)
79
return (
810
<header className={`header ${className}`}>
911
<div className="header__content">
10-
<h1 className="header__title">{title}</h1>
12+
<h1 className="header__title">
13+
{title}{" "}
14+
{newPage && (
15+
<Chip text="NEW" className={"header__chip ml-1"}/>
16+
)}
17+
</h1>
1118
<Web3Status />
1219
</div>
1320
{!isEmptyArray(subLinks) && (

solidity/dashboard/src/components/Icons.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ export { ReactComponent as Plus } from "../static/svg/plus.svg"
4949
export { ReactComponent as StakeDrop } from "../static/svg/stakedrop.svg"
5050
export { ReactComponent as SwordOperations } from "../static/svg/sword-operations.svg"
5151
export { ReactComponent as MoreInfo } from "../static/svg/more-info.svg"
52+
export { ReactComponent as EthToken } from "../static/svg/eth_token.svg"
53+
export { ReactComponent as SantaHat } from "../static/svg/santa-hat.svg"
5254

5355
const Badge = ({ height, width }) => (
5456
<svg
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import React, { useMemo } from "react"
2+
import BigNumber from "bignumber.js"
3+
import DoubleIcon from "./DoubleIcon"
4+
import * as Icons from "./Icons"
5+
import { SubmitButton } from "./Button"
6+
import Card from "./Card"
7+
import { displayAmount } from "../utils/token.utils"
8+
import { gt } from "../utils/arithmetics.utils"
9+
import { Skeleton } from "./skeletons"
10+
11+
const LiquidityRewardCard = ({
12+
title,
13+
liquidityPairContractName,
14+
MainIcon,
15+
SecondaryIcon,
16+
viewPoolLink,
17+
apy,
18+
// Percentage of the deposited liquidity tokens in the `LPRewards` pool.
19+
percentageOfTotalPool,
20+
// Current reward balance earned in `LPRewards` contract.
21+
rewardBalance,
22+
// Balance of the wrapped token.
23+
wrappedTokenBalance,
24+
// Balance of wrapped token deposited in the `LPRewards` contract.
25+
lpBalance,
26+
isFetching,
27+
wrapperClassName = "",
28+
addLpTokens,
29+
withdrawLiquidityRewards,
30+
}) => {
31+
const formattedApy = useMemo(() => {
32+
const bn = new BigNumber(apy)
33+
if (bn.isEqualTo(Infinity)) return <span>&#8734;</span>
34+
35+
return bn.isLessThan(0.01) && bn.isGreaterThan(0)
36+
? "<0.01%"
37+
: bn.multipliedBy(100).decimalPlaces(2, BigNumber.ROUND_DOWN).toString() +
38+
"%"
39+
}, [apy])
40+
41+
const formattedPercentageOfTotalPool = useMemo(() => {
42+
const bn = new BigNumber(percentageOfTotalPool)
43+
return bn.isLessThan(0.01) && bn.isGreaterThan(0)
44+
? "<0.01"
45+
: bn.decimalPlaces(2, BigNumber.ROUND_DOWN)
46+
}, [percentageOfTotalPool])
47+
48+
return (
49+
<Card className={`liquidity__card tile ${wrapperClassName}`}>
50+
<Icons.SantaHat className="liquidity-card__santa-hat" />
51+
<div className={"liquidity__card-title"}>
52+
<DoubleIcon
53+
MainIcon={MainIcon}
54+
SecondaryIcon={SecondaryIcon}
55+
className={`liquidity__double-icon-container`}
56+
/>
57+
<h2 className={"h2--alt text-grey-70"}>{title}</h2>
58+
</div>
59+
<h4 className="liquidity__card-subtitle text-grey-40">
60+
Uniswap Pool&nbsp;
61+
<a
62+
target="_blank"
63+
rel="noopener noreferrer"
64+
href={viewPoolLink}
65+
className="text-small"
66+
>
67+
View pool
68+
</a>
69+
</h4>
70+
<div className={"liquidity__info text-grey-60 mt-2"}>
71+
<div className={"liquidity__info-tile bg-mint-10"}>
72+
<h2 className={"liquidity__info-tile__title text-mint-100"}>
73+
{formattedApy}*
74+
</h2>
75+
<h6>Annual % yield (APY)</h6>
76+
</div>
77+
<div className={"liquidity__info-tile bg-mint-10"}>
78+
{isFetching ? (
79+
<Skeleton tag="h2" shining color="mint-20" />
80+
) : (
81+
<h2
82+
className={"liquidity__info-tile__title text-mint-100"}
83+
>{`${formattedPercentageOfTotalPool}%`}</h2>
84+
)}
85+
<h6>% of total pool</h6>
86+
</div>
87+
</div>
88+
<div className={"text-smaller text-grey-70 text-center mb-2"}>
89+
* APY calculated assuming $1M pool
90+
</div>
91+
<div className={"liquidity__token-balance"}>
92+
<span className={"liquidity__token-balance_title text-grey-70"}>
93+
Reward
94+
</span>
95+
<div className={"liquidity__token-balance_values text-grey-70"}>
96+
<h3 className={"liquidity__token-balance_values_label"}>
97+
<Icons.KeepOutline />
98+
<span>KEEP</span>
99+
</h3>
100+
{isFetching ? (
101+
<Skeleton tag="h3" shining color="grey-20" className="ml-3" />
102+
) : (
103+
<h3>{displayAmount(rewardBalance)}</h3>
104+
)}
105+
</div>
106+
</div>
107+
<SubmitButton
108+
className={`liquidity__add-more-tokens btn btn-primary btn-lg w-100`}
109+
disabled={!gt(wrappedTokenBalance, 0)}
110+
onSubmitAction={(awaitingPromise) =>
111+
addLpTokens(
112+
wrappedTokenBalance,
113+
liquidityPairContractName,
114+
awaitingPromise
115+
)
116+
}
117+
>
118+
add more lp tokens
119+
</SubmitButton>
120+
121+
<SubmitButton
122+
className={"liquidity__withdraw btn btn-secondary btn-lg w-100"}
123+
disabled={!gt(rewardBalance, 0)}
124+
onSubmitAction={(awaitingPromise) =>
125+
withdrawLiquidityRewards(liquidityPairContractName, awaitingPromise)
126+
}
127+
>
128+
withdraw all
129+
</SubmitButton>
130+
{gt(rewardBalance, 0) && (
131+
<div className={"text-validation text-center"}>
132+
Withdraw includes rewards and principal
133+
</div>
134+
)}
135+
</Card>
136+
)
137+
}
138+
139+
export default LiquidityRewardCard

solidity/dashboard/src/components/PageWrapper.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Header from "./Header"
44
import { renderPage } from "./Routing"
55
import { isEmptyArray } from "../utils/array.utils"
66

7-
const PageWrapper = ({ title, routes, children, headerClassName = "" }) => {
7+
const PageWrapper = ({ title, routes, children, headerClassName = "", newPage = false }) => {
88
const hasRoutes = !isEmptyArray(routes)
99

1010
return (
@@ -13,6 +13,7 @@ const PageWrapper = ({ title, routes, children, headerClassName = "" }) => {
1313
title={title}
1414
subLinks={hasRoutes ? routes.map((_) => _.route) : []}
1515
className={headerClassName}
16+
newPage={newPage}
1617
/>
1718
<main>
1819
{children}

0 commit comments

Comments
 (0)