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

Migrator Tool for Convex Positions #58

Closed
wants to merge 8 commits into from
Closed
Changes from 1 commit
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
Next Next commit
migrate cvx positions
jarbacoa committed Mar 17, 2022
commit c5f42bbc5f0780cb0ffea0fc7786a5c1172332ae
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ import { USDPricedFuseAsset } from "utils/fetchFusePoolData"
import { InfoIcon } from "@chakra-ui/icons"
import AppLink from "components/shared/AppLink"
import { CTokenAvatarGroup } from "components/shared/Icons/CTokenIcon"
import { eligibleTokens, tokenInfo } from "constants/convex"
import { eligibleTokens, CONVEX_CTOKEN_INFO } from "constants/convex"

export const PluginRewardsModal = ({
market,
@@ -61,10 +61,10 @@ export const PluginRewardsModal = ({
<InfoIcon size="15px" />
<Text>This market streams
<CTokenAvatarGroup tokenAddresses={rewardTokens} popOnHover={false} /> rewards
from the <b>{tokenInfo[market.underlyingSymbol].convexPoolName}</b> Convex pool
to suppliers of <b>{tokenInfo[market.underlyingSymbol].curvePoolName}</b> Curve LPs. </Text>
{/* <Text fontSize="sm"> Deposit your {tokenInfo[market.underlyingSymbol].curvePoolName} Curve LP tokens into Fuse to borrow against it while earning all the same rewards from Convex.</Text> */}
{/* <Text py={1}>View reward rates for <b>{tokenInfo[market.underlyingSymbol].convexPoolName}</b> on Convex </Text> */}
from the <b>{CONVEX_CTOKEN_INFO[market.underlyingSymbol].convexPoolName}</b> Convex pool
to suppliers of <b>{CONVEX_CTOKEN_INFO[market.underlyingSymbol].curvePoolName}</b> Curve LPs. </Text>
{/* <Text fontSize="sm"> Deposit your {CONVEX_CTOKEN_INFO[market.underlyingSymbol].curvePoolName} Curve LP tokens into Fuse to borrow against it while earning all the same rewards from Convex.</Text> */}
{/* <Text py={1}>View reward rates for <b>{CONVEX_CTOKEN_INFO[market.underlyingSymbol].convexPoolName}</b> on Convex </Text> */}
</VStack>
{/* </AppLink> */}

@@ -73,17 +73,17 @@ export const PluginRewardsModal = ({
Info
</Heading>

<InfoPairs title="Curve Pool" link={tokenInfo[market.underlyingSymbol].curvePoolLink} address={''} />
<InfoPairs title="Curve LP Token" address={tokenInfo[market.underlyingSymbol].lpToken} />
<InfoPairs title="ERC4626 Plugin" address={tokenInfo[market.underlyingSymbol].plugin} />
<InfoPairs title="Curve Pool" link={CONVEX_CTOKEN_INFO[market.underlyingSymbol].curvePoolLink} address={''} />
<InfoPairs title="Curve LP Token" address={CONVEX_CTOKEN_INFO[market.underlyingSymbol].lpToken} />
<InfoPairs title="ERC4626 Plugin" address={CONVEX_CTOKEN_INFO[market.underlyingSymbol].plugin} />

</Flex>
}
</ModalBody>
<ModalFooter mt={2}>
<AppLink isExternal={true} href="https://www.convexfinance.com/stake">
<Button colorScheme='white' minW="100%">
View rates for {' '} <Text mx={1} fontWeight={"bold"}>{tokenInfo[market.underlyingSymbol].convexPoolName}</Text> {' '} on Convex
View rates for {' '} <Text mx={1} fontWeight={"bold"}>{CONVEX_CTOKEN_INFO[market.underlyingSymbol].convexPoolName}</Text> {' '} on Convex
</Button>
</AppLink>
</ModalFooter>
28 changes: 28 additions & 0 deletions src/components/shared/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -7,6 +7,14 @@ import { useMemo, useState, useEffect } from "react";
import NewHeader from "../Header2/NewHeader";
import Footer from "./Footer";

import { Button, Image } from "@chakra-ui/react"

//CVX
import { useAccountBalances } from "context/BalancesContext"
import { useDisclosure } from "@chakra-ui/react";
import CVXMigrateModal from "components/pages/Fuse/Modals/CVXMigrateModal";



const Layout = ({ children }) => {
const { chainId } = useRari()
@@ -37,6 +45,16 @@ const Layout = ({ children }) => {
return () => document.removeEventListener("keydown", handler);
}, []);

const [_, __, cvxBalances] = useAccountBalances()
const hasCvxBalances = !!Object.keys(cvxBalances ?? {}).length
const { isOpen, onOpen, onClose } = useDisclosure()

console.log({cvxBalances})

useEffect(() => {
console.log({ hasCvxBalances })
if (!!hasCvxBalances) onOpen()
}, [hasCvxBalances])

return (
<Column
@@ -62,11 +80,21 @@ const Layout = ({ children }) => {

<NewHeader />
{children}
{!!hasCvxBalances && <CVXMigrateModal isOpen={isOpen} onClose={onClose} />}
{!!hasCvxBalances && <ConvexModalButton onOpen={onOpen} />}
<Footer />
</Column>
);
};


const ConvexModalButton = ({onOpen}: {onOpen: any}) => {
return (
<Button onClick={onOpen} position="fixed" bottom={0} right={0} m={5}>
<Image src="/static/icons/convex.svg" h="100%" w="100%"/>
</Button>
)
}


export default Layout;
1 change: 0 additions & 1 deletion src/components/shared/SwitchNetworkMenu.tsx
Original file line number Diff line number Diff line change
@@ -86,7 +86,6 @@ const SwitchNetworkMenu: React.FC = () => {
// If user presses meta key or control key + slash they will toggle the private allocation claim mode.
useEffect(() => {
const handler = (e: KeyboardEvent) => {
console.log(e.code)
if (e.code === "Slash") {
e.preventDefault();
setDevMode(true);
7 changes: 6 additions & 1 deletion src/constants/convex.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const eligibleTokens = ["FRAX3CRV-f", "steCRV", "UST_whv23CRV-f", "crv3crypto", "D3-f", "FEI3CRV3CRV-f", "alUSD3CRV-f"]

export const tokenInfo: PluginCTokenInfoType = {
export const CONVEX_CTOKEN_INFO: PluginCTokenInfoType = {
"FRAX3CRV-f": {
"cToken": "0x2ec70d3Ff3FD7ac5c2a72AAA64A398b6CA7428A5",
"plugin": "0xd88e89ac6a0859e9b91078cb2a183a36ba6c8933",
@@ -89,3 +89,8 @@ type PluginCTokenInfoType = {
}

export const POOL_156_COMPTROLLER = "0x07cd53380FE9B2a5E64099591b498c73F0EfaA66"


export const SUPPORTED_CONVEX_LPS = [

]
15 changes: 9 additions & 6 deletions src/context/BalancesContext.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@

import { StakedConvexBalancesMap, useStakedConvexBalances } from "hooks/convex/useStakedConvexBalances";
import { useTokenBalances } from "hooks/useTokenBalance";
import { SubgraphUnderlyingAsset } from "pages/api/explore";
import { createContext, useContext, ReactNode, useMemo } from "react";
import { createContext, useContext, ReactNode, useMemo, useEffect } from "react";
import { queryAllUnderlyingAssets } from "services/gql";
import useSWR from "swr";
import { UnderlyingAsset } from "types/tokens";
import { useRari } from "./RariContext";

export const BalancesContext = createContext<any | undefined>(undefined);
@@ -35,6 +36,7 @@ export const BalancesContextProvider = ({
);

const tokenBalances = useTokenBalances(tokenAddresses);
const cvxBalances = useStakedConvexBalances()

const balances: {
[address: string]: number;
@@ -54,15 +56,16 @@ export const BalancesContextProvider = ({
return ret;
}, [tokenBalances, isAuthed]);


return (
<BalancesContext.Provider value={balances}>
<BalancesContext.Provider value={{ balances, cvxBalances }}>
{children}
</BalancesContext.Provider>
);
};

export const useAccountBalances = (): [any, string[]] => {
const balances = useContext(BalancesContext);
export const useAccountBalances = (): [any, string[], StakedConvexBalancesMap] => {
const { balances, cvxBalances } = useContext(BalancesContext);

const significantTokens: string[] = useMemo(
() =>
@@ -80,5 +83,5 @@ export const useAccountBalances = (): [any, string[]] => {
);
}

return [balances, significantTokens];
return [balances, significantTokens, cvxBalances];
};
4 changes: 4 additions & 0 deletions src/context/RariContext.tsx
Original file line number Diff line number Diff line change
@@ -131,6 +131,10 @@ export const RariProvider = ({ children }: { children: ReactNode }) => {
const queryClient = useQueryClient();
const { t } = useTranslation();

useEffect(() => {
// if (!!requestedAddress) setAddress(requestedAddress as string)
}, [requestedAddress])

useEffect(() => {
//toast on brave users
if(typeof navigator !== 'object') return
1 change: 1 addition & 0 deletions src/contracts/abi/ConvexBaseRewardPool.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"inputs":[{"internalType":"uint256","name":"pid_","type":"uint256"},{"internalType":"address","name":"stakingToken_","type":"address"},{"internalType":"address","name":"rewardToken_","type":"address"},{"internalType":"address","name":"operator_","type":"address"},{"internalType":"address","name":"rewardManager_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"address","name":"_reward","type":"address"}],"name":"addExtraReward","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"clearExtraRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"donate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"duration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"extraRewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"extraRewardsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReward","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_claimExtras","type":"bool"}],"name":"getReward","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"historicalRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newRewardRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewards","type":"uint256"}],"name":"queueNewRewards","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"queuedRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_for","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stakeFor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"claim","type":"bool"}],"name":"withdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"claim","type":"bool"}],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"claim","type":"bool"}],"name":"withdrawAllAndUnwrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"claim","type":"bool"}],"name":"withdrawAndUnwrap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
4 changes: 2 additions & 2 deletions src/hooks/convex/useConvexPoolSuppliedCTokens.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { tokenInfo } from 'constants/convex';
import { CONVEX_CTOKEN_INFO } from 'constants/convex';
import { useRari } from 'context/RariContext'
import { BigNumber } from 'ethers';
import { Interface } from 'ethers/lib/utils';
@@ -11,7 +11,7 @@ export const useConvexPoolSuppliedCTokens = (comptrollerAddress: string) => {

const { data: suppliedMarkets } = useQuery(`Pool ${comptrollerAddress} CTokens User ${address}`, async () => {

const markets = Object.values(tokenInfo).map((value => value.cToken))
const markets = Object.values(CONVEX_CTOKEN_INFO).map((value => value.cToken))

const IComptroller = new Interface(JSON.parse(
fuse.compoundContracts["contracts/CErc20Delegate.sol:CErc20Delegate"].abi
61 changes: 61 additions & 0 deletions src/hooks/convex/useStakedConvexBalances.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { providers } from "@0xsequence/multicall";
import { useRari } from "context/RariContext";
import { useQuery } from "react-query";

import BaseRewardPoolABI from "contracts/abi/ConvexBaseRewardPool.json"
import { CONVEX_CTOKEN_INFO } from "constants/convex";
import { Contract } from "ethers";
import { BigNumber } from "ethers";

export type StakedConvexBalancesMap = {
[cToken: string]: {
balance: BigNumber,
baseRewardsPool: string
}
}

export const useStakedConvexBalances = (): StakedConvexBalancesMap => {
const { fuse, address, isAuthed } = useRari();
const multiCallProvider = new providers.MulticallProvider(fuse.provider)
const { data: stakedConvexBalances } = useQuery<StakedConvexBalancesMap | undefined>(
' staked convex balances for ' + address,
async () => {
if (!isAuthed) return undefined

let map: StakedConvexBalancesMap = {}

await Promise.all(Object.values(CONVEX_CTOKEN_INFO)
.map(c => ({ baseRewardsPool: c.rewardsContract, cToken: c.cToken }))
.map(({ baseRewardsPool, cToken }) => {
let contract = new Contract(baseRewardsPool, BaseRewardPoolABI as any, multiCallProvider)
return contract.balanceOf(address)
.then((balance: BigNumber) => {
if (!balance.isZero()) {
map[cToken] = {
balance,
baseRewardsPool,
}
}
})
.catch((_err: any) => { })
}
))

console.log({map})

return map
},
{
enabled: !!address ? true : false,
refetchOnMount: false,
refetchOnWindowFocus: false,
}
)

// const hasBalances =

return stakedConvexBalances ?? {}

}


Loading