From 423ec54731316cd1fa17d2d772f9bd0e0a91b3b3 Mon Sep 17 00:00:00 2001 From: amatureApe Date: Tue, 12 Sep 2023 18:44:08 -0700 Subject: [PATCH 01/84] init --- pages/vepop.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 98964fe..6ea6d8e 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -55,6 +55,7 @@ export default function VePOP() { const [votes, setVotes] = useState(gauges?.map(gauge => 0)); const [totalVotes, setTotalVotes] = useState(0); + const [alreadyVoted, setAlreadyVoted] = useState(false); const [showLockModal, setShowLockModal] = useState(false); const [showMangementModal, setShowMangementModal] = useState(false); @@ -75,6 +76,8 @@ export default function VePOP() { const { write: claimOPop = noOp } = useClaimOPop(OPOP_MINTER, gaugeRewards?.amounts?.filter(gauge => Number(gauge.amount) > 0).map(gauge => gauge.address)); + console.log("PING", gauges); + function handleVotes(val: number, index: number) { setVotes((prevVotes) => { const updatedVotes = [...prevVotes]; From 725bbfdb37cd08ade7c6b778750d4596fdb9bd37 Mon Sep 17 00:00:00 2001 From: amatureApe Date: Wed, 13 Sep 2023 03:08:30 -0700 Subject: [PATCH 02/84] fix exercise oPOP overflow --- components/vepop/modals/oPop/OPopModal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/vepop/modals/oPop/OPopModal.tsx b/components/vepop/modals/oPop/OPopModal.tsx index 2849880..0aae5dc 100644 --- a/components/vepop/modals/oPop/OPopModal.tsx +++ b/components/vepop/modals/oPop/OPopModal.tsx @@ -10,7 +10,7 @@ import { getVeAddresses } from "lib/utils/addresses"; import { useAllowance } from "lib/Erc20/hooks"; import { approveBalance } from "hooks/useApproveBalance"; import { Address } from "wagmi"; -import { utils } from "ethers"; +import { utils, BigNumber } from "ethers"; const { BalancerOracle: OPOP_ORACLE, WETH: WETH, oPOP: OPOP } = getVeAddresses(); @@ -43,7 +43,7 @@ export default function OPopModal({ show }: { show: [boolean, Function] }): JSX. if (chain.id !== Number(5)) switchNetwork?.(Number(5)); if (needAllowance) await approveBalance(WETH, OPOP); - exerciseOPop(OPOP, account, utils.parseEther(String(amount)).toString(), (utils.parseEther(maxPaymentAmount.toFixed(18)).toNumber() * 1e4).toString()); // Temp values for Goerli + exerciseOPop(OPOP, account, utils.parseEther(String(amount)).toString(), utils.parseEther(maxPaymentAmount.toFixed(18)).mul(BigNumber.from("10000")).toString()); setShowModal(false); } From 4a218678055f706f1106dc3dabee7209876f91cf Mon Sep 17 00:00:00 2001 From: amatureApe Date: Wed, 13 Sep 2023 05:20:04 -0700 Subject: [PATCH 03/84] useLastUserVotes hook --- hooks/useLastUserVotes.ts | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 hooks/useLastUserVotes.ts diff --git a/hooks/useLastUserVotes.ts b/hooks/useLastUserVotes.ts new file mode 100644 index 0000000..05f8d87 --- /dev/null +++ b/hooks/useLastUserVotes.ts @@ -0,0 +1,54 @@ +import { ethers, BigNumber } from 'ethers'; +import { useContractReads, useAccount } from 'wagmi'; +import { getVeAddresses } from 'lib/utils/addresses'; +import useGauges from "lib/Gauges/useGauges"; +import { Pop } from 'lib/types'; + +const DAYS = 24 * 60 * 60; + +const { GaugeController: GAUGE_CONTROLLER, +} = getVeAddresses() + +// const GaugeControllerContract = { +// address: GAUGE_CONTROLLER, +// abi: 'last_user_vote(address,address)(uint256)', +// } + +function useLastUserVotes() { + const user = useAccount(); + const { data: gauges = [] } = useGauges({ address: GAUGE_CONTROLLER, chainId: 5 }) + + const { data: lastUserVotes } = useContractReads({ + contracts: Array(gauges).fill(undefined).map((contract) => { + return { + address, + abi: abiController, + functionName: "last_user_votes", + chainId: 5, + args: [user, contract] + } + }), + }) as Pop.HookResult + + const checkTimestampsExceedLimit = async () => { + const provider = new ethers.providers.JsonRpcProvider(process.env.NEXT_PUBLIC_ALCHEMY_API_KEY); + const currentBlock = await provider.getBlock('latest'); + const limitTimestamp = currentBlock.timestamp - (DAYS * 10); + + return lastUserVotes.some(voteTimestamp => + voteTimestamp.gt(BigNumber.from(limitTimestamp)) + ); + }; + + return checkTimestampsExceedLimit; +} + +const abiController = [ + { + "stateMutability": "view", + "type": "function", + "name": "last_user_vote", + "inputs": [{ "name": "arg0", "type": "address" }, { "name": "arg1", "type": "address" }], + "outputs": [{ "name": "", "type": "uint256" }] + } +] \ No newline at end of file From 2a73d3702139c33fe4e8be31ab75a563754fcdc2 Mon Sep 17 00:00:00 2001 From: amatureApe Date: Wed, 13 Sep 2023 05:37:45 -0700 Subject: [PATCH 04/84] cleanup --- hooks/useLastUserVotes.ts | 40 +++++++++++++-------------------------- pages/vepop.tsx | 4 +++- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/hooks/useLastUserVotes.ts b/hooks/useLastUserVotes.ts index 05f8d87..7198cd7 100644 --- a/hooks/useLastUserVotes.ts +++ b/hooks/useLastUserVotes.ts @@ -1,46 +1,32 @@ import { ethers, BigNumber } from 'ethers'; -import { useContractReads, useAccount } from 'wagmi'; +import { useContractReads } from 'wagmi'; import { getVeAddresses } from 'lib/utils/addresses'; -import useGauges from "lib/Gauges/useGauges"; import { Pop } from 'lib/types'; const DAYS = 24 * 60 * 60; -const { GaugeController: GAUGE_CONTROLLER, -} = getVeAddresses() - -// const GaugeControllerContract = { -// address: GAUGE_CONTROLLER, -// abi: 'last_user_vote(address,address)(uint256)', -// } - -function useLastUserVotes() { - const user = useAccount(); - const { data: gauges = [] } = useGauges({ address: GAUGE_CONTROLLER, chainId: 5 }) - - const { data: lastUserVotes } = useContractReads({ - contracts: Array(gauges).fill(undefined).map((contract) => { +export default async function useLastUserVotes({ addresses, chainId, account }: { addresses: string[], chainId: number, account: string }): { data: boolean, status: string } { + const { data, status } = useContractReads({ + contracts: Array(addresses).fill(undefined).map((contract) => { return { address, abi: abiController, functionName: "last_user_votes", - chainId: 5, - args: [user, contract] + chainId: chainId, + args: [account, contract] } }), }) as Pop.HookResult - const checkTimestampsExceedLimit = async () => { - const provider = new ethers.providers.JsonRpcProvider(process.env.NEXT_PUBLIC_ALCHEMY_API_KEY); - const currentBlock = await provider.getBlock('latest'); - const limitTimestamp = currentBlock.timestamp - (DAYS * 10); + const provider = new ethers.providers.JsonRpcProvider(process.env.NEXT_PUBLIC_ALCHEMY_API_KEY); + const currentBlock = await provider.getBlock('latest'); + const limitTimestamp = currentBlock.timestamp - (DAYS * 10); - return lastUserVotes.some(voteTimestamp => - voteTimestamp.gt(BigNumber.from(limitTimestamp)) - ); - }; + const alreadyVoted = data.some(voteTimestamp => + voteTimestamp.gt(BigNumber.from(limitTimestamp)) + ); - return checkTimestampsExceedLimit; + return { data: alreadyVoted, status: status }; } const abiController = [ diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 6ea6d8e..2a4d472 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -25,6 +25,7 @@ import { useClaimOPop } from "lib/OPop/useClaimOPop"; import { showSuccessToast, showErrorToast } from "lib/Toasts"; import { getVeAddresses } from "lib/utils/addresses"; import { WalletIcon } from "@heroicons/react/24/outline"; +import { useLastUserVotes } from "hooks/useLastUserVotes"; const { BalancerPool: POP_LP, @@ -52,10 +53,11 @@ export default function VePOP() { const { data: gauges } = useGauges({ address: GAUGE_CONTROLLER, chainId: 5 }) const { data: gaugeRewards } = useClaimableOPop({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) + const { data: alreadyVoted } = useLastUserVotes({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) const [votes, setVotes] = useState(gauges?.map(gauge => 0)); const [totalVotes, setTotalVotes] = useState(0); - const [alreadyVoted, setAlreadyVoted] = useState(false); + const [canVote, setCanVote] = useState(false); const [showLockModal, setShowLockModal] = useState(false); const [showMangementModal, setShowMangementModal] = useState(false); From 789f60117d0edff7faa5580ba9912d9aaec0d123 Mon Sep 17 00:00:00 2001 From: amatureApe Date: Wed, 13 Sep 2023 05:48:20 -0700 Subject: [PATCH 05/84] cleanup wip --- hooks/useLastUserVotes.ts | 9 ++++----- pages/vepop.tsx | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hooks/useLastUserVotes.ts b/hooks/useLastUserVotes.ts index 7198cd7..c92d9ad 100644 --- a/hooks/useLastUserVotes.ts +++ b/hooks/useLastUserVotes.ts @@ -1,19 +1,18 @@ import { ethers, BigNumber } from 'ethers'; import { useContractReads } from 'wagmi'; -import { getVeAddresses } from 'lib/utils/addresses'; import { Pop } from 'lib/types'; const DAYS = 24 * 60 * 60; -export default async function useLastUserVotes({ addresses, chainId, account }: { addresses: string[], chainId: number, account: string }): { data: boolean, status: string } { +export async function getLastUserVotes({ addresses, chainId, account }: { addresses: string[], chainId: number, account: string }): Promise<{ data: boolean, status: string }> { const { data, status } = useContractReads({ - contracts: Array(addresses).fill(undefined).map((contract) => { + contracts: addresses.map((address) => { return { address, abi: abiController, - functionName: "last_user_votes", + functionName: "last_user_vote", chainId: chainId, - args: [account, contract] + args: [account, address] } }), }) as Pop.HookResult diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 2a4d472..4ad4c35 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -25,7 +25,7 @@ import { useClaimOPop } from "lib/OPop/useClaimOPop"; import { showSuccessToast, showErrorToast } from "lib/Toasts"; import { getVeAddresses } from "lib/utils/addresses"; import { WalletIcon } from "@heroicons/react/24/outline"; -import { useLastUserVotes } from "hooks/useLastUserVotes"; +import { getLastUserVotes } from "hooks/useLastUserVotes"; const { BalancerPool: POP_LP, @@ -53,7 +53,6 @@ export default function VePOP() { const { data: gauges } = useGauges({ address: GAUGE_CONTROLLER, chainId: 5 }) const { data: gaugeRewards } = useClaimableOPop({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) - const { data: alreadyVoted } = useLastUserVotes({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) const [votes, setVotes] = useState(gauges?.map(gauge => 0)); const [totalVotes, setTotalVotes] = useState(0); @@ -79,6 +78,7 @@ export default function VePOP() { const { write: claimOPop = noOp } = useClaimOPop(OPOP_MINTER, gaugeRewards?.amounts?.filter(gauge => Number(gauge.amount) > 0).map(gauge => gauge.address)); console.log("PING", gauges); + console.log("PING0", getLastUserVotes({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account })) function handleVotes(val: number, index: number) { setVotes((prevVotes) => { From b14c1815fa17b86ae23ce1ce13ccf7bade6af3f4 Mon Sep 17 00:00:00 2001 From: amatureApe Date: Wed, 13 Sep 2023 06:24:53 -0700 Subject: [PATCH 06/84] remove async --- hooks/useLastUserVotes.ts | 11 +++++------ pages/vepop.tsx | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/hooks/useLastUserVotes.ts b/hooks/useLastUserVotes.ts index c92d9ad..b981831 100644 --- a/hooks/useLastUserVotes.ts +++ b/hooks/useLastUserVotes.ts @@ -1,14 +1,15 @@ -import { ethers, BigNumber } from 'ethers'; +import { BigNumber } from 'ethers'; import { useContractReads } from 'wagmi'; import { Pop } from 'lib/types'; const DAYS = 24 * 60 * 60; -export async function getLastUserVotes({ addresses, chainId, account }: { addresses: string[], chainId: number, account: string }): Promise<{ data: boolean, status: string }> { +export function useLastUserVotes({ addresses, chainId, account }: { addresses: string[], chainId: number, account: string }): { data: boolean, status: string } { + console.log("DING"); const { data, status } = useContractReads({ contracts: addresses.map((address) => { return { - address, + address: address, abi: abiController, functionName: "last_user_vote", chainId: chainId, @@ -17,9 +18,7 @@ export async function getLastUserVotes({ addresses, chainId, account }: { addres }), }) as Pop.HookResult - const provider = new ethers.providers.JsonRpcProvider(process.env.NEXT_PUBLIC_ALCHEMY_API_KEY); - const currentBlock = await provider.getBlock('latest'); - const limitTimestamp = currentBlock.timestamp - (DAYS * 10); + const limitTimestamp = Math.floor(Date.now() / 1000) - (DAYS * 10); const alreadyVoted = data.some(voteTimestamp => voteTimestamp.gt(BigNumber.from(limitTimestamp)) diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 4ad4c35..4b09629 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -25,7 +25,7 @@ import { useClaimOPop } from "lib/OPop/useClaimOPop"; import { showSuccessToast, showErrorToast } from "lib/Toasts"; import { getVeAddresses } from "lib/utils/addresses"; import { WalletIcon } from "@heroicons/react/24/outline"; -import { getLastUserVotes } from "hooks/useLastUserVotes"; +import { useLastUserVotes } from "hooks/useLastUserVotes"; const { BalancerPool: POP_LP, @@ -77,8 +77,8 @@ export default function VePOP() { const { write: claimOPop = noOp } = useClaimOPop(OPOP_MINTER, gaugeRewards?.amounts?.filter(gauge => Number(gauge.amount) > 0).map(gauge => gauge.address)); - console.log("PING", gauges); - console.log("PING0", getLastUserVotes({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account })) + // console.log("PING", gauges); + console.log("PING0", useLastUserVotes({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account })) function handleVotes(val: number, index: number) { setVotes((prevVotes) => { From 8f0f4c8d0f32cece0f11be5a334a0c42876977ef Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 14 Sep 2023 10:49:15 +0200 Subject: [PATCH 07/84] canVote --- components/vepop/Gauge.tsx | 12 +- .../Gauges/useHasAlreadyVoted.ts | 18 +- pages/vepop.tsx | 230 +++++++++--------- 3 files changed, 132 insertions(+), 128 deletions(-) rename hooks/useLastUserVotes.ts => lib/Gauges/useHasAlreadyVoted.ts (56%) diff --git a/components/vepop/Gauge.tsx b/components/vepop/Gauge.tsx index a5afc2f..f43bf9a 100644 --- a/components/vepop/Gauge.tsx +++ b/components/vepop/Gauge.tsx @@ -18,7 +18,7 @@ import useGaugeWeights from "lib/Gauges/useGaugeWeights"; const { GaugeController: GAUGE_CONTROLLER } = getVeAddresses(); -export default function Gauge({ gauge, index, votes, handleVotes, veBal }: { gauge: Gauge, index: number, votes: number[], handleVotes: Function, veBal: BigNumberWithFormatted }): JSX.Element { +export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote }: { gauge: Gauge, index: number, votes: number[], handleVotes: Function, veBal: BigNumberWithFormatted, canVote: boolean }): JSX.Element { const { address: account } = useAccount() const { data: token } = useVaultToken(gauge.vault, gauge.chainId); const { data: adapter } = useAdapterToken(gauge.vault, gauge.chainId); @@ -82,24 +82,24 @@ export default function Gauge({ gauge, index, votes, handleVotes, veBal }: { gau

Vote

- + <Title level={2} fontWeight="font-normal" as="span" className={`mr-1 ${canVote ? "text-primary" : "text-secondaryLight"}`}> {votes[index] / 100 || 0} %
onChange(val)} + onChange={canVote ? (val) => onChange(val) : () => { }} max={10000} />
diff --git a/hooks/useLastUserVotes.ts b/lib/Gauges/useHasAlreadyVoted.ts similarity index 56% rename from hooks/useLastUserVotes.ts rename to lib/Gauges/useHasAlreadyVoted.ts index b981831..a1b620b 100644 --- a/hooks/useLastUserVotes.ts +++ b/lib/Gauges/useHasAlreadyVoted.ts @@ -1,27 +1,31 @@ import { BigNumber } from 'ethers'; -import { useContractReads } from 'wagmi'; import { Pop } from 'lib/types'; +import { getVeAddresses } from 'lib/utils/addresses'; +import { Address, useContractReads } from 'wagmi'; const DAYS = 24 * 60 * 60; -export function useLastUserVotes({ addresses, chainId, account }: { addresses: string[], chainId: number, account: string }): { data: boolean, status: string } { - console.log("DING"); +const { GaugeController: GAUGE_CONTROLLER } = getVeAddresses() + +export function useHasAlreadyVoted({ addresses, chainId, account }: { addresses: string[], chainId: number, account: string }): { data: boolean, status: string } { const { data, status } = useContractReads({ - contracts: addresses.map((address) => { + contracts: addresses?.map((address) => { return { - address: address, + address: GAUGE_CONTROLLER as Address, abi: abiController, functionName: "last_user_vote", chainId: chainId, args: [account, address] } }), + enabled: !!account && addresses?.length > 0, }) as Pop.HookResult const limitTimestamp = Math.floor(Date.now() / 1000) - (DAYS * 10); + console.log(data) - const alreadyVoted = data.some(voteTimestamp => - voteTimestamp.gt(BigNumber.from(limitTimestamp)) + const alreadyVoted = data?.some(voteTimestamp => + voteTimestamp?.gt(BigNumber.from(limitTimestamp)) ); return { data: alreadyVoted, status: status }; diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 4b09629..547a9d8 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -25,7 +25,7 @@ import { useClaimOPop } from "lib/OPop/useClaimOPop"; import { showSuccessToast, showErrorToast } from "lib/Toasts"; import { getVeAddresses } from "lib/utils/addresses"; import { WalletIcon } from "@heroicons/react/24/outline"; -import { useLastUserVotes } from "hooks/useLastUserVotes"; +import { useHasAlreadyVoted } from "lib/Gauges/useHasAlreadyVoted"; const { BalancerPool: POP_LP, @@ -56,7 +56,8 @@ export default function VePOP() { const [votes, setVotes] = useState(gauges?.map(gauge => 0)); const [totalVotes, setTotalVotes] = useState(0); - const [canVote, setCanVote] = useState(false); + const { data: hasAlreadyVoted } = useHasAlreadyVoted({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) + const canVote = account && Number(veBal?.value) > 0 && !hasAlreadyVoted const [showLockModal, setShowLockModal] = useState(false); const [showMangementModal, setShowMangementModal] = useState(false); @@ -77,9 +78,6 @@ export default function VePOP() { const { write: claimOPop = noOp } = useClaimOPop(OPOP_MINTER, gaugeRewards?.amounts?.filter(gauge => Number(gauge.amount) > 0).map(gauge => gauge.address)); - // console.log("PING", gauges); - console.log("PING0", useLastUserVotes({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account })) - function handleVotes(val: number, index: number) { setVotes((prevVotes) => { const updatedVotes = [...prevVotes]; @@ -127,122 +125,124 @@ export default function VePOP() { } } - return ( - - - -
-
-
-

- Lock 20WETH-80POP for vePOP, Rewards, and Voting Power -

-

- Vote with your vePOP below to influence how much $oPOP each pool will receive. Your vote will persist until you change it and editing a pool can only be done once every 10 days. -

-
- Mint the token needed for testing on Goerli here:
- POP
- WETH
- BalancerPool -
-
-
- -
-
-

vePOP

- -

My POP LP

-

{popLpBal?.formatted}

-
- -

My Locked POP LP

-

{lockedBal ? formatAndRoundBigNumber(lockedBal?.amount, 18) : ""}

-
- -

Locked Until

-

{lockedBal && lockedBal?.end.toString() !== "0" ? new Date(Number(lockedBal?.end) * 1000).toLocaleDateString() : "-"}

-
- -

My vePOP

-

{veBal?.formatted}

-
- -

Voting period ends

-

{votingPeriodEnd()[0]}d : {votingPeriodEnd()[1]}h: {votingPeriodEnd()[2]}m

-
-
- setShowLockModal(true)} disabled={Number(veBal?.value) > 0} /> - setShowMangementModal(true)} disabled={Number(veBal?.value) === 0} /> -
-
- -
-

Total vePOP Rewards

- -

APR

-

? %

-
- -

Claimable oPOP

-

{(Number(gaugeRewards?.total) / 1e18).toFixed(2)}

-
-
-
-

My oPOP

-
-

- {(Number(oPopBal?.value) / 1e18).toFixed(2)} - + {(!votes || votes.length === 0) ? <> + : <> + + + +

+
+
+

+ Lock 20WETH-80POP for vePOP, Rewards, and Voting Power +

+

+ Vote with your vePOP below to influence how much $oPOP each pool will receive. Your vote will persist until you change it and editing a pool can only be done once every 10 days.

-

($ {formatNumber((Number(oPopBal?.value) / 1e18) * (Number(oPopPrice?.value) / 1e18))})

+
+ Mint the token needed for testing on Goerli here:
+ POP
+ WETH
+ BalancerPool +
+
+ +
+
+

vePOP

+ +

My POP LP

+

{popLpBal?.formatted}

+
+ +

My Locked POP LP

+

{lockedBal ? formatAndRoundBigNumber(lockedBal?.amount, 18) : ""}

+
+ +

Locked Until

+

{lockedBal && lockedBal?.end.toString() !== "0" ? new Date(Number(lockedBal?.end) * 1000).toLocaleDateString() : "-"}

+
+ +

My vePOP

+

{veBal?.formatted}

+
+ +

Voting period ends

+

{votingPeriodEnd()[0]}d : {votingPeriodEnd()[1]}h: {votingPeriodEnd()[2]}m

+
+
+ setShowLockModal(true)} disabled={Number(veBal?.value) > 0} /> + setShowMangementModal(true)} disabled={Number(veBal?.value) === 0} /> +
+
+ +
+

Total vePOP Rewards

+ +

APR

+

? %

+
+ +

Claimable oPOP

+

{(Number(gaugeRewards?.total) / 1e18).toFixed(2)}

+
+
+
+

My oPOP

+
+

+ {(Number(oPopBal?.value) / 1e18).toFixed(2)} + +

+

($ {formatNumber((Number(oPopBal?.value) / 1e18) * (Number(oPopPrice?.value) / 1e18))})

+
+
+
+ setShowOPopModal(true)} disabled={Number(oPopBal?.value) === 0} /> + claimOPop()} disabled={Number(gaugeRewards?.total) === 0} /> +
+
+
+ +
+ {gauges?.length > 0 ? gauges.map((gauge, index) => + + ) + :

Loading Gauges...

+ } +
+ +
+

Gauge Voting not available on mobile.

+
+ +
+ {canVote && <> +
+

+ Voting power used: + { + veBal && veBal.value + ? (votes?.reduce((a, b) => a + b, 0) / 100).toFixed(2) + : "0" + }% + +

+ +
+ }
-
- setShowOPopModal(true)} disabled={Number(oPopBal?.value) === 0} /> - claimOPop()} disabled={Number(gaugeRewards?.total) === 0} /> -
+
-
- -
- {gauges?.length > 0 ? gauges.map((gauge, index) => - - ) - :

Loading Gauges...

- } -
- -
-

Gauge Voting not available on mobile.

-
- -
- {account &&
-

- Voting power used: - { - veBal && veBal.value - ? (votes?.reduce((a, b) => a + b, 0) / 100).toFixed(2) - : "0" - }% - -

- - - -
} -
- -
+ }
) } From 8469cdd28262b03e9e3b8857a6ea8168d21d6f6f Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 19 Sep 2023 13:29:58 +0200 Subject: [PATCH 08/84] fixed build issue --- components/vepop/Gauge.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/vepop/Gauge.tsx b/components/vepop/Gauge.tsx index 1286cbd..ef04a3e 100644 --- a/components/vepop/Gauge.tsx +++ b/components/vepop/Gauge.tsx @@ -40,7 +40,7 @@ export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote return (
@@ -83,7 +83,7 @@ export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote
- {/votes[index] / 100).toFixed() || 0} % + {(votes[index] / 100).toFixed() || 0} %
@@ -114,7 +114,7 @@ export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote
- } + } > {/* Accordion Content */}
From 024f1bfa045a5d2adefe88adec209b56e2e230b7 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 19 Sep 2023 16:20:42 +0200 Subject: [PATCH 09/84] fixed empty votes --- pages/vepop.tsx | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 547a9d8..f6862ba 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -54,8 +54,7 @@ export default function VePOP() { const { data: gauges } = useGauges({ address: GAUGE_CONTROLLER, chainId: 5 }) const { data: gaugeRewards } = useClaimableOPop({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) - const [votes, setVotes] = useState(gauges?.map(gauge => 0)); - const [totalVotes, setTotalVotes] = useState(0); + const [votes, setVotes] = useState([]); const { data: hasAlreadyVoted } = useHasAlreadyVoted({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) const canVote = account && Number(veBal?.value) > 0 && !hasAlreadyVoted @@ -63,6 +62,12 @@ export default function VePOP() { const [showMangementModal, setShowMangementModal] = useState(false); const [showOPopModal, setShowOPopModal] = useState(false); + useEffect(() => { + if (gauges?.length > 0, votes?.length === 0) { + setVotes(new Array(gauges.length).fill(0)); + } + }, [gauges, votes]) + function votingPeriodEnd(): number[] { const periodEnd = getVotePeriodEndTime(); const interval: Interval = { start: new Date(), end: periodEnd }; @@ -84,9 +89,8 @@ export default function VePOP() { const updatedTotalVotes = updatedVotes.reduce((a, b) => a + b, 0) - updatedVotes[index] + val; if (updatedTotalVotes <= 10000) { + // TODO should we adjust the val to the max possible value if it exceeds 10000? updatedVotes[index] = val; - setTotalVotes(updatedTotalVotes); - return updatedVotes; } return prevVotes; @@ -122,9 +126,9 @@ export default function VePOP() { .catch(error => { showErrorToast(error); }); - } } + return ( {(!votes || votes.length === 0) ? <> @@ -155,11 +159,11 @@ export default function VePOP() {

vePOP

My POP LP

-

{popLpBal?.formatted}

+

{popLpBal?.formatted || "0"}

My Locked POP LP

-

{lockedBal ? formatAndRoundBigNumber(lockedBal?.amount, 18) : ""}

+

{lockedBal ? formatAndRoundBigNumber(lockedBal?.amount, 18) : "0"}

Locked Until

@@ -167,7 +171,7 @@ export default function VePOP() {

My vePOP

-

{veBal?.formatted}

+

{veBal?.formatted || "0"}

Voting period ends

@@ -187,17 +191,21 @@ export default function VePOP() {

Claimable oPOP

-

{(Number(gaugeRewards?.total) / 1e18).toFixed(2)}

+

{gaugeRewards?.total ? (Number(gaugeRewards?.total) / 1e18).toFixed(2) : "0"}

My oPOP

- {(Number(oPopBal?.value) / 1e18).toFixed(2)} + {oPopBal?.value ? (Number(oPopBal?.value) / 1e18).toFixed(2) : "0"}

-

($ {formatNumber((Number(oPopBal?.value) / 1e18) * (Number(oPopPrice?.value) / 1e18))})

+

+ ($ {oPopPrice?.value && oPopBal?.value ? + formatNumber((Number(oPopBal?.value) / 1e18) * (Number(oPopPrice?.value) / 1e18)) : + "0"}) +

From 90476f97265b9796fd56ae097a5d15e4ba163cb0 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 19 Sep 2023 16:21:37 +0200 Subject: [PATCH 10/84] fixed hooks in gauges --- components/vepop/Gauge.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/vepop/Gauge.tsx b/components/vepop/Gauge.tsx index ef04a3e..6425e60 100644 --- a/components/vepop/Gauge.tsx +++ b/components/vepop/Gauge.tsx @@ -20,9 +20,9 @@ const { GaugeController: GAUGE_CONTROLLER } = getVeAddresses(); export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote }: { gauge: Gauge, index: number, votes: number[], handleVotes: Function, veBal: BigNumberWithFormatted, canVote: boolean }): JSX.Element { const { address: account } = useAccount() - const { data: token } = useVaultToken(gauge.vault, gauge.chainId); - const { data: adapter } = useAdapterToken(gauge.vault, gauge.chainId); - const vaultMetadata = useVaultMetadata(gauge.vault, gauge.chainId); + const { data: token } = useVaultToken({ vaultAddress: gauge.vault, chainId: gauge.chainId }); + const { data: adapter } = useAdapterToken({ vaultAddress: gauge.vault, chainId: gauge.chainId }); + const vaultMetadata = useVaultMetadata({ vaultAddress: gauge.vault, chainId: gauge.chainId }); const { data: weights } = useGaugeWeights({ address: gauge.address, account: account, chainId: gauge.chainId }) From 46fdcac74f8dc2eb2be8c66c69b877058383c53e Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 20 Sep 2023 12:21:00 +0200 Subject: [PATCH 11/84] added console logs --- lib/Gauges/useGauges.ts | 7 +++++++ pages/vepop.tsx | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/Gauges/useGauges.ts b/lib/Gauges/useGauges.ts index f716c73..0b90f03 100644 --- a/lib/Gauges/useGauges.ts +++ b/lib/Gauges/useGauges.ts @@ -9,6 +9,7 @@ export interface Gauge { } export default function useGauges({ address, chainId }: { address: string, chainId: number }): Pop.HookResult { + console.log({ address, chainId }) const { data: n_gauges } = useContractRead({ address, abi: abiController, @@ -16,6 +17,7 @@ export default function useGauges({ address, chainId }: { address: string, chain chainId, args: [] }) as { data: BigNumber, status: string } + console.log({ n_gauges }) const { data: gauges } = useContractReads({ contracts: Array(n_gauges?.toNumber()).fill(undefined).map((item, idx) => { @@ -29,6 +31,7 @@ export default function useGauges({ address, chainId }: { address: string, chain }), enabled: !!n_gauges, }) as { data: string[], status: string } + console.log({ gauges }) const { data: areGaugesKilled } = useContractReads({ contracts: gauges?.map((gauge: any) => { @@ -42,8 +45,11 @@ export default function useGauges({ address, chainId }: { address: string, chain }), enabled: !!gauges, }) as { data: boolean[], status: string } + console.log({ areGaugesKilled }) const aliveGauges = areGaugesKilled ? gauges?.filter((gauge: any, idx: number) => !areGaugesKilled[idx]) : gauges + console.log({ aliveGauges }) + const { data, status } = useContractReads({ contracts: aliveGauges?.map((gauge: any) => { return { @@ -59,6 +65,7 @@ export default function useGauges({ address, chainId }: { address: string, chain return (data as string[]).map((token, i) => { return { address: aliveGauges[i], vault: token, chainId: chainId } }) } }) as { data: Gauge[], status: string } + console.log({ data, status }) return { data, status } as Pop.HookResult; } diff --git a/pages/vepop.tsx b/pages/vepop.tsx index f6862ba..531441e 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -64,7 +64,7 @@ export default function VePOP() { useEffect(() => { if (gauges?.length > 0, votes?.length === 0) { - setVotes(new Array(gauges.length).fill(0)); + setVotes(new Array(gauges?.length).fill(0)); } }, [gauges, votes]) From d372e6cad924e81f590889bb052623d3579b9830 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 20 Sep 2023 12:26:58 +0200 Subject: [PATCH 12/84] removed console logs --- lib/Gauges/useGauges.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/Gauges/useGauges.ts b/lib/Gauges/useGauges.ts index 0b90f03..91cc11b 100644 --- a/lib/Gauges/useGauges.ts +++ b/lib/Gauges/useGauges.ts @@ -9,7 +9,6 @@ export interface Gauge { } export default function useGauges({ address, chainId }: { address: string, chainId: number }): Pop.HookResult { - console.log({ address, chainId }) const { data: n_gauges } = useContractRead({ address, abi: abiController, @@ -17,7 +16,6 @@ export default function useGauges({ address, chainId }: { address: string, chain chainId, args: [] }) as { data: BigNumber, status: string } - console.log({ n_gauges }) const { data: gauges } = useContractReads({ contracts: Array(n_gauges?.toNumber()).fill(undefined).map((item, idx) => { @@ -31,7 +29,6 @@ export default function useGauges({ address, chainId }: { address: string, chain }), enabled: !!n_gauges, }) as { data: string[], status: string } - console.log({ gauges }) const { data: areGaugesKilled } = useContractReads({ contracts: gauges?.map((gauge: any) => { @@ -45,10 +42,8 @@ export default function useGauges({ address, chainId }: { address: string, chain }), enabled: !!gauges, }) as { data: boolean[], status: string } - console.log({ areGaugesKilled }) const aliveGauges = areGaugesKilled ? gauges?.filter((gauge: any, idx: number) => !areGaugesKilled[idx]) : gauges - console.log({ aliveGauges }) const { data, status } = useContractReads({ contracts: aliveGauges?.map((gauge: any) => { @@ -65,7 +60,6 @@ export default function useGauges({ address, chainId }: { address: string, chain return (data as string[]).map((token, i) => { return { address: aliveGauges[i], vault: token, chainId: chainId } }) } }) as { data: Gauge[], status: string } - console.log({ data, status }) return { data, status } as Pop.HookResult; } From 764f8101babbb114cdc6ee3ff13225c74818d0ca Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 20 Sep 2023 12:33:35 +0200 Subject: [PATCH 13/84] vepop page uses NoSSR --- lib/Gauges/useHasAlreadyVoted.ts | 1 - pages/vepop.tsx | 12 +++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/Gauges/useHasAlreadyVoted.ts b/lib/Gauges/useHasAlreadyVoted.ts index a1b620b..c4242e1 100644 --- a/lib/Gauges/useHasAlreadyVoted.ts +++ b/lib/Gauges/useHasAlreadyVoted.ts @@ -22,7 +22,6 @@ export function useHasAlreadyVoted({ addresses, chainId, account }: { addresses: }) as Pop.HookResult const limitTimestamp = Math.floor(Date.now() / 1000) - (DAYS * 10); - console.log(data) const alreadyVoted = data?.some(voteTimestamp => voteTimestamp?.gt(BigNumber.from(limitTimestamp)) diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 531441e..18939cc 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -38,9 +38,7 @@ const { Minter: OPOP_MINTER } = getVeAddresses(); -export default function VePOP() { - const { waitForTx } = useWaitForTx(); - +function VePopContainer() { const { address: account } = useAccount() const { data: signer } = useSigner({ chainId: 5 }) @@ -130,7 +128,7 @@ export default function VePOP() { } return ( - + <> {(!votes || votes.length === 0) ? <> : <> @@ -251,8 +249,12 @@ export default function VePOP() {
} -
+ ) } +export default function VePOP() { + return +} + function noOp() { } From 96d988b875f41a6f472d333713e2457bdcfe7a61 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 20 Sep 2023 14:16:01 +0200 Subject: [PATCH 14/84] wip - added weth claiming --- lib/FeeDistributor/useClaimToken.ts | 22 +++++ lib/FeeDistributor/useClaimableTokens.ts | 20 +++++ lib/FeeDistributor/useUserWethRewards.ts | 102 +++++++++++++++++++++++ lib/types.ts | 1 + lib/utils/addresses/index.ts | 3 +- pages/vepop.tsx | 57 ++++++++----- 6 files changed, 184 insertions(+), 21 deletions(-) create mode 100644 lib/FeeDistributor/useClaimToken.ts create mode 100644 lib/FeeDistributor/useClaimableTokens.ts create mode 100644 lib/FeeDistributor/useUserWethRewards.ts diff --git a/lib/FeeDistributor/useClaimToken.ts b/lib/FeeDistributor/useClaimToken.ts new file mode 100644 index 0000000..ef0f327 --- /dev/null +++ b/lib/FeeDistributor/useClaimToken.ts @@ -0,0 +1,22 @@ +import { showErrorToast, showSuccessToast } from "lib/Toasts"; +import { useContractWrite, usePrepareContractWrite } from "wagmi"; + +export function useClaimTokens(address: `0x${string}`, user: `0x${string}`, tokens: string[]) { + const { config } = usePrepareContractWrite({ + address, + abi: ["function claimTokens(address user, address[] calldata tokens) external"], + functionName: "claimTokens", + args: [user, tokens], + chainId: Number(5), + }); + + return useContractWrite({ + ...config, + onSuccess: () => { + showSuccessToast("wETH Succesfully Claimed!"); + }, + onError: (error) => { + showErrorToast(error); + } + }); +} \ No newline at end of file diff --git a/lib/FeeDistributor/useClaimableTokens.ts b/lib/FeeDistributor/useClaimableTokens.ts new file mode 100644 index 0000000..b0355da --- /dev/null +++ b/lib/FeeDistributor/useClaimableTokens.ts @@ -0,0 +1,20 @@ +import { useContractRead } from "wagmi"; +import { BigNumber } from 'ethers'; +import { Pop } from "lib/types"; + +interface ClaimableTokensArgs { + address: `0x${string}`; + user: `0x${string}`; + timestamp: number; + chainId?: number; +} + +export default function useClaimableTokens({ chainId, address, user, timestamp }: ClaimableTokensArgs): Pop.HookResult { + return useContractRead({ + abi: ["function getUserBalanceAtTimestamp(address user, uint256 timestamp) external view returns (uint256)"], + address, + functionName: "getUserBalanceAtTimestamp", + chainId: chainId, + args: [user, timestamp], + }) as Pop.HookResult; +}; \ No newline at end of file diff --git a/lib/FeeDistributor/useUserWethRewards.ts b/lib/FeeDistributor/useUserWethRewards.ts new file mode 100644 index 0000000..7082e52 --- /dev/null +++ b/lib/FeeDistributor/useUserWethRewards.ts @@ -0,0 +1,102 @@ +import { BigNumber } from 'ethers'; +import { useContractRead } from 'wagmi'; + +export function useUserWethReward({ chainId, address, user, token, timestamp }: { address: `0x${string}`, chainId: number, user: `0x${string}`, token: `0x${string}`, timestamp: number }): { data: BigNumber } { + console.log("user", user, timestamp); + const { data: totalSupplyAtTimestamp } = useContractRead({ + address, + abi: abiFeeDistributor, + functionName: "getTotalSupplyAtTimestamp", + chainId: chainId, + args: [timestamp] + }) as { data: BigNumber } + + const { data: userBalanceAtTimestamp } = useContractRead({ + address, + abi: abiFeeDistributor, + functionName: "getUserBalanceAtTimestamp", + chainId: chainId, + args: [user, timestamp] + }) as { data: BigNumber } + + const { data: tokensDistributedInWeek } = useContractRead({ + address, + abi: abiFeeDistributor, + functionName: "getTokensDistributedInWeek", + chainId: chainId, + args: [token, timestamp] + }) as { data: BigNumber } + + console.log("totalSupplyAtTimestamp", totalSupplyAtTimestamp) + console.log("userBalanceAtTimestamp", userBalanceAtTimestamp) + console.log("tokensDistributedInWeek", tokensDistributedInWeek) + + if (userBalanceAtTimestamp && tokensDistributedInWeek && totalSupplyAtTimestamp) { + const userReward = userBalanceAtTimestamp.mul(tokensDistributedInWeek).div(totalSupplyAtTimestamp); + return { data: userReward }; + } + + return { data: BigNumber.from(0) }; +} + +const abiFeeDistributor = [ + { + "stateMutability": "view", + "type": "function", + "name": "getTokensDistributedInWeek", + "inputs": [ + { + "name": "token", + "type": "address" + }, + { + "name": "timestamp", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "getTotalSupplyAtTimestamp", + "inputs": [ + { + "name": "timestamp", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "getUserBalanceAtTimestamp", + "inputs": [ + { + "name": "user", + "type": "address" + }, + { + "name": "timestamp", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, +] \ No newline at end of file diff --git a/lib/types.ts b/lib/types.ts index df6f3fc..8475f9c 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -118,6 +118,7 @@ export type veAddresses = { Vault1POPGauge: `0x${string}`; Vault2WETHGauge: `0x${string}`; VaultRouter: `0x${string}`; + FeeDistributor: `0x${string}`; }; diff --git a/lib/utils/addresses/index.ts b/lib/utils/addresses/index.ts index 6a86178..c11df4b 100644 --- a/lib/utils/addresses/index.ts +++ b/lib/utils/addresses/index.ts @@ -25,7 +25,8 @@ const veAddresses = { Vault2WETHGauge: "0x73F846D3d5Ec3bDFF8893c123e9966BdBeA4c00B", Vault3USDCGauge: "0x50185e24e6Db0FB08A530752FE828A19776237c1", Vault4DAIGauge: "0x744DaBDc35A924705E49d3183A389040e9E0A84A", - VaultRouter: "0x1DB17afE14732A5267a0839D5f3dE0AF1426cb9E" + VaultRouter: "0x1DB17afE14732A5267a0839D5f3dE0AF1426cb9E", + FeeDistributor: "0x2661cdddb673DDcF2e0bc0dD7Fd432fCF1fe9e74" }; export function getVeAddresses(): veAddresses { diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 18939cc..b0d451f 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -26,6 +26,9 @@ import { showSuccessToast, showErrorToast } from "lib/Toasts"; import { getVeAddresses } from "lib/utils/addresses"; import { WalletIcon } from "@heroicons/react/24/outline"; import { useHasAlreadyVoted } from "lib/Gauges/useHasAlreadyVoted"; +import { useUserWethReward } from "lib/FeeDistributor/useUserWethRewards"; +import { useClaimTokens } from "lib/FeeDistributor/useClaimToken"; +import useClaimableTokens from "lib/FeeDistributor/useClaimableTokens"; const { BalancerPool: POP_LP, @@ -35,7 +38,8 @@ const { POP: POP, WETH: WETH, BalancerOracle: OPOP_ORACLE, - Minter: OPOP_MINTER + Minter: OPOP_MINTER, + FeeDistributor: FEE_DISTRIBUTOR } = getVeAddresses(); function VePopContainer() { @@ -52,6 +56,9 @@ function VePopContainer() { const { data: gauges } = useGauges({ address: GAUGE_CONTROLLER, chainId: 5 }) const { data: gaugeRewards } = useClaimableOPop({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) + const { data: claimableTokens } = useClaimableTokens({ chainId: 5, address: FEE_DISTRIBUTOR, user: "0x4204FDD868FFe0e62F57e6A626F8C9530F7d5AD1", timestamp: 1694649600 }) + const { data: userWethReward } = useUserWethReward({ chainId: 5, address: FEE_DISTRIBUTOR, user: "0x4204FDD868FFe0e62F57e6A626F8C9530F7d5AD1", token: WETH, timestamp: 1694649600 }) + const [votes, setVotes] = useState([]); const { data: hasAlreadyVoted } = useHasAlreadyVoted({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) const canVote = account && Number(veBal?.value) > 0 && !hasAlreadyVoted @@ -80,6 +87,7 @@ function VePopContainer() { } const { write: claimOPop = noOp } = useClaimOPop(OPOP_MINTER, gaugeRewards?.amounts?.filter(gauge => Number(gauge.amount) > 0).map(gauge => gauge.address)); + const { write: claimTokens = noOp } = useClaimTokens(FEE_DISTRIBUTOR, account, [WETH]); function handleVotes(val: number, index: number) { setVotes((prevVotes) => { @@ -185,31 +193,40 @@ function VePopContainer() {

Total vePOP Rewards

APR

-

? %

+

{formatNumber(Number(userWethReward) / 1e18)} %

-

Claimable oPOP

-

{gaugeRewards?.total ? (Number(gaugeRewards?.total) / 1e18).toFixed(2) : "0"}

+

Claimable WETH

+

{Number(claimableTokens) > 0 ? (Number(claimableTokens) / 1e18).toFixed(2) : "0"}

+
+ claimTokens()} disabled={Number(claimableTokens) === 0} /> +
-
-

My oPOP

-
-

- {oPopBal?.value ? (Number(oPopBal?.value) / 1e18).toFixed(2) : "0"} - -

-

- ($ {oPopPrice?.value && oPopBal?.value ? - formatNumber((Number(oPopBal?.value) / 1e18) * (Number(oPopPrice?.value) / 1e18)) : - "0"}) -

+
+ +

Claimable oPOP

+

{gaugeRewards?.total ? (Number(gaugeRewards?.total) / 1e18).toFixed(2) : "0"}

+
+ +

My oPOP

+
+

+ {oPopBal?.value ? (Number(oPopBal?.value) / 1e18).toFixed(2) : "0"} + +

+

+ ($ {oPopPrice?.value && oPopBal?.value ? + formatNumber((Number(oPopBal?.value) / 1e18) * (Number(oPopPrice?.value) / 1e18)) : + "0"}) +

+
+
+
+ setShowOPopModal(true)} disabled={Number(oPopBal?.value) === 0} /> + claimOPop()} disabled={Number(gaugeRewards?.total) === 0} />
-
- setShowOPopModal(true)} disabled={Number(oPopBal?.value) === 0} /> - claimOPop()} disabled={Number(gaugeRewards?.total) === 0} /> -
From 3c1b187077a730846fed65a761ee7b7ee982556f Mon Sep 17 00:00:00 2001 From: amatureApe Date: Wed, 20 Sep 2023 05:39:58 -0700 Subject: [PATCH 15/84] cleanup wETH rewards UI --- lib/FeeDistributor/useUserWethRewards.ts | 5 ----- pages/vepop.tsx | 12 +++++++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/FeeDistributor/useUserWethRewards.ts b/lib/FeeDistributor/useUserWethRewards.ts index 7082e52..230219c 100644 --- a/lib/FeeDistributor/useUserWethRewards.ts +++ b/lib/FeeDistributor/useUserWethRewards.ts @@ -2,7 +2,6 @@ import { BigNumber } from 'ethers'; import { useContractRead } from 'wagmi'; export function useUserWethReward({ chainId, address, user, token, timestamp }: { address: `0x${string}`, chainId: number, user: `0x${string}`, token: `0x${string}`, timestamp: number }): { data: BigNumber } { - console.log("user", user, timestamp); const { data: totalSupplyAtTimestamp } = useContractRead({ address, abi: abiFeeDistributor, @@ -27,10 +26,6 @@ export function useUserWethReward({ chainId, address, user, token, timestamp }: args: [token, timestamp] }) as { data: BigNumber } - console.log("totalSupplyAtTimestamp", totalSupplyAtTimestamp) - console.log("userBalanceAtTimestamp", userBalanceAtTimestamp) - console.log("tokensDistributedInWeek", tokensDistributedInWeek) - if (userBalanceAtTimestamp && tokensDistributedInWeek && totalSupplyAtTimestamp) { const userReward = userBalanceAtTimestamp.mul(tokensDistributedInWeek).div(totalSupplyAtTimestamp); return { data: userReward }; diff --git a/pages/vepop.tsx b/pages/vepop.tsx index b0d451f..b6245b0 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -1,4 +1,4 @@ -import { BigNumber, Contract, Wallet, constants } from "ethers"; +import { BigNumber, Contract, Wallet, constants, utils } from "ethers"; import { useApproveBalance } from "hooks/useApproveBalance"; import { useAllowance, useBalanceOf } from "lib/Erc20/hooks"; import { getVotePeriodEndTime } from "lib/Gauges/utils"; @@ -56,9 +56,11 @@ function VePopContainer() { const { data: gauges } = useGauges({ address: GAUGE_CONTROLLER, chainId: 5 }) const { data: gaugeRewards } = useClaimableOPop({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) - const { data: claimableTokens } = useClaimableTokens({ chainId: 5, address: FEE_DISTRIBUTOR, user: "0x4204FDD868FFe0e62F57e6A626F8C9530F7d5AD1", timestamp: 1694649600 }) + // const { data: claimableTokens } = useClaimableTokens({ chainId: 5, address: FEE_DISTRIBUTOR, user: "0x4204FDD868FFe0e62F57e6A626F8C9530F7d5AD1", timestamp: 1694649600 }) const { data: userWethReward } = useUserWethReward({ chainId: 5, address: FEE_DISTRIBUTOR, user: "0x4204FDD868FFe0e62F57e6A626F8C9530F7d5AD1", token: WETH, timestamp: 1694649600 }) + console.log("userWethReward", userWethReward); + const [votes, setVotes] = useState([]); const { data: hasAlreadyVoted } = useHasAlreadyVoted({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) const canVote = account && Number(veBal?.value) > 0 && !hasAlreadyVoted @@ -193,14 +195,14 @@ function VePopContainer() {

Total vePOP Rewards

APR

-

{formatNumber(Number(userWethReward) / 1e18)} %

+

??? %

Claimable WETH

-

{Number(claimableTokens) > 0 ? (Number(claimableTokens) / 1e18).toFixed(2) : "0"}

+

{parseFloat(utils.formatEther(userWethReward)).toFixed(3)} wETH

- claimTokens()} disabled={Number(claimableTokens) === 0} /> + claimTokens()} disabled={false} />
From a07a0d26ca97987c2386f028cfa9fc54f3725e56 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 22 Sep 2023 12:46:12 +0200 Subject: [PATCH 16/84] added getVeApy function --- lib/FeeDistributor/getVeApy.ts | 95 ++++++++++++++++++++++++ lib/FeeDistributor/useClaimableTokens.ts | 20 ----- lib/FeeDistributor/useUserWethRewards.ts | 30 ++++++-- pages/vepop.tsx | 24 +++--- 4 files changed, 134 insertions(+), 35 deletions(-) create mode 100644 lib/FeeDistributor/getVeApy.ts delete mode 100644 lib/FeeDistributor/useClaimableTokens.ts diff --git a/lib/FeeDistributor/getVeApy.ts b/lib/FeeDistributor/getVeApy.ts new file mode 100644 index 0000000..945fc25 --- /dev/null +++ b/lib/FeeDistributor/getVeApy.ts @@ -0,0 +1,95 @@ +import { useContractRead } from "wagmi"; +import { BigNumber, Contract } from 'ethers'; +import { Pop } from "lib/types"; +import { defi_llama } from "lib/utils/resolvers/price-resolvers/resolvers"; +import { thisPeriodTimestamp } from "lib/Gauges/utils"; +import { RPC_PROVIDERS } from "lib/utils"; + +interface ClaimableTokensArgs { + address: `0x${string}`; + token: `0x${string}`; + chainId: number +} + +export default async function getVeApy({ chainId, address, token }: ClaimableTokensArgs): Promise { + const popPriceUSD = await defi_llama("0x6F0fecBC276de8fC69257065fE47C5a03d986394", 10) + const wethPriceUSD = await defi_llama("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 1) + const timestamp = BigNumber.from(String(thisPeriodTimestamp() - 604800)); + + + const feeDistributor = new Contract(address, abiFeeDistributor, RPC_PROVIDERS[chainId]) + const totalSupplyAtTimestamp = await feeDistributor.getTotalSupplyAtTimestamp(timestamp) + const tokensDistributedInWeek = await feeDistributor.getTokensDistributedInWeek(token, timestamp) + + if (Number(tokensDistributedInWeek) > 0 && Number(totalSupplyAtTimestamp) > 0) { + const rewardValue = Number(tokensDistributedInWeek) * (Number(wethPriceUSD.value) / 1e18) + const supplyValue = Number(totalSupplyAtTimestamp) * (Number(popPriceUSD.value) / 1e18); + const apy = (rewardValue / supplyValue) * 52; + return apy; + } + + return 0; +}; + + +const abiFeeDistributor = [ + { + "stateMutability": "view", + "type": "function", + "name": "getTokensDistributedInWeek", + "inputs": [ + { + "name": "token", + "type": "address" + }, + { + "name": "timestamp", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "getTotalSupplyAtTimestamp", + "inputs": [ + { + "name": "timestamp", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "getUserBalanceAtTimestamp", + "inputs": [ + { + "name": "user", + "type": "address" + }, + { + "name": "timestamp", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, +] as const \ No newline at end of file diff --git a/lib/FeeDistributor/useClaimableTokens.ts b/lib/FeeDistributor/useClaimableTokens.ts deleted file mode 100644 index b0355da..0000000 --- a/lib/FeeDistributor/useClaimableTokens.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { useContractRead } from "wagmi"; -import { BigNumber } from 'ethers'; -import { Pop } from "lib/types"; - -interface ClaimableTokensArgs { - address: `0x${string}`; - user: `0x${string}`; - timestamp: number; - chainId?: number; -} - -export default function useClaimableTokens({ chainId, address, user, timestamp }: ClaimableTokensArgs): Pop.HookResult { - return useContractRead({ - abi: ["function getUserBalanceAtTimestamp(address user, uint256 timestamp) external view returns (uint256)"], - address, - functionName: "getUserBalanceAtTimestamp", - chainId: chainId, - args: [user, timestamp], - }) as Pop.HookResult; -}; \ No newline at end of file diff --git a/lib/FeeDistributor/useUserWethRewards.ts b/lib/FeeDistributor/useUserWethRewards.ts index 230219c..c705cc1 100644 --- a/lib/FeeDistributor/useUserWethRewards.ts +++ b/lib/FeeDistributor/useUserWethRewards.ts @@ -1,13 +1,27 @@ import { BigNumber } from 'ethers'; +import { time } from 'highcharts'; +import { getVotePeriodEndTime, thisPeriodTimestamp } from 'lib/Gauges/utils'; +import { RPC_PROVIDERS } from 'lib/utils'; +import { useEffect, useState } from 'react'; import { useContractRead } from 'wagmi'; -export function useUserWethReward({ chainId, address, user, token, timestamp }: { address: `0x${string}`, chainId: number, user: `0x${string}`, token: `0x${string}`, timestamp: number }): { data: BigNumber } { +async function getLatestTimestamp(chainId: number) { + const latestBlockNumber = await RPC_PROVIDERS[chainId].getBlockNumber() + const latestBlock = await RPC_PROVIDERS[chainId].getBlock(latestBlockNumber) + return latestBlock.timestamp +} + +export function useUserWethReward({ chainId, address, user, token }: { address: `0x${string}`, chainId: number, user: `0x${string}`, token: `0x${string}` }): { data: BigNumber } { + console.log({ chainId, address, user, token, thisPeriod: thisPeriodTimestamp(), nextPeriod: getVotePeriodEndTime() }) + const timestamp = BigNumber.from(String(thisPeriodTimestamp() - 604800)); + const { data: totalSupplyAtTimestamp } = useContractRead({ address, abi: abiFeeDistributor, functionName: "getTotalSupplyAtTimestamp", chainId: chainId, - args: [timestamp] + args: [timestamp], + enabled: !!timestamp && !!user && !!token }) as { data: BigNumber } const { data: userBalanceAtTimestamp } = useContractRead({ @@ -15,7 +29,8 @@ export function useUserWethReward({ chainId, address, user, token, timestamp }: abi: abiFeeDistributor, functionName: "getUserBalanceAtTimestamp", chainId: chainId, - args: [user, timestamp] + args: [user, timestamp], + enabled: !!timestamp && !!user && !!token }) as { data: BigNumber } const { data: tokensDistributedInWeek } = useContractRead({ @@ -23,10 +38,13 @@ export function useUserWethReward({ chainId, address, user, token, timestamp }: abi: abiFeeDistributor, functionName: "getTokensDistributedInWeek", chainId: chainId, - args: [token, timestamp] + args: [token, timestamp], + enabled: !!timestamp && !!user && !!token }) as { data: BigNumber } - if (userBalanceAtTimestamp && tokensDistributedInWeek && totalSupplyAtTimestamp) { + console.log({ tokensDistributedInWeek: Number(tokensDistributedInWeek), totalSupplyAtTimestamp: Number(totalSupplyAtTimestamp) }) + + if (Number(userBalanceAtTimestamp) && Number(tokensDistributedInWeek) > 0 && Number(totalSupplyAtTimestamp) > 0) { const userReward = userBalanceAtTimestamp.mul(tokensDistributedInWeek).div(totalSupplyAtTimestamp); return { data: userReward }; } @@ -94,4 +112,4 @@ const abiFeeDistributor = [ } ] }, -] \ No newline at end of file +] as const \ No newline at end of file diff --git a/pages/vepop.tsx b/pages/vepop.tsx index b6245b0..9d271c2 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -1,9 +1,9 @@ -import { BigNumber, Contract, Wallet, constants, utils } from "ethers"; +import { BigNumber, Contract, Wallet, constants, ethers, utils } from "ethers"; import { useApproveBalance } from "hooks/useApproveBalance"; import { useAllowance, useBalanceOf } from "lib/Erc20/hooks"; import { getVotePeriodEndTime } from "lib/Gauges/utils"; import { Pop } from "lib/types"; -import { formatAndRoundBigNumber, formatNumber, useConsistentRepolling } from "lib/utils"; +import { RPC_PROVIDERS, formatAndRoundBigNumber, formatNumber, useConsistentRepolling } from "lib/utils"; import useWaitForTx from "lib/utils/hooks/useWaitForTx"; import { useEffect, useState } from "react"; import toast from "react-hot-toast"; @@ -28,7 +28,8 @@ import { WalletIcon } from "@heroicons/react/24/outline"; import { useHasAlreadyVoted } from "lib/Gauges/useHasAlreadyVoted"; import { useUserWethReward } from "lib/FeeDistributor/useUserWethRewards"; import { useClaimTokens } from "lib/FeeDistributor/useClaimToken"; -import useClaimableTokens from "lib/FeeDistributor/useClaimableTokens"; +import useClaimableTokens from "lib/FeeDistributor/getVeApy"; +import getVeApy from "lib/FeeDistributor/getVeApy"; const { BalancerPool: POP_LP, @@ -56,10 +57,7 @@ function VePopContainer() { const { data: gauges } = useGauges({ address: GAUGE_CONTROLLER, chainId: 5 }) const { data: gaugeRewards } = useClaimableOPop({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) - // const { data: claimableTokens } = useClaimableTokens({ chainId: 5, address: FEE_DISTRIBUTOR, user: "0x4204FDD868FFe0e62F57e6A626F8C9530F7d5AD1", timestamp: 1694649600 }) - const { data: userWethReward } = useUserWethReward({ chainId: 5, address: FEE_DISTRIBUTOR, user: "0x4204FDD868FFe0e62F57e6A626F8C9530F7d5AD1", token: WETH, timestamp: 1694649600 }) - - console.log("userWethReward", userWethReward); + const { data: userWethReward } = useUserWethReward({ chainId: 5, address: FEE_DISTRIBUTOR, user: account, token: WETH }) const [votes, setVotes] = useState([]); const { data: hasAlreadyVoted } = useHasAlreadyVoted({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) @@ -69,6 +67,14 @@ function VePopContainer() { const [showMangementModal, setShowMangementModal] = useState(false); const [showOPopModal, setShowOPopModal] = useState(false); + const [apy, setApy] = useState(undefined); + + useEffect(() => { + if (!apy) { + getVeApy({ chainId: 5, address: FEE_DISTRIBUTOR, token: WETH }).then(res => setApy(res)) + } + }, [apy]) + useEffect(() => { if (gauges?.length > 0, votes?.length === 0) { setVotes(new Array(gauges?.length).fill(0)); @@ -195,14 +201,14 @@ function VePopContainer() {

Total vePOP Rewards

APR

-

??? %

+

{apy || "0"} %

Claimable WETH

{parseFloat(utils.formatEther(userWethReward)).toFixed(3)} wETH

- claimTokens()} disabled={false} /> + claimTokens()} disabled={Number(userWethReward) === 0} />
From c7ab04c658375512aa4c6e4a8a1e0cfa7245afa8 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 22 Sep 2023 14:13:05 +0200 Subject: [PATCH 17/84] fixed useUserWethRewards --- lib/FeeDistributor/useUserWethRewards.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/FeeDistributor/useUserWethRewards.ts b/lib/FeeDistributor/useUserWethRewards.ts index c705cc1..2d77028 100644 --- a/lib/FeeDistributor/useUserWethRewards.ts +++ b/lib/FeeDistributor/useUserWethRewards.ts @@ -12,8 +12,7 @@ async function getLatestTimestamp(chainId: number) { } export function useUserWethReward({ chainId, address, user, token }: { address: `0x${string}`, chainId: number, user: `0x${string}`, token: `0x${string}` }): { data: BigNumber } { - console.log({ chainId, address, user, token, thisPeriod: thisPeriodTimestamp(), nextPeriod: getVotePeriodEndTime() }) - const timestamp = BigNumber.from(String(thisPeriodTimestamp() - 604800)); + const timestamp = BigNumber.from(String(thisPeriodTimestamp())); const { data: totalSupplyAtTimestamp } = useContractRead({ address, @@ -42,8 +41,6 @@ export function useUserWethReward({ chainId, address, user, token }: { address: enabled: !!timestamp && !!user && !!token }) as { data: BigNumber } - console.log({ tokensDistributedInWeek: Number(tokensDistributedInWeek), totalSupplyAtTimestamp: Number(totalSupplyAtTimestamp) }) - if (Number(userBalanceAtTimestamp) && Number(tokensDistributedInWeek) > 0 && Number(totalSupplyAtTimestamp) > 0) { const userReward = userBalanceAtTimestamp.mul(tokensDistributedInWeek).div(totalSupplyAtTimestamp); return { data: userReward }; From b74189d2985c494e74e41afaaee1f406539b3d45 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 19 Oct 2023 14:58:46 +0200 Subject: [PATCH 18/84] deployed on mainnet --- lib/types.ts | 10 +++++--- lib/utils/addresses/index.ts | 48 +++++++++++++++++------------------- pages/vepop.tsx | 20 +++++++-------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 8475f9c..369cf4c 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -106,8 +106,9 @@ export type veAddresses = { BalancerOracle: `0x${string}`; oPOP: `0x${string}`; VaultRegistry: `0x${string}`; - Vault1POP: `0x${string}`; - Vault2WETH: `0x${string}`; + Vault1DAI: `0x${string}`; + Vault2USDC: `0x${string}`; + Vault2OUSD: `0x${string}`; Minter: `0x${string}`; TokenAdmin: `0x${string}`; VotingEscrow: `0x${string}`; @@ -115,8 +116,9 @@ export type veAddresses = { GaugeFactory: `0x${string}`; SmartWalletChecker: `0x${string}`; VotingEscrowDelegation: `0x${string}`; - Vault1POPGauge: `0x${string}`; - Vault2WETHGauge: `0x${string}`; + Vault1DAIGauge: `0x${string}`; + Vault2USDCGauge: `0x${string}`; + Vault2OUSDGauge: `0x${string}`; VaultRouter: `0x${string}`; FeeDistributor: `0x${string}`; }; diff --git a/lib/utils/addresses/index.ts b/lib/utils/addresses/index.ts index c11df4b..d71ea5c 100644 --- a/lib/utils/addresses/index.ts +++ b/lib/utils/addresses/index.ts @@ -1,31 +1,29 @@ import { veAddresses } from "lib/types"; const veAddresses = { - POP: "0x2e76177da141D86e10076dABdcc607Eb8054BdC4", - WETH: "0x2D9B33e9918Dce388d1Cb8Bf09D4E827b899e9d9", - USDC: "0x0F5f584470b66f53F1C0462969bE64dDD25dDeA4", - DAI: "0x6e38bB4A2968EF776bDF648025170229b9C71ad5", - BalancerPool: "0x1050f901A307e7E71471CA3d12dfceA01d0a0A1c", - BalancerOracle: "0x1493510a056A4B5bE001Dfbb8624E83B55E9a6cc", - oPOP: "0x14737B576e8F9aE54cb72F69ef1205ECa06f08b9", - VaultRegistry: "0x141359231649B9Fbeb9bd799bf981F97F959c4B5", - Vault1POP: "0xf936E7b590851332caf95F6f7f401dE72E89311B", - Vault2WETH: "0x079072685B587d5f3Bd89F9EeafD0ee03f9788f7", - Vault3USDC: "0x421830c97Cd323a1b4566B8cDdD79282f11f4fe2", - Vault4DAI: "0x6E44af35DbdB8Ce2A48D0C09752ee007bF2203E0", - BoostV2: "0x36915f72E2d26EdADC42B06e2fF7723B127C61A1", - Minter: "0x6Aa312053A67056261a29E34B68fE683A1151a0e", - TokenAdmin: "0x314Ac07C01521eA98E366d91d45613Bc7b5C0159", - VotingEscrow: "0x991C6135D57d17E8ECACE25d4B56108bC2309f77", - GaugeController: "0xf11826c60417E3d9c965E31c91644b3c08FB04fC", - GaugeFactory: "0xf03B2b617deBd8392641e5527A08D323a9f8dE9f", - SmartWalletChecker: "0xDdB110d3a3bb4A0C2506dF9D8234461e41A682F1", - VotingEscrowDelegation: "0x7ca6c7aF59d00ec8498AEe92517D92e179d3C46b", - Vault1POPGauge: "0x6c70f4328b7a77A644657138438fbD1240A59a30", - Vault2WETHGauge: "0x73F846D3d5Ec3bDFF8893c123e9966BdBeA4c00B", - Vault3USDCGauge: "0x50185e24e6Db0FB08A530752FE828A19776237c1", - Vault4DAIGauge: "0x744DaBDc35A924705E49d3183A389040e9E0A84A", - VaultRouter: "0x1DB17afE14732A5267a0839D5f3dE0AF1426cb9E", + POP: "0xD0Cd466b34A24fcB2f87676278AF2005Ca8A78c4", + WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + USDC: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + DAI: "0x6B175474E89094C44Da98b954EedeAC495271d0F", + BalancerPool: "0xd5A44704beFD1CfCCa67F7bc498a7654cC092959 ", + BalancerOracle: "0x0124a1697e207De725cd1e7b40aa9b0Ed37Ed5de", + oPOP: "0xDfFA4D3ed6B433810354430464a5C00b6ea0F1dF", + VaultRegistry: "0x007318Dc89B314b47609C684260CfbfbcD412864", + Vault1DAI: "0x5d344226578DC100b2001DA251A4b154df58194f", + Vault2USDC: "0xc1D4a319dD7C44e332Bd54c724433C6067FeDd0D", + Vault3OUSD: "0xc8C88fdF2802733f8c4cd7c0bE0557fdC5d2471c", + BoostV2: "0x9e607c0612cc44298F843288124FaCD19246022B", + Minter: "0xD37578f51CD8E66819C3689a9Af540Ca2a0AfF04", + TokenAdmin: "0xd00053501355298b8F5bAcC0610c396e127d974a", + VotingEscrow: "0xF7D4B9152CaDD0992e35152b315081De23133c7A", + GaugeController: "0xD7fFc91eb0a7db28FaED4eb2747cb5153F301f55", + GaugeFactory: "0x54AC26a8fD403F63Df2f0094307Eba90A0Ef7D64", + SmartWalletChecker: "0xD036025237aE258d53862A3c36461145683ef506", + VotingEscrowDelegation: "0x212a09F7E81781F045bb065f95c498c2D9C68507", + Vault1DAIGauge: "0x56b01649cc12711a568775a83ecb5129502d40fa", + Vault2USDCGauge: "0x5d0525137402240bc11dfa36d82260c39839c337", + Vault3OUSDGauge: "0x91af5f8869be163a973c054daa30a84bf7f8f405", + VaultRouter: "0x8aed8Ea73044910760E8957B6c5b28Ac51f8f809", FeeDistributor: "0x2661cdddb673DDcF2e0bc0dD7Fd432fCF1fe9e74" }; diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 9d271c2..8b62940 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -45,22 +45,22 @@ const { function VePopContainer() { const { address: account } = useAccount() - const { data: signer } = useSigner({ chainId: 5 }) + const { data: signer } = useSigner({ chainId: 1 }) - const { data: popLpBal } = useBalanceOf({ chainId: 5, address: POP_LP, account }) - const { data: oPopBal } = useBalanceOf({ chainId: 5, address: OPOP, account }) - const { data: lockedBal } = useLockedBalanceOf({ chainId: 5, address: VOTING_ESCROW, account }) - const { data: veBal } = useBalanceOf({ chainId: 5, address: VOTING_ESCROW, account }) + const { data: popLpBal } = useBalanceOf({ chainId: 1, address: POP_LP, account }) + const { data: oPopBal } = useBalanceOf({ chainId: 1, address: OPOP, account }) + const { data: lockedBal } = useLockedBalanceOf({ chainId: 1, address: VOTING_ESCROW, account }) + const { data: veBal } = useBalanceOf({ chainId: 1, address: VOTING_ESCROW, account }) - const { data: oPopPrice } = useOPopPrice({ chainId: 5, address: OPOP_ORACLE }) + const { data: oPopPrice } = useOPopPrice({ chainId: 1, address: OPOP_ORACLE }) - const { data: gauges } = useGauges({ address: GAUGE_CONTROLLER, chainId: 5 }) - const { data: gaugeRewards } = useClaimableOPop({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) + const { data: gauges } = useGauges({ address: GAUGE_CONTROLLER, chainId: 1 }) + const { data: gaugeRewards } = useClaimableOPop({ addresses: gauges?.map(gauge => gauge.address), chainId: 1, account }) const { data: userWethReward } = useUserWethReward({ chainId: 5, address: FEE_DISTRIBUTOR, user: account, token: WETH }) const [votes, setVotes] = useState([]); - const { data: hasAlreadyVoted } = useHasAlreadyVoted({ addresses: gauges?.map(gauge => gauge.address), chainId: 5, account }) + const { data: hasAlreadyVoted } = useHasAlreadyVoted({ addresses: gauges?.map(gauge => gauge.address), chainId: 1, account }) const canVote = account && Number(veBal?.value) > 0 && !hasAlreadyVoted const [showLockModal, setShowLockModal] = useState(false); @@ -71,7 +71,7 @@ function VePopContainer() { useEffect(() => { if (!apy) { - getVeApy({ chainId: 5, address: FEE_DISTRIBUTOR, token: WETH }).then(res => setApy(res)) + getVeApy({ chainId: 5, address: FEE_DISTRIBUTOR, token: "0x2D9B33e9918Dce388d1Cb8Bf09D4E827b899e9d9" }).then(res => setApy(res)) } }, [apy]) From ff0b5a640d455a1014f1a54c9b93139802ff6c06 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 19 Oct 2023 16:07:52 +0200 Subject: [PATCH 19/84] repalced chainId 5 with 1 --- components/vepop/modals/lock/LockModal.tsx | 6 ++--- .../vepop/modals/lock/LockPopInterface.tsx | 8 +++---- .../modals/manage/IncreaseStakeInterface.tsx | 8 +++---- .../vepop/modals/manage/ManageLockModal.tsx | 10 ++++----- .../modals/oPop/ExerciseOPopInterface.tsx | 22 +++++++++---------- components/vepop/modals/oPop/OPopModal.tsx | 4 ++-- pages/experimental/sweet-vaults.tsx | 2 +- pages/sweet-vaults.tsx | 4 ++-- pages/vepop.tsx | 2 +- 9 files changed, 33 insertions(+), 33 deletions(-) diff --git a/components/vepop/modals/lock/LockModal.tsx b/components/vepop/modals/lock/LockModal.tsx index f39a387..83bb299 100644 --- a/components/vepop/modals/lock/LockModal.tsx +++ b/components/vepop/modals/lock/LockModal.tsx @@ -38,7 +38,7 @@ export default function LockModal({ show }: { show: [boolean, Function] }): JSX. write: approve = noOp, isSuccess: isApproveSuccess, isLoading: isApproveLoading, - } = useApproveBalance(POP_LP, VOTING_ESCROW, 5, { + } = useApproveBalance(POP_LP, VOTING_ESCROW, 1, { onSuccess: (tx) => { waitForTx(tx, { successMessage: "POP approved!", @@ -52,7 +52,7 @@ export default function LockModal({ show }: { show: [boolean, Function] }): JSX. }, }); - const { data: allowance } = useAllowance({ chainId: 5, address: POP_LP, account: VOTING_ESCROW as Address }); + const { data: allowance } = useAllowance({ chainId: 1, address: POP_LP, account: VOTING_ESCROW as Address }); const showApproveButton = isApproveSuccess ? false : amount > Number(allowance?.value || 0); useEffect(() => { @@ -65,7 +65,7 @@ export default function LockModal({ show }: { show: [boolean, Function] }): JSX. if ((amount || 0) == 0) return; // Early exit if value is ZERO - if (chain.id !== Number(5)) switchNetwork?.(Number(5)); + if (chain.id !== Number(1)) switchNetwork?.(Number(1)); if (showApproveButton) await approveBalance(POP_LP, VOTING_ESCROW); // When approved continue to deposit diff --git a/components/vepop/modals/lock/LockPopInterface.tsx b/components/vepop/modals/lock/LockPopInterface.tsx index 77af610..2aea002 100644 --- a/components/vepop/modals/lock/LockPopInterface.tsx +++ b/components/vepop/modals/lock/LockPopInterface.tsx @@ -26,8 +26,8 @@ export default function LockPopInterface({ amountState, daysState }: { amountState: [number, Dispatch>], daysState: [number, Dispatch>] }): JSX.Element { const { address: account } = useAccount() - const { data: popLp } = useToken({ chainId: 5, address: POP_LP as Address }); - const { data: popLpBal } = useBalanceOf({ chainId: 5, address: POP_LP, account }) + const { data: popLp } = useToken({ chainId: 1, address: POP_LP as Address }); + const { data: popLpBal } = useBalanceOf({ chainId: 1, address: POP_LP, account }) const [amount, setAmount] = amountState const [days, setDays] = daysState @@ -57,7 +57,7 @@ export default function LockPopInterface({ amountState, daysState }: captionText={``} onSelectToken={() => { }} onMaxClick={handleMaxClick} - chainId={5} + chainId={1} value={amount} onChange={handleChangeInput} defaultValue={amount} @@ -70,7 +70,7 @@ export default function LockPopInterface({ amountState, daysState }: errorMessage={errorMessage} allowInput tokenList={[]} - getTokenUrl="https://app.balancer.fi/#/goerli/pool/0x1050f901a307e7e71471ca3d12dfcea01d0a0a1c0002000000000000000008b4" // temp link + getTokenUrl="https://app.balancer.fi/#/ethereum/pool/0xd5a44704befd1cfcca67f7bc498a7654cc092959000200000000000000000609" // temp link />
diff --git a/components/vepop/modals/manage/IncreaseStakeInterface.tsx b/components/vepop/modals/manage/IncreaseStakeInterface.tsx index 8547973..954ed22 100644 --- a/components/vepop/modals/manage/IncreaseStakeInterface.tsx +++ b/components/vepop/modals/manage/IncreaseStakeInterface.tsx @@ -15,8 +15,8 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }: { amountState: [number, Dispatch>], lockedBal: LockedBalance }): JSX.Element { const { address: account } = useAccount() - const { data: popLp } = useToken({ chainId: 5, address: POP_LP as Address }); - const { data: popLpBal } = useBalanceOf({ chainId: 5, address: POP_LP, account }) + const { data: popLp } = useToken({ chainId: 1, address: POP_LP as Address }); + const { data: popLpBal } = useBalanceOf({ chainId: 1, address: POP_LP, account }) const [amount, setAmount] = amountState @@ -41,7 +41,7 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }: captionText={``} onSelectToken={() => { }} onMaxClick={handleMaxClick} - chainId={5} + chainId={1} value={amount} onChange={handleChangeInput} defaultValue={amount} @@ -54,7 +54,7 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }: errorMessage={errorMessage} allowInput tokenList={[]} - getTokenUrl="https://app.balancer.fi/#/goerli/pool/0x1050f901a307e7e71471ca3d12dfcea01d0a0a1c0002000000000000000008b4" // temp link + getTokenUrl="https://app.balancer.fi/#/ethereum/pool/0xd5a44704befd1cfcca67f7bc498a7654cc092959000200000000000000000609" // temp link />
diff --git a/components/vepop/modals/manage/ManageLockModal.tsx b/components/vepop/modals/manage/ManageLockModal.tsx index 2a559ae..4fdbc6f 100644 --- a/components/vepop/modals/manage/ManageLockModal.tsx +++ b/components/vepop/modals/manage/ManageLockModal.tsx @@ -41,8 +41,8 @@ export default function ManageLockModal({ show }: { show: [boolean, Function] }) const [step, setStep] = useState(0); const [mangementOption, setMangementOption] = useState(); - const { data: vePopBal } = useBalanceOf({ chainId: 5, address: VOTING_ESCROW, account }) - const { data: lockedBal } = useLockedBalanceOf({ chainId: 5, address: VOTING_ESCROW, account }) + const { data: vePopBal } = useBalanceOf({ chainId: 1, address: VOTING_ESCROW, account }) + const { data: lockedBal } = useLockedBalanceOf({ chainId: 1, address: VOTING_ESCROW, account }) const [amount, setAmount] = useState(0); const [days, setDays] = useState(7); @@ -56,7 +56,7 @@ export default function ManageLockModal({ show }: { show: [boolean, Function] }) write: approve = noOp, isSuccess: isApproveSuccess, isLoading: isApproveLoading, - } = useApproveBalance(POP_LP, VOTING_ESCROW, 5, { + } = useApproveBalance(POP_LP, VOTING_ESCROW, 1, { onSuccess: (tx) => { waitForTx(tx, { successMessage: "POP LP approved!", @@ -68,7 +68,7 @@ export default function ManageLockModal({ show }: { show: [boolean, Function] }) }, }); - const { data: allowance } = useAllowance({ chainId: 5, address: POP_LP, account: VOTING_ESCROW as Address }); + const { data: allowance } = useAllowance({ chainId: 1, address: POP_LP, account: VOTING_ESCROW as Address }); const showApproveButton = isApproveSuccess ? false : amount > Number(allowance?.value || 0); useEffect(() => { @@ -78,7 +78,7 @@ export default function ManageLockModal({ show }: { show: [boolean, Function] }) ) async function handleMainAction() { - if (chain.id !== Number(5)) switchNetwork?.(Number(5)); + if (chain.id !== Number(1)) switchNetwork?.(Number(1)); if (mangementOption === ManagementOption.IncreaseLock) { if ((amount || 0) == 0) return; diff --git a/components/vepop/modals/oPop/ExerciseOPopInterface.tsx b/components/vepop/modals/oPop/ExerciseOPopInterface.tsx index 7d666fd..7e0e049 100644 --- a/components/vepop/modals/oPop/ExerciseOPopInterface.tsx +++ b/components/vepop/modals/oPop/ExerciseOPopInterface.tsx @@ -30,18 +30,18 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta const [amount, setAmount] = amountState; const [maxPaymentAmount, setMaxPaymentAmount] = maxPaymentAmountState; - const { data: oPopPrice } = useOPopPrice({ chainId: 5, address: OPOP_ORACLE }) + const { data: oPopPrice } = useOPopPrice({ chainId: 1, address: OPOP_ORACLE }) const { data: popPrice } = usePrice({ chainId: 1, address: "0xd0cd466b34a24fcb2f87676278af2005ca8a78c4" }) const { data: wethPrice } = usePrice({ chainId: 1, address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" }) - const { data: oPopDiscount } = useOPopDiscount({ chainId: 5, address: OPOP_ORACLE }) + const { data: oPopDiscount } = useOPopDiscount({ chainId: 1, address: OPOP_ORACLE }) - const { data: oPopBal } = useBalanceOf({ chainId: 5, address: OPOP, account }) - const { data: ethBal } = useBalance({ chainId: 5, address: account }) - const { data: wethBal } = useBalanceOf({ chainId: 5, address: WETH, account }) + const { data: oPopBal } = useBalanceOf({ chainId: 1, address: OPOP, account }) + const { data: ethBal } = useBalance({ chainId: 1, address: account }) + const { data: wethBal } = useBalanceOf({ chainId: 1, address: WETH, account }) - const { data: oPop } = useToken({ chainId: 5, address: OPOP as Address }); - const { data: pop } = useToken({ chainId: 5, address: POP as Address }); - const { data: weth } = useToken({ chainId: 5, address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" as Address }); // temp - WETH + const { data: oPop } = useToken({ chainId: 1, address: OPOP as Address }); + const { data: pop } = useToken({ chainId: 1, address: POP as Address }); + const { data: weth } = useToken({ chainId: 1, address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" as Address }); // temp - WETH const handleMaxWeth = () => { @@ -91,7 +91,7 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta captionText={"Amount oPOP"} onSelectToken={() => { }} onMaxClick={handleMaxOPop} - chainId={5} + chainId={1} value={amount} onChange={handleOPopInput} allowInput={true} @@ -113,7 +113,7 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta captionText={"Amount WETH"} onSelectToken={() => { }} onMaxClick={handleMaxWeth} - chainId={5} + chainId={1} value={maxPaymentAmount * 1e3} // temp Goerli value onChange={handleEthInput} allowInput={true} @@ -157,7 +157,7 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta className={`flex flex-row items-center justify-end`} >
- +

{pop?.symbol} diff --git a/components/vepop/modals/oPop/OPopModal.tsx b/components/vepop/modals/oPop/OPopModal.tsx index 0aae5dc..9dca208 100644 --- a/components/vepop/modals/oPop/OPopModal.tsx +++ b/components/vepop/modals/oPop/OPopModal.tsx @@ -25,7 +25,7 @@ export default function OPopModal({ show }: { show: [boolean, Function] }): JSX. const [amount, setAmount] = useState(0); const [maxPaymentAmount, setMaxPaymentAmount] = useState(0); - const { data: allowance } = useAllowance({ chainId: 5, address: WETH, account: OPOP as Address }); + const { data: allowance } = useAllowance({ chainId: 1, address: WETH, account: OPOP as Address }); const needAllowance = amount > Number(allowance?.value || 0); useEffect(() => { @@ -40,7 +40,7 @@ export default function OPopModal({ show }: { show: [boolean, Function] }): JSX. if ((amount || 0) == 0) return; // Early exit if value is ZERO - if (chain.id !== Number(5)) switchNetwork?.(Number(5)); + if (chain.id !== Number(1)) switchNetwork?.(Number(1)); if (needAllowance) await approveBalance(WETH, OPOP); exerciseOPop(OPOP, account, utils.parseEther(String(amount)).toString(), utils.parseEther(maxPaymentAmount.toFixed(18)).mul(BigNumber.from("10000")).toString()); diff --git a/pages/experimental/sweet-vaults.tsx b/pages/experimental/sweet-vaults.tsx index 3f3fa3d..2f42ccd 100644 --- a/pages/experimental/sweet-vaults.tsx +++ b/pages/experimental/sweet-vaults.tsx @@ -78,7 +78,7 @@ const PopSweetVaults: NextPage = () => { Mint the token needed for testing on Goerli here:
POP
WETH
- BalancerPool + BalancerPool

diff --git a/pages/sweet-vaults.tsx b/pages/sweet-vaults.tsx index 20b76f0..22d3dff 100644 --- a/pages/sweet-vaults.tsx +++ b/pages/sweet-vaults.tsx @@ -43,7 +43,7 @@ const PopSweetVaults: NextPage = () => { const { data: arbVaults = [] } = useAllVaults(selectedNetworks.includes(ChainId.Arbitrum) ? ChainId.Arbitrum : undefined); const { data: bscVaults = [] } = useAllVaults(selectedNetworks.includes(ChainId.BNB) ? ChainId.BNB : undefined); - const { data: gauges = [] } = useGauges({ address: GAUGE_CONTROLLER, chainId: 5 }) + const { data: gauges = [] } = useGauges({ address: GAUGE_CONTROLLER, chainId: 1 }) const allVaults = [ // ...ethVaults.map(vault => { return { address: vault, chainId: ChainId.Ethereum } }), @@ -89,7 +89,7 @@ const PopSweetVaults: NextPage = () => { Mint the token needed for testing on Goerli here:
POP
WETH
- BalancerPool + BalancerPool
diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 8b62940..4eb2f4e 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -163,7 +163,7 @@ function VePopContainer() { Mint the token needed for testing on Goerli here:
POP
WETH
- BalancerPool + BalancerPool
From 71636fb945d6696fe95ac6c348c302dbf70ed409 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Mon, 23 Oct 2023 15:40:12 +0200 Subject: [PATCH 20/84] merge cleanup --- .env.example | 3 +- components/button/SecondaryActionButton.tsx | 29 +- components/button/TertiaryActionButton.tsx | 30 +- components/common/TokenIcon.tsx | 2 +- components/input/InputTokenWithError.tsx | 2 +- components/landing/Products.tsx | 2 +- components/vault/SmartVault.tsx | 13 +- components/vepop/Gauge.tsx | 52 +- components/vepop/StakingInterface.tsx | 75 +++ components/vepop/VeRewards.tsx | 61 +++ components/vepop/modals/lock/LockModal.tsx | 76 ++- components/vepop/modals/lock/LockPopInfo.tsx | 26 + .../vepop/modals/lock/LockPopInterface.tsx | 23 +- components/vepop/modals/lock/LockPreview.tsx | 30 ++ .../vepop/modals/lock/VotingPowerInfo.tsx | 23 + .../modals/manage/IncreaseStakeInterface.tsx | 39 +- .../modals/manage/IncreaseStakePreview.tsx | 36 ++ .../modals/manage/IncreaseTimeInteface.tsx | 71 +++ .../modals/manage/IncreaseTimePreview.tsx | 37 ++ .../vepop/modals/manage/ManageLockModal.tsx | 100 ++-- .../modals/manage/SelectManagementOption.tsx | 50 ++ .../vepop/modals/manage/UnstakePreview.tsx | 32 ++ .../modals/oPop/ExerciseOPopInterface.tsx | 108 ++-- components/vepop/modals/oPop/OPopModal.tsx | 62 +-- components/vepop/modals/oPop/OptionInfo.tsx | 18 + lib/constants/abi/BalancerOracle.ts | 1 + lib/constants/abi/Gauge.ts | 1 + lib/constants/abi/GaugeController.ts | 1 + lib/constants/abi/Minter.ts | 1 + lib/constants/abi/OPop.ts | 1 + lib/constants/abi/VotingEscrow.ts | 1 + lib/constants/abi/index.ts | 8 +- lib/feeDistributor/getClaimableVeReward.ts | 108 ++++ lib/feeDistributor/getVeApy.ts | 48 +- lib/feeDistributor/useClaimToken.ts | 2 +- lib/feeDistributor/useUserWethRewards.ts | 112 ----- lib/gauges/calculateGaugeAPR.ts | 84 ++-- lib/gauges/getGaugeRewards.ts | 32 ++ lib/gauges/getGauges.ts | 81 +++ lib/gauges/hasAlreadyVoted.ts | 26 + lib/gauges/interactions.ts | 213 ++++++++ lib/gauges/useClaimableOPop.ts | 19 - lib/gauges/useCurrentGaugeWeight.ts | 19 - lib/gauges/useGaugeWeights.ts | 24 +- lib/gauges/useGauges.ts | 121 ----- lib/gauges/useHasAlreadyVoted.ts | 41 -- lib/gauges/useLockedBalanceOf.ts | 27 +- lib/gauges/utils.ts | 142 +----- lib/oPop/ethToUsd.ts | 38 ++ lib/oPop/interactions.ts | 105 ++++ lib/types.ts | 44 +- lib/utils/addresses/index.ts | 4 +- lib/utils/formatBigNumber.ts | 9 +- lib/utils/helpers.ts | 7 + lib/vault/getVault.ts | 54 +- next.config.js | 7 - package.json | 3 +- pages/vaults.tsx | 72 ++- pages/vepop.tsx | 236 ++------- yarn.lock | 467 +++++++++++++----- 60 files changed, 2001 insertions(+), 1158 deletions(-) create mode 100644 components/vepop/StakingInterface.tsx create mode 100644 components/vepop/VeRewards.tsx create mode 100644 components/vepop/modals/lock/LockPopInfo.tsx create mode 100644 components/vepop/modals/lock/LockPreview.tsx create mode 100644 components/vepop/modals/lock/VotingPowerInfo.tsx create mode 100644 components/vepop/modals/manage/IncreaseStakePreview.tsx create mode 100644 components/vepop/modals/manage/IncreaseTimeInteface.tsx create mode 100644 components/vepop/modals/manage/IncreaseTimePreview.tsx create mode 100644 components/vepop/modals/manage/SelectManagementOption.tsx create mode 100644 components/vepop/modals/manage/UnstakePreview.tsx create mode 100644 components/vepop/modals/oPop/OptionInfo.tsx create mode 100644 lib/constants/abi/BalancerOracle.ts create mode 100644 lib/constants/abi/Gauge.ts create mode 100644 lib/constants/abi/GaugeController.ts create mode 100644 lib/constants/abi/Minter.ts create mode 100644 lib/constants/abi/OPop.ts create mode 100644 lib/constants/abi/VotingEscrow.ts create mode 100644 lib/feeDistributor/getClaimableVeReward.ts delete mode 100644 lib/feeDistributor/useUserWethRewards.ts create mode 100644 lib/gauges/getGaugeRewards.ts create mode 100644 lib/gauges/getGauges.ts create mode 100644 lib/gauges/hasAlreadyVoted.ts create mode 100644 lib/gauges/interactions.ts delete mode 100644 lib/gauges/useClaimableOPop.ts delete mode 100644 lib/gauges/useCurrentGaugeWeight.ts delete mode 100644 lib/gauges/useGauges.ts delete mode 100644 lib/gauges/useHasAlreadyVoted.ts create mode 100644 lib/oPop/ethToUsd.ts create mode 100644 lib/oPop/interactions.ts diff --git a/.env.example b/.env.example index 84b4040..25ad48e 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,5 @@ -RPC_URL= PINATA_API_SECRET= PINATA_API_KEY= -PINATA_JWT= IPFS_URL= DUNE_API_KEY= +NEXT_PUBLIC_ALCHEMY_API_KEY= \ No newline at end of file diff --git a/components/button/SecondaryActionButton.tsx b/components/button/SecondaryActionButton.tsx index a09f568..4ad61e7 100644 --- a/components/button/SecondaryActionButton.tsx +++ b/components/button/SecondaryActionButton.tsx @@ -1,30 +1,15 @@ -import RightArrowIcon from "@/components/svg/RightArrowIcon"; -import React, { useState } from "react"; import { ButtonProps } from "@/components/button/MainActionButton"; -export default function SecondaryActionButton({ label, handleClick, hidden, disabled = false }: ButtonProps): JSX.Element { - const [arrowColor, setArrowColor] = useState("645F4B"); - const [arrowClass, setArrowClass] = useState("transform translate-x-0"); - - const animateArrow = () => { - setArrowColor("000000"); - setArrowClass("transform -translate-x-1/2"); - setTimeout(() => { - setArrowColor("645F4B"); - setArrowClass("transform translate-x-0"); - }, 500); - }; +export default function SecondaryActionButton({ label, handleClick, disabled = false, hidden = false }: ButtonProps): JSX.Element { return ( ); -}; \ No newline at end of file +}; diff --git a/components/button/TertiaryActionButton.tsx b/components/button/TertiaryActionButton.tsx index 27b1731..92c67ce 100644 --- a/components/button/TertiaryActionButton.tsx +++ b/components/button/TertiaryActionButton.tsx @@ -1,16 +1,30 @@ +import RightArrowIcon from "@/components/svg/RightArrowIcon"; +import React, { useState } from "react"; import { ButtonProps } from "@/components/button/MainActionButton"; -export default function TertiaryActionButton({ label, handleClick, disabled = false, hidden = false }: ButtonProps): JSX.Element { +export default function TertiaryActionButton({ label, handleClick, hidden, disabled = false }: ButtonProps): JSX.Element { + const [arrowColor, setArrowColor] = useState("645F4B"); + const [arrowClass, setArrowClass] = useState("transform translate-x-0"); + + const animateArrow = () => { + setArrowColor("000000"); + setArrowClass("transform -translate-x-1/2"); + setTimeout(() => { + setArrowColor("645F4B"); + setArrowClass("transform translate-x-0"); + }, 500); + }; return ( ); -}; - +}; \ No newline at end of file diff --git a/components/common/TokenIcon.tsx b/components/common/TokenIcon.tsx index 4aa70ef..068529f 100644 --- a/components/common/TokenIcon.tsx +++ b/components/common/TokenIcon.tsx @@ -21,6 +21,6 @@ export default function TokenIcon({ return token icon } return ( - token icon + token icon ); } \ No newline at end of file diff --git a/components/input/InputTokenWithError.tsx b/components/input/InputTokenWithError.tsx index 109e216..8fb6994 100644 --- a/components/input/InputTokenWithError.tsx +++ b/components/input/InputTokenWithError.tsx @@ -62,7 +62,7 @@ export default function InputTokenWithError({

- {`${formatNumber(Number(selectedToken?.balance) / (10 ** (selectedToken?.decimals as number)))}`} + {`${selectedToken?.balance ? formatNumber(Number(selectedToken?.balance) / (10 ** (selectedToken?.decimals as number))) : "0"}`}

}
diff --git a/components/landing/Products.tsx b/components/landing/Products.tsx index 644e9b4..b959bcc 100644 --- a/components/landing/Products.tsx +++ b/components/landing/Products.tsx @@ -51,7 +51,7 @@ export default function Products(): JSX.Element { content:

Coming soon

, }, ]} - route="" + route="vepop" /> ([]); + + useEffect(() => { + if (vault?.price && gaugeApr.length === 0 && !!gauge) { + calculateAPR({ vaultPrice: vault?.price, gauge: gauge?.address, publicClient }).then(res => setGaugeApr(res)) + } + }, [vault, gaugeApr]) + // Is loading / error if (!vaultData || baseToken.length === 0) return <> // Dont show if we filter by deployer @@ -89,6 +99,7 @@ export default function SmartVault({ {apy ? `${NumberFormatter.format(apy)} %` : "0 %"} + {gaugeApr.length > 0 && {`+ (${formatNumber(gaugeApr[0])} % - ${formatNumber(gaugeApr[1])} %)`}}
diff --git a/components/vepop/Gauge.tsx b/components/vepop/Gauge.tsx index 93b41dd..2c61c2d 100644 --- a/components/vepop/Gauge.tsx +++ b/components/vepop/Gauge.tsx @@ -1,36 +1,22 @@ -import Accordion from "components/Accordion"; -import { AssetWithName } from "components/SweetVault/AssetWithName"; -import useAdapterToken from "hooks/useAdapter"; -import useVaultToken from "hooks/useVaultToken"; -import useCurrentGaugeWeight from "lib/Gauges/useCurrentGaugeWeight"; -import { Gauge } from "@/lib/gauges/useGauges"; -import useUpcomingGaugeWeight from "lib/Gauges/useUpcomingGaugeWeight"; -import useVaultMetadata from "lib/Vault/hooks/useVaultMetadata"; -import { BigNumberWithFormatted } from "lib/types"; -import Slider from "rc-slider"; import { useState } from "react"; -import { getVeAddresses } from "lib/utils/addresses"; -import Title from "components/content/Title"; -import { Contract } from "ethers"; -import { RPC_PROVIDERS } from "lib/utils"; -import { useAccount } from "wagmi"; -import useGaugeWeights from "lib/Gauges/useGaugeWeights"; - -const { GaugeController: GAUGE_CONTROLLER } = getVeAddresses(); +import { Address, useAccount } from "wagmi"; +import Slider from "rc-slider"; +import AssetWithName from "@/components/vault/AssetWithName"; +import { VaultData } from "@/lib/types"; +import Accordion from "@/components/common/Accordion"; +import Title from "@/components/common/Title"; +import useGaugeWeights from "@/lib/gauges/useGaugeWeights"; -export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote }: { gauge: Gauge, index: number, votes: number[], handleVotes: Function, veBal: BigNumberWithFormatted, canVote: boolean }): JSX.Element { +export default function Gauge({ vault, index, votes, handleVotes, canVote }: { vault: VaultData, index: number, votes: number[], handleVotes: Function, canVote: boolean }): JSX.Element { const { address: account } = useAccount() - const { data: token } = useVaultToken({ vaultAddress: gauge.vault, chainId: gauge.chainId }); - const { data: adapter } = useAdapterToken({ vaultAddress: gauge.vault, chainId: gauge.chainId }); - const vaultMetadata = useVaultMetadata({ vaultAddress: gauge.vault, chainId: gauge.chainId }); - const { data: weights } = useGaugeWeights({ address: gauge.address, account: account, chainId: gauge.chainId }) + const { data: weights } = useGaugeWeights({ address: vault.gauge?.address as Address, account: account as Address, chainId: vault.chainId }) const [amount, setAmount] = useState(0); - function onChange(value) { + function onChange(value: number) { const currentVoteForThisGauge = votes[index]; - const potentialNewTotalVotes = votes.reduce((a, b) => a + b, 0) - currentVoteForThisGauge + value; + const potentialNewTotalVotes = votes.reduce((a, b) => a + b, 0) - currentVoteForThisGauge + Number(value); if (potentialNewTotalVotes <= 10000) { handleVotes(value, index); @@ -38,17 +24,15 @@ export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote } } + console.log({weights}) + return (
- +
@@ -73,7 +57,7 @@ export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote

My Votes

- {(Number(weights?.[2]) / 1e10).toFixed() || 0} % + {(Number(weights?.[2].power) / 1e10).toFixed() || 0} %

@@ -99,7 +83,7 @@ export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote backgroundColor: '#fff', }} value={amount} - onChange={canVote ? (val) => onChange(val) : () => { }} + onChange={canVote ? (val: any) => onChange(Number(val)) : () => { }} max={10000} />
@@ -122,7 +106,7 @@ export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote

Gauge address:

- {gauge.address} + {vault.gauge?.address}

@@ -130,7 +114,7 @@ export default function Gauge({ gauge, index, votes, handleVotes, veBal, canVote

Vault address:

- {gauge.vault} + {vault.address}

diff --git a/components/vepop/StakingInterface.tsx b/components/vepop/StakingInterface.tsx new file mode 100644 index 0000000..bdfee8d --- /dev/null +++ b/components/vepop/StakingInterface.tsx @@ -0,0 +1,75 @@ +import { intervalToDuration } from "date-fns"; +import { Dispatch, useState } from "react"; +import { Address, useAccount, useBalance } from "wagmi"; +import { getVotePeriodEndTime } from "@/lib/gauges/utils"; +import MainActionButton from "@/components/button/MainActionButton"; +import SecondaryActionButton from "@/components//button/SecondaryActionButton"; +import useLockedBalanceOf from "@/lib/gauges/useLockedBalanceOf"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { formatAndRoundBigNumber } from "@/lib/utils/formatBigNumber"; +import LockModal from "@/components/vepop/modals/lock/LockModal"; +import ManageLockModal from "@/components/vepop/modals/manage/ManageLockModal"; +import { SetStateAction } from "jotai"; + +function votingPeriodEnd(): number[] { + const periodEnd = getVotePeriodEndTime(); + const interval = { start: new Date(), end: periodEnd }; + const timeUntilEnd = intervalToDuration(interval); + const formattedTime = [ + (timeUntilEnd.days || 0) % 7, + timeUntilEnd.hours || 0, + timeUntilEnd.minutes || 0, + timeUntilEnd.seconds || 0, + ]; + return formattedTime; +} + +const { + BalancerPool: POP_LP, + VotingEscrow: VOTING_ESCROW, +} = getVeAddresses(); + +interface StakingInterfaceProps { + setShowLockModal: Dispatch>; + setShowMangementModal: Dispatch>; +} + +export default function StakingInterface({ setShowLockModal, setShowMangementModal }: StakingInterfaceProps): JSX.Element { + const { address: account } = useAccount() + + const { data: lockedBal } = useLockedBalanceOf({ chainId: 1, address: VOTING_ESCROW, account: account as Address }) + const { data: veBal } = useBalance({ chainId: 1, address: VOTING_ESCROW }) + const { data: popLpBal } = useBalance({ chainId: 1, address: POP_LP }) + + return ( + <> +
+

vePOP

+ +

My POP LP

+

{popLpBal?.formatted || "0"}

+
+ +

My Locked POP LP

+

{lockedBal ? formatAndRoundBigNumber(lockedBal?.amount, 18) : "0"}

+
+ +

Locked Until

+

{lockedBal && lockedBal?.end.toString() !== "0" ? new Date(Number(lockedBal?.end) * 1000).toLocaleDateString() : "-"}

+
+ +

My vePOP

+

{veBal?.formatted || "0"}

+
+ +

Voting period ends

+

{votingPeriodEnd()[0]}d : {votingPeriodEnd()[1]}h: {votingPeriodEnd()[2]}m

+
+
+ setShowLockModal(true)} disabled={Number(veBal?.value) > 0} /> + setShowMangementModal(true)} disabled={Number(veBal?.value) === 0} /> +
+
+ + ) +} \ No newline at end of file diff --git a/components/vepop/VeRewards.tsx b/components/vepop/VeRewards.tsx new file mode 100644 index 0000000..f41013e --- /dev/null +++ b/components/vepop/VeRewards.tsx @@ -0,0 +1,61 @@ +import { useEffect, useState } from "react"; +import { Address, formatEther } from "viem"; +import { goerli } from "viem/chains"; +import { useAccount } from "wagmi"; +import MainActionButton from "@/components/button/MainActionButton"; +import getClaimableVeReward from "@/lib/feeDistributor/getClaimableVeReward"; +import getVeApy from "@/lib/feeDistributor/getVeApy"; +import { useClaimTokens } from "@/lib/feeDistributor/useClaimToken"; +import { getVeAddresses } from "@/lib/utils/addresses"; + +function noOp() { } + +const { + WETH: WETH, + FeeDistributor: FEE_DISTRIBUTOR +} = getVeAddresses(); + +export default function VeRewards(): JSX.Element { + const { address: account } = useAccount() + const { write: claimTokens = noOp } = useClaimTokens(FEE_DISTRIBUTOR, account as Address, [WETH]); + + const [apy, setApy] = useState(0); + + useEffect(() => { + if (apy === 0) { + getVeApy({ chain: goerli, address: FEE_DISTRIBUTOR, token: "0x2D9B33e9918Dce388d1Cb8Bf09D4E827b899e9d9" }).then(res => setApy(res)) + } + }, [apy]) + + const [initalLoad, setInitalLoad] = useState(false); + const [accountLoad, setAccountLoad] = useState(false); + + const [claimableVeReward, setClaimableVeReward] = useState(BigInt(0)); + + useEffect(() => { + async function getClaimableReward() { + setInitalLoad(true) + if (account) setAccountLoad(true) + getClaimableVeReward({ chain: goerli, address: FEE_DISTRIBUTOR, user: account as Address, token: WETH }).then(res => setClaimableVeReward(res)) + } + if (!account && !initalLoad) getClaimableReward(); + if (account && !accountLoad) getClaimableReward() + }, [account]) + + return ( +
+

Total vePOP Rewards

+ +

APR

+

{apy} %

+
+ +

Claimable WETH

+

{parseFloat(formatEther(claimableVeReward)).toFixed(3)} wETH

+
+
+ claimTokens()} disabled={Number(claimableVeReward) === 0} /> +
+
+ ) +} \ No newline at end of file diff --git a/components/vepop/modals/lock/LockModal.tsx b/components/vepop/modals/lock/LockModal.tsx index 83bb299..0cb9887 100644 --- a/components/vepop/modals/lock/LockModal.tsx +++ b/components/vepop/modals/lock/LockModal.tsx @@ -1,19 +1,17 @@ -import Modal from "components/Modal/Modal"; -import VotingPowerInfo from "./VotingPowerInfo"; -import LockPopInterface from "./LockPopInterface"; -import LockPreview from "./LockPreview"; -import LockPopInfo from "./LockPopInfo"; -import { useEffect, useState } from "react"; -import MainActionButton from "components/MainActionButton"; -import TertiaryActionButton from "components/TertiaryActionButton"; -import SecondaryActionButton from "components/SecondaryActionButton"; -import useWaitForTx from "lib/utils/hooks/useWaitForTx"; -import { useCreateLock } from "lib/Gauges/utils"; -import { useApproveBalance, approveBalance } from "hooks/useApproveBalance"; -import toast from "react-hot-toast"; -import { useAllowance } from "lib/Erc20/hooks"; -import { Address, useNetwork, useSwitchNetwork } from "wagmi"; -import { getVeAddresses } from "lib/utils/addresses"; +import { Address, useAccount, useNetwork, usePublicClient, useSwitchNetwork, useWalletClient } from "wagmi"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { WalletClient } from "viem"; +import Modal from "@/components/modal/Modal"; +import MainActionButton from "@/components/button/MainActionButton"; +import SecondaryActionButton from "@/components/button/SecondaryActionButton"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import LockPopInfo from "@/components/vepop/modals/lock/LockPopInfo"; +import LockPopInterface from "@/components/vepop/modals/lock/LockPopInterface"; +import LockPreview from "@/components/vepop/modals/lock/LockPreview"; +import VotingPowerInfo from "@/components/vepop/modals/lock/VotingPowerInfo"; +import { handleAllowance } from "@/lib/approve"; +import { Token } from "@/lib/types"; +import { createLock } from "@/lib/gauges/interactions"; const { BalancerPool: POP_LP, @@ -22,39 +20,20 @@ const { function noOp() { } -export default function LockModal({ show }: { show: [boolean, Function] }): JSX.Element { +export default function LockModal({ show }: { show: [boolean, Dispatch>] }): JSX.Element { + const { address: account } = useAccount(); const { chain } = useNetwork(); const { switchNetwork } = useSwitchNetwork(); + const publicClient = usePublicClient(); + const { data: walletClient } = useWalletClient() + const [step, setStep] = useState(0); const [showModal, setShowModal] = show; const [amount, setAmount] = useState(0); const [days, setDays] = useState(7); - const { waitForTx } = useWaitForTx(); - const { write: createLock } = useCreateLock(VOTING_ESCROW, (amount * (10 ** 18) || 0), days); - const { - write: approve = noOp, - isSuccess: isApproveSuccess, - isLoading: isApproveLoading, - } = useApproveBalance(POP_LP, VOTING_ESCROW, 1, { - onSuccess: (tx) => { - waitForTx(tx, { - successMessage: "POP approved!", - errorMessage: "Something went wrong", - }); - }, - onError: () => { - toast.error("User rejected the transaction", { - position: "top-center", - }); - }, - }); - - const { data: allowance } = useAllowance({ chainId: 1, address: POP_LP, account: VOTING_ESCROW as Address }); - const showApproveButton = isApproveSuccess ? false : amount > Number(allowance?.value || 0); - useEffect(() => { if (!showModal) setStep(0) }, @@ -65,17 +44,24 @@ export default function LockModal({ show }: { show: [boolean, Function] }): JSX. if ((amount || 0) == 0) return; // Early exit if value is ZERO - if (chain.id !== Number(1)) switchNetwork?.(Number(1)); + if (chain?.id as number !== Number(1)) switchNetwork?.(Number(1)); - if (showApproveButton) await approveBalance(POP_LP, VOTING_ESCROW); + await handleAllowance({ + token: { address: POP_LP } as Token, + inputAmount: (amount * (10 ** 18) || 0), + account: account as Address, + spender: VOTING_ESCROW, + publicClient, + walletClient: walletClient as WalletClient + }) // When approved continue to deposit - createLock(); + createLock(({ amount: (amount || 0), days, account: account as Address, clients: { publicClient, walletClient: walletClient as WalletClient } })); setShowModal(false); } return ( - + <> {step === 0 && } {step === 1 && } @@ -84,7 +70,7 @@ export default function LockModal({ show }: { show: [boolean, Function] }): JSX.
{step < 3 && setStep(step + 1)} />} - {step === 3 && } + {step === 3 && } {step === 0 && setStep(2)} />} {step === 1 || step === 3 && setStep(step - 1)} />}
diff --git a/components/vepop/modals/lock/LockPopInfo.tsx b/components/vepop/modals/lock/LockPopInfo.tsx new file mode 100644 index 0000000..3f71b2a --- /dev/null +++ b/components/vepop/modals/lock/LockPopInfo.tsx @@ -0,0 +1,26 @@ +export default function LockPopInfo(): JSX.Element { + return ( +
+ + + + + +
+

Locking POP

+

+ Lock your POP LP to receive vote-escrowed vePOP. + vePOP has many purposes. + It allows you to boost your vault yield by earning POP call options (oPOP). + You can use vePOP to vote on vault gauge incentives, + participate in governance and earn protocol fees. + Unlocking POP early results in a penalty of up to 75% of your POP. +

+
+
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/components/vepop/modals/lock/LockPopInterface.tsx b/components/vepop/modals/lock/LockPopInterface.tsx index 2aea002..d067ae3 100644 --- a/components/vepop/modals/lock/LockPopInterface.tsx +++ b/components/vepop/modals/lock/LockPopInterface.tsx @@ -1,13 +1,12 @@ -import InputNumber from "components/InputNumber"; import { Dispatch, FormEventHandler, SetStateAction, useMemo } from "react"; -import { calcUnlockTime, calculateVeOut } from "lib/Gauges/utils"; -import { useBalanceOf } from "lib/Erc20/hooks"; -import { Address, useAccount, useToken } from "wagmi"; -import InputTokenWithError from "components/InputTokenWithError"; -import { safeRound } from "lib/utils"; -import { constants } from "ethers"; -import { validateInput } from "components/SweetVault/internals/input"; -import { getVeAddresses } from "lib/utils/addresses"; +import { Address, useBalance, useToken } from "wagmi"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import InputTokenWithError from "@/components/input/InputTokenWithError"; +import InputNumber from "@/components/input/InputNumber"; +import { calcUnlockTime, calculateVeOut } from "@/lib/gauges/utils"; +import { ZERO } from "@/lib/constants"; +import { safeRound } from "@/lib/utils/formatBigNumber"; +import { validateInput } from "@/lib/utils/helpers"; const { BalancerPool: POP_LP } = getVeAddresses(); @@ -24,10 +23,8 @@ function LockTimeButton({ label, isActive, handleClick }: { label: string, isAct export default function LockPopInterface({ amountState, daysState }: { amountState: [number, Dispatch>], daysState: [number, Dispatch>] }): JSX.Element { - const { address: account } = useAccount() - const { data: popLp } = useToken({ chainId: 1, address: POP_LP as Address }); - const { data: popLpBal } = useBalanceOf({ chainId: 1, address: POP_LP, account }) + const { data: popLpBal } = useBalance({ chainId: 1, address: POP_LP }) const [amount, setAmount] = amountState const [days, setDays] = daysState @@ -36,7 +33,7 @@ export default function LockPopInterface({ amountState, daysState }: return (amount || 0) > Number(popLpBal?.formatted) ? "* Balance not available" : ""; }, [amount, popLpBal?.formatted]); - const handleMaxClick = () => setAmount(safeRound(popLpBal?.value || constants.Zero, 18)); + const handleMaxClick = () => setAmount(Number(safeRound(popLpBal?.value || ZERO, 18))); const handleChangeInput: FormEventHandler = ({ currentTarget: { value } }) => { setAmount(validateInput(value).isValid ? Number(value as any) : 0); diff --git a/components/vepop/modals/lock/LockPreview.tsx b/components/vepop/modals/lock/LockPreview.tsx new file mode 100644 index 0000000..f1c9a62 --- /dev/null +++ b/components/vepop/modals/lock/LockPreview.tsx @@ -0,0 +1,30 @@ +import { calcUnlockTime, calculateVeOut } from "@/lib/gauges/utils"; + +export default function LockPreview({ amount, days }: { amount: number, days: number }): JSX.Element { + return ( +
+ +

Preview Lock

+ +
+
+

Lock Amount

+

{amount > 0 ? amount.toFixed(2) : "0"} POP

+
+
+

Unlock Date

+

{new Date(calcUnlockTime(days)).toLocaleDateString()}

+
+
+

Initial Voting Power

+

{amount > 0 ? calculateVeOut(amount, days).toFixed(2) : "0"}

+
+
+ +
+

Important: vePOP is not transferrable and unlocking POP LP early results in a penalty of up to 75% of your POP LP

+
+ +
+ ) +} \ No newline at end of file diff --git a/components/vepop/modals/lock/VotingPowerInfo.tsx b/components/vepop/modals/lock/VotingPowerInfo.tsx new file mode 100644 index 0000000..e773a00 --- /dev/null +++ b/components/vepop/modals/lock/VotingPowerInfo.tsx @@ -0,0 +1,23 @@ +export default function VotingPowerInfo(): JSX.Element { + return ( +
+ + + + + + +
+

Voting Power

+

+ Lock your POP LP longer for more vePOP. + Your vePOP balance represents your voting power which decreases linearly until expiry. +

+
+
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/components/vepop/modals/manage/IncreaseStakeInterface.tsx b/components/vepop/modals/manage/IncreaseStakeInterface.tsx index 954ed22..96e09fa 100644 --- a/components/vepop/modals/manage/IncreaseStakeInterface.tsx +++ b/components/vepop/modals/manage/IncreaseStakeInterface.tsx @@ -1,22 +1,25 @@ import { Dispatch, FormEventHandler, SetStateAction, useMemo } from "react"; -import { calcDaysToUnlock, calculateVeOut } from "lib/Gauges/utils"; -import { useBalanceOf } from "lib/Erc20/hooks"; -import { Address, useAccount, useToken } from "wagmi"; -import InputTokenWithError from "components/InputTokenWithError"; -import { formatAndRoundBigNumber, safeRound } from "lib/utils"; -import { constants } from "ethers"; -import { validateInput } from "components/SweetVault/internals/input"; -import { LockedBalance } from "lib/Gauges/useLockedBalanceOf"; -import { getVeAddresses } from "lib/utils/addresses"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { Address, useBalance, useToken } from "wagmi"; +import { formatAndRoundBigNumber, safeRound } from "@/lib/utils/formatBigNumber"; +import { ZERO } from "@/lib/constants"; +import InputTokenWithError from "@/components/input/InputTokenWithError"; +import { calcDaysToUnlock, calculateVeOut } from "@/lib/gauges/utils"; +import { validateInput } from "@/lib/utils/helpers"; const { BalancerPool: POP_LP } = getVeAddresses(); -export default function IncreaseStakeInterface({ amountState, lockedBal }: - { amountState: [number, Dispatch>], lockedBal: LockedBalance }): JSX.Element { - const { address: account } = useAccount() +interface IncreaseStakeInterfaceProps { + amountState: [number, Dispatch>]; + lockedBal: { amount: bigint, end: bigint } +} +export default function IncreaseStakeInterface({ amountState, lockedBal }: IncreaseStakeInterfaceProps +): JSX.Element { const { data: popLp } = useToken({ chainId: 1, address: POP_LP as Address }); - const { data: popLpBal } = useBalanceOf({ chainId: 1, address: POP_LP, account }) + const { data: popLpBal } = useBalance({ chainId: 1, address: POP_LP }) + + console.log({ popLpBal }) const [amount, setAmount] = amountState @@ -24,7 +27,7 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }: return (amount || 0) > Number(popLpBal?.formatted) ? "* Balance not available" : ""; }, [amount, popLpBal?.formatted]); - const handleMaxClick = () => setAmount(safeRound(popLpBal?.value || constants.Zero, 18)); + const handleMaxClick = () => setAmount(Number(safeRound(popLpBal?.value || ZERO, 18))); const handleChangeInput: FormEventHandler = ({ currentTarget: { value } }) => { setAmount(validateInput(value).isValid ? Number(value as any) : 0); @@ -48,7 +51,7 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }: selectedToken={ { ...popLp, - balance: Number(popLpBal?.value || 0), + balance: Number(popLpBal?.value || 0) || 0, } as any } errorMessage={errorMessage} @@ -72,7 +75,11 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }:

New Voting Power

-

{amount > 0 ? calculateVeOut(amount + (Number(lockedBal?.amount) / 1e18), calcDaysToUnlock(Number(lockedBal?.end))).toFixed(2) : "Enter the amount to view your voting power"}

+

+ {amount > 0 ? + calculateVeOut(amount + (Number(lockedBal?.amount) / 1e18), calcDaysToUnlock(Number(lockedBal?.end))).toFixed(2) + : "Enter the amount to view your voting power"} +

diff --git a/components/vepop/modals/manage/IncreaseStakePreview.tsx b/components/vepop/modals/manage/IncreaseStakePreview.tsx new file mode 100644 index 0000000..22f7a16 --- /dev/null +++ b/components/vepop/modals/manage/IncreaseStakePreview.tsx @@ -0,0 +1,36 @@ +import { calcDaysToUnlock, calculateVeOut } from "@/lib/gauges/utils" + +export default function IncreaseStakePreview({ amount, lockedBal }: { amount: number, lockedBal: { amount: bigint, end: bigint } }): JSX.Element { + const totalLocked = (Number(lockedBal?.amount) / 1e18) + amount + + return ( +
+ +

Preview Lock

+ +
+
+

Lock Amount

+

{amount > 0 ? amount.toFixed(2) : "0"} POP LP

+
+
+

Total Locked

+

{lockedBal ? totalLocked.toFixed(2) : ""} POP LP

+
+
+

Unlock Date

+

{lockedBal && lockedBal?.end.toString() !== "0" ? new Date(Number(lockedBal?.end) * 1000).toLocaleDateString() : "-"}

+
+
+

New Voting Power

+

{amount > 0 ? calculateVeOut((Number(lockedBal?.amount) / 1e18) + amount, calcDaysToUnlock(Number(lockedBal?.end))).toFixed(2) : "0"} vePOP

+
+
+ +
+

Important: vePOP is not transferrable and unlocking POP LP early results in a penalty of up to 75% of your POP LP

+
+ +
+ ) +} \ No newline at end of file diff --git a/components/vepop/modals/manage/IncreaseTimeInteface.tsx b/components/vepop/modals/manage/IncreaseTimeInteface.tsx new file mode 100644 index 0000000..4772c4d --- /dev/null +++ b/components/vepop/modals/manage/IncreaseTimeInteface.tsx @@ -0,0 +1,71 @@ +import { Dispatch, FormEventHandler, SetStateAction } from "react"; +import InputNumber from "@/components/input/InputNumber"; +import { calcDaysToUnlock, calcUnlockTime, calculateVeOut } from "@/lib/gauges/utils"; + + +function LockTimeButton({ label, isActive, handleClick }: { label: string, isActive: boolean, handleClick: Function }): JSX.Element { + return ( + + ) +} + +export default function IncreaseTimeInterface({ daysState, lockedBal }: + { daysState: [number, Dispatch>], lockedBal: { amount: bigint, end: bigint } }): JSX.Element { + const [days, setDays] = daysState + + const handleSetDays: FormEventHandler = ({ currentTarget: { value } }) => { + setDays(Number(value)); + }; + + const totalDays = calcDaysToUnlock(Number(lockedBal?.end)) + days + + return ( +
+ +

Increase lock time

+ +
+

Lockup Time

+
+ setDays(7)} /> + setDays(30)} /> + setDays(90)} /> + setDays(180)} /> + setDays(365)} /> + setDays(730)} /> +
+ +
+
+
+

Unlocks at:

+

{new Date(calcUnlockTime(totalDays)).toLocaleDateString()}

+
+
+ +
+

New Voting Power

+
+

{Number(lockedBal?.amount) > 0 ? calculateVeOut(Number(lockedBal?.amount) / 1e18, totalDays).toFixed(2) : "0"}

+
+
+ +
+ ) +} \ No newline at end of file diff --git a/components/vepop/modals/manage/IncreaseTimePreview.tsx b/components/vepop/modals/manage/IncreaseTimePreview.tsx new file mode 100644 index 0000000..5e54d52 --- /dev/null +++ b/components/vepop/modals/manage/IncreaseTimePreview.tsx @@ -0,0 +1,37 @@ +import { calcDaysToUnlock, calcUnlockTime, calculateVeOut } from "@/lib/gauges/utils" + +export default function IncreaseTimePreview({ days, lockedBal }: { days: number, lockedBal: { amount: bigint, end: bigint } }): JSX.Element { + const totalDays = calcDaysToUnlock(Number(lockedBal?.end)) + days + const amount = Number(lockedBal?.amount) / 1e18 + + return ( +
+ +

Preview Lock

+ +
+
+

Lock Time

+

{days} Days

+
+
+

Unlock Date

+

{new Date(calcUnlockTime(totalDays)).toLocaleDateString()}

+
+
+

Lock Amount

+

{lockedBal && amount.toFixed(2)}

+
+
+

New Voting Power

+

{amount > 0 ? calculateVeOut(amount, totalDays).toFixed(2) : "0"} vePOP

+
+
+ +
+

Important: vePOP is not transferrable and unlocking POP LP early results in a penalty of up to 75% of your POP LP

+
+ +
+ ) +} \ No newline at end of file diff --git a/components/vepop/modals/manage/ManageLockModal.tsx b/components/vepop/modals/manage/ManageLockModal.tsx index 4fdbc6f..b8bf63e 100644 --- a/components/vepop/modals/manage/ManageLockModal.tsx +++ b/components/vepop/modals/manage/ManageLockModal.tsx @@ -1,98 +1,88 @@ -import Modal from "components/Modal/Modal"; -import { useEffect, useState } from "react"; -import MainActionButton from "components/MainActionButton"; -import TertiaryActionButton from "components/TertiaryActionButton"; -import SecondaryActionButton from "components/SecondaryActionButton"; -import useWaitForTx from "lib/utils/hooks/useWaitForTx"; -import { useCreateLock, useIncreaseLockAmount, useIncreaseLockTime, useWithdrawLock } from "lib/Gauges/utils"; -import { useApproveBalance } from "hooks/useApproveBalance"; -import toast from "react-hot-toast"; -import { useAllowance, useBalanceOf } from "lib/Erc20/hooks"; -import { Address, useAccount, useNetwork, useSwitchNetwork } from "wagmi"; +import { Address, useAccount, useBalance, useNetwork, usePublicClient, useSwitchNetwork, useWalletClient } from "wagmi"; +import { WalletClient } from "viem"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { getVeAddresses } from "lib/utils/addresses"; +import useLockedBalanceOf from "@/lib/gauges/useLockedBalanceOf"; +import Modal from "@/components/modal/Modal"; +import MainActionButton from "@/components/button/MainActionButton"; +import SecondaryActionButton from "@/components/button/SecondaryActionButton"; +import { showErrorToast } from "@/lib/toasts"; +import { handleAllowance } from "@/lib/approve"; +import { Token } from "@/lib/types"; +import { increaseLockAmount, increaseLockTime, withdrawLock } from "@/lib/gauges/interactions"; import SelectManagementOption from "./SelectManagementOption"; import IncreaseStakeInterface from "./IncreaseStakeInterface"; import IncreaseStakePreview from "./IncreaseStakePreview"; -import UnstakePreview from "./UnstakePreview"; +import IncreaseTimeInterface from "./IncreaseTimeInteface"; import IncreaseTimePreview from "./IncreaseTimePreview"; -import IncreaseTimeInterface from "./IncreaseTimeInterface"; -import useLockedBalanceOf from "lib/Gauges/useLockedBalanceOf"; -import { showSuccessToast, showErrorToast } from "lib/Toasts"; -import { getVeAddresses } from "lib/utils/addresses"; +import UnstakePreview from "./UnstakePreview"; const { BalancerPool: POP_LP, VotingEscrow: VOTING_ESCROW, } = getVeAddresses(); -function noOp() { } - export enum ManagementOption { IncreaseLock, IncreaseTime, Unlock } -export default function ManageLockModal({ show }: { show: [boolean, Function] }): JSX.Element { +export default function ManageLockModal({ show }: { show: [boolean, Dispatch>] }): JSX.Element { const { chain } = useNetwork(); const { switchNetwork } = useSwitchNetwork(); const { address: account } = useAccount(); + const publicClient = usePublicClient(); + const { data: walletClient } = useWalletClient() + const [showModal, setShowModal] = show; const [step, setStep] = useState(0); const [mangementOption, setMangementOption] = useState(); - const { data: vePopBal } = useBalanceOf({ chainId: 1, address: VOTING_ESCROW, account }) - const { data: lockedBal } = useLockedBalanceOf({ chainId: 1, address: VOTING_ESCROW, account }) + const { data: vePopBal } = useBalance({ chainId: 1, address: VOTING_ESCROW }) + const { data: lockedBal } = useLockedBalanceOf({ chainId: 1, address: VOTING_ESCROW, account: account as Address }) as { data: { amount: bigint, end: bigint } } const [amount, setAmount] = useState(0); const [days, setDays] = useState(7); - const isIncreaseLockValid = ((parseInt(lockedBal?.end.toHexString() || '0', 16) - Math.floor(Date.now() / 1000)) / (604800)) < 207 - - const { waitForTx } = useWaitForTx(); - const { write: increaseLockAmount } = useIncreaseLockAmount(VOTING_ESCROW, amount); - const { write: increaseLockTime } = useIncreaseLockTime(VOTING_ESCROW, Number(lockedBal?.end || 0) + (days * 86400)); - const { write: withdrawLock } = useWithdrawLock(VOTING_ESCROW); - const { - write: approve = noOp, - isSuccess: isApproveSuccess, - isLoading: isApproveLoading, - } = useApproveBalance(POP_LP, VOTING_ESCROW, 1, { - onSuccess: (tx) => { - waitForTx(tx, { - successMessage: "POP LP approved!", - errorMessage: "Something went wrong", - }); - }, - onError: (error) => { - showErrorToast(error); - }, - }); - - const { data: allowance } = useAllowance({ chainId: 1, address: POP_LP, account: VOTING_ESCROW as Address }); - const showApproveButton = isApproveSuccess ? false : amount > Number(allowance?.value || 0); + const isIncreaseLockValid = ((Number(lockedBal?.end) - Math.floor(Date.now() / 1000)) / (604800)) < 207 useEffect(() => { - if (!showModal) { setStep(0); setMangementOption(null) } + if (!showModal) { + setStep(0); + // @ts-ignore + setMangementOption(null) + } }, [showModal] ) async function handleMainAction() { - if (chain.id !== Number(1)) switchNetwork?.(Number(1)); + if (chain?.id as number !== Number(1)) switchNetwork?.(Number(1)); + + const clients = { publicClient, walletClient: walletClient as WalletClient } if (mangementOption === ManagementOption.IncreaseLock) { if ((amount || 0) == 0) return; - // Early exit if value is ZERO - if (showApproveButton) return approve(); - increaseLockAmount() + await handleAllowance({ + token: { address: POP_LP } as Token, + inputAmount: (amount * (10 ** 18) || 0), + account: account as Address, + spender: VOTING_ESCROW, + publicClient, + walletClient: walletClient as WalletClient + }) + increaseLockAmount({ amount, account: account as Address, clients }) } - if (mangementOption === ManagementOption.IncreaseTime) increaseLockTime() - if (mangementOption === ManagementOption.Unlock) withdrawLock() - setShowModal(false) + + if (mangementOption === ManagementOption.IncreaseTime) increaseLockTime({ unlockTime: Number(lockedBal?.end || 0) + (days * 86400), account: account as Address, clients }) + if (mangementOption === ManagementOption.Unlock) withdrawLock({ account: account as Address, clients }) + + setShowModal(false); } return ( - + <> {step === 0 && } @@ -107,7 +97,7 @@ export default function ManageLockModal({ show }: { show: [boolean, Function] }) {step === 2 && <> - + } diff --git a/components/vepop/modals/manage/SelectManagementOption.tsx b/components/vepop/modals/manage/SelectManagementOption.tsx new file mode 100644 index 0000000..351b2aa --- /dev/null +++ b/components/vepop/modals/manage/SelectManagementOption.tsx @@ -0,0 +1,50 @@ +import TertiaryActionButton from "@/components/button/TertiaryActionButton"; +import { ManagementOption } from "@/components/vepop/modals/manage/ManageLockModal"; + +export default function SelectManagementOption({ setStep, setManagementOption }: { setStep: Function, setManagementOption: Function }): JSX.Element { + return ( +
+ + + + + +
+

Update your Lock

+

+ Increase your vePOP by locking more POP LP or increasing the lock time for your locked POP LP balance. + Alternatively Unlock your locked POP LP. +

+
+
+
+ { + setManagementOption(ManagementOption.IncreaseLock); + setStep(1) + }} + /> +
+
+ { + setManagementOption(ManagementOption.IncreaseTime); + setStep(1) + }} + /> +
+
+ { + setManagementOption(ManagementOption.Unlock); + setStep(1) + }} + /> +
+
+
+ ) +} \ No newline at end of file diff --git a/components/vepop/modals/manage/UnstakePreview.tsx b/components/vepop/modals/manage/UnstakePreview.tsx new file mode 100644 index 0000000..65d27f8 --- /dev/null +++ b/components/vepop/modals/manage/UnstakePreview.tsx @@ -0,0 +1,32 @@ +export default function UnstakePreview({ amount }: { amount: number }): JSX.Element { + return ( +
+ +

Preview Unlock

+ +
+
+

Unlock Amount

+

{amount > 0 ? amount.toFixed(2) : "0"} POP LP

+
+
+

Unlock Penalty

+

25%

+
+
+

Returned Amount

+

{amount > 0 ? (amount * 0.75).toFixed(2) : "0"} POP LP

+
+
+

New Voting Power

+

0

+
+
+ +
+

Important: Unlocking your POP LP early will results in a penalty of {(amount * 0.25).toFixed(2)} POP LP

+
+ +
+ ) +} \ No newline at end of file diff --git a/components/vepop/modals/oPop/ExerciseOPopInterface.tsx b/components/vepop/modals/oPop/ExerciseOPopInterface.tsx index 7e0e049..0657320 100644 --- a/components/vepop/modals/oPop/ExerciseOPopInterface.tsx +++ b/components/vepop/modals/oPop/ExerciseOPopInterface.tsx @@ -1,20 +1,15 @@ import { Dispatch, FormEventHandler, SetStateAction, useEffect, useState } from "react"; -import { ethers } from "ethers"; -import { useAllowance, useBalanceOf } from "lib/Erc20/hooks"; -import { Address, useAccount, useBalance, useNetwork, useSwitchNetwork, useToken } from "wagmi"; -import { exerciseOPop } from "lib/OPop/useExerciseOPop"; -import InputTokenWithError from "components/InputTokenWithError"; -import { constants, utils } from "ethers"; +import { Address, useAccount, useBalance, usePublicClient, useToken } from "wagmi"; import { PlusIcon } from "@heroicons/react/24/outline"; -import InputNumber from "components/InputNumber"; -import TokenIcon from "components/TokenIcon"; -import useOPopPrice from "lib/OPop/useOPopPrice"; -import useOPopDiscount from "lib/OPop/useOPopDiscount"; -import { usePrice } from "lib/Price"; -import { formatAndRoundBigNumber, safeRound } from "lib/utils"; -import { validateInput } from "components/AssetInputWithAction/internals/input"; -import { getVeAddresses } from "lib/utils/addresses"; -import { useEthToUsd } from "lib/utils/resolvers/price-resolvers/ethToUsd"; +import TokenIcon from "@/components/common/TokenIcon"; +import InputTokenWithError from "@/components/input/InputTokenWithError"; +import { BalancerOracleAbi, ZERO } from "@/lib/constants"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { formatAndRoundBigNumber, safeRound } from "@/lib/utils/formatBigNumber"; +import { validateInput } from "@/lib/utils/helpers"; +import { Token } from "@/lib/types"; +import { llama } from "@/lib/resolver/price/resolver"; +import { useEthToUsd } from "@/lib/oPop/ethToUsd"; const { POP: POP, @@ -23,51 +18,77 @@ const { WETH: WETH } = getVeAddresses(); -export default function ExerciseOPopInterface({ amountState, maxPaymentAmountState }: - { amountState: [number, Dispatch>], maxPaymentAmountState: [number, Dispatch>] }): JSX.Element { +interface ExerciseOPopInterfaceProps { + amountState: [number, Dispatch>]; + maxPaymentAmountState: [number, Dispatch>]; +} + +export default function ExerciseOPopInterface({ amountState, maxPaymentAmountState }: ExerciseOPopInterfaceProps): JSX.Element { const { address: account } = useAccount(); + const publicClient = usePublicClient(); const [amount, setAmount] = amountState; const [maxPaymentAmount, setMaxPaymentAmount] = maxPaymentAmountState; - const { data: oPopPrice } = useOPopPrice({ chainId: 1, address: OPOP_ORACLE }) - const { data: popPrice } = usePrice({ chainId: 1, address: "0xd0cd466b34a24fcb2f87676278af2005ca8a78c4" }) - const { data: wethPrice } = usePrice({ chainId: 1, address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" }) - const { data: oPopDiscount } = useOPopDiscount({ chainId: 1, address: OPOP_ORACLE }) - - const { data: oPopBal } = useBalanceOf({ chainId: 1, address: OPOP, account }) + const { data: oPopBal } = useBalance({ chainId: 1, address: OPOP }) const { data: ethBal } = useBalance({ chainId: 1, address: account }) - const { data: wethBal } = useBalanceOf({ chainId: 1, address: WETH, account }) - - const { data: oPop } = useToken({ chainId: 1, address: OPOP as Address }); - const { data: pop } = useToken({ chainId: 1, address: POP as Address }); - const { data: weth } = useToken({ chainId: 1, address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" as Address }); // temp - WETH - - - const handleMaxWeth = () => { - const maxEth = safeRound(ethBal?.value || constants.Zero, 18); + const { data: wethBal } = useBalance({ chainId: 1, address: WETH }) + + const { data: oPop } = useToken({ chainId: 1, address: OPOP }); + const { data: pop } = useToken({ chainId: 1, address: POP }); + const { data: weth } = useToken({ chainId: 1, address: WETH }); + + const [oPopPrice, setOPopPrice] = useState(ZERO); + const [oPopDiscount, setOPopDiscount] = useState(0); + const [popPrice, setPopPrice] = useState(0); + const [wethPrice, setWethPrice] = useState(0); + + const [initialLoad, setInitialLoad] = useState(false) + + useEffect(() => { + function setUpPrices() { + setInitialLoad(true) + + llama({ address: "0x6F0fecBC276de8fC69257065fE47C5a03d986394", chainId: 10 }).then(res => setPopPrice(res)) + llama({ address: WETH, chainId: 1 }).then(res => setWethPrice(res)) + publicClient.readContract({ + address: OPOP_ORACLE, + abi: BalancerOracleAbi, + functionName: 'getPrice', + }).then(res => setOPopPrice(res)) + publicClient.readContract({ + address: OPOP_ORACLE, + abi: BalancerOracleAbi, + functionName: 'multiplier', + }).then(res => setOPopDiscount(res)) + } + if (!initialLoad) setUpPrices() + }, [initialLoad]) + + function handleMaxWeth() { + const maxEth = Number(safeRound(ethBal?.value || ZERO, 18)); setMaxPaymentAmount(maxEth); setAmount(getOPopAmount(maxEth)) }; - const handleMaxOPop = () => { - const maxOPop = safeRound(oPopBal?.value || constants.Zero, 18); + function handleMaxOPop() { + const maxOPop = Number(safeRound(oPopBal?.value || ZERO, 18)); setMaxPaymentAmount(getPaymentAmount(maxOPop)); setAmount(maxOPop) }; function getPaymentAmount(oPopAmount: number) { - const oPopValue = oPopAmount * (Number(oPopPrice?.value) / 1e18); + const oPopValue = oPopAmount * (Number(oPopPrice) / 1e18); - return oPopValue / (Number(wethPrice?.value) / 1e18); + return oPopValue / wethPrice; } function getOPopAmount(paymentAmount: number) { - const ethValue = paymentAmount * (Number(wethPrice?.value) / 1e18); + const ethValue = paymentAmount * wethPrice; - return ethValue / (Number(oPopPrice?.value) / 1e18); + return ethValue / (Number(oPopPrice) / 1e18); } const handleOPopInput: FormEventHandler = ({ currentTarget: { value } }) => { @@ -85,7 +106,10 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta return (

Exercise oPOP

-

Strike Price: $ {formatAndRoundBigNumber(useEthToUsd(oPopPrice?.value), 18)} | POP Price: $ {formatAndRoundBigNumber(popPrice?.value, 18)} | Discount: {(Number(oPopDiscount) / 100).toFixed(2)} %

+

+ Strike Price: $ {formatAndRoundBigNumber(useEthToUsd(oPopPrice) || ZERO, 18)} + | POP Price: $ {popPrice} + | Discount: {(Number(oPopDiscount) / 100).toFixed(2)} %

(Number(oPopBal?.value) / 1e18) ? "Insufficient Balance" : ""} @@ -122,7 +146,7 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta ...weth, decimals: 18, icon: "https://etherscan.io/token/images/weth_28.png", - balance: wethBal?.value || constants.Zero, + balance: wethBal?.value || ZERO, } as any } tokenList={[]} @@ -157,7 +181,7 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta className={`flex flex-row items-center justify-end`} >
- +

{pop?.symbol} diff --git a/components/vepop/modals/oPop/OPopModal.tsx b/components/vepop/modals/oPop/OPopModal.tsx index 9dca208..1c7c78b 100644 --- a/components/vepop/modals/oPop/OPopModal.tsx +++ b/components/vepop/modals/oPop/OPopModal.tsx @@ -1,23 +1,24 @@ -import Modal from "components/Modal/Modal"; -import { useEffect, useState } from "react"; -import MainActionButton from "components/MainActionButton"; -import SecondaryActionButton from "components/SecondaryActionButton"; -import { useAccount, useNetwork, useSwitchNetwork } from "wagmi"; -import { useExerciseOPop, exerciseOPop } from "lib/OPop/useExerciseOPop"; -import ExerciseOPopInterface from "./ExerciseOPopInterface"; -import OptionInfo from "./OptionInfo"; -import { getVeAddresses } from "lib/utils/addresses"; -import { useAllowance } from "lib/Erc20/hooks"; -import { approveBalance } from "hooks/useApproveBalance"; -import { Address } from "wagmi"; -import { utils, BigNumber } from "ethers"; +import Modal from "@/components/modal/Modal"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { Address, WalletClient, useAccount, useNetwork, usePublicClient, useSwitchNetwork, useWalletClient } from "wagmi"; +import OptionInfo from "@/components/vepop/modals/oPop/OptionInfo"; +import ExerciseOPopInterface from "@/components/vepop/modals/oPop/ExerciseOPopInterface"; +import MainActionButton from "@/components/button/MainActionButton"; +import SecondaryActionButton from "@/components/button/SecondaryActionButton"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { Token } from "@/lib/types"; +import { handleAllowance } from "@/lib/approve"; +import { parseEther } from "viem"; +import { exerciseOPop } from "@/lib/oPop/interactions"; const { BalancerOracle: OPOP_ORACLE, WETH: WETH, oPOP: OPOP } = getVeAddresses(); -export default function OPopModal({ show }: { show: [boolean, Function] }): JSX.Element { +export default function OPopModal({ show }: { show: [boolean, Dispatch>] }): JSX.Element { const { chain } = useNetwork(); const { switchNetwork } = useSwitchNetwork(); const { address: account } = useAccount(); + const publicClient = usePublicClient(); + const { data: walletClient } = useWalletClient() const [step, setStep] = useState(0); const [showModal, setShowModal] = show; @@ -25,9 +26,6 @@ export default function OPopModal({ show }: { show: [boolean, Function] }): JSX. const [amount, setAmount] = useState(0); const [maxPaymentAmount, setMaxPaymentAmount] = useState(0); - const { data: allowance } = useAllowance({ chainId: 1, address: WETH, account: OPOP as Address }); - const needAllowance = amount > Number(allowance?.value || 0); - useEffect(() => { if (!showModal) setStep(0) setAmount(0); @@ -40,28 +38,36 @@ export default function OPopModal({ show }: { show: [boolean, Function] }): JSX. if ((amount || 0) == 0) return; // Early exit if value is ZERO - if (chain.id !== Number(1)) switchNetwork?.(Number(1)); + if (chain?.id as number !== Number(1)) switchNetwork?.(Number(1)); + + await handleAllowance({ + token: { address: WETH } as Token, + inputAmount: (amount * (10 ** 18) || 0), + account: account as Address, + spender: OPOP, + publicClient, + walletClient: walletClient as WalletClient + }) - if (needAllowance) await approveBalance(WETH, OPOP); - exerciseOPop(OPOP, account, utils.parseEther(String(amount)).toString(), utils.parseEther(maxPaymentAmount.toFixed(18)).mul(BigNumber.from("10000")).toString()); + exerciseOPop({ + account: account as Address, + amount: parseEther(Number(amount).toLocaleString("fullwide", { useGrouping: false })), + maxPaymentAmount: parseEther(maxPaymentAmount.toFixed(18)) * BigInt("10000"), + clients: { publicClient, walletClient: walletClient as WalletClient } + }); setShowModal(false); } return ( - + <> {step === 0 && } {step === 1 && }

{step === 0 && setStep(step + 1)} />} - { - step === 1 && ( - needAllowance - ? - : - ) - } {step === 1 && setStep(step - 1)} />} + {step === 1 && } + {step === 1 && setStep(step - 1)} />}
diff --git a/components/vepop/modals/oPop/OptionInfo.tsx b/components/vepop/modals/oPop/OptionInfo.tsx new file mode 100644 index 0000000..0d195e8 --- /dev/null +++ b/components/vepop/modals/oPop/OptionInfo.tsx @@ -0,0 +1,18 @@ +export default function OptionInfo(): JSX.Element { + return ( +
+ + + + + +
+

Exercise oPOP

+

+ Exercise your oPOP to buy discounted POP. + You need to burn oPOP and pay with WETH to get cheap POP directly from the DAO. +

+
+
+ ) +} \ No newline at end of file diff --git a/lib/constants/abi/BalancerOracle.ts b/lib/constants/abi/BalancerOracle.ts new file mode 100644 index 0000000..c453027 --- /dev/null +++ b/lib/constants/abi/BalancerOracle.ts @@ -0,0 +1 @@ +export const BalancerOracleAbi = [{ "inputs": [{ "internalType": "contract IBalancerTwapOracle", "name": "balancerTwapOracle_", "type": "address" }, { "internalType": "address", "name": "owner_", "type": "address" }, { "internalType": "uint16", "name": "multiplier_", "type": "uint16" }, { "internalType": "uint56", "name": "secs_", "type": "uint56" }, { "internalType": "uint56", "name": "ago_", "type": "uint56" }, { "internalType": "uint128", "name": "minPrice_", "type": "uint128" }], "stateMutability": "nonpayable", "type": "constructor" }, { "inputs": [], "name": "BalancerOracle__TWAPOracleNotReady", "type": "error" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" }], "name": "OwnershipTransferred", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": false, "internalType": "uint16", "name": "multiplier", "type": "uint16" }, { "indexed": false, "internalType": "uint56", "name": "secs", "type": "uint56" }, { "indexed": false, "internalType": "uint56", "name": "ago", "type": "uint56" }, { "indexed": false, "internalType": "uint128", "name": "minPrice", "type": "uint128" }], "name": "SetParams", "type": "event" }, { "inputs": [], "name": "ago", "outputs": [{ "internalType": "uint56", "name": "", "type": "uint56" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "balancerTwapOracle", "outputs": [{ "internalType": "contract IBalancerTwapOracle", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "getPrice", "outputs": [{ "internalType": "uint256", "name": "price", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "minPrice", "outputs": [{ "internalType": "uint128", "name": "", "type": "uint128" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "multiplier", "outputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "secs", "outputs": [{ "internalType": "uint56", "name": "", "type": "uint56" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint16", "name": "multiplier_", "type": "uint16" }, { "internalType": "uint56", "name": "secs_", "type": "uint56" }, { "internalType": "uint56", "name": "ago_", "type": "uint56" }, { "internalType": "uint128", "name": "minPrice_", "type": "uint128" }], "name": "setParams", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }] as const \ No newline at end of file diff --git a/lib/constants/abi/Gauge.ts b/lib/constants/abi/Gauge.ts new file mode 100644 index 0000000..e19da76 --- /dev/null +++ b/lib/constants/abi/Gauge.ts @@ -0,0 +1 @@ +export const GaugeAbi = [{ "name": "Deposit", "inputs": [{ "name": "provider", "type": "address", "indexed": true }, { "name": "value", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "Withdraw", "inputs": [{ "name": "provider", "type": "address", "indexed": true }, { "name": "value", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "UpdateLiquidityLimit", "inputs": [{ "name": "user", "type": "address", "indexed": true }, { "name": "original_balance", "type": "uint256", "indexed": false }, { "name": "original_supply", "type": "uint256", "indexed": false }, { "name": "working_balance", "type": "uint256", "indexed": false }, { "name": "working_supply", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "Transfer", "inputs": [{ "name": "_from", "type": "address", "indexed": true }, { "name": "_to", "type": "address", "indexed": true }, { "name": "_value", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "Approval", "inputs": [{ "name": "_owner", "type": "address", "indexed": true }, { "name": "_spender", "type": "address", "indexed": true }, { "name": "_value", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "RewardDistributorUpdated", "inputs": [{ "name": "reward_token", "type": "address", "indexed": true }, { "name": "distributor", "type": "address", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "RelativeWeightCapChanged", "inputs": [{ "name": "new_relative_weight_cap", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "NewPendingAdmin", "inputs": [{ "name": "new_pending_admin", "type": "address", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "NewAdmin", "inputs": [{ "name": "new_admin", "type": "address", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "NewTokenlessProduction", "inputs": [{ "name": "new_tokenless_production", "type": "uint8", "indexed": false }], "anonymous": false, "type": "event" }, { "stateMutability": "nonpayable", "type": "constructor", "inputs": [{ "name": "minter", "type": "address" }, { "name": "delegation_proxy", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "deposit", "inputs": [{ "name": "_value", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "deposit", "inputs": [{ "name": "_value", "type": "uint256" }, { "name": "_addr", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "deposit", "inputs": [{ "name": "_value", "type": "uint256" }, { "name": "_addr", "type": "address" }, { "name": "_claim_rewards", "type": "bool" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "withdraw", "inputs": [{ "name": "_value", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "withdraw", "inputs": [{ "name": "_value", "type": "uint256" }, { "name": "_claim_rewards", "type": "bool" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "claim_rewards", "inputs": [], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "claim_rewards", "inputs": [{ "name": "_addr", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "claim_rewards", "inputs": [{ "name": "_addr", "type": "address" }, { "name": "_receiver", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "transferFrom", "inputs": [{ "name": "_from", "type": "address" }, { "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" }], "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "transfer", "inputs": [{ "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" }], "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "approve", "inputs": [{ "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" }], "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "permit", "inputs": [{ "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" }, { "name": "_deadline", "type": "uint256" }, { "name": "_v", "type": "uint8" }, { "name": "_r", "type": "bytes32" }, { "name": "_s", "type": "bytes32" }], "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "increaseAllowance", "inputs": [{ "name": "_spender", "type": "address" }, { "name": "_added_value", "type": "uint256" }], "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "decreaseAllowance", "inputs": [{ "name": "_spender", "type": "address" }, { "name": "_subtracted_value", "type": "uint256" }], "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "user_checkpoint", "inputs": [{ "name": "addr", "type": "address" }], "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "set_rewards_receiver", "inputs": [{ "name": "_receiver", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "kick", "inputs": [{ "name": "addr", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "deposit_reward_token", "inputs": [{ "name": "_reward_token", "type": "address" }, { "name": "_amount", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "add_reward", "inputs": [{ "name": "_reward_token", "type": "address" }, { "name": "_distributor", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "set_reward_distributor", "inputs": [{ "name": "_reward_token", "type": "address" }, { "name": "_distributor", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "killGauge", "inputs": [], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "unkillGauge", "inputs": [], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "change_pending_admin", "inputs": [{ "name": "new_pending_admin", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "claim_admin", "inputs": [], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "set_tokenless_production", "inputs": [{ "name": "new_tokenless_production", "type": "uint8" }], "outputs": [] }, { "stateMutability": "view", "type": "function", "name": "claimed_reward", "inputs": [{ "name": "_addr", "type": "address" }, { "name": "_token", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "claimable_reward", "inputs": [{ "name": "_user", "type": "address" }, { "name": "_reward_token", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "claimable_tokens", "inputs": [{ "name": "addr", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "integrate_checkpoint", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "future_epoch_time", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "inflation_rate", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "version", "inputs": [], "outputs": [{ "name": "", "type": "string" }] }, { "stateMutability": "view", "type": "function", "name": "allowance", "inputs": [{ "name": "owner", "type": "address" }, { "name": "spender", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "is_killed", "inputs": [], "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "initialize", "inputs": [{ "name": "_lp_token", "type": "address" }, { "name": "relative_weight_cap", "type": "uint256" }, { "name": "_admin", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "setRelativeWeightCap", "inputs": [{ "name": "relative_weight_cap", "type": "uint256" }], "outputs": [] }, { "stateMutability": "view", "type": "function", "name": "getRelativeWeightCap", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "getCappedRelativeWeight", "inputs": [{ "name": "time", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "pure", "type": "function", "name": "getMaxRelativeWeightCap", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "tokenless_production", "inputs": [], "outputs": [{ "name": "", "type": "uint8" }] }, { "stateMutability": "view", "type": "function", "name": "pending_admin", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "admin", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "balanceOf", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "totalSupply", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "name", "inputs": [], "outputs": [{ "name": "", "type": "string" }] }, { "stateMutability": "view", "type": "function", "name": "symbol", "inputs": [], "outputs": [{ "name": "", "type": "string" }] }, { "stateMutability": "view", "type": "function", "name": "DOMAIN_SEPARATOR", "inputs": [], "outputs": [{ "name": "", "type": "bytes32" }] }, { "stateMutability": "view", "type": "function", "name": "nonces", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "lp_token", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "gauge_state", "inputs": [], "outputs": [{ "name": "", "type": "uint8" }] }, { "stateMutability": "view", "type": "function", "name": "decimals", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "reward_count", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "reward_data", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "tuple", "components": [{ "name": "token", "type": "address" }, { "name": "distributor", "type": "address" }, { "name": "period_finish", "type": "uint256" }, { "name": "rate", "type": "uint256" }, { "name": "last_update", "type": "uint256" }, { "name": "integral", "type": "uint256" }] }] }, { "stateMutability": "view", "type": "function", "name": "rewards_receiver", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "reward_integral_for", "inputs": [{ "name": "arg0", "type": "address" }, { "name": "arg1", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "working_balances", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "working_supply", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "integrate_inv_supply_of", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "integrate_checkpoint_of", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "integrate_fraction", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "period", "inputs": [], "outputs": [{ "name": "", "type": "int128" }] }, { "stateMutability": "view", "type": "function", "name": "reward_tokens", "inputs": [{ "name": "arg0", "type": "uint256" }], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "period_timestamp", "inputs": [{ "name": "arg0", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "integrate_inv_supply", "inputs": [{ "name": "arg0", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }] as const; \ No newline at end of file diff --git a/lib/constants/abi/GaugeController.ts b/lib/constants/abi/GaugeController.ts new file mode 100644 index 0000000..587ee6b --- /dev/null +++ b/lib/constants/abi/GaugeController.ts @@ -0,0 +1 @@ +export const GaugeControllerAbi = [{ "name": "AddType", "inputs": [{ "name": "name", "type": "string", "indexed": false }, { "name": "type_id", "type": "int128", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "NewTypeWeight", "inputs": [{ "name": "type_id", "type": "int128", "indexed": false }, { "name": "time", "type": "uint256", "indexed": false }, { "name": "weight", "type": "uint256", "indexed": false }, { "name": "total_weight", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "NewGaugeWeight", "inputs": [{ "name": "gauge_address", "type": "address", "indexed": false }, { "name": "time", "type": "uint256", "indexed": false }, { "name": "weight", "type": "uint256", "indexed": false }, { "name": "total_weight", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "VoteForGauge", "inputs": [{ "name": "time", "type": "uint256", "indexed": false }, { "name": "user", "type": "address", "indexed": false }, { "name": "gauge_addr", "type": "address", "indexed": false }, { "name": "weight", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "NewGauge", "inputs": [{ "name": "addr", "type": "address", "indexed": false }, { "name": "gauge_type", "type": "int128", "indexed": false }, { "name": "weight", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "NewPendingAdmin", "inputs": [{ "name": "new_pending_admin", "type": "address", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "NewAdmin", "inputs": [{ "name": "new_admin", "type": "address", "indexed": false }], "anonymous": false, "type": "event" }, { "stateMutability": "nonpayable", "type": "constructor", "inputs": [{ "name": "_voting_escrow", "type": "address" }, { "name": "_admin", "type": "address" }], "outputs": [] }, { "stateMutability": "view", "type": "function", "name": "token", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "voting_escrow", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "gauge_exists", "inputs": [{ "name": "_addr", "type": "address" }], "outputs": [{ "name": "", "type": "bool" }] }, { "stateMutability": "view", "type": "function", "name": "gauge_types", "inputs": [{ "name": "_addr", "type": "address" }], "outputs": [{ "name": "", "type": "int128" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "add_gauge", "inputs": [{ "name": "addr", "type": "address" }, { "name": "gauge_type", "type": "int128" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "add_gauge", "inputs": [{ "name": "addr", "type": "address" }, { "name": "gauge_type", "type": "int128" }, { "name": "weight", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "checkpoint", "inputs": [], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "checkpoint_gauge", "inputs": [{ "name": "addr", "type": "address" }], "outputs": [] }, { "stateMutability": "view", "type": "function", "name": "gauge_relative_weight", "inputs": [{ "name": "addr", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "gauge_relative_weight", "inputs": [{ "name": "addr", "type": "address" }, { "name": "time", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "gauge_relative_weight_write", "inputs": [{ "name": "addr", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "gauge_relative_weight_write", "inputs": [{ "name": "addr", "type": "address" }, { "name": "time", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "add_type", "inputs": [{ "name": "_name", "type": "string" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "add_type", "inputs": [{ "name": "_name", "type": "string" }, { "name": "weight", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "change_type_weight", "inputs": [{ "name": "type_id", "type": "int128" }, { "name": "weight", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "change_gauge_weight", "inputs": [{ "name": "addr", "type": "address" }, { "name": "weight", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "vote_for_many_gauge_weights", "inputs": [{ "name": "_gauge_addrs", "type": "address[8]" }, { "name": "_user_weight", "type": "uint256[8]" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "vote_for_gauge_weights", "inputs": [{ "name": "_gauge_addr", "type": "address" }, { "name": "_user_weight", "type": "uint256" }], "outputs": [] }, { "stateMutability": "view", "type": "function", "name": "get_gauge_weight", "inputs": [{ "name": "addr", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "get_type_weight", "inputs": [{ "name": "type_id", "type": "int128" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "get_total_weight", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "get_weights_sum_per_type", "inputs": [{ "name": "type_id", "type": "int128" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "change_pending_admin", "inputs": [{ "name": "new_pending_admin", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "claim_admin", "inputs": [], "outputs": [] }, { "stateMutability": "view", "type": "function", "name": "pending_admin", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "admin", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "n_gauge_types", "inputs": [], "outputs": [{ "name": "", "type": "int128" }] }, { "stateMutability": "view", "type": "function", "name": "n_gauges", "inputs": [], "outputs": [{ "name": "", "type": "int128" }] }, { "stateMutability": "view", "type": "function", "name": "gauge_type_names", "inputs": [{ "name": "arg0", "type": "int128" }], "outputs": [{ "name": "", "type": "string" }] }, { "stateMutability": "view", "type": "function", "name": "gauges", "inputs": [{ "name": "arg0", "type": "uint256" }], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "vote_user_slopes", "inputs": [{ "name": "arg0", "type": "address" }, { "name": "arg1", "type": "address" }], "outputs": [{ "name": "", "type": "tuple", "components": [{ "name": "slope", "type": "uint256" }, { "name": "power", "type": "uint256" }, { "name": "end", "type": "uint256" }] }] }, { "stateMutability": "view", "type": "function", "name": "vote_user_power", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "last_user_vote", "inputs": [{ "name": "arg0", "type": "address" }, { "name": "arg1", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "points_weight", "inputs": [{ "name": "arg0", "type": "address" }, { "name": "arg1", "type": "uint256" }], "outputs": [{ "name": "", "type": "tuple", "components": [{ "name": "bias", "type": "uint256" }, { "name": "slope", "type": "uint256" }] }] }, { "stateMutability": "view", "type": "function", "name": "time_weight", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "points_sum", "inputs": [{ "name": "arg0", "type": "int128" }, { "name": "arg1", "type": "uint256" }], "outputs": [{ "name": "", "type": "tuple", "components": [{ "name": "bias", "type": "uint256" }, { "name": "slope", "type": "uint256" }] }] }, { "stateMutability": "view", "type": "function", "name": "time_sum", "inputs": [{ "name": "arg0", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "points_total", "inputs": [{ "name": "arg0", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "time_total", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "points_type_weight", "inputs": [{ "name": "arg0", "type": "int128" }, { "name": "arg1", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "time_type_weight", "inputs": [{ "name": "arg0", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }] as const; \ No newline at end of file diff --git a/lib/constants/abi/Minter.ts b/lib/constants/abi/Minter.ts new file mode 100644 index 0000000..92dd3d0 --- /dev/null +++ b/lib/constants/abi/Minter.ts @@ -0,0 +1 @@ +export const MinterAbi = [{ "inputs": [{ "internalType": "contract ITokenAdmin", "name": "tokenAdmin", "type": "address" }, { "internalType": "contract IGaugeController", "name": "gaugeController", "type": "address" }], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "recipient", "type": "address" }, { "indexed": false, "internalType": "address", "name": "gauge", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "minted", "type": "uint256" }], "name": "Minted", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": true, "internalType": "address", "name": "minter", "type": "address" }, { "indexed": false, "internalType": "bool", "name": "approval", "type": "bool" }], "name": "MinterApprovalSet", "type": "event" }, { "inputs": [{ "internalType": "address", "name": "minter", "type": "address" }, { "internalType": "address", "name": "user", "type": "address" }], "name": "allowed_to_mint_for", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "getGaugeController", "outputs": [{ "internalType": "contract IGaugeController", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "minter", "type": "address" }, { "internalType": "address", "name": "user", "type": "address" }], "name": "getMinterApproval", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "getToken", "outputs": [{ "internalType": "contract IERC20", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "getTokenAdmin", "outputs": [{ "internalType": "contract ITokenAdmin", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "gauge", "type": "address" }], "name": "mint", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "gauge", "type": "address" }, { "internalType": "address", "name": "user", "type": "address" }], "name": "mintFor", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address[]", "name": "gauges", "type": "address[]" }], "name": "mintMany", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address[]", "name": "gauges", "type": "address[]" }, { "internalType": "address", "name": "user", "type": "address" }], "name": "mintManyFor", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "gauge", "type": "address" }, { "internalType": "address", "name": "user", "type": "address" }], "name": "mint_for", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address[8]", "name": "gauges", "type": "address[8]" }], "name": "mint_many", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "user", "type": "address" }, { "internalType": "address", "name": "gauge", "type": "address" }], "name": "minted", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "minter", "type": "address" }, { "internalType": "bool", "name": "approval", "type": "bool" }], "name": "setMinterApproval", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "minter", "type": "address" }], "name": "toggle_approve_mint", "outputs": [], "stateMutability": "nonpayable", "type": "function" }] as const \ No newline at end of file diff --git a/lib/constants/abi/OPop.ts b/lib/constants/abi/OPop.ts new file mode 100644 index 0000000..e62cc36 --- /dev/null +++ b/lib/constants/abi/OPop.ts @@ -0,0 +1 @@ +export const OPopAbi = [{ "inputs": [{ "internalType": "string", "name": "name_", "type": "string" }, { "internalType": "string", "name": "symbol_", "type": "string" }, { "internalType": "address", "name": "owner_", "type": "address" }, { "internalType": "address", "name": "tokenAdmin_", "type": "address" }, { "internalType": "contract ERC20", "name": "paymentToken_", "type": "address" }, { "internalType": "contract ERC20", "name": "underlyingToken_", "type": "address" }, { "internalType": "contract IOracle", "name": "oracle_", "type": "address" }, { "internalType": "address", "name": "treasury_", "type": "address" }], "stateMutability": "nonpayable", "type": "constructor" }, { "inputs": [], "name": "OptionsToken__NotTokenAdmin", "type": "error" }, { "inputs": [], "name": "OptionsToken__PastDeadline", "type": "error" }, { "inputs": [], "name": "OptionsToken__SlippageTooHigh", "type": "error" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "Approval", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "sender", "type": "address" }, { "indexed": true, "internalType": "address", "name": "recipient", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "paymentAmount", "type": "uint256" }], "name": "Exercise", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" }], "name": "OwnershipTransferred", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "contract IOracle", "name": "newOracle", "type": "address" }], "name": "SetOracle", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "newTreasury", "type": "address" }], "name": "SetTreasury", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "Transfer", "type": "event" }, { "inputs": [], "name": "DOMAIN_SEPARATOR", "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "", "type": "address" }, { "internalType": "address", "name": "", "type": "address" }], "name": "allowance", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "approve", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "", "type": "address" }], "name": "balanceOf", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "decimals", "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }, { "internalType": "uint256", "name": "maxPaymentAmount", "type": "uint256" }, { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "deadline", "type": "uint256" }], "name": "exercise", "outputs": [{ "internalType": "uint256", "name": "paymentAmount", "type": "uint256" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }, { "internalType": "uint256", "name": "maxPaymentAmount", "type": "uint256" }, { "internalType": "address", "name": "recipient", "type": "address" }], "name": "exercise", "outputs": [{ "internalType": "uint256", "name": "paymentAmount", "type": "uint256" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "mint", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "name", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "", "type": "address" }], "name": "nonces", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "oracle", "outputs": [{ "internalType": "contract IOracle", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "paymentToken", "outputs": [{ "internalType": "contract ERC20", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "uint256", "name": "deadline", "type": "uint256" }, { "internalType": "uint8", "name": "v", "type": "uint8" }, { "internalType": "bytes32", "name": "r", "type": "bytes32" }, { "internalType": "bytes32", "name": "s", "type": "bytes32" }], "name": "permit", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "contract IOracle", "name": "oracle_", "type": "address" }], "name": "setOracle", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "treasury_", "type": "address" }], "name": "setTreasury", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "tokenAdmin", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "totalSupply", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "transfer", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "from", "type": "address" }, { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "transferFrom", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "treasury", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "underlyingToken", "outputs": [{ "internalType": "contract ERC20", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }] as const; \ No newline at end of file diff --git a/lib/constants/abi/VotingEscrow.ts b/lib/constants/abi/VotingEscrow.ts new file mode 100644 index 0000000..21ebab8 --- /dev/null +++ b/lib/constants/abi/VotingEscrow.ts @@ -0,0 +1 @@ +export const VotingEscrowAbi = [{ "name": "Deposit", "inputs": [{ "name": "provider", "type": "address", "indexed": true }, { "name": "value", "type": "uint256", "indexed": false }, { "name": "locktime", "type": "uint256", "indexed": true }, { "name": "type", "type": "int128", "indexed": false }, { "name": "ts", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "Withdraw", "inputs": [{ "name": "provider", "type": "address", "indexed": true }, { "name": "value", "type": "uint256", "indexed": false }, { "name": "ts", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "Penalty", "inputs": [{ "name": "provider", "type": "address", "indexed": true }, { "name": "value", "type": "uint256", "indexed": false }, { "name": "ts", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "Supply", "inputs": [{ "name": "prevSupply", "type": "uint256", "indexed": false }, { "name": "supply", "type": "uint256", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "NewPendingAdmin", "inputs": [{ "name": "new_pending_admin", "type": "address", "indexed": false }], "anonymous": false, "type": "event" }, { "name": "NewAdmin", "inputs": [{ "name": "new_admin", "type": "address", "indexed": false }], "anonymous": false, "type": "event" }, { "stateMutability": "nonpayable", "type": "constructor", "inputs": [{ "name": "token_addr", "type": "address" }, { "name": "_name", "type": "string" }, { "name": "_symbol", "type": "string" }, { "name": "_admin", "type": "address" }], "outputs": [] }, { "stateMutability": "view", "type": "function", "name": "token", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "name", "inputs": [], "outputs": [{ "name": "", "type": "string" }] }, { "stateMutability": "view", "type": "function", "name": "symbol", "inputs": [], "outputs": [{ "name": "", "type": "string" }] }, { "stateMutability": "view", "type": "function", "name": "decimals", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "commit_smart_wallet_checker", "inputs": [{ "name": "addr", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "apply_smart_wallet_checker", "inputs": [], "outputs": [] }, { "stateMutability": "view", "type": "function", "name": "get_last_user_slope", "inputs": [{ "name": "addr", "type": "address" }], "outputs": [{ "name": "", "type": "int128" }] }, { "stateMutability": "view", "type": "function", "name": "user_point_history__ts", "inputs": [{ "name": "_addr", "type": "address" }, { "name": "_idx", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "locked__end", "inputs": [{ "name": "_addr", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "checkpoint", "inputs": [], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "deposit_for", "inputs": [{ "name": "_addr", "type": "address" }, { "name": "_value", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "create_lock", "inputs": [{ "name": "_value", "type": "uint256" }, { "name": "_unlock_time", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "increase_amount", "inputs": [{ "name": "_value", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "increase_unlock_time", "inputs": [{ "name": "_unlock_time", "type": "uint256" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "withdraw", "inputs": [], "outputs": [] }, { "stateMutability": "view", "type": "function", "name": "balanceOf", "inputs": [{ "name": "addr", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "balanceOf", "inputs": [{ "name": "addr", "type": "address" }, { "name": "_t", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "balanceOfAt", "inputs": [{ "name": "addr", "type": "address" }, { "name": "_block", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "totalSupply", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "totalSupply", "inputs": [{ "name": "t", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "totalSupplyAt", "inputs": [{ "name": "_block", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "nonpayable", "type": "function", "name": "change_pending_admin", "inputs": [{ "name": "new_pending_admin", "type": "address" }], "outputs": [] }, { "stateMutability": "nonpayable", "type": "function", "name": "claim_admin", "inputs": [], "outputs": [] }, { "stateMutability": "view", "type": "function", "name": "pending_admin", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "admin", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "supply", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "locked", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "tuple", "components": [{ "name": "amount", "type": "int128" }, { "name": "end", "type": "uint256" }] }] }, { "stateMutability": "view", "type": "function", "name": "epoch", "inputs": [], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "point_history", "inputs": [{ "name": "arg0", "type": "uint256" }], "outputs": [{ "name": "", "type": "tuple", "components": [{ "name": "bias", "type": "int128" }, { "name": "slope", "type": "int128" }, { "name": "ts", "type": "uint256" }, { "name": "blk", "type": "uint256" }] }] }, { "stateMutability": "view", "type": "function", "name": "user_point_history", "inputs": [{ "name": "arg0", "type": "address" }, { "name": "arg1", "type": "uint256" }], "outputs": [{ "name": "", "type": "tuple", "components": [{ "name": "bias", "type": "int128" }, { "name": "slope", "type": "int128" }, { "name": "ts", "type": "uint256" }, { "name": "blk", "type": "uint256" }] }] }, { "stateMutability": "view", "type": "function", "name": "user_point_epoch", "inputs": [{ "name": "arg0", "type": "address" }], "outputs": [{ "name": "", "type": "uint256" }] }, { "stateMutability": "view", "type": "function", "name": "slope_changes", "inputs": [{ "name": "arg0", "type": "uint256" }], "outputs": [{ "name": "", "type": "int128" }] }, { "stateMutability": "view", "type": "function", "name": "future_smart_wallet_checker", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }, { "stateMutability": "view", "type": "function", "name": "smart_wallet_checker", "inputs": [], "outputs": [{ "name": "", "type": "address" }] }] as const; \ No newline at end of file diff --git a/lib/constants/abi/index.ts b/lib/constants/abi/index.ts index 34c65c3..96fe83e 100644 --- a/lib/constants/abi/index.ts +++ b/lib/constants/abi/index.ts @@ -1,3 +1,9 @@ export * from "./ERC20"; export * from "./Vault"; -export * from "./VaultRegistry"; \ No newline at end of file +export * from "./VaultRegistry"; +export * from "./GaugeController"; +export * from "./Gauge"; +export * from "./VotingEscrow"; +export * from "./BalancerOracle"; +export * from "./OPop"; +export * from "./Minter"; \ No newline at end of file diff --git a/lib/feeDistributor/getClaimableVeReward.ts b/lib/feeDistributor/getClaimableVeReward.ts new file mode 100644 index 0000000..8dd1854 --- /dev/null +++ b/lib/feeDistributor/getClaimableVeReward.ts @@ -0,0 +1,108 @@ +import { Chain, createPublicClient, http } from 'viem'; +import { thisPeriodTimestamp } from '@/lib/gauges/utils'; +import { ZERO } from '@/lib/constants'; +import { RPC_URLS } from '@/lib/utils/connectors'; + +interface GetVeRewardsProps { + chain: Chain; + address: `0x${string}`; + user: `0x${string}`; + token: `0x${string}`; +}; + +export default async function getClaimableVeReward({ chain, address, user, token }: GetVeRewardsProps): Promise { + const timestamp = BigInt(String(thisPeriodTimestamp())); + + const client = createPublicClient({ chain, transport: http(RPC_URLS[chain.id]) }) + const data = await client.multicall({ + contracts: [ + { + address, + abi: abiFeeDistributor, + functionName: "getTotalSupplyAtTimestamp", + args: [timestamp] + }, + { + address, + abi: abiFeeDistributor, + functionName: "getUserBalanceAtTimestamp", + args: [user, timestamp] + }, + { + address, + abi: abiFeeDistributor, + functionName: "getTokensDistributedInWeek", + args: [token, timestamp] + }, + ], + allowFailure: false + }) + + if (Number(data[1]) && Number(data[2]) > 0 && Number(data[0]) > 0) { + return (data[1] * data[2]) / data[0]; + } + + return ZERO; +} + +const abiFeeDistributor = [ + { + "stateMutability": "view", + "type": "function", + "name": "getTokensDistributedInWeek", + "inputs": [ + { + "name": "token", + "type": "address" + }, + { + "name": "timestamp", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "getTotalSupplyAtTimestamp", + "inputs": [ + { + "name": "timestamp", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, + { + "stateMutability": "view", + "type": "function", + "name": "getUserBalanceAtTimestamp", + "inputs": [ + { + "name": "user", + "type": "address" + }, + { + "name": "timestamp", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + }, +] as const \ No newline at end of file diff --git a/lib/feeDistributor/getVeApy.ts b/lib/feeDistributor/getVeApy.ts index 945fc25..99a6a96 100644 --- a/lib/feeDistributor/getVeApy.ts +++ b/lib/feeDistributor/getVeApy.ts @@ -1,29 +1,41 @@ -import { useContractRead } from "wagmi"; -import { BigNumber, Contract } from 'ethers'; -import { Pop } from "lib/types"; -import { defi_llama } from "lib/utils/resolvers/price-resolvers/resolvers"; -import { thisPeriodTimestamp } from "lib/Gauges/utils"; -import { RPC_PROVIDERS } from "lib/utils"; +import { Chain, createPublicClient, http } from "viem"; +import { llama } from "@/lib/resolver/price/resolver"; +import { thisPeriodTimestamp } from "@/lib/gauges/utils"; +import { RPC_URLS } from "@/lib/utils/connectors"; interface ClaimableTokensArgs { + chain: Chain; address: `0x${string}`; token: `0x${string}`; - chainId: number } -export default async function getVeApy({ chainId, address, token }: ClaimableTokensArgs): Promise { - const popPriceUSD = await defi_llama("0x6F0fecBC276de8fC69257065fE47C5a03d986394", 10) - const wethPriceUSD = await defi_llama("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 1) - const timestamp = BigNumber.from(String(thisPeriodTimestamp() - 604800)); +export default async function getVeApy({ chain, address, token }: ClaimableTokensArgs): Promise { + const popPriceUSD = await llama({ address: "0x6F0fecBC276de8fC69257065fE47C5a03d986394", chainId: 10 }) + const wethPriceUSD = await llama({ address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", chainId: 1 }) + const timestamp = BigInt(String(thisPeriodTimestamp() - 604800)); + const client = createPublicClient({ chain, transport: http(RPC_URLS[chain.id]) }) + const data = await client.multicall({ + contracts: [ + { + address, + abi: abiFeeDistributor, + functionName: "getTotalSupplyAtTimestamp", + args: [timestamp] + }, + { + address, + abi: abiFeeDistributor, + functionName: "getTokensDistributedInWeek", + args: [token, timestamp] + }, + ], + allowFailure: false + }) - const feeDistributor = new Contract(address, abiFeeDistributor, RPC_PROVIDERS[chainId]) - const totalSupplyAtTimestamp = await feeDistributor.getTotalSupplyAtTimestamp(timestamp) - const tokensDistributedInWeek = await feeDistributor.getTokensDistributedInWeek(token, timestamp) - - if (Number(tokensDistributedInWeek) > 0 && Number(totalSupplyAtTimestamp) > 0) { - const rewardValue = Number(tokensDistributedInWeek) * (Number(wethPriceUSD.value) / 1e18) - const supplyValue = Number(totalSupplyAtTimestamp) * (Number(popPriceUSD.value) / 1e18); + if (Number(data[1]) > 0 && Number(data[0]) > 0) { + const rewardValue = Number(data[1]) * wethPriceUSD + const supplyValue = Number(data[0]) * popPriceUSD; const apy = (rewardValue / supplyValue) * 52; return apy; } diff --git a/lib/feeDistributor/useClaimToken.ts b/lib/feeDistributor/useClaimToken.ts index ef0f327..68dfcc0 100644 --- a/lib/feeDistributor/useClaimToken.ts +++ b/lib/feeDistributor/useClaimToken.ts @@ -1,4 +1,4 @@ -import { showErrorToast, showSuccessToast } from "lib/Toasts"; +import { showErrorToast, showSuccessToast } from "lib/toasts"; import { useContractWrite, usePrepareContractWrite } from "wagmi"; export function useClaimTokens(address: `0x${string}`, user: `0x${string}`, tokens: string[]) { diff --git a/lib/feeDistributor/useUserWethRewards.ts b/lib/feeDistributor/useUserWethRewards.ts deleted file mode 100644 index 2d77028..0000000 --- a/lib/feeDistributor/useUserWethRewards.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { BigNumber } from 'ethers'; -import { time } from 'highcharts'; -import { getVotePeriodEndTime, thisPeriodTimestamp } from 'lib/Gauges/utils'; -import { RPC_PROVIDERS } from 'lib/utils'; -import { useEffect, useState } from 'react'; -import { useContractRead } from 'wagmi'; - -async function getLatestTimestamp(chainId: number) { - const latestBlockNumber = await RPC_PROVIDERS[chainId].getBlockNumber() - const latestBlock = await RPC_PROVIDERS[chainId].getBlock(latestBlockNumber) - return latestBlock.timestamp -} - -export function useUserWethReward({ chainId, address, user, token }: { address: `0x${string}`, chainId: number, user: `0x${string}`, token: `0x${string}` }): { data: BigNumber } { - const timestamp = BigNumber.from(String(thisPeriodTimestamp())); - - const { data: totalSupplyAtTimestamp } = useContractRead({ - address, - abi: abiFeeDistributor, - functionName: "getTotalSupplyAtTimestamp", - chainId: chainId, - args: [timestamp], - enabled: !!timestamp && !!user && !!token - }) as { data: BigNumber } - - const { data: userBalanceAtTimestamp } = useContractRead({ - address, - abi: abiFeeDistributor, - functionName: "getUserBalanceAtTimestamp", - chainId: chainId, - args: [user, timestamp], - enabled: !!timestamp && !!user && !!token - }) as { data: BigNumber } - - const { data: tokensDistributedInWeek } = useContractRead({ - address, - abi: abiFeeDistributor, - functionName: "getTokensDistributedInWeek", - chainId: chainId, - args: [token, timestamp], - enabled: !!timestamp && !!user && !!token - }) as { data: BigNumber } - - if (Number(userBalanceAtTimestamp) && Number(tokensDistributedInWeek) > 0 && Number(totalSupplyAtTimestamp) > 0) { - const userReward = userBalanceAtTimestamp.mul(tokensDistributedInWeek).div(totalSupplyAtTimestamp); - return { data: userReward }; - } - - return { data: BigNumber.from(0) }; -} - -const abiFeeDistributor = [ - { - "stateMutability": "view", - "type": "function", - "name": "getTokensDistributedInWeek", - "inputs": [ - { - "name": "token", - "type": "address" - }, - { - "name": "timestamp", - "type": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256" - } - ] - }, - { - "stateMutability": "view", - "type": "function", - "name": "getTotalSupplyAtTimestamp", - "inputs": [ - { - "name": "timestamp", - "type": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256" - } - ] - }, - { - "stateMutability": "view", - "type": "function", - "name": "getUserBalanceAtTimestamp", - "inputs": [ - { - "name": "user", - "type": "address" - }, - { - "name": "timestamp", - "type": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256" - } - ] - }, -] as const \ No newline at end of file diff --git a/lib/gauges/calculateGaugeAPR.ts b/lib/gauges/calculateGaugeAPR.ts index d453faf..9dd7052 100644 --- a/lib/gauges/calculateGaugeAPR.ts +++ b/lib/gauges/calculateGaugeAPR.ts @@ -1,58 +1,82 @@ -import { RPC_PROVIDERS } from "lib/utils"; -import { defi_llama } from "lib/utils/resolvers/price-resolvers/resolvers"; -import { getVeAddresses } from "lib/utils/addresses" -import GaugeControllerAbi from "lib/utils/constants/abi/GaugeController" -import LiquidityGaugeAbi from "lib/utils/constants/abi/LiquidityGauge" import { thisPeriodTimestamp } from "@/lib/gauges/utils"; -import { Address } from "viem"; +import { Address, PublicClient, formatEther } from "viem"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { llama } from "@/lib/resolver/price/resolver"; +import { GaugeAbi, GaugeControllerAbi } from "@/lib/constants"; const { GaugeController: GAUGE_CONTROLLER } = getVeAddresses() -const provider = RPC_PROVIDERS[5]; -async function getGaugeData(_gauge: Address) { - const gaugeContract = new Contract(_gauge, LiquidityGaugeAbi, provider); - - const is_killed = await gaugeContract.is_killed(); - const inflation_rate = await gaugeContract.inflation_rate(); - const relative_weight = await gaugeContract.getCappedRelativeWeight(thisPeriodTimestamp()); - const tokenless_production = await gaugeContract.tokenless_production(); - const working_supply = await gaugeContract.working_supply(); +async function getGaugeData(gauge: Address, publicClient: PublicClient): Promise<[boolean, number, number, number, number]> { + const gaugeContract = { + address: gauge, + abi: GaugeAbi + } - return [is_killed, Number(inflation_rate) / 1e18, Number(relative_weight) / 1e18, Number(tokenless_production), Number(working_supply) / 1e18]; + const data = await publicClient.multicall({ + contracts: [ + { + ...gaugeContract, + functionName: 'is_killed', + }, + { + ...gaugeContract, + functionName: 'inflation_rate', + }, + { + ...gaugeContract, + functionName: 'getCappedRelativeWeight', + args: [BigInt(thisPeriodTimestamp())] + }, + { + ...gaugeContract, + functionName: 'tokenless_production', + }, + { + ...gaugeContract, + functionName: 'working_supply', + }, + ], + allowFailure: false + }) + + return [data[0], Number(formatEther(data[1])), Number(formatEther(data[2])), Number(data[3]), Number(formatEther(data[4]))]; } -async function getGaugeControllerData(_gauge: Address) { - const gaugeControllerContract = new Contract(GAUGE_CONTROLLER, GaugeControllerAbi, provider); - - const gauge_exists = await gaugeControllerContract.gauge_exists(_gauge); - - return [gauge_exists]; +interface CalculateAPRProps { + vaultPrice: number; + gauge: Address; + publicClient: PublicClient; } -export default async function calculateAPR(vaultTokenPriceUSD: number, gaugeAddress: Address) { +export default async function calculateAPR({ vaultPrice, gauge, publicClient }: CalculateAPRProps): Promise { /// fetch the price of token0, token1 and LIT in USD - const popPriceUSD = await defi_llama("0x6F0fecBC276de8fC69257065fE47C5a03d986394", 10) + const popPriceUSD = await llama({ address: "0x6F0fecBC276de8fC69257065fE47C5a03d986394", chainId: 10 }) /// calculate the lowerAPR and upperAPR let lowerAPR = 0; let upperAPR = 0; - if (gaugeAddress) { - const [is_killed, inflation_rate, relative_weight, tokenless_production, working_supply] = await getGaugeData(gaugeAddress); - const [gauge_exists] = await getGaugeControllerData(gaugeAddress); + if (gauge) { + const [is_killed, inflation_rate, relative_weight, tokenless_production, working_supply] = await getGaugeData(gauge, publicClient); + const gauge_exists = await publicClient.readContract({ + address: GAUGE_CONTROLLER, + abi: GaugeControllerAbi, + functionName: 'gauge_exists', + args: [gauge] + }) /// @dev the price of oPOP is determined by applying the discount factor to the POP price. /// as of this writing, the discount factor of 50% but is subject to change. Additional dev /// work is needed to programmatically apply the discount factor at any given point in time. - const oPopPriceUSD = (Number(popPriceUSD.value) / 1e18) * 0.5; + const oPopPriceUSD = popPriceUSD * 0.5; if (gauge_exists == true && is_killed == false) { const relative_inflation = inflation_rate * relative_weight; if (relative_inflation > 0) { const annualRewardUSD = relative_inflation * 86400 * 365 * oPopPriceUSD; const effectiveSupply = working_supply > 0 ? working_supply : 1; - const workingSupplyUSD = effectiveSupply * vaultTokenPriceUSD; + const workingSupplyUSD = effectiveSupply * vaultPrice; lowerAPR = (((annualRewardUSD * tokenless_production) / 100) / workingSupplyUSD) * 100; upperAPR = (annualRewardUSD / workingSupplyUSD) * 100; @@ -60,7 +84,7 @@ export default async function calculateAPR(vaultTokenPriceUSD: number, gaugeAddr } } else { console.log('~~~~~ No Gauge Found ~~~~~'); - return; + return []; } console.log(`lowerAPR: ${Number(lowerAPR).toFixed(2)}%`); diff --git a/lib/gauges/getGaugeRewards.ts b/lib/gauges/getGaugeRewards.ts new file mode 100644 index 0000000..e502dd1 --- /dev/null +++ b/lib/gauges/getGaugeRewards.ts @@ -0,0 +1,32 @@ +import { Address } from "wagmi"; +import { GaugeAbi, ZERO } from "@/lib/constants"; +import { PublicClient } from "viem"; + +interface GetGaugeRewardsProps { + gauges: Address[]; + account: Address; + publicClient: PublicClient; +} + +export type GaugeRewards = { + total: bigint, + amounts: { amount: bigint, address: Address }[] +} + +export default async function getGaugeRewards({ gauges, account, publicClient }: GetGaugeRewardsProps): Promise { + const data = await publicClient.multicall({ + contracts: gauges.map((address) => { + return { + address, + abi: GaugeAbi, + functionName: 'claimable_tokens', + args: [account] + } + }), + allowFailure: false + }) + + const total = data?.reduce((acc: bigint, curr: bigint) => acc + (curr || ZERO), ZERO); + const amounts = data?.map((amount, i) => { return { amount: amount, address: gauges[i] } }); + return { total, amounts } +} \ No newline at end of file diff --git a/lib/gauges/getGauges.ts b/lib/gauges/getGauges.ts new file mode 100644 index 0000000..ea178bf --- /dev/null +++ b/lib/gauges/getGauges.ts @@ -0,0 +1,81 @@ +import { Address, PublicClient, getAddress } from "viem"; +import { ADDRESS_ZERO, GaugeAbi, GaugeControllerAbi } from "@/lib/constants"; + +export interface Gauge { + address: Address; + lpToken: Address; + decimals: number; + balance: number; + chainId: number; +} + +export default async function getGauges({ address, account = ADDRESS_ZERO, publicClient }: { address: Address, account?: Address, publicClient: PublicClient }): Promise { + const nGauges = await publicClient.readContract({ + address: address, + abi: GaugeControllerAbi, + functionName: 'n_gauges', + }) + + const gaugeController = { + address: address, + abi: GaugeControllerAbi + } as const + + const gauges = await publicClient.multicall({ + contracts: Array(Number(nGauges)).fill(undefined).map((item, idx) => { + return { + ...gaugeController, + functionName: "gauges", + args: [idx] + } + }), + allowFailure: false + }) as Address[] + + const areGaugesKilled = await publicClient.multicall({ + contracts: gauges.map((gauge: Address) => { + return { + address: gauge, + abi: GaugeAbi, + functionName: "is_killed", + } + }), + allowFailure: false + }) + + const aliveGauges = gauges?.filter((gauge: any, idx: number) => !areGaugesKilled[idx]) + + const lpTokens = await publicClient.multicall({ + contracts: aliveGauges.map((gauge: Address) => { + const gaugeContract = { + address: gauge, + abi: GaugeAbi, + } + return [{ + ...gaugeContract, + functionName: "lp_token", + }, + { + ...gaugeContract, + functionName: "decimals", + }, + { + ...gaugeContract, + functionName: 'balanceOf', + args: [account] + }] + }).flat(), + allowFailure: false + }) + + return aliveGauges.map((gauge: Address, i: number) => { + if (i > 0) i = i * 3 + return { + address: getAddress(gauge), + lpToken: getAddress(lpTokens[i + 0] as Address), + decimals: Number(lpTokens[i + 1]), + balance: account === ADDRESS_ZERO ? 0 : Number(lpTokens[i + 2]), + chainId: publicClient.chain?.id as number + } + }) +} \ No newline at end of file diff --git a/lib/gauges/hasAlreadyVoted.ts b/lib/gauges/hasAlreadyVoted.ts new file mode 100644 index 0000000..3b68a25 --- /dev/null +++ b/lib/gauges/hasAlreadyVoted.ts @@ -0,0 +1,26 @@ +import { PublicClient } from 'viem'; +import { Address } from 'wagmi'; +import { getVeAddresses } from '@/lib/utils/addresses'; +import { GaugeControllerAbi } from '@/lib/constants'; + +const DAYS = 24 * 60 * 60; + +const { GaugeController: GAUGE_CONTROLLER } = getVeAddresses() + +export async function hasAlreadyVoted({ addresses, publicClient, account }: { addresses: Address[], publicClient: PublicClient, account: Address }): Promise { + const data = await publicClient.multicall({ + contracts: addresses.map((address) => { + return { + address: GAUGE_CONTROLLER, + abi: GaugeControllerAbi, + functionName: "last_user_vote", + args: [account, address] + } + }), + allowFailure: false + }) + + const limitTimestamp = BigInt(Math.floor(Date.now() / 1000) - (DAYS * 10)); + + return data?.some((voteTimestamp: bigint) => voteTimestamp > limitTimestamp); +} \ No newline at end of file diff --git a/lib/gauges/interactions.ts b/lib/gauges/interactions.ts new file mode 100644 index 0000000..8a0cf4a --- /dev/null +++ b/lib/gauges/interactions.ts @@ -0,0 +1,213 @@ +import { Abi, Address, PublicClient, WalletClient, parseEther, zeroAddress } from "viem"; +import { VaultData } from "@/lib/types"; +import { showErrorToast, showSuccessToast } from "@/lib/toasts"; +import { SimulationResponse } from "@/lib/types"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { GaugeControllerAbi, VotingEscrowAbi } from "@/lib/constants"; + +type SimulationContract = { + address: Address; + abi: Abi; +} + +interface SimulateProps { + account: Address; + contract: SimulationContract; + functionName: string; + publicClient: PublicClient; + args?: any[] +} + +const { GaugeController: GAUGE_CONTROLLER, VotingEscrow: VOTING_ESCROW } = getVeAddresses() + +async function simulateCall({ account, contract, functionName, publicClient, args }: SimulateProps): Promise { + try { + const { request } = await publicClient.simulateContract({ + account, + address: contract.address, + abi: contract.abi, + // @ts-ignore + functionName, + args + }) + return { request: request, success: true, error: null } + } catch (error: any) { + return { request: null, success: false, error: error.shortMessage } + } +} + +type Clients = { + publicClient: PublicClient; + walletClient: WalletClient; +} + +interface SendVotesProps { + vaults: VaultData[]; + votes: number[]; + account: Address; + clients: Clients; +} + +export async function sendVotes({ vaults, votes, account, clients }: SendVotesProps) { + let addr = new Array(8); + let v = new Array(8); + + for (let i = 0; i < Math.ceil(vaults.length / 8); i++) { + addr = []; + v = []; + + for (let n = 0; n < 8; n++) { + const l = i * 8; + v[n] = votes[n + l] === undefined ? 0 : votes[n + l]; + addr[n] = vaults[n + l] === undefined || votes[n + l] === 0 ? zeroAddress : vaults[n + l].address; + + } + + + const { request, success, error: simulationError } = await simulateCall({ + account, + contract: { + address: GAUGE_CONTROLLER, + abi: GaugeControllerAbi, + }, + functionName: "vote_for_many_gauge_weights", + publicClient: clients.publicClient, + args: [addr, v] + }) + + if (success) { + try { + const hash = await clients.walletClient.writeContract(request) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast("Voted for gauges!") + } catch (error: any) { + showErrorToast(error.shortMessage) + } + } else { + showErrorToast(simulationError) + } + } +} + +interface CreateLockProps { + amount: number | string; + days: number; + account: Address; + clients: Clients; +} + +export async function createLock({ amount, days, account, clients }: CreateLockProps) { + const { request, success, error: simulationError } = await simulateCall({ + account, + contract: { + address: VOTING_ESCROW, + abi: VotingEscrowAbi, + }, + functionName: "create_lock", + publicClient: clients.publicClient, + args: [parseEther(Number(amount).toLocaleString("fullwide", { useGrouping: false })), BigInt(Math.floor(Date.now() / 1000) + (86400 * days))] + }) + + if (success) { + try { + const hash = await clients.walletClient.writeContract(request) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast("Lock created successfully!") + } catch (error: any) { + showErrorToast(error.shortMessage) + } + } else { + showErrorToast(simulationError) + } +} + +interface IncreaseLockAmountProps { + amount: number | string; + account: Address; + clients: Clients; +} + +export async function increaseLockAmount({ amount, account, clients }: IncreaseLockAmountProps) { + const { request, success, error: simulationError } = await simulateCall({ + account, + contract: { + address: VOTING_ESCROW, + abi: VotingEscrowAbi, + }, + functionName: "increase_amount", + publicClient: clients.publicClient, + args: [parseEther(Number(amount).toLocaleString("fullwide", { useGrouping: false }))] + }) + + if (success) { + try { + const hash = await clients.walletClient.writeContract(request) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast("Lock amount increased successfully!") + } catch (error: any) { + showErrorToast(error.shortMessage) + } + } else { + showErrorToast(simulationError) + } +} + +interface IncreaseLockTimeProps { + unlockTime: number; + account: Address; + clients: Clients; +} + +export async function increaseLockTime({ unlockTime, account, clients }: IncreaseLockTimeProps) { + const { request, success, error: simulationError } = await simulateCall({ + account, + contract: { + address: VOTING_ESCROW, + abi: VotingEscrowAbi, + }, + functionName: "increase_unlock_time", + publicClient: clients.publicClient, + args: [BigInt(unlockTime)] + }) + + if (success) { + try { + const hash = await clients.walletClient.writeContract(request) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast("Lock time increased successfully!") + } catch (error: any) { + showErrorToast(error.shortMessage) + } + } else { + showErrorToast(simulationError) + } +} + +interface WithdrawLockProps { + account: Address; + clients: Clients; +} + +export async function withdrawLock({ account, clients }: WithdrawLockProps) { + const { request, success, error: simulationError } = await simulateCall({ + account, + contract: { + address: VOTING_ESCROW, + abi: VotingEscrowAbi, + }, + functionName: "withdraw", + publicClient: clients.publicClient, + }) + + if (success) { + try { + const hash = await clients.walletClient.writeContract(request) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast("Withdrawal successful!") + } catch (error: any) { + showErrorToast(error.shortMessage) + } + } else { + showErrorToast(simulationError) + } +} \ No newline at end of file diff --git a/lib/gauges/useClaimableOPop.ts b/lib/gauges/useClaimableOPop.ts deleted file mode 100644 index 148e8b8..0000000 --- a/lib/gauges/useClaimableOPop.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { useContractReads } from "wagmi"; - - -export default function useClaimableOPop({ addresses, chainId, account }: { addresses: string[], chainId: number, account: string }): Pop.HookResult<{ total: BigNumber, amounts: { amount: BigNumber, address: string }[] }> { - const { data, status } = useContractReads({ - enabled: addresses?.length > 0 && !!chainId && !!account, - scopeKey: `useClaimableOPop:${chainId}:${account}`, - contracts: addresses?.map((address) => ({ - address: (!!address && address) || "", - chainId: Number(chainId), - abi: ["function claimable_tokens(address) external view returns (uint256)"], - functionName: "claimable_tokens", - args: [account], - })), - }) as Pop.HookResult; - const total = data?.reduce((acc, curr) => acc.add(curr || constants.Zero), constants.Zero); - const amounts = data?.map((amount, i) => { return { amount: amount, address: addresses[i] } }); - return { data: { total, amounts }, status: status } -} \ No newline at end of file diff --git a/lib/gauges/useCurrentGaugeWeight.ts b/lib/gauges/useCurrentGaugeWeight.ts deleted file mode 100644 index 6fc576c..0000000 --- a/lib/gauges/useCurrentGaugeWeight.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { useContractRead } from "wagmi"; - -export default function useCurrentGaugeWeight({ address, account, chainId }: { address: string, account: string, chainId: number }): Pop.HookResult { - return useContractRead({ - address, - chainId: Number(chainId), - abi: ["function gauge_relative_weight(address) view returns (uint256)"], - functionName: "gauge_relative_weight", - args: (!!account && [account]) || [], - scopeKey: `current_gauge_relative_weight:${chainId}:${address}:${account}`, - enabled: !!address && !!account && !!chainId, - select: (data) => { - return { - value: (data as BigNumber) || BigNumber.from(0), - formatted: formatAndRoundBigNumber(data as BigNumber, 18), - }; - }, - }) as Pop.HookResult; -} \ No newline at end of file diff --git a/lib/gauges/useGaugeWeights.ts b/lib/gauges/useGaugeWeights.ts index 68d0ce0..9e6d55e 100644 --- a/lib/gauges/useGaugeWeights.ts +++ b/lib/gauges/useGaugeWeights.ts @@ -1,20 +1,17 @@ -import { BigNumber, constants } from "ethers"; -import { BigNumberWithFormatted, Pop } from "lib/types"; -import { formatAndRoundBigNumber } from "lib/utils"; -import { Address, useContractRead, useContractReads } from "wagmi"; -import { getVotePeriodEndTime } from "./utils"; -import { getVeAddresses } from "lib/utils/addresses"; +import { Address, zeroAddress } from "viem"; +import { useContractReads } from "wagmi"; +import { getVotePeriodEndTime } from "@/lib/gauges/utils"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { GaugeControllerAbi } from "@/lib/constants"; const { GaugeController: GAUGE_CONTROLLER } = getVeAddresses(); -export default function useGaugeWeights({ address, account, chainId }: { address: string, account: string, chainId: number }): Pop.HookResult { +export default function useGaugeWeights({ address, account, chainId }: { address: Address, account: Address, chainId: number }) { const contract = { address: GAUGE_CONTROLLER, chainId: Number(chainId), - abi: ["function gauge_relative_weight(address,uint256) view returns (uint256)", - "function gauge_relative_weight(address) view returns (uint256)", - "function vote_user_slopes(address user, address gauge) external view returns (uint256)"] + abi: GaugeControllerAbi } return useContractReads({ @@ -27,14 +24,15 @@ export default function useGaugeWeights({ address, account, chainId }: { address { ...contract, functionName: "gauge_relative_weight", - args: [address, getVotePeriodEndTime() / 1000] + args: [address, BigInt(getVotePeriodEndTime() / 1000)] }, { ...contract, functionName: "vote_user_slopes", - args: [account || constants.AddressZero, address] + args: [account || zeroAddress, address] } ], enabled: !!address && !!chainId, - }) as Pop.HookResult + allowFailure: false, + }) } \ No newline at end of file diff --git a/lib/gauges/useGauges.ts b/lib/gauges/useGauges.ts deleted file mode 100644 index 1cb5bda..0000000 --- a/lib/gauges/useGauges.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { useContractRead, useContractReads } from "wagmi"; - -export interface Gauge { - address: string; - vault: string; - chainId: number; -} - -export default function useGauges({ address, chainId }: { address: string, chainId: number }): Pop.HookResult { - const { data: n_gauges } = useContractRead({ - address, - abi: abiController, - functionName: "n_gauges", - chainId, - args: [] - }) as { data: BigNumber, status: string } - - const { data: gauges } = useContractReads({ - contracts: Array(n_gauges?.toNumber()).fill(undefined).map((item, idx) => { - return { - address, - abi: abiController, - functionName: "gauges", - chainId, - args: [idx] - } - }), - enabled: !!n_gauges, - }) as { data: string[], status: string } - - const { data: areGaugesKilled } = useContractReads({ - contracts: gauges?.map((gauge: any) => { - return { - address: gauge, - abi: abiGauge, - functionName: "is_killed", - chainId, - args: [] - } - }), - enabled: !!gauges, - }) as { data: boolean[], status: string } - - const aliveGauges = areGaugesKilled ? gauges?.filter((gauge: any, idx: number) => !areGaugesKilled[idx]) : gauges - - const { data, status } = useContractReads({ - contracts: aliveGauges?.map((gauge: any) => { - return { - address: gauge, - abi: abiGauge, - functionName: "lp_token", - chainId, - args: [], - } - }), - enabled: !!aliveGauges, - select: (data) => { - return (data as string[]).map((token, i) => { return { address: aliveGauges[i], vault: token, chainId: chainId } }) - } - }) as { data: Gauge[], status: string } - - return { data, status } as Pop.HookResult; -} - -const abiController = [ - { - "stateMutability": "view", - "type": "function", - "name": "n_gauges", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "int128" - } - ] - }, - { - "stateMutability": "view", - "type": "function", - "name": "gauges", - "inputs": [ - { - "name": "arg0", - "type": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "address" - } - ] - }, -] -const abiGauge = [ - { - "stateMutability": "view", - "type": "function", - "name": "lp_token", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address" - } - ] - }, - { - "stateMutability": "view", - "type": "function", - "name": "is_killed", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "bool" - } - ] - }, -] \ No newline at end of file diff --git a/lib/gauges/useHasAlreadyVoted.ts b/lib/gauges/useHasAlreadyVoted.ts deleted file mode 100644 index c4242e1..0000000 --- a/lib/gauges/useHasAlreadyVoted.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { BigNumber } from 'ethers'; -import { Pop } from 'lib/types'; -import { getVeAddresses } from 'lib/utils/addresses'; -import { Address, useContractReads } from 'wagmi'; - -const DAYS = 24 * 60 * 60; - -const { GaugeController: GAUGE_CONTROLLER } = getVeAddresses() - -export function useHasAlreadyVoted({ addresses, chainId, account }: { addresses: string[], chainId: number, account: string }): { data: boolean, status: string } { - const { data, status } = useContractReads({ - contracts: addresses?.map((address) => { - return { - address: GAUGE_CONTROLLER as Address, - abi: abiController, - functionName: "last_user_vote", - chainId: chainId, - args: [account, address] - } - }), - enabled: !!account && addresses?.length > 0, - }) as Pop.HookResult - - const limitTimestamp = Math.floor(Date.now() / 1000) - (DAYS * 10); - - const alreadyVoted = data?.some(voteTimestamp => - voteTimestamp?.gt(BigNumber.from(limitTimestamp)) - ); - - return { data: alreadyVoted, status: status }; -} - -const abiController = [ - { - "stateMutability": "view", - "type": "function", - "name": "last_user_vote", - "inputs": [{ "name": "arg0", "type": "address" }, { "name": "arg1", "type": "address" }], - "outputs": [{ "name": "", "type": "uint256" }] - } -] \ No newline at end of file diff --git a/lib/gauges/useLockedBalanceOf.ts b/lib/gauges/useLockedBalanceOf.ts index 84e838f..9481eaa 100644 --- a/lib/gauges/useLockedBalanceOf.ts +++ b/lib/gauges/useLockedBalanceOf.ts @@ -1,20 +1,21 @@ -import { useContractRead } from "wagmi"; +import { Address, useContractRead } from "wagmi"; export interface LockedBalance { amount: bigint; end: bigint; } -export default function useLockedBalanceOf({ chainId, address, account }): Pop.HookResult { - return useConsistentRepolling( - useContractRead({ - address, - chainId: Number(chainId), - abi: ["function locked(address) view returns ((uint256,uint256))"], - functionName: "locked", - args: (!!account && [account]) || [], - scopeKey: `lockedBalanceOf:${chainId}:${address}:${account}`, - enabled: !!(chainId && address && account), - select: (data) => { return { amount: data[0], end: data[1] } } - })) as Pop.HookResult; +export default function useLockedBalanceOf({ chainId, address, account }: { chainId: number, address: Address, account: Address }) { + return useContractRead({ + address, + chainId: Number(chainId), + abi: ["function locked(address) view returns ((uint256,uint256))"], + functionName: "locked", + args: (!!account && [account]) || [], + scopeKey: `lockedBalanceOf:${chainId}:${address}:${account}`, + enabled: !!(chainId && address && account), + select: (data: any) => { return { amount: data[0], end: data[1] } }, + watch: true, + cacheTime: 2_000, + }) } \ No newline at end of file diff --git a/lib/gauges/utils.ts b/lib/gauges/utils.ts index 9623597..4684aa0 100644 --- a/lib/gauges/utils.ts +++ b/lib/gauges/utils.ts @@ -1,9 +1,9 @@ import { useContractWrite, usePrepareContractWrite } from "wagmi"; import { nextThursday } from "date-fns" -import { showSuccessToast, showErrorToast } from "@/lib/toasts"; import { useState, useEffect } from "react"; import { parseEther } from "viem"; import { ChainId } from "@/lib/utils/connectors"; +import { showSuccessToast, showErrorToast } from "@/lib/toasts"; export function calcUnlockTime(days: number, start = Date.now()): number { const week = 86400 * 7; @@ -42,142 +42,4 @@ export function getVotePeriodEndTime(): number { export function thisPeriodTimestamp(): number { const week = 604800 * 1000; return (Math.floor(Date.now() / week) * week) / 1000; -}; - -export function useCreateLock(address: `0x${string}`, amount: number | string, days: number) { - const [unlockTime, setUnlockTime] = useState(0); - - useEffect(() => { - // This will run once when the component is mounted or whenever `days` changes - const newUnlockTime = Math.floor(Date.now() / 1000) + (86400 * days); - setUnlockTime(newUnlockTime); - }, [days]); - - const { config } = usePrepareContractWrite({ - address, - abi: ["function create_lock(uint256,uint256) external"], - functionName: "create_lock", - args: [Number(amount).toLocaleString("fullwide", { useGrouping: false }), unlockTime], - chainId: Number(5), - }); - - const result = useContractWrite({ - ...config, - onSuccess: () => { - showSuccessToast("Lock created successfully!"); - }, - onError: (error) => { - showErrorToast(error); - } - }); - - return result; -} - -export function useIncreaseLockAmount(address: `0x${string}`, amount: number | string) { - const { config } = usePrepareContractWrite({ - address, - abi: ["function increase_amount(uint256) external"], - functionName: "increase_amount", - args: [parseEther(Number(amount).toLocaleString("fullwide", { useGrouping: false }))], - chainId: Number(5), - }); - - const result = useContractWrite({ - ...config, - onSuccess: () => { - showSuccessToast("Lock amount increased successfully!"); - }, - onError: (error) => { - showErrorToast(error); - } - }); - - return result; -} - -export function useIncreaseLockTime(address: `0x${string}`, unlockTime: number) { - const { config } = usePrepareContractWrite({ - address, - abi: ["function increase_unlock_time(uint256) external"], - functionName: "increase_unlock_time", - args: [unlockTime], - chainId: Number(5), - }); - - const result = useContractWrite({ - ...config, - onSuccess: () => { - showSuccessToast("Lock time increased successfully!"); - }, - onError: (error) => { - showErrorToast(error); - } - }); - - return result; -} - -export function useWithdrawLock(address: `0x${string}`) { - const { config } = usePrepareContractWrite({ - address, - abi: ["function withdraw() external"], - functionName: "withdraw", - args: [], - chainId: Number(5), - }); - - - const result = useContractWrite({ - ...config, - onSuccess: () => { - showSuccessToast("Withdrawal successful!"); - }, - onError: (error) => { - showErrorToast(error); - } - }); - - return result; -} - -export function useGaugeDeposit(address: `0x${string}`, chainId: ChainId, amount: number | string) { - const { config } = usePrepareContractWrite({ - address, - abi: ["function deposit(uint256 assetAmount) external"], - functionName: "deposit", - args: [Number(amount).toLocaleString("fullwide", { useGrouping: false })], - chainId: Number(chainId), - }); - - return useContractWrite({ - ...config, - onSuccess: () => { - showSuccessToast("Gauge Deposit Success!"); - }, - onError: (error) => { - showErrorToast(error); - } - }); -} - - -export function useGaugeWithdraw(address: `0x${string}`, chainId: ChainId, amount: number | string) { - const { config } = usePrepareContractWrite({ - address, - abi: ["function withdraw(uint256 assetAmount) external"], - functionName: "withdraw", - args: [Number(amount).toLocaleString("fullwide", { useGrouping: false })], - chainId: Number(chainId), - }); - - return useContractWrite({ - ...config, - onSuccess: () => { - showSuccessToast("Gauge Withdraw Success!"); - }, - onError: (error) => { - showErrorToast(error); - } - }); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/lib/oPop/ethToUsd.ts b/lib/oPop/ethToUsd.ts new file mode 100644 index 0000000..98454b6 --- /dev/null +++ b/lib/oPop/ethToUsd.ts @@ -0,0 +1,38 @@ +import { useState, useEffect } from 'react'; +import axios from 'axios'; +import { formatEther, parseEther, parseUnits } from 'viem'; + +async function getEthToUsdPrice(): Promise { + try { + const response = await axios.get('https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd'); + return response.data.ethereum.usd; + } catch (error) { + throw new Error('Failed to fetch ETH price from CoinGecko'); + } +} + +async function convertEthToUsd(ethAmount: bigint): Promise { + const ethToUsdPrice = await getEthToUsdPrice(); + const ethAmountFloat = parseFloat(formatEther(ethAmount)); + const usdValue = ethAmountFloat * ethToUsdPrice; + return parseEther(usdValue.toString()); +} + +export function useEthToUsd(ethAmount: bigint) { + const [usdValue, setUsdValue] = useState(null); + + useEffect(() => { + async function fetchUsdValue() { + try { + const value = await convertEthToUsd(ethAmount); + setUsdValue(value); + } catch (error) { + console.error(error); + } + } + + fetchUsdValue(); + }, [ethAmount]); + + return usdValue; +} \ No newline at end of file diff --git a/lib/oPop/interactions.ts b/lib/oPop/interactions.ts new file mode 100644 index 0000000..f825ed2 --- /dev/null +++ b/lib/oPop/interactions.ts @@ -0,0 +1,105 @@ +import { Abi, Address, PublicClient, WalletClient, parseEther } from "viem"; +import { showErrorToast, showSuccessToast } from "@/lib/toasts"; +import { MinterAbi, OPopAbi } from "@/lib/constants"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { SimulationResponse } from "@/lib/types"; + +type SimulationContract = { + address: Address; + abi: Abi; +} + +interface SimulateProps { + account: Address; + contract: SimulationContract; + functionName: string; + publicClient: PublicClient; + args?: any[] +} + +const { oPOP: OPOP, Minter: OPOP_MINTER } = getVeAddresses() + +async function simulateCall({ account, contract, functionName, publicClient, args }: SimulateProps): Promise { + try { + const { request } = await publicClient.simulateContract({ + account, + address: contract.address, + abi: contract.abi, + // @ts-ignore + functionName, + args + }) + return { request: request, success: true, error: null } + } catch (error: any) { + return { request: null, success: false, error: error.shortMessage } + } +} + +type Clients = { + publicClient: PublicClient; + walletClient: WalletClient; +} + +interface ExerciseOPopProps { + amount: bigint; + maxPaymentAmount: bigint; + account: Address; + clients: Clients +} + +export async function exerciseOPop({ amount, maxPaymentAmount, account, clients }: ExerciseOPopProps) { + const { request, success, error: simulationError } = await simulateCall({ + account, + contract: { + address: OPOP, + abi: OPopAbi, + }, + functionName: "exercise", + publicClient: clients.publicClient, + args: [amount, maxPaymentAmount] + }) + + if (success) { + try { + const hash = await clients.walletClient.writeContract(request) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast("oPOP exercised successfully!") + } catch (error: any) { + showErrorToast(error.shortMessage) + } + } else { + showErrorToast(simulationError) + } +} + + +interface ClaimOPopProps { + gauges: Address[]; + account: Address; + clients: Clients +} + +export async function claimOPop({ gauges, account, clients }: ClaimOPopProps) { + const { request, success, error: simulationError } = await simulateCall({ + account, + contract: { + address: OPOP_MINTER, + abi: MinterAbi, + }, + functionName: "mintMany", + publicClient: clients.publicClient, + args: [gauges] + }) + + if (success) { + try { + const hash = await clients.walletClient.writeContract(request) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast("oPOP Succesfully Claimed!") + } catch (error: any) { + showErrorToast(error.shortMessage) + } + } else { + showErrorToast(simulationError) + } +} \ No newline at end of file diff --git a/lib/types.ts b/lib/types.ts index e5bc1c7..808629b 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -12,27 +12,29 @@ export type Token = { }; export type veAddresses = { - POP: `0x${string}`; - WETH: `0x${string}`; - BalancerPool: `0x${string}`; - BalancerOracle: `0x${string}`; - oPOP: `0x${string}`; - VaultRegistry: `0x${string}`; - Vault1DAI: `0x${string}`; - Vault2USDC: `0x${string}`; - Vault2OUSD: `0x${string}`; - Minter: `0x${string}`; - TokenAdmin: `0x${string}`; - VotingEscrow: `0x${string}`; - GaugeController: `0x${string}`; - GaugeFactory: `0x${string}`; - SmartWalletChecker: `0x${string}`; - VotingEscrowDelegation: `0x${string}`; - Vault1DAIGauge: `0x${string}`; - Vault2USDCGauge: `0x${string}`; - Vault2OUSDGauge: `0x${string}`; - VaultRouter: `0x${string}`; - FeeDistributor: `0x${string}`; + POP: Address; + WETH: Address; + USDC: Address; + DAI: Address + BalancerPool: Address; + BalancerOracle: Address; + oPOP: Address; + VaultRegistry: Address; + Vault1DAI: Address; + Vault2USDC: Address; + Vault3OUSD: Address; + Minter: Address; + TokenAdmin: Address; + VotingEscrow: Address; + GaugeController: Address; + GaugeFactory: Address; + SmartWalletChecker: Address; + VotingEscrowDelegation: Address; + Vault1DAIGauge: Address; + Vault2USDCGauge: Address; + Vault3OUSDGauge: Address; + VaultRouter: Address; + FeeDistributor: Address; }; diff --git a/lib/utils/addresses/index.ts b/lib/utils/addresses/index.ts index d71ea5c..18a5b4d 100644 --- a/lib/utils/addresses/index.ts +++ b/lib/utils/addresses/index.ts @@ -1,6 +1,6 @@ import { veAddresses } from "lib/types"; -const veAddresses = { +const VeAddresses = { POP: "0xD0Cd466b34A24fcB2f87676278AF2005Ca8A78c4", WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", USDC: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", @@ -28,5 +28,5 @@ const veAddresses = { }; export function getVeAddresses(): veAddresses { - return veAddresses as veAddresses; + return VeAddresses as veAddresses; } diff --git a/lib/utils/formatBigNumber.ts b/lib/utils/formatBigNumber.ts index 58b07b5..cad35c8 100644 --- a/lib/utils/formatBigNumber.ts +++ b/lib/utils/formatBigNumber.ts @@ -1,5 +1,5 @@ import { formatUnits, parseUnits } from "viem"; -import { ZERO } from "./helpers"; +import { ZERO } from "@/lib/constants"; const MILLION = 1e6; const THOUSAND = 1e3; @@ -66,4 +66,9 @@ export function numberToBigNumber(value: number | string, decimals: number): Big export const NumberFormatter = Intl.NumberFormat("en", { //@ts-ignore notation: "compact", -}); \ No newline at end of file +}); + +export function safeRound(bn: bigint, decimals = 18): bigint { + const roundingValue = parseUnits("1", decimals > 8 ? 8 : 2) + return (bn / roundingValue) * roundingValue +} \ No newline at end of file diff --git a/lib/utils/helpers.ts b/lib/utils/helpers.ts index e69de29..8efc54c 100644 --- a/lib/utils/helpers.ts +++ b/lib/utils/helpers.ts @@ -0,0 +1,7 @@ +export function validateInput(value: string | number): { formatted: string, isValid: boolean } { + const formatted = value === "." ? "0" : (`${value || "0"}`.replace(/\.$/, ".0") as any); + return { + formatted, + isValid: value === "" || isFinite(Number(formatted)), + }; +}; \ No newline at end of file diff --git a/lib/vault/getVault.ts b/lib/vault/getVault.ts index 701f57f..20a0b47 100644 --- a/lib/vault/getVault.ts +++ b/lib/vault/getVault.ts @@ -1,4 +1,4 @@ -import { Address, Chain, ReadContractParameters, createPublicClient, getAddress, http } from "viem" +import { Address, Chain, ChainDisconnectedError, ReadContractParameters, createPublicClient, getAddress, http } from "viem" import { PublicClient } from "wagmi" import axios from "axios" import { VaultAbi } from "@/lib/constants/abi/Vault" @@ -10,6 +10,10 @@ import getVaultAddresses from "@/lib/vault/getVaultAddresses" import getAssetIcon from "@/lib/vault/getAssetIcon" import getVaultName from "@/lib/vault/getVaultName" import getOptionalMetadata from "@/lib/vault/getOptionalMetadata" +import { getVeAddresses } from "../utils/addresses" +import getGauges from "@/lib/gauges/getGauges" +import type { Gauge } from "@/lib/gauges/getGauges" + function prepareVaultContract(vault: Address, account: Address): ReadContractParameters[] { const vaultContract = { @@ -216,6 +220,32 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va } }) + + // Add gauges + if (client.chain.id === 1) { + const { + GaugeController: GAUGE_CONTROLLER, + } = getVeAddresses(); + const gauges = await getGauges({ address: GAUGE_CONTROLLER, publicClient: client }) + metadata = metadata.map((entry, i) => { + const foundGauge = gauges.find((gauge: Gauge) => gauge.lpToken === entry.address) + const gauge = foundGauge ? { + address: foundGauge.address, + name: `${entry.vault.name}-gauge`, + symbol: `st-${entry.vault.name}`, + decimals: foundGauge.decimals, + logoURI: "", // wont be used, just here for consistency + balance: foundGauge.balance, + price: entry.pricePerShare, + } : undefined + + return { + ...entry, + gauge + } + }) + } + return metadata as unknown as VaultData[] } @@ -258,7 +288,7 @@ export async function getVault({ vault, account = ADDRESS_ZERO, client }: { vaul balance: 0, // wont be used, just here for consistency, price: 0, // wont be used, just here for consistency, } - return { + const result = { address: getAddress(vault), vault: { address: getAddress(vault), @@ -292,4 +322,24 @@ export async function getVault({ vault, account = ADDRESS_ZERO, client }: { vaul }, chainId: client.chain.id } + + // Add gauges + if (client.chain.id === 1) { + const { + GaugeController: GAUGE_CONTROLLER, + } = getVeAddresses(); + const gauges = await getGauges({ address: GAUGE_CONTROLLER, publicClient: client }) + const foundGauge = gauges.find((gauge: Gauge) => gauge.lpToken === result.address) + // @ts-ignore + result.gauge = foundGauge ? { + address: foundGauge.address, + name: `${result.vault.name}-gauge`, + symbol: `st-${result.vault.name}`, + decimals: foundGauge.decimals, + logoURI: "", // wont be used, just here for consistency + balance: foundGauge.balance, + price: result.pricePerShare, + } : undefined + } + return result; } \ No newline at end of file diff --git a/next.config.js b/next.config.js index 9ef6557..2c21a9a 100644 --- a/next.config.js +++ b/next.config.js @@ -9,18 +9,11 @@ module.exports = { ignoreBuildErrors: true, }, env: { - RPC_URL: process.env.RPC_URL, - CHAIN_ID: process.env.CHAIN_ID, - APP_ENV: process.env.APP_ENV, - INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID, - ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY, PINATA_API_SECRET: process.env.PINATA_API_SECRET, PINATA_API_KEY: process.env.PINATA_API_KEY, IPFS_URL: process.env.IPFS_URL, DUNE_API_KEY: process.env.DUNE_API_KEY, - NEXT_PUBLIC_ENABLE_TESTNETS: process.env.ENABLE_TESTNETS, NEXT_PUBLIC_ALCHEMY_API_KEY: process.env.NEXT_PUBLIC_ALCHEMY_API_KEY, - NEXT_PUBLIC_ZERION_KEY: process.env.ZERION_KEY, }, images: { domains: ["rawcdn.githack.com"], diff --git a/package.json b/package.json index 6a5ed12..5b77694 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "marked-react": "^1.3.2", "next": "^13.5.2", "path": "^0.12.7", + "rc-slider": "^10.3.1", "rc-tooltip": "^6.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -34,7 +35,7 @@ "slick-carousel": "^1.8.1", "tailwind-scrollbar-hide": "^1.1.7", "tailwindcss": "^3.2.6", - "vaultcraft-sdk": "0.1.14", + "vaultcraft-sdk": "0.1.15", "viem": "1.11.1", "wagmi": "1.4.2" }, diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 570f312..17d739b 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -2,9 +2,9 @@ import NoSSR from "react-no-ssr"; import { useEffect, useState } from "react"; import type { NextPage } from "next"; -import { useAccount } from "wagmi"; +import { Address, useAccount, useBalance, usePublicClient, useWalletClient } from "wagmi"; import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; -import { ChainId, SUPPORTED_NETWORKS } from "@/lib/utils/connectors"; +import { SUPPORTED_NETWORKS } from "@/lib/utils/connectors"; import { NumberFormatter } from "@/lib/utils/formatBigNumber"; import useNetworkFilter from "@/lib/useNetworkFilter"; import getVaultNetworth from "@/lib/vault/getVaultNetworth"; @@ -13,6 +13,11 @@ import { getVaultsByChain } from "@/lib/vault/getVault"; import { VaultData } from "@/lib/types"; import SmartVault from "@/components/vault/SmartVault"; import NetworkFilter from "@/components/network/NetworkFilter"; +import MainActionButton from "@/components/button/MainActionButton"; +import getGaugeRewards, { GaugeRewards } from "@/lib/gauges/getGaugeRewards"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { claimOPop } from "@/lib/oPop/interactions"; +import { WalletClient } from "viem"; export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2fD2C18f79F93eF299B20B681Ab2a61f5F28A6fF", "0xDFf04Efb38465369fd1A2E8B40C364c22FfEA340", "0xd4D442AC311d918272911691021E6073F620eb07", //@dev for some reason the live 3Crypto yVault isnt picked up by the yearnAdapter nor the yearnFactoryAdapter @@ -22,8 +27,13 @@ export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2 "0x860b717B360378E44A241b23d8e8e171E0120fF0", // R/Dai ] +const { oPOP: OPOP } = getVeAddresses(); + + const Vaults: NextPage = () => { const { address: account } = useAccount(); + const publicClient = usePublicClient() + const { data: walletClient } = useWalletClient() const [initalLoad, setInitalLoad] = useState(false); const [accountLoad, setAccountLoad] = useState(false); @@ -32,16 +42,25 @@ const Vaults: NextPage = () => { const [vaults, setVaults] = useState([]); const vaultTvl = useVaultTvl(); + const [gaugeRewards, setGaugeRewards] = useState() + const { data: oBal } = useBalance({ chainId: 1, address: OPOP }) + const [searchString, handleSearch] = useState(""); useEffect(() => { async function getVaults() { setInitalLoad(true) if (account) setAccountLoad(true) - const fetchedVaults = await Promise.all( + const fetchedVaults = (await Promise.all( SUPPORTED_NETWORKS.map(async (chain) => getVaultsByChain({ chain, account })) - ); - setVaults(fetchedVaults.flat()); + )).flat(); + const rewards = await getGaugeRewards({ + gauges: fetchedVaults.filter(vault => vault.gauge && vault.chainId === 1).map(vault => vault.gauge?.address) as Address[], + account: account as Address, + publicClient + }) + setGaugeRewards(rewards) + setVaults(fetchedVaults); } if (!account && !initalLoad) getVaults(); if (account && !accountLoad) getVaults() @@ -73,8 +92,8 @@ const Vaults: NextPage = () => {

-
-
+
+

TVL

@@ -89,6 +108,45 @@ const Vaults: NextPage = () => {
+ +
+
+

My oPOP

+
+ {`${oBal ? NumberFormatter.format(Number(oBal?.value)) : "0"}`} +
+
+ +
+

Claimable oPOP

+
+ {`$${gaugeRewards ? NumberFormatter.format(Number(gaugeRewards?.total)) : "0"}`} +
+
+ +
+ + claimOPop({ + gauges: gaugeRewards?.amounts?.filter(gauge => Number(gauge.amount) > 0).map(gauge => gauge.address) as Address[], + account: account as Address, + clients: { publicClient, walletClient: walletClient as WalletClient } + })} + /> +
+
+
+ + claimOPop({ + gauges: gaugeRewards?.amounts?.filter(gauge => Number(gauge.amount) > 0).map(gauge => gauge.address) as Address[], + account: account as Address, + clients: { publicClient, walletClient: walletClient as WalletClient } + })} + /> +
diff --git a/pages/vepop.tsx b/pages/vepop.tsx index b535db7..100eafb 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -1,101 +1,59 @@ // @ts-ignore import NoSSR from "react-no-ssr"; +import { mainnet, useAccount, useBalance, usePublicClient, useWalletClient } from "wagmi"; +import { Address, WalletClient } from "viem"; import { useEffect, useState } from "react"; -import { intervalToDuration } from "date-fns"; -import { WalletIcon } from "@heroicons/react/24/outline"; - -import MainActionButton from "@/components/button/MainActionButton"; -import SecondaryActionButton from "@/components/button/SecondaryActionButton"; - -import useGauges from "@/lib/gauges/useGauges"; -import type { Gauge } from "@/lib/gauges/useGauges"; - +import { getVeAddresses } from "@/lib/utils/addresses"; +import { hasAlreadyVoted } from "@/lib/gauges/hasAlreadyVoted"; +import { VaultData } from "@/lib/types"; +import { getVaultsByChain } from "@/lib/vault/getVault"; +import VeRewards from "@/components/vepop/VeRewards"; +import StakingInterface from "@/components/vepop/StakingInterface"; +import { sendVotes } from "@/lib/gauges/interactions"; import Gauge from "@/components/vepop/Gauge"; import LockModal from "@/components/vepop/modals/lock/LockModal"; import ManageLockModal from "@/components/vepop/modals/manage/ManageLockModal"; -import useLockedBalanceOf from "@/lib/Gauges/useLockedBalanceOf"; -import useOPopPrice from "@/lib/OPop/useOPopPrice"; -import useOPopDiscount from "@/lib/OPop/useOPopDiscount"; -import OPopModal from "@/components/vepop/modals/oPop/OPopModal"; -import useClaimableOPop from "@/lib/Gauges/useClaimableOPop"; -import { useClaimOPop } from "@/lib/OPop/useClaimOPop"; -import { showSuccessToast, showErrorToast } from "@/lib/toasts"; -import { getVeAddresses } from "@/lib/utils/addresses"; -import { useHasAlreadyVoted } from "@/lib/gauges/useHasAlreadyVoted"; -import { useUserWethReward } from "@/lib/feeDistributor/useUserWethRewards"; -import { useClaimTokens } from "@/lib/feeDistributor/useClaimToken"; -import useClaimableTokens from "@/lib/feeDistributor/getVeApy"; -import getVeApy from "@/lib/feeDistributor/getVeApy"; -import { useAccount } from "wagmi"; -import { formatAndRoundBigNumber, formatNumber } from "@/lib/utils/formatBigNumber"; -import { Address, formatEther, zeroAddress } from "viem"; -import { getVotePeriodEndTime } from "@/lib/gauges/utils"; -const { - BalancerPool: POP_LP, - VotingEscrow: VOTING_ESCROW, - GaugeController: GAUGE_CONTROLLER, - oPOP: OPOP, - POP: POP, - WETH: WETH, - BalancerOracle: OPOP_ORACLE, - Minter: OPOP_MINTER, - FeeDistributor: FEE_DISTRIBUTOR -} = getVeAddresses(); +const { VotingEscrow: VOTING_ESCROW } = getVeAddresses(); function VePopContainer() { const { address: account } = useAccount() - const { data: signer } = useSigner({ chainId: 1 }) + const publicClient = usePublicClient(); + const { data: walletClient } = useWalletClient() - const { data: popLpBal } = useBalanceOf({ chainId: 1, address: POP_LP, account }) - const { data: oPopBal } = useBalanceOf({ chainId: 1, address: OPOP, account }) - const { data: lockedBal } = useLockedBalanceOf({ chainId: 1, address: VOTING_ESCROW, account }) - const { data: veBal } = useBalanceOf({ chainId: 1, address: VOTING_ESCROW, account }) + const { data: veBal } = useBalance({ chainId: 1, address: VOTING_ESCROW }) - const { data: oPopPrice } = useOPopPrice({ chainId: 1, address: OPOP_ORACLE }) + const [initalLoad, setInitalLoad] = useState(false); + const [accountLoad, setAccountLoad] = useState(false); - const { data: gauges } = useGauges({ address: GAUGE_CONTROLLER, chainId: 1 }) - const { data: gaugeRewards } = useClaimableOPop({ addresses: gauges?.map((gauge: Gauge) => gauge.address), chainId: 1, account }) - - const { data: userWethReward } = useUserWethReward({ chainId: 5, address: FEE_DISTRIBUTOR, user: account, token: WETH }) - - const [votes, setVotes] = useState([]); - const { data: hasAlreadyVoted } = useHasAlreadyVoted({ addresses: gauges?.map((gauge: Gauge) => gauge.address), chainId: 1, account }) - const canVote = account && Number(veBal?.value) > 0 && !hasAlreadyVoted + const [vaults, setVaults] = useState([]); + const [votes, setVotes] = useState([]); + const [canVote, setCanVote] = useState(false); const [showLockModal, setShowLockModal] = useState(false); const [showMangementModal, setShowMangementModal] = useState(false); - const [showOPopModal, setShowOPopModal] = useState(false); - - const [apy, setApy] = useState(undefined); useEffect(() => { - if (!apy) { - getVeApy({ chainId: 5, address: FEE_DISTRIBUTOR, token: "0x2D9B33e9918Dce388d1Cb8Bf09D4E827b899e9d9" }).then(res => setApy(res)) - } - }, [apy]) - - useEffect(() => { - if (gauges?.length > 0, votes?.length === 0) { - setVotes(new Array(gauges?.length).fill(0)); + async function initialSetup() { + setInitalLoad(true) + if (account) setAccountLoad(true) + const allVaults = await getVaultsByChain({ chain: mainnet, account }) + const vaultsWithGauges = allVaults.filter(vault => !!vault.gauge) + setVaults(vaultsWithGauges); + if (vaultsWithGauges.length > 0 && votes.length === 0) { + setVotes(vaultsWithGauges.map(gauge => 0)); + + const hasVoted = await hasAlreadyVoted({ + addresses: vaultsWithGauges?.map((vault: VaultData) => vault.gauge?.address as Address), + publicClient, + account: account as Address + }) + setCanVote(!!account && Number(veBal?.value) > 0 && !hasVoted) + } } - }, [gauges, votes]) - - function votingPeriodEnd(): number[] { - const periodEnd = getVotePeriodEndTime(); - const interval: Interval = { start: new Date(), end: periodEnd }; - const timeUntilEnd: Duration = intervalToDuration(interval); - const formattedTime = [ - (timeUntilEnd.days || 0) % 7, - timeUntilEnd.hours || 0, - timeUntilEnd.minutes || 0, - timeUntilEnd.seconds || 0, - ]; - return formattedTime; - } - - const { write: claimOPop = noOp } = useClaimOPop(OPOP_MINTER, gaugeRewards?.amounts?.filter((gauge: Gauge) => Number(gauge.amount) > 0).map((gauge: Gauge) => gauge.address)); - const { write: claimTokens = noOp } = useClaimTokens(FEE_DISTRIBUTOR, account as Address, [WETH]); + if (!account && !initalLoad) initialSetup(); + if (account && !accountLoad) initialSetup() + }, [account]) function handleVotes(val: number, index: number) { setVotes((prevVotes) => { @@ -111,136 +69,32 @@ function VePopContainer() { }); } - - function sendVotesTx() { - const gaugeController = new Contract( - GAUGE_CONTROLLER, - ["function vote_for_many_gauge_weights(address[8],uint256[8]) external"], - signer - ); - - let addr = new Array(8); - let v = new Array(8); - - for (let i = 0; i < Math.ceil(gauges.length / 8); i++) { - addr = []; - v = []; - - for (let n = 0; n < 8; n++) { - const l = i * 8; - v[n] = votes[n + l] === undefined ? 0 : votes[n + l]; - addr[n] = gauges[n + l] === undefined || votes[n + l] === 0 ? zeroAddress : gauges[n + l].address; - - } - - gaugeController.vote_for_many_gauge_weights(addr, v) - .then(() => { - showSuccessToast(); - }) - .catch((error: any) => { - showErrorToast(error); - }); - } - } - return ( <> {(!votes || votes.length === 0) ? <> : <> -
-

- Lock 20WETH-80POP for vePOP, Rewards, and Voting Power +

+ Lock 20WETH-80POP for vePOP, voting Power & oPOP

Vote with your vePOP below to influence how much $oPOP each pool will receive. Your vote will persist until you change it and editing a pool can only be done once every 10 days.

-
- Mint the token needed for testing on Goerli here:
- POP
- WETH
- BalancerPool -
-
-
-

vePOP

- -

My POP LP

-

{popLpBal?.formatted || "0"}

-
- -

My Locked POP LP

-

{lockedBal ? formatAndRoundBigNumber(lockedBal?.amount, 18) : "0"}

-
- -

Locked Until

-

{lockedBal && lockedBal?.end.toString() !== "0" ? new Date(Number(lockedBal?.end) * 1000).toLocaleDateString() : "-"}

-
- -

My vePOP

-

{veBal?.formatted || "0"}

-
- -

Voting period ends

-

{votingPeriodEnd()[0]}d : {votingPeriodEnd()[1]}h: {votingPeriodEnd()[2]}m

-
-
- setShowLockModal(true)} disabled={Number(veBal?.value) > 0} /> - setShowMangementModal(true)} disabled={Number(veBal?.value) === 0} /> -
-
- -
-

Total vePOP Rewards

- -

APR

-

{apy || "0"} %

-
- -

Claimable WETH

-

{parseFloat(formatEther(userWethReward)).toFixed(3)} wETH

-
-
- claimTokens()} disabled={Number(userWethReward) === 0} /> -
-
-
- -

Claimable oPOP

-

{gaugeRewards?.total ? (Number(gaugeRewards?.total) / 1e18).toFixed(2) : "0"}

-
- -

My oPOP

-
-

- {oPopBal?.value ? (Number(oPopBal?.value) / 1e18).toFixed(2) : "0"} - -

-

- ($ {oPopPrice?.value && oPopBal?.value ? - formatNumber((Number(oPopBal?.value) / 1e18) * (Number(oPopPrice?.value) / 1e18)) : - "0"}) -

-
-
-
- setShowOPopModal(true)} disabled={Number(oPopBal?.value) === 0} /> - claimOPop()} disabled={Number(gaugeRewards?.total) === 0} /> -
-
-
+
+ +
- {gauges?.length > 0 ? gauges.map((gauge: Gauge, index: number) => - + {vaults?.length > 0 ? vaults.map((vault: VaultData, index: number) => + ) :

Loading Gauges...

} @@ -264,7 +118,7 @@ function VePopContainer() {

diff --git a/yarn.lock b/yarn.lock index 6cdf827..1f36598 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== +"@adraffy/ens-normalize@1.10.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" + integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== + "@adraffy/ens-normalize@1.9.4": version "1.9.4" resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.4.tgz#aae21cb858bbb0411949d5b7b3051f4209043f62" @@ -17,7 +22,7 @@ resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== -"@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.6", "@babel/runtime@^7.23.2": +"@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.6", "@babel/runtime@^7.23.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== @@ -47,6 +52,17 @@ stream-browserify "^3.0.0" util "^0.12.4" +"@curvefi/api@2.44.0": + version "2.44.0" + resolved "https://registry.yarnpkg.com/@curvefi/api/-/api-2.44.0.tgz#0df6149c8f0764f56a9905438aa37099f1710705" + integrity sha512-3GPrUf2wTE2q7Lf0j7EpDpObwAG3Qn480UvY6YeMzq+8sQpuBsa42uXtXidNEr2vr7uA47hKH1tDrYbCmo/gdQ== + dependencies: + axios "^0.21.1" + bignumber.js "^9.0.1" + ethcall "^6.0.1" + ethers "^6.3.0" + memoizee "^0.4.15" + "@emotion/hash@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" @@ -79,10 +95,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.51.0": - version "8.51.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa" - integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg== +"@eslint/js@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c" + integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA== "@headlessui/react@^1.7.10": version "1.7.17" @@ -96,12 +112,12 @@ resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.0.18.tgz#f80301907c243df03c7e9fd76c0286e95361f7c1" integrity sha512-7TyMjRrZZMBPa+/5Y8lN0iyvUU/01PeMGX2+RE7cQWpEUIcb4QotzUObFkJDejj/HUH4qjP/eQ0gzzKs2f+6Yw== -"@humanwhocodes/config-array@^0.11.11": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" + "@humanwhocodes/object-schema" "^2.0.1" debug "^4.1.1" minimatch "^3.0.5" @@ -110,10 +126,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" @@ -347,9 +363,9 @@ fastq "^1.6.0" "@rainbow-me/rainbowkit@^1.0.11": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rainbow-me/rainbowkit/-/rainbowkit-1.1.2.tgz#733a2c864dd7dd3625ed54440a1ccb18b0636c72" - integrity sha512-yWxKDfHL4xDZJW34APGkmO2SkxjHwrEeAfvx6+137hWLttQwHcalG9nj4II8roYV2/2XJPmQsbEs7TM0rC0fOg== + version "1.1.3" + resolved "https://registry.yarnpkg.com/@rainbow-me/rainbowkit/-/rainbowkit-1.1.3.tgz#593d11e7f5bdee5be35b4c8d890eb55884632730" + integrity sha512-sgklyUmKFFholbRxjbnkQwzlC0wsP0GnCKl6d+4qTpBbQK3P2kfCM9AcDWdkTv3XVQ40fByE8mc3jJ+rI8JdIw== dependencies: "@vanilla-extract/css" "1.9.1" "@vanilla-extract/dynamic" "2.0.2" @@ -369,9 +385,9 @@ rc-util "^5.24.4" "@rc-component/trigger@^1.17.0": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-1.17.1.tgz#3de00f7a8997bb4d8e608502e095d6d4e713ddc9" - integrity sha512-ocD6GlyrPMtWfSdGmfURpudj6ZQqykG/+GH9QVhziG/0EtpPqK5FUbptwXDJGBJwvKhk4Z6jhxJE7utH464SgQ== + version "1.17.2" + resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-1.17.2.tgz#dca84a87754eb5b796859c48910ba06e7fb8454e" + integrity sha512-Jp3dXk/IzwHKM2Tn3ezdvQSwkPeH4v1s7QjIo7f5NFLIZVpJQ8a34FduZw8E6fT1PVgLXYd/JBIyd+YpgyQddA== dependencies: "@babel/runtime" "^7.23.2" "@rc-component/portal" "^1.1.0" @@ -444,9 +460,9 @@ buffer "~6.0.3" "@solana/web3.js@^1.70.1": - version "1.87.1" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.87.1.tgz#da376cebbc4cc97ece0cb028d799163ea147f299" - integrity sha512-E8Y9bNlZ8TQlhOvCx1b7jG+TjA4SJLVwufmIk1+tcQctUhK5HiB1Q8ljd4yQDkFlk6OOeAlAeqvW0YntWJU94Q== + version "1.87.2" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.87.2.tgz#d83484ab576f421342138ca1e0b98d2b9cfc6a00" + integrity sha512-TZNhS+tvJbYjm0LAvIkUy/3Aqgt2l6/3X6XsVUpvj5MGOl2Q6Ch8hYSxcUUtMbAFNN3sUXmV8NhhMLNJEvI6TA== dependencies: "@babel/runtime" "^7.22.6" "@noble/curves" "^1.2.0" @@ -675,13 +691,18 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.33.tgz#80bf1da64b15f21fd8c1dc387c31929317d99ee9" integrity sha512-AuHIyzR5Hea7ij0P9q7vx7xu4z0C28ucwjAZC0ja7JhINyCnOw8/DnvAPQQ9TfOlCtZAmCERKQX9+o1mgQhuOQ== -"@types/node@*": +"@types/node@*", "@types/node@^20.2.5": version "20.8.7" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.7.tgz#ad23827850843de973096edfc5abc9e922492a25" integrity sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ== dependencies: undici-types "~5.25.1" +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/node@^12.12.54": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" @@ -698,9 +719,9 @@ integrity sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g== "@types/react@^18.0.9": - version "18.2.29" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.29.tgz#88b48a287e00f6fdcd6f95662878fb701ae18b27" - integrity sha512-Z+ZrIRocWtdD70j45izShRwDuiB4JZqDegqMFW/I8aG5DxxLKOzVNoq62UIO82v9bdgi+DO1jvsb9sTEZUSm+Q== + version "18.2.31" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.31.tgz#74ae2630e4aa9af599584157abd3b95d96fb9b40" + integrity sha512-c2UnPv548q+5DFh03y8lEDeMfDwBn9G3dRwfkrxQMo/dOtRHUUO57k6pHvBIfH/VF4Nh+98mZ5aaSe+2echD5g== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -775,6 +796,11 @@ "@typescript-eslint/types" "6.8.0" eslint-visitor-keys "^3.4.1" +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + "@vanilla-extract/css@1.9.1": version "1.9.1" resolved "https://registry.yarnpkg.com/@vanilla-extract/css/-/css-1.9.1.tgz#337b79faa5f8f98915a90c3fe3c30b54be746c09" @@ -1194,6 +1220,11 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" +abi-coder@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/abi-coder/-/abi-coder-5.0.0.tgz#df36b51bb02aea45f54f24c403b4245f79a75fcf" + integrity sha512-Kpyv/AhAaIaVJiJ6S/xqoTsiJrfSMc3QsBCiRDqic3o1CZNKGR3CIeT1K/1VZ7Wk5uSwsOAxQcke1TVUEz+usg== + abitype@0.8.7: version "0.8.7" resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.8.7.tgz#e4b3f051febd08111f486c0cc6a98fa72d033622" @@ -1214,6 +1245,11 @@ acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + aes-js@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" @@ -1291,7 +1327,7 @@ array-buffer-byte-length@^1.0.0: call-bind "^1.0.2" is-array-buffer "^3.0.1" -array-includes@^3.1.6: +array-includes@^3.1.6, array-includes@^3.1.7: version "3.1.7" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== @@ -1307,7 +1343,7 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.findlastindex@^1.2.2: +array.prototype.findlastindex@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== @@ -1318,7 +1354,7 @@ array.prototype.findlastindex@^1.2.2: es-shim-unscopables "^1.0.0" get-intrinsic "^1.2.1" -array.prototype.flat@^1.3.1: +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== @@ -1328,7 +1364,7 @@ array.prototype.flat@^1.3.1: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.1: +array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -1413,6 +1449,13 @@ axe-core@^4.6.2: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.2.tgz#2f6f3cde40935825cf4465e3c1c9e77b240ff6ae" integrity sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g== +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + axios@^1.3.6, axios@^1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.1.tgz#11fbaa11fc35f431193a9564109c88c1f27b585f" @@ -1461,7 +1504,7 @@ bigint-buffer@^1.1.5: dependencies: bindings "^1.3.0" -bignumber.js@*: +bignumber.js@*, bignumber.js@^9.0.1: version "9.1.2" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== @@ -1551,13 +1594,14 @@ busboy@1.6.0: dependencies: streamsearch "^1.1.0" -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" callsites@^3.0.0: version "3.1.0" @@ -1575,9 +1619,9 @@ camelcase@^5.0.0: integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: - version "1.0.30001551" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001551.tgz#1f2cfa8820bd97c971a57349d7fd8f6e08664a3e" - integrity sha512-vtBAez47BoGMMzlbYhfXrMV1kvRF2WP/lqiMuDu1Sb4EE4LKEgjopFDSRtZfdVnslNRpOqV/woE+Xgrwj6VQlg== + version "1.0.30001553" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz#e64e7dc8fd4885cd246bb476471420beb5e474b5" + integrity sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A== chalk@^4.0.0, chalk@^4.1.1: version "4.1.2" @@ -1602,7 +1646,7 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" -classnames@^2.2.1, classnames@^2.3.1, classnames@^2.3.2: +classnames@^2.2.1, classnames@^2.2.5, classnames@^2.3.1, classnames@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== @@ -1728,6 +1772,14 @@ csstype@^3.0.2, csstype@^3.0.7: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + damerau-levenshtein@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -1779,7 +1831,7 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -define-data-property@^1.0.1: +define-data-property@^1.0.1, define-data-property@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== @@ -1879,9 +1931,9 @@ duplexify@^4.1.2: stream-shift "^1.0.0" electron-to-chromium@^1.4.535: - version "1.4.559" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.559.tgz#050483c22c5eb2345017a8976a67b060559a33f4" - integrity sha512-iS7KhLYCSJbdo3rUSkhDTVuFNCV34RKs2UaB9Ecr7VlqzjjWW//0nfsFF5dtDmyXlZQaDYYtID5fjtC/6lpRug== + version "1.4.563" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.563.tgz#dabb424202754c1fed2d2938ff564b23d3bbf0d3" + integrity sha512-dg5gj5qOgfZNkPNeyKBZQAQitIQ/xwfIDmEQJHCbXaD9ebTZxwJXUsDYcBlAvZGZLi+/354l35J1wkmP6CqYaw== emoji-regex@^8.0.0: version "8.0.0" @@ -1914,25 +1966,25 @@ enhanced-resolve@^5.12.0: tapable "^2.2.0" es-abstract@^1.22.1: - version "1.22.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.2.tgz#90f7282d91d0ad577f505e423e52d4c1d93c1b8a" - integrity sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA== + version "1.22.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== dependencies: array-buffer-byte-length "^1.0.0" arraybuffer.prototype.slice "^1.0.2" available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + call-bind "^1.0.5" es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" - get-intrinsic "^1.2.1" + get-intrinsic "^1.2.2" get-symbol-description "^1.0.0" globalthis "^1.0.3" gopd "^1.0.1" - has "^1.0.3" has-property-descriptors "^1.0.0" has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" internal-slot "^1.0.5" is-array-buffer "^3.0.2" is-callable "^1.2.7" @@ -1942,7 +1994,7 @@ es-abstract@^1.22.1: is-string "^1.0.7" is-typed-array "^1.1.12" is-weakref "^1.0.2" - object-inspect "^1.12.3" + object-inspect "^1.13.1" object-keys "^1.1.1" object.assign "^4.1.4" regexp.prototype.flags "^1.5.1" @@ -1956,7 +2008,7 @@ es-abstract@^1.22.1: typed-array-byte-offset "^1.0.0" typed-array-length "^1.0.4" unbox-primitive "^1.0.2" - which-typed-array "^1.1.11" + which-typed-array "^1.1.13" es-iterator-helpers@^1.0.12: version "1.0.15" @@ -1979,20 +2031,20 @@ es-iterator-helpers@^1.0.12: safe-array-concat "^1.0.1" es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + version "2.0.2" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" + integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" + get-intrinsic "^1.2.2" has-tostringtag "^1.0.0" + hasown "^2.0.0" es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== dependencies: - has "^1.0.3" + hasown "^2.0.0" es-to-primitive@^1.2.1: version "1.2.1" @@ -2003,6 +2055,24 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: + version "0.10.62" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" + integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + next-tick "^1.1.0" + +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + es6-promise@^4.0.3: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" @@ -2015,6 +2085,24 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +es6-weak-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" + integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== + dependencies: + d "1" + es5-ext "^0.10.46" + es6-iterator "^2.0.3" + es6-symbol "^3.1.1" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -2040,7 +2128,7 @@ eslint-config-next@^13.3.4: eslint-plugin-react "^7.33.2" eslint-plugin-react-hooks "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" -eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.7: +eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: version "0.3.9" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== @@ -2070,25 +2158,25 @@ eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: debug "^3.2.7" eslint-plugin-import@^2.28.1: - version "2.28.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4" - integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A== - dependencies: - array-includes "^3.1.6" - array.prototype.findlastindex "^1.2.2" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" + version "2.29.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155" + integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg== + dependencies: + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" + eslint-import-resolver-node "^0.3.9" eslint-module-utils "^2.8.0" - has "^1.0.3" - is-core-module "^2.13.0" + hasown "^2.0.0" + is-core-module "^2.13.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.fromentries "^2.0.6" - object.groupby "^1.0.0" - object.values "^1.1.6" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" semver "^6.3.1" tsconfig-paths "^3.14.2" @@ -2155,17 +2243,18 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.15.0: - version "8.51.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.51.0.tgz#4a82dae60d209ac89a5cff1604fea978ba4950f3" - integrity sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA== + version "8.52.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc" + integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.51.0" - "@humanwhocodes/config-array" "^0.11.11" + "@eslint/js" "8.52.0" + "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -2273,6 +2362,35 @@ eth-rpc-errors@^4.0.2: dependencies: fast-safe-stringify "^2.0.6" +ethcall@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/ethcall/-/ethcall-6.0.2.tgz#bc814289453a79402bef514b902fa45ee1f7946a" + integrity sha512-FyaKLlxtaVt+kRmhzDG3YfW4VxqasxZE2CDSfylMVp8kCxsBikzFE1BO90yAMGdjdwaX0kHlvjWSxKRpiEcI4w== + dependencies: + "@types/node" "^20.2.5" + abi-coder "^5.0.0" + +ethers@^6.3.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.8.0.tgz#0a26f57e96fd697cefcfcef464e0c325689d1daf" + integrity sha512-zrFbmQRlraM+cU5mE4CZTLBurZTs2gdp2ld0nG/f3ecBK+x6lZ69KSxBqZ4NjclxwfTxl5LeNufcBbMsTdY53Q== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== + dependencies: + d "1" + es5-ext "~0.10.14" + eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -2283,6 +2401,13 @@ events@^3.3.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +ext@^1.1.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + extend@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -2402,7 +2527,7 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== -follow-redirects@^1.15.0: +follow-redirects@^1.14.0, follow-redirects@^1.15.0: version "1.15.3" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== @@ -2452,7 +2577,7 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1: +function-bind@^1.1.1, function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== @@ -2477,15 +2602,15 @@ get-caller-file@^2.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== dependencies: - function-bind "^1.1.1" - has "^1.0.3" + function-bind "^1.1.2" has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" get-nonce@^1.0.0: version "1.0.1" @@ -2621,11 +2746,11 @@ has-flag@^4.0.0: integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== dependencies: - get-intrinsic "^1.1.1" + get-intrinsic "^1.2.2" has-proto@^1.0.1: version "1.0.1" @@ -2657,6 +2782,13 @@ hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + hey-listen@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68" @@ -2725,12 +2857,12 @@ inherits@2.0.3: integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== internal-slot@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" + get-intrinsic "^1.2.2" + hasown "^2.0.0" side-channel "^1.0.4" invariant@^2.2.4: @@ -2791,12 +2923,12 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.11.0, is-core-module@^2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== +is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: - has "^1.0.3" + hasown "^2.0.0" is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" @@ -2863,6 +2995,11 @@ is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-promise@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -3184,6 +3321,13 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" + integrity sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ== + dependencies: + es5-ext "~0.10.2" + make-plural@*: version "7.3.0" resolved "https://registry.yarnpkg.com/make-plural/-/make-plural-7.3.0.tgz#2889dbafca2fb097037c47967d3e3afa7e48a52c" @@ -3209,6 +3353,20 @@ media-query-parser@^2.0.2: dependencies: "@babel/runtime" "^7.12.5" +memoizee@^0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72" + integrity sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ== + dependencies: + d "^1.0.1" + es5-ext "^0.10.53" + es6-weak-map "^2.0.3" + event-emitter "^0.3.5" + is-promise "^2.2.2" + lru-queue "^0.1.0" + next-tick "^1.1.0" + timers-ext "^0.1.7" + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -3312,6 +3470,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +next-tick@1, next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + next@^13.5.2: version "13.5.6" resolved "https://registry.yarnpkg.com/next/-/next-13.5.6.tgz#e964b5853272236c37ce0dd2c68302973cf010b1" @@ -3384,10 +3547,10 @@ object-hash@^3.0.0: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== -object-inspect@^1.12.3, object-inspect@^1.9.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.0.tgz#42695d3879e1cd5bda6df5062164d80c996e23e2" - integrity sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g== +object-inspect@^1.13.1, object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== object-keys@^1.1.1: version "1.1.1" @@ -3413,7 +3576,7 @@ object.entries@^1.1.6: define-properties "^1.2.0" es-abstract "^1.22.1" -object.fromentries@^2.0.6: +object.fromentries@^2.0.6, object.fromentries@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== @@ -3422,7 +3585,7 @@ object.fromentries@^2.0.6: define-properties "^1.2.0" es-abstract "^1.22.1" -object.groupby@^1.0.0: +object.groupby@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== @@ -3440,7 +3603,7 @@ object.hasown@^1.1.2: define-properties "^1.2.0" es-abstract "^1.22.1" -object.values@^1.1.6: +object.values@^1.1.6, object.values@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== @@ -3802,15 +3965,24 @@ rc-motion@^2.0.0: rc-util "^5.21.0" rc-resize-observer@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.3.1.tgz#b61b9f27048001243617b81f95e53d7d7d7a6a3d" - integrity sha512-iFUdt3NNhflbY3mwySv5CA1TC06zdJ+pfo0oc27xpf4PIOvfZwZGtD9Kz41wGYqC4SLio93RVAirSSpYlV/uYg== + version "1.4.0" + resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz#7bba61e6b3c604834980647cce6451914750d0cc" + integrity sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q== dependencies: "@babel/runtime" "^7.20.7" classnames "^2.2.1" - rc-util "^5.27.0" + rc-util "^5.38.0" resize-observer-polyfill "^1.5.1" +rc-slider@^10.3.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-10.3.1.tgz#345e818975f4bb61b66340799af8cfccad7c8ad7" + integrity sha512-XszsZLkbjcG9ogQy/zUC0n2kndoKUAnY/Vnk1Go5Gx+JJQBz0Tl15d5IfSiglwBUZPS9vsUJZkfCmkIZSqWbcA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.27.0" + rc-tooltip@^6.1.0: version "6.1.1" resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-6.1.1.tgz#8f3bf2b7008f091977da19aa4617a48cefed3d10" @@ -4112,6 +4284,16 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + set-function-name@^2.0.0, set-function-name@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" @@ -4419,6 +4601,14 @@ thread-stream@^0.15.1: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +timers-ext@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" + integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== + dependencies: + es5-ext "~0.10.46" + next-tick "1" + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -4461,6 +4651,11 @@ tslib@1.14.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" @@ -4478,6 +4673,16 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" + integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== + typed-array-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" @@ -4636,11 +4841,12 @@ valtio@1.11.2: proxy-compare "2.5.1" use-sync-external-store "1.2.0" -vaultcraft-sdk@0.1.14: - version "0.1.14" - resolved "https://registry.yarnpkg.com/vaultcraft-sdk/-/vaultcraft-sdk-0.1.14.tgz#a56f97402ace1f46dd15ebec55caceffdf444b66" - integrity sha512-O4kv1BK8xbTylPO+OW2sVMZgO2BMqzHXsNHtyeYlWYwEzC+RhWejwGXu6sUrVsFYPiMmTFbu0ZWDe6jIbb4nTw== +vaultcraft-sdk@0.1.15: + version "0.1.15" + resolved "https://registry.yarnpkg.com/vaultcraft-sdk/-/vaultcraft-sdk-0.1.15.tgz#2844e8d6c1be08f85084426f0805a825fa13ca16" + integrity sha512-nCpP0xOiE3yCpfKhud0+VCPP4twwfTodoSan6SvJbflVy9kLzBSQPIRU27H4KiDC9yIZEe11MHVHkLfhWfcXrA== dependencies: + "@curvefi/api" "2.44.0" axios "^1.5.0" dotenv "^16.3.1" node-cache "^5.1.2" @@ -4752,13 +4958,13 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== -which-typed-array@^1.1.11, which-typed-array@^1.1.2, which-typed-array@^1.1.9: - version "1.1.11" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" - integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== +which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.2, which-typed-array@^1.1.9: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== dependencies: available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + call-bind "^1.0.4" for-each "^0.3.3" gopd "^1.0.1" has-tostringtag "^1.0.0" @@ -4789,6 +4995,11 @@ ws@8.13.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + ws@^7.4.5, ws@^7.5.1: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" @@ -4850,8 +5061,8 @@ yocto-queue@^0.1.0: integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== zustand@^4.3.1: - version "4.4.3" - resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.3.tgz#1d54cf7fa4507ad8bf58e2f13e08ddc8a6730128" - integrity sha512-oRy+X3ZazZvLfmv6viIaQmtLOMeij1noakIsK/Y47PWYhT8glfXzQ4j0YcP5i0P0qI1A4rIB//SGROGyZhx91A== + version "4.4.4" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.4.tgz#cc06202219972bd61cef1fd10105e6384ae1d5cf" + integrity sha512-5UTUIAiHMNf5+mFp7/AnzJXS7+XxktULFN0+D1sCiZWyX7ZG+AQpqs2qpYrynRij4QvoDdCD+U+bmg/cG3Ucxw== dependencies: use-sync-external-store "1.2.0" From 642648ab7e4a15576c5ec45eb8ed45b4d5953b57 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Mon, 23 Oct 2023 15:54:28 +0200 Subject: [PATCH 21/84] added vepop to menus --- components/navbar/MobileMenu.tsx | 7 +------ components/navbar/NavbarLinks.tsx | 6 +++++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/components/navbar/MobileMenu.tsx b/components/navbar/MobileMenu.tsx index 2c751f2..a643bcc 100644 --- a/components/navbar/MobileMenu.tsx +++ b/components/navbar/MobileMenu.tsx @@ -65,12 +65,7 @@ export default function MobileMenu(): JSX.Element { const closePopUp = () => { setShowPopUp(false); }; - - function handleCloseAll() { - toggleMenu(false); - toggleProductsMenu(false); - } - + return ( <>
diff --git a/components/navbar/NavbarLinks.tsx b/components/navbar/NavbarLinks.tsx index 457489f..98c8f72 100644 --- a/components/navbar/NavbarLinks.tsx +++ b/components/navbar/NavbarLinks.tsx @@ -3,9 +3,13 @@ import NavbarLink from "@/components/navbar/NavbarLink" const links: { label: string, url: string, onClick?: Function }[] = [ { - label: "Vaults", + label: "Smmart Vaults", url: "/vaults", }, + { + label: "Boost Vaults", + url: "/vepop", + }, { label: "Stats", url: "/stats" From 66010e3ffbb8a0cdbc139ca04e9c6db0be928c8d Mon Sep 17 00:00:00 2001 From: RedVeil Date: Mon, 23 Oct 2023 16:29:24 +0200 Subject: [PATCH 22/84] fixed locking --- components/navbar/NavbarLinks.tsx | 2 +- components/vepop/Gauge.tsx | 2 -- components/vepop/StakingInterface.tsx | 21 +++++++++---------- .../vepop/modals/lock/LockPopInterface.tsx | 15 ++++++++----- .../modals/manage/IncreaseStakeInterface.tsx | 10 ++++----- .../vepop/modals/manage/ManageLockModal.tsx | 2 +- .../modals/oPop/ExerciseOPopInterface.tsx | 6 +++--- lib/gauges/useLockedBalanceOf.ts | 6 ++---- lib/utils/addresses/index.ts | 2 +- pages/vaults.tsx | 2 +- pages/vepop.tsx | 2 +- 11 files changed, 34 insertions(+), 36 deletions(-) diff --git a/components/navbar/NavbarLinks.tsx b/components/navbar/NavbarLinks.tsx index 98c8f72..0f1636a 100644 --- a/components/navbar/NavbarLinks.tsx +++ b/components/navbar/NavbarLinks.tsx @@ -3,7 +3,7 @@ import NavbarLink from "@/components/navbar/NavbarLink" const links: { label: string, url: string, onClick?: Function }[] = [ { - label: "Smmart Vaults", + label: "Smart Vaults", url: "/vaults", }, { diff --git a/components/vepop/Gauge.tsx b/components/vepop/Gauge.tsx index 2c61c2d..026e009 100644 --- a/components/vepop/Gauge.tsx +++ b/components/vepop/Gauge.tsx @@ -24,8 +24,6 @@ export default function Gauge({ vault, index, votes, handleVotes, canVote }: { v } } - console.log({weights}) - return ( diff --git a/components/vepop/StakingInterface.tsx b/components/vepop/StakingInterface.tsx index bdfee8d..ffc0b7d 100644 --- a/components/vepop/StakingInterface.tsx +++ b/components/vepop/StakingInterface.tsx @@ -1,15 +1,14 @@ import { intervalToDuration } from "date-fns"; -import { Dispatch, useState } from "react"; +import { Dispatch, SetStateAction } from "react"; import { Address, useAccount, useBalance } from "wagmi"; import { getVotePeriodEndTime } from "@/lib/gauges/utils"; import MainActionButton from "@/components/button/MainActionButton"; import SecondaryActionButton from "@/components//button/SecondaryActionButton"; import useLockedBalanceOf from "@/lib/gauges/useLockedBalanceOf"; import { getVeAddresses } from "@/lib/utils/addresses"; -import { formatAndRoundBigNumber } from "@/lib/utils/formatBigNumber"; -import LockModal from "@/components/vepop/modals/lock/LockModal"; -import ManageLockModal from "@/components/vepop/modals/manage/ManageLockModal"; -import { SetStateAction } from "jotai"; +import { NumberFormatter } from "@/lib/utils/formatBigNumber"; +import { formatEther } from "viem"; +import { ZERO } from "@/lib/constants"; function votingPeriodEnd(): number[] { const periodEnd = getVotePeriodEndTime(); @@ -38,20 +37,20 @@ export default function StakingInterface({ setShowLockModal, setShowMangementMod const { address: account } = useAccount() const { data: lockedBal } = useLockedBalanceOf({ chainId: 1, address: VOTING_ESCROW, account: account as Address }) - const { data: veBal } = useBalance({ chainId: 1, address: VOTING_ESCROW }) - const { data: popLpBal } = useBalance({ chainId: 1, address: POP_LP }) - + const { data: veBal } = useBalance({ chainId: 1, address: account, token: VOTING_ESCROW }) + const { data: popLpBal } = useBalance({ chainId: 1, address: account, token: POP_LP }) + return ( <>

vePOP

My POP LP

-

{popLpBal?.formatted || "0"}

+

{NumberFormatter.format(Number(formatEther(popLpBal?.value || ZERO))) || "0"}

My Locked POP LP

-

{lockedBal ? formatAndRoundBigNumber(lockedBal?.amount, 18) : "0"}

+

{lockedBal ? NumberFormatter.format(Number(formatEther(lockedBal?.amount))) : "0"}

Locked Until

@@ -59,7 +58,7 @@ export default function StakingInterface({ setShowLockModal, setShowMangementMod

My vePOP

-

{veBal?.formatted || "0"}

+

{NumberFormatter.format(Number(formatEther(veBal?.value || ZERO))) || "0"}

Voting period ends

diff --git a/components/vepop/modals/lock/LockPopInterface.tsx b/components/vepop/modals/lock/LockPopInterface.tsx index d067ae3..3778c0f 100644 --- a/components/vepop/modals/lock/LockPopInterface.tsx +++ b/components/vepop/modals/lock/LockPopInterface.tsx @@ -1,5 +1,5 @@ import { Dispatch, FormEventHandler, SetStateAction, useMemo } from "react"; -import { Address, useBalance, useToken } from "wagmi"; +import { Address, useAccount, useBalance, useToken } from "wagmi"; import { getVeAddresses } from "@/lib/utils/addresses"; import InputTokenWithError from "@/components/input/InputTokenWithError"; import InputNumber from "@/components/input/InputNumber"; @@ -21,10 +21,15 @@ function LockTimeButton({ label, isActive, handleClick }: { label: string, isAct ) } -export default function LockPopInterface({ amountState, daysState }: - { amountState: [number, Dispatch>], daysState: [number, Dispatch>] }): JSX.Element { - const { data: popLp } = useToken({ chainId: 1, address: POP_LP as Address }); - const { data: popLpBal } = useBalance({ chainId: 1, address: POP_LP }) +interface LockPopInterfaceProps { + amountState: [number, Dispatch>]; + daysState: [number, Dispatch>]; +} + +export default function LockPopInterface({ amountState, daysState }: LockPopInterfaceProps): JSX.Element { + const { address: account } = useAccount() + const { data: popLp } = useToken({ chainId: 1, address: POP_LP }); + const { data: popLpBal } = useBalance({ chainId: 1, address: account, token: POP_LP }) const [amount, setAmount] = amountState const [days, setDays] = daysState diff --git a/components/vepop/modals/manage/IncreaseStakeInterface.tsx b/components/vepop/modals/manage/IncreaseStakeInterface.tsx index 96e09fa..77fe932 100644 --- a/components/vepop/modals/manage/IncreaseStakeInterface.tsx +++ b/components/vepop/modals/manage/IncreaseStakeInterface.tsx @@ -1,6 +1,6 @@ import { Dispatch, FormEventHandler, SetStateAction, useMemo } from "react"; import { getVeAddresses } from "@/lib/utils/addresses"; -import { Address, useBalance, useToken } from "wagmi"; +import { Address, useAccount, useBalance, useToken } from "wagmi"; import { formatAndRoundBigNumber, safeRound } from "@/lib/utils/formatBigNumber"; import { ZERO } from "@/lib/constants"; import InputTokenWithError from "@/components/input/InputTokenWithError"; @@ -14,12 +14,10 @@ interface IncreaseStakeInterfaceProps { lockedBal: { amount: bigint, end: bigint } } -export default function IncreaseStakeInterface({ amountState, lockedBal }: IncreaseStakeInterfaceProps -): JSX.Element { +export default function IncreaseStakeInterface({ amountState, lockedBal }: IncreaseStakeInterfaceProps): JSX.Element { + const { address: account } = useAccount() const { data: popLp } = useToken({ chainId: 1, address: POP_LP as Address }); - const { data: popLpBal } = useBalance({ chainId: 1, address: POP_LP }) - - console.log({ popLpBal }) + const { data: popLpBal } = useBalance({ chainId: 1, address: account, token: POP_LP }) const [amount, setAmount] = amountState diff --git a/components/vepop/modals/manage/ManageLockModal.tsx b/components/vepop/modals/manage/ManageLockModal.tsx index b8bf63e..15deefb 100644 --- a/components/vepop/modals/manage/ManageLockModal.tsx +++ b/components/vepop/modals/manage/ManageLockModal.tsx @@ -40,7 +40,7 @@ export default function ManageLockModal({ show }: { show: [boolean, Dispatch(0); diff --git a/components/vepop/modals/oPop/ExerciseOPopInterface.tsx b/components/vepop/modals/oPop/ExerciseOPopInterface.tsx index 0657320..953064d 100644 --- a/components/vepop/modals/oPop/ExerciseOPopInterface.tsx +++ b/components/vepop/modals/oPop/ExerciseOPopInterface.tsx @@ -1,5 +1,5 @@ import { Dispatch, FormEventHandler, SetStateAction, useEffect, useState } from "react"; -import { Address, useAccount, useBalance, usePublicClient, useToken } from "wagmi"; +import { useAccount, useBalance, usePublicClient, useToken } from "wagmi"; import { PlusIcon } from "@heroicons/react/24/outline"; import TokenIcon from "@/components/common/TokenIcon"; import InputTokenWithError from "@/components/input/InputTokenWithError"; @@ -30,9 +30,9 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta const [amount, setAmount] = amountState; const [maxPaymentAmount, setMaxPaymentAmount] = maxPaymentAmountState; - const { data: oPopBal } = useBalance({ chainId: 1, address: OPOP }) + const { data: oPopBal } = useBalance({ chainId: 1, address: account, token: OPOP }) const { data: ethBal } = useBalance({ chainId: 1, address: account }) - const { data: wethBal } = useBalance({ chainId: 1, address: WETH }) + const { data: wethBal } = useBalance({ chainId: 1, address: account, token: WETH }) const { data: oPop } = useToken({ chainId: 1, address: OPOP }); const { data: pop } = useToken({ chainId: 1, address: POP }); diff --git a/lib/gauges/useLockedBalanceOf.ts b/lib/gauges/useLockedBalanceOf.ts index 9481eaa..2875833 100644 --- a/lib/gauges/useLockedBalanceOf.ts +++ b/lib/gauges/useLockedBalanceOf.ts @@ -1,4 +1,5 @@ import { Address, useContractRead } from "wagmi"; +import { VotingEscrowAbi } from "@/lib/constants"; export interface LockedBalance { amount: bigint; @@ -9,13 +10,10 @@ export default function useLockedBalanceOf({ chainId, address, account }: { chai return useContractRead({ address, chainId: Number(chainId), - abi: ["function locked(address) view returns ((uint256,uint256))"], + abi: VotingEscrowAbi, functionName: "locked", args: (!!account && [account]) || [], scopeKey: `lockedBalanceOf:${chainId}:${address}:${account}`, enabled: !!(chainId && address && account), - select: (data: any) => { return { amount: data[0], end: data[1] } }, - watch: true, - cacheTime: 2_000, }) } \ No newline at end of file diff --git a/lib/utils/addresses/index.ts b/lib/utils/addresses/index.ts index 18a5b4d..0256ae7 100644 --- a/lib/utils/addresses/index.ts +++ b/lib/utils/addresses/index.ts @@ -5,7 +5,7 @@ const VeAddresses = { WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", USDC: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", DAI: "0x6B175474E89094C44Da98b954EedeAC495271d0F", - BalancerPool: "0xd5A44704beFD1CfCCa67F7bc498a7654cC092959 ", + BalancerPool: "0xd5A44704beFD1CfCCa67F7bc498a7654cC092959", BalancerOracle: "0x0124a1697e207De725cd1e7b40aa9b0Ed37Ed5de", oPOP: "0xDfFA4D3ed6B433810354430464a5C00b6ea0F1dF", VaultRegistry: "0x007318Dc89B314b47609C684260CfbfbcD412864", diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 17d739b..be46552 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -43,7 +43,7 @@ const Vaults: NextPage = () => { const vaultTvl = useVaultTvl(); const [gaugeRewards, setGaugeRewards] = useState() - const { data: oBal } = useBalance({ chainId: 1, address: OPOP }) + const { data: oBal } = useBalance({ chainId: 1, address: account, token: OPOP }) const [searchString, handleSearch] = useState(""); diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 100eafb..daea83e 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -21,7 +21,7 @@ function VePopContainer() { const publicClient = usePublicClient(); const { data: walletClient } = useWalletClient() - const { data: veBal } = useBalance({ chainId: 1, address: VOTING_ESCROW }) + const { data: veBal } = useBalance({ chainId: 1, address: account, token: VOTING_ESCROW }) const [initalLoad, setInitalLoad] = useState(false); const [accountLoad, setAccountLoad] = useState(false); From 591fcdf9ea6af3029fe3526cd3add0648ee1ed33 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Mon, 23 Oct 2023 18:13:01 +0200 Subject: [PATCH 23/84] voting fixed --- components/vepop/Gauge.tsx | 2 +- lib/gauges/interactions.ts | 3 +- pages/vepop.tsx | 125 ++++++++++++++++++------------------- 3 files changed, 62 insertions(+), 68 deletions(-) diff --git a/components/vepop/Gauge.tsx b/components/vepop/Gauge.tsx index 026e009..72f806a 100644 --- a/components/vepop/Gauge.tsx +++ b/components/vepop/Gauge.tsx @@ -55,7 +55,7 @@ export default function Gauge({ vault, index, votes, handleVotes, canVote }: { v

My Votes

- {(Number(weights?.[2].power) / 1e10).toFixed() || 0} % + {(Number(weights?.[2].power) / 100).toFixed()} %

diff --git a/lib/gauges/interactions.ts b/lib/gauges/interactions.ts index 8a0cf4a..02316b3 100644 --- a/lib/gauges/interactions.ts +++ b/lib/gauges/interactions.ts @@ -59,11 +59,10 @@ export async function sendVotes({ vaults, votes, account, clients }: SendVotesPr for (let n = 0; n < 8; n++) { const l = i * 8; v[n] = votes[n + l] === undefined ? 0 : votes[n + l]; - addr[n] = vaults[n + l] === undefined || votes[n + l] === 0 ? zeroAddress : vaults[n + l].address; + addr[n] = vaults[n + l] === undefined || votes[n + l] === 0 ? zeroAddress : vaults[n + l].gauge?.address as Address; } - const { request, success, error: simulationError } = await simulateCall({ account, contract: { diff --git a/pages/vepop.tsx b/pages/vepop.tsx index daea83e..4675ced 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -56,79 +56,74 @@ function VePopContainer() { }, [account]) function handleVotes(val: number, index: number) { - setVotes((prevVotes) => { - const updatedVotes = [...prevVotes]; - const updatedTotalVotes = updatedVotes.reduce((a, b) => a + b, 0) - updatedVotes[index] + val; + const updatedVotes = [...votes]; + const updatedTotalVotes = updatedVotes.reduce((a, b) => a + b, 0) - updatedVotes[index] + val; - if (updatedTotalVotes <= 10000) { - // TODO should we adjust the val to the max possible value if it exceeds 10000? - updatedVotes[index] = val; - } + if (updatedTotalVotes <= 10000) { + // TODO should we adjust the val to the max possible value if it exceeds 10000? + updatedVotes[index] = val; + } - return prevVotes; - }); + setVotes((prevVotes) => updatedVotes); } return ( <> - {(!votes || votes.length === 0) ? <> - : <> - - -
-
-
-

- Lock 20WETH-80POP for vePOP, voting Power & oPOP -

-

- Vote with your vePOP below to influence how much $oPOP each pool will receive. Your vote will persist until you change it and editing a pool can only be done once every 10 days. -

-
-
- -
- - -
- -
- {vaults?.length > 0 ? vaults.map((vault: VaultData, index: number) => - - ) - :

Loading Gauges...

- } -
- -
-

Gauge Voting not available on mobile.

-
- -
- {canVote && <> -
-

- Voting power used: - { - veBal && veBal.value - ? (votes?.reduce((a, b) => a + b, 0) / 100).toFixed(2) - : "0" - }% - -

- -
- } + + +
+
+
+

+ Lock 20WETH-80POP for vePOP, voting Power & oPOP +

+

+ Vote with your vePOP below to influence how much $oPOP each pool will receive. Your vote will persist until you change it and editing a pool can only be done once every 10 days. +

+
+
+ +
+ + +
+ +
+ {vaults?.length > 0 ? vaults.map((vault: VaultData, index: number) => + + ) + :

Loading Gauges...

+ } +
+ +
+

Gauge Voting not available on mobile.

+
+ +
+ {canVote && <> +
+

+ Voting power used: + { + veBal && veBal.value + ? (votes?.reduce((a, b) => a + b, 0) / 100).toFixed(2) + : "0" + }% + +

+
+ } +
-
- } - +
+ ) } From 8d122b7364bab1c935a5151bc25fcc2e431c703f Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 24 Oct 2023 10:33:53 +0200 Subject: [PATCH 24/84] update balances by block --- components/vepop/StakingInterface.tsx | 6 +++--- components/vepop/modals/lock/LockPopInterface.tsx | 5 +++-- components/vepop/modals/manage/IncreaseStakeInterface.tsx | 3 ++- lib/gauges/useLockedBalanceOf.ts | 1 + pages/vepop.tsx | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/components/vepop/StakingInterface.tsx b/components/vepop/StakingInterface.tsx index ffc0b7d..e93a1bb 100644 --- a/components/vepop/StakingInterface.tsx +++ b/components/vepop/StakingInterface.tsx @@ -37,9 +37,9 @@ export default function StakingInterface({ setShowLockModal, setShowMangementMod const { address: account } = useAccount() const { data: lockedBal } = useLockedBalanceOf({ chainId: 1, address: VOTING_ESCROW, account: account as Address }) - const { data: veBal } = useBalance({ chainId: 1, address: account, token: VOTING_ESCROW }) - const { data: popLpBal } = useBalance({ chainId: 1, address: account, token: POP_LP }) - + const { data: veBal } = useBalance({ chainId: 1, address: account, token: VOTING_ESCROW, watch: true }) + const { data: popLpBal } = useBalance({ chainId: 1, address: account, token: POP_LP, watch: true }) + return ( <>
diff --git a/components/vepop/modals/lock/LockPopInterface.tsx b/components/vepop/modals/lock/LockPopInterface.tsx index 3778c0f..5a8c6ed 100644 --- a/components/vepop/modals/lock/LockPopInterface.tsx +++ b/components/vepop/modals/lock/LockPopInterface.tsx @@ -1,5 +1,5 @@ import { Dispatch, FormEventHandler, SetStateAction, useMemo } from "react"; -import { Address, useAccount, useBalance, useToken } from "wagmi"; +import { useAccount, useBalance, useToken } from "wagmi"; import { getVeAddresses } from "@/lib/utils/addresses"; import InputTokenWithError from "@/components/input/InputTokenWithError"; import InputNumber from "@/components/input/InputNumber"; @@ -7,6 +7,7 @@ import { calcUnlockTime, calculateVeOut } from "@/lib/gauges/utils"; import { ZERO } from "@/lib/constants"; import { safeRound } from "@/lib/utils/formatBigNumber"; import { validateInput } from "@/lib/utils/helpers"; +import { formatEther } from "viem"; const { BalancerPool: POP_LP } = getVeAddresses(); @@ -38,7 +39,7 @@ export default function LockPopInterface({ amountState, daysState }: LockPopInte return (amount || 0) > Number(popLpBal?.formatted) ? "* Balance not available" : ""; }, [amount, popLpBal?.formatted]); - const handleMaxClick = () => setAmount(Number(safeRound(popLpBal?.value || ZERO, 18))); + const handleMaxClick = () => setAmount(Number(formatEther(safeRound(popLpBal?.value || ZERO, 18)))); const handleChangeInput: FormEventHandler = ({ currentTarget: { value } }) => { setAmount(validateInput(value).isValid ? Number(value as any) : 0); diff --git a/components/vepop/modals/manage/IncreaseStakeInterface.tsx b/components/vepop/modals/manage/IncreaseStakeInterface.tsx index 77fe932..977afa8 100644 --- a/components/vepop/modals/manage/IncreaseStakeInterface.tsx +++ b/components/vepop/modals/manage/IncreaseStakeInterface.tsx @@ -6,6 +6,7 @@ import { ZERO } from "@/lib/constants"; import InputTokenWithError from "@/components/input/InputTokenWithError"; import { calcDaysToUnlock, calculateVeOut } from "@/lib/gauges/utils"; import { validateInput } from "@/lib/utils/helpers"; +import { formatEther } from "viem"; const { BalancerPool: POP_LP } = getVeAddresses(); @@ -25,7 +26,7 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }: Incre return (amount || 0) > Number(popLpBal?.formatted) ? "* Balance not available" : ""; }, [amount, popLpBal?.formatted]); - const handleMaxClick = () => setAmount(Number(safeRound(popLpBal?.value || ZERO, 18))); + const handleMaxClick = () => setAmount(Number(formatEther(safeRound(popLpBal?.value || ZERO, 18)))); const handleChangeInput: FormEventHandler = ({ currentTarget: { value } }) => { setAmount(validateInput(value).isValid ? Number(value as any) : 0); diff --git a/lib/gauges/useLockedBalanceOf.ts b/lib/gauges/useLockedBalanceOf.ts index 2875833..f8aaa50 100644 --- a/lib/gauges/useLockedBalanceOf.ts +++ b/lib/gauges/useLockedBalanceOf.ts @@ -15,5 +15,6 @@ export default function useLockedBalanceOf({ chainId, address, account }: { chai args: (!!account && [account]) || [], scopeKey: `lockedBalanceOf:${chainId}:${address}:${account}`, enabled: !!(chainId && address && account), + watch: true }) } \ No newline at end of file diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 4675ced..44ce5ec 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -21,7 +21,7 @@ function VePopContainer() { const publicClient = usePublicClient(); const { data: walletClient } = useWalletClient() - const { data: veBal } = useBalance({ chainId: 1, address: account, token: VOTING_ESCROW }) + const { data: veBal } = useBalance({ chainId: 1, address: account, token: VOTING_ESCROW, watch: true }) const [initalLoad, setInitalLoad] = useState(false); const [accountLoad, setAccountLoad] = useState(false); From 4e3f272c7e7bff7879f15081175276744b488a90 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 24 Oct 2023 12:37:05 +0200 Subject: [PATCH 25/84] fixed decimals inputs --- components/vault/VaultInputs.tsx | 31 +++++----- components/vepop/modals/lock/LockModal.tsx | 13 +++-- components/vepop/modals/lock/LockPopInfo.tsx | 2 +- .../vepop/modals/lock/LockPopInterface.tsx | 13 ++--- components/vepop/modals/lock/LockPreview.tsx | 7 ++- .../modals/manage/IncreaseStakeInterface.tsx | 15 +++-- .../modals/manage/IncreaseStakePreview.tsx | 9 +-- .../vepop/modals/manage/ManageLockModal.tsx | 11 ++-- .../modals/manage/SelectManagementOption.tsx | 2 +- components/vepop/modals/oPop/OptionInfo.tsx | 2 +- lib/vault/getVault.ts | 58 +++++++++---------- 11 files changed, 82 insertions(+), 81 deletions(-) diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index aefe5e2..8c7e6fa 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -9,6 +9,7 @@ import { handleAllowance } from "@/lib/approve"; import { WalletClient } from "viem"; import { vaultDeposit, vaultDepositAndStake, vaultRedeem, vaultUnstakeAndWithdraw } from "@/lib/vault/interactions"; import { ADDRESS_ZERO } from "@/lib/constants"; +import { validateInput } from "@/lib/utils/helpers"; const { VaultRouter: VAULT_ROUTER } = { VaultRouter: ADDRESS_ZERO as Address } @@ -30,7 +31,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId const [inputToken, setInputToken] = useState() const [outputToken, setOutputToken] = useState() - const [inputBalance, setInputBalance] = useState(0); + const [inputBalance, setInputBalance] = useState("0"); const [isDeposit, setIsDeposit] = useState(true); @@ -40,10 +41,11 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId setOutputToken(!!gauge ? gauge : vault) }, []) - function handleChangeInput(e: any) { - setInputBalance(Number(e.currentTarget.value)); - } + const value = e.currentTarget.value + setInputBalance(validateInput(value).isValid ? value : "0"); + }; + function switchTokens() { if (isDeposit) { @@ -61,7 +63,8 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId async function handleMainAction() { - if (inputBalance === 0) return; + const val = Number(inputBalance) + if (val === 0) return; if (chain?.id !== Number(chainId)) switchNetwork?.(Number(chainId)); @@ -72,7 +75,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId console.log("out vault") await handleAllowance({ token: inputToken, - inputAmount: (inputBalance * (10 ** inputToken?.decimals)), + inputAmount: (val * (10 ** inputToken?.decimals)), account: account as Address, spender: vault.address, publicClient, @@ -81,7 +84,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId vaultDeposit({ address: vault.address, account: account as Address, - amount: (inputBalance * (10 ** inputToken?.decimals)), + amount: (val * (10 ** inputToken?.decimals)), publicClient, walletClient: walletClient as WalletClient }) @@ -90,7 +93,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId console.log("out gauge") await handleAllowance({ token: inputToken, - inputAmount: (inputBalance * (10 ** inputToken?.decimals)), + inputAmount: (val * (10 ** inputToken?.decimals)), account: account as Address, spender: VAULT_ROUTER, publicClient, @@ -99,7 +102,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId vaultDepositAndStake({ address: VAULT_ROUTER, account: account as Address, - amount: (inputBalance * (10 ** inputToken?.decimals)), + amount: (val * (10 ** inputToken?.decimals)), vault: vault?.address as Address, gauge: gauge?.address as Address, publicClient, @@ -119,7 +122,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId vaultRedeem({ address: vault.address, account: account as Address, - amount: (inputBalance * (10 ** inputToken?.decimals)), + amount: (val * (10 ** inputToken?.decimals)), publicClient, walletClient: walletClient as WalletClient }) @@ -128,7 +131,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId console.log("out gauge") await handleAllowance({ token: vault, - inputAmount: (inputBalance * (10 ** vault?.decimals)), + inputAmount: (val * (10 ** vault?.decimals)), account: account as Address, spender: gauge?.address as Address, publicClient, @@ -148,7 +151,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId console.log("out asset") await handleAllowance({ token: inputToken, - inputAmount: (inputBalance * (10 ** vault?.decimals)), + inputAmount: (val * (10 ** vault?.decimals)), account: account as Address, spender: VAULT_ROUTER, publicClient, @@ -157,7 +160,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId vaultUnstakeAndWithdraw({ address: VAULT_ROUTER, account: account as Address, - amount: (inputBalance * (10 ** inputToken?.decimals)), + amount: (val * (10 ** inputToken?.decimals)), vault: vault?.address as Address, gauge: gauge?.address as Address, publicClient, @@ -217,7 +220,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId onSelectToken={option => setOutputToken(option)} onMaxClick={() => { }} chainId={chainId} - value={(inputBalance * (Number(inputToken?.price)) / Number(outputToken?.price)) || 0} + value={(Number(inputBalance) * (Number(inputToken?.price)) / Number(outputToken?.price)) || 0} onChange={() => { }} selectedToken={outputToken} errorMessage={""} diff --git a/components/vepop/modals/lock/LockModal.tsx b/components/vepop/modals/lock/LockModal.tsx index 0cb9887..29e30fe 100644 --- a/components/vepop/modals/lock/LockModal.tsx +++ b/components/vepop/modals/lock/LockModal.tsx @@ -18,8 +18,6 @@ const { VotingEscrow: VOTING_ESCROW } = getVeAddresses() -function noOp() { } - export default function LockModal({ show }: { show: [boolean, Dispatch>] }): JSX.Element { const { address: account } = useAccount(); const { chain } = useNetwork(); @@ -31,7 +29,7 @@ export default function LockModal({ show }: { show: [boolean, Dispatch(0); + const [amount, setAmount] = useState("0"); const [days, setDays] = useState(7); useEffect(() => { @@ -41,21 +39,24 @@ export default function LockModal({ show }: { show: [boolean, Dispatch - +
diff --git a/components/vepop/modals/lock/LockPopInterface.tsx b/components/vepop/modals/lock/LockPopInterface.tsx index 5a8c6ed..944c5a9 100644 --- a/components/vepop/modals/lock/LockPopInterface.tsx +++ b/components/vepop/modals/lock/LockPopInterface.tsx @@ -23,7 +23,7 @@ function LockTimeButton({ label, isActive, handleClick }: { label: string, isAct } interface LockPopInterfaceProps { - amountState: [number, Dispatch>]; + amountState: [string, Dispatch>]; daysState: [number, Dispatch>]; } @@ -36,13 +36,13 @@ export default function LockPopInterface({ amountState, daysState }: LockPopInte const [days, setDays] = daysState const errorMessage = useMemo(() => { - return (amount || 0) > Number(popLpBal?.formatted) ? "* Balance not available" : ""; + return (Number(amount) || 0) > Number(popLpBal?.formatted) ? "* Balance not available" : ""; }, [amount, popLpBal?.formatted]); - const handleMaxClick = () => setAmount(Number(formatEther(safeRound(popLpBal?.value || ZERO, 18)))); + const handleMaxClick = () => setAmount(formatEther(safeRound(popLpBal?.value || ZERO, 18))); const handleChangeInput: FormEventHandler = ({ currentTarget: { value } }) => { - setAmount(validateInput(value).isValid ? Number(value as any) : 0); + setAmount(validateInput(value).isValid ? value : "0"); }; const handleSetDays: FormEventHandler = ({ currentTarget: { value } }) => { @@ -61,9 +61,8 @@ export default function LockPopInterface({ amountState, daysState }: LockPopInte onSelectToken={() => { }} onMaxClick={handleMaxClick} chainId={1} - value={amount} + value={String(amount)} onChange={handleChangeInput} - defaultValue={amount} selectedToken={ { ...popLp, @@ -112,7 +111,7 @@ export default function LockPopInterface({ amountState, daysState }: LockPopInte

Voting Power

-

{amount > 0 ? calculateVeOut(amount, days).toFixed(2) : "Enter the amount to view your voting power"}

+

{Number(amount) > 0 ? calculateVeOut(Number(amount), days).toFixed(2) : "Enter the amount to view your voting power"}

diff --git a/components/vepop/modals/lock/LockPreview.tsx b/components/vepop/modals/lock/LockPreview.tsx index f1c9a62..b111a65 100644 --- a/components/vepop/modals/lock/LockPreview.tsx +++ b/components/vepop/modals/lock/LockPreview.tsx @@ -1,6 +1,7 @@ import { calcUnlockTime, calculateVeOut } from "@/lib/gauges/utils"; -export default function LockPreview({ amount, days }: { amount: number, days: number }): JSX.Element { +export default function LockPreview({ amount, days }: { amount: string, days: number }): JSX.Element { + const val = Number(amount); return (
@@ -9,7 +10,7 @@ export default function LockPreview({ amount, days }: { amount: number, days: nu

Lock Amount

-

{amount > 0 ? amount.toFixed(2) : "0"} POP

+

{val > 0 ? val.toFixed(2) : "0"} POP

Unlock Date

@@ -17,7 +18,7 @@ export default function LockPreview({ amount, days }: { amount: number, days: nu

Initial Voting Power

-

{amount > 0 ? calculateVeOut(amount, days).toFixed(2) : "0"}

+

{val > 0 ? calculateVeOut(val, days).toFixed(2) : "0"}

diff --git a/components/vepop/modals/manage/IncreaseStakeInterface.tsx b/components/vepop/modals/manage/IncreaseStakeInterface.tsx index 977afa8..d211837 100644 --- a/components/vepop/modals/manage/IncreaseStakeInterface.tsx +++ b/components/vepop/modals/manage/IncreaseStakeInterface.tsx @@ -11,7 +11,7 @@ import { formatEther } from "viem"; const { BalancerPool: POP_LP } = getVeAddresses(); interface IncreaseStakeInterfaceProps { - amountState: [number, Dispatch>]; + amountState: [string, Dispatch>]; lockedBal: { amount: bigint, end: bigint } } @@ -23,13 +23,13 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }: Incre const [amount, setAmount] = amountState const errorMessage = useMemo(() => { - return (amount || 0) > Number(popLpBal?.formatted) ? "* Balance not available" : ""; + return (Number(amount) || 0) > Number(popLpBal?.formatted) ? "* Balance not available" : ""; }, [amount, popLpBal?.formatted]); - const handleMaxClick = () => setAmount(Number(formatEther(safeRound(popLpBal?.value || ZERO, 18)))); + const handleMaxClick = () => setAmount(formatEther(safeRound(popLpBal?.value || ZERO, 18))); const handleChangeInput: FormEventHandler = ({ currentTarget: { value } }) => { - setAmount(validateInput(value).isValid ? Number(value as any) : 0); + setAmount(validateInput(value).isValid ? value : "0"); }; return ( @@ -44,9 +44,8 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }: Incre onSelectToken={() => { }} onMaxClick={handleMaxClick} chainId={1} - value={amount} + value={String(amount)} onChange={handleChangeInput} - defaultValue={amount} selectedToken={ { ...popLp, @@ -75,8 +74,8 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }: Incre

New Voting Power

- {amount > 0 ? - calculateVeOut(amount + (Number(lockedBal?.amount) / 1e18), calcDaysToUnlock(Number(lockedBal?.end))).toFixed(2) + {Number(amount) > 0 ? + calculateVeOut(Number(amount) + (Number(lockedBal?.amount) / 1e18), calcDaysToUnlock(Number(lockedBal?.end))).toFixed(2) : "Enter the amount to view your voting power"}

diff --git a/components/vepop/modals/manage/IncreaseStakePreview.tsx b/components/vepop/modals/manage/IncreaseStakePreview.tsx index 22f7a16..4db5261 100644 --- a/components/vepop/modals/manage/IncreaseStakePreview.tsx +++ b/components/vepop/modals/manage/IncreaseStakePreview.tsx @@ -1,7 +1,8 @@ import { calcDaysToUnlock, calculateVeOut } from "@/lib/gauges/utils" -export default function IncreaseStakePreview({ amount, lockedBal }: { amount: number, lockedBal: { amount: bigint, end: bigint } }): JSX.Element { - const totalLocked = (Number(lockedBal?.amount) / 1e18) + amount +export default function IncreaseStakePreview({ amount, lockedBal }: { amount: string, lockedBal: { amount: bigint, end: bigint } }): JSX.Element { + const val = Number(amount); + const totalLocked = (Number(lockedBal?.amount) / 1e18) + val return (
@@ -11,7 +12,7 @@ export default function IncreaseStakePreview({ amount, lockedBal }: { amount: nu

Lock Amount

-

{amount > 0 ? amount.toFixed(2) : "0"} POP LP

+

{val > 0 ? val.toFixed(2) : "0"} POP LP

Total Locked

@@ -23,7 +24,7 @@ export default function IncreaseStakePreview({ amount, lockedBal }: { amount: nu

New Voting Power

-

{amount > 0 ? calculateVeOut((Number(lockedBal?.amount) / 1e18) + amount, calcDaysToUnlock(Number(lockedBal?.end))).toFixed(2) : "0"} vePOP

+

{val > 0 ? calculateVeOut((Number(lockedBal?.amount) / 1e18) + val, calcDaysToUnlock(Number(lockedBal?.end))).toFixed(2) : "0"} vePOP

diff --git a/components/vepop/modals/manage/ManageLockModal.tsx b/components/vepop/modals/manage/ManageLockModal.tsx index 15deefb..0d712a6 100644 --- a/components/vepop/modals/manage/ManageLockModal.tsx +++ b/components/vepop/modals/manage/ManageLockModal.tsx @@ -40,10 +40,10 @@ export default function ManageLockModal({ show }: { show: [boolean, Dispatch(0); + const [amount, setAmount] = useState("0"); const [days, setDays] = useState(7); const isIncreaseLockValid = ((Number(lockedBal?.end) - Math.floor(Date.now() / 1000)) / (604800)) < 207 @@ -59,20 +59,21 @@ export default function ManageLockModal({ show }: { show: [boolean, Dispatch - +
diff --git a/components/vepop/modals/oPop/OptionInfo.tsx b/components/vepop/modals/oPop/OptionInfo.tsx index 0d195e8..126a09d 100644 --- a/components/vepop/modals/oPop/OptionInfo.tsx +++ b/components/vepop/modals/oPop/OptionInfo.tsx @@ -3,7 +3,7 @@ export default function OptionInfo(): JSX.Element {
- +
diff --git a/lib/vault/getVault.ts b/lib/vault/getVault.ts index 20a0b47..18ad2ca 100644 --- a/lib/vault/getVault.ts +++ b/lib/vault/getVault.ts @@ -1,4 +1,4 @@ -import { Address, Chain, ChainDisconnectedError, ReadContractParameters, createPublicClient, getAddress, http } from "viem" +import { Address, Chain, ReadContractParameters, createPublicClient, getAddress, http } from "viem" import { PublicClient } from "wagmi" import axios from "axios" import { VaultAbi } from "@/lib/constants/abi/Vault" @@ -11,9 +11,7 @@ import getAssetIcon from "@/lib/vault/getAssetIcon" import getVaultName from "@/lib/vault/getVaultName" import getOptionalMetadata from "@/lib/vault/getOptionalMetadata" import { getVeAddresses } from "../utils/addresses" -import getGauges from "@/lib/gauges/getGauges" -import type { Gauge } from "@/lib/gauges/getGauges" - +import getGauges, { Gauge } from "../gauges/getGauges" function prepareVaultContract(vault: Address, account: Address): ReadContractParameters[] { const vaultContract = { @@ -219,32 +217,30 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va tvl: (entry.totalSupply * pricePerShare) / (10 ** entry.asset.decimals) } }) - - - // Add gauges - if (client.chain.id === 1) { - const { - GaugeController: GAUGE_CONTROLLER, - } = getVeAddresses(); - const gauges = await getGauges({ address: GAUGE_CONTROLLER, publicClient: client }) - metadata = metadata.map((entry, i) => { - const foundGauge = gauges.find((gauge: Gauge) => gauge.lpToken === entry.address) - const gauge = foundGauge ? { - address: foundGauge.address, - name: `${entry.vault.name}-gauge`, - symbol: `st-${entry.vault.name}`, - decimals: foundGauge.decimals, - logoURI: "", // wont be used, just here for consistency - balance: foundGauge.balance, - price: entry.pricePerShare, - } : undefined - - return { - ...entry, - gauge - } - }) - } + // Add gauges + if (client.chain.id === 1) { + const { + GaugeController: GAUGE_CONTROLLER, + } = getVeAddresses(); + const gauges = await getGauges({ address: GAUGE_CONTROLLER, publicClient: client }) + metadata = metadata.map((entry, i) => { + const foundGauge = gauges.find((gauge: Gauge) => gauge.lpToken === entry.address) + const gauge = foundGauge ? { + address: foundGauge.address, + name: `${entry.vault.name}-gauge`, + symbol: `st-${entry.vault.name}`, + decimals: foundGauge.decimals, + logoURI: "", // wont be used, just here for consistency + balance: foundGauge.balance, + price: entry.pricePerShare, + } : undefined + + return { + ...entry, + gauge + } + }) + } return metadata as unknown as VaultData[] } @@ -322,7 +318,7 @@ export async function getVault({ vault, account = ADDRESS_ZERO, client }: { vaul }, chainId: client.chain.id } - + // Add gauges if (client.chain.id === 1) { const { From dcd1e0371f0fdc8cae6bc5376e2aa006c5e74a0c Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 24 Oct 2023 17:39:27 +0200 Subject: [PATCH 26/84] added custom time --- .../vepop/modals/manage/IncreaseTimeInteface.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/vepop/modals/manage/IncreaseTimeInteface.tsx b/components/vepop/modals/manage/IncreaseTimeInteface.tsx index 4772c4d..4f02404 100644 --- a/components/vepop/modals/manage/IncreaseTimeInteface.tsx +++ b/components/vepop/modals/manage/IncreaseTimeInteface.tsx @@ -30,18 +30,22 @@ export default function IncreaseTimeInterface({ daysState, lockedBal }:

Increase lock time

-

Lockup Time

-
+
+

Lockup Time

+

Custom Time

+
+
setDays(7)} /> setDays(30)} /> setDays(90)} /> setDays(180)} /> setDays(365)} /> setDays(730)} /> -
+ setDays(1460)} /> +
Date: Tue, 24 Oct 2023 17:41:28 +0200 Subject: [PATCH 27/84] custom time for lock --- components/vepop/modals/lock/LockPopInterface.tsx | 11 +++++++---- ...easeTimeInteface.tsx => IncreaseTimeInterface.tsx} | 0 components/vepop/modals/manage/ManageLockModal.tsx | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) rename components/vepop/modals/manage/{IncreaseTimeInteface.tsx => IncreaseTimeInterface.tsx} (100%) diff --git a/components/vepop/modals/lock/LockPopInterface.tsx b/components/vepop/modals/lock/LockPopInterface.tsx index 944c5a9..ec736a7 100644 --- a/components/vepop/modals/lock/LockPopInterface.tsx +++ b/components/vepop/modals/lock/LockPopInterface.tsx @@ -77,8 +77,11 @@ export default function LockPopInterface({ amountState, daysState }: LockPopInte
-

Lockup Time

-
+
+

Lockup Time

+

Custom Time

+
+
setDays(7)} /> setDays(30)} /> setDays(90)} /> @@ -86,10 +89,10 @@ export default function LockPopInterface({ amountState, daysState }: LockPopInte setDays(365)} /> setDays(730)} /> setDays(1460)} /> -
+
Date: Wed, 25 Oct 2023 10:05:48 +0200 Subject: [PATCH 28/84] removed ve rewards --- pages/vepop.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 44ce5ec..c775952 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -85,7 +85,7 @@ function VePopContainer() {
- + {/* */}
From 0466e104369bffd8b2b0152ed79ce672615c9ae0 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 25 Oct 2023 12:24:43 +0200 Subject: [PATCH 29/84] vepop works still on other networks --- lib/gauges/utils.ts | 5 ----- pages/vepop.tsx | 3 ++- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/gauges/utils.ts b/lib/gauges/utils.ts index 4684aa0..d47ad4e 100644 --- a/lib/gauges/utils.ts +++ b/lib/gauges/utils.ts @@ -1,9 +1,4 @@ -import { useContractWrite, usePrepareContractWrite } from "wagmi"; import { nextThursday } from "date-fns" -import { useState, useEffect } from "react"; -import { parseEther } from "viem"; -import { ChainId } from "@/lib/utils/connectors"; -import { showSuccessToast, showErrorToast } from "@/lib/toasts"; export function calcUnlockTime(days: number, start = Date.now()): number { const week = 86400 * 7; diff --git a/pages/vepop.tsx b/pages/vepop.tsx index c775952..2efdc8c 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -40,7 +40,7 @@ function VePopContainer() { const allVaults = await getVaultsByChain({ chain: mainnet, account }) const vaultsWithGauges = allVaults.filter(vault => !!vault.gauge) setVaults(vaultsWithGauges); - if (vaultsWithGauges.length > 0 && votes.length === 0) { + if (vaultsWithGauges.length > 0 && votes.length === 0 && publicClient.chain.id === 1) { setVotes(vaultsWithGauges.map(gauge => 0)); const hasVoted = await hasAlreadyVoted({ @@ -85,6 +85,7 @@ function VePopContainer() {
+ {/* */}
From 4f31342b650ca656dc86f45af9071942244eb524 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 26 Oct 2023 17:55:57 +0200 Subject: [PATCH 30/84] vault oPop adjustments --- components/vault/SmartVault.tsx | 2 +- components/vault/VaultInputs.tsx | 4 +-- lib/vault/getVault.ts | 50 ++++++++++++++++---------------- pages/vaults.tsx | 6 ++-- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/components/vault/SmartVault.tsx b/components/vault/SmartVault.tsx index 33b3f47..1dbc3f6 100644 --- a/components/vault/SmartVault.tsx +++ b/components/vault/SmartVault.tsx @@ -86,7 +86,7 @@ export default function SmartVault({
{account ? (!!gauge ? - formatAndRoundNumber(gauge?.balance || 0, vault.decimals) : + formatAndRoundNumber(gauge?.balance || 0, gauge.decimals) : formatAndRoundNumber(vault.balance, vault.decimals) ) : "-"} diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index 8c7e6fa..f1cbc47 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -8,10 +8,10 @@ import { Token } from "@/lib/types"; import { handleAllowance } from "@/lib/approve"; import { WalletClient } from "viem"; import { vaultDeposit, vaultDepositAndStake, vaultRedeem, vaultUnstakeAndWithdraw } from "@/lib/vault/interactions"; -import { ADDRESS_ZERO } from "@/lib/constants"; import { validateInput } from "@/lib/utils/helpers"; +import { getVeAddresses } from "@/lib/utils/addresses"; -const { VaultRouter: VAULT_ROUTER } = { VaultRouter: ADDRESS_ZERO as Address } +const { VaultRouter: VAULT_ROUTER } = getVeAddresses() interface VaultInputsProps { vault: Token; diff --git a/lib/vault/getVault.ts b/lib/vault/getVault.ts index 18ad2ca..5583b92 100644 --- a/lib/vault/getVault.ts +++ b/lib/vault/getVault.ts @@ -217,30 +217,30 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va tvl: (entry.totalSupply * pricePerShare) / (10 ** entry.asset.decimals) } }) - // Add gauges - if (client.chain.id === 1) { - const { - GaugeController: GAUGE_CONTROLLER, - } = getVeAddresses(); - const gauges = await getGauges({ address: GAUGE_CONTROLLER, publicClient: client }) - metadata = metadata.map((entry, i) => { - const foundGauge = gauges.find((gauge: Gauge) => gauge.lpToken === entry.address) - const gauge = foundGauge ? { - address: foundGauge.address, - name: `${entry.vault.name}-gauge`, - symbol: `st-${entry.vault.name}`, - decimals: foundGauge.decimals, - logoURI: "", // wont be used, just here for consistency - balance: foundGauge.balance, - price: entry.pricePerShare, - } : undefined - - return { - ...entry, - gauge - } - }) - } + // Add gauges + if (client.chain.id === 1) { + const { + GaugeController: GAUGE_CONTROLLER, + } = getVeAddresses(); + const gauges = await getGauges({ address: GAUGE_CONTROLLER, account: account, publicClient: client }) + metadata = metadata.map((entry, i) => { + const foundGauge = gauges.find((gauge: Gauge) => gauge.lpToken === entry.address) + const gauge = foundGauge ? { + address: foundGauge.address, + name: `${entry.vault.name}-gauge`, + symbol: `st-${entry.vault.name}`, + decimals: foundGauge.decimals, + logoURI: "", // wont be used, just here for consistency + balance: foundGauge.balance, + price: entry.pricePerShare, + } : undefined + + return { + ...entry, + gauge + } + }) + } return metadata as unknown as VaultData[] } @@ -318,7 +318,7 @@ export async function getVault({ vault, account = ADDRESS_ZERO, client }: { vaul }, chainId: client.chain.id } - + // Add gauges if (client.chain.id === 1) { const { diff --git a/pages/vaults.tsx b/pages/vaults.tsx index be46552..efbc85c 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -43,7 +43,7 @@ const Vaults: NextPage = () => { const vaultTvl = useVaultTvl(); const [gaugeRewards, setGaugeRewards] = useState() - const { data: oBal } = useBalance({ chainId: 1, address: account, token: OPOP }) + const { data: oBal } = useBalance({ chainId: 1, address: account, token: OPOP, watch: true }) const [searchString, handleSearch] = useState(""); @@ -113,14 +113,14 @@ const Vaults: NextPage = () => {

My oPOP

- {`${oBal ? NumberFormatter.format(Number(oBal?.value)) : "0"}`} + {`${oBal ? NumberFormatter.format(Number(oBal?.value) / 1e18) : "0"}`}

Claimable oPOP

- {`$${gaugeRewards ? NumberFormatter.format(Number(gaugeRewards?.total)) : "0"}`} + {`$${gaugeRewards ? NumberFormatter.format(Number(gaugeRewards?.total) / 1e18) : "0"}`}
From 71533b3abeafdf715b59c2681fa8c417f6a2d751 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 27 Oct 2023 17:17:13 +0200 Subject: [PATCH 31/84] OPOP interface --- components/vepop/OPopInterface.tsx | 84 +++++++++++++++++++ .../modals/oPop/ExerciseOPopInterface.tsx | 46 +++++----- components/vepop/modals/oPop/OPopModal.tsx | 14 ++-- lib/gauges/hasAlreadyVoted.ts | 4 +- lib/oPop/interactions.ts | 2 +- lib/vault/getVault.ts | 5 +- pages/vaults.tsx | 15 ++-- pages/vepop.tsx | 12 +-- public/images/tokens/oPop.svg | 8 ++ 9 files changed, 144 insertions(+), 46 deletions(-) create mode 100644 components/vepop/OPopInterface.tsx create mode 100644 public/images/tokens/oPop.svg diff --git a/components/vepop/OPopInterface.tsx b/components/vepop/OPopInterface.tsx new file mode 100644 index 0000000..26f8ed7 --- /dev/null +++ b/components/vepop/OPopInterface.tsx @@ -0,0 +1,84 @@ +import getGaugeRewards, { GaugeRewards } from "@/lib/gauges/getGaugeRewards" +import getGauges from "@/lib/gauges/getGauges"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { NumberFormatter } from "@/lib/utils/formatBigNumber"; +import { Dispatch, SetStateAction, useEffect, useState } from "react" +import { Address, useAccount, useBalance, usePublicClient, useWalletClient } from "wagmi" +import MainActionButton from "../button/MainActionButton"; +import SecondaryActionButton from "../button/SecondaryActionButton"; +import { claimOPop } from "@/lib/oPop/interactions"; +import { WalletClient } from "viem"; + +const { + GaugeController: GAUGE_CONTROLLER, + oPOP: OPOP, + POP, + WETH +} = getVeAddresses(); + +interface OPopInterfaceProps { + setShowOPopModal: Dispatch>; +} + +export default function OPopInterface({ setShowOPopModal }: OPopInterfaceProps): JSX.Element { + const { address: account } = useAccount() + const publicClient = usePublicClient(); + const { data: walletClient } = useWalletClient() + + const [gaugeRewards, setGaugeRewards] = useState() + const { data: popBal } = useBalance({ chainId: 1, address: account, token: POP, watch: true }) + const { data: oBal } = useBalance({ chainId: 1, address: account, token: OPOP, watch: true }) + const { data: wethBal } = useBalance({ chainId: 1, address: account, token: WETH, watch: true }) + + const [initalLoad, setInitalLoad] = useState(false); + + useEffect(() => { + async function getValues() { + setInitalLoad(true) + const gauges = await getGauges({ address: GAUGE_CONTROLLER, account: account, publicClient }) + + const rewards = await getGaugeRewards({ + gauges: gauges.filter(gauge => gauge.chainId === 1).map(gauge => gauge.address) as Address[], + account: account as Address, + publicClient + }) + setGaugeRewards(rewards) + } + if (account && !initalLoad) getValues() + }, [account]) + + return ( +
+

oPOP

+ +

Claimable oPOP

+

{`${gaugeRewards ? NumberFormatter.format(Number(gaugeRewards?.total) / 1e18) : "0"}`}

+
+ +

My POP

+

{`${popBal ? NumberFormatter.format(Number(popBal?.value) / 1e18) : "0"}`}

+
+ +

My oPOP

+

{`${oBal ? NumberFormatter.format(Number(oBal?.value) / 1e18) : "0"}`}

+
+ +

My WETH

+

{`${oBal ? NumberFormatter.format(Number(wethBal?.value) / 1e18) : "0"}`}

+
+
+ + claimOPop({ + gauges: gaugeRewards?.amounts?.filter(gauge => Number(gauge.amount) > 0).map(gauge => gauge.address) as Address[], + account: account as Address, + clients: { publicClient, walletClient: walletClient as WalletClient } + })} + disabled={gaugeRewards ? Number(gaugeRewards?.total) === 0 : true} + /> + setShowOPopModal(true)} disabled={oBal ? Number(oBal?.value) === 0 : true} /> +
+
+ ) +} \ No newline at end of file diff --git a/components/vepop/modals/oPop/ExerciseOPopInterface.tsx b/components/vepop/modals/oPop/ExerciseOPopInterface.tsx index 953064d..fe92af6 100644 --- a/components/vepop/modals/oPop/ExerciseOPopInterface.tsx +++ b/components/vepop/modals/oPop/ExerciseOPopInterface.tsx @@ -10,6 +10,7 @@ import { validateInput } from "@/lib/utils/helpers"; import { Token } from "@/lib/types"; import { llama } from "@/lib/resolver/price/resolver"; import { useEthToUsd } from "@/lib/oPop/ethToUsd"; +import { formatEther } from "viem"; const { POP: POP, @@ -18,9 +19,11 @@ const { WETH: WETH } = getVeAddresses(); +const SLIPPAGE = 0.01 // @dev adding some slippage to the call -- TODO -> we should later allow users to change that + interface ExerciseOPopInterfaceProps { - amountState: [number, Dispatch>]; - maxPaymentAmountState: [number, Dispatch>]; + amountState: [string, Dispatch>]; + maxPaymentAmountState: [string, Dispatch>]; } export default function ExerciseOPopInterface({ amountState, maxPaymentAmountState }: ExerciseOPopInterfaceProps): JSX.Element { @@ -31,14 +34,13 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta const [maxPaymentAmount, setMaxPaymentAmount] = maxPaymentAmountState; const { data: oPopBal } = useBalance({ chainId: 1, address: account, token: OPOP }) - const { data: ethBal } = useBalance({ chainId: 1, address: account }) const { data: wethBal } = useBalance({ chainId: 1, address: account, token: WETH }) const { data: oPop } = useToken({ chainId: 1, address: OPOP }); const { data: pop } = useToken({ chainId: 1, address: POP }); const { data: weth } = useToken({ chainId: 1, address: WETH }); - const [oPopPrice, setOPopPrice] = useState(ZERO); + const [oPopPrice, setOPopPrice] = useState(ZERO); // oPOP price in ETH (needs to be multiplied with the eth price to arrive at USD prices) const [oPopDiscount, setOPopDiscount] = useState(0); const [popPrice, setPopPrice] = useState(0); const [wethPrice, setWethPrice] = useState(0); @@ -66,41 +68,41 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta }, [initialLoad]) function handleMaxWeth() { - const maxEth = Number(safeRound(ethBal?.value || ZERO, 18)); + const maxEth = formatEther(safeRound(wethBal?.value || ZERO, 18)); setMaxPaymentAmount(maxEth); - setAmount(getOPopAmount(maxEth)) + setAmount(getOPopAmount(Number(maxEth))) }; function handleMaxOPop() { - const maxOPop = Number(safeRound(oPopBal?.value || ZERO, 18)); + const maxOPop = formatEther(safeRound(oPopBal?.value || ZERO, 18)); - setMaxPaymentAmount(getPaymentAmount(maxOPop)); + setMaxPaymentAmount(getMaxPaymentAmount(Number(maxOPop))); setAmount(maxOPop) }; - function getPaymentAmount(oPopAmount: number) { - const oPopValue = oPopAmount * (Number(oPopPrice) / 1e18); + function getMaxPaymentAmount(oPopAmount: number) { + const oPopValue = oPopAmount * ((Number(oPopPrice) / 1e18) * wethPrice); - return oPopValue / wethPrice; + return String((oPopValue / wethPrice) * (1 + SLIPPAGE)); } function getOPopAmount(paymentAmount: number) { const ethValue = paymentAmount * wethPrice; - return ethValue / (Number(oPopPrice) / 1e18); + return String(ethValue / (((Number(oPopPrice) / 1e18) * wethPrice) * (1 - SLIPPAGE))); } const handleOPopInput: FormEventHandler = ({ currentTarget: { value } }) => { - const amount = validateInput(value).isValid ? Number(value as any) : 0 + const amount = validateInput(value).isValid ? value : "0" setAmount(amount); - setMaxPaymentAmount(getPaymentAmount(amount)); + setMaxPaymentAmount(getMaxPaymentAmount(Number(amount))); }; const handleEthInput: FormEventHandler = ({ currentTarget: { value } }) => { - const amount = validateInput(value).isValid ? Number(value as any) : 0 + const amount = validateInput(value).isValid ? value : "0" setMaxPaymentAmount(amount); - setAmount(getOPopAmount(amount)); + setAmount(getOPopAmount(Number(amount))); }; return ( @@ -122,11 +124,11 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta selectedToken={ { ...oPop, - icon: "/images/icons/oPOP.svg", + logoURI: "/images/tokens/oPop.svg", balance: oPopBal?.value || ZERO, } as any } - errorMessage={amount > (Number(oPopBal?.value) / 1e18) ? "Insufficient Balance" : ""} + errorMessage={Number(amount) > (Number(oPopBal?.value) / 1e18) ? "Insufficient Balance" : ""} tokenList={[]} />
@@ -138,19 +140,19 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta onSelectToken={() => { }} onMaxClick={handleMaxWeth} chainId={1} - value={maxPaymentAmount * 1e3} // temp Goerli value + value={maxPaymentAmount} onChange={handleEthInput} allowInput={true} selectedToken={ { ...weth, decimals: 18, - icon: "https://etherscan.io/token/images/weth_28.png", + logoURI: "https://etherscan.io/token/images/weth_28.png", balance: wethBal?.value || ZERO, } as any } tokenList={[]} - errorMessage={(maxPaymentAmount * 1e3) > (Number(wethBal?.value) / 1e18) ? "Insufficient Balance" : ""} + errorMessage={Number(maxPaymentAmount) > (Number(wethBal?.value) / 1e18) ? "Insufficient Balance" : ""} />
@@ -181,7 +183,7 @@ export default function ExerciseOPopInterface({ amountState, maxPaymentAmountSta className={`flex flex-row items-center justify-end`} >
- +

{pop?.symbol} diff --git a/components/vepop/modals/oPop/OPopModal.tsx b/components/vepop/modals/oPop/OPopModal.tsx index 1c7c78b..cd43a95 100644 --- a/components/vepop/modals/oPop/OPopModal.tsx +++ b/components/vepop/modals/oPop/OPopModal.tsx @@ -23,26 +23,26 @@ export default function OPopModal({ show }: { show: [boolean, Dispatch(0); - const [maxPaymentAmount, setMaxPaymentAmount] = useState(0); + const [amount, setAmount] = useState("0"); + const [maxPaymentAmount, setMaxPaymentAmount] = useState("0"); useEffect(() => { if (!showModal) setStep(0) - setAmount(0); - setMaxPaymentAmount(0); + setAmount("0"); + setMaxPaymentAmount("0"); }, [showModal] ) async function handleExerciseOPop() { - if ((amount || 0) == 0) return; + if ((Number(amount) || 0) == 0) return; // Early exit if value is ZERO if (chain?.id as number !== Number(1)) switchNetwork?.(Number(1)); await handleAllowance({ token: { address: WETH } as Token, - inputAmount: (amount * (10 ** 18) || 0), + inputAmount: (Number(amount) * (10 ** 18) || 0), account: account as Address, spender: OPOP, publicClient, @@ -52,7 +52,7 @@ export default function OPopModal({ show }: { show: [boolean, Dispatch { +export async function hasAlreadyVoted({ addresses, publicClient, account = zeroAddress }: { addresses: Address[], publicClient: PublicClient, account?: Address }): Promise { const data = await publicClient.multicall({ contracts: addresses.map((address) => { return { diff --git a/lib/oPop/interactions.ts b/lib/oPop/interactions.ts index f825ed2..6c8ba0f 100644 --- a/lib/oPop/interactions.ts +++ b/lib/oPop/interactions.ts @@ -56,7 +56,7 @@ export async function exerciseOPop({ amount, maxPaymentAmount, account, clients }, functionName: "exercise", publicClient: clients.publicClient, - args: [amount, maxPaymentAmount] + args: [amount, maxPaymentAmount, account] }) if (success) { diff --git a/lib/vault/getVault.ts b/lib/vault/getVault.ts index 5583b92..046ecb0 100644 --- a/lib/vault/getVault.ts +++ b/lib/vault/getVault.ts @@ -13,6 +13,8 @@ import getOptionalMetadata from "@/lib/vault/getOptionalMetadata" import { getVeAddresses } from "../utils/addresses" import getGauges, { Gauge } from "../gauges/getGauges" +const { GaugeController: GAUGE_CONTROLLER } = getVeAddresses(); + function prepareVaultContract(vault: Address, account: Address): ReadContractParameters[] { const vaultContract = { address: vault, @@ -219,9 +221,6 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va }) // Add gauges if (client.chain.id === 1) { - const { - GaugeController: GAUGE_CONTROLLER, - } = getVeAddresses(); const gauges = await getGauges({ address: GAUGE_CONTROLLER, account: account, publicClient: client }) metadata = metadata.map((entry, i) => { const foundGauge = gauges.find((gauge: Gauge) => gauge.lpToken === entry.address) diff --git a/pages/vaults.tsx b/pages/vaults.tsx index efbc85c..90bddf8 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -54,12 +54,15 @@ const Vaults: NextPage = () => { const fetchedVaults = (await Promise.all( SUPPORTED_NETWORKS.map(async (chain) => getVaultsByChain({ chain, account })) )).flat(); - const rewards = await getGaugeRewards({ - gauges: fetchedVaults.filter(vault => vault.gauge && vault.chainId === 1).map(vault => vault.gauge?.address) as Address[], - account: account as Address, - publicClient - }) - setGaugeRewards(rewards) + + if (account) { + const rewards = await getGaugeRewards({ + gauges: fetchedVaults.filter(vault => vault.gauge && vault.chainId === 1).map(vault => vault.gauge?.address) as Address[], + account: account as Address, + publicClient + }) + setGaugeRewards(rewards) + } setVaults(fetchedVaults); } if (!account && !initalLoad) getVaults(); diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 2efdc8c..9fab4c1 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -7,12 +7,13 @@ import { getVeAddresses } from "@/lib/utils/addresses"; import { hasAlreadyVoted } from "@/lib/gauges/hasAlreadyVoted"; import { VaultData } from "@/lib/types"; import { getVaultsByChain } from "@/lib/vault/getVault"; -import VeRewards from "@/components/vepop/VeRewards"; import StakingInterface from "@/components/vepop/StakingInterface"; import { sendVotes } from "@/lib/gauges/interactions"; import Gauge from "@/components/vepop/Gauge"; import LockModal from "@/components/vepop/modals/lock/LockModal"; import ManageLockModal from "@/components/vepop/modals/manage/ManageLockModal"; +import OPopModal from "@/components/vepop/modals/oPop/OPopModal"; +import OPopInterface from "@/components/vepop/OPopInterface"; const { VotingEscrow: VOTING_ESCROW } = getVeAddresses(); @@ -32,6 +33,7 @@ function VePopContainer() { const [showLockModal, setShowLockModal] = useState(false); const [showMangementModal, setShowMangementModal] = useState(false); + const [showOPopModal, setShowOPopModal] = useState(false); useEffect(() => { async function initialSetup() { @@ -71,6 +73,7 @@ function VePopContainer() { <> +

@@ -85,9 +88,8 @@ function VePopContainer() {
- - {/* */} -
+ +
{vaults?.length > 0 ? vaults.map((vault: VaultData, index: number) => @@ -123,7 +125,7 @@ function VePopContainer() { }
-
+
) } diff --git a/public/images/tokens/oPop.svg b/public/images/tokens/oPop.svg new file mode 100644 index 0000000..c4eb769 --- /dev/null +++ b/public/images/tokens/oPop.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file From e1ef71462d06e91ab8ffc27b2314eae91599c99e Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 1 Nov 2023 21:20:18 +0100 Subject: [PATCH 32/84] wip - gaugeInteractions --- components/vault/SmartVault.tsx | 17 +- components/vault/VaultInputs.tsx | 193 +++++++--- components/vepop/modals/lock/LockModal.tsx | 2 +- .../vepop/modals/manage/ManageLockModal.tsx | 2 +- components/vepop/modals/oPop/OPopModal.tsx | 2 +- lib/approve.ts | 6 +- lib/constants/index.ts | 2 + lib/gauges/interactions.ts | 75 +++- lib/utils/getZapAssets.ts | 46 +++ lib/vault/interactions.ts | 62 ++++ lib/vault/zap.ts | 344 ++++++++++++++++++ pages/vaults.tsx | 38 +- 12 files changed, 720 insertions(+), 69 deletions(-) create mode 100644 lib/utils/getZapAssets.ts create mode 100644 lib/vault/zap.ts diff --git a/components/vault/SmartVault.tsx b/components/vault/SmartVault.tsx index 1dbc3f6..4454020 100644 --- a/components/vault/SmartVault.tsx +++ b/components/vault/SmartVault.tsx @@ -14,19 +14,22 @@ import { Token, VaultData } from "@/lib/types"; import calculateAPR from "@/lib/gauges/calculateGaugeAPR"; -function getBaseToken(vaultData: VaultData): Token[] { - const baseToken = [vaultData.vault, vaultData.asset] - if (!!vaultData.gauge) baseToken.push(vaultData.gauge) - return baseToken; +function getTokenOptions(vaultData: VaultData, zapAssets?: Token[]): Token[] { + const tokenOptions = [vaultData.vault, vaultData.asset] + if (!!vaultData.gauge) tokenOptions.push(vaultData.gauge) + if (zapAssets) tokenOptions.push(...zapAssets.filter(asset => getAddress(asset.address) !== getAddress(vaultData.asset.address))) + return tokenOptions; } export default function SmartVault({ vaultData, searchString, + zapAssets, deployer, }: { vaultData: VaultData, searchString: string, + zapAssets?: Token[], deployer?: Address }) { const publicClient = usePublicClient(); @@ -35,7 +38,7 @@ export default function SmartVault({ const vault = vaultData.vault; const asset = vaultData.asset; const gauge = vaultData.gauge; - const baseToken = getBaseToken(vaultData); + const tokenOptions = getTokenOptions(vaultData, zapAssets); const [apy, setApy] = useState(0); @@ -55,7 +58,7 @@ export default function SmartVault({ }, [vault, gaugeApr]) // Is loading / error - if (!vaultData || baseToken.length === 0) return <> + if (!vaultData || tokenOptions.length === 0) return <> // Dont show if we filter by deployer if (!!deployer && getAddress(deployer) !== getAddress(vaultData?.metadata?.creator)) return <> // Vault is not in search term @@ -120,7 +123,7 @@ export default function SmartVault({ vault={vault} asset={asset} gauge={gauge} - tokenOptions={[vaultData.vault, vaultData.asset]} + tokenOptions={tokenOptions} chainId={vaultData.chainId} />
diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index f1cbc47..7d34a58 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -7,11 +7,13 @@ import TabSelector from "@/components/common/TabSelector"; import { Token } from "@/lib/types"; import { handleAllowance } from "@/lib/approve"; import { WalletClient } from "viem"; -import { vaultDeposit, vaultDepositAndStake, vaultRedeem, vaultUnstakeAndWithdraw } from "@/lib/vault/interactions"; +import { vaultDeposit, vaultDepositAndStake, vaultRedeem, vaultUnstakeAndWithdraw, zapIntoGauge, zapIntoVault } from "@/lib/vault/interactions"; import { validateInput } from "@/lib/utils/helpers"; import { getVeAddresses } from "@/lib/utils/addresses"; +import { gaugeDeposit, gaugeWithdraw } from "@/lib/gauges/interactions"; const { VaultRouter: VAULT_ROUTER } = getVeAddresses() +const COWSWAP_RELAYER = "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110" interface VaultInputsProps { vault: Token; @@ -64,49 +66,49 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId async function handleMainAction() { const val = Number(inputBalance) - if (val === 0) return; + if (val === 0 || !inputToken || !outputToken || !account || !walletClient) return; if (chain?.id !== Number(chainId)) switchNetwork?.(Number(chainId)); - switch (inputToken?.address) { + switch (inputToken.address) { case asset.address: console.log("in asset") - if (outputToken?.address === vault.address) { + if (outputToken.address === vault.address) { console.log("out vault") await handleAllowance({ - token: inputToken, - inputAmount: (val * (10 ** inputToken?.decimals)), - account: account as Address, + token: inputToken.address, + inputAmount: (val * (10 ** inputToken.decimals)), + account, spender: vault.address, publicClient, - walletClient: walletClient as WalletClient + walletClient }) vaultDeposit({ address: vault.address, - account: account as Address, - amount: (val * (10 ** inputToken?.decimals)), + account, + amount: (val * (10 ** inputToken.decimals)), publicClient, - walletClient: walletClient as WalletClient + walletClient }) } - else if (outputToken?.address === gauge?.address) { + else if (outputToken.address === gauge?.address) { console.log("out gauge") await handleAllowance({ - token: inputToken, - inputAmount: (val * (10 ** inputToken?.decimals)), - account: account as Address, + token: inputToken.address, + inputAmount: (val * (10 ** inputToken.decimals)), + account, spender: VAULT_ROUTER, publicClient, - walletClient: walletClient as WalletClient + walletClient }) vaultDepositAndStake({ address: VAULT_ROUTER, - account: account as Address, - amount: (val * (10 ** inputToken?.decimals)), + account, + amount: (val * (10 ** inputToken.decimals)), vault: vault?.address as Address, gauge: gauge?.address as Address, publicClient, - walletClient: walletClient as WalletClient + walletClient }) } else { @@ -117,59 +119,166 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId break; case vault.address: console.log("in vault") - if (outputToken?.address === asset.address) { + if (outputToken.address === asset.address) { console.log("out asset") vaultRedeem({ address: vault.address, - account: account as Address, - amount: (val * (10 ** inputToken?.decimals)), + account, + amount: (val * (10 ** inputToken.decimals)), publicClient, - walletClient: walletClient as WalletClient + walletClient }) } - else if (outputToken?.address === gauge?.address) { + else if (outputToken.address === gauge?.address) { console.log("out gauge") await handleAllowance({ - token: vault, - inputAmount: (val * (10 ** vault?.decimals)), - account: account as Address, - spender: gauge?.address as Address, + token: inputToken.address, + inputAmount: (val * (10 ** inputToken.decimals)), + account, + spender: gauge.address, publicClient, - walletClient: walletClient as WalletClient + walletClient + }) + gaugeDeposit({ + address: gauge.address, + amount: (val * (10 ** inputToken.decimals)), + account, + clients: { + publicClient, + walletClient + } }) - //gaugeDeposit() } - else { + else if (outputToken.address === vault.address) { console.log("out error") // wrong output token return } + else { + console.log("out zap") + // TODO - check asset pre balance + vaultRedeem({ + address: vault.address, + account, + amount: (val * (10 ** inputToken.decimals)), + publicClient, + walletClient + }) + // TODO -- wait for transaction to resolve + // TODO -- check asset past balance + // TODO -- zap + return + } break; case gauge?.address: console.log("in gauge") - if (outputToken?.address === asset.address) { + if (outputToken.address === asset.address) { console.log("out asset") await handleAllowance({ - token: inputToken, - inputAmount: (val * (10 ** vault?.decimals)), - account: account as Address, + token: inputToken.address, + inputAmount: (val * (10 ** inputToken.decimals)), + account, spender: VAULT_ROUTER, publicClient, - walletClient: walletClient as WalletClient + walletClient }) vaultUnstakeAndWithdraw({ address: VAULT_ROUTER, - account: account as Address, - amount: (val * (10 ** inputToken?.decimals)), - vault: vault?.address as Address, + account, + amount: (val * (10 ** inputToken.decimals)), + vault: vault.address, gauge: gauge?.address as Address, publicClient, - walletClient: walletClient as WalletClient + walletClient }) } - else if (outputToken?.address === vault.address) { + else if (outputToken.address === vault.address) { console.log("out vault") - //gaugeWithdraw() + gaugeWithdraw({ + address: gauge?.address as Address, + amount: (val * (10 ** inputToken.decimals)), + account, + clients: { + publicClient, + walletClient + } + }) + } + else if (outputToken.address === gauge?.address) { + console.log("out error") + // wrong output token + return + } + else { + console.log("out zap") + // TODO - check asset pre balance + await handleAllowance({ + token: inputToken.address, + inputAmount: (val * (10 ** inputToken.decimals)), + account, + spender: VAULT_ROUTER, + publicClient, + walletClient + }) + await vaultUnstakeAndWithdraw({ + address: VAULT_ROUTER, + account, + amount: (val * (10 ** inputToken.decimals)), + vault: vault.address, + gauge: gauge?.address as Address, + publicClient, + walletClient + }) + // TODO -- wait for transaction to resolve + // TODO -- check asset past balance + // TODO -- zap + return + } + break; + default: + console.log("in zap asset") + if (outputToken.address === vault.address) { + console.log("out vault") + // handle cow router allowance + await handleAllowance({ + token: inputToken.address, + inputAmount: (val * (10 ** inputToken.decimals)), + account, + spender: COWSWAP_RELAYER, + publicClient, + walletClient + }) + zapIntoVault({ + sellToken: inputToken.address, + asset: asset.address, + vault: vault.address, + account, + amount: (val * (10 ** inputToken.decimals)), + publicClient, + walletClient + }) + } + else if (outputToken.address === gauge?.address) { + console.log("out gauge") + await handleAllowance({ + token: inputToken.address, + inputAmount: (val * (10 ** inputToken.decimals)), + account, + spender: COWSWAP_RELAYER, + publicClient, + walletClient + }) + zapIntoGauge({ + sellToken: inputToken.address, + router: VAULT_ROUTER, + asset: asset.address, + vault: vault.address, + gauge: gauge.address, + account, + amount: (val * (10 ** inputToken.decimals)), + publicClient, + walletClient + }) } else { console.log("out error") diff --git a/components/vepop/modals/lock/LockModal.tsx b/components/vepop/modals/lock/LockModal.tsx index 29e30fe..3d75b4e 100644 --- a/components/vepop/modals/lock/LockModal.tsx +++ b/components/vepop/modals/lock/LockModal.tsx @@ -48,7 +48,7 @@ export default function LockModal({ show }: { show: [boolean, Dispatch { const allowance = await publicClient.readContract({ - address: token.address, + address: token, abi: ERC20Abi, functionName: "allowance", args: [account, spender] }) if (Number(allowance) === 0 || Number(allowance) < inputAmount) { - return approve({ address: token.address, account, spender, publicClient, walletClient }) + return approve({ address: token, account, spender, publicClient, walletClient }) } return true } diff --git a/lib/constants/index.ts b/lib/constants/index.ts index 684db0c..f76f84d 100644 --- a/lib/constants/index.ts +++ b/lib/constants/index.ts @@ -11,6 +11,8 @@ export function getAssetsByChain(chainId: number): Token[] { symbol: asset.symbol, decimals: asset.decimals, logoURI: asset.logoURI, + balance: 0, + price: 0 } }); } diff --git a/lib/gauges/interactions.ts b/lib/gauges/interactions.ts index 02316b3..50f0b42 100644 --- a/lib/gauges/interactions.ts +++ b/lib/gauges/interactions.ts @@ -1,9 +1,9 @@ import { Abi, Address, PublicClient, WalletClient, parseEther, zeroAddress } from "viem"; import { VaultData } from "@/lib/types"; -import { showErrorToast, showSuccessToast } from "@/lib/toasts"; +import { showErrorToast, showLoadingToast, showSuccessToast } from "@/lib/toasts"; import { SimulationResponse } from "@/lib/types"; import { getVeAddresses } from "@/lib/utils/addresses"; -import { GaugeControllerAbi, VotingEscrowAbi } from "@/lib/constants"; +import { GaugeAbi, GaugeControllerAbi, VotingEscrowAbi } from "@/lib/constants"; type SimulationContract = { address: Address; @@ -49,6 +49,8 @@ interface SendVotesProps { } export async function sendVotes({ vaults, votes, account, clients }: SendVotesProps) { + showLoadingToast("Sending votes...") + let addr = new Array(8); let v = new Array(8); @@ -96,6 +98,8 @@ interface CreateLockProps { } export async function createLock({ amount, days, account, clients }: CreateLockProps) { + showLoadingToast("Creating lock...") + const { request, success, error: simulationError } = await simulateCall({ account, contract: { @@ -127,6 +131,8 @@ interface IncreaseLockAmountProps { } export async function increaseLockAmount({ amount, account, clients }: IncreaseLockAmountProps) { + showLoadingToast("Increasing lock amount...") + const { request, success, error: simulationError } = await simulateCall({ account, contract: { @@ -158,6 +164,8 @@ interface IncreaseLockTimeProps { } export async function increaseLockTime({ unlockTime, account, clients }: IncreaseLockTimeProps) { + showLoadingToast("Increasing lock time...") + const { request, success, error: simulationError } = await simulateCall({ account, contract: { @@ -188,6 +196,8 @@ interface WithdrawLockProps { } export async function withdrawLock({ account, clients }: WithdrawLockProps) { + showLoadingToast("Withdrawing lock...") + const { request, success, error: simulationError } = await simulateCall({ account, contract: { @@ -209,4 +219,65 @@ export async function withdrawLock({ account, clients }: WithdrawLockProps) { } else { showErrorToast(simulationError) } +} + +interface GaugeInteractionProps { + address: Address; + amount: number; + account: Address; + clients: Clients; +} + +export async function gaugeDeposit({ address, amount, account, clients }: GaugeInteractionProps) { + showLoadingToast("Staking into Gauge...") + + const { request, success, error: simulationError } = await simulateCall({ + account, + contract: { + address, + abi: GaugeAbi, + }, + functionName: "deposit", + publicClient: clients.publicClient, + args: [amount] + }) + + if (success) { + try { + const hash = await clients.walletClient.writeContract(request) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast("Staked into Gauge successful!") + } catch (error: any) { + showErrorToast(error.shortMessage) + } + } else { + showErrorToast(simulationError) + } +} + +export async function gaugeWithdraw({ address, amount, account, clients }: GaugeInteractionProps) { + showLoadingToast("Unstaking from Gauge...") + + const { request, success, error: simulationError } = await simulateCall({ + account, + contract: { + address, + abi: GaugeAbi, + }, + functionName: "withdraw", + publicClient: clients.publicClient, + args: [amount] + }) + + if (success) { + try { + const hash = await clients.walletClient.writeContract(request) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast("Unstaked from Gauge successful!") + } catch (error: any) { + showErrorToast(error.shortMessage) + } + } else { + showErrorToast(simulationError) + } } \ No newline at end of file diff --git a/lib/utils/getZapAssets.ts b/lib/utils/getZapAssets.ts new file mode 100644 index 0000000..9a6835c --- /dev/null +++ b/lib/utils/getZapAssets.ts @@ -0,0 +1,46 @@ +import { Token } from "@/lib/types"; +import assets from "@/lib/constants/assets"; +import { Address, Chain, createPublicClient, http } from "viem"; +import axios from "axios"; +import { RPC_URLS, networkMap } from "@/lib/utils/connectors"; +import { ERC20Abi } from "@/lib/constants"; + +const symbolsToSelect = ["DAI", "USDC", "USDT", "LUSD", "WETH", "WBTC"] + +export default async function getZapAssets({ chain, account }: { chain: Chain, account?: Address }): Promise { + const selected = assets.filter(asset => asset.chains.includes(chain.id)).filter(asset => symbolsToSelect.includes(asset.symbol)) + if (selected.length === 0) return [] + // Add prices + const { data } = await axios.get(`https://coins.llama.fi/prices/current/${String(selected.map(asset => `${networkMap[chain.id].toLowerCase()}:${asset.address[String(chain.id)]}`))}`) + + let balances: bigint[]; + if (account) { + const client = createPublicClient({ chain, transport: http(RPC_URLS[chain.id]) }) + balances = await client.multicall({ + contracts: selected.map(asset => { + return { + address: asset.address[String(chain.id)], + abi: ERC20Abi, + functionName: 'balanceOf', + args: [account] + } + }), + allowFailure: false + }) + } + + return selected.map((asset, i) => { + const address = asset.address[String(chain.id)] + const key = `${networkMap[chain.id].toLowerCase()}:${address}` + const price = Number(data.coins[key]?.price || 0) + return { + address, + name: asset.name, + symbol: asset.symbol, + decimals: asset.decimals, + logoURI: asset.logoURI, + balance: account ? Number(balances[i]) : 0, + price + } + }) +} \ No newline at end of file diff --git a/lib/vault/interactions.ts b/lib/vault/interactions.ts index bcc03ce..90fd741 100644 --- a/lib/vault/interactions.ts +++ b/lib/vault/interactions.ts @@ -3,6 +3,9 @@ import { SimulationResponse } from "@/lib/types"; import { VaultAbi } from "@/lib/constants"; import { Address, PublicClient, WalletClient } from "viem"; import { VaultRouterAbi } from "@/lib/constants/abi/VaultRouter"; +import zap from "./zap"; +import { handleAllowance } from "../approve"; +import axios from "axios"; interface VaultWriteProps { address: Address; @@ -40,7 +43,20 @@ interface VaultRouterSimulateProps { publicClient: PublicClient; } +interface ZapIntoVaultProps { + sellToken: Address; + asset: Address; + vault: Address; + account: Address; + amount: number; + publicClient: PublicClient; + walletClient: WalletClient; +} +interface ZapIntoGaugeProps extends ZapIntoVaultProps { + router: Address; + gauge: Address; +} async function simulateVaultCall({ address, account, amount, functionName, publicClient }: VaultSimulateProps): Promise { try { @@ -163,4 +179,50 @@ export async function vaultUnstakeAndWithdraw({ address, account, amount, vault, showErrorToast(simulationError) return false; } +} + +// TODO -- error handling +// TODO -- adjust timeout +export async function zapIntoVault({ sellToken, asset, vault, account, amount, publicClient, walletClient }: ZapIntoVaultProps): Promise { + showLoadingToast("Zapping into asset...") + const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient }) + + // await fullfillment + let depositAmount = 0; + setTimeout(async () => { depositAmount = Number((await axios.get(`https://api.cow.fi/mainnet/api/v1/orders/${orderId}`)).data.executedBuyAmount) }, 3600) + + // approve vault + await handleAllowance({ + token: asset, + inputAmount: depositAmount, + account, + spender: vault, + publicClient, + walletClient + }) + + return vaultDeposit({ address: vault, account, amount: depositAmount, publicClient, walletClient }) +} + +// TODO -- error handling +// TODO -- adjust timeout +export async function zapIntoGauge({ sellToken, asset, router, vault, gauge, account, amount, publicClient, walletClient }: ZapIntoGaugeProps): Promise { + showLoadingToast("Zapping into asset...") + const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient }) + + // await fullfillment + let depositAmount = 0; + setTimeout(async () => { depositAmount = Number((await axios.get(`https://api.cow.fi/mainnet/api/v1/orders/${orderId}`)).data.executedBuyAmount) }, 3600) + + // approve vault + await handleAllowance({ + token: asset, + inputAmount: depositAmount, + account, + spender: vault, + publicClient, + walletClient + }) + + return vaultDepositAndStake({ address: router, account, vault, gauge, amount: depositAmount, publicClient, walletClient }) } \ No newline at end of file diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts new file mode 100644 index 0000000..2161cca --- /dev/null +++ b/lib/vault/zap.ts @@ -0,0 +1,344 @@ +import axios from "axios" +import { Address, ByteArray, Hex, WalletClient, hashTypedData, pad, zeroAddress } from "viem"; + +const GPv2Settlement = "0x9008D19f58AAbD9eD0D60971565AA8510560ab41" + +const cowDomain = { + name: "Gnosis Protocol", + version: "v2", + chainId: 1, + verifyingContract: GPv2Settlement, +} + +export enum OrderKind { + /** + * A sell order. + */ + SELL = "sell", + /** + * A buy order. + */ + BUY = "buy", +} + +/** + * Gnosis Protocol v2 order data. + */ +export interface Order { + /** + * Sell token address. + */ + sellToken: string; + /** + * Buy token address. + */ + buyToken: string; + /** + * An optional address to receive the proceeds of the trade instead of the + * owner (i.e. the order signer). + */ + receiver?: string; + /** + * The order sell amount. + * + * For fill or kill sell orders, this amount represents the exact sell amount + * that will be executed in the trade. For fill or kill buy orders, this + * amount represents the maximum sell amount that can be executed. For partial + * fill orders, this represents a component of the limit price fraction. + */ + sellAmount: bigint | string; + /** + * The order buy amount. + * + * For fill or kill sell orders, this amount represents the minimum buy amount + * that can be executed in the trade. For fill or kill buy orders, this amount + * represents the exact buy amount that will be executed. For partial fill + * orders, this represents a component of the limit price fraction. + */ + buyAmount: bigint; + /** + * The timestamp this order is valid until + */ + validTo: number | Date; + /** + * Arbitrary application specific data that can be added to an order. This can + * also be used to ensure uniqueness between two orders with otherwise the + * exact same parameters. + */ + appData: ByteArray | Hex; + /** + * Fee to give to the protocol. + */ + feeAmount: bigint; + /** + * The order kind. + */ + kind: OrderKind; + /** + * Specifies whether or not the order is partially fillable. + */ + partiallyFillable: boolean; + /** + * Specifies how the sell token balance will be withdrawn. It can either be + * taken using ERC20 token allowances made directly to the Vault relayer + * (default) or using Balancer Vault internal or external balances. + */ + sellTokenBalance?: OrderBalance; + /** + * Specifies how the buy token balance will be paid. It can either be paid + * directly in ERC20 tokens (default) in Balancer Vault internal balances. + */ + buyTokenBalance?: OrderBalance; +} + +/** + * Normalized representation of an {@link Order} for EIP-712 operations. + */ +export type NormalizedOrder = Omit< + Order, + "validTo" | "appData" | "kind" | "sellTokenBalance" | "buyTokenBalance" +> & { + receiver: string; + validTo: number; + appData: string; + kind: "sell" | "buy"; + sellTokenBalance: "erc20" | "external" | "internal"; + buyTokenBalance: "erc20" | "internal"; +}; + +/** + * The signing scheme used to sign the order. + */ +export enum SigningScheme { + /** + * The EIP-712 typed data signing scheme. This is the preferred scheme as it + * provides more infomation to wallets performing the signature on the data + * being signed. + * + * + */ + EIP712 = 0b00, + /** + * Message signed using eth_sign RPC call. + */ + ETHSIGN = 0b01, + /** + * Smart contract signatures as defined in EIP-1271. + * + * + */ + EIP1271 = 0b10, + /** + * Pre-signed order. + */ + PRESIGN = 0b11, +} + +/** + * The EIP-712 type fields definition for a Gnosis Protocol v2 order. + */ +export const ORDER_TYPE_FIELDS = [ + { name: "sellToken", type: "address" }, + { name: "buyToken", type: "address" }, + { name: "receiver", type: "address" }, + { name: "sellAmount", type: "uint256" }, + { name: "buyAmount", type: "uint256" }, + { name: "validTo", type: "uint32" }, + { name: "appData", type: "bytes32" }, + { name: "feeAmount", type: "uint256" }, + { name: "kind", type: "string" }, + { name: "partiallyFillable", type: "bool" }, + { name: "sellTokenBalance", type: "string" }, + { name: "buyTokenBalance", type: "string" }, +]; + + +/** + * Order balance configuration. + */ +export enum OrderBalance { + /** + * Use ERC20 token balances. + */ + ERC20 = "erc20", + /** + * Use Balancer Vault external balances. + * + * This can only be specified specified for the sell balance and allows orders + * to re-use Vault ERC20 allowances. When specified for the buy balance, it + * will be treated as {@link OrderBalance.ERC20}. + */ + EXTERNAL = "external", + /** + * Use Balancer Vault internal balances. + */ + INTERNAL = "internal", +} + +/** + * Normalizes the balance configuration for a buy token. Specifically, this + * function ensures that {@link OrderBalance.EXTERNAL} gets normalized to + * {@link OrderBalance.ERC20}. + * + * @param balance The balance configuration. + * @returns The normalized balance configuration. + */ +export function normalizeBuyTokenBalance( + balance: OrderBalance | undefined, +): OrderBalance.ERC20 | OrderBalance.INTERNAL { + switch (balance) { + case undefined: + case OrderBalance.ERC20: + case OrderBalance.EXTERNAL: + return OrderBalance.ERC20; + case OrderBalance.INTERNAL: + return OrderBalance.INTERNAL; + default: + throw new Error(`invalid order balance ${balance}`); + } +} + +/** + * Normalizes a timestamp value to a Unix timestamp. + * @param time The timestamp value to normalize. + * @return Unix timestamp or number of seconds since the Unix Epoch. + */ +export function timestamp(t: number | Date): number { + return typeof t === "number" ? t : ~~(t.getTime() / 1000); +} + + +/** + * Normalizes an app data value to a 32-byte hash. + * @param hashLike A hash-like value to normalize. + * @returns A 32-byte hash encoded as a hex-string. + */ +export function hashify(h: ByteArray | Hex | number): string { + return typeof h === "number" + ? `0x${h.toString(16).padStart(64, "0")}` + : pad(h, { size: 32 }) as string; +} + +/** + * Normalizes an order for hashing and signing, so that it can be used with + * Ethers.js for EIP-712 operations. + * @param hashLike A hash-like value to normalize. + * @returns A 32-byte hash encoded as a hex-string. + */ +export function normalizeOrder(order: Order): NormalizedOrder { + if (order.receiver === zeroAddress) { + throw new Error("receiver cannot be address(0)"); + } + + const normalizedOrder = { + ...order, + sellTokenBalance: order.sellTokenBalance ?? OrderBalance.ERC20, + receiver: order.receiver ?? zeroAddress, + validTo: timestamp(order.validTo), + appData: hashify(order.appData), + buyTokenBalance: normalizeBuyTokenBalance(order.buyTokenBalance), + }; + return normalizedOrder; +} + + +async function ecdsaSignTypedData( + scheme: any, + account: Address, + owner: WalletClient, + domain: any, + types: any, + data: NormalizedOrder, +): Promise { + let signature: string | null = null; + + switch (scheme) { + case SigningScheme.EIP712: + signature = await owner.signTypedData({ account, domain, types, primaryType: "Order", message: data }); + break; + case SigningScheme.ETHSIGN: + signature = await owner.signMessage({ + account, + message: { raw: hashTypedData({ domain, types, primaryType: "Order", message: data }) }, + }); + break; + default: + throw new Error("invalid signing scheme"); + } + return signature +} + +export type SigningResult = { signature: string; signingScheme: SigningScheme } + +export async function signOrder( + order: Order, + chainId: number, + account: Address, + signer: WalletClient, + signingMethod: 'default' | 'v4' | 'int_v4' | 'v3' | 'eth_sign' = 'v4' +): Promise { + const scheme = signingMethod === 'eth_sign' ? SigningScheme.ETHSIGN : SigningScheme.EIP712 + return { + scheme, + data: await ecdsaSignTypedData( + scheme, + account, + signer, + cowDomain, + { Order: ORDER_TYPE_FIELDS }, + normalizeOrder(order), + ), + } +} + +// TODO - add slippage control +// TODO -- adjust timeout +export default async function zap({ account, signer, sellToken, buyToken, amount }: { account: Address, signer: WalletClient, sellToken: Address, buyToken: Address, amount: number }): Promise { + const quote = (await axios.post( + "https://api.cow.fi/mainnet/api/v1/quote", + JSON.stringify({ + sellToken, + buyToken, + from: account, + receiver: account, + validTo: Math.floor(Date.now() / 1000) + 3600, + partiallyFillable: false, + kind: "sell", + sellAmountBeforeFee: String(amount) + }), + { headers: { 'Content-Type': 'application/json' } } + )).data.quote + const order: Order = { + sellToken: quote.sellToken, + buyToken: quote.buyToken, + receiver: quote.receiver, + sellAmount: quote.sellAmount, + buyAmount: quote.buyAmount, + validTo: Math.floor(Date.now() / 1000) + 3600, + feeAmount: quote.feeAmount, + kind: quote.kind, + partiallyFillable: false, + sellTokenBalance: quote.sellTokenBalance, + buyTokenBalance: quote.buyTokenBalance, + appData: "0x0000000000000000000000000000000000000000000000000000000000000000" + } + + const signedOrder = await signOrder( + order, + 1, + account, + signer) + + const orderId = (await axios.post( + "https://api.cow.fi/mainnet/api/v1/orders", + JSON.stringify({ + ...order, + signature: signedOrder.data, + from: "0x22f5413C075Ccd56D575A54763831C4c27A37Bdb", + signingScheme: quote.signingScheme, + appData: "0x0000000000000000000000000000000000000000000000000000000000000000", + }), + { headers: { 'Content-Type': 'application/json' } } + )).data + return orderId +} \ No newline at end of file diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 90bddf8..601358b 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -10,7 +10,7 @@ import useNetworkFilter from "@/lib/useNetworkFilter"; import getVaultNetworth from "@/lib/vault/getVaultNetworth"; import useVaultTvl from "@/lib/useVaultTvl"; import { getVaultsByChain } from "@/lib/vault/getVault"; -import { VaultData } from "@/lib/types"; +import { Token, VaultData } from "@/lib/types"; import SmartVault from "@/components/vault/SmartVault"; import NetworkFilter from "@/components/network/NetworkFilter"; import MainActionButton from "@/components/button/MainActionButton"; @@ -18,6 +18,7 @@ import getGaugeRewards, { GaugeRewards } from "@/lib/gauges/getGaugeRewards"; import { getVeAddresses } from "@/lib/utils/addresses"; import { claimOPop } from "@/lib/oPop/interactions"; import { WalletClient } from "viem"; +import getZapAssets from "@/lib/utils/getZapAssets"; export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2fD2C18f79F93eF299B20B681Ab2a61f5F28A6fF", "0xDFf04Efb38465369fd1A2E8B40C364c22FfEA340", "0xd4D442AC311d918272911691021E6073F620eb07", //@dev for some reason the live 3Crypto yVault isnt picked up by the yearnAdapter nor the yearnFactoryAdapter @@ -40,6 +41,8 @@ const Vaults: NextPage = () => { const [selectedNetworks, selectNetwork] = useNetworkFilter(SUPPORTED_NETWORKS.map(network => network.id)); const [vaults, setVaults] = useState([]); + const [zapAssets, setZapAssets] = useState<{ [key: number]: Token[] }>({}); + const vaultTvl = useVaultTvl(); const [gaugeRewards, setGaugeRewards] = useState() @@ -51,10 +54,17 @@ const Vaults: NextPage = () => { async function getVaults() { setInitalLoad(true) if (account) setAccountLoad(true) + // get zap assets + const newZapAssets: { [key: number]: Token[] } = {} + SUPPORTED_NETWORKS.forEach(async (chain) => newZapAssets[chain.id] = await getZapAssets({ chain, account })) + setZapAssets(newZapAssets); + + // get vaults const fetchedVaults = (await Promise.all( SUPPORTED_NETWORKS.map(async (chain) => getVaultsByChain({ chain, account })) )).flat(); - + + // get gauge rewards if (account) { const rewards = await getGaugeRewards({ gauges: fetchedVaults.filter(vault => vault.gauge && vault.chainId === 1).map(vault => vault.gauge?.address) as Address[], @@ -63,6 +73,7 @@ const Vaults: NextPage = () => { }) setGaugeRewards(rewards) } + setVaults(fetchedVaults); } if (!account && !initalLoad) getVaults(); @@ -168,16 +179,19 @@ const Vaults: NextPage = () => {
- {vaults.length > 0 ? vaults.filter(vault => selectedNetworks.includes(vault.chainId)).filter(vault => !HIDDEN_VAULTS.includes(vault.address)).map((vault) => { - return ( - - ) - }) + {vaults.length > 0 && + Object.keys(zapAssets).length > 0 + ? vaults.filter(vault => selectedNetworks.includes(vault.chainId)).filter(vault => !HIDDEN_VAULTS.includes(vault.address)).map((vault) => { + return ( + + ) + }) :

Loading Vaults...

}
From 38d114a22812fd668054f7bddc21ad52c51f426c Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 1 Nov 2023 22:14:14 +0100 Subject: [PATCH 33/84] checking cow for available zap assets --- components/vault/VaultInputs.tsx | 8 +++---- lib/utils/getZapAssets.ts | 39 +++++++++++++++++++++++++++++++- pages/vaults.tsx | 11 +++++---- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index 7d34a58..9616962 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -306,8 +306,8 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId onChange={handleChangeInput} selectedToken={inputToken} errorMessage={""} - tokenList={[]} - allowSelection={false} + tokenList={tokenOptions} + allowSelection={isDeposit} allowInput />
@@ -333,8 +333,8 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId onChange={() => { }} selectedToken={outputToken} errorMessage={""} - tokenList={[]} - allowSelection={false} + tokenList={tokenOptions} + allowSelection={!isDeposit} allowInput={false} />
diff --git a/lib/utils/getZapAssets.ts b/lib/utils/getZapAssets.ts index 9a6835c..67b17ea 100644 --- a/lib/utils/getZapAssets.ts +++ b/lib/utils/getZapAssets.ts @@ -1,6 +1,6 @@ import { Token } from "@/lib/types"; import assets from "@/lib/constants/assets"; -import { Address, Chain, createPublicClient, http } from "viem"; +import { Address, Chain, createPublicClient, getAddress, http } from "viem"; import axios from "axios"; import { RPC_URLS, networkMap } from "@/lib/utils/connectors"; import { ERC20Abi } from "@/lib/constants"; @@ -43,4 +43,41 @@ export default async function getZapAssets({ chain, account }: { chain: Chain, a price } }) +} + +export async function getAvailableZapAssets() { + const numTokens = Number((await axios({ + url: "https://api.thegraph.com/subgraphs/name/cowprotocol/cow", + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify({ + query: ` + query getNumTokens { + totals { + tokens + } + }`, + }) + })).data.data.totals[0].tokens); + + let addresses = [] + for (let i = 0; i < numTokens;) { + const tokens = (await axios({ + url: "https://api.thegraph.com/subgraphs/name/cowprotocol/cow", + method: 'post', + headers: { 'Content-Type': 'application/json' }, + data: JSON.stringify({ + query: ` + query MyQuery { + tokens(first: 1000, skip:${i}) { + address + } + }`, + }) + })).data.data.tokens; + addresses.push(...tokens.map((token: any) => getAddress(token.address))) + i += 1000 + } + addresses = addresses.flat() + return addresses } \ No newline at end of file diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 601358b..006c6b0 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -18,7 +18,7 @@ import getGaugeRewards, { GaugeRewards } from "@/lib/gauges/getGaugeRewards"; import { getVeAddresses } from "@/lib/utils/addresses"; import { claimOPop } from "@/lib/oPop/interactions"; import { WalletClient } from "viem"; -import getZapAssets from "@/lib/utils/getZapAssets"; +import getZapAssets, { getAvailableZapAssets } from "@/lib/utils/getZapAssets"; export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2fD2C18f79F93eF299B20B681Ab2a61f5F28A6fF", "0xDFf04Efb38465369fd1A2E8B40C364c22FfEA340", "0xd4D442AC311d918272911691021E6073F620eb07", //@dev for some reason the live 3Crypto yVault isnt picked up by the yearnAdapter nor the yearnFactoryAdapter @@ -42,7 +42,7 @@ const Vaults: NextPage = () => { const [selectedNetworks, selectNetwork] = useNetworkFilter(SUPPORTED_NETWORKS.map(network => network.id)); const [vaults, setVaults] = useState([]); const [zapAssets, setZapAssets] = useState<{ [key: number]: Token[] }>({}); - + const [availableZapAssets, setAvailableZapAssets] = useState<{ [key: number]: Address[] }>({}) const vaultTvl = useVaultTvl(); const [gaugeRewards, setGaugeRewards] = useState() @@ -59,11 +59,14 @@ const Vaults: NextPage = () => { SUPPORTED_NETWORKS.forEach(async (chain) => newZapAssets[chain.id] = await getZapAssets({ chain, account })) setZapAssets(newZapAssets); + // get available zapAddresses + setAvailableZapAssets({ 1: await getAvailableZapAssets() }) + // get vaults const fetchedVaults = (await Promise.all( SUPPORTED_NETWORKS.map(async (chain) => getVaultsByChain({ chain, account })) )).flat(); - + // get gauge rewards if (account) { const rewards = await getGaugeRewards({ @@ -187,7 +190,7 @@ const Vaults: NextPage = () => { key={`sv-${vault.address}-${vault.chainId}`} vaultData={vault} searchString={searchString} - zapAssets={zapAssets[vault.chainId]} + zapAssets={vault.chainId === 1 && availableZapAssets[1].includes(vault.asset.address) ? zapAssets[vault.chainId] : undefined} deployer={"0x22f5413C075Ccd56D575A54763831C4c27A37Bdb"} /> ) From f6ea8e521a727f269f51d8f6014bc77a13d3f6ab Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 2 Nov 2023 09:33:03 +0100 Subject: [PATCH 34/84] added minor error handling, timeout and zap+router interactions --- components/vault/VaultInputs.tsx | 34 ++++++++++++++++++++------------ lib/vault/getVault.ts | 8 ++++---- lib/vault/interactions.ts | 20 +++++++++++-------- lib/vault/zap.ts | 20 +++++++++++++------ 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index 9616962..b50f0bd 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -11,6 +11,8 @@ import { vaultDeposit, vaultDepositAndStake, vaultRedeem, vaultUnstakeAndWithdra import { validateInput } from "@/lib/utils/helpers"; import { getVeAddresses } from "@/lib/utils/addresses"; import { gaugeDeposit, gaugeWithdraw } from "@/lib/gauges/interactions"; +import { ERC20Abi } from "@/lib/constants"; +import zap from "@/lib/vault/zap"; const { VaultRouter: VAULT_ROUTER } = getVeAddresses() const COWSWAP_RELAYER = "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110" @@ -156,18 +158,17 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId } else { console.log("out zap") - // TODO - check asset pre balance - vaultRedeem({ + + const preBal = asset.balance + await vaultRedeem({ address: vault.address, account, amount: (val * (10 ** inputToken.decimals)), publicClient, walletClient }) - // TODO -- wait for transaction to resolve - // TODO -- check asset past balance - // TODO -- zap - return + const postBal = Number(await publicClient.readContract({ address: asset.address, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) + zap({ account, signer: walletClient, sellToken: asset.address, buyToken: outputToken.address, amount: postBal - preBal }) } break; case gauge?.address: @@ -211,7 +212,8 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId } else { console.log("out zap") - // TODO - check asset pre balance + + const preBal = asset.balance await handleAllowance({ token: inputToken.address, inputAmount: (val * (10 ** inputToken.decimals)), @@ -229,10 +231,8 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId publicClient, walletClient }) - // TODO -- wait for transaction to resolve - // TODO -- check asset past balance - // TODO -- zap - return + const postBal = Number(await publicClient.readContract({ address: asset.address, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) + zap({ account, signer: walletClient, sellToken: asset.address, buyToken: outputToken.address, amount: postBal - preBal }) } break; default: @@ -306,7 +306,11 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId onChange={handleChangeInput} selectedToken={inputToken} errorMessage={""} - tokenList={tokenOptions} + tokenList={tokenOptions.filter(token => + gauge?.address + ? token.address !== gauge?.address + : token.address !== vault.address + )} allowSelection={isDeposit} allowInput /> @@ -333,7 +337,11 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId onChange={() => { }} selectedToken={outputToken} errorMessage={""} - tokenList={tokenOptions} + tokenList={tokenOptions.filter(token => + gauge?.address + ? token.address !== gauge?.address + : token.address !== vault.address + )} allowSelection={!isDeposit} allowInput={false} /> diff --git a/lib/vault/getVault.ts b/lib/vault/getVault.ts index 046ecb0..f27c42e 100644 --- a/lib/vault/getVault.ts +++ b/lib/vault/getVault.ts @@ -168,7 +168,7 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va name: String(assetAndAdapterMeta[i + 3]), symbol: String(assetAndAdapterMeta[i + 4]), decimals: entry.vault.decimals, - logoURI: "", // wont be used, just here for consistency + logoURI: "/images/tokens/pop.svg", // wont be used, just here for consistency balance: 0, price: 0, } @@ -229,7 +229,7 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va name: `${entry.vault.name}-gauge`, symbol: `st-${entry.vault.name}`, decimals: foundGauge.decimals, - logoURI: "", // wont be used, just here for consistency + logoURI: "/images/tokens/pop.svg", // wont be used, just here for consistency balance: foundGauge.balance, price: entry.pricePerShare, } : undefined @@ -279,7 +279,7 @@ export async function getVault({ vault, account = ADDRESS_ZERO, client }: { vaul name: String(assetAndAdapterMeta[3]), symbol: String(assetAndAdapterMeta[4]), decimals: Number(results[2]), - logoURI: "", // wont be used, just here for consistency, + logoURI: "/images/tokens/pop.svg", // wont be used, just here for consistency, balance: 0, // wont be used, just here for consistency, price: 0, // wont be used, just here for consistency, } @@ -331,7 +331,7 @@ export async function getVault({ vault, account = ADDRESS_ZERO, client }: { vaul name: `${result.vault.name}-gauge`, symbol: `st-${result.vault.name}`, decimals: foundGauge.decimals, - logoURI: "", // wont be used, just here for consistency + logoURI: "/images/tokens/pop.svg", // wont be used, just here for consistency balance: foundGauge.balance, price: result.pricePerShare, } : undefined diff --git a/lib/vault/interactions.ts b/lib/vault/interactions.ts index 90fd741..a22fc8f 100644 --- a/lib/vault/interactions.ts +++ b/lib/vault/interactions.ts @@ -49,6 +49,8 @@ interface ZapIntoVaultProps { vault: Address; account: Address; amount: number; + slippage?: number; + timeout?: number; publicClient: PublicClient; walletClient: WalletClient; } @@ -182,14 +184,15 @@ export async function vaultUnstakeAndWithdraw({ address, account, amount, vault, } // TODO -- error handling -// TODO -- adjust timeout -export async function zapIntoVault({ sellToken, asset, vault, account, amount, publicClient, walletClient }: ZapIntoVaultProps): Promise { +export async function zapIntoVault({ sellToken, asset, vault, account, amount, slippage = 100, timeout = 60, publicClient, walletClient }: ZapIntoVaultProps): Promise { showLoadingToast("Zapping into asset...") - const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient }) + const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient, slippage, timeout }) // await fullfillment let depositAmount = 0; - setTimeout(async () => { depositAmount = Number((await axios.get(`https://api.cow.fi/mainnet/api/v1/orders/${orderId}`)).data.executedBuyAmount) }, 3600) + setTimeout(async () => { depositAmount = Number((await axios.get(`https://api.cow.fi/mainnet/api/v1/orders/${orderId}`)).data.executedBuyAmount) }, timeout) + + if (depositAmount === 0) return false // error happened // approve vault await handleAllowance({ @@ -205,14 +208,15 @@ export async function zapIntoVault({ sellToken, asset, vault, account, amount, p } // TODO -- error handling -// TODO -- adjust timeout -export async function zapIntoGauge({ sellToken, asset, router, vault, gauge, account, amount, publicClient, walletClient }: ZapIntoGaugeProps): Promise { +export async function zapIntoGauge({ sellToken, asset, router, vault, gauge, account, amount, slippage = 100, timeout = 60, publicClient, walletClient }: ZapIntoGaugeProps): Promise { showLoadingToast("Zapping into asset...") - const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient }) + const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient, slippage, timeout }) // await fullfillment let depositAmount = 0; - setTimeout(async () => { depositAmount = Number((await axios.get(`https://api.cow.fi/mainnet/api/v1/orders/${orderId}`)).data.executedBuyAmount) }, 3600) + setTimeout(async () => { depositAmount = Number((await axios.get(`https://api.cow.fi/mainnet/api/v1/orders/${orderId}`)).data.executedBuyAmount) }, timeout) + + if (depositAmount === 0) return false // error happened // approve vault await handleAllowance({ diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index 2161cca..fe03a78 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -291,9 +291,17 @@ export async function signOrder( } } -// TODO - add slippage control -// TODO -- adjust timeout -export default async function zap({ account, signer, sellToken, buyToken, amount }: { account: Address, signer: WalletClient, sellToken: Address, buyToken: Address, amount: number }): Promise { +interface ZapProps { + sellToken: Address; + buyToken: Address; + amount: number; + account: Address; + signer: WalletClient; + slippage?: number; // slippage allowance in BPS + timeout?: number; // in s +} + +export default async function zap({ sellToken, buyToken, amount, account, signer, slippage = 100, timeout = 60 }: ZapProps): Promise { const quote = (await axios.post( "https://api.cow.fi/mainnet/api/v1/quote", JSON.stringify({ @@ -301,7 +309,7 @@ export default async function zap({ account, signer, sellToken, buyToken, amount buyToken, from: account, receiver: account, - validTo: Math.floor(Date.now() / 1000) + 3600, + validTo: Math.floor(Date.now() / 1000) + timeout, partiallyFillable: false, kind: "sell", sellAmountBeforeFee: String(amount) @@ -313,8 +321,8 @@ export default async function zap({ account, signer, sellToken, buyToken, amount buyToken: quote.buyToken, receiver: quote.receiver, sellAmount: quote.sellAmount, - buyAmount: quote.buyAmount, - validTo: Math.floor(Date.now() / 1000) + 3600, + buyAmount: BigInt((Number(quote.buyAmount) * (10_000 - slippage)) / 10_000), // @dev we might need to format the number to cast it into a bigint + validTo: Math.floor(Date.now() / 1000) + timeout, feeAmount: quote.feeAmount, kind: quote.kind, partiallyFillable: false, From 5c1304708ee7aa234f33f4a23164a4660ddc67fd Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 2 Nov 2023 14:31:25 +0100 Subject: [PATCH 35/84] added zap settings --- components/vault/VaultInputs.tsx | 61 ++++++++++++++++++++++++++++++-- lib/vault/getVault.ts | 2 +- lib/vault/interactions.ts | 22 +++++++++--- lib/vault/zap.ts | 7 ++-- 4 files changed, 81 insertions(+), 11 deletions(-) diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index b50f0bd..7ee918a 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -1,4 +1,4 @@ -import { ArrowDownIcon } from "@heroicons/react/24/outline"; +import { ArrowDownIcon, Cog6ToothIcon } from "@heroicons/react/24/outline"; import InputTokenWithError from "@/components/input/InputTokenWithError"; import MainActionButton from "@/components/button/MainActionButton"; import { useEffect, useState } from "react"; @@ -13,6 +13,8 @@ import { getVeAddresses } from "@/lib/utils/addresses"; import { gaugeDeposit, gaugeWithdraw } from "@/lib/gauges/interactions"; import { ERC20Abi } from "@/lib/constants"; import zap from "@/lib/vault/zap"; +import Modal from "../modal/Modal"; +import InputNumber from "../input/InputNumber"; const { VaultRouter: VAULT_ROUTER } = getVeAddresses() const COWSWAP_RELAYER = "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110" @@ -39,6 +41,11 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId const [isDeposit, setIsDeposit] = useState(true); + // Zap Settings + const [showModal, setShowModal] = useState(false) + const [timeout, setTimeout] = useState(60); // number of seconds a cow order is valid for + const [slippage, setSlippage] = useState(100); // In BPS 0 - 10_000 + useEffect(() => { // set default input/output tokens setInputToken(asset) @@ -168,7 +175,15 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId walletClient }) const postBal = Number(await publicClient.readContract({ address: asset.address, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) - zap({ account, signer: walletClient, sellToken: asset.address, buyToken: outputToken.address, amount: postBal - preBal }) + zap({ + account, + signer: walletClient, + sellToken: asset.address, + buyToken: outputToken.address, + amount: postBal - preBal, + slippage, + timeout + }) } break; case gauge?.address: @@ -232,7 +247,15 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId walletClient }) const postBal = Number(await publicClient.readContract({ address: asset.address, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) - zap({ account, signer: walletClient, sellToken: asset.address, buyToken: outputToken.address, amount: postBal - preBal }) + zap({ + account, + signer: walletClient, + sellToken: asset.address, + buyToken: outputToken.address, + amount: postBal - preBal, + slippage, + timeout + }) } break; default: @@ -240,6 +263,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId if (outputToken.address === vault.address) { console.log("out vault") // handle cow router allowance + console.log("approve cow router") await handleAllowance({ token: inputToken.address, inputAmount: (val * (10 ** inputToken.decimals)), @@ -254,6 +278,8 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId vault: vault.address, account, amount: (val * (10 ** inputToken.decimals)), + slippage, + timeout, publicClient, walletClient }) @@ -276,6 +302,8 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId gauge: gauge.address, account, amount: (val * (10 ** inputToken.decimals)), + slippage, + timeout, publicClient, walletClient }) @@ -291,6 +319,26 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId if (!inputToken || !outputToken) return <> return <> + +
+

Slippage (in BPS)

+
+ setSlippage(Number(e.currentTarget.value))} + /> +
+
+
+

Timeout (in seconds)

+
+ setTimeout(Number(e.currentTarget.value))} + /> +
+
+
+ {((isDeposit && ![asset.address, vault.address].includes(inputToken.address)) || + (!isDeposit && ![asset.address, vault.address].includes(outputToken.address))) && +
setShowModal(true)}> +
+ }
diff --git a/lib/vault/getVault.ts b/lib/vault/getVault.ts index f27c42e..1614521 100644 --- a/lib/vault/getVault.ts +++ b/lib/vault/getVault.ts @@ -256,7 +256,7 @@ export async function getVault({ vault, account = ADDRESS_ZERO, client }: { vaul const vaultName = await getVaultName({ address: getAddress(vault), cid: registryMetadata[3] }) const price = await resolvePrice({ chainId: client.chain.id, client: client, address: results[3] as Address, resolver: 'llama' }) - const assetsPerShare = Number(results[6]) > 0 ? Number(results[5]) / Number(results[6]) : Number(1) + const assetsPerShare = Number(results[6]) > 0 ? Number(results[5]) / Number(results[6]) : Number(1e-9) const pricePerShare = assetsPerShare * price const fees = results[7] as [BigInt, BigInt, BigInt, BigInt] diff --git a/lib/vault/interactions.ts b/lib/vault/interactions.ts index a22fc8f..3b6bd6f 100644 --- a/lib/vault/interactions.ts +++ b/lib/vault/interactions.ts @@ -186,14 +186,26 @@ export async function vaultUnstakeAndWithdraw({ address, account, amount, vault, // TODO -- error handling export async function zapIntoVault({ sellToken, asset, vault, account, amount, slippage = 100, timeout = 60, publicClient, walletClient }: ZapIntoVaultProps): Promise { showLoadingToast("Zapping into asset...") + console.log("zap") const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient, slippage, timeout }) - + console.log({ orderId }) // await fullfillment + console.log("waiting for order fulfillment") let depositAmount = 0; - setTimeout(async () => { depositAmount = Number((await axios.get(`https://api.cow.fi/mainnet/api/v1/orders/${orderId}`)).data.executedBuyAmount) }, timeout) - - if (depositAmount === 0) return false // error happened + setTimeout(async () => { + console.log("getting order receipt") + const orderData = (await axios.get(`https://api.cow.fi/mainnet/api/v1/orders/${orderId}`)).data + console.log({ orderData }) + depositAmount = Number(orderData.executedBuyAmount) + }, timeout) + console.log({ depositAmount }) + if (depositAmount === 0) { + // error happened + showErrorToast("Zap Order failed") + return false + } + console.log("approving vault") // approve vault await handleAllowance({ token: asset, @@ -203,7 +215,7 @@ export async function zapIntoVault({ sellToken, asset, vault, account, amount, s publicClient, walletClient }) - + console.log("vault deposit") return vaultDeposit({ address: vault, account, amount: depositAmount, publicClient, walletClient }) } diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index fe03a78..1a8e038 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -302,6 +302,7 @@ interface ZapProps { } export default async function zap({ sellToken, buyToken, amount, account, signer, slippage = 100, timeout = 60 }: ZapProps): Promise { + console.log("getting quote") const quote = (await axios.post( "https://api.cow.fi/mainnet/api/v1/quote", JSON.stringify({ @@ -316,6 +317,7 @@ export default async function zap({ sellToken, buyToken, amount, account, signer }), { headers: { 'Content-Type': 'application/json' } } )).data.quote + console.log({quote}) const order: Order = { sellToken: quote.sellToken, buyToken: quote.buyToken, @@ -330,13 +332,14 @@ export default async function zap({ sellToken, buyToken, amount, account, signer buyTokenBalance: quote.buyTokenBalance, appData: "0x0000000000000000000000000000000000000000000000000000000000000000" } - + console.log({order}) + console.log("signing order") const signedOrder = await signOrder( order, 1, account, signer) - + console.log("posting order") const orderId = (await axios.post( "https://api.cow.fi/mainnet/api/v1/orders", JSON.stringify({ From f104b0c3bb753fcd8f9648b9597413ace394a418 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 2 Nov 2023 16:01:23 +0100 Subject: [PATCH 36/84] zap settings --- components/input/InputTokenWithError.tsx | 2 +- lib/gauges/calculateGaugeAPR.ts | 3 --- lib/vault/getVault.ts | 4 ++-- lib/vault/zap.ts | 15 ++++++++------- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/components/input/InputTokenWithError.tsx b/components/input/InputTokenWithError.tsx index 8fb6994..6a0b526 100644 --- a/components/input/InputTokenWithError.tsx +++ b/components/input/InputTokenWithError.tsx @@ -62,7 +62,7 @@ export default function InputTokenWithError({

- {`${selectedToken?.balance ? formatNumber(Number(selectedToken?.balance) / (10 ** (selectedToken?.decimals as number))) : "0"}`} + {`${formatNumber(Number(selectedToken?.balance) / (10 ** (selectedToken?.decimals as number)))}`}

}
diff --git a/lib/gauges/calculateGaugeAPR.ts b/lib/gauges/calculateGaugeAPR.ts index 9dd7052..7847079 100644 --- a/lib/gauges/calculateGaugeAPR.ts +++ b/lib/gauges/calculateGaugeAPR.ts @@ -87,8 +87,5 @@ export default async function calculateAPR({ vaultPrice, gauge, publicClient }: return []; } - console.log(`lowerAPR: ${Number(lowerAPR).toFixed(2)}%`); - console.log(`upperAPR: ${Number(upperAPR).toFixed(2)}%`); - return [lowerAPR, upperAPR]; } \ No newline at end of file diff --git a/lib/vault/getVault.ts b/lib/vault/getVault.ts index 1614521..7a04660 100644 --- a/lib/vault/getVault.ts +++ b/lib/vault/getVault.ts @@ -231,7 +231,7 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va decimals: foundGauge.decimals, logoURI: "/images/tokens/pop.svg", // wont be used, just here for consistency balance: foundGauge.balance, - price: entry.pricePerShare, + price: entry.pricePerShare * 1e9, } : undefined return { @@ -333,7 +333,7 @@ export async function getVault({ vault, account = ADDRESS_ZERO, client }: { vaul decimals: foundGauge.decimals, logoURI: "/images/tokens/pop.svg", // wont be used, just here for consistency balance: foundGauge.balance, - price: result.pricePerShare, + price: result.pricePerShare * 1e9, } : undefined } return result; diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index 1a8e038..0029a4c 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -46,7 +46,7 @@ export interface Order { * amount represents the maximum sell amount that can be executed. For partial * fill orders, this represents a component of the limit price fraction. */ - sellAmount: bigint | string; + sellAmount: string; /** * The order buy amount. * @@ -55,7 +55,7 @@ export interface Order { * represents the exact buy amount that will be executed. For partial fill * orders, this represents a component of the limit price fraction. */ - buyAmount: bigint; + buyAmount: string; /** * The timestamp this order is valid until */ @@ -69,7 +69,7 @@ export interface Order { /** * Fee to give to the protocol. */ - feeAmount: bigint; + feeAmount: string; /** * The order kind. */ @@ -313,17 +313,17 @@ export default async function zap({ sellToken, buyToken, amount, account, signer validTo: Math.floor(Date.now() / 1000) + timeout, partiallyFillable: false, kind: "sell", - sellAmountBeforeFee: String(amount) + sellAmountBeforeFee: amount.toLocaleString("fullwide", { useGrouping: false }) }), { headers: { 'Content-Type': 'application/json' } } )).data.quote - console.log({quote}) + console.log({ quote }) const order: Order = { sellToken: quote.sellToken, buyToken: quote.buyToken, receiver: quote.receiver, sellAmount: quote.sellAmount, - buyAmount: BigInt((Number(quote.buyAmount) * (10_000 - slippage)) / 10_000), // @dev we might need to format the number to cast it into a bigint + buyAmount: ((Number(quote.buyAmount) * (10_000 - slippage)) / 10_000).toLocaleString("fullwide", { useGrouping: false }), // @dev we might need to format the number to cast it into a bigint validTo: Math.floor(Date.now() / 1000) + timeout, feeAmount: quote.feeAmount, kind: quote.kind, @@ -332,7 +332,7 @@ export default async function zap({ sellToken, buyToken, amount, account, signer buyTokenBalance: quote.buyTokenBalance, appData: "0x0000000000000000000000000000000000000000000000000000000000000000" } - console.log({order}) + console.log({ order }) console.log("signing order") const signedOrder = await signOrder( order, @@ -340,6 +340,7 @@ export default async function zap({ sellToken, buyToken, amount, account, signer account, signer) console.log("posting order") + console.log({ signedOrder }) const orderId = (await axios.post( "https://api.cow.fi/mainnet/api/v1/orders", JSON.stringify({ From 4b9377e1d8e748ed27732ea8867c91baf4525760 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 3 Nov 2023 12:35:23 +0100 Subject: [PATCH 37/84] zapping in working --- components/vault/VaultInputs.tsx | 4 +- lib/vault/interactions.ts | 131 ++++++++++++++++++++++--------- lib/vault/zap.ts | 13 ++- 3 files changed, 105 insertions(+), 43 deletions(-) diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index 7ee918a..fda30c0 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -43,7 +43,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId // Zap Settings const [showModal, setShowModal] = useState(false) - const [timeout, setTimeout] = useState(60); // number of seconds a cow order is valid for + const [timeout, setTimeout] = useState(300); // number of seconds a cow order is valid for const [slippage, setSlippage] = useState(100); // In BPS 0 - 10_000 useEffect(() => { @@ -165,7 +165,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId } else { console.log("out zap") - + // TODO -- await fulfillment const preBal = asset.balance await vaultRedeem({ address: vault.address, diff --git a/lib/vault/interactions.ts b/lib/vault/interactions.ts index 3b6bd6f..3ee53f3 100644 --- a/lib/vault/interactions.ts +++ b/lib/vault/interactions.ts @@ -191,54 +191,107 @@ export async function zapIntoVault({ sellToken, asset, vault, account, amount, s console.log({ orderId }) // await fullfillment console.log("waiting for order fulfillment") - let depositAmount = 0; - setTimeout(async () => { - console.log("getting order receipt") - const orderData = (await axios.get(`https://api.cow.fi/mainnet/api/v1/orders/${orderId}`)).data - console.log({ orderData }) - depositAmount = Number(orderData.executedBuyAmount) - }, timeout) - console.log({ depositAmount }) - if (depositAmount === 0) { - // error happened - showErrorToast("Zap Order failed") - return false - } - console.log("approving vault") - // approve vault - await handleAllowance({ - token: asset, - inputAmount: depositAmount, - account, - spender: vault, - publicClient, - walletClient + let traded = false; + + let secondsPassed = 0; + setInterval(() => { console.log(secondsPassed); secondsPassed += 1 }, 1000) + + let success = false; + + publicClient.watchEvent({ + address: '0x9008D19f58AAbD9eD0D60971565AA8510560ab41', + event: { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": false, "internalType": "contract IERC20", "name": "sellToken", "type": "address" }, { "indexed": false, "internalType": "contract IERC20", "name": "buyToken", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "buyAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "feeAmount", "type": "uint256" }, { "indexed": false, "internalType": "bytes", "name": "orderUid", "type": "bytes" }], "name": "Trade", "type": "event" }, + onLogs: async (logs) => { + console.log(logs) + traded = true; + console.log("do stuff") + const found = logs.find(log => log.args.orderUid?.toLowerCase() === orderId.toLowerCase()) + if (found) { + console.log("MATCHED ORDER") + + let depositAmount = Number(found.args.buyAmount); + + console.log({ depositAmount }) + console.log("approving vault") + // approve vault + await handleAllowance({ + token: asset, + inputAmount: depositAmount, + account, + spender: vault, + publicClient, + walletClient + }) + console.log("vault deposit") + success = await vaultDeposit({ address: vault, account, amount: depositAmount, publicClient, walletClient }) + } + } }) - console.log("vault deposit") - return vaultDeposit({ address: vault, account, amount: depositAmount, publicClient, walletClient }) + + setTimeout(() => { + if (!traded) { + console.log("ERROR") + showErrorToast("Zap Order failed") + } + }, timeout * 1000) + + return success } // TODO -- error handling export async function zapIntoGauge({ sellToken, asset, router, vault, gauge, account, amount, slippage = 100, timeout = 60, publicClient, walletClient }: ZapIntoGaugeProps): Promise { showLoadingToast("Zapping into asset...") - const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient, slippage, timeout }) + console.log("zap") + const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient, slippage, timeout }) + console.log({ orderId }) // await fullfillment - let depositAmount = 0; - setTimeout(async () => { depositAmount = Number((await axios.get(`https://api.cow.fi/mainnet/api/v1/orders/${orderId}`)).data.executedBuyAmount) }, timeout) - - if (depositAmount === 0) return false // error happened - - // approve vault - await handleAllowance({ - token: asset, - inputAmount: depositAmount, - account, - spender: vault, - publicClient, - walletClient + console.log("waiting for order fulfillment") + + let traded = false; + + let secondsPassed = 0; + setInterval(() => { console.log(secondsPassed); secondsPassed += 1 }, 1000) + + let success = false; + + publicClient.watchEvent({ + address: '0x9008D19f58AAbD9eD0D60971565AA8510560ab41', + event: { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": false, "internalType": "contract IERC20", "name": "sellToken", "type": "address" }, { "indexed": false, "internalType": "contract IERC20", "name": "buyToken", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "buyAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "feeAmount", "type": "uint256" }, { "indexed": false, "internalType": "bytes", "name": "orderUid", "type": "bytes" }], "name": "Trade", "type": "event" }, + onLogs: async (logs) => { + console.log(logs) + traded = true; + console.log("do stuff") + const found = logs.find(log => log.args.orderUid?.toLowerCase() === orderId.toLowerCase()) + if (found) { + console.log("MATCHED ORDER") + + let depositAmount = Number(found.args.buyAmount); + + console.log({ depositAmount }) + console.log("approving vault") + // approve router + await handleAllowance({ + token: asset, + inputAmount: depositAmount, + account, + spender: router, + publicClient, + walletClient + }) + console.log("vault deposit and stake") + success = await vaultDepositAndStake({ address: router, account, vault, gauge, amount: depositAmount, publicClient, walletClient }) + } + } }) - return vaultDepositAndStake({ address: router, account, vault, gauge, amount: depositAmount, publicClient, walletClient }) + setTimeout(() => { + if (!traded) { + console.log("ERROR") + showErrorToast("Zap Order failed") + } + }, timeout * 1000) + + return success } \ No newline at end of file diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index 0029a4c..419e9ca 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -310,7 +310,7 @@ export default async function zap({ sellToken, buyToken, amount, account, signer buyToken, from: account, receiver: account, - validTo: Math.floor(Date.now() / 1000) + timeout, + validTo: Math.ceil(Date.now() / 1000) + timeout, partiallyFillable: false, kind: "sell", sellAmountBeforeFee: amount.toLocaleString("fullwide", { useGrouping: false }) @@ -324,7 +324,7 @@ export default async function zap({ sellToken, buyToken, amount, account, signer receiver: quote.receiver, sellAmount: quote.sellAmount, buyAmount: ((Number(quote.buyAmount) * (10_000 - slippage)) / 10_000).toLocaleString("fullwide", { useGrouping: false }), // @dev we might need to format the number to cast it into a bigint - validTo: Math.floor(Date.now() / 1000) + timeout, + validTo: Math.ceil(Date.now() / 1000) + timeout, feeAmount: quote.feeAmount, kind: quote.kind, partiallyFillable: false, @@ -341,6 +341,15 @@ export default async function zap({ sellToken, buyToken, amount, account, signer signer) console.log("posting order") console.log({ signedOrder }) + console.log({ + orderReq: { + ...order, + signature: signedOrder.data, + from: "0x22f5413C075Ccd56D575A54763831C4c27A37Bdb", + signingScheme: quote.signingScheme, + appData: "0x0000000000000000000000000000000000000000000000000000000000000000", + } + }) const orderId = (await axios.post( "https://api.cow.fi/mainnet/api/v1/orders", JSON.stringify({ From 7ee4dde88dface11846341b3980207dc201edf5b Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 3 Nov 2023 13:06:10 +0100 Subject: [PATCH 38/84] zap out --- components/vault/VaultInputs.tsx | 46 ++++++++++++++++++++++++++------ lib/vault/interactions.ts | 14 +++++----- lib/vault/zap.ts | 8 +++--- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index fda30c0..1934929 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -15,6 +15,7 @@ import { ERC20Abi } from "@/lib/constants"; import zap from "@/lib/vault/zap"; import Modal from "../modal/Modal"; import InputNumber from "../input/InputNumber"; +import { showErrorToast, showSuccessToast } from "@/lib/toasts"; const { VaultRouter: VAULT_ROUTER } = getVeAddresses() const COWSWAP_RELAYER = "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110" @@ -43,7 +44,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId // Zap Settings const [showModal, setShowModal] = useState(false) - const [timeout, setTimeout] = useState(300); // number of seconds a cow order is valid for + const [tradeTimeout, setTradeTimeout] = useState(300); // number of seconds a cow order is valid for const [slippage, setSlippage] = useState(100); // In BPS 0 - 10_000 useEffect(() => { @@ -175,15 +176,44 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId walletClient }) const postBal = Number(await publicClient.readContract({ address: asset.address, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) - zap({ + const orderId = await zap({ account, signer: walletClient, sellToken: asset.address, buyToken: outputToken.address, amount: postBal - preBal, slippage, - timeout + tradeTimeout }) + console.log("waiting for order fulfillment") + + let traded = false; + + let secondsPassed = 0; + setInterval(() => { console.log(secondsPassed); secondsPassed += 1 }, 1000) + + publicClient.watchEvent({ + address: '0x9008D19f58AAbD9eD0D60971565AA8510560ab41', + event: { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": false, "internalType": "contract IERC20", "name": "sellToken", "type": "address" }, { "indexed": false, "internalType": "contract IERC20", "name": "buyToken", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "buyAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "feeAmount", "type": "uint256" }, { "indexed": false, "internalType": "bytes", "name": "orderUid", "type": "bytes" }], "name": "Trade", "type": "event" }, + onLogs: async (logs) => { + console.log(logs) + traded = true; + console.log("do stuff") + const found = logs.find(log => log.args.orderUid?.toLowerCase() === orderId.toLowerCase()) + if (found) { + console.log("MATCHED ORDER") + showSuccessToast("Zapped out!") + } + } + }) + + setTimeout(() => { + if (!traded) { + console.log("ERROR") + showErrorToast("Zap Order failed") + } + }, tradeTimeout * 1000) + } break; case gauge?.address: @@ -254,7 +284,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId buyToken: outputToken.address, amount: postBal - preBal, slippage, - timeout + tradeTimeout }) } break; @@ -279,7 +309,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId account, amount: (val * (10 ** inputToken.decimals)), slippage, - timeout, + tradeTimeout, publicClient, walletClient }) @@ -303,7 +333,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId account, amount: (val * (10 ** inputToken.decimals)), slippage, - timeout, + tradeTimeout, publicClient, walletClient }) @@ -333,8 +363,8 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId

Timeout (in seconds)

setTimeout(Number(e.currentTarget.value))} + value={tradeTimeout} + onChange={(e) => setTradeTimeout(Number(e.currentTarget.value))} />
diff --git a/lib/vault/interactions.ts b/lib/vault/interactions.ts index 3ee53f3..5c294a1 100644 --- a/lib/vault/interactions.ts +++ b/lib/vault/interactions.ts @@ -50,7 +50,7 @@ interface ZapIntoVaultProps { account: Address; amount: number; slippage?: number; - timeout?: number; + tradeTimeout?: number; publicClient: PublicClient; walletClient: WalletClient; } @@ -184,10 +184,10 @@ export async function vaultUnstakeAndWithdraw({ address, account, amount, vault, } // TODO -- error handling -export async function zapIntoVault({ sellToken, asset, vault, account, amount, slippage = 100, timeout = 60, publicClient, walletClient }: ZapIntoVaultProps): Promise { +export async function zapIntoVault({ sellToken, asset, vault, account, amount, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapIntoVaultProps): Promise { showLoadingToast("Zapping into asset...") console.log("zap") - const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient, slippage, timeout }) + const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient, slippage, tradeTimeout }) console.log({ orderId }) // await fullfillment console.log("waiting for order fulfillment") @@ -234,17 +234,17 @@ export async function zapIntoVault({ sellToken, asset, vault, account, amount, s console.log("ERROR") showErrorToast("Zap Order failed") } - }, timeout * 1000) + }, tradeTimeout * 1000) return success } // TODO -- error handling -export async function zapIntoGauge({ sellToken, asset, router, vault, gauge, account, amount, slippage = 100, timeout = 60, publicClient, walletClient }: ZapIntoGaugeProps): Promise { +export async function zapIntoGauge({ sellToken, asset, router, vault, gauge, account, amount, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapIntoGaugeProps): Promise { showLoadingToast("Zapping into asset...") console.log("zap") - const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient, slippage, timeout }) + const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient, slippage, tradeTimeout }) console.log({ orderId }) // await fullfillment console.log("waiting for order fulfillment") @@ -291,7 +291,7 @@ export async function zapIntoGauge({ sellToken, asset, router, vault, gauge, acc console.log("ERROR") showErrorToast("Zap Order failed") } - }, timeout * 1000) + }, tradeTimeout * 1000) return success } \ No newline at end of file diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index 419e9ca..13694c5 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -298,10 +298,10 @@ interface ZapProps { account: Address; signer: WalletClient; slippage?: number; // slippage allowance in BPS - timeout?: number; // in s + tradeTimeout?: number; // in s } -export default async function zap({ sellToken, buyToken, amount, account, signer, slippage = 100, timeout = 60 }: ZapProps): Promise { +export default async function zap({ sellToken, buyToken, amount, account, signer, slippage = 100, tradeTimeout = 60 }: ZapProps): Promise { console.log("getting quote") const quote = (await axios.post( "https://api.cow.fi/mainnet/api/v1/quote", @@ -310,7 +310,7 @@ export default async function zap({ sellToken, buyToken, amount, account, signer buyToken, from: account, receiver: account, - validTo: Math.ceil(Date.now() / 1000) + timeout, + validTo: Math.ceil(Date.now() / 1000) + tradeTimeout, partiallyFillable: false, kind: "sell", sellAmountBeforeFee: amount.toLocaleString("fullwide", { useGrouping: false }) @@ -324,7 +324,7 @@ export default async function zap({ sellToken, buyToken, amount, account, signer receiver: quote.receiver, sellAmount: quote.sellAmount, buyAmount: ((Number(quote.buyAmount) * (10_000 - slippage)) / 10_000).toLocaleString("fullwide", { useGrouping: false }), // @dev we might need to format the number to cast it into a bigint - validTo: Math.ceil(Date.now() / 1000) + timeout, + validTo: Math.ceil(Date.now() / 1000) + tradeTimeout, feeAmount: quote.feeAmount, kind: quote.kind, partiallyFillable: false, From 53ac29d05e1b1b03a02738cee20fec70cf17c951 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 3 Nov 2023 13:18:55 +0100 Subject: [PATCH 39/84] zap available design --- components/vault/AssetWithName.tsx | 32 ++++++++++++++++-------------- components/vault/SmartVault.tsx | 11 +++++++++- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/components/vault/AssetWithName.tsx b/components/vault/AssetWithName.tsx index 1dc6484..942bcd4 100644 --- a/components/vault/AssetWithName.tsx +++ b/components/vault/AssetWithName.tsx @@ -23,20 +23,22 @@ export default function AssetWithName({ vault }: { vault: Vault }) { const protocolName = vault.metadata.optionalMetadata?.protocol?.name const protocolIcon = protocolName ? protocolNameToLlamaProtocol[protocolName] : "popcorn" - return
-
- - + return ( +
+
+ + +
+

+ {vault.metadata.vaultName || vault.asset.name} +

+
+ +

{protocolName}

+
-

- {vault.metadata.vaultName || vault.asset.name} -

-
- -

{protocolName}

-
-
+ ) } \ No newline at end of file diff --git a/components/vault/SmartVault.tsx b/components/vault/SmartVault.tsx index 4454020..8fc0ae2 100644 --- a/components/vault/SmartVault.tsx +++ b/components/vault/SmartVault.tsx @@ -70,10 +70,15 @@ export default function SmartVault({ header={
-
+
+ +
+

{zapAssets && zapAssets?.length > 0 && "⚡ Zap available"}

+
+

Your Wallet

@@ -112,6 +117,10 @@ export default function SmartVault({

+
+

{zapAssets && zapAssets?.length > 0 && "⚡ Zap available"}

+
+
} > From d87c169c6c7d6142baa67df7dcd22e8cfdffad03 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 3 Nov 2023 14:34:49 +0100 Subject: [PATCH 40/84] using actual receiver --- lib/vault/zap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index 13694c5..223e3cf 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -345,7 +345,7 @@ export default async function zap({ sellToken, buyToken, amount, account, signer orderReq: { ...order, signature: signedOrder.data, - from: "0x22f5413C075Ccd56D575A54763831C4c27A37Bdb", + from: quote.receiver, signingScheme: quote.signingScheme, appData: "0x0000000000000000000000000000000000000000000000000000000000000000", } @@ -355,7 +355,7 @@ export default async function zap({ sellToken, buyToken, amount, account, signer JSON.stringify({ ...order, signature: signedOrder.data, - from: "0x22f5413C075Ccd56D575A54763831C4c27A37Bdb", + from: quote.receiver, signingScheme: quote.signingScheme, appData: "0x0000000000000000000000000000000000000000000000000000000000000000", }), From b06d1cf7291898ece79a112f47a4bb90fe6a3857 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 3 Nov 2023 14:51:49 +0100 Subject: [PATCH 41/84] remove ohm-dai --- pages/vaults.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 006c6b0..d7c3bcf 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -26,6 +26,7 @@ export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2 "0xcBb5A4a829bC086d062e4af8Eba69138aa61d567", // yOhmFrax factory "0x9E237F8A3319b47934468e0b74F0D5219a967aB8", // yABoosted Balancer "0x860b717B360378E44A241b23d8e8e171E0120fF0", // R/Dai + "0xBae30fBD558A35f147FDBaeDbFF011557d3C8bd2", // 50OHM - 50 DAI ] const { oPOP: OPOP } = getVeAddresses(); From 574683848bd8cb7b2aa1651d1aa2bef3840cba82 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 3 Nov 2023 16:37:54 +0100 Subject: [PATCH 42/84] mutate page on normal actions --- components/vault/SmartVault.tsx | 5 ++ components/vault/VaultInputs.tsx | 24 ++++++--- lib/gauges/interactions.ts | 10 +++- pages/vaults.tsx | 84 ++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 10 deletions(-) diff --git a/components/vault/SmartVault.tsx b/components/vault/SmartVault.tsx index 8fc0ae2..fb5e6c7 100644 --- a/components/vault/SmartVault.tsx +++ b/components/vault/SmartVault.tsx @@ -12,6 +12,7 @@ import TokenIcon from "@/components/common/TokenIcon"; import Title from "@/components/common/Title"; import { Token, VaultData } from "@/lib/types"; import calculateAPR from "@/lib/gauges/calculateGaugeAPR"; +import { MutateTokenBalanceProps } from "pages/vaults"; function getTokenOptions(vaultData: VaultData, zapAssets?: Token[]): Token[] { @@ -24,11 +25,13 @@ function getTokenOptions(vaultData: VaultData, zapAssets?: Token[]): Token[] { export default function SmartVault({ vaultData, searchString, + mutateTokenBalance, zapAssets, deployer, }: { vaultData: VaultData, searchString: string, + mutateTokenBalance: (props: MutateTokenBalanceProps) => void zapAssets?: Token[], deployer?: Address }) { @@ -134,6 +137,7 @@ export default function SmartVault({ gauge={gauge} tokenOptions={tokenOptions} chainId={vaultData.chainId} + mutateTokenBalance={mutateTokenBalance} />
@@ -157,6 +161,7 @@ export default function SmartVault({ {/*
*/} +

{vault.address}

diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index 1934929..df3018c 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -16,6 +16,7 @@ import zap from "@/lib/vault/zap"; import Modal from "../modal/Modal"; import InputNumber from "../input/InputNumber"; import { showErrorToast, showSuccessToast } from "@/lib/toasts"; +import { MutateTokenBalanceProps } from "pages/vaults"; const { VaultRouter: VAULT_ROUTER } = getVeAddresses() const COWSWAP_RELAYER = "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110" @@ -25,10 +26,11 @@ interface VaultInputsProps { asset: Token; gauge?: Token; tokenOptions: Token[]; - chainId: number + chainId: number; + mutateTokenBalance: (props: MutateTokenBalanceProps) => void; } -export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId }: VaultInputsProps): JSX.Element { +export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId, mutateTokenBalance }: VaultInputsProps): JSX.Element { const publicClient = usePublicClient(); const { data: walletClient } = useWalletClient() const { address: account } = useAccount(); @@ -93,13 +95,14 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId publicClient, walletClient }) - vaultDeposit({ + const success = await vaultDeposit({ address: vault.address, account, amount: (val * (10 ** inputToken.decimals)), publicClient, walletClient }) + if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) } else if (outputToken.address === gauge?.address) { console.log("out gauge") @@ -111,7 +114,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId publicClient, walletClient }) - vaultDepositAndStake({ + const success = await vaultDepositAndStake({ address: VAULT_ROUTER, account, amount: (val * (10 ** inputToken.decimals)), @@ -120,6 +123,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId publicClient, walletClient }) + if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) } else { console.log("out error") @@ -131,13 +135,14 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId console.log("in vault") if (outputToken.address === asset.address) { console.log("out asset") - vaultRedeem({ + const success = await vaultRedeem({ address: vault.address, account, amount: (val * (10 ** inputToken.decimals)), publicClient, walletClient }) + if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) } else if (outputToken.address === gauge?.address) { console.log("out gauge") @@ -149,7 +154,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId publicClient, walletClient }) - gaugeDeposit({ + const success = await gaugeDeposit({ address: gauge.address, amount: (val * (10 ** inputToken.decimals)), account, @@ -158,6 +163,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId walletClient } }) + if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) } else if (outputToken.address === vault.address) { console.log("out error") @@ -228,7 +234,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId publicClient, walletClient }) - vaultUnstakeAndWithdraw({ + const success = await vaultUnstakeAndWithdraw({ address: VAULT_ROUTER, account, amount: (val * (10 ** inputToken.decimals)), @@ -237,10 +243,11 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId publicClient, walletClient }) + if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) } else if (outputToken.address === vault.address) { console.log("out vault") - gaugeWithdraw({ + const success = await gaugeWithdraw({ address: gauge?.address as Address, amount: (val * (10 ** inputToken.decimals)), account, @@ -249,6 +256,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId walletClient } }) + if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) } else if (outputToken.address === gauge?.address) { console.log("out error") diff --git a/lib/gauges/interactions.ts b/lib/gauges/interactions.ts index 50f0b42..d883ed6 100644 --- a/lib/gauges/interactions.ts +++ b/lib/gauges/interactions.ts @@ -228,7 +228,7 @@ interface GaugeInteractionProps { clients: Clients; } -export async function gaugeDeposit({ address, amount, account, clients }: GaugeInteractionProps) { +export async function gaugeDeposit({ address, amount, account, clients }: GaugeInteractionProps): Promise { showLoadingToast("Staking into Gauge...") const { request, success, error: simulationError } = await simulateCall({ @@ -247,15 +247,18 @@ export async function gaugeDeposit({ address, amount, account, clients }: GaugeI const hash = await clients.walletClient.writeContract(request) const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) showSuccessToast("Staked into Gauge successful!") + return true } catch (error: any) { showErrorToast(error.shortMessage) + return false; } } else { showErrorToast(simulationError) + return false; } } -export async function gaugeWithdraw({ address, amount, account, clients }: GaugeInteractionProps) { +export async function gaugeWithdraw({ address, amount, account, clients }: GaugeInteractionProps): Promise { showLoadingToast("Unstaking from Gauge...") const { request, success, error: simulationError } = await simulateCall({ @@ -274,10 +277,13 @@ export async function gaugeWithdraw({ address, amount, account, clients }: Gauge const hash = await clients.walletClient.writeContract(request) const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) showSuccessToast("Unstaked from Gauge successful!") + return true } catch (error: any) { showErrorToast(error.shortMessage) + return false; } } else { showErrorToast(simulationError) + return false; } } \ No newline at end of file diff --git a/pages/vaults.tsx b/pages/vaults.tsx index d7c3bcf..4590612 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -19,6 +19,7 @@ import { getVeAddresses } from "@/lib/utils/addresses"; import { claimOPop } from "@/lib/oPop/interactions"; import { WalletClient } from "viem"; import getZapAssets, { getAvailableZapAssets } from "@/lib/utils/getZapAssets"; +import { ERC20Abi, VaultAbi } from "@/lib/constants"; export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2fD2C18f79F93eF299B20B681Ab2a61f5F28A6fF", "0xDFf04Efb38465369fd1A2E8B40C364c22FfEA340", "0xd4D442AC311d918272911691021E6073F620eb07", //@dev for some reason the live 3Crypto yVault isnt picked up by the yearnAdapter nor the yearnFactoryAdapter @@ -31,6 +32,15 @@ export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2 const { oPOP: OPOP } = getVeAddresses(); +const NETWORKS_SUPPORTING_ZAP = [1] + +export interface MutateTokenBalanceProps { + inputToken: Address; + outputToken: Address; + vault: Address; + chainId: number; + account: Address; +} const Vaults: NextPage = () => { const { address: account } = useAccount(); @@ -97,6 +107,79 @@ const Vaults: NextPage = () => { }); }, [account]); + + async function mutateTokenBalance({ inputToken, outputToken, vault, chainId, account }: MutateTokenBalanceProps) { + const data = await publicClient.multicall({ + contracts: [ + { + address: inputToken, + abi: ERC20Abi, + functionName: "balanceOf", + args: [account] + }, + { + address: outputToken, + abi: ERC20Abi, + functionName: "balanceOf", + args: [account] + }, + { + address: vault, + abi: VaultAbi, + functionName: 'totalAssets' + }, + { + address: vault, + abi: VaultAbi, + functionName: 'totalSupply' + }], + allowFailure: false + }) + + // Modify zap assets + if (NETWORKS_SUPPORTING_ZAP.includes(chainId)) { + const zapAssetFound = zapAssets[chainId].find(asset => asset.address === inputToken || asset.address === outputToken) // @dev -- might need to copy the state here already to avoid modifing a pointer + if (zapAssetFound) { + zapAssetFound.balance = zapAssetFound.address === inputToken ? Number(data[0]) : Number(data[1]) + setZapAssets({ ...zapAssets, [chainId]: [...zapAssets[chainId], zapAssetFound] }) + } + } + + // Modify vaults, assets and gauges + const newVaultState: VaultData[] = [...vaults] + newVaultState.forEach(vaultData => { + if (vaultData.chainId === chainId) { + // Modify vault pricing and tvl + if (vaultData.address === vault) { + const assetsPerShare = Number(data[3]) > 0 ? Number(data[2]) / Number(data[3]) : Number(1e-9) + const pricePerShare = assetsPerShare * vaultData.assetPrice + + vaultData.totalAssets = Number(data[2]) + vaultData.totalSupply = Number(data[3]) + vaultData.assetsPerShare = assetsPerShare + vaultData.pricePerShare = pricePerShare + vaultData.tvl = (Number(data[3]) * pricePerShare) / (10 ** vaultData.asset.decimals) + vaultData.vault.price = pricePerShare * 1e9 + + if (vaultData.gauge) vaultData.gauge.price = pricePerShare * 1e9 + } + // Adjust vault balance + if (vaultData.vault.address === inputToken || vaultData.vault.address === outputToken) { + vaultData.vault.balance = vaultData.vault.address === inputToken ? Number(data[0]) : Number(data[1]) + } + // Adjust asset balance + if (vaultData.asset.address === inputToken || vaultData.asset.address === outputToken) { + vaultData.asset.balance = vaultData.asset.address === inputToken ? Number(data[0]) : Number(data[1]) + } + // Adjust gauge balance + if (vaultData.gauge?.address === inputToken || vaultData.gauge?.address === outputToken) { + vaultData.gauge.balance = vaultData.gauge.address === inputToken ? Number(data[0]) : Number(data[1]) + } + } + }) + setVaults(newVaultState) + } + return (
@@ -190,6 +273,7 @@ const Vaults: NextPage = () => { Date: Tue, 7 Nov 2023 11:52:48 +0100 Subject: [PATCH 43/84] hide yCRV --- pages/vaults.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 4590612..152e0bb 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -28,6 +28,7 @@ export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2 "0x9E237F8A3319b47934468e0b74F0D5219a967aB8", // yABoosted Balancer "0x860b717B360378E44A241b23d8e8e171E0120fF0", // R/Dai "0xBae30fBD558A35f147FDBaeDbFF011557d3C8bd2", // 50OHM - 50 DAI + "0x759281a408A48bfe2029D259c23D7E848A7EA1bC", // yCRV ] const { oPOP: OPOP } = getVeAddresses(); From 2f1c685b60e50045bbdebe7b703fc55c0b9b8255 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 7 Nov 2023 12:05:41 +0100 Subject: [PATCH 44/84] wip - zapping --- components/page/Page.tsx | 2 +- components/vault/VaultInputs.tsx | 4 +- lib/vault/interactions.ts | 98 ++++++++++++++++---------------- lib/vault/zap.ts | 34 +++++++---- pages/vepop.tsx | 2 - 5 files changed, 74 insertions(+), 66 deletions(-) diff --git a/components/page/Page.tsx b/components/page/Page.tsx index dc547c8..c91ef02 100644 --- a/components/page/Page.tsx +++ b/components/page/Page.tsx @@ -32,7 +32,7 @@ export default function Page({ children }: { children: JSX.Element }): JSX.Eleme return ( <> -
+
diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index df3018c..e576695 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -310,7 +310,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId publicClient, walletClient }) - zapIntoVault({ + const success = zapIntoVault({ sellToken: inputToken.address, asset: asset.address, vault: vault.address, @@ -332,7 +332,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId publicClient, walletClient }) - zapIntoGauge({ + const success = zapIntoGauge({ sellToken: inputToken.address, router: VAULT_ROUTER, asset: asset.address, diff --git a/lib/vault/interactions.ts b/lib/vault/interactions.ts index 5c294a1..c909596 100644 --- a/lib/vault/interactions.ts +++ b/lib/vault/interactions.ts @@ -188,55 +188,55 @@ export async function zapIntoVault({ sellToken, asset, vault, account, amount, s showLoadingToast("Zapping into asset...") console.log("zap") const orderId = await zap({ sellToken, buyToken: asset, amount, account, signer: walletClient, slippage, tradeTimeout }) - console.log({ orderId }) - // await fullfillment - console.log("waiting for order fulfillment") - - let traded = false; - - let secondsPassed = 0; - setInterval(() => { console.log(secondsPassed); secondsPassed += 1 }, 1000) - - let success = false; - - publicClient.watchEvent({ - address: '0x9008D19f58AAbD9eD0D60971565AA8510560ab41', - event: { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": false, "internalType": "contract IERC20", "name": "sellToken", "type": "address" }, { "indexed": false, "internalType": "contract IERC20", "name": "buyToken", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "buyAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "feeAmount", "type": "uint256" }, { "indexed": false, "internalType": "bytes", "name": "orderUid", "type": "bytes" }], "name": "Trade", "type": "event" }, - onLogs: async (logs) => { - console.log(logs) - traded = true; - console.log("do stuff") - const found = logs.find(log => log.args.orderUid?.toLowerCase() === orderId.toLowerCase()) - if (found) { - console.log("MATCHED ORDER") - - let depositAmount = Number(found.args.buyAmount); - - console.log({ depositAmount }) - console.log("approving vault") - // approve vault - await handleAllowance({ - token: asset, - inputAmount: depositAmount, - account, - spender: vault, - publicClient, - walletClient - }) - console.log("vault deposit") - success = await vaultDeposit({ address: vault, account, amount: depositAmount, publicClient, walletClient }) - } - } - }) - - setTimeout(() => { - if (!traded) { - console.log("ERROR") - showErrorToast("Zap Order failed") - } - }, tradeTimeout * 1000) - - return success + // console.log({ orderId }) + // // await fullfillment + // console.log("waiting for order fulfillment") + + // let traded = false; + + // let secondsPassed = 0; + // setInterval(() => { console.log(secondsPassed); secondsPassed += 1 }, 1000) + + // let success = false; + + // publicClient.watchEvent({ + // address: '0x9008D19f58AAbD9eD0D60971565AA8510560ab41', + // event: { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": false, "internalType": "contract IERC20", "name": "sellToken", "type": "address" }, { "indexed": false, "internalType": "contract IERC20", "name": "buyToken", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "buyAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "feeAmount", "type": "uint256" }, { "indexed": false, "internalType": "bytes", "name": "orderUid", "type": "bytes" }], "name": "Trade", "type": "event" }, + // onLogs: async (logs) => { + // console.log(logs) + // traded = true; + // console.log("do stuff") + // const found = logs.find(log => log.args.orderUid?.toLowerCase() === orderId.toLowerCase()) + // if (found) { + // console.log("MATCHED ORDER") + + // let depositAmount = Number(found.args.buyAmount); + + // console.log({ depositAmount }) + // console.log("approving vault") + // // approve vault + // await handleAllowance({ + // token: asset, + // inputAmount: depositAmount, + // account, + // spender: vault, + // publicClient, + // walletClient + // }) + // console.log("vault deposit") + // success = await vaultDeposit({ address: vault, account, amount: depositAmount, publicClient, walletClient }) + // } + // } + // }) + + // setTimeout(() => { + // if (!traded) { + // console.log("ERROR") + // showErrorToast("Zap Order failed") + // } + // }, tradeTimeout * 1000) + + return false } // TODO -- error handling diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index 223e3cf..fe2434d 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -303,6 +303,16 @@ interface ZapProps { export default async function zap({ sellToken, buyToken, amount, account, signer, slippage = 100, tradeTimeout = 60 }: ZapProps): Promise { console.log("getting quote") + console.log({ + sellToken, + buyToken, + from: account, + receiver: account, + validTo: Math.ceil(Date.now() / 1000) + tradeTimeout, + partiallyFillable: false, + kind: "sell", + sellAmountBeforeFee: amount.toLocaleString("fullwide", { useGrouping: false }) + }) const quote = (await axios.post( "https://api.cow.fi/mainnet/api/v1/quote", JSON.stringify({ @@ -350,16 +360,16 @@ export default async function zap({ sellToken, buyToken, amount, account, signer appData: "0x0000000000000000000000000000000000000000000000000000000000000000", } }) - const orderId = (await axios.post( - "https://api.cow.fi/mainnet/api/v1/orders", - JSON.stringify({ - ...order, - signature: signedOrder.data, - from: quote.receiver, - signingScheme: quote.signingScheme, - appData: "0x0000000000000000000000000000000000000000000000000000000000000000", - }), - { headers: { 'Content-Type': 'application/json' } } - )).data - return orderId + // const orderId = (await axios.post( + // "https://api.cow.fi/mainnet/api/v1/orders", + // JSON.stringify({ + // ...order, + // signature: signedOrder.data, + // from: quote.receiver, + // signingScheme: quote.signingScheme, + // appData: "0x0000000000000000000000000000000000000000000000000000000000000000", + // }), + // { headers: { 'Content-Type': 'application/json' } } + // )).data + return "orderId" } \ No newline at end of file diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 9fab4c1..59b1327 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -133,5 +133,3 @@ function VePopContainer() { export default function VePOP() { return } - -function noOp() { } From 7153da3f4ce7fcfeb12d9fc7961a92eb83cf6d00 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 9 Nov 2023 14:28:00 +0100 Subject: [PATCH 45/84] added vcx migration page --- lib/constants/abi/VCX.ts | 448 +++++++++++++++++++++++++++++++++++ lib/constants/abi/index.ts | 3 +- lib/types.ts | 1 + lib/utils/addresses/index.ts | 3 +- pages/migration.tsx | 182 ++++++++++++++ public/images/tokens/vcx.svg | 8 + 6 files changed, 643 insertions(+), 2 deletions(-) create mode 100644 lib/constants/abi/VCX.ts create mode 100644 pages/migration.tsx create mode 100644 public/images/tokens/vcx.svg diff --git a/lib/constants/abi/VCX.ts b/lib/constants/abi/VCX.ts new file mode 100644 index 0000000..4b3d28b --- /dev/null +++ b/lib/constants/abi/VCX.ts @@ -0,0 +1,448 @@ +export const VCXAbi = [ + { + "inputs": [ + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "string", + "name": "_symbol", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "popAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "vcxAmount", + "type": "uint256" + } + ], + "name": "Migrated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldTs", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newTs", + "type": "uint256" + } + ], + "name": "UpdatedEndOfMigrationTs", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "endOfMigrationTs", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "migrate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "ts", + "type": "uint256" + } + ], + "name": "setEndOfMigrationTs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] as const \ No newline at end of file diff --git a/lib/constants/abi/index.ts b/lib/constants/abi/index.ts index 96fe83e..5c4d900 100644 --- a/lib/constants/abi/index.ts +++ b/lib/constants/abi/index.ts @@ -6,4 +6,5 @@ export * from "./Gauge"; export * from "./VotingEscrow"; export * from "./BalancerOracle"; export * from "./OPop"; -export * from "./Minter"; \ No newline at end of file +export * from "./Minter"; +export * from "./VCX"; \ No newline at end of file diff --git a/lib/types.ts b/lib/types.ts index 808629b..29376f3 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -12,6 +12,7 @@ export type Token = { }; export type veAddresses = { + VCX: Address; POP: Address; WETH: Address; USDC: Address; diff --git a/lib/utils/addresses/index.ts b/lib/utils/addresses/index.ts index 0256ae7..9fd8a34 100644 --- a/lib/utils/addresses/index.ts +++ b/lib/utils/addresses/index.ts @@ -1,11 +1,12 @@ import { veAddresses } from "lib/types"; const VeAddresses = { + VCX: "0x27af2Cf1C25114eF3b9bb43Fcef601dC6D959226", POP: "0xD0Cd466b34A24fcB2f87676278AF2005Ca8A78c4", WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", USDC: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", DAI: "0x6B175474E89094C44Da98b954EedeAC495271d0F", - BalancerPool: "0xd5A44704beFD1CfCCa67F7bc498a7654cC092959", + BalancerPool: "0xd5A44704beFD1CfCCa67F7bc498a7654cC092959", BalancerOracle: "0x0124a1697e207De725cd1e7b40aa9b0Ed37Ed5de", oPOP: "0xDfFA4D3ed6B433810354430464a5C00b6ea0F1dF", VaultRegistry: "0x007318Dc89B314b47609C684260CfbfbcD412864", diff --git a/pages/migration.tsx b/pages/migration.tsx new file mode 100644 index 0000000..6b7737e --- /dev/null +++ b/pages/migration.tsx @@ -0,0 +1,182 @@ +import MainActionButton from "@/components/button/MainActionButton"; +import InputTokenWithError from "@/components/input/InputTokenWithError"; +import { handleAllowance } from "@/lib/approve"; +import { VCXAbi } from "@/lib/constants"; +import { showErrorToast, showLoadingToast, showSuccessToast } from "@/lib/toasts"; +import { SimulationResponse } from "@/lib/types"; +import { getVeAddresses } from "@/lib/utils/addresses"; +import { validateInput } from "@/lib/utils/helpers"; +import { ArrowDownIcon } from "@heroicons/react/24/outline"; +import { useState } from "react"; +import { Address, WalletClient, formatEther } from "viem"; +import { PublicClient, useAccount, useBalance, useNetwork, usePublicClient, useSwitchNetwork, useWalletClient } from "wagmi"; + +const { VCX, POP } = getVeAddresses(); + +interface SimulateProps { + address: Address; + account: Address; + amount: number; + publicClient: PublicClient; +} + +interface MigrateWriteProps { + address: Address; + account: Address; + amount: number; + publicClient: PublicClient; + walletClient: WalletClient; +} + +async function simulate({ address, account, amount, publicClient }: SimulateProps): Promise { + try { + const { request } = await publicClient.simulateContract({ + account, + address, + abi: VCXAbi, + // @ts-ignore + functionName: "migrate", + // @dev Since numbers get converted to strings like 1e+21 or similar we need to convert it back to numbers like 10000000000000 and than cast them into BigInts + args: [account, BigInt(Number(amount).toLocaleString("fullwide", { useGrouping: false }))] + }) + return { request: request, success: true, error: null } + } catch (error: any) { + return { request: null, success: false, error: error.shortMessage } + } +} + +async function migrate({ address, account, amount, publicClient, walletClient }: MigrateWriteProps): Promise { + showLoadingToast("Migrating POP to VCX...") + + const { request, success, error: simulationError } = await simulate({ address, account, amount, publicClient }) + + if (success) { + try { + const hash = await walletClient.writeContract(request) + const receipt = await publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast("Migration sucessful!") + return true; + } catch (error: any) { + showErrorToast(error.shortMessage) + return false; + } + } else { + showErrorToast(simulationError) + return false; + } +} + +export default function Migration(): JSX.Element { + const { address: account } = useAccount(); + const publicClient = usePublicClient() + const { data: walletClient } = useWalletClient() + const { chain } = useNetwork(); + const { switchNetwork } = useSwitchNetwork(); + + const { data: vcxBal } = useBalance({ chainId: 1, address: account, token: VCX, watch: true }) + const { data: popBal } = useBalance({ chainId: 1, address: account, token: POP, watch: true }) + + const [inputBalance, setInputBalance] = useState("0"); + + function handleChangeInput(e: any) { + const value = e.currentTarget.value + setInputBalance(validateInput(value).isValid ? value : "0"); + }; + + async function handleMainAction() { + const val = Number(inputBalance) + if (val === 0 || !account || !walletClient) return; + + if (chain?.id !== 1) switchNetwork?.(1); + + await handleAllowance({ + token: POP, + inputAmount: (val * (10 ** 18)), + account, + spender: VCX, + publicClient, + walletClient + }) + migrate({ + address: VCX, + account, + amount: (val * (10 ** 18)), + publicClient, + walletClient + }) + } + + return ( + <> +
+

+ POP Migration +

+

+ Migrate your POP to VCX +

+
+ {(vcxBal && popBal) ? +
+ { }} + onMaxClick={() => handleChangeInput({ currentTarget: { value: formatEther(popBal.value) } })} + chainId={1} + value={inputBalance} + onChange={handleChangeInput} + selectedToken={{ + address: POP, + name: "POP", + symbol: "POP", + decimals: 18, + logoURI: "", + balance: Number(popBal.value), + price: 1, + }} + errorMessage={""} + tokenList={[]} + allowInput + /> +
+ + { }} + onMaxClick={() => { }} + chainId={1} + value={(Number(inputBalance) * 10) || 0} + onChange={() => { }} + selectedToken={{ + address: VCX, + name: "VCX", + symbol: "VCX", + decimals: 18, + logoURI: "/images/tokens/vcx.svg", + balance: 0, + price: 1, + }} + errorMessage={""} + tokenList={[]} + allowSelection={false} + allowInput={false} + /> + +
+ :

Loading...

+ } + + ) + +} \ No newline at end of file diff --git a/public/images/tokens/vcx.svg b/public/images/tokens/vcx.svg new file mode 100644 index 0000000..fdaac91 --- /dev/null +++ b/public/images/tokens/vcx.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file From a7e76a07677915af0a471519d1fc9439fe844511 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 9 Nov 2023 14:34:41 +0100 Subject: [PATCH 46/84] render when no address --- pages/migration.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/migration.tsx b/pages/migration.tsx index 6b7737e..b921032 100644 --- a/pages/migration.tsx +++ b/pages/migration.tsx @@ -8,7 +8,7 @@ import { getVeAddresses } from "@/lib/utils/addresses"; import { validateInput } from "@/lib/utils/helpers"; import { ArrowDownIcon } from "@heroicons/react/24/outline"; import { useState } from "react"; -import { Address, WalletClient, formatEther } from "viem"; +import { Address, WalletClient, formatEther, zeroAddress } from "viem"; import { PublicClient, useAccount, useBalance, useNetwork, usePublicClient, useSwitchNetwork, useWalletClient } from "wagmi"; const { VCX, POP } = getVeAddresses(); @@ -73,8 +73,8 @@ export default function Migration(): JSX.Element { const { chain } = useNetwork(); const { switchNetwork } = useSwitchNetwork(); - const { data: vcxBal } = useBalance({ chainId: 1, address: account, token: VCX, watch: true }) - const { data: popBal } = useBalance({ chainId: 1, address: account, token: POP, watch: true }) + const { data: vcxBal } = useBalance({ chainId: 1, address: account || zeroAddress, token: VCX, watch: true }) + const { data: popBal } = useBalance({ chainId: 1, address: account || zeroAddress, token: POP, watch: true }) const [inputBalance, setInputBalance] = useState("0"); From 1a948a49215bdc8d7c06bd01b84f582e55304331 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 9 Nov 2023 14:43:07 +0100 Subject: [PATCH 47/84] round inputs --- components/vault/VaultInputs.tsx | 4 ++-- lib/constants/index.ts | 3 ++- pages/migration.tsx | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index e576695..02e813b 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -11,7 +11,7 @@ import { vaultDeposit, vaultDepositAndStake, vaultRedeem, vaultUnstakeAndWithdra import { validateInput } from "@/lib/utils/helpers"; import { getVeAddresses } from "@/lib/utils/addresses"; import { gaugeDeposit, gaugeWithdraw } from "@/lib/gauges/interactions"; -import { ERC20Abi } from "@/lib/constants"; +import { ERC20Abi, ROUNDING_VALUE } from "@/lib/constants"; import zap from "@/lib/vault/zap"; import Modal from "../modal/Modal"; import InputNumber from "../input/InputNumber"; @@ -386,7 +386,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId setInputToken(option)} - onMaxClick={() => handleChangeInput({ currentTarget: { value: inputToken.balance / (10 ** inputToken.decimals) } })} + onMaxClick={() => handleChangeInput({ currentTarget: { value: Math.round((inputToken.balance / (10 ** inputToken.decimals)) * ROUNDING_VALUE) / ROUNDING_VALUE } })} chainId={chainId} value={inputBalance} onChange={handleChangeInput} diff --git a/lib/constants/index.ts b/lib/constants/index.ts index f76f84d..d0019bb 100644 --- a/lib/constants/index.ts +++ b/lib/constants/index.ts @@ -38,4 +38,5 @@ export const ADDRESS_ZERO: Address = "0x0000000000000000000000000000000000000000 export const MAX_INT256 = BigInt(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) export const MAX_UINT256 = BigInt(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) export const MINUS_ONE = BigInt(-0x01) -export const ZERO = BigInt(0) \ No newline at end of file +export const ZERO = BigInt(0) +export const ROUNDING_VALUE = 10_000; \ No newline at end of file diff --git a/pages/migration.tsx b/pages/migration.tsx index b921032..454db62 100644 --- a/pages/migration.tsx +++ b/pages/migration.tsx @@ -1,7 +1,7 @@ import MainActionButton from "@/components/button/MainActionButton"; import InputTokenWithError from "@/components/input/InputTokenWithError"; import { handleAllowance } from "@/lib/approve"; -import { VCXAbi } from "@/lib/constants"; +import { ROUNDING_VALUE, VCXAbi } from "@/lib/constants"; import { showErrorToast, showLoadingToast, showSuccessToast } from "@/lib/toasts"; import { SimulationResponse } from "@/lib/types"; import { getVeAddresses } from "@/lib/utils/addresses"; @@ -121,7 +121,7 @@ export default function Migration(): JSX.Element { { }} - onMaxClick={() => handleChangeInput({ currentTarget: { value: formatEther(popBal.value) } })} + onMaxClick={() => handleChangeInput({ currentTarget: { value: Math.round(Number(formatEther(popBal.value)) * ROUNDING_VALUE) / ROUNDING_VALUE } })} chainId={1} value={inputBalance} onChange={handleChangeInput} From 874575a6b2575384b0dfba8d27436cbd1fb04d5a Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 9 Nov 2023 17:53:26 +0100 Subject: [PATCH 48/84] wip - using enso for zap assets --- components/button/PseudoRadioButton.tsx | 4 +- components/vault/SmartVault.tsx | 16 +- components/vault/VaultInputs.tsx | 150 +++++++---------- lib/utils/getZapAssets.ts | 41 +---- lib/vault/interactions.ts | 210 ++++++++++++------------ pages/vaults.tsx | 2 +- 6 files changed, 187 insertions(+), 236 deletions(-) diff --git a/components/button/PseudoRadioButton.tsx b/components/button/PseudoRadioButton.tsx index e239e90..5f789e2 100644 --- a/components/button/PseudoRadioButton.tsx +++ b/components/button/PseudoRadioButton.tsx @@ -6,10 +6,10 @@ interface PseudoRadioButtonProps { extraClasses?: string; } -export default function PseudoRadioButton({ label, handleClick, isActive, activeClass, extraClasses, }: PseudoRadioButtonProps): JSX.Element { +export default function PseudoRadioButton({ label, handleClick, isActive, activeClass, extraClasses}: PseudoRadioButtonProps): JSX.Element { return ( +} \ No newline at end of file From 385e62371bbbfb7298185f6fcc589b426b749531 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 10 Nov 2023 11:57:29 +0100 Subject: [PATCH 51/84] enso wallet --- pages/zapPage.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pages/zapPage.tsx b/pages/zapPage.tsx index f7ef9bb..f79ad94 100644 --- a/pages/zapPage.tsx +++ b/pages/zapPage.tsx @@ -8,9 +8,15 @@ async function zapDemo(publicClient: any, walletClient: any) { `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=0x849664E1F06693103c4852c232034Ae7A8C42736&spender=0x849664E1F06693103c4852c232034Ae7A8C42736&amountIn=50000000&slippage=300&tokenIn=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&tokenOut=0x6B175474E89094C44Da98b954EedeAC495271d0F`, { headers: { Authorization: `Bearer ee722f6b-8d53-463b-8440-71ba67df0cf4` } } )).data - console.log({ quote }) + const ensoWallet = (await axios.get("https://api.enso.finance/api/v1/wallet?chainId=1&fromAddress=0x849664E1F06693103c4852c232034Ae7A8C42736")).data + // ensoWallet -> + // { + // "address": "0xC3347AECd3C8049b64C6476e9CF05B6BEc00a9Ee", + // "isDeployed": false + // } + await handleAllowance({ token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", inputAmount: 50000000, @@ -20,7 +26,7 @@ async function zapDemo(publicClient: any, walletClient: any) { walletClient }) - const hash = await walletClient.sendTransaction({ account:"0x849664E1F06693103c4852c232034Ae7A8C42736", data: quote.tx.data, chain: mainnet }) + const hash = await walletClient.sendTransaction({ account: "0x849664E1F06693103c4852c232034Ae7A8C42736", data: quote.tx.data, chain: mainnet }) console.log({ hash }) const receipt = await publicClient.waitForTransactionReceipt({ hash }) console.log({ receipt }) From fac670e62fcac9daa080d4493d2ae46a370c767e Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 10 Nov 2023 12:37:38 +0100 Subject: [PATCH 52/84] zaps working --- .env.example | 3 +- lib/vault/zap.ts | 332 +-------------- next.config.js | 1 + package.json | 4 +- pages/_app.tsx | 16 +- pages/zapPage.tsx | 43 -- yarn.lock | 1013 ++++++++++++++++++++++++++++++++------------- 7 files changed, 750 insertions(+), 662 deletions(-) delete mode 100644 pages/zapPage.tsx diff --git a/.env.example b/.env.example index 25ad48e..abd9220 100644 --- a/.env.example +++ b/.env.example @@ -2,4 +2,5 @@ PINATA_API_SECRET= PINATA_API_KEY= IPFS_URL= DUNE_API_KEY= -NEXT_PUBLIC_ALCHEMY_API_KEY= \ No newline at end of file +NEXT_PUBLIC_ALCHEMY_API_KEY= +ENSO_API_KEY= \ No newline at end of file diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index fd49d07..db71824 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -1,298 +1,7 @@ import axios from "axios" -import { Address, ByteArray, Hex, PublicClient, WalletClient, getAddress, hashTypedData, pad, zeroAddress } from "viem"; -import { mainnet } from "wagmi"; -import { showErrorToast, showSuccessToast } from "../toasts"; -import { handleAllowance } from "../approve"; - -const GPv2Settlement = "0x9008D19f58AAbD9eD0D60971565AA8510560ab41" - -const cowDomain = { - name: "Gnosis Protocol", - version: "v2", - chainId: 1, - verifyingContract: GPv2Settlement, -} - -export enum OrderKind { - /** - * A sell order. - */ - SELL = "sell", - /** - * A buy order. - */ - BUY = "buy", -} - -/** - * Gnosis Protocol v2 order data. - */ -export interface Order { - /** - * Sell token address. - */ - sellToken: string; - /** - * Buy token address. - */ - buyToken: string; - /** - * An optional address to receive the proceeds of the trade instead of the - * owner (i.e. the order signer). - */ - receiver?: string; - /** - * The order sell amount. - * - * For fill or kill sell orders, this amount represents the exact sell amount - * that will be executed in the trade. For fill or kill buy orders, this - * amount represents the maximum sell amount that can be executed. For partial - * fill orders, this represents a component of the limit price fraction. - */ - sellAmount: string; - /** - * The order buy amount. - * - * For fill or kill sell orders, this amount represents the minimum buy amount - * that can be executed in the trade. For fill or kill buy orders, this amount - * represents the exact buy amount that will be executed. For partial fill - * orders, this represents a component of the limit price fraction. - */ - buyAmount: string; - /** - * The timestamp this order is valid until - */ - validTo: number | Date; - /** - * Arbitrary application specific data that can be added to an order. This can - * also be used to ensure uniqueness between two orders with otherwise the - * exact same parameters. - */ - appData: ByteArray | Hex; - /** - * Fee to give to the protocol. - */ - feeAmount: string; - /** - * The order kind. - */ - kind: OrderKind; - /** - * Specifies whether or not the order is partially fillable. - */ - partiallyFillable: boolean; - /** - * Specifies how the sell token balance will be withdrawn. It can either be - * taken using ERC20 token allowances made directly to the Vault relayer - * (default) or using Balancer Vault internal or external balances. - */ - sellTokenBalance?: OrderBalance; - /** - * Specifies how the buy token balance will be paid. It can either be paid - * directly in ERC20 tokens (default) in Balancer Vault internal balances. - */ - buyTokenBalance?: OrderBalance; -} - -/** - * Normalized representation of an {@link Order} for EIP-712 operations. - */ -export type NormalizedOrder = Omit< - Order, - "validTo" | "appData" | "kind" | "sellTokenBalance" | "buyTokenBalance" -> & { - receiver: string; - validTo: number; - appData: string; - kind: "sell" | "buy"; - sellTokenBalance: "erc20" | "external" | "internal"; - buyTokenBalance: "erc20" | "internal"; -}; - -/** - * The signing scheme used to sign the order. - */ -export enum SigningScheme { - /** - * The EIP-712 typed data signing scheme. This is the preferred scheme as it - * provides more infomation to wallets performing the signature on the data - * being signed. - * - * - */ - EIP712 = 0b00, - /** - * Message signed using eth_sign RPC call. - */ - ETHSIGN = 0b01, - /** - * Smart contract signatures as defined in EIP-1271. - * - * - */ - EIP1271 = 0b10, - /** - * Pre-signed order. - */ - PRESIGN = 0b11, -} - -/** - * The EIP-712 type fields definition for a Gnosis Protocol v2 order. - */ -export const ORDER_TYPE_FIELDS = [ - { name: "sellToken", type: "address" }, - { name: "buyToken", type: "address" }, - { name: "receiver", type: "address" }, - { name: "sellAmount", type: "uint256" }, - { name: "buyAmount", type: "uint256" }, - { name: "validTo", type: "uint32" }, - { name: "appData", type: "bytes32" }, - { name: "feeAmount", type: "uint256" }, - { name: "kind", type: "string" }, - { name: "partiallyFillable", type: "bool" }, - { name: "sellTokenBalance", type: "string" }, - { name: "buyTokenBalance", type: "string" }, -]; - - -/** - * Order balance configuration. - */ -export enum OrderBalance { - /** - * Use ERC20 token balances. - */ - ERC20 = "erc20", - /** - * Use Balancer Vault external balances. - * - * This can only be specified specified for the sell balance and allows orders - * to re-use Vault ERC20 allowances. When specified for the buy balance, it - * will be treated as {@link OrderBalance.ERC20}. - */ - EXTERNAL = "external", - /** - * Use Balancer Vault internal balances. - */ - INTERNAL = "internal", -} - -/** - * Normalizes the balance configuration for a buy token. Specifically, this - * function ensures that {@link OrderBalance.EXTERNAL} gets normalized to - * {@link OrderBalance.ERC20}. - * - * @param balance The balance configuration. - * @returns The normalized balance configuration. - */ -export function normalizeBuyTokenBalance( - balance: OrderBalance | undefined, -): OrderBalance.ERC20 | OrderBalance.INTERNAL { - switch (balance) { - case undefined: - case OrderBalance.ERC20: - case OrderBalance.EXTERNAL: - return OrderBalance.ERC20; - case OrderBalance.INTERNAL: - return OrderBalance.INTERNAL; - default: - throw new Error(`invalid order balance ${balance}`); - } -} - -/** - * Normalizes a timestamp value to a Unix timestamp. - * @param time The timestamp value to normalize. - * @return Unix timestamp or number of seconds since the Unix Epoch. - */ -export function timestamp(t: number | Date): number { - return typeof t === "number" ? t : ~~(t.getTime() / 1000); -} - - -/** - * Normalizes an app data value to a 32-byte hash. - * @param hashLike A hash-like value to normalize. - * @returns A 32-byte hash encoded as a hex-string. - */ -export function hashify(h: ByteArray | Hex | number): string { - return typeof h === "number" - ? `0x${h.toString(16).padStart(64, "0")}` - : pad(h, { size: 32 }) as string; -} - -/** - * Normalizes an order for hashing and signing, so that it can be used with - * Ethers.js for EIP-712 operations. - * @param hashLike A hash-like value to normalize. - * @returns A 32-byte hash encoded as a hex-string. - */ -export function normalizeOrder(order: Order): NormalizedOrder { - if (order.receiver === zeroAddress) { - throw new Error("receiver cannot be address(0)"); - } - - const normalizedOrder = { - ...order, - sellTokenBalance: order.sellTokenBalance ?? OrderBalance.ERC20, - receiver: order.receiver ?? zeroAddress, - validTo: timestamp(order.validTo), - appData: hashify(order.appData), - buyTokenBalance: normalizeBuyTokenBalance(order.buyTokenBalance), - }; - return normalizedOrder; -} - - -async function ecdsaSignTypedData( - scheme: any, - account: Address, - owner: WalletClient, - domain: any, - types: any, - data: NormalizedOrder, -): Promise { - let signature: string | null = null; - - switch (scheme) { - case SigningScheme.EIP712: - signature = await owner.signTypedData({ account, domain, types, primaryType: "Order", message: data }); - break; - case SigningScheme.ETHSIGN: - signature = await owner.signMessage({ - account, - message: { raw: hashTypedData({ domain, types, primaryType: "Order", message: data }) }, - }); - break; - default: - throw new Error("invalid signing scheme"); - } - return signature -} - -export type SigningResult = { signature: string; signingScheme: SigningScheme } - -export async function signOrder( - order: Order, - chainId: number, - account: Address, - signer: WalletClient, - signingMethod: 'default' | 'v4' | 'int_v4' | 'v3' | 'eth_sign' = 'v4' -): Promise { - const scheme = signingMethod === 'eth_sign' ? SigningScheme.ETHSIGN : SigningScheme.EIP712 - return { - scheme, - data: await ecdsaSignTypedData( - scheme, - account, - signer, - cowDomain, - { Order: ORDER_TYPE_FIELDS }, - normalizeOrder(order), - ), - } -} +import { Address, PublicClient, WalletClient, getAddress } from "viem"; +import { showErrorToast, showSuccessToast } from "@/lib/toasts"; +import { handleAllowance } from "@/lib/approve"; interface ZapProps { sellToken: Address; @@ -306,41 +15,28 @@ interface ZapProps { } export default async function zap({ sellToken, buyToken, amount, account, publicClient, walletClient, slippage = 100, tradeTimeout = 60 }: ZapProps): Promise { - console.log({ - sellToken, - buyToken, - from: account, - receiver: account, - validTo: Math.ceil(Date.now() / 1000) + tradeTimeout, - partiallyFillable: false, - kind: "sell", - sellAmountBeforeFee: amount.toLocaleString("fullwide", { useGrouping: false }) - }) const quote = (await axios.get( - `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}`, - { headers: { Authorization: `Bearer ee722f6b-8d53-463b-8440-71ba67df0cf4` } } + `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=${account}&spender=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}`, + { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } } )).data - console.log({ quote }) - await handleAllowance({ + const ensoWallet = (await axios.get( + `https://api.enso.finance/api/v1/wallet?chainId=1&fromAddress=${account}`, + { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } }) + ).data + + const success = await handleAllowance({ token: sellToken, inputAmount: amount, account, - spender: getAddress("0xC3347AECd3C8049b64C6476e9CF05B6BEc00a9Ee"), + spender: getAddress(ensoWallet.address), publicClient, walletClient }) + if (!success) return false try { - //const request = await walletClient.prepareTransactionRequest({ account, to: getAddress(quote.tx.to), data: quote.tx.data, chain: mainnet }) - //console.log({request}) - // const signature = await walletClient.signTransaction(request) - // console.log({signature}) - // const hash = await walletClient.sendRawTransaction(signature as any) - const hash = await walletClient.sendTransaction({ account, data: quote.tx.data, chain: mainnet }) - console.log({ hash }) + const hash = await walletClient.sendTransaction(quote.tx) const receipt = await publicClient.waitForTransactionReceipt({ hash }) - console.log({ receipt }) - showSuccessToast("Zapped successfully") return true; } catch (error: any) { diff --git a/next.config.js b/next.config.js index 2c21a9a..17fe0fc 100644 --- a/next.config.js +++ b/next.config.js @@ -14,6 +14,7 @@ module.exports = { IPFS_URL: process.env.IPFS_URL, DUNE_API_KEY: process.env.DUNE_API_KEY, NEXT_PUBLIC_ALCHEMY_API_KEY: process.env.NEXT_PUBLIC_ALCHEMY_API_KEY, + ENSO_API_KEY:process.env.ENSO_API_KEY, }, images: { domains: ["rawcdn.githack.com"], diff --git a/package.json b/package.json index 5b77694..6216a62 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "tailwind-scrollbar-hide": "^1.1.7", "tailwindcss": "^3.2.6", "vaultcraft-sdk": "0.1.15", - "viem": "1.11.1", - "wagmi": "1.4.2" + "viem": "1.18.9", + "wagmi": "1.4.5" }, "devDependencies": { "@types/node": "^17.0.35", diff --git a/pages/_app.tsx b/pages/_app.tsx index 1ab8ef2..5939e4a 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -36,17 +36,17 @@ const connectors = connectorsForWallets([ groupName: 'Suggested', wallets: [ injectedWallet({ chains }), - rainbowWallet({ projectId:'b2f883ab9ae2fbb812cb8e0d83efea7b', chains }), - metaMaskWallet({ projectId:'b2f883ab9ae2fbb812cb8e0d83efea7b', chains }), + rainbowWallet({ projectId: 'b2f883ab9ae2fbb812cb8e0d83efea7b', chains }), + metaMaskWallet({ projectId: 'b2f883ab9ae2fbb812cb8e0d83efea7b', chains }), ], }, { groupName: 'Others', wallets: [ coinbaseWallet({ chains, appName: 'Popcorn' }), - walletConnectWallet({ projectId:'b2f883ab9ae2fbb812cb8e0d83efea7b', chains }), - coin98Wallet({ projectId:'b2f883ab9ae2fbb812cb8e0d83efea7b', chains }) - ] + walletConnectWallet({ projectId: 'b2f883ab9ae2fbb812cb8e0d83efea7b', chains }), + coin98Wallet({ projectId: 'b2f883ab9ae2fbb812cb8e0d83efea7b', chains }) + ] } ]); @@ -100,9 +100,9 @@ export default function MyApp(props: any) { - - {getLayout()} - + + {getLayout()} + diff --git a/pages/zapPage.tsx b/pages/zapPage.tsx deleted file mode 100644 index f79ad94..0000000 --- a/pages/zapPage.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { handleAllowance } from "@/lib/approve" -import axios from "axios" -import { getAddress } from "viem" -import { mainnet, useAccount, usePublicClient, useWalletClient } from "wagmi" - -async function zapDemo(publicClient: any, walletClient: any) { - const quote = (await axios.get( - `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=0x849664E1F06693103c4852c232034Ae7A8C42736&spender=0x849664E1F06693103c4852c232034Ae7A8C42736&amountIn=50000000&slippage=300&tokenIn=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&tokenOut=0x6B175474E89094C44Da98b954EedeAC495271d0F`, - { headers: { Authorization: `Bearer ee722f6b-8d53-463b-8440-71ba67df0cf4` } } - )).data - console.log({ quote }) - - const ensoWallet = (await axios.get("https://api.enso.finance/api/v1/wallet?chainId=1&fromAddress=0x849664E1F06693103c4852c232034Ae7A8C42736")).data - // ensoWallet -> - // { - // "address": "0xC3347AECd3C8049b64C6476e9CF05B6BEc00a9Ee", - // "isDeployed": false - // } - - await handleAllowance({ - token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - inputAmount: 50000000, - account: "0x849664E1F06693103c4852c232034Ae7A8C42736", - spender: "0xC3347AECd3C8049b64C6476e9CF05B6BEc00a9Ee", - publicClient, - walletClient - }) - - const hash = await walletClient.sendTransaction({ account: "0x849664E1F06693103c4852c232034Ae7A8C42736", data: quote.tx.data, chain: mainnet }) - console.log({ hash }) - const receipt = await publicClient.waitForTransactionReceipt({ hash }) - console.log({ receipt }) - -} - - -export default function ZapPage() { - const { address: account } = useAccount(); - const publicClient = usePublicClient() - const { data: walletClient } = useWalletClient() - - return <> -} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 1f36598..64627bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,7 +22,7 @@ resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== -"@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.6", "@babel/runtime@^7.23.2": +"@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== @@ -76,14 +76,14 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.6.1": - version "4.9.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4" - integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA== + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== +"@eslint/eslintrc@^2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.3.tgz#797470a75fe0fbd5a53350ee715e85e87baff22d" + integrity sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -95,10 +95,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.52.0": - version "8.52.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c" - integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA== +"@eslint/js@8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d" + integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w== "@headlessui/react@^1.7.10": version "1.7.17" @@ -131,6 +131,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== +"@ioredis/commands@^1.1.1": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" + integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== + "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" @@ -362,10 +367,102 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@parcel/watcher-android-arm64@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.3.0.tgz#d82e74bb564ebd4d8a88791d273a3d2bd61e27ab" + integrity sha512-f4o9eA3dgk0XRT3XhB0UWpWpLnKgrh1IwNJKJ7UJek7eTYccQ8LR7XUWFKqw6aEq5KUNlCcGvSzKqSX/vtWVVA== + +"@parcel/watcher-darwin-arm64@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.3.0.tgz#c9cd03f8f233d512fcfc873d5b4e23f1569a82ad" + integrity sha512-mKY+oijI4ahBMc/GygVGvEdOq0L4DxhYgwQqYAz/7yPzuGi79oXrZG52WdpGA1wLBPrYb0T8uBaGFo7I6rvSKw== + +"@parcel/watcher-darwin-x64@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.3.0.tgz#83c902994a2a49b9e1ab5050dba24876fdc2c219" + integrity sha512-20oBj8LcEOnLE3mgpy6zuOq8AplPu9NcSSSfyVKgfOhNAc4eF4ob3ldj0xWjGGbOF7Dcy1Tvm6ytvgdjlfUeow== + +"@parcel/watcher-freebsd-x64@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.3.0.tgz#7a0f4593a887e2752b706aff2dae509aef430cf6" + integrity sha512-7LftKlaHunueAEiojhCn+Ef2CTXWsLgTl4hq0pkhkTBFI3ssj2bJXmH2L67mKpiAD5dz66JYk4zS66qzdnIOgw== + +"@parcel/watcher-linux-arm-glibc@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.3.0.tgz#3fc90c3ebe67de3648ed2f138068722f9b1d47da" + integrity sha512-1apPw5cD2xBv1XIHPUlq0cO6iAaEUQ3BcY0ysSyD9Kuyw4MoWm1DV+W9mneWI+1g6OeP6dhikiFE6BlU+AToTQ== + +"@parcel/watcher-linux-arm64-glibc@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.3.0.tgz#f7bbbf2497d85fd11e4c9e9c26ace8f10ea9bcbc" + integrity sha512-mQ0gBSQEiq1k/MMkgcSB0Ic47UORZBmWoAWlMrTW6nbAGoLZP+h7AtUM7H3oDu34TBFFvjy4JCGP43JlylkTQA== + +"@parcel/watcher-linux-arm64-musl@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.3.0.tgz#de131a9fcbe1fa0854e9cbf4c55bed3b35bcff43" + integrity sha512-LXZAExpepJew0Gp8ZkJ+xDZaTQjLHv48h0p0Vw2VMFQ8A+RKrAvpFuPVCVwKJCr5SE+zvaG+Etg56qXvTDIedw== + +"@parcel/watcher-linux-x64-glibc@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.3.0.tgz#193dd1c798003cdb5a1e59470ff26300f418a943" + integrity sha512-P7Wo91lKSeSgMTtG7CnBS6WrA5otr1K7shhSjKHNePVmfBHDoAOHYRXgUmhiNfbcGk0uMCHVcdbfxtuiZCHVow== + +"@parcel/watcher-linux-x64-musl@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.3.0.tgz#6dbdb86d96e955ab0fe4a4b60734ec0025a689dd" + integrity sha512-+kiRE1JIq8QdxzwoYY+wzBs9YbJ34guBweTK8nlzLKimn5EQ2b2FSC+tAOpq302BuIMjyuUGvBiUhEcLIGMQ5g== + +"@parcel/watcher-wasm@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-wasm/-/watcher-wasm-2.3.0.tgz#73b66c6fbd2a3326ae86a1ec77eab7139d0dd725" + integrity sha512-ejBAX8H0ZGsD8lSICDNyMbSEtPMWgDL0WFCt/0z7hyf5v8Imz4rAM8xY379mBsECkq/Wdqa5WEDLqtjZ+6NxfA== + dependencies: + is-glob "^4.0.3" + micromatch "^4.0.5" + napi-wasm "^1.1.0" + +"@parcel/watcher-win32-arm64@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.3.0.tgz#59da26a431da946e6c74fa6b0f30b120ea6650b6" + integrity sha512-35gXCnaz1AqIXpG42evcoP2+sNL62gZTMZne3IackM+6QlfMcJLy3DrjuL6Iks7Czpd3j4xRBzez3ADCj1l7Aw== + +"@parcel/watcher-win32-ia32@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.3.0.tgz#3ee6a18b08929cd3b788e8cc9547fd9a540c013a" + integrity sha512-FJS/IBQHhRpZ6PiCjFt1UAcPr0YmCLHRbTc00IBTrelEjlmmgIVLeOx4MSXzx2HFEy5Jo5YdhGpxCuqCyDJ5ow== + +"@parcel/watcher-win32-x64@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.3.0.tgz#14e7246289861acc589fd608de39fe5d8b4bb0a7" + integrity sha512-dLx+0XRdMnVI62kU3wbXvbIRhLck4aE28bIGKbRGS7BJNt54IIj9+c/Dkqb+7DJEbHUZAX1bwaoM8PqVlHJmCA== + +"@parcel/watcher@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.3.0.tgz#803517abbc3981a1a1221791d9f59dc0590d50f9" + integrity sha512-pW7QaFiL11O0BphO+bq3MgqeX/INAk9jgBldVDYjlQPO4VddoZnF22TcF9onMhnLVHuNqBJeRf+Fj7eezi/+rQ== + dependencies: + detect-libc "^1.0.3" + is-glob "^4.0.3" + micromatch "^4.0.5" + node-addon-api "^7.0.0" + optionalDependencies: + "@parcel/watcher-android-arm64" "2.3.0" + "@parcel/watcher-darwin-arm64" "2.3.0" + "@parcel/watcher-darwin-x64" "2.3.0" + "@parcel/watcher-freebsd-x64" "2.3.0" + "@parcel/watcher-linux-arm-glibc" "2.3.0" + "@parcel/watcher-linux-arm64-glibc" "2.3.0" + "@parcel/watcher-linux-arm64-musl" "2.3.0" + "@parcel/watcher-linux-x64-glibc" "2.3.0" + "@parcel/watcher-linux-x64-musl" "2.3.0" + "@parcel/watcher-win32-arm64" "2.3.0" + "@parcel/watcher-win32-ia32" "2.3.0" + "@parcel/watcher-win32-x64" "2.3.0" + "@rainbow-me/rainbowkit@^1.0.11": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@rainbow-me/rainbowkit/-/rainbowkit-1.1.3.tgz#593d11e7f5bdee5be35b4c8d890eb55884632730" - integrity sha512-sgklyUmKFFholbRxjbnkQwzlC0wsP0GnCKl6d+4qTpBbQK3P2kfCM9AcDWdkTv3XVQ40fByE8mc3jJ+rI8JdIw== + version "1.2.0" + resolved "https://registry.yarnpkg.com/@rainbow-me/rainbowkit/-/rainbowkit-1.2.0.tgz#8ddcb3acef5408ef375e3df349429144aa230e12" + integrity sha512-XjdeX31GwFdRR/1rCRqPXiO94nbq2qOlnaox5P4K/KMRIUwyelKzak27uWw8Krmor/Hcrd5FisfepGDS0tUfEA== dependencies: "@vanilla-extract/css" "1.9.1" "@vanilla-extract/dynamic" "2.0.2" @@ -374,6 +471,7 @@ i18n-js "^4.3.2" qrcode "1.5.0" react-remove-scroll "2.5.4" + ua-parser-js "^1.0.35" "@rc-component/portal@^1.1.0": version "1.1.2" @@ -384,10 +482,10 @@ classnames "^2.3.2" rc-util "^5.24.4" -"@rc-component/trigger@^1.17.0": - version "1.17.2" - resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-1.17.2.tgz#dca84a87754eb5b796859c48910ba06e7fb8454e" - integrity sha512-Jp3dXk/IzwHKM2Tn3ezdvQSwkPeH4v1s7QjIo7f5NFLIZVpJQ8a34FduZw8E6fT1PVgLXYd/JBIyd+YpgyQddA== +"@rc-component/trigger@^1.18.0": + version "1.18.1" + resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-1.18.1.tgz#149881ace55943f0b74ae0470dc9f05b8f0b5d51" + integrity sha512-bAcxJJ1Y+EJVgn8BRik7d8JjjAPND5zKkHQ3159zeR0gVoG4Z0RgEDAiXFFoie3/WpoJ9dRJyjrIpnH4Ef7PEg== dependencies: "@babel/runtime" "^7.23.2" "@rc-component/portal" "^1.1.0" @@ -426,9 +524,9 @@ viem "^1.0.0" "@safe-global/safe-gateway-typescript-sdk@^3.5.3": - version "3.12.0" - resolved "https://registry.yarnpkg.com/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.12.0.tgz#aa767a32f4d10f4ec9a47ad7e32d547d3b51e94c" - integrity sha512-hExCo62lScVC9/ztVqYEYL2pFxcqLTvB8fj0WtdP5FWrvbtEgD0pbVolchzD5bf85pbzvEwdAxSVS7EdCZxTNw== + version "3.13.2" + resolved "https://registry.yarnpkg.com/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.13.2.tgz#f03884c7eb766f5508085d95ab96063a28e20920" + integrity sha512-kGlJecJHBzGrGTq/yhLANh56t+Zur6Ubpt+/w03ARX1poDb4TM8vKU3iV8tuYpk359PPWp+Qvjnqb9oW2YQcYw== "@scure/base@~1.1.0", "@scure/base@~1.1.2": version "1.1.3" @@ -460,11 +558,11 @@ buffer "~6.0.3" "@solana/web3.js@^1.70.1": - version "1.87.2" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.87.2.tgz#d83484ab576f421342138ca1e0b98d2b9cfc6a00" - integrity sha512-TZNhS+tvJbYjm0LAvIkUy/3Aqgt2l6/3X6XsVUpvj5MGOl2Q6Ch8hYSxcUUtMbAFNN3sUXmV8NhhMLNJEvI6TA== + version "1.87.5" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.87.5.tgz#74df3f19ef65e3a419bd1810f500f8e51f4ab63b" + integrity sha512-hy5RVGVw8eXq//g41mIFhk5Jx4QH1CwbkPiQn/3MmHp6VD2HBRVMMZUSGUhYZxbK7NoIjQUsiv4MOlnl3VaUag== dependencies: - "@babel/runtime" "^7.22.6" + "@babel/runtime" "^7.23.2" "@noble/curves" "^1.2.0" "@noble/hashes" "^1.3.1" "@solana/buffer-layout" "^4.0.0" @@ -663,16 +761,16 @@ use-sync-external-store "^1.2.0" "@types/connect@^3.4.33": - version "3.4.37" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.37.tgz#c66a96689fd3127c8772eb3e9e5c6028ec1a9af5" - integrity sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q== + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== dependencies: "@types/node" "*" "@types/debug@^4.1.7": - version "4.1.10" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.10.tgz#f23148a6eb771a34c466a4fc28379d8101e84494" - integrity sha512-tOSCru6s732pofZ+sMv9o4o3Zc+Sa8l3bxd/tweTQudFn06vAzb13ZX46Zi6m6EJ+RUbRTHvgQJ1gBtSgkaUYA== + version "4.1.12" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" + integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== dependencies: "@types/ms" "*" @@ -687,16 +785,16 @@ integrity sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w== "@types/ms@*": - version "0.7.33" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.33.tgz#80bf1da64b15f21fd8c1dc387c31929317d99ee9" - integrity sha512-AuHIyzR5Hea7ij0P9q7vx7xu4z0C28ucwjAZC0ja7JhINyCnOw8/DnvAPQQ9TfOlCtZAmCERKQX9+o1mgQhuOQ== + version "0.7.34" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" + integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/node@*", "@types/node@^20.2.5": - version "20.8.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.7.tgz#ad23827850843de973096edfc5abc9e922492a25" - integrity sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ== + version "20.9.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.0.tgz#bfcdc230583aeb891cf51e73cfdaacdd8deae298" + integrity sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw== dependencies: - undici-types "~5.25.1" + undici-types "~5.26.4" "@types/node@18.15.13": version "18.15.13" @@ -714,28 +812,28 @@ integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== "@types/prop-types@*": - version "15.7.9" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.9.tgz#b6f785caa7ea1fe4414d9df42ee0ab67f23d8a6d" - integrity sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g== + version "15.7.10" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.10.tgz#892afc9332c4d62a5ea7e897fe48ed2085bbb08a" + integrity sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A== "@types/react@^18.0.9": - version "18.2.31" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.31.tgz#74ae2630e4aa9af599584157abd3b95d96fb9b40" - integrity sha512-c2UnPv548q+5DFh03y8lEDeMfDwBn9G3dRwfkrxQMo/dOtRHUUO57k6pHvBIfH/VF4Nh+98mZ5aaSe+2echD5g== + version "18.2.37" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.37.tgz#0f03af69e463c0f19a356c2660dbca5d19c44cae" + integrity sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" csstype "^3.0.2" "@types/scheduler@*": - version "0.16.5" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.5.tgz#4751153abbf8d6199babb345a52e1eb4167d64af" - integrity sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw== + version "0.16.6" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.6.tgz#eb26db6780c513de59bee0b869ef289ad3068711" + integrity sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA== "@types/trusted-types@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.5.tgz#5cac7e7df3275bb95f79594f192d97da3b4fd5fe" - integrity sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA== + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.6.tgz#d12451beaeb9c3838f12024580dc500b7e88b0ad" + integrity sha512-HYtNooPvUY9WAVRBr4u+4Qa9fYD1ze2IUlAD3HoA6oehn1taGwBx3Oa52U4mTslTS+GAExKpaFu39Y5xUEwfjg== "@types/ws@^7.4.4": version "7.4.7" @@ -744,56 +842,49 @@ dependencies: "@types/node" "*" -"@types/ws@^8.5.5": - version "8.5.8" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.8.tgz#13efec7bd439d0bdf2af93030804a94f163b1430" - integrity sha512-flUksGIQCnJd6sZ1l5dqCEG/ksaoAg/eUwiLAGTJQcfgvZJKF++Ta4bJA6A5aPSJmsr+xlseHn4KLgVlNnvPTg== - dependencies: - "@types/node" "*" - "@typescript-eslint/parser@^5.4.2 || ^6.0.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.8.0.tgz#bb2a969d583db242f1ee64467542f8b05c2e28cb" - integrity sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg== - dependencies: - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/typescript-estree" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.10.0.tgz#578af79ae7273193b0b6b61a742a2bc8e02f875a" + integrity sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog== + dependencies: + "@typescript-eslint/scope-manager" "6.10.0" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/typescript-estree" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz#5cac7977385cde068ab30686889dd59879811efd" - integrity sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g== +"@typescript-eslint/scope-manager@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz#b0276118b13d16f72809e3cecc86a72c93708540" + integrity sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg== dependencies: - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" -"@typescript-eslint/types@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.8.0.tgz#1ab5d4fe1d613e3f65f6684026ade6b94f7e3ded" - integrity sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ== +"@typescript-eslint/types@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.10.0.tgz#f4f0a84aeb2ac546f21a66c6e0da92420e921367" + integrity sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg== -"@typescript-eslint/typescript-estree@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz#9565f15e0cd12f55cf5aa0dfb130a6cb0d436ba1" - integrity sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg== +"@typescript-eslint/typescript-estree@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz#667381eed6f723a1a8ad7590a31f312e31e07697" + integrity sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg== dependencies: - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/visitor-keys" "6.10.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/visitor-keys@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz#cffebed56ae99c45eba901c378a6447b06be58b8" - integrity sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg== +"@typescript-eslint/visitor-keys@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz#b9eaf855a1ac7e95633ae1073af43d451e8f84e3" + integrity sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg== dependencies: - "@typescript-eslint/types" "6.8.0" + "@typescript-eslint/types" "6.10.0" eslint-visitor-keys "^3.4.1" "@ungap/structured-clone@^1.2.0": @@ -835,36 +926,36 @@ resolved "https://registry.yarnpkg.com/@vanilla-extract/sprinkles/-/sprinkles-1.5.0.tgz#c921183ae518bb484299c2dc81f2acefd91c3dbe" integrity sha512-W58f2Rzz5lLmk0jbhgStVlZl5wEiPB1Ur3fRvUaBM+MrifZ3qskmFq/CiH//fEYeG5Dh9vF1qRviMMH46cX9Nw== -"@wagmi/connectors@3.1.2": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-3.1.2.tgz#4fd33fc4061ffb53c68860a203f099c6cac649c3" - integrity sha512-IlLKErqCzQRBUcCvXGPowcczbWcvJtEG006gPsAoePNJEXCHEWoKASghgu+L/bqD7006Z6mW6zlTNjcSQJvFAg== +"@wagmi/connectors@3.1.3": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-3.1.3.tgz#112aad63a8042ce4a5a3dc4db9eaa4da0fbcf0fc" + integrity sha512-UgwsQKQDFObJVJMf9pDfFoXTv710o4zrTHyhIWKBTMMkLpCMsMxN5+ZaDhBYt/BgoRinfRYQo8uwuwLhxE6Log== dependencies: "@coinbase/wallet-sdk" "^3.6.6" "@ledgerhq/connect-kit-loader" "^1.1.0" "@safe-global/safe-apps-provider" "^0.17.1" "@safe-global/safe-apps-sdk" "^8.0.0" - "@walletconnect/ethereum-provider" "2.10.1" + "@walletconnect/ethereum-provider" "2.10.2" "@walletconnect/legacy-provider" "^2.0.0" "@walletconnect/modal" "2.6.2" - "@walletconnect/utils" "2.10.1" + "@walletconnect/utils" "2.10.2" abitype "0.8.7" eventemitter3 "^4.0.7" -"@wagmi/core@1.4.2": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-1.4.2.tgz#facf21c06d236b651782cfdd20005f02a3afcb9b" - integrity sha512-szgNs2DCbBXKsq3wdm/YD8FWkg7lfmTRAv25b2nJYJUTQN59pVXznlWfq8VCJLamhKOYjeYHlTQxXkAeUAJdhw== +"@wagmi/core@1.4.5": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-1.4.5.tgz#bab215bfc1e028bc720b772d8d69dd12ae0c0ebf" + integrity sha512-N9luRb1Uk4tBN9kaYcQSWKE9AsRt/rvZaFt5IZech4JPzNN2sQlfhKd9GEjOXYRDqEPHdDvos7qyBKiDNTz4GA== dependencies: - "@wagmi/connectors" "3.1.2" + "@wagmi/connectors" "3.1.3" abitype "0.8.7" eventemitter3 "^4.0.7" zustand "^4.3.1" -"@walletconnect/core@2.10.1": - version "2.10.1" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.10.1.tgz#d1fb442bd77424666bacdb0f5a07f7708fb3d984" - integrity sha512-WAoXfmj+Zy5q48TnrKUjmHXJCBahzKwbul+noepRZf7JDtUAZ9IOWpUjg+UPRbfK5EiWZ0TF42S6SXidf7EHoQ== +"@walletconnect/core@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.10.2.tgz#a1bf6e3e87b33f9df795ce0970d8ddd400fdc8a3" + integrity sha512-JQz/xp3SLEpTeRQctdck2ugSBVEpMxoSE+lFi2voJkZop1hv6P+uqr6E4PzjFluAjeAnKlT1xvra0aFWjPWVcw== dependencies: "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-provider" "1.0.13" @@ -877,8 +968,8 @@ "@walletconnect/relay-auth" "^1.0.4" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.10.1" - "@walletconnect/utils" "2.10.1" + "@walletconnect/types" "2.10.2" + "@walletconnect/utils" "2.10.2" events "^3.3.0" lodash.isequal "4.5.0" uint8arrays "^3.1.0" @@ -911,19 +1002,19 @@ dependencies: tslib "1.14.1" -"@walletconnect/ethereum-provider@2.10.1": - version "2.10.1" - resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.10.1.tgz#4733a98f0b388cf5ae6c2b269f50da87da432ee5" - integrity sha512-Yhoz8EXkKzxOlBT6G+elphqCx/gkH6RxD9/ZAiy9lLc8Ng5p1gvKCVVP5zsGNE9FbkKmHd+J9JJRzn2Bw2yqtQ== +"@walletconnect/ethereum-provider@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.10.2.tgz#d5aca538fbcbbf7dd771bceb2430de30f06411de" + integrity sha512-QMYFZ6+rVq2CJLdIPdKK0j1Qm66UA27oQU5V2SrL8EVwl7wFfm0Bq7fnL+qAWeDpn612dNeNErpk/ROa1zWlWg== dependencies: "@walletconnect/jsonrpc-http-connection" "^1.0.7" "@walletconnect/jsonrpc-provider" "^1.0.13" "@walletconnect/jsonrpc-types" "^1.0.3" "@walletconnect/jsonrpc-utils" "^1.0.8" - "@walletconnect/sign-client" "2.10.1" - "@walletconnect/types" "2.10.1" - "@walletconnect/universal-provider" "2.10.1" - "@walletconnect/utils" "2.10.1" + "@walletconnect/sign-client" "2.10.2" + "@walletconnect/types" "2.10.2" + "@walletconnect/universal-provider" "2.10.2" + "@walletconnect/utils" "2.10.2" events "^3.3.0" "@walletconnect/events@^1.0.1": @@ -991,12 +1082,13 @@ ws "^7.5.1" "@walletconnect/keyvaluestorage@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.0.2.tgz#92f5ca0f54c1a88a093778842ce0c874d86369c8" - integrity sha512-U/nNG+VLWoPFdwwKx0oliT4ziKQCEoQ27L5Hhw8YOFGA2Po9A9pULUYNWhDgHkrb0gYDNt//X7wABcEWWBd3FQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.0.tgz#782ad09af71e5241147fd7479f8814bd8ab8bb38" + integrity sha512-CjDBs1WmLGstYRoxWx9oAskTKj1deu7gvPycxZo2jYMa85hAYe762AITKWW1i2OJ8y9+5WJTGDAy3inVl8pjtw== dependencies: - safe-json-utils "^1.1.1" - tslib "1.14.1" + "@walletconnect/safe-json" "^1.0.1" + idb-keyval "^6.2.1" + unstorage "^1.9.0" "@walletconnect/legacy-client@^2.0.0": version "2.0.0" @@ -1128,19 +1220,19 @@ dependencies: tslib "1.14.1" -"@walletconnect/sign-client@2.10.1": - version "2.10.1" - resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.10.1.tgz#db60bc9400cd79f0cb2380067343512b21ee4749" - integrity sha512-iG3eJGi1yXeG3xGeVSSMf8wDFyx239B0prLQfy1uYDtYFb2ynnH/09oqAZyKn96W5nfQzUgM2Mz157PVdloH3Q== +"@walletconnect/sign-client@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.10.2.tgz#33300a9cfe42487473f66b73c99535f6b26f8c54" + integrity sha512-vviSLV3f92I0bReX+OLr1HmbH0uIzYEQQFd1MzIfDk9PkfFT/LLAHhUnDaIAMkIdippqDcJia+5QEtT4JihL3Q== dependencies: - "@walletconnect/core" "2.10.1" + "@walletconnect/core" "2.10.2" "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/logger" "^2.0.1" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.10.1" - "@walletconnect/utils" "2.10.1" + "@walletconnect/types" "2.10.2" + "@walletconnect/utils" "2.10.2" events "^3.3.0" "@walletconnect/time@^1.0.2": @@ -1150,10 +1242,10 @@ dependencies: tslib "1.14.1" -"@walletconnect/types@2.10.1": - version "2.10.1" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.10.1.tgz#1355bce236f3eef575716ea3efe4beed98a873ef" - integrity sha512-7pccAhajQdiH2kYywjE1XI64IqRI+4ioyGy0wvz8d0UFQ/DSG3MLKR8jHf5aTOafQQ/HRLz6xvlzN4a7gIVkUQ== +"@walletconnect/types@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.10.2.tgz#68e433a29ec2cf42d79d8b50c77bd5c1d91db721" + integrity sha512-luNV+07Wdla4STi9AejseCQY31tzWKQ5a7C3zZZaRK/di+rFaAAb7YW04OP4klE7tw/mJRGPTlekZElmHxO8kQ== dependencies: "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "1.2.1" @@ -1162,25 +1254,25 @@ "@walletconnect/logger" "^2.0.1" events "^3.3.0" -"@walletconnect/universal-provider@2.10.1": - version "2.10.1" - resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.10.1.tgz#c4a77bd2eed1a335edae5b2b298636092fff63ef" - integrity sha512-81QxTH/X4dRoYCz0U9iOrBYOcj7N897ONcB57wsGhEkV7Rc9htmWJq2CzeOuxvVZ+pNZkE+/aw9LrhizO1Ltxg== +"@walletconnect/universal-provider@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.10.2.tgz#85c8da39f65da8fe33f65f62689e703607b5ddc5" + integrity sha512-wFgI0LbQ3D56sgaUMsgOHCM5m8WLxiC71BGuCKQfApgsbNMVKugYVy2zWHyUyi8sqTQHI+uSaVpDev4UHq9LEw== dependencies: "@walletconnect/jsonrpc-http-connection" "^1.0.7" "@walletconnect/jsonrpc-provider" "1.0.13" "@walletconnect/jsonrpc-types" "^1.0.2" "@walletconnect/jsonrpc-utils" "^1.0.7" "@walletconnect/logger" "^2.0.1" - "@walletconnect/sign-client" "2.10.1" - "@walletconnect/types" "2.10.1" - "@walletconnect/utils" "2.10.1" + "@walletconnect/sign-client" "2.10.2" + "@walletconnect/types" "2.10.2" + "@walletconnect/utils" "2.10.2" events "^3.3.0" -"@walletconnect/utils@2.10.1": - version "2.10.1" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.10.1.tgz#65b37c9800eb0e80a08385b6987471fb46e1e22e" - integrity sha512-DM0dKgm9O58l7VqJEyV2OVv16XRePhDAReI23let6WdW1dSpw/Y/A89Lp99ZJOjLm2FxyblMRF3YRaZtHwBffw== +"@walletconnect/utils@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.10.2.tgz#1f2c6a2f1bb95bcc4517b1e94aa7164c9286eb46" + integrity sha512-syxXRpc2yhSknMu3IfiBGobxOY7fLfLTJuw+ppKaeO6WUdZpIit3wfuGOcc0Ms3ZPFCrGfyGOoZsCvgdXtptRg== dependencies: "@stablelib/chacha20poly1305" "1.0.1" "@stablelib/hkdf" "1.0.1" @@ -1190,7 +1282,7 @@ "@walletconnect/relay-api" "^1.0.9" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.10.1" + "@walletconnect/types" "2.10.2" "@walletconnect/window-getters" "^1.0.1" "@walletconnect/window-metadata" "^1.0.1" detect-browser "5.3.0" @@ -1240,10 +1332,10 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== +acorn@^8.10.0, acorn@^8.9.0: + version "8.11.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" + integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== aes-js@4.0.0-beta.5: version "4.0.0-beta.5" @@ -1294,7 +1386,7 @@ any-promise@^1.0.0: resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== -anymatch@~3.1.2: +anymatch@^3.1.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -1302,6 +1394,11 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +arch@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== + arg@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" @@ -1312,7 +1409,7 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -aria-query@^5.1.3: +aria-query@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== @@ -1398,10 +1495,10 @@ arraybuffer.prototype.slice@^1.0.2: is-array-buffer "^3.0.2" is-shared-array-buffer "^1.0.2" -ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== +ast-types-flow@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" + integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== async-mutex@^0.2.6: version "0.2.6" @@ -1444,10 +1541,10 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -axe-core@^4.6.2: - version "4.8.2" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.2.tgz#2f6f3cde40935825cf4465e3c1c9e77b240ff6ae" - integrity sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g== +axe-core@=4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" + integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== axios@^0.21.1: version "0.21.4" @@ -1457,15 +1554,15 @@ axios@^0.21.1: follow-redirects "^1.14.0" axios@^1.3.6, axios@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.1.tgz#11fbaa11fc35f431193a9564109c88c1f27b585f" - integrity sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A== + version "1.6.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.1.tgz#76550d644bf0a2d469a01f9244db6753208397d7" + integrity sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" proxy-from-env "^1.1.0" -axobject-query@^3.1.1: +axobject-query@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" integrity sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg== @@ -1619,9 +1716,9 @@ camelcase@^5.0.0: integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: - version "1.0.30001553" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz#e64e7dc8fd4885cd246bb476471420beb5e474b5" - integrity sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A== + version "1.0.30001561" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da" + integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw== chalk@^4.0.0, chalk@^4.1.1: version "4.1.2" @@ -1646,6 +1743,13 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +citty@^0.1.3, citty@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/citty/-/citty-0.1.4.tgz#91091be06ae4951dffa42fd443de7fe72245f2e0" + integrity sha512-Q3bK1huLxzQrvj7hImJ7Z1vKYJRPQCDnd0EjXfHMidcjecGOMuLrmuQmtWmFkuKLcMThlGh1yCKG8IEc6VeNXQ== + dependencies: + consola "^3.2.3" + classnames@^2.2.1, classnames@^2.2.5, classnames@^2.3.1, classnames@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" @@ -1656,6 +1760,15 @@ client-only@0.0.1, client-only@^0.0.1: resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== +clipboardy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-3.0.0.tgz#f3876247404d334c9ed01b6f269c11d09a5e3092" + integrity sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg== + dependencies: + arch "^2.2.0" + execa "^5.1.1" + is-wsl "^2.2.0" + cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -1680,6 +1793,11 @@ clsx@^1.1.0: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== +cluster-key-slot@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -1719,6 +1837,16 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +consola@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/consola/-/consola-3.2.3.tgz#0741857aa88cfa0d6fd53f1cff0375136e98502f" + integrity sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ== + +cookie-es@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.0.0.tgz#4759684af168dfc54365b2c2dda0a8d7ee1e4865" + integrity sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ== + cookiejar@^2.1.0: version "2.1.4" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" @@ -1748,7 +1876,7 @@ cross-fetch@^3.1.4: dependencies: node-fetch "^2.6.12" -cross-spawn@^7.0.2: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1849,6 +1977,11 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0, de has-property-descriptors "^1.0.0" object-keys "^1.1.1" +defu@^6.1.2: + version "6.1.3" + resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.3.tgz#6d7f56bc61668e844f9f593ace66fd67ef1205fd" + integrity sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ== + delay@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" @@ -1859,16 +1992,31 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +denque@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" + integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== + dequal@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== +destr@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.2.tgz#8d3c0ee4ec0a76df54bc8b819bca215592a8c218" + integrity sha512-65AlobnZMiCET00KaFFjUefxDX0khFA/E4myqZ7a6Sq1yZtR8+FVIvilVX66vF2uobSumxooYZChiRPCKNqhmg== + detect-browser@5.3.0, detect-browser@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + detect-node-es@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" @@ -1931,9 +2079,9 @@ duplexify@^4.1.2: stream-shift "^1.0.0" electron-to-chromium@^1.4.535: - version "1.4.563" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.563.tgz#dabb424202754c1fed2d2938ff564b23d3bbf0d3" - integrity sha512-dg5gj5qOgfZNkPNeyKBZQAQitIQ/xwfIDmEQJHCbXaD9ebTZxwJXUsDYcBlAvZGZLi+/354l35J1wkmP6CqYaw== + version "1.4.580" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.580.tgz#2f8f70f70733a6be1fb6f31de1224e6dc4bb196d" + integrity sha512-T5q3pjQon853xxxHUq3ZP68ZpvJHuSMY2+BZaW3QzjS4HvNuvsMmZ/+lU+nCrftre1jFZ+OSlExynXWBihnXzw== emoji-regex@^8.0.0: version "8.0.0" @@ -2010,7 +2158,7 @@ es-abstract@^1.22.1: unbox-primitive "^1.0.2" which-typed-array "^1.1.13" -es-iterator-helpers@^1.0.12: +es-iterator-helpers@^1.0.12, es-iterator-helpers@^1.0.15: version "1.0.15" resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== @@ -2181,26 +2329,26 @@ eslint-plugin-import@^2.28.1: tsconfig-paths "^3.14.2" eslint-plugin-jsx-a11y@^6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz#fca5e02d115f48c9a597a6894d5bcec2f7a76976" - integrity sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA== + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz#2fa9c701d44fcd722b7c771ec322432857fcbad2" + integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA== dependencies: - "@babel/runtime" "^7.20.7" - aria-query "^5.1.3" - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - ast-types-flow "^0.0.7" - axe-core "^4.6.2" - axobject-query "^3.1.1" + "@babel/runtime" "^7.23.2" + aria-query "^5.3.0" + array-includes "^3.1.7" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "=4.7.0" + axobject-query "^3.2.1" damerau-levenshtein "^1.0.8" emoji-regex "^9.2.2" - has "^1.0.3" - jsx-ast-utils "^3.3.3" - language-tags "=1.0.5" + es-iterator-helpers "^1.0.15" + hasown "^2.0.0" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - semver "^6.3.0" + object.entries "^1.1.7" + object.fromentries "^2.0.7" "eslint-plugin-react-hooks@^4.5.0 || 5.0.0-canary-7118f5dd7-20230705": version "4.6.0" @@ -2243,14 +2391,14 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.15.0: - version "8.52.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc" - integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg== + version "8.53.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.53.0.tgz#14f2c8244298fcae1f46945459577413ba2697ce" + integrity sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.52.0" + "@eslint/eslintrc" "^2.1.3" + "@eslint/js" "8.53.0" "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -2371,9 +2519,9 @@ ethcall@^6.0.1: abi-coder "^5.0.0" ethers@^6.3.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.8.0.tgz#0a26f57e96fd697cefcfcef464e0c325689d1daf" - integrity sha512-zrFbmQRlraM+cU5mE4CZTLBurZTs2gdp2ld0nG/f3ecBK+x6lZ69KSxBqZ4NjclxwfTxl5LeNufcBbMsTdY53Q== + version "6.8.1" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.8.1.tgz#ee2a1a39b5f62a13678f90ccd879175391d0a2b4" + integrity sha512-iEKm6zox5h1lDn6scuRWdIdFJUCGg3+/aQWu0F4K0GVyEZiktFkqrJbRjTn1FlYEPz7RKA707D6g5Kdk6j7Ljg== dependencies: "@adraffy/ens-normalize" "1.10.0" "@noble/curves" "1.2.0" @@ -2401,6 +2549,21 @@ events@^3.3.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +execa@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + ext@^1.1.2: version "1.7.0" resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" @@ -2423,10 +2586,10 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== +fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -2617,6 +2780,16 @@ get-nonce@^1.0.0: resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== +get-port-please@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/get-port-please/-/get-port-please-3.1.1.tgz#2556623cddb4801d823c0a6a15eec038abb483be" + integrity sha512-3UBAyM3u4ZBVYDsxOQfJDxEa6XTbpBDrOjp4mf7ExFRt5BKs/QywQQiJsh2B+hxcZLSapWqCRvElUe8DnKcFHA== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -2735,6 +2908,20 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +h3@^1.7.1, h3@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.8.2.tgz#69ea8ca0285c1bb268cd08b9a7017e02939f88b7" + integrity sha512-1Ca0orJJlCaiFY68BvzQtP2lKLk46kcLAxVM8JgYbtm2cUg6IY7pjpYgWMwUvDO9QI30N5JAukOKoT8KD3Q0PQ== + dependencies: + cookie-es "^1.0.0" + defu "^6.1.2" + destr "^2.0.1" + iron-webcrypto "^0.10.1" + radix3 "^1.1.0" + ufo "^1.3.0" + uncrypto "^0.1.3" + unenv "^1.7.4" + has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -2769,11 +2956,6 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" - integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== - hash.js@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" @@ -2795,9 +2977,19 @@ hey-listen@^1.0.8: integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q== highcharts@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/highcharts/-/highcharts-11.1.0.tgz#715eb55fd081351b526e28cd89ac0e4e30b35c15" - integrity sha512-vhmqq6/frteWMx0GKYWwEFL25g4OYc7+m+9KQJb/notXbNtIb8KVy+ijOF7XAFqF165cq0pdLIePAmyFY5ph3g== + version "11.2.0" + resolved "https://registry.yarnpkg.com/highcharts/-/highcharts-11.2.0.tgz#32ddc885b1c7a7d438df30c6d751c28991b16616" + integrity sha512-9i650YK7ZBA1Mgtr3avMkLVCAI45RQvYnwi+eHsdFSaBGuQN6BHoa4j4lMkSJLv0V4LISTK1z7J7G82Lzd7zwg== + +http-shutdown@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/http-shutdown/-/http-shutdown-1.2.2.tgz#41bc78fc767637c4c95179bc492f312c0ae64c5f" + integrity sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== humanize-ms@^1.2.1: version "1.2.1" @@ -2815,6 +3007,11 @@ i18n-js@^4.3.2: lodash "*" make-plural "*" +idb-keyval@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.1.tgz#94516d625346d16f56f3b33855da11bfded2db33" + integrity sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg== + ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -2872,6 +3069,26 @@ invariant@^2.2.4: dependencies: loose-envify "^1.0.0" +ioredis@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.3.2.tgz#9139f596f62fc9c72d873353ac5395bcf05709f7" + integrity sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA== + dependencies: + "@ioredis/commands" "^1.1.1" + cluster-key-slot "^1.1.0" + debug "^4.3.4" + denque "^2.1.0" + lodash.defaults "^4.2.0" + lodash.isarguments "^3.1.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + +iron-webcrypto@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-0.10.1.tgz#cab8636a468685533a8521bfd7f06b19b7174809" + integrity sha512-QGOS8MRMnj/UiOa+aMIgfyHcvkhqNUsUxb1XzskENvbo+rEfp6TOwqd1KPuDzXC4OnGHcMSVxDGRoilqB8ViqA== + is-arguments@^1.0.4: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -2937,6 +3154,11 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -3020,6 +3242,11 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -3066,6 +3293,13 @@ is-weakset@^2.0.1: call-bind "^1.0.2" get-intrinsic "^1.1.1" +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" @@ -3081,11 +3315,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isomorphic-ws@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" - integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== - isomorphic-ws@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" @@ -3125,15 +3354,15 @@ jayson@^4.1.0: uuid "^8.3.2" ws "^7.4.5" -jiti@^1.18.2: - version "1.20.0" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42" - integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA== +jiti@^1.19.1, jiti@^1.20.0: + version "1.21.0" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" + integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== jotai@^2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/jotai/-/jotai-2.4.3.tgz#a8eff8ca6de968d6a04616329dd1335ce52e70f3" - integrity sha512-CSAHX9LqWG5WCrU8OgBoZbBJ+Bo9rQU0mPusEF4e0CZ/SNFgurG26vb3UpgvCSJZgYVcUQNiUBM5q86PA8rstQ== + version "2.5.1" + resolved "https://registry.yarnpkg.com/jotai/-/jotai-2.5.1.tgz#eed05a32a4ac1264c531a77e86478f7ad3197ca3" + integrity sha512-vanPCCSuHczUXNbVh/iUunuMfrWRL4FdBtAbTRmrfqezJcKb8ybBTg8iivyYuUHapjcDETyJe1E4inlo26bVHA== "js-tokens@^3.0.0 || ^4.0.0": version "4.0.0" @@ -3187,12 +3416,17 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" +jsonc-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: version "3.3.5" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== @@ -3223,17 +3457,17 @@ keyvaluestorage-interface@^1.0.0: resolved "https://registry.yarnpkg.com/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz#13ebdf71f5284ad54be94bd1ad9ed79adad515ff" integrity sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g== -language-subtag-registry@~0.3.2: +language-subtag-registry@^0.3.20: version "0.3.22" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== -language-tags@=1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" - integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ== +language-tags@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" + integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== dependencies: - language-subtag-registry "~0.3.2" + language-subtag-registry "^0.3.20" levn@^0.4.1: version "0.4.1" @@ -3253,6 +3487,29 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +listhen@^1.2.2: + version "1.5.5" + resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.5.5.tgz#58915512af70f770aa3e9fb19367adf479bb58c4" + integrity sha512-LXe8Xlyh3gnxdv4tSjTjscD1vpr/2PRpzq8YIaMJgyKzRG8wdISlWVWnGThJfHnlJ6hmLt2wq1yeeix0TEbuoA== + dependencies: + "@parcel/watcher" "^2.3.0" + "@parcel/watcher-wasm" "2.3.0" + citty "^0.1.4" + clipboardy "^3.0.0" + consola "^3.2.3" + defu "^6.1.2" + get-port-please "^3.1.1" + h3 "^1.8.1" + http-shutdown "^1.2.2" + jiti "^1.20.0" + mlly "^1.4.2" + node-forge "^1.3.1" + pathe "^1.1.1" + std-env "^3.4.3" + ufo "^1.3.0" + untun "^0.1.2" + uqr "^0.1.2" + lit-element@^3.3.0: version "3.3.3" resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.3.3.tgz#10bc19702b96ef5416cf7a70177255bfb17b3209" @@ -3292,6 +3549,16 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== + lodash.isequal@4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" @@ -3314,6 +3581,11 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lru-cache@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" + integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g== + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3367,6 +3639,11 @@ memoizee@^0.4.15: next-tick "^1.1.0" timers-ext "^0.1.7" +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -3402,6 +3679,16 @@ mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + mini-svg-data-uri@^1.2.3: version "1.4.4" resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" @@ -3424,6 +3711,16 @@ minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +mlly@^1.2.0, mlly@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.4.2.tgz#7cf406aa319ff6563d25da6b36610a93f2a8007e" + integrity sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg== + dependencies: + acorn "^8.10.0" + pathe "^1.1.1" + pkg-types "^1.0.3" + ufo "^1.3.0" + motion@10.16.2: version "10.16.2" resolved "https://registry.yarnpkg.com/motion/-/motion-10.16.2.tgz#7dc173c6ad62210a7e9916caeeaf22c51e598d21" @@ -3436,6 +3733,11 @@ motion@10.16.2: "@motionone/utils" "^10.15.1" "@motionone/vue" "^10.16.2" +mri@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -3461,9 +3763,14 @@ mz@^2.7.0: thenify-all "^1.0.0" nanoid@^3.3.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" - integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +napi-wasm@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/napi-wasm/-/napi-wasm-1.1.0.tgz#bbe617823765ae9c1bc12ff5942370eae7b2ba4e" + integrity sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg== natural-compare@^1.4.0: version "1.4.0" @@ -3503,6 +3810,11 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== +node-addon-api@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.0.0.tgz#8136add2f510997b3b94814f4af1cce0b0e3962e" + integrity sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA== + node-cache@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d" @@ -3510,6 +3822,11 @@ node-cache@^5.1.2: dependencies: clone "2.x" +node-fetch-native@^1.2.0, node-fetch-native@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.4.1.tgz#5a336e55b4e1b1e72b9927da09fecd2b374c9be5" + integrity sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w== + node-fetch@^2.6.12: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -3517,6 +3834,11 @@ node-fetch@^2.6.12: dependencies: whatwg-url "^5.0.0" +node-forge@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: version "4.6.1" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.1.tgz#24b6d075e5e391b8d5539d98c7fc5c210cac8a3e" @@ -3537,6 +3859,13 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -3567,7 +3896,7 @@ object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.6: +object.entries@^1.1.6, object.entries@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== @@ -3612,6 +3941,15 @@ object.values@^1.1.6, object.values@^1.1.7: define-properties "^1.2.0" es-abstract "^1.22.1" +ofetch@^1.1.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.3.tgz#588cb806a28e5c66c2c47dd8994f9059a036d8c0" + integrity sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg== + dependencies: + destr "^2.0.1" + node-fetch-native "^1.4.0" + ufo "^1.3.0" + on-exit-leak-free@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209" @@ -3624,6 +3962,13 @@ once@^1.3.0, once@^1.4.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -3696,7 +4041,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -3719,6 +4064,11 @@ path@^0.12.7: process "^0.11.1" util "^0.10.3" +pathe@^1.1.0, pathe@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.1.tgz#1dd31d382b974ba69809adc9a7a347e65d84829a" + integrity sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -3779,6 +4129,15 @@ pirates@^4.0.1: resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== +pkg-types@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868" + integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A== + dependencies: + jsonc-parser "^3.2.0" + mlly "^1.2.0" + pathe "^1.1.0" + pngjs@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" @@ -3838,9 +4197,9 @@ postcss@8.4.31, postcss@^8.4.23: source-map-js "^1.0.2" preact@^10.12.0, preact@^10.5.9: - version "10.18.1" - resolved "https://registry.yarnpkg.com/preact/-/preact-10.18.1.tgz#3b84bb305f0b05f4ad5784b981d15fcec4e105da" - integrity sha512-mKUD7RRkQQM6s7Rkmi7IFkoEHjuFqRQUaXamO61E6Nn7vqF/bo7EZCmSyrUnp2UWHw0O7XjZ2eeXis+m7tf4lg== + version "10.18.2" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.18.2.tgz#e3aeccc292aebbc2e0b76ed76570aa61dd5f75e4" + integrity sha512-X/K43vocUHDg0XhWVmTTMbec4LT/iBMh+csCEqJk+pJqegaXsvjdqN80ZZ3L+93azWCnWCZ+WGwYb8SplxeNjA== prelude-ls@^1.2.1: version "1.2.1" @@ -3887,9 +4246,9 @@ proxy-from-env@^1.1.0: integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== punycode@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== qrcode@1.5.0: version "1.5.0" @@ -3948,6 +4307,11 @@ quick-format-unescaped@^4.0.3: resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== +radix3@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.0.tgz#9745df67a49c522e94a33d0a93cf743f104b6e0d" + integrity sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A== + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -3975,27 +4339,27 @@ rc-resize-observer@^1.3.1: resize-observer-polyfill "^1.5.1" rc-slider@^10.3.1: - version "10.3.1" - resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-10.3.1.tgz#345e818975f4bb61b66340799af8cfccad7c8ad7" - integrity sha512-XszsZLkbjcG9ogQy/zUC0n2kndoKUAnY/Vnk1Go5Gx+JJQBz0Tl15d5IfSiglwBUZPS9vsUJZkfCmkIZSqWbcA== + version "10.4.0" + resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-10.4.0.tgz#efc016583fdea5f5dfb4f3dc61b6755a19e5f453" + integrity sha512-ZlpWjFhOlEf0w4Ng31avFBkXNNBj60NAcTPaIoiCxBkJ29wOtHSPMqv9PZeEoqmx64bpJkgK7kPa47HG4LPzww== dependencies: "@babel/runtime" "^7.10.1" classnames "^2.2.5" rc-util "^5.27.0" rc-tooltip@^6.1.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-6.1.1.tgz#8f3bf2b7008f091977da19aa4617a48cefed3d10" - integrity sha512-YoxL0Ev4htsX37qgN23eKr0L5PIRpZaLVL9GX6aJ4x6UEnwgXZYUNCAEHfKlKT3eD1felDq3ob4+Cn9lprLDBw== + version "6.1.2" + resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-6.1.2.tgz#33923ecfb2cf24347975093cbd0b048ab33c9567" + integrity sha512-89zwvybvCxGJu3+gGF8w5AXd4HHk6hIN7K0vZbkzjilVaEAIWPqc1fcyeUeP71n3VCcw7pTL9LyFupFbrx8gHw== dependencies: "@babel/runtime" "^7.11.2" - "@rc-component/trigger" "^1.17.0" + "@rc-component/trigger" "^1.18.0" classnames "^2.3.1" rc-util@^5.21.0, rc-util@^5.24.4, rc-util@^5.27.0, rc-util@^5.38.0: - version "5.38.0" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.38.0.tgz#18a3d1c26ba3c43fabfbe6303e825dabd9e5f4f0" - integrity sha512-yV/YBNdFn+edyBpBdCqkPE29Su0jWcHNgwx2dJbRqMrMfrUcMJUjCRV+ZPhcvWyKFJ63GzEerPrz9JIVo0zXmA== + version "5.38.1" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.38.1.tgz#4915503b89855f5c5cd9afd4c72a7a17568777bb" + integrity sha512-e4ZMs7q9XqwTuhIK7zBIVFltUtMSjphuPPQXHoHlzRzNdOwUxDejo0Zls5HYaJfRKNURcsS/ceKVULlhjBrxng== dependencies: "@babel/runtime" "^7.18.3" react-is "^18.2.0" @@ -4108,6 +4472,18 @@ real-require@^0.1.0: resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.1.0.tgz#736ac214caa20632847b7ca8c1056a0767df9381" integrity sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg== +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== + dependencies: + redis-errors "^1.0.0" + reflect.getprototypeof@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3" @@ -4195,9 +4571,9 @@ rimraf@^3.0.2: glob "^7.1.3" rpc-websockets@^7.5.1: - version "7.6.1" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.6.1.tgz#7d1dd00e5ad3e17bbe1d88ba6e66f4cb579cb66b" - integrity sha512-MmRGaJJvxTHSRxYPjJJqcj2zWnCetw7YbYbKlD0Yc7qVw6PsZhRJg1MI3mpWlpBs+4zO+urlNfLl9zLsdOD/gA== + version "7.6.2" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.6.2.tgz#ed82f21ea8290f26d73f10d0dc0f9425dc364b81" + integrity sha512-+M1fOYMPxvOQDHbSItkD/an4fRwPZ1Nft1zv48G84S0TyChG2A1GXmjWkbs3o2NxW+q36H9nM2uLo5yojTrPaA== dependencies: "@babel/runtime" "^7.17.2" eventemitter3 "^4.0.7" @@ -4241,11 +4617,6 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-json-utils@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/safe-json-utils/-/safe-json-utils-1.1.1.tgz#0e883874467d95ab914c3f511096b89bfb3e63b1" - integrity sha512-SAJWGKDs50tAbiDXLf89PDwt9XYkWyANFWVzn4dTXl5QyI8t2o/bW5/OJl3lvc2WVU4MEpTo9Yz5NVFNsp+OJQ== - safe-regex-test@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" @@ -4267,7 +4638,7 @@ scheduler@^0.23.0: dependencies: loose-envify "^1.1.0" -semver@^6.3.0, semver@^6.3.1: +semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -4332,6 +4703,11 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -4364,6 +4740,16 @@ split2@^4.0.0: resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + +std-env@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.4.3.tgz#326f11db518db751c83fd58574f449b7c3060910" + integrity sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q== + stream-browserify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" @@ -4464,6 +4850,11 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -4533,19 +4924,19 @@ tailwind-scrollbar-hide@^1.1.7: integrity sha512-X324n9OtpTmOMqEgDUEA/RgLrNfBF/jwJdctaPZDzB3mppxJk7TLIDmOreEDm1Bq4R9LSPu4Epf8VSdovNU+iA== tailwindcss@^3.2.6: - version "3.3.3" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf" - integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w== + version "3.3.5" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.5.tgz#22a59e2fbe0ecb6660809d9cc5f3976b077be3b8" + integrity sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA== dependencies: "@alloc/quick-lru" "^5.2.0" arg "^5.0.2" chokidar "^3.5.3" didyoumean "^1.2.2" dlv "^1.1.3" - fast-glob "^3.2.12" + fast-glob "^3.3.0" glob-parent "^6.0.2" is-glob "^4.0.3" - jiti "^1.18.2" + jiti "^1.19.1" lilconfig "^2.1.0" micromatch "^4.0.5" normalize-path "^3.0.0" @@ -4734,6 +5125,16 @@ typescript@5.0.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== +ua-parser-js@^1.0.35: + version "1.0.37" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.37.tgz#b5dc7b163a5c1f0c510b08446aed4da92c46373f" + integrity sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ== + +ufo@^1.2.0, ufo@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.1.tgz#e085842f4627c41d4c1b60ebea1f75cdab4ce86b" + integrity sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw== + uint8arrays@^3.0.0, uint8arrays@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0" @@ -4751,10 +5152,52 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -undici-types@~5.25.1: - version "5.25.3" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" - integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA== +uncrypto@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/uncrypto/-/uncrypto-0.1.3.tgz#e1288d609226f2d02d8d69ee861fa20d8348ef2b" + integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +unenv@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.7.4.tgz#a0e5a78de2c7c3c4563c06ba9763c96c59db3333" + integrity sha512-fjYsXYi30It0YCQYqLOcT6fHfMXsBr2hw9XC7ycf8rTG7Xxpe3ZssiqUnD0khrjiZEmkBXWLwm42yCSCH46fMw== + dependencies: + consola "^3.2.3" + defu "^6.1.2" + mime "^3.0.0" + node-fetch-native "^1.4.0" + pathe "^1.1.1" + +unstorage@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.9.0.tgz#0c1977f4e769a48344339ac97ec3f2feea94d43d" + integrity sha512-VpD8ZEYc/le8DZCrny3bnqKE4ZjioQxBRnWE+j5sGNvziPjeDlaS1NaFFHzl/kkXaO3r7UaF8MGQrs14+1B4pQ== + dependencies: + anymatch "^3.1.3" + chokidar "^3.5.3" + destr "^2.0.1" + h3 "^1.7.1" + ioredis "^5.3.2" + listhen "^1.2.2" + lru-cache "^10.0.0" + mri "^1.2.0" + node-fetch-native "^1.2.0" + ofetch "^1.1.1" + ufo "^1.2.0" + +untun@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/untun/-/untun-0.1.2.tgz#fa42a62ae24c1c5c6f3209692a2b0e1f573f1353" + integrity sha512-wLAMWvxfqyTiBODA1lg3IXHQtjggYLeTK7RnSfqtOXixWJ3bAa2kK/HHmOOg19upteqO3muLvN6O/icbyQY33Q== + dependencies: + citty "^0.1.3" + consola "^3.2.3" + pathe "^1.1.1" update-browserslist-db@^1.0.13: version "1.0.13" @@ -4764,6 +5207,11 @@ update-browserslist-db@^1.0.13: escalade "^3.1.1" picocolors "^1.0.0" +uqr@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/uqr/-/uqr-0.1.2.tgz#5c6cd5dcff9581f9bb35b982cb89e2c483a41d7d" + integrity sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA== + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -4852,25 +5300,10 @@ vaultcraft-sdk@0.1.15: node-cache "^5.1.2" viem "^1.5.3" -viem@1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/viem/-/viem-1.11.1.tgz#30531740eb52e5d1ff1167d8df462d1a8d45afb8" - integrity sha512-PPNsPacRS7nryakQQJ9PjYGjUa0QgV8lbERhRuJm8X4kGUzSAsTQaQmy4hvV0cRAEHg8tG0TMD+GTCfwzZM3Yw== - dependencies: - "@adraffy/ens-normalize" "1.9.4" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@scure/bip32" "1.3.2" - "@scure/bip39" "1.2.1" - "@types/ws" "^8.5.5" - abitype "0.9.8" - isomorphic-ws "5.0.0" - ws "8.13.0" - -viem@^1.0.0, viem@^1.5.3: - version "1.16.6" - resolved "https://registry.yarnpkg.com/viem/-/viem-1.16.6.tgz#78118c9269506a59e2bc4deab13f1646e113d3fc" - integrity sha512-jcWcFQ+xzIfDwexwPJRvCuCRJKEkK9iHTStG7mpU5MmuSBpACs4nATBDyXNFtUiyYTFzLlVEwWkt68K0nCSImg== +viem@1.18.9, viem@^1.0.0, viem@^1.5.3: + version "1.18.9" + resolved "https://registry.yarnpkg.com/viem/-/viem-1.18.9.tgz#8be8fe3148b1c6c3bccc853001df98f91a8aeb30" + integrity sha512-eAXtoTwAFA3YEgjTYMb5ZTQrDC0UPx5qyZ4sv90TirVKepcM9mBPksTkC1SSWya0UdxhBmhEBL/CiYMjmGCTWg== dependencies: "@adraffy/ens-normalize" "1.9.4" "@noble/curves" "1.2.0" @@ -4881,15 +5314,15 @@ viem@^1.0.0, viem@^1.5.3: isows "1.0.3" ws "8.13.0" -wagmi@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-1.4.2.tgz#cd681b1d35cf36613a11852cf25c2c39ce456f9f" - integrity sha512-Cxu0LatB44stqHoqdc6dgsTb9woYH1bEquJFq9PbTkePmnRCvceAD4aFUREUTaBWzIBcouhFlanWweDzEnb3mg== +wagmi@1.4.5: + version "1.4.5" + resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-1.4.5.tgz#65ccf763e17892871196b6e5b188e29f0b08d3df" + integrity sha512-Ph62E6cO5n2Z8Z5LTyZrkaNprxTsbC4w0qZJT4OJdXrEELziI8z/b4FO6amVFXdu2rDp/wpvF56e4mhKC8/Kdw== dependencies: "@tanstack/query-sync-storage-persister" "^4.27.1" "@tanstack/react-query" "^4.28.0" "@tanstack/react-query-persist-client" "^4.28.0" - "@wagmi/core" "1.4.2" + "@wagmi/core" "1.4.5" abitype "0.8.7" use-sync-external-store "^1.2.0" @@ -5026,9 +5459,9 @@ yallist@^4.0.0: integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yaml@^2.1.1: - version "2.3.3" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.3.tgz#01f6d18ef036446340007db8e016810e5d64aad9" - integrity sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ== + version "2.3.4" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" + integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== yargs-parser@^18.1.2: version "18.1.3" @@ -5061,8 +5494,8 @@ yocto-queue@^0.1.0: integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== zustand@^4.3.1: - version "4.4.4" - resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.4.tgz#cc06202219972bd61cef1fd10105e6384ae1d5cf" - integrity sha512-5UTUIAiHMNf5+mFp7/AnzJXS7+XxktULFN0+D1sCiZWyX7ZG+AQpqs2qpYrynRij4QvoDdCD+U+bmg/cG3Ucxw== + version "4.4.6" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.6.tgz#03c78e3e2686c47095c93714c0c600b72a6512bd" + integrity sha512-Rb16eW55gqL4W2XZpJh0fnrATxYEG3Apl2gfHTyDSE965x/zxslTikpNch0JgNjJA9zK6gEFW8Fl6d1rTZaqgg== dependencies: use-sync-external-store "1.2.0" From f3fd9dee4e26ae92c9e0cbea678319dc1399864d Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 10 Nov 2023 13:04:17 +0100 Subject: [PATCH 53/84] wip - logging --- components/vault/VaultInputs.tsx | 44 +------------------------------- lib/vault/zap.ts | 5 +++- 2 files changed, 5 insertions(+), 44 deletions(-) diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index b4d6329..5c00da1 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -6,21 +6,16 @@ import { Address, useAccount, useNetwork, usePublicClient, useSwitchNetwork, use import TabSelector from "@/components/common/TabSelector"; import { Token } from "@/lib/types"; import { handleAllowance } from "@/lib/approve"; -import { WalletClient, parseUnits } from "viem"; import { vaultDeposit, vaultDepositAndStake, vaultRedeem, vaultUnstakeAndWithdraw, zapIntoGauge, zapIntoVault, zapOutOfGauge, zapOutOfVault } from "@/lib/vault/interactions"; import { validateInput } from "@/lib/utils/helpers"; import { getVeAddresses } from "@/lib/utils/addresses"; import { gaugeDeposit, gaugeWithdraw } from "@/lib/gauges/interactions"; -import { ERC20Abi, ROUNDING_VALUE } from "@/lib/constants"; -import zap from "@/lib/vault/zap"; +import { ROUNDING_VALUE } from "@/lib/constants"; import Modal from "../modal/Modal"; import InputNumber from "../input/InputNumber"; -import { showErrorToast, showSuccessToast } from "@/lib/toasts"; import { MutateTokenBalanceProps } from "pages/vaults"; -// import { useExecutePosition, usePositions } from "@ensofinance/use-defi"; const { VaultRouter: VAULT_ROUTER } = getVeAddresses() -const COWSWAP_RELAYER = "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110" interface VaultInputsProps { vault: Token; @@ -76,43 +71,6 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId } } - - // function isZap() { - // // @dev - temp -> only for first testing - // if (Number(inputBalance) === 0 || !inputToken || !outputToken || !account || !walletClient || chainId !== 1) return false - - // if (isDeposit) { - // return ![vault.address, asset.address].includes(inputToken.address) - // } else { - // return ![vault.address, asset.address].includes(outputToken.address) - // } - // } - - // function getZapParams() { - // if (isDeposit) { - // return { - // position: { chainId: 1, address: asset.address }, - // tokenIn: inputToken?.address, - // amountIn: parseUnits(inputBalance, inputToken?.decimals) - // } - // } else { - // return { - // position: { chainId: 1, address: outputToken.address }, - // tokenIn: vault.address, - // amountIn: parseUnits(inputBalance, inputToken?.decimals) - // } - // } - // } - - - // const { - // executionDetails - // } = useExecutePosition({ - // position: isZap() ? { chainId: 1, address: inputToken?.address } as any : undefined, - // tokenIn: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - // amountIn: parseUnits(0.1, 18) // from viem - // }) - async function handleMainAction() { const val = Number(inputBalance) if (val === 0 || !inputToken || !outputToken || !account || !walletClient) return; diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index db71824..8760346 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -15,15 +15,18 @@ interface ZapProps { } export default async function zap({ sellToken, buyToken, amount, account, publicClient, walletClient, slippage = 100, tradeTimeout = 60 }: ZapProps): Promise { + console.log({ qouteUrl: `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=${account}&spender=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}` }) const quote = (await axios.get( `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=${account}&spender=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}`, { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } } )).data + console.log({ quote }) + console.log({ ensoWalletUrl: `https://api.enso.finance/api/v1/wallet?chainId=1&fromAddress=${account}` }) const ensoWallet = (await axios.get( `https://api.enso.finance/api/v1/wallet?chainId=1&fromAddress=${account}`, { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } }) ).data - + console.log({ ensoWallet: ensoWallet }) const success = await handleAllowance({ token: sellToken, inputAmount: amount, From fa031f0c5fcccbcbd27ea026a1cd4dbbf32de7c2 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Mon, 13 Nov 2023 14:46:18 +0100 Subject: [PATCH 54/84] zaps working? --- lib/vault/zap.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index 8760346..c7e34ae 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -15,13 +15,6 @@ interface ZapProps { } export default async function zap({ sellToken, buyToken, amount, account, publicClient, walletClient, slippage = 100, tradeTimeout = 60 }: ZapProps): Promise { - console.log({ qouteUrl: `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=${account}&spender=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}` }) - const quote = (await axios.get( - `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=${account}&spender=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}`, - { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } } - )).data - console.log({ quote }) - console.log({ ensoWalletUrl: `https://api.enso.finance/api/v1/wallet?chainId=1&fromAddress=${account}` }) const ensoWallet = (await axios.get( `https://api.enso.finance/api/v1/wallet?chainId=1&fromAddress=${account}`, { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } }) @@ -37,12 +30,20 @@ export default async function zap({ sellToken, buyToken, amount, account, public }) if (!success) return false + console.log({ qouteUrl: `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=${account}&spender=${account}&receiver=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}` }) + const quote = (await axios.get( + `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=${account}&spender=${account}&receiver=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}`, + { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } } + )).data + console.log({ quote }) + try { const hash = await walletClient.sendTransaction(quote.tx) const receipt = await publicClient.waitForTransactionReceipt({ hash }) showSuccessToast("Zapped successfully") return true; } catch (error: any) { + console.log(error) showErrorToast(error.shortMessage) return false; } From 0f51544bcca42f453986f284193e09d83331725a Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 14 Nov 2023 11:04:15 +0100 Subject: [PATCH 55/84] zaps in and out working --- components/vault/SmartVault.tsx | 2 +- components/vault/VaultInputs.tsx | 16 +++++++++++++--- lib/utils/formatBigNumber.ts | 1 + lib/vault/interactions.ts | 12 ++++++++++-- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/components/vault/SmartVault.tsx b/components/vault/SmartVault.tsx index e9efb60..017ddf9 100644 --- a/components/vault/SmartVault.tsx +++ b/components/vault/SmartVault.tsx @@ -118,7 +118,7 @@ export default function SmartVault({

TVL

- $ {NumberFormatter.format(vaultData.tvl)} + $ {vaultData.tvl < 1 ? "0" : NumberFormatter.format(vaultData.tvl)}
diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index 5c00da1..5d18c10 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -14,6 +14,8 @@ import { ROUNDING_VALUE } from "@/lib/constants"; import Modal from "../modal/Modal"; import InputNumber from "../input/InputNumber"; import { MutateTokenBalanceProps } from "pages/vaults"; +import { safeRound } from "@/lib/utils/formatBigNumber"; +import { formatUnits, parseUnits } from "viem"; const { VaultRouter: VAULT_ROUTER } = getVeAddresses() @@ -225,6 +227,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId } else { console.log("out zap") + console.log({ gaugeBal: gauge?.balance, amount: (val * (10 ** inputToken.decimals)) }) const success = await zapOutOfGauge({ buyToken: outputToken.address, asset: asset.address, @@ -252,7 +255,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId vault: vault.address, account, amount: (val * (10 ** inputToken.decimals)), - assetBal: inputToken.balance, + assetBal: asset.balance, slippage, tradeTimeout, publicClient, @@ -270,7 +273,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId gauge: gauge.address, account, amount: (val * (10 ** inputToken.decimals)), - assetBal: inputToken.balance, + assetBal: asset.balance, slippage, tradeTimeout, publicClient, @@ -318,7 +321,14 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId setInputToken(option)} - onMaxClick={() => handleChangeInput({ currentTarget: { value: Math.round((inputToken.balance / (10 ** inputToken.decimals)) * ROUNDING_VALUE) / ROUNDING_VALUE } })} + onMaxClick={() => handleChangeInput( + { + currentTarget: { + value: formatUnits(safeRound( + BigInt(inputToken.balance.toLocaleString("fullwide", { useGrouping: false })), + inputToken.decimals), inputToken.decimals) + } + })} chainId={chainId} value={inputBalance} onChange={handleChangeInput} diff --git a/lib/utils/formatBigNumber.ts b/lib/utils/formatBigNumber.ts index cad35c8..7e2f10d 100644 --- a/lib/utils/formatBigNumber.ts +++ b/lib/utils/formatBigNumber.ts @@ -66,6 +66,7 @@ export function numberToBigNumber(value: number | string, decimals: number): Big export const NumberFormatter = Intl.NumberFormat("en", { //@ts-ignore notation: "compact", + maximumSignificantDigits: 3 }); export function safeRound(bn: bigint, decimals = 18): bigint { diff --git a/lib/vault/interactions.ts b/lib/vault/interactions.ts index 6b04de2..12c805a 100644 --- a/lib/vault/interactions.ts +++ b/lib/vault/interactions.ts @@ -114,6 +114,7 @@ async function simulateVaultRouterCall({ address, account, amount, vault, gauge, } export async function vaultDeposit({ address, account, amount, publicClient, walletClient }: VaultWriteProps): Promise { + console.log({ address, account, amount, publicClient, walletClient }) showLoadingToast("Depositing into the vault...") const { request, success, error: simulationError } = await simulateVaultCall({ address, account, amount, functionName: "deposit", publicClient }) @@ -208,7 +209,11 @@ export async function zapIntoVault({ sellToken, asset, vault, account, amount, a const postBal = Number(await publicClient.readContract({ address: asset, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) if (successZap) { + console.log({ postBal, assetBal }) + const depositAmount = postBal - assetBal + console.log({ depositAmount }) + await handleAllowance({ token: asset, inputAmount: depositAmount, @@ -227,9 +232,10 @@ export async function zapIntoGauge({ sellToken, asset, router, vault, gauge, acc showLoadingToast("Zapping into asset...") const successZap = await zap({ sellToken, buyToken: asset, amount, account, publicClient, walletClient, slippage, tradeTimeout }) const postBal = Number(await publicClient.readContract({ address: asset, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) - + console.log({ postBal, assetBal }) if (successZap) { const depositAmount = postBal - assetBal + console.log({ depositAmount }) await handleAllowance({ token: asset, inputAmount: depositAmount, @@ -253,6 +259,7 @@ export async function zapOutOfVault({ buyToken, asset, vault, account, amount, a walletClient }) const postBal = Number(await publicClient.readContract({ address: asset, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) + console.log({ postBal, assetBal, amount: postBal - assetBal }) if (success) { showLoadingToast("Zapping into asset...") @@ -282,6 +289,7 @@ export async function zapOutOfGauge({ buyToken, asset, router, vault, gauge, acc walletClient }) const postBal = Number(await publicClient.readContract({ address: asset, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) + console.log({ postBal, assetBal, amount: postBal - assetBal }) if (success) { showLoadingToast("Zapping into asset...") @@ -291,7 +299,7 @@ export async function zapOutOfGauge({ buyToken, asset, router, vault, gauge, acc publicClient, sellToken: asset, buyToken, - amount: postBal - assetBal, + amount: postBal - assetBal, slippage, tradeTimeout }) From b3945219811b1151b58fe0ccc7ed64d3bba5236a Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 14 Nov 2023 11:18:37 +0100 Subject: [PATCH 56/84] hide menu on link click --- components/navbar/DesktopMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/navbar/DesktopMenu.tsx b/components/navbar/DesktopMenu.tsx index 9ebd014..c7e453f 100644 --- a/components/navbar/DesktopMenu.tsx +++ b/components/navbar/DesktopMenu.tsx @@ -105,7 +105,7 @@ export default function DesktopMenu(): JSX.Element { Logo
-
+
toggleMenu(false)}>
From e1cd5146759a22c4573ca07efa2b0d3a1adbd65a Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 15 Nov 2023 10:20:24 +0100 Subject: [PATCH 57/84] zaps on other chains --- components/vault/SmartVault.tsx | 4 ---- components/vault/VaultInputs.tsx | 4 ++++ lib/vault/interactions.ts | 16 ++++++++++------ lib/vault/zap.ts | 11 ++++++----- pages/vaults.tsx | 9 +++++++-- 5 files changed, 27 insertions(+), 17 deletions(-) diff --git a/components/vault/SmartVault.tsx b/components/vault/SmartVault.tsx index 017ddf9..c1efba5 100644 --- a/components/vault/SmartVault.tsx +++ b/components/vault/SmartVault.tsx @@ -160,10 +160,6 @@ export default function SmartVault({
- {/*
- -
*/} -

{vault.address}

diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index 5d18c10..e603a87 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -170,6 +170,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId else { console.log("out zap") const success = await zapOutOfVault({ + chainId, buyToken: outputToken.address, asset: asset.address, vault: vault.address, @@ -229,6 +230,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId console.log("out zap") console.log({ gaugeBal: gauge?.balance, amount: (val * (10 ** inputToken.decimals)) }) const success = await zapOutOfGauge({ + chainId, buyToken: outputToken.address, asset: asset.address, router: VAULT_ROUTER, @@ -250,6 +252,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId if (outputToken.address === vault.address) { console.log("out vault") const success = await zapIntoVault({ + chainId, sellToken: inputToken.address, asset: asset.address, vault: vault.address, @@ -266,6 +269,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId else if (outputToken.address === gauge?.address) { console.log("out gauge") const success = await zapIntoGauge({ + chainId, sellToken: inputToken.address, router: VAULT_ROUTER, asset: asset.address, diff --git a/lib/vault/interactions.ts b/lib/vault/interactions.ts index 12c805a..163e72c 100644 --- a/lib/vault/interactions.ts +++ b/lib/vault/interactions.ts @@ -44,6 +44,7 @@ interface VaultRouterSimulateProps { } interface ZapIntoVaultProps { + chainId: number; sellToken: Address; asset: Address; vault: Address; @@ -62,6 +63,7 @@ interface ZapIntoGaugeProps extends ZapIntoVaultProps { } interface ZapOutOfVaultProps { + chainId: number; buyToken: Address; asset: Address; vault: Address; @@ -203,9 +205,9 @@ export async function vaultUnstakeAndWithdraw({ address, account, amount, vault, } } -export async function zapIntoVault({ sellToken, asset, vault, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapIntoVaultProps): Promise { +export async function zapIntoVault({ chainId, sellToken, asset, vault, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapIntoVaultProps): Promise { showLoadingToast("Zapping into asset...") - const successZap = await zap({ sellToken, buyToken: asset, amount, account, publicClient, walletClient, slippage, tradeTimeout }) + const successZap = await zap({ chainId, sellToken, buyToken: asset, amount, account, publicClient, walletClient, slippage, tradeTimeout }) const postBal = Number(await publicClient.readContract({ address: asset, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) if (successZap) { @@ -228,9 +230,9 @@ export async function zapIntoVault({ sellToken, asset, vault, account, amount, a } } -export async function zapIntoGauge({ sellToken, asset, router, vault, gauge, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapIntoGaugeProps): Promise { +export async function zapIntoGauge({ chainId, sellToken, asset, router, vault, gauge, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapIntoGaugeProps): Promise { showLoadingToast("Zapping into asset...") - const successZap = await zap({ sellToken, buyToken: asset, amount, account, publicClient, walletClient, slippage, tradeTimeout }) + const successZap = await zap({ chainId, sellToken, buyToken: asset, amount, account, publicClient, walletClient, slippage, tradeTimeout }) const postBal = Number(await publicClient.readContract({ address: asset, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) console.log({ postBal, assetBal }) if (successZap) { @@ -250,7 +252,7 @@ export async function zapIntoGauge({ sellToken, asset, router, vault, gauge, acc } } -export async function zapOutOfVault({ buyToken, asset, vault, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapOutOfVaultProps): Promise { +export async function zapOutOfVault({ chainId, buyToken, asset, vault, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapOutOfVaultProps): Promise { const success = await vaultRedeem({ address: vault, account, @@ -264,6 +266,7 @@ export async function zapOutOfVault({ buyToken, asset, vault, account, amount, a if (success) { showLoadingToast("Zapping into asset...") return await zap({ + chainId, account, walletClient, publicClient, @@ -278,7 +281,7 @@ export async function zapOutOfVault({ buyToken, asset, vault, account, amount, a } } -export async function zapOutOfGauge({ buyToken, asset, router, vault, gauge, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapOutOfGaugeProps): Promise { +export async function zapOutOfGauge({ chainId, buyToken, asset, router, vault, gauge, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapOutOfGaugeProps): Promise { const success = await vaultUnstakeAndWithdraw({ address: router, account, @@ -294,6 +297,7 @@ export async function zapOutOfGauge({ buyToken, asset, router, vault, gauge, acc if (success) { showLoadingToast("Zapping into asset...") return await zap({ + chainId, account, walletClient, publicClient, diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index c7e34ae..6a000e6 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -4,6 +4,7 @@ import { showErrorToast, showSuccessToast } from "@/lib/toasts"; import { handleAllowance } from "@/lib/approve"; interface ZapProps { + chainId: number; sellToken: Address; buyToken: Address; amount: number; @@ -14,9 +15,9 @@ interface ZapProps { tradeTimeout?: number; // in s } -export default async function zap({ sellToken, buyToken, amount, account, publicClient, walletClient, slippage = 100, tradeTimeout = 60 }: ZapProps): Promise { +export default async function zap({ chainId, sellToken, buyToken, amount, account, publicClient, walletClient, slippage = 100, tradeTimeout = 60 }: ZapProps): Promise { const ensoWallet = (await axios.get( - `https://api.enso.finance/api/v1/wallet?chainId=1&fromAddress=${account}`, + `https://api.enso.finance/api/v1/wallet?chainId=${chainId}&fromAddress=${account}`, { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } }) ).data console.log({ ensoWallet: ensoWallet }) @@ -30,13 +31,13 @@ export default async function zap({ sellToken, buyToken, amount, account, public }) if (!success) return false - console.log({ qouteUrl: `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=${account}&spender=${account}&receiver=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}` }) + console.log({ qouteUrl: `https://api.enso.finance/api/v1/shortcuts/route?chainId=${chainId}&fromAddress=${account}&spender=${account}&receiver=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}` }) const quote = (await axios.get( - `https://api.enso.finance/api/v1/shortcuts/route?chainId=1&fromAddress=${account}&spender=${account}&receiver=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}`, + `https://api.enso.finance/api/v1/shortcuts/route?chainId=${chainId}&fromAddress=${account}&spender=${account}&receiver=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}`, { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } } )).data console.log({ quote }) - + try { const hash = await walletClient.sendTransaction(quote.tx) const receipt = await publicClient.waitForTransactionReceipt({ hash }) diff --git a/pages/vaults.tsx b/pages/vaults.tsx index a2b9ff7..9443448 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -72,7 +72,12 @@ const Vaults: NextPage = () => { setZapAssets(newZapAssets); // get available zapAddresses - setAvailableZapAssets({ 1: await getAvailableZapAssets(1) }) + setAvailableZapAssets({ + 1: await getAvailableZapAssets(1), + 137: await getAvailableZapAssets(137), + 10: await getAvailableZapAssets(10), + 42161: await getAvailableZapAssets(42161) + }) // get vaults const fetchedVaults = (await Promise.all( @@ -276,7 +281,7 @@ const Vaults: NextPage = () => { vaultData={vault} mutateTokenBalance={mutateTokenBalance} searchString={searchString} - zapAssets={vault.chainId === 1 && availableZapAssets[1].includes(vault.asset.address) ? zapAssets[vault.chainId] : undefined} + zapAssets={availableZapAssets[vault.chainId].includes(vault.asset.address) ? zapAssets[vault.chainId] : undefined} deployer={"0x22f5413C075Ccd56D575A54763831C4c27A37Bdb"} /> ) From 5bb3d0ff264e1a81c6469a2ef7581649c908cf0e Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 16 Nov 2023 14:11:06 +0100 Subject: [PATCH 58/84] added action steps, loading vaults globally --- components/landing/Hero.tsx | 22 +- components/page/Page.tsx | 17 ++ components/vault/ActionSteps.tsx | 27 ++ components/vault/VaultInputs.tsx | 358 ++++++++++----------------- components/vepop/OPopInterface.tsx | 12 +- lib/approve.ts | 19 +- lib/atoms/vaults.ts | 5 + lib/gauges/interactions.ts | 260 ++++++++----------- lib/getNetworth.ts | 23 +- lib/types.ts | 20 +- lib/utils/connectors.ts | 8 +- lib/utils/helpers.ts | 28 ++- lib/vault/getActionSteps.ts | 144 +++++++++++ lib/vault/getOptionalMetadata.ts | 3 +- lib/vault/getVaultNetworth.ts | 96 ------- lib/vault/handleVaultInteraction.ts | 145 +++++++++++ lib/vault/interactions.ts | 275 +++----------------- lib/vault/zap.ts | 28 +-- next.config.js | 2 +- pages/_app.tsx | 2 +- pages/vaults.tsx | 79 +++--- pages/vepop.tsx | 23 +- public/images/loader/grid.svg | 38 +++ public/images/loader/progressBar.svg | 16 ++ public/images/loader/puff.svg | 16 ++ public/images/loader/spinner.svg | 12 + 26 files changed, 835 insertions(+), 843 deletions(-) create mode 100644 components/vault/ActionSteps.tsx create mode 100644 lib/atoms/vaults.ts create mode 100644 lib/vault/getActionSteps.ts delete mode 100644 lib/vault/getVaultNetworth.ts create mode 100644 lib/vault/handleVaultInteraction.ts create mode 100644 public/images/loader/grid.svg create mode 100644 public/images/loader/progressBar.svg create mode 100644 public/images/loader/puff.svg create mode 100644 public/images/loader/spinner.svg diff --git a/components/landing/Hero.tsx b/components/landing/Hero.tsx index 1dd9663..c833586 100644 --- a/components/landing/Hero.tsx +++ b/components/landing/Hero.tsx @@ -1,11 +1,15 @@ import StatusWithLabel from "@/components/common/StatusWithLabel"; -import { Networth, getTotalNetworth } from "@/lib/getNetworth"; +import { vaultsAtom } from "@/lib/atoms/vaults"; +import { Networth, getTotalNetworth, getVaultNetworthByChain } from "@/lib/getNetworth"; +import { SUPPORTED_NETWORKS } from "@/lib/utils/connectors"; import { NumberFormatter } from "@/lib/utils/formatBigNumber"; +import { useAtom } from "jotai"; import { useEffect, useState } from "react"; -import { useAccount } from "wagmi"; +import { Address, useAccount } from "wagmi"; export default function Hero(): JSX.Element { const { address: account } = useAccount(); + const [vaults] = useAtom(vaultsAtom) const [networth, setNetworth] = useState({ pop: 0, stake: 0, vault: 0, total: 0 }); const [tvl, setTvl] = useState("0"); const [loading, setLoading] = useState(true); @@ -19,13 +23,15 @@ export default function Hero(): JSX.Element { )) }, []) + useEffect(() => { - if (account && loading) - // fetch and set networth - getTotalNetworth({ account }).then(res => { - setNetworth(res.total); - setLoading(false); - }); + async function fetchNetworth() { + const vaultNetworth = SUPPORTED_NETWORKS.map(chain => getVaultNetworthByChain({ vaults, chainId: chain.id })).reduce((a, b) => a + b, 0) + const totalNetworth = await getTotalNetworth({ account: account as Address }) + setNetworth({ ...totalNetworth.total, vault: vaultNetworth, total: totalNetworth.total.total + vaultNetworth }); + setLoading(false); + } + if (account && loading && vaults.length > 0) fetchNetworth() }, [account]); diff --git a/components/page/Page.tsx b/components/page/Page.tsx index c91ef02..6bfdea2 100644 --- a/components/page/Page.tsx +++ b/components/page/Page.tsx @@ -9,6 +9,10 @@ import Navbar from "@/components/navbar/NavBar"; import { useAtom } from "jotai"; import { yieldOptionsAtom } from "@/lib/atoms/sdk"; import { CachedProvider, YieldOptions } from "vaultcraft-sdk"; +import { SUPPORTED_NETWORKS } from "@/lib/utils/connectors"; +import { getVaultsByChain } from "@/lib/vault/getVault"; +import { vaultsAtom } from "@/lib/atoms/vaults"; +import { useAccount } from "wagmi"; async function setUpYieldOptions() { const ttl = 360_000; @@ -20,8 +24,10 @@ async function setUpYieldOptions() { export default function Page({ children }: { children: JSX.Element }): JSX.Element { const { pathname } = useRouter(); + const { address: account } = useAccount() const [yieldOptions, setYieldOptions] = useAtom(yieldOptionsAtom) + const [, setVaults] = useAtom(vaultsAtom) useEffect(() => { if (!yieldOptions) { @@ -29,6 +35,17 @@ export default function Page({ children }: { children: JSX.Element }): JSX.Eleme } }, []) + useEffect(() => { + async function getVaults() { + // get vaults + const fetchedVaults = (await Promise.all( + SUPPORTED_NETWORKS.map(async (chain) => getVaultsByChain({ chain, account })) + )).flat(); + setVaults(fetchedVaults) + } + getVaults() + }, [account]) + return ( <> diff --git a/components/vault/ActionSteps.tsx b/components/vault/ActionSteps.tsx new file mode 100644 index 0000000..9d1f6e1 --- /dev/null +++ b/components/vault/ActionSteps.tsx @@ -0,0 +1,27 @@ +import { ActionStep } from "@/lib/vault/getActionSteps" + +function getStepColor(preFix: string, step: any): string { + if (step.loading) return `${preFix}-primary` + if (step.success) return `${preFix}-green-500` + if (step.error) return `${preFix}-red-500` + return `${preFix}-primaryLight` +} + +interface ActionStepsProps { + steps: ActionStep[] +} + +export default function ActionSteps({ steps }: ActionStepsProps): JSX.Element { + return ( +
+ { + steps.map(i => <> +
+ {i.loading ? :

{i.step}

} +
+ {i.step < steps.length &&

----->

} + ) + } +
+ ) +} \ No newline at end of file diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index e603a87..418e040 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -4,20 +4,17 @@ import MainActionButton from "@/components/button/MainActionButton"; import { useEffect, useState } from "react"; import { Address, useAccount, useNetwork, usePublicClient, useSwitchNetwork, useWalletClient } from "wagmi"; import TabSelector from "@/components/common/TabSelector"; -import { Token } from "@/lib/types"; -import { handleAllowance } from "@/lib/approve"; -import { vaultDeposit, vaultDepositAndStake, vaultRedeem, vaultUnstakeAndWithdraw, zapIntoGauge, zapIntoVault, zapOutOfGauge, zapOutOfVault } from "@/lib/vault/interactions"; +import { ActionType, Token } from "@/lib/types"; import { validateInput } from "@/lib/utils/helpers"; -import { getVeAddresses } from "@/lib/utils/addresses"; -import { gaugeDeposit, gaugeWithdraw } from "@/lib/gauges/interactions"; -import { ROUNDING_VALUE } from "@/lib/constants"; import Modal from "../modal/Modal"; import InputNumber from "../input/InputNumber"; import { MutateTokenBalanceProps } from "pages/vaults"; import { safeRound } from "@/lib/utils/formatBigNumber"; import { formatUnits, parseUnits } from "viem"; - -const { VaultRouter: VAULT_ROUTER } = getVeAddresses() +import handleVaultInteraction from "@/lib/vault/handleVaultInteraction"; +import getActionSteps, { ActionStep } from "@/lib/vault/getActionSteps"; +import { useConnectModal } from "@rainbow-me/rainbowkit"; +import ActionSteps from "./ActionSteps"; interface VaultInputsProps { vault: Token; @@ -34,10 +31,15 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId const { address: account } = useAccount(); const { chain } = useNetwork(); const { switchNetwork } = useSwitchNetwork(); + const { openConnectModal } = useConnectModal(); const [inputToken, setInputToken] = useState() const [outputToken, setOutputToken] = useState() + const [stepCounter, setStepCounter] = useState(0) + const [steps, setSteps] = useState([]) + const [action, setAction] = useState(ActionType.Deposit) + const [inputBalance, setInputBalance] = useState("0"); const [isDeposit, setIsDeposit] = useState(true); @@ -51,6 +53,9 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId // set default input/output tokens setInputToken(asset) setOutputToken(!!gauge ? gauge : vault) + const actionType = !!gauge ? ActionType.DepositAndStake : ActionType.Deposit + setAction(actionType) + setSteps(getActionSteps(actionType)) }, []) function handleChangeInput(e: any) { @@ -58,240 +63,135 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId setInputBalance(validateInput(value).isValid ? value : "0"); }; - function switchTokens() { + setStepCounter(0) if (isDeposit) { // Switch to Withdraw setInputToken(!!gauge ? gauge : vault); setOutputToken(asset) setIsDeposit(false) + setAction(!!gauge ? ActionType.UnstakeAndWithdraw : ActionType.Withdrawal) } else { // Switch to Deposit setInputToken(asset); setOutputToken(!!gauge ? gauge : vault) setIsDeposit(true) + setAction(!!gauge ? ActionType.DepositAndStake : ActionType.Deposit) } } - async function handleMainAction() { - const val = Number(inputBalance) - if (val === 0 || !inputToken || !outputToken || !account || !walletClient) return; - - if (chain?.id !== Number(chainId)) switchNetwork?.(Number(chainId)); - - switch (inputToken.address) { + function handleTokenSelect(input: Token, output: Token): void { + switch (input.address) { case asset.address: - console.log("in asset") - if (outputToken.address === vault.address) { - console.log("out vault") - await handleAllowance({ - token: inputToken.address, - inputAmount: (val * (10 ** inputToken.decimals)), - account, - spender: vault.address, - publicClient, - walletClient - }) - const success = await vaultDeposit({ - address: vault.address, - account, - amount: (val * (10 ** inputToken.decimals)), - publicClient, - walletClient - }) - if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) + switch (output.address) { + case asset.address: + // error + break + case vault.address: + setAction(ActionType.Deposit) + setSteps(getActionSteps(ActionType.Deposit)) + case gauge?.address: + setAction(ActionType.DepositAndStake) + setSteps(getActionSteps(ActionType.DepositAndStake)) + default: + // error + break } - else if (outputToken.address === gauge?.address) { - console.log("out gauge") - await handleAllowance({ - token: inputToken.address, - inputAmount: (val * (10 ** inputToken.decimals)), - account, - spender: VAULT_ROUTER, - publicClient, - walletClient - }) - const success = await vaultDepositAndStake({ - address: VAULT_ROUTER, - account, - amount: (val * (10 ** inputToken.decimals)), - vault: vault?.address as Address, - gauge: gauge?.address as Address, - publicClient, - walletClient - }) - if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) - } - else { - console.log("out error") - // wrong output token - return - } - break; case vault.address: - console.log("in vault") - if (outputToken.address === asset.address) { - console.log("out asset") - const success = await vaultRedeem({ - address: vault.address, - account, - amount: (val * (10 ** inputToken.decimals)), - publicClient, - walletClient - }) - if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) - } - else if (outputToken.address === gauge?.address) { - console.log("out gauge") - await handleAllowance({ - token: inputToken.address, - inputAmount: (val * (10 ** inputToken.decimals)), - account, - spender: gauge.address, - publicClient, - walletClient - }) - const success = await gaugeDeposit({ - address: gauge.address, - amount: (val * (10 ** inputToken.decimals)), - account, - clients: { - publicClient, - walletClient - } - }) - if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) - } - else if (outputToken.address === vault.address) { - console.log("out error") - // wrong output token - return - } - else { - console.log("out zap") - const success = await zapOutOfVault({ - chainId, - buyToken: outputToken.address, - asset: asset.address, - vault: vault.address, - account, - amount: (val * (10 ** inputToken.decimals)), - assetBal: asset.balance, - walletClient: walletClient, - publicClient: publicClient, - slippage, - tradeTimeout - }) - if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) + switch (output.address) { + case asset.address: + setAction(ActionType.Withdrawal) + setSteps(getActionSteps(ActionType.Withdrawal)) + case vault.address: + // error + break + case gauge?.address: + setAction(ActionType.Stake) + setSteps(getActionSteps(ActionType.Stake)) + default: + setAction(ActionType.ZapWithdrawal) + setSteps(getActionSteps(ActionType.ZapWithdrawal)) } - break; case gauge?.address: - console.log("in gauge") - if (outputToken.address === asset.address) { - console.log("out asset") - await handleAllowance({ - token: inputToken.address, - inputAmount: (val * (10 ** inputToken.decimals)), - account, - spender: VAULT_ROUTER, - publicClient, - walletClient - }) - const success = await vaultUnstakeAndWithdraw({ - address: VAULT_ROUTER, - account, - amount: (val * (10 ** inputToken.decimals)), - vault: vault.address, - gauge: gauge?.address as Address, - publicClient, - walletClient - }) - if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) + switch (output.address) { + case asset.address: + setAction(ActionType.UnstakeAndWithdraw) + setSteps(getActionSteps(ActionType.UnstakeAndWithdraw)) + case vault.address: + setAction(ActionType.Unstake) + setSteps(getActionSteps(ActionType.Unstake)) + case gauge?.address: + // error + break + default: + setAction(ActionType.ZapUnstakeAndWithdraw) + setSteps(getActionSteps(ActionType.ZapUnstakeAndWithdraw)) } - else if (outputToken.address === vault.address) { - console.log("out vault") - const success = await gaugeWithdraw({ - address: gauge?.address as Address, - amount: (val * (10 ** inputToken.decimals)), - account, - clients: { - publicClient, - walletClient - } - }) - if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) - } - else if (outputToken.address === gauge?.address) { - console.log("out error") - // wrong output token - return - } - else { - console.log("out zap") - console.log({ gaugeBal: gauge?.balance, amount: (val * (10 ** inputToken.decimals)) }) - const success = await zapOutOfGauge({ - chainId, - buyToken: outputToken.address, - asset: asset.address, - router: VAULT_ROUTER, - vault: vault.address, - gauge: gauge?.address as Address, - account, - amount: (val * (10 ** inputToken.decimals)), - assetBal: asset.balance, - walletClient: walletClient, - publicClient: publicClient, - slippage, - tradeTimeout - }) - if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) - } - break; default: - console.log("in zap asset") - if (outputToken.address === vault.address) { - console.log("out vault") - const success = await zapIntoVault({ - chainId, - sellToken: inputToken.address, - asset: asset.address, - vault: vault.address, - account, - amount: (val * (10 ** inputToken.decimals)), - assetBal: asset.balance, - slippage, - tradeTimeout, - publicClient, - walletClient - }) - if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) - } - else if (outputToken.address === gauge?.address) { - console.log("out gauge") - const success = await zapIntoGauge({ - chainId, - sellToken: inputToken.address, - router: VAULT_ROUTER, - asset: asset.address, - vault: vault.address, - gauge: gauge.address, - account, - amount: (val * (10 ** inputToken.decimals)), - assetBal: asset.balance, - slippage, - tradeTimeout, - publicClient, - walletClient - }) - if (success) mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) + switch (output.address) { + case asset.address: + // error + break + case vault.address: + setAction(ActionType.ZapDeposit) + setSteps(getActionSteps(ActionType.ZapDeposit)) + case gauge?.address: + setAction(ActionType.ZapDepositAndStake) + setSteps(getActionSteps(ActionType.ZapDepositAndStake)) + default: + // error + break } - else { - console.log("out error") - // wrong output token - return - } - break; } + setInputToken(input); + setOutputToken(output) + } + + async function handleMainAction() { + const val = Number(inputBalance) + if (val === 0 || !inputToken || !outputToken || !account || !walletClient) return; + + if (chain?.id !== Number(chainId)) switchNetwork?.(Number(chainId)); + + const stepsCopy = [...steps] + const currentStep = stepsCopy[stepCounter] + currentStep.loading = true + setSteps(stepsCopy) + + const vaultInteraction = await handleVaultInteraction({ + action, + stepCounter, + chainId, + amount: (val * (10 ** inputToken.decimals)), + inputToken, + outputToken, + asset, + vault, + gauge, + account, + slippage, + tradeTimeout, + clients: { publicClient, walletClient } + }) + const success = await vaultInteraction() + + currentStep.loading = false + currentStep.success = success; + currentStep.error = !success; + setSteps(stepsCopy) + setStepCounter(stepCounter + 1) + + if (stepCounter === steps.length) { + mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) + // Reset to start + setSteps(getActionSteps(action)) + setStepCounter(0) + } + } + + function resetActions() { + setSteps(getActionSteps(action)) + setStepCounter(0) } if (!inputToken || !outputToken) return <> @@ -380,12 +280,24 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId {((isDeposit && ![asset.address, vault.address].includes(inputToken.address)) || (!isDeposit && ![asset.address, vault.address].includes(outputToken.address))) &&
setShowModal(true)}> -
} -
- +
+ +
+
+ {account ? ( + <> + {(stepCounter === steps.length || steps.some(step => !step.loading && step.error)) ? + : + + } + + ) + : < MainActionButton label={"Connect Wallet"} handleClick={openConnectModal} /> + }
} \ No newline at end of file diff --git a/components/vepop/OPopInterface.tsx b/components/vepop/OPopInterface.tsx index 26f8ed7..e6da3fb 100644 --- a/components/vepop/OPopInterface.tsx +++ b/components/vepop/OPopInterface.tsx @@ -8,6 +8,7 @@ import MainActionButton from "../button/MainActionButton"; import SecondaryActionButton from "../button/SecondaryActionButton"; import { claimOPop } from "@/lib/oPop/interactions"; import { WalletClient } from "viem"; +import { Token } from "@/lib/types"; const { GaugeController: GAUGE_CONTROLLER, @@ -17,10 +18,11 @@ const { } = getVeAddresses(); interface OPopInterfaceProps { + gauges: Token[]; setShowOPopModal: Dispatch>; } -export default function OPopInterface({ setShowOPopModal }: OPopInterfaceProps): JSX.Element { +export default function OPopInterface({ gauges, setShowOPopModal }: OPopInterfaceProps): JSX.Element { const { address: account } = useAccount() const publicClient = usePublicClient(); const { data: walletClient } = useWalletClient() @@ -35,17 +37,15 @@ export default function OPopInterface({ setShowOPopModal }: OPopInterfaceProps): useEffect(() => { async function getValues() { setInitalLoad(true) - const gauges = await getGauges({ address: GAUGE_CONTROLLER, account: account, publicClient }) - const rewards = await getGaugeRewards({ - gauges: gauges.filter(gauge => gauge.chainId === 1).map(gauge => gauge.address) as Address[], + gauges: gauges.map(gauge => gauge.address) as Address[], account: account as Address, publicClient }) setGaugeRewards(rewards) } - if (account && !initalLoad) getValues() - }, [account]) + if (account && gauges.length > 0 && !initalLoad) getValues() + }, [gauges, account]) return (
diff --git a/lib/approve.ts b/lib/approve.ts index 7cd5052..e17f97c 100644 --- a/lib/approve.ts +++ b/lib/approve.ts @@ -1,15 +1,14 @@ import { Address, PublicClient, WalletClient } from "viem" import { ERC20Abi } from "@/lib/constants" import { showErrorToast, showLoadingToast, showSuccessToast } from "@/lib/toasts" -import { SimulationResponse, Token } from "@/lib/types"; +import { Clients, SimulationResponse, Token } from "@/lib/types"; interface HandleAllowanceProps { token: Address; - inputAmount: number; + amount: number; account: Address; spender: Address; - publicClient: PublicClient; - walletClient: WalletClient; + clients: Clients; } interface SimulateApproveProps { @@ -19,25 +18,25 @@ interface SimulateApproveProps { publicClient: PublicClient; } -interface ApprovePops extends SimulateApproveProps { +interface ApproveProps extends SimulateApproveProps { walletClient: WalletClient; } -export async function handleAllowance({ token, inputAmount, account, spender, publicClient, walletClient }: HandleAllowanceProps): Promise { - const allowance = await publicClient.readContract({ +export async function handleAllowance({ token, amount, account, spender, clients }: HandleAllowanceProps): Promise { + const allowance = await clients.publicClient.readContract({ address: token, abi: ERC20Abi, functionName: "allowance", args: [account, spender] }) - if (Number(allowance) === 0 || Number(allowance) < inputAmount) { - return approve({ address: token, account, spender, publicClient, walletClient }) + if (Number(allowance) === 0 || Number(allowance) < amount) { + return approve({ address: token, account, spender, publicClient: clients.publicClient, walletClient: clients.walletClient }) } return true } -export default async function approve({ address, account, spender, publicClient, walletClient }: ApprovePops): Promise { +export default async function approve({ address, account, spender, publicClient, walletClient }: ApproveProps): Promise { showLoadingToast("Approving assets for deposit...") const { request, success, error: simulationError } = await simulateApprove({ address, account, spender, publicClient }) diff --git a/lib/atoms/vaults.ts b/lib/atoms/vaults.ts new file mode 100644 index 0000000..ccf5554 --- /dev/null +++ b/lib/atoms/vaults.ts @@ -0,0 +1,5 @@ +import { atom } from "jotai"; +import { VaultData } from "@/lib/types"; + + +export const vaultsAtom = atom([]); diff --git a/lib/gauges/interactions.ts b/lib/gauges/interactions.ts index d883ed6..e3e9b7d 100644 --- a/lib/gauges/interactions.ts +++ b/lib/gauges/interactions.ts @@ -4,6 +4,7 @@ import { showErrorToast, showLoadingToast, showSuccessToast } from "@/lib/toasts import { SimulationResponse } from "@/lib/types"; import { getVeAddresses } from "@/lib/utils/addresses"; import { GaugeAbi, GaugeControllerAbi, VotingEscrowAbi } from "@/lib/constants"; +import { handleCallResult } from "../utils/helpers"; type SimulationContract = { address: Address; @@ -48,7 +49,7 @@ interface SendVotesProps { clients: Clients; } -export async function sendVotes({ vaults, votes, account, clients }: SendVotesProps) { +export async function sendVotes({ vaults, votes, account, clients }: SendVotesProps): Promise { showLoadingToast("Sending votes...") let addr = new Array(8); @@ -65,29 +66,23 @@ export async function sendVotes({ vaults, votes, account, clients }: SendVotesPr } - const { request, success, error: simulationError } = await simulateCall({ - account, - contract: { - address: GAUGE_CONTROLLER, - abi: GaugeControllerAbi, - }, - functionName: "vote_for_many_gauge_weights", - publicClient: clients.publicClient, - args: [addr, v] + const success = await handleCallResult({ + successMessage: "Voted for gauges!", + simulationResponse: await simulateCall({ + account, + contract: { + address: GAUGE_CONTROLLER, + abi: GaugeControllerAbi, + }, + functionName: "vote_for_many_gauge_weights", + publicClient: clients.publicClient, + args: [addr, v] + }), + clients }) - - if (success) { - try { - const hash = await clients.walletClient.writeContract(request) - const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Voted for gauges!") - } catch (error: any) { - showErrorToast(error.shortMessage) - } - } else { - showErrorToast(simulationError) - } + if (!success) return false } + return true } interface CreateLockProps { @@ -97,31 +92,23 @@ interface CreateLockProps { clients: Clients; } -export async function createLock({ amount, days, account, clients }: CreateLockProps) { +export async function createLock({ amount, days, account, clients }: CreateLockProps): Promise { showLoadingToast("Creating lock...") - const { request, success, error: simulationError } = await simulateCall({ - account, - contract: { - address: VOTING_ESCROW, - abi: VotingEscrowAbi, - }, - functionName: "create_lock", - publicClient: clients.publicClient, - args: [parseEther(Number(amount).toLocaleString("fullwide", { useGrouping: false })), BigInt(Math.floor(Date.now() / 1000) + (86400 * days))] + return handleCallResult({ + successMessage: "Lock created successfully!", + simulationResponse: await simulateCall({ + account, + contract: { + address: VOTING_ESCROW, + abi: VotingEscrowAbi, + }, + functionName: "create_lock", + publicClient: clients.publicClient, + args: [parseEther(Number(amount).toLocaleString("fullwide", { useGrouping: false })), BigInt(Math.floor(Date.now() / 1000) + (86400 * days))] + }), + clients }) - - if (success) { - try { - const hash = await clients.walletClient.writeContract(request) - const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Lock created successfully!") - } catch (error: any) { - showErrorToast(error.shortMessage) - } - } else { - showErrorToast(simulationError) - } } interface IncreaseLockAmountProps { @@ -130,31 +117,23 @@ interface IncreaseLockAmountProps { clients: Clients; } -export async function increaseLockAmount({ amount, account, clients }: IncreaseLockAmountProps) { +export async function increaseLockAmount({ amount, account, clients }: IncreaseLockAmountProps): Promise { showLoadingToast("Increasing lock amount...") - const { request, success, error: simulationError } = await simulateCall({ - account, - contract: { - address: VOTING_ESCROW, - abi: VotingEscrowAbi, - }, - functionName: "increase_amount", - publicClient: clients.publicClient, - args: [parseEther(Number(amount).toLocaleString("fullwide", { useGrouping: false }))] + return handleCallResult({ + successMessage: "Lock amount increased successfully!", + simulationResponse: await simulateCall({ + account, + contract: { + address: VOTING_ESCROW, + abi: VotingEscrowAbi, + }, + functionName: "increase_amount", + publicClient: clients.publicClient, + args: [parseEther(Number(amount).toLocaleString("fullwide", { useGrouping: false }))] + }), + clients }) - - if (success) { - try { - const hash = await clients.walletClient.writeContract(request) - const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Lock amount increased successfully!") - } catch (error: any) { - showErrorToast(error.shortMessage) - } - } else { - showErrorToast(simulationError) - } } interface IncreaseLockTimeProps { @@ -163,31 +142,23 @@ interface IncreaseLockTimeProps { clients: Clients; } -export async function increaseLockTime({ unlockTime, account, clients }: IncreaseLockTimeProps) { +export async function increaseLockTime({ unlockTime, account, clients }: IncreaseLockTimeProps): Promise { showLoadingToast("Increasing lock time...") - const { request, success, error: simulationError } = await simulateCall({ - account, - contract: { - address: VOTING_ESCROW, - abi: VotingEscrowAbi, - }, - functionName: "increase_unlock_time", - publicClient: clients.publicClient, - args: [BigInt(unlockTime)] + return handleCallResult({ + successMessage: "Lock amount increased successfully!", + simulationResponse: await simulateCall({ + account, + contract: { + address: VOTING_ESCROW, + abi: VotingEscrowAbi, + }, + functionName: "increase_unlock_time", + publicClient: clients.publicClient, + args: [BigInt(unlockTime)] + }), + clients }) - - if (success) { - try { - const hash = await clients.walletClient.writeContract(request) - const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Lock time increased successfully!") - } catch (error: any) { - showErrorToast(error.shortMessage) - } - } else { - showErrorToast(simulationError) - } } interface WithdrawLockProps { @@ -195,95 +166,66 @@ interface WithdrawLockProps { clients: Clients; } -export async function withdrawLock({ account, clients }: WithdrawLockProps) { +export async function withdrawLock({ account, clients }: WithdrawLockProps): Promise { showLoadingToast("Withdrawing lock...") - const { request, success, error: simulationError } = await simulateCall({ - account, - contract: { - address: VOTING_ESCROW, - abi: VotingEscrowAbi, - }, - functionName: "withdraw", - publicClient: clients.publicClient, + return handleCallResult({ + successMessage: "Withdrawal successful!", + simulationResponse: await simulateCall({ + account, + contract: { + address: VOTING_ESCROW, + abi: VotingEscrowAbi, + }, + functionName: "withdraw", + publicClient: clients.publicClient, + }), + clients }) - - if (success) { - try { - const hash = await clients.walletClient.writeContract(request) - const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Withdrawal successful!") - } catch (error: any) { - showErrorToast(error.shortMessage) - } - } else { - showErrorToast(simulationError) - } } interface GaugeInteractionProps { + chainId: number; address: Address; amount: number; account: Address; clients: Clients; } -export async function gaugeDeposit({ address, amount, account, clients }: GaugeInteractionProps): Promise { +export async function gaugeDeposit({ chainId, address, amount, account, clients }: GaugeInteractionProps): Promise { showLoadingToast("Staking into Gauge...") - const { request, success, error: simulationError } = await simulateCall({ - account, - contract: { - address, - abi: GaugeAbi, - }, - functionName: "deposit", - publicClient: clients.publicClient, - args: [amount] + return handleCallResult({ + successMessage: "Staked into Gauge successful!", + simulationResponse: await simulateCall({ + account, + contract: { + address, + abi: GaugeAbi, + }, + functionName: "deposit", + publicClient: clients.publicClient, + args: [amount] + }), + clients }) - - if (success) { - try { - const hash = await clients.walletClient.writeContract(request) - const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Staked into Gauge successful!") - return true - } catch (error: any) { - showErrorToast(error.shortMessage) - return false; - } - } else { - showErrorToast(simulationError) - return false; - } } -export async function gaugeWithdraw({ address, amount, account, clients }: GaugeInteractionProps): Promise { +export async function gaugeWithdraw({ chainId, address, amount, account, clients }: GaugeInteractionProps): Promise { showLoadingToast("Unstaking from Gauge...") - const { request, success, error: simulationError } = await simulateCall({ - account, - contract: { - address, - abi: GaugeAbi, - }, - functionName: "withdraw", - publicClient: clients.publicClient, - args: [amount] + return handleCallResult({ + successMessage: "Unstaked from Gauge successful!", + simulationResponse: await simulateCall({ + account, + contract: { + address, + abi: GaugeAbi, + }, + functionName: "withdraw", + publicClient: clients.publicClient, + args: [amount] + }), + clients }) - - if (success) { - try { - const hash = await clients.walletClient.writeContract(request) - const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Unstaked from Gauge successful!") - return true - } catch (error: any) { - showErrorToast(error.shortMessage) - return false; - } - } else { - showErrorToast(simulationError) - return false; - } } \ No newline at end of file diff --git a/lib/getNetworth.ts b/lib/getNetworth.ts index 37ab5f0..0d9705e 100644 --- a/lib/getNetworth.ts +++ b/lib/getNetworth.ts @@ -3,9 +3,8 @@ import { Chain, arbitrum, optimism, polygon } from "viem/chains"; import { Address, mainnet } from "wagmi"; import { ChainId, RPC_URLS } from "@/lib/utils/connectors"; import { ERC20Abi, PopByChain, PopStakingByChain } from "@/lib/constants"; -import getVaultAddresses from "@/lib/vault/getVaultAddresses"; import { resolvePrice } from "@/lib/resolver/price/price"; -import { getVaultNetworthByChain } from "@/lib/vault/getVaultNetworth"; +import { VaultData } from "./types"; const BaseAddressesByChain: { [key: number]: Address[] } = { 1: [PopByChain[ChainId.Ethereum], PopStakingByChain[ChainId.Ethereum]], @@ -26,6 +25,14 @@ export type Networth = { total: number } +export function getVaultNetworthByChain({ vaults, chainId }: { vaults: VaultData[], chainId: number }): number { + const vaultValue = vaults.filter(vaultData => vaultData.chainId === chainId).map(vaultData => (vaultData.vault.balance * vaultData.vault.price) / (10 ** vaultData.vault.decimals)).reduce((a, b) => a + b, 0) + const gaugeValue = vaults.filter( + vaultData => vaultData.chainId === chainId && !!vaultData.gauge?.address) + .map(vaultData => ((vaultData.gauge?.balance || 0) * (vaultData.gauge?.price || 0)) / (10 ** (vaultData.gauge?.decimals || 0))).reduce((a, b) => a + b, 0) + return vaultValue + gaugeValue +} + async function getBalancesByChain({ account, client, addresses }: { account: Address, client: PublicClient, addresses: Address[] }) : Promise<{ address: Address, balance: number, decimals: number }[]> { let res = await client.multicall({ @@ -58,22 +65,16 @@ export async function getNetworthByChain({ account, chain }: { account: Address, chain, transport: http(RPC_URLS[chain.id]) }) - // Get addresses - const vaultAddresses = await getVaultAddresses({ client }) - const addresses = [...BaseAddressesByChain[client.chain?.id as number], ...vaultAddresses] // Get balances - const balances = await getBalancesByChain({ account, client, addresses }) + const balances = await getBalancesByChain({ account, client, addresses: BaseAddressesByChain[client.chain?.id as number] }) // Get value of POP holdings const popPrice = await resolvePrice({ address: PopByChain[10], chainId: 10, client: undefined, resolver: 'llama' }) const popNetworth = ((balances.find(entry => entry.address === PopByChain[chain.id])?.balance || 0) * popPrice) / (1e18); const stakeNetworth = ((balances.find(entry => entry.address === PopStakingByChain[chain.id])?.balance || 0) * popPrice) / (1e18); - // Get value of vault holdings - const vaultNetworth = await getVaultNetworthByChain({ account, chain }) - - return { pop: popNetworth, stake: stakeNetworth, vault: vaultNetworth, total: popNetworth + stakeNetworth + vaultNetworth } + return { pop: popNetworth, stake: stakeNetworth, vault: 0, total: popNetworth + stakeNetworth } } export async function getTotalNetworth({ account }: { account: Address }): Promise { @@ -90,7 +91,7 @@ export async function getTotalNetworth({ account }: { account: Address }): Promi total: { pop: ethereumNetworth.pop + polygonNetworth.pop + optimismNetworth.pop + arbitrumNetworth.pop, stake: ethereumNetworth.stake + polygonNetworth.stake + optimismNetworth.stake + arbitrumNetworth.stake, - vault: ethereumNetworth.vault + polygonNetworth.vault + optimismNetworth.vault + arbitrumNetworth.vault, + vault: 0, total: ethereumNetworth.total + polygonNetworth.total + optimismNetworth.total + arbitrumNetworth.total } } diff --git a/lib/types.ts b/lib/types.ts index 29376f3..9d6d886 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,5 +1,5 @@ import { ProtocolName } from "vaultcraft-sdk"; -import { Address } from "viem"; +import { Address, PublicClient, WalletClient } from "viem"; export type Token = { address: Address; @@ -106,4 +106,22 @@ export interface IconProps { color: string; size: string; className?: string; +} + +export interface Clients { + publicClient: PublicClient; + walletClient: WalletClient; +} + +export enum ActionType { + Deposit, + Withdrawal, + Stake, + Unstake, + DepositAndStake, + UnstakeAndWithdraw, + ZapDeposit, + ZapWithdrawal, + ZapDepositAndStake, + ZapUnstakeAndWithdraw } \ No newline at end of file diff --git a/lib/utils/connectors.ts b/lib/utils/connectors.ts index 458fa13..87c973e 100644 --- a/lib/utils/connectors.ts +++ b/lib/utils/connectors.ts @@ -81,10 +81,10 @@ export const networkLogos: { [key: number]: string } = { [ChainId.RemoteFork]: "/images/networks/testNets.png", }; export const RPC_URLS: { [key: number]: string } = { - [ChainId.Ethereum]: `https://eth-mainnet.alchemyapi.io/v2/${process.env.NEXT_PUBLIC_ALCHEMY_API_KEY}`, - [ChainId.Arbitrum]: `https://arb-mainnet.g.alchemy.com/v2/${process.env.NEXT_PUBLIC_ALCHEMY_API_KEY}`, - [ChainId.Polygon]: `https://polygon-mainnet.g.alchemy.com/v2/${process.env.NEXT_PUBLIC_ALCHEMY_API_KEY}`, - [ChainId.Optimism]: `https://opt-mainnet.g.alchemy.com/v2/${process.env.NEXT_PUBLIC_ALCHEMY_API_KEY}`, + [ChainId.Ethereum]: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, + [ChainId.Arbitrum]: `https://arb-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`, + [ChainId.Polygon]: `https://polygon-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`, + [ChainId.Optimism]: `https://opt-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`, [ChainId.Goerli]: "https://goerli.blockpi.network/v1/rpc/public", [ChainId.BNB]: `https://bsc-dataseed1.binance.org`, [ChainId.Localhost]: `http://localhost:8545`, diff --git a/lib/utils/helpers.ts b/lib/utils/helpers.ts index 8efc54c..ab847f7 100644 --- a/lib/utils/helpers.ts +++ b/lib/utils/helpers.ts @@ -1,7 +1,33 @@ +import { showErrorToast, showSuccessToast } from "../toasts"; +import { Clients, SimulationResponse } from "../types"; + export function validateInput(value: string | number): { formatted: string, isValid: boolean } { const formatted = value === "." ? "0" : (`${value || "0"}`.replace(/\.$/, ".0") as any); return { formatted, isValid: value === "" || isFinite(Number(formatted)), }; -}; \ No newline at end of file +}; + +interface HandleCallResultProps { + successMessage: string; + simulationResponse: SimulationResponse; + clients: Clients; +} + +export async function handleCallResult({ successMessage, simulationResponse, clients }: HandleCallResultProps): Promise { + if (simulationResponse.success) { + try { + const hash = await clients.walletClient.writeContract(simulationResponse.request) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) + showSuccessToast(successMessage) + return true; + } catch (error: any) { + showErrorToast(error.shortMessage) + return false; + } + } else { + showErrorToast(simulationResponse.error) + return false; + } +} \ No newline at end of file diff --git a/lib/vault/getActionSteps.ts b/lib/vault/getActionSteps.ts new file mode 100644 index 0000000..3b4a9e3 --- /dev/null +++ b/lib/vault/getActionSteps.ts @@ -0,0 +1,144 @@ +import { ActionType } from "../types"; + +export interface ActionStep { + step: number; + label: string; + success: boolean; + error: boolean; + loading: boolean; +} + +const BaseStepInfo = { + success: false, + error: false, + loading: false +} + +export default function getActionSteps(action: ActionType): ActionStep[] { + switch (action) { + case ActionType.Deposit: + return [{ + step: 1, + label: "Handle Allowance", + ...BaseStepInfo + }, + { + step: 2, + label: "Deposit into Vault", + ...BaseStepInfo + }] + case ActionType.Withdrawal: + return [{ + step: 1, + label: "Withdraw from Vault", + ...BaseStepInfo + }] + case ActionType.Stake: + return [{ + step: 1, + label: "Handle Allowance", + ...BaseStepInfo + }, + { + step: 2, + label: "Stake into Gauge", + ...BaseStepInfo + }] + case ActionType.Unstake: + return [{ + step: 1, + label: "Unstake from Gauge", + ...BaseStepInfo + }] + case ActionType.DepositAndStake: + return [{ + step: 1, + label: "Handle Allowance", + ...BaseStepInfo + }, + { + step: 2, + label: "Deposit and Stake", + ...BaseStepInfo + }] + case ActionType.UnstakeAndWithdraw: + return [{ + step: 1, + label: "Handle Allowance", + ...BaseStepInfo + }, + { + step: 2, + label: "Unstake and Withdraw", + ...BaseStepInfo + }] + case ActionType.ZapDeposit: + return [{ + step: 1, + label: "Handle Zap Allowance", + ...BaseStepInfo + }, { + step: 2, + label: "Zap", + ...BaseStepInfo + }, { + step: 3, + label: "Handle Allowance", + ...BaseStepInfo + }, { + step: 4, + label: "Deposit", + ...BaseStepInfo + }] + case ActionType.ZapWithdrawal: + return [{ + step: 1, + label: "Withdraw", + ...BaseStepInfo + }, { + step: 2, + label: "Handle Zap Allowance", + ...BaseStepInfo + }, { + step: 3, + label: "Zap", + ...BaseStepInfo + }] + case ActionType.ZapDepositAndStake: + return [{ + step: 1, + label: "Handle Zap Allowance", + ...BaseStepInfo + }, { + step: 2, + label: "Zap", + ...BaseStepInfo + }, { + step: 3, + label: "Handle Allowance", + ...BaseStepInfo + }, { + step: 4, + label: "Deposit and Stake", + ...BaseStepInfo + }] + case ActionType.ZapUnstakeAndWithdraw: + return [{ + step: 1, + label: "Handle Allowance", + ...BaseStepInfo + }, { + step: 2, + label: "Unstake and Withdraw", + ...BaseStepInfo + }, { + step: 3, + label: "Handle Zap Allowance", + ...BaseStepInfo + }, { + step: 4, + label: "Zap", + ...BaseStepInfo + }] + } +} \ No newline at end of file diff --git a/lib/vault/getOptionalMetadata.ts b/lib/vault/getOptionalMetadata.ts index 61727cd..7161cfa 100644 --- a/lib/vault/getOptionalMetadata.ts +++ b/lib/vault/getOptionalMetadata.ts @@ -1,9 +1,8 @@ import TokenMetadata, { addLpMetadata } from "@/lib/utils/metadata/tokenMetadata"; import ProtocolMetadata from "@/lib/utils/metadata/protocolMetadata"; import StrategyMetadata, { addGenericStrategyDescription } from "@/lib/utils/metadata/strategyMetadata"; -import { Token } from "../types"; +import { Token, OptionalMetadata } from "../types"; import { Address } from "viem"; -import { OptionalMetadata } from "./getVault"; function getLocalMetadata(address: string): OptionalMetadata | undefined { switch (address) { diff --git a/lib/vault/getVaultNetworth.ts b/lib/vault/getVaultNetworth.ts deleted file mode 100644 index 41ed07e..0000000 --- a/lib/vault/getVaultNetworth.ts +++ /dev/null @@ -1,96 +0,0 @@ -import axios from "axios"; -import { Address, PublicClient, mainnet } from "wagmi"; -import { ChainId, RPC_URLS, networkMap } from "@/lib/utils/connectors"; -import { VaultAbi } from "@/lib/constants"; -import getVaultAddresses from "@/lib/vault/getVaultAddresses"; -import { Chain, createPublicClient, http } from "viem"; -import { arbitrum, optimism, polygon } from "viem/chains"; - -function prepareContract(address: Address, account: Address) { - const vaultContract = { - address, - abi: VaultAbi - } - return [{ - ...vaultContract, - functionName: 'asset' - }, - { - ...vaultContract, - functionName: 'totalAssets' - }, - { - ...vaultContract, - functionName: 'totalSupply' - }, - { - ...vaultContract, - functionName: 'balanceOf', - args: [account] - }, - { - ...vaultContract, - functionName: 'decimals' - }] -} - -async function getVaultValues({ addresses, account, client }: { addresses: Address[], account: Address, client: PublicClient }): Promise { - const res = await client.multicall({ contracts: addresses.map(address => prepareContract(address, account)).flat(), allowFailure: false }) - - return addresses.map((address, i) => { - if (i > 0) i = i * 5 - const assetsPerShare = Number(res[i + 1]) === 0 ? 0 : Number(res[i + 1]) / Number(res[i + 2]) - return { - vault: address, - asset: res[i] as Address, - assetsPerShare: assetsPerShare, - totalAssets: Number(res[i + 1]), - totalSupply: Number(res[i + 2]), - balance: Number(res[i + 3]), - decimals: Number(res[i + 4]) - } - }) -} - -export async function getVaultNetworthByChain({ account, chain }: { account: Address, chain: Chain }): Promise { - const client = createPublicClient({ - chain, - transport: http(RPC_URLS[chain.id]) - }) - const addresses = await getVaultAddresses({ client }) - const vaultValues = await getVaultValues({ addresses, account, client }) - const { data } = await axios.get(`https://coins.llama.fi/prices/current/${String(vaultValues.map(entry => `${networkMap[chain.id].toLowerCase()}:${entry.asset}`))}`) - const vaults = vaultValues.map((entry, i) => { - const assetPrice = Number(data.coins[`${networkMap[chain.id].toLowerCase()}:${entry.asset}`]?.price || 0) - return { - ...entry, - price: assetPrice * entry.assetsPerShare, - balanceValue: entry.balance === 0 ? 0 : (entry.balance * assetPrice * entry.assetsPerShare) / (10 ** ((entry.decimals as number) - 9)) - } - }) - - return vaults.reduce((acc, entry) => acc + entry.balanceValue, 0) -} - -type VaultNetworth = { - [ChainId.Ethereum]: number, - [ChainId.Polygon]: number, - [ChainId.Optimism]: number, - [ChainId.Arbitrum]: number, - total: number -} - -export default async function getVaultNetworth({ account }: { account: Address }): Promise { - const ethereumNetworth = await getVaultNetworthByChain({ account, chain: mainnet }) - const polygonNetworth = await getVaultNetworthByChain({ account, chain: polygon }) - const optimismNetworth = await getVaultNetworthByChain({ account, chain: optimism }) - const arbitrumNetworth = await getVaultNetworthByChain({ account, chain: arbitrum }) - - return { - [ChainId.Ethereum]: ethereumNetworth, - [ChainId.Polygon]: polygonNetworth, - [ChainId.Optimism]: optimismNetworth, - [ChainId.Arbitrum]: arbitrumNetworth, - total: ethereumNetworth + polygonNetworth + optimismNetworth + arbitrumNetworth - } -} \ No newline at end of file diff --git a/lib/vault/handleVaultInteraction.ts b/lib/vault/handleVaultInteraction.ts new file mode 100644 index 0000000..42faead --- /dev/null +++ b/lib/vault/handleVaultInteraction.ts @@ -0,0 +1,145 @@ +import axios from "axios" +import { Address, getAddress } from "viem"; +import { handleAllowance } from "../approve"; +import { ActionType, Clients, Token } from "../types"; +import { vaultDeposit, vaultDepositAndStake, vaultRedeem, vaultUnstakeAndWithdraw } from "./interactions"; +import zap from "./zap"; +import { getVeAddresses } from "../utils/addresses"; +import { gaugeDeposit, gaugeWithdraw } from "../gauges/interactions"; +import { erc20ABI } from "wagmi"; + +const { VaultRouter: VAULT_ROUTER } = getVeAddresses() + +interface HandleVaultInteractionProps { + stepCounter: number; + action: ActionType; + chainId: number; + amount: number; + inputToken: Token; + outputToken: Token; + asset: Token, + vault: Token, + gauge?: Token, + account: Address, + slippage: number; + tradeTimeout: number, + clients: Clients, +} + +export default async function handleVaultInteraction({ + action, + stepCounter, + chainId, + amount, + inputToken, + outputToken, + asset, + vault, + gauge, + account, + slippage, + tradeTimeout, + clients, +}: HandleVaultInteractionProps): Promise<() => Promise> { + let postBal = 0; + switch (action) { + case ActionType.Deposit: + switch (stepCounter) { + case 0: + return () => handleAllowance({ token: inputToken.address, amount, account, spender: outputToken.address, clients }) + case 1: + return () => vaultDeposit({ chainId, vault: vault.address, account, amount, clients }) + } + case ActionType.Withdrawal: + return () => vaultRedeem({ chainId, vault: vault.address, account, amount, clients }) + case ActionType.Stake: + switch (stepCounter) { + case 0: + return () => handleAllowance({ token: inputToken.address, amount, account, spender: gauge?.address as Address, clients }) + case 1: + return () => gaugeDeposit({ chainId, address: gauge?.address as Address, account, amount, clients }) + } + case ActionType.Unstake: + return () => gaugeWithdraw({ chainId, address: gauge?.address as Address, account, amount, clients }) + case ActionType.DepositAndStake: + switch (stepCounter) { + case 0: + return () => handleAllowance({ token: inputToken.address, amount, account, spender: VAULT_ROUTER, clients }) + case 1: + return () => vaultDepositAndStake({ chainId, router: VAULT_ROUTER, vault: vault.address, gauge: gauge?.address as Address, account, amount, clients }) + } + case ActionType.UnstakeAndWithdraw: + switch (stepCounter) { + case 0: + return () => handleAllowance({ token: inputToken.address, amount, account, spender: VAULT_ROUTER, clients }) + case 1: + return () => vaultUnstakeAndWithdraw({ chainId, router: VAULT_ROUTER, vault: vault.address, gauge: gauge?.address as Address, account, amount, clients }) + } + case ActionType.ZapDeposit: + switch (stepCounter) { + case 0: + const ensoWallet = (await axios.get( + `https://api.enso.finance/api/v1/wallet?chainId=${chainId}&fromAddress=${account}`, + { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } }) + ).data + return () => handleAllowance({ token: inputToken.address, amount, account, spender: getAddress(ensoWallet.address), clients }) + case 1: + return () => zap({ chainId, sellToken: inputToken.address, buyToken: asset.address, amount, account, slippage, tradeTimeout, clients }) + case 2: + postBal = Number(await clients.publicClient.readContract({ address: asset.address, abi: erc20ABI, functionName: "balanceOf", args: [account] })) + return () => handleAllowance({ token: asset.address, amount: postBal - asset.balance, account, spender: vault.address, clients }) + case 3: + postBal = Number(await clients.publicClient.readContract({ address: asset.address, abi: erc20ABI, functionName: "balanceOf", args: [account] })) + return () => vaultDeposit({ chainId, vault: vault.address, account, amount: postBal - asset.balance, clients }) + } + case ActionType.ZapWithdrawal: + switch (stepCounter) { + case 0: + return () => vaultRedeem({ chainId, vault: vault.address, account, amount, clients }) + case 1: + const ensoWallet = (await axios.get( + `https://api.enso.finance/api/v1/wallet?chainId=${chainId}&fromAddress=${account}`, + { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } }) + ).data + return () => handleAllowance({ token: asset.address, amount, account, spender: getAddress(ensoWallet.address), clients }) + case 2: + postBal = Number(await clients.publicClient.readContract({ address: asset.address, abi: erc20ABI, functionName: "balanceOf", args: [account] })) + return () => zap({ chainId, sellToken: asset.address, buyToken: outputToken.address, amount: postBal - asset.balance, account, slippage, tradeTimeout, clients }) + } + case ActionType.ZapDepositAndStake: + switch (stepCounter) { + case 0: + const ensoWallet = (await axios.get( + `https://api.enso.finance/api/v1/wallet?chainId=${chainId}&fromAddress=${account}`, + { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } }) + ).data + return () => handleAllowance({ token: inputToken.address, amount, account, spender: getAddress(ensoWallet.address), clients }) + case 1: + return () => zap({ chainId, sellToken: inputToken.address, buyToken: asset.address, amount, account, slippage, tradeTimeout, clients }) + case 2: + postBal = Number(await clients.publicClient.readContract({ address: asset.address, abi: erc20ABI, functionName: "balanceOf", args: [account] })) + return () => handleAllowance({ token: asset.address, amount: postBal - asset.balance, account, spender: VAULT_ROUTER, clients }) + case 3: + postBal = Number(await clients.publicClient.readContract({ address: asset.address, abi: erc20ABI, functionName: "balanceOf", args: [account] })) + return () => vaultDepositAndStake({ chainId, router: VAULT_ROUTER, vault: vault.address, gauge: gauge?.address as Address, account, amount: postBal - asset.balance, clients }) + } + case ActionType.ZapUnstakeAndWithdraw: + switch (stepCounter) { + case 0: + return () => handleAllowance({ token: inputToken.address, amount, account, spender: VAULT_ROUTER, clients }) + case 1: + return () => vaultUnstakeAndWithdraw({ chainId, router: VAULT_ROUTER, vault: vault.address, gauge: gauge?.address as Address, account, amount, clients }) + case 2: + const ensoWallet = (await axios.get( + `https://api.enso.finance/api/v1/wallet?chainId=${chainId}&fromAddress=${account}`, + { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } }) + ).data + return () => handleAllowance({ token: asset.address, amount, account, spender: getAddress(ensoWallet.address), clients }) + case 3: + return () => zap({ chainId, sellToken: asset.address, buyToken: outputToken.address, amount, account, slippage, tradeTimeout, clients }) + } + default: + // We should never reach this code. This is here just to make ts happy + return async () => false + } +} \ No newline at end of file diff --git a/lib/vault/interactions.ts b/lib/vault/interactions.ts index 163e72c..f1ecaa4 100644 --- a/lib/vault/interactions.ts +++ b/lib/vault/interactions.ts @@ -1,83 +1,32 @@ -import { showSuccessToast, showErrorToast, showLoadingToast } from "@/lib/toasts"; -import { SimulationResponse } from "@/lib/types"; -import { ERC20Abi, VaultAbi } from "@/lib/constants"; -import { Address, PublicClient, WalletClient } from "viem"; +import { showLoadingToast } from "@/lib/toasts"; +import { Clients, SimulationResponse } from "@/lib/types"; +import { VaultAbi } from "@/lib/constants"; +import { Address, PublicClient } from "viem"; import { VaultRouterAbi } from "@/lib/constants/abi/VaultRouter"; -import zap from "./zap"; -import { handleAllowance } from "../approve"; -import axios from "axios"; +import { handleCallResult } from "../utils/helpers"; interface VaultWriteProps { - address: Address; - account: Address; - amount: number; - publicClient: PublicClient; - walletClient: WalletClient; -} - -interface VaultSimulateProps { - address: Address; - account: Address; - amount: number; - functionName: string; - publicClient: PublicClient; -} - -interface VaultRouterWriteProps { - address: Address; - account: Address; - amount: number; - vault: Address; - gauge: Address; - publicClient: PublicClient; - walletClient: WalletClient; -} - -interface VaultRouterSimulateProps { - address: Address; - account: Address; - amount: number; - vault: Address; - gauge: Address; - functionName: string; - publicClient: PublicClient; -} - -interface ZapIntoVaultProps { chainId: number; - sellToken: Address; - asset: Address; vault: Address; account: Address; amount: number; - assetBal: number; - slippage?: number; - tradeTimeout?: number; - publicClient: PublicClient; - walletClient: WalletClient; + clients: Clients; } -interface ZapIntoGaugeProps extends ZapIntoVaultProps { +interface VaultRouterWriteProps extends VaultWriteProps { router: Address; gauge: Address; } -interface ZapOutOfVaultProps { - chainId: number; - buyToken: Address; - asset: Address; - vault: Address; +interface VaultSimulateProps { + address: Address; account: Address; amount: number; - assetBal: number; - slippage?: number; - tradeTimeout?: number; + functionName: string; publicClient: PublicClient; - walletClient: WalletClient; } - -interface ZapOutOfGaugeProps extends ZapOutOfVaultProps { - router: Address; +interface VaultRouterSimulateProps extends VaultSimulateProps { + vault: Address; gauge: Address; } @@ -115,199 +64,43 @@ async function simulateVaultRouterCall({ address, account, amount, vault, gauge, } } -export async function vaultDeposit({ address, account, amount, publicClient, walletClient }: VaultWriteProps): Promise { - console.log({ address, account, amount, publicClient, walletClient }) +export async function vaultDeposit({ chainId, vault, account, amount, clients }: VaultWriteProps): Promise { showLoadingToast("Depositing into the vault...") - const { request, success, error: simulationError } = await simulateVaultCall({ address, account, amount, functionName: "deposit", publicClient }) - - if (success) { - try { - const hash = await walletClient.writeContract(request) - const receipt = await publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Deposited into the vault!") - return true; - } catch (error: any) { - showErrorToast(error.shortMessage) - return false; - } - } else { - showErrorToast(simulationError) - return false; - } + return handleCallResult({ + successMessage: "Deposited into the vault!", + simulationResponse: await simulateVaultCall({ address: vault, account, amount, functionName: "deposit", publicClient: clients.publicClient }), + clients + }) } -export async function vaultRedeem({ address, account, amount, publicClient, walletClient }: VaultWriteProps): Promise { +export async function vaultRedeem({ chainId, vault, account, amount, clients }: VaultWriteProps): Promise { showLoadingToast("Withdrawing from the vault...") - const { request, success, error: simulationError } = await simulateVaultCall({ address, account, amount, functionName: "redeem", publicClient }) - - if (success) { - try { - const hash = await walletClient.writeContract(request) - const receipt = await publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Withdrawn from the vault!") - return true; - } catch (error: any) { - showErrorToast(error.shortMessage) - return false; - } - } else { - showErrorToast(simulationError) - return false; - } + return handleCallResult({ + successMessage: "Withdrawn from the vault!", + simulationResponse: await simulateVaultCall({ address: vault, account, amount, functionName: "redeem", publicClient: clients.publicClient }), + clients + }) } -export async function vaultDepositAndStake({ address, account, amount, vault, gauge, publicClient, walletClient }: VaultRouterWriteProps): Promise { +export async function vaultDepositAndStake({ chainId, router, vault, gauge, account, amount, clients }: VaultRouterWriteProps): Promise { showLoadingToast("Depositing into the vault...") - const { request, success, error: simulationError } = await simulateVaultRouterCall({ - address, account, amount, vault, gauge, functionName: "depositAndStake", publicClient + return handleCallResult({ + successMessage: "Deposited into the vault and staked into Gauge!", + simulationResponse: await simulateVaultRouterCall({ address: router, account, amount, vault, gauge, functionName: "depositAndStake", publicClient: clients.publicClient }), + clients }) - - if (success) { - try { - const hash = await walletClient.writeContract(request) - const receipt = await publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Deposited into the vault!") - return true; - } catch (error: any) { - showErrorToast(error.shortMessage) - return false; - } - } else { - showErrorToast(simulationError) - return false; - } } -export async function vaultUnstakeAndWithdraw({ address, account, amount, vault, gauge, publicClient, walletClient }: VaultRouterWriteProps): Promise { +export async function vaultUnstakeAndWithdraw({ chainId, router, vault, gauge, account, amount, clients }: VaultRouterWriteProps): Promise { showLoadingToast("Withdrawing from the vault...") - const { request, success, error: simulationError } = await simulateVaultRouterCall({ - address, account, amount, vault, gauge, functionName: "unstakeAndWithdraw", publicClient - }) - - if (success) { - try { - const hash = await walletClient.writeContract(request) - const receipt = await publicClient.waitForTransactionReceipt({ hash }) - showSuccessToast("Withdrawn from the vault!") - return true; - } catch (error: any) { - showErrorToast(error.shortMessage) - return false; - } - } else { - showErrorToast(simulationError) - return false; - } -} - -export async function zapIntoVault({ chainId, sellToken, asset, vault, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapIntoVaultProps): Promise { - showLoadingToast("Zapping into asset...") - const successZap = await zap({ chainId, sellToken, buyToken: asset, amount, account, publicClient, walletClient, slippage, tradeTimeout }) - const postBal = Number(await publicClient.readContract({ address: asset, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) - - if (successZap) { - console.log({ postBal, assetBal }) - - const depositAmount = postBal - assetBal - console.log({ depositAmount }) - - await handleAllowance({ - token: asset, - inputAmount: depositAmount, - account, - spender: vault, - publicClient, - walletClient - }) - return await vaultDeposit({ address: vault, account, amount: depositAmount, publicClient, walletClient }) - } else { - return false - } -} - -export async function zapIntoGauge({ chainId, sellToken, asset, router, vault, gauge, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapIntoGaugeProps): Promise { - showLoadingToast("Zapping into asset...") - const successZap = await zap({ chainId, sellToken, buyToken: asset, amount, account, publicClient, walletClient, slippage, tradeTimeout }) - const postBal = Number(await publicClient.readContract({ address: asset, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) - console.log({ postBal, assetBal }) - if (successZap) { - const depositAmount = postBal - assetBal - console.log({ depositAmount }) - await handleAllowance({ - token: asset, - inputAmount: depositAmount, - account, - spender: router, - publicClient, - walletClient - }) - return await vaultDepositAndStake({ address: router, account, vault, gauge, amount: depositAmount, publicClient, walletClient }) - } else { - return false - } -} - -export async function zapOutOfVault({ chainId, buyToken, asset, vault, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapOutOfVaultProps): Promise { - const success = await vaultRedeem({ - address: vault, - account, - amount, - publicClient, - walletClient + return handleCallResult({ + successMessage: "Unstaked from Gauge and withdrawn from Vault!", + simulationResponse: await simulateVaultRouterCall({ address: router, account, amount, vault, gauge, functionName: "unstakeAndWithdraw", publicClient: clients.publicClient }), + clients }) - const postBal = Number(await publicClient.readContract({ address: asset, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) - console.log({ postBal, assetBal, amount: postBal - assetBal }) - - if (success) { - showLoadingToast("Zapping into asset...") - return await zap({ - chainId, - account, - walletClient, - publicClient, - sellToken: asset, - buyToken, - amount: postBal - assetBal, - slippage, - tradeTimeout - }) - } else { - return false - } -} - -export async function zapOutOfGauge({ chainId, buyToken, asset, router, vault, gauge, account, amount, assetBal, slippage = 100, tradeTimeout = 60, publicClient, walletClient }: ZapOutOfGaugeProps): Promise { - const success = await vaultUnstakeAndWithdraw({ - address: router, - account, - amount, - vault, - gauge, - publicClient, - walletClient - }) - const postBal = Number(await publicClient.readContract({ address: asset, abi: ERC20Abi, functionName: "balanceOf", args: [account] })) - console.log({ postBal, assetBal, amount: postBal - assetBal }) - - if (success) { - showLoadingToast("Zapping into asset...") - return await zap({ - chainId, - account, - walletClient, - publicClient, - sellToken: asset, - buyToken, - amount: postBal - assetBal, - slippage, - tradeTimeout - }) - } else { - return false - } } \ No newline at end of file diff --git a/lib/vault/zap.ts b/lib/vault/zap.ts index 6a000e6..3ff1faa 100644 --- a/lib/vault/zap.ts +++ b/lib/vault/zap.ts @@ -2,6 +2,7 @@ import axios from "axios" import { Address, PublicClient, WalletClient, getAddress } from "viem"; import { showErrorToast, showSuccessToast } from "@/lib/toasts"; import { handleAllowance } from "@/lib/approve"; +import { Clients } from "../types"; interface ZapProps { chainId: number; @@ -9,38 +10,19 @@ interface ZapProps { buyToken: Address; amount: number; account: Address; - publicClient: PublicClient; - walletClient: WalletClient; slippage?: number; // slippage allowance in BPS tradeTimeout?: number; // in s + clients: Clients; } -export default async function zap({ chainId, sellToken, buyToken, amount, account, publicClient, walletClient, slippage = 100, tradeTimeout = 60 }: ZapProps): Promise { - const ensoWallet = (await axios.get( - `https://api.enso.finance/api/v1/wallet?chainId=${chainId}&fromAddress=${account}`, - { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } }) - ).data - console.log({ ensoWallet: ensoWallet }) - const success = await handleAllowance({ - token: sellToken, - inputAmount: amount, - account, - spender: getAddress(ensoWallet.address), - publicClient, - walletClient - }) - if (!success) return false - - console.log({ qouteUrl: `https://api.enso.finance/api/v1/shortcuts/route?chainId=${chainId}&fromAddress=${account}&spender=${account}&receiver=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}` }) +export default async function zap({ chainId, sellToken, buyToken, amount, account, slippage = 100, tradeTimeout = 60, clients }: ZapProps): Promise { const quote = (await axios.get( `https://api.enso.finance/api/v1/shortcuts/route?chainId=${chainId}&fromAddress=${account}&spender=${account}&receiver=${account}&amountIn=${amount.toLocaleString("fullwide", { useGrouping: false })}&slippage=${slippage}&tokenIn=${sellToken}&tokenOut=${buyToken}`, { headers: { Authorization: `Bearer ${process.env.ENSO_API_KEY}` } } )).data - console.log({ quote }) - try { - const hash = await walletClient.sendTransaction(quote.tx) - const receipt = await publicClient.waitForTransactionReceipt({ hash }) + const hash = await clients.walletClient.sendTransaction(quote.tx) + const receipt = await clients.publicClient.waitForTransactionReceipt({ hash }) showSuccessToast("Zapped successfully") return true; } catch (error: any) { diff --git a/next.config.js b/next.config.js index 17fe0fc..b9faa02 100644 --- a/next.config.js +++ b/next.config.js @@ -13,7 +13,7 @@ module.exports = { PINATA_API_KEY: process.env.PINATA_API_KEY, IPFS_URL: process.env.IPFS_URL, DUNE_API_KEY: process.env.DUNE_API_KEY, - NEXT_PUBLIC_ALCHEMY_API_KEY: process.env.NEXT_PUBLIC_ALCHEMY_API_KEY, + ALCHEMY_API_KEY: process.env.ALCHEMY_API_KEY, ENSO_API_KEY:process.env.ENSO_API_KEY, }, images: { diff --git a/pages/_app.tsx b/pages/_app.tsx index 5939e4a..deace63 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -22,7 +22,7 @@ import { const { chains, publicClient } = configureChains(SUPPORTED_NETWORKS, [ alchemyProvider({ - apiKey: process.env.NEXT_PUBLIC_ALCHEMY_API_KEY as string, + apiKey: process.env.ALCHEMY_API_KEY as string, }), jsonRpcProvider({ rpc: (chain) => ({ http: chain.rpcUrls.default.http[0] }) })], { diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 9443448..67f1dab 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -7,9 +7,7 @@ import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import { SUPPORTED_NETWORKS } from "@/lib/utils/connectors"; import { NumberFormatter } from "@/lib/utils/formatBigNumber"; import useNetworkFilter from "@/lib/useNetworkFilter"; -import getVaultNetworth from "@/lib/vault/getVaultNetworth"; import useVaultTvl from "@/lib/useVaultTvl"; -import { getVaultsByChain } from "@/lib/vault/getVault"; import { Token, VaultData } from "@/lib/types"; import SmartVault from "@/components/vault/SmartVault"; import NetworkFilter from "@/components/network/NetworkFilter"; @@ -20,13 +18,16 @@ import { claimOPop } from "@/lib/oPop/interactions"; import { WalletClient } from "viem"; import getZapAssets, { getAvailableZapAssets } from "@/lib/utils/getZapAssets"; import { ERC20Abi, VaultAbi } from "@/lib/constants"; +import { getVaultNetworthByChain } from "@/lib/getNetworth"; +import { useAtom } from "jotai"; +import { vaultsAtom } from "@/lib/atoms/vaults"; export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2fD2C18f79F93eF299B20B681Ab2a61f5F28A6fF", "0xDFf04Efb38465369fd1A2E8B40C364c22FfEA340", "0xd4D442AC311d918272911691021E6073F620eb07", //@dev for some reason the live 3Crypto yVault isnt picked up by the yearnAdapter nor the yearnFactoryAdapter "0x8bd3D95Ec173380AD546a4Bd936B9e8eCb642de1", // Sample Stargate Vault "0xcBb5A4a829bC086d062e4af8Eba69138aa61d567", // yOhmFrax factory "0x9E237F8A3319b47934468e0b74F0D5219a967aB8", // yABoosted Balancer - "0x860b717B360378E44A241b23d8e8e171E0120fF0", // R/Dai + "0x860b717B360378E44A241b23d8e8e171E0120fF0", // R/Dai "0xBae30fBD558A35f147FDBaeDbFF011557d3C8bd2", // 50OHM - 50 DAI "0x759281a408A48bfe2029D259c23D7E848A7EA1bC", // yCRV ] @@ -52,10 +53,14 @@ const Vaults: NextPage = () => { const [accountLoad, setAccountLoad] = useState(false); const [selectedNetworks, selectNetwork] = useNetworkFilter(SUPPORTED_NETWORKS.map(network => network.id)); - const [vaults, setVaults] = useState([]); + + const [vaults, setVaults] = useAtom(vaultsAtom) + const [zapAssets, setZapAssets] = useState<{ [key: number]: Token[] }>({}); const [availableZapAssets, setAvailableZapAssets] = useState<{ [key: number]: Address[] }>({}) + const vaultTvl = useVaultTvl(); + const [networth, setNetworth] = useState(0); const [gaugeRewards, setGaugeRewards] = useState() const { data: oBal } = useBalance({ chainId: 1, address: account, token: OPOP, watch: true }) @@ -72,46 +77,28 @@ const Vaults: NextPage = () => { setZapAssets(newZapAssets); // get available zapAddresses - setAvailableZapAssets({ + setAvailableZapAssets({ 1: await getAvailableZapAssets(1), 137: await getAvailableZapAssets(137), 10: await getAvailableZapAssets(10), - 42161: await getAvailableZapAssets(42161) - }) - - // get vaults - const fetchedVaults = (await Promise.all( - SUPPORTED_NETWORKS.map(async (chain) => getVaultsByChain({ chain, account })) - )).flat(); + 42161: await getAvailableZapAssets(42161), + 56: await getAvailableZapAssets(56) + }) // get gauge rewards if (account) { const rewards = await getGaugeRewards({ - gauges: fetchedVaults.filter(vault => vault.gauge && vault.chainId === 1).map(vault => vault.gauge?.address) as Address[], + gauges: vaults.filter(vault => vault.gauge && vault.chainId === 1).map(vault => vault.gauge?.address) as Address[], account: account as Address, publicClient }) setGaugeRewards(rewards) } - - setVaults(fetchedVaults); + setNetworth(SUPPORTED_NETWORKS.map(chain => getVaultNetworthByChain({ vaults, chainId: chain.id })).reduce((a, b) => a + b, 0)); } - if (!account && !initalLoad) getVaults(); - if (account && !accountLoad) getVaults() - }, [account]) - - const [networth, setNetworth] = useState(0); - const [loading, setLoading] = useState(true); - - - useEffect(() => { - if (account && loading) - // fetch and set networth - getVaultNetworth({ account }).then(res => { - setNetworth(res.total); - setLoading(false); - }); - }, [account]); + if (!account && !initalLoad && vaults.length > 0) getVaults(); + if (account && !accountLoad && vaults.length > 0) getVaults() + }, [account, initalLoad, accountLoad, vaults]) async function mutateTokenBalance({ inputToken, outputToken, vault, chainId, account }: MutateTokenBalanceProps) { @@ -211,7 +198,7 @@ const Vaults: NextPage = () => {

Deposits

- {`$${loading ? "..." : NumberFormatter.format(networth)}`} + {`$${NumberFormatter.format(networth)}`}
@@ -272,21 +259,19 @@ const Vaults: NextPage = () => {
- {vaults.length > 0 && - Object.keys(zapAssets).length > 0 - ? vaults.filter(vault => selectedNetworks.includes(vault.chainId)).filter(vault => !HIDDEN_VAULTS.includes(vault.address)).map((vault) => { - return ( - - ) - }) - :

Loading Vaults...

+ {(vaults.length > 0 && Object.keys(availableZapAssets).length > 0) ? vaults.filter(vault => selectedNetworks.includes(vault.chainId)).filter(vault => !HIDDEN_VAULTS.includes(vault.address)).map((vault) => { + return ( + + ) + }) + :

Loading Vaults...

}
diff --git a/pages/vepop.tsx b/pages/vepop.tsx index 59b1327..1fa2f33 100644 --- a/pages/vepop.tsx +++ b/pages/vepop.tsx @@ -5,7 +5,7 @@ import { Address, WalletClient } from "viem"; import { useEffect, useState } from "react"; import { getVeAddresses } from "@/lib/utils/addresses"; import { hasAlreadyVoted } from "@/lib/gauges/hasAlreadyVoted"; -import { VaultData } from "@/lib/types"; +import { Token, VaultData } from "@/lib/types"; import { getVaultsByChain } from "@/lib/vault/getVault"; import StakingInterface from "@/components/vepop/StakingInterface"; import { sendVotes } from "@/lib/gauges/interactions"; @@ -14,6 +14,8 @@ import LockModal from "@/components/vepop/modals/lock/LockModal"; import ManageLockModal from "@/components/vepop/modals/manage/ManageLockModal"; import OPopModal from "@/components/vepop/modals/oPop/OPopModal"; import OPopInterface from "@/components/vepop/OPopInterface"; +import { vaultsAtom } from "@/lib/atoms/vaults"; +import { useAtom } from "jotai"; const { VotingEscrow: VOTING_ESCROW } = getVeAddresses(); @@ -27,7 +29,7 @@ function VePopContainer() { const [initalLoad, setInitalLoad] = useState(false); const [accountLoad, setAccountLoad] = useState(false); - const [vaults, setVaults] = useState([]); + const [vaults, setVaults] = useAtom(vaultsAtom) const [votes, setVotes] = useState([]); const [canVote, setCanVote] = useState(false); @@ -39,8 +41,8 @@ function VePopContainer() { async function initialSetup() { setInitalLoad(true) if (account) setAccountLoad(true) - const allVaults = await getVaultsByChain({ chain: mainnet, account }) - const vaultsWithGauges = allVaults.filter(vault => !!vault.gauge) + + const vaultsWithGauges = vaults.filter(vault => !!vault.gauge) setVaults(vaultsWithGauges); if (vaultsWithGauges.length > 0 && votes.length === 0 && publicClient.chain.id === 1) { setVotes(vaultsWithGauges.map(gauge => 0)); @@ -53,9 +55,9 @@ function VePopContainer() { setCanVote(!!account && Number(veBal?.value) > 0 && !hasVoted) } } - if (!account && !initalLoad) initialSetup(); - if (account && !accountLoad) initialSetup() - }, [account]) + if (!account && !initalLoad && vaults.length > 0) initialSetup(); + if (account && !accountLoad && vaults.length > 0) initialSetup() + }, [account, initalLoad, accountLoad, vaults]) function handleVotes(val: number, index: number) { const updatedVotes = [...votes]; @@ -88,11 +90,14 @@ function VePopContainer() {
- + 0 ? vaults.filter(vault => !!vault.gauge?.address).map((vault: VaultData) => vault.gauge as Token) : []} + setShowOPopModal={setShowOPopModal} + />
- {vaults?.length > 0 ? vaults.map((vault: VaultData, index: number) => + {vaults?.length > 0 ? vaults.filter(vault => !!vault.gauge?.address).map((vault: VaultData, index: number) => ) :

Loading Gauges...

diff --git a/public/images/loader/grid.svg b/public/images/loader/grid.svg new file mode 100644 index 0000000..1015da8 --- /dev/null +++ b/public/images/loader/grid.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/loader/progressBar.svg b/public/images/loader/progressBar.svg new file mode 100644 index 0000000..888cf53 --- /dev/null +++ b/public/images/loader/progressBar.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/loader/puff.svg b/public/images/loader/puff.svg new file mode 100644 index 0000000..86f9008 --- /dev/null +++ b/public/images/loader/puff.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/loader/spinner.svg b/public/images/loader/spinner.svg new file mode 100644 index 0000000..18d12b6 --- /dev/null +++ b/public/images/loader/spinner.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file From e6a77f1d1f10c33b0f52a26a148c59e48290cacd Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 16 Nov 2023 14:25:00 +0100 Subject: [PATCH 59/84] minor style adjustment migration + handleAllowance fix --- components/vepop/modals/lock/LockModal.tsx | 8 +- .../vepop/modals/manage/ManageLockModal.tsx | 6 +- components/vepop/modals/oPop/OPopModal.tsx | 8 +- pages/migration.tsx | 133 +++++++++--------- 4 files changed, 81 insertions(+), 74 deletions(-) diff --git a/components/vepop/modals/lock/LockModal.tsx b/components/vepop/modals/lock/LockModal.tsx index 3d75b4e..cfce880 100644 --- a/components/vepop/modals/lock/LockModal.tsx +++ b/components/vepop/modals/lock/LockModal.tsx @@ -49,11 +49,13 @@ export default function LockModal({ show }: { show: [boolean, Dispatch -
-

+
+

POP Migration

-

+

Migrate your POP to VCX

- {(vcxBal && popBal) ? -
- { }} - onMaxClick={() => handleChangeInput({ currentTarget: { value: Math.round(Number(formatEther(popBal.value)) * ROUNDING_VALUE) / ROUNDING_VALUE } })} - chainId={1} - value={inputBalance} - onChange={handleChangeInput} - selectedToken={{ - address: POP, - name: "POP", - symbol: "POP", - decimals: 18, - logoURI: "", - balance: Number(popBal.value), - price: 1, - }} - errorMessage={""} - tokenList={[]} - allowInput - /> -
-

@@ -107,16 +259,18 @@ const Vaults: NextPage = () => {
- {vaults.length > 0 ? vaults.filter(vault => selectedNetworks.includes(vault.chainId)).filter(vault => !HIDDEN_VAULTS.includes(vault.address)).map((vault) => { + {(vaults.length > 0 && Object.keys(availableZapAssets).length > 0) ? vaults.filter(vault => selectedNetworks.includes(vault.chainId)).filter(vault => !HIDDEN_VAULTS.includes(vault.address)).map((vault) => { return ( ) }) - :

Loading Vaults...

+ :

Loading Vaults...

}
diff --git a/pages/stats.tsx b/pages/stats.tsx index d5a6323..a956524 100644 --- a/pages/stats.tsx +++ b/pages/stats.tsx @@ -401,7 +401,7 @@ export default function Vaults() { color: "#9B55FF" }, { - name: "POP in 80/20 BAL pool, USD", + name: "VCX in 80/20 BAL pool, USD", y: 80, //Number(popInBalPool?.token?.latestUSDPrice) * Number(popInBalPool?.balance), color: "#7AFB79" }, @@ -461,11 +461,11 @@ export default function Vaults() {

${statistics.marketCap.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })}

-

POP Price

+

VCX Price

${statistics.popPrice.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })}

-

Burned POP

+

Burned VCX

Coming Soon

@@ -473,14 +473,14 @@ export default function Vaults() {
Logo
-

POPCORN

-

Liquid POP market (Mainnet only)

+

VCXCORN

+

Liquid VCX market (Mainnet only)

-

POP in 80/20 BAL pool

+

VCX in 80/20 BAL pool

Coming Soon {/*statistics.popInBalPool.toLocaleString()*/}

@@ -492,15 +492,15 @@ export default function Vaults() {

Coming Soon {/*statistics.balLp.toLocaleString()*/}

-

vePOP (staked LPs)

+

veVCX (staked LPs)

Coming Soon {/*statistics.vePop.toLocaleString()*/}

-

cPOP emissions

+

cVCX emissions

Coming Soon {/*statistics.cPopEmissions.toLocaleString()*/}

-

cPOP exercised

+

cVCX exercised

Coming Soon {/*(statistics.cPopExercised * 100).toLocaleString() %*/}

@@ -541,7 +541,7 @@ export default function Vaults() {

Coming Soon

-

cPOP Revenue

+

cVCX Revenue

Coming Soon {/*statistics.cPopRevenue.toLocaleString()*/}

@@ -561,19 +561,19 @@ export default function Vaults() {

${statistics.weekDexVolume.toLocaleString()}

-

{'Wallets with POP > 100'}

+

{'Wallets with VCX > 100'}

{statistics.walletsPopMoreHundred.toLocaleString()}

-

{'Wallets with POP > 1,000'}

+

{'Wallets with VCX > 1,000'}

{statistics.walletsPopMoreThousand.toLocaleString()}

-

{'Wallets with POP > 100,000'}

+

{'Wallets with VCX > 100,000'}

{statistics.walletsPopMoreHundredThousand.toLocaleString()}

-

{'Wallets with POP > 1,000,000'}

+

{'Wallets with VCX > 1,000,000'}

{statistics.walletsPopMoreMillion.toLocaleString()}

diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 67f1dab..27620a0 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -32,7 +32,7 @@ export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2 "0x759281a408A48bfe2029D259c23D7E848A7EA1bC", // yCRV ] -const { oPOP: OPOP } = getVeAddresses(); +const { oVCX } = getVeAddresses(); const NETWORKS_SUPPORTING_ZAP = [1] @@ -63,7 +63,7 @@ const Vaults: NextPage = () => { const [networth, setNetworth] = useState(0); const [gaugeRewards, setGaugeRewards] = useState() - const { data: oBal } = useBalance({ chainId: 1, address: account, token: OPOP, watch: true }) + const { data: oBal } = useBalance({ chainId: 1, address: account, token: oVCX, watch: true }) const [searchString, handleSearch] = useState(""); @@ -205,14 +205,14 @@ const Vaults: NextPage = () => {
-

My oPOP

+

My oVCX

{`${oBal ? NumberFormatter.format(Number(oBal?.value) / 1e18) : "0"}`}
-

Claimable oPOP

+

Claimable oVCX

{`$${gaugeRewards ? NumberFormatter.format(Number(gaugeRewards?.total) / 1e18) : "0"}`}
@@ -220,7 +220,7 @@ const Vaults: NextPage = () => {
claimOPop({ gauges: gaugeRewards?.amounts?.filter(gauge => Number(gauge.amount) > 0).map(gauge => gauge.address) as Address[], @@ -232,7 +232,7 @@ const Vaults: NextPage = () => {
claimOPop({ gauges: gaugeRewards?.amounts?.filter(gauge => Number(gauge.amount) > 0).map(gauge => gauge.address) as Address[], From f46931ccf3da5205022be548fd5798995fe9bc8d Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 22 Nov 2023 11:11:53 +0100 Subject: [PATCH 62/84] replaced gitbook link --- components/page/Footer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/page/Footer.tsx b/components/page/Footer.tsx index d132183..1534eaf 100644 --- a/components/page/Footer.tsx +++ b/components/page/Footer.tsx @@ -29,7 +29,7 @@ const GeneralLinks = [ }, { label: "Gitbook", - href: "https://popcorn-dao.gitbook.io/popcorndao-gitbook/about-popcorn/welcome-to-popcorn", + href: "https://docs.vaultcraft.io/welcome-to-vaultcraft/introduction", }, { label: "Disclaimer", From 326dfe8c690a40c4e69f08edc20ecd70c73b98b7 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 23 Nov 2023 11:46:18 +0100 Subject: [PATCH 63/84] sorting + token metadata cleanup --- components/page/Page.tsx | 8 +- components/svg/SwitchIcon.tsx | 12 + components/vault/AssetWithName.tsx | 8 +- components/vault/SmartVault.tsx | 27 +- components/vault/VaultsSorting.tsx | 159 ++++++++++++ lib/resolver/price/index.ts | 3 +- lib/resolver/price/resolver/index.ts | 3 +- lib/resolver/price/resolver/vault.ts | 12 - lib/types.ts | 4 + lib/utils/helpers.ts | 38 ++- lib/utils/metadata/protocolMetadata.ts | 8 + lib/vault/getOptionalMetadata.ts | 24 +- lib/vault/getVault.ts | 173 +++++-------- package.json | 2 +- pages/vaults.tsx | 52 +++- yarn.lock | 335 +++++++++++++------------ 16 files changed, 541 insertions(+), 327 deletions(-) create mode 100644 components/svg/SwitchIcon.tsx create mode 100644 components/vault/VaultsSorting.tsx delete mode 100644 lib/resolver/price/resolver/vault.ts diff --git a/components/page/Page.tsx b/components/page/Page.tsx index 6bfdea2..bab9718 100644 --- a/components/page/Page.tsx +++ b/components/page/Page.tsx @@ -19,7 +19,7 @@ async function setUpYieldOptions() { const provider = new CachedProvider(); await provider.initialize("https://raw.githubusercontent.com/Popcorn-Limited/apy-data/main/apy-data.json"); - return new YieldOptions(provider, ttl); + return new YieldOptions({ provider, ttl }); } export default function Page({ children }: { children: JSX.Element }): JSX.Element { @@ -39,12 +39,12 @@ export default function Page({ children }: { children: JSX.Element }): JSX.Eleme async function getVaults() { // get vaults const fetchedVaults = (await Promise.all( - SUPPORTED_NETWORKS.map(async (chain) => getVaultsByChain({ chain, account })) + SUPPORTED_NETWORKS.map(async (chain) => getVaultsByChain({ chain, account, yieldOptions: yieldOptions as YieldOptions })) )).flat(); setVaults(fetchedVaults) } - getVaults() - }, [account]) + if (yieldOptions) getVaults() + }, [account, yieldOptions]) return ( <> diff --git a/components/svg/SwitchIcon.tsx b/components/svg/SwitchIcon.tsx new file mode 100644 index 0000000..0d7b717 --- /dev/null +++ b/components/svg/SwitchIcon.tsx @@ -0,0 +1,12 @@ +import { IconProps } from "@/lib/types" + + +const SwitchIcon: React.FC = ({ className, color, size}) => { + return ( + + + + ) +} + +export default SwitchIcon; diff --git a/components/vault/AssetWithName.tsx b/components/vault/AssetWithName.tsx index 942bcd4..b93c690 100644 --- a/components/vault/AssetWithName.tsx +++ b/components/vault/AssetWithName.tsx @@ -1,8 +1,6 @@ import NetworkSticker from "@/components/network/NetworkSticker"; import TokenIcon from "@/components/common/TokenIcon"; -import { ChainId } from "@/lib/utils/connectors"; -import { Vault } from "@/lib/vault/getVault"; -import { Token } from "@/lib/types"; +import { VaultData } from "@/lib/types"; const protocolNameToLlamaProtocol: { [key: string]: string } = { "Aave": "aave", @@ -17,9 +15,11 @@ const protocolNameToLlamaProtocol: { [key: string]: string } = { "Origin": "origin-defi", "Stargate": "stargate", "Yearn": "yearn-finance", + "Pirex": "pirex", + "Sommelier": "sommelier" } -export default function AssetWithName({ vault }: { vault: Vault }) { +export default function AssetWithName({ vault }: { vault: VaultData }) { const protocolName = vault.metadata.optionalMetadata?.protocol?.name const protocolIcon = protocolName ? protocolNameToLlamaProtocol[protocolName] : "popcorn" diff --git a/components/vault/SmartVault.tsx b/components/vault/SmartVault.tsx index c1efba5..84ae8c0 100644 --- a/components/vault/SmartVault.tsx +++ b/components/vault/SmartVault.tsx @@ -37,31 +37,12 @@ export default function SmartVault({ zapAssets, deployer, }: SmartVaultsProps) { - const publicClient = usePublicClient(); - const [yieldOptions] = useAtom(yieldOptionsAtom); const { address: account } = useAccount(); const vault = vaultData.vault; const asset = vaultData.asset; const gauge = vaultData.gauge; const tokenOptions = getTokenOptions(vaultData, zapAssets); - const [apy, setApy] = useState(0); - - useEffect(() => { - if (!apy) { - // @ts-ignore - yieldOptions?.getApy(vaultData.chainId, vaultData.metadata.optionalMetadata.resolver, vaultData.asset.address).then(res => setApy(!!res ? res.total : 0)) - } - }, [apy]) - - const [gaugeApr, setGaugeApr] = useState([]); - - useEffect(() => { - if (vault?.price && gaugeApr.length === 0 && !!gauge) { - calculateAPR({ vaultPrice: vault?.price, gauge: gauge?.address, publicClient }).then(res => setGaugeApr(res)) - } - }, [vault, gaugeApr]) - // Is loading / error if (!vaultData || tokenOptions.length === 0) return <> // Dont show if we filter by deployer @@ -110,9 +91,13 @@ export default function SmartVault({

vAPY

- {apy ? `${NumberFormatter.format(apy)} %` : "0 %"} + {vaultData.apy ? `${NumberFormatter.format(vaultData.apy)} %` : "0 %"} - {gaugeApr.length > 0 && {`+ (${formatNumber(gaugeApr[0])} % - ${formatNumber(gaugeApr[1])} %)`}} + {!!vaultData.gaugeMinApy && !!vaultData.gaugeMaxApy && + + {`+ (${formatNumber(vaultData.gaugeMinApy)} % - ${formatNumber(vaultData.gaugeMaxApy)} %)`} + + }
diff --git a/components/vault/VaultsSorting.tsx b/components/vault/VaultsSorting.tsx new file mode 100644 index 0000000..4656777 --- /dev/null +++ b/components/vault/VaultsSorting.tsx @@ -0,0 +1,159 @@ +import PseudoRadioButton from "@/components/button/PseudoRadioButton"; +import { useMemo, useRef, useState } from "react"; +import PopUpModal from "@/components/modal/PopUpModal"; +import SwitchIcon from "@/components/svg/SwitchIcon"; + +export enum VAULT_SORTING_TYPE { + none = 'none', + mostTvl = 'most-tvl', + lessTvl = 'less-tvl', + mostvAPR = 'most-apr', + lessvAPR = 'less-apr' +} + +interface VaultSortingProps { + className?: string, + currentSortingType: VAULT_SORTING_TYPE, + sortByMostTvl: () => void, + sortByLessTvl: () => void + sortByMostApy: () => void, + sortByLessApy: () => void +} + +export default function VaultsSorting( + { + className, + currentSortingType, + sortByMostTvl, + sortByLessTvl, + sortByMostApy, + sortByLessApy, + }: VaultSortingProps): JSX.Element { + const [openFilter, setOpenSorting] = useState(false); + + const dropdownRef = useRef(null); + + const isLessThenMdScreenSize = useMemo(() => window.innerWidth < 1024, [window.innerWidth]) + + const sortingLessTvl = () => { + sortByLessTvl() + toggleDropdown() + } + + const sortingMostTvl = () => { + sortByMostTvl() + toggleDropdown() + } + + const sortingLessApy = () => { + sortByLessApy() + toggleDropdown() + } + + const sortingMostApy = () => { + sortByMostApy() + toggleDropdown() + } + + const toggleDropdown = () => { + setOpenSorting(prevState => !prevState) + } + + return ( +
+ + {openFilter && !isLessThenMdScreenSize && ( +
+ + + + +
+ )} + {isLessThenMdScreenSize && ( +
+ setOpenSorting(false)}> + <> +

Select a sorting type

+
+ + + + +
+ +
+
+ )} +
+ ); +} diff --git a/lib/resolver/price/index.ts b/lib/resolver/price/index.ts index b9adab0..214ed33 100644 --- a/lib/resolver/price/index.ts +++ b/lib/resolver/price/index.ts @@ -1,7 +1,7 @@ import { Address } from "viem"; import { PublicClient } from "wagmi"; -import { llama, vault } from "./resolver" +import { llama } from "./resolver" export type PriceResolverParams = { address: Address, @@ -13,7 +13,6 @@ export type PriceResolvers = typeof PriceResolvers; export const PriceResolvers: { [key: string]: ({ address, chainId, client }: PriceResolverParams) => Promise } = { llama, - vault, default: llama }; diff --git a/lib/resolver/price/resolver/index.ts b/lib/resolver/price/resolver/index.ts index f653d71..91258b0 100644 --- a/lib/resolver/price/resolver/index.ts +++ b/lib/resolver/price/resolver/index.ts @@ -1,2 +1 @@ -export * from "./llama"; -export * from "./vault"; \ No newline at end of file +export * from "./llama"; \ No newline at end of file diff --git a/lib/resolver/price/resolver/vault.ts b/lib/resolver/price/resolver/vault.ts deleted file mode 100644 index 382c315..0000000 --- a/lib/resolver/price/resolver/vault.ts +++ /dev/null @@ -1,12 +0,0 @@ -import getAssetAndValueByVault from "@/lib/vault/getAssetAndAssetsPerShare"; -import { PriceResolverParams } from ".."; -import { resolvePrice } from "../price"; - -export async function vault({ address, chainId, client }: PriceResolverParams): Promise { - if (!client) return 0; - - const { asset, assetsPerShare } = await getAssetAndValueByVault({ address, client }); - const price = await resolvePrice({ chainId: chainId, client: client, address: asset, resolver: 'llama' }) - - return Number(assetsPerShare) * price -} diff --git a/lib/types.ts b/lib/types.ts index bda8378..53670a3 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -65,6 +65,10 @@ export type VaultData = { depositLimit: number; metadata: VaultMetadata; chainId: number; + apy: number; + gaugeMinApy?: number; + gaugeMaxApy?: number; + totalApy:number; } export type VaultMetadata = { diff --git a/lib/utils/helpers.ts b/lib/utils/helpers.ts index ab847f7..8acad1e 100644 --- a/lib/utils/helpers.ts +++ b/lib/utils/helpers.ts @@ -1,5 +1,5 @@ import { showErrorToast, showSuccessToast } from "../toasts"; -import { Clients, SimulationResponse } from "../types"; +import { Clients, SimulationResponse, Token } from "../types"; export function validateInput(value: string | number): { formatted: string, isValid: boolean } { const formatted = value === "." ? "0" : (`${value || "0"}`.replace(/\.$/, ".0") as any); @@ -30,4 +30,40 @@ export async function handleCallResult({ successMessage, simulationResponse, cli showErrorToast(simulationResponse.error) return false; } +} + + +export function cleanTokenName(token: Token): string { + if (token.name.includes("Hop")) { + return token.name.slice(0, token.name.indexOf(" LP Token")) + } + else if (token.name.includes("Curve.fi Factory USD Metapool")) { + return token.name.slice(31) + } + else if (token.name.includes("Curve.fi Factory Pool:")) { + return token.name.slice(23) + } + else if (token.name.includes("StableV")) { + return token.name.slice(15) + } + else if (token.name.includes("VolatileV")) { + return token.name.slice(17) + } + return token.name +} + +export function cleanTokenSymbol(token: Token): string { + if (token.symbol.includes("HOP-LP")) { + const split = token.symbol.split("LP-") + return split[0] + split[1] + } + else if (token.symbol.includes("AMMV2")) { + const split = token.symbol.split("AMMV2-") + return split[0].slice(0, -1) + split[1] + } + else if (token.symbol.includes("AMM")) { + const split = token.symbol.split("AMM-") + return split[0].slice(0, -1) + split[1] + } + return token.symbol } \ No newline at end of file diff --git a/lib/utils/metadata/protocolMetadata.ts b/lib/utils/metadata/protocolMetadata.ts index de311ba..b3095e5 100644 --- a/lib/utils/metadata/protocolMetadata.ts +++ b/lib/utils/metadata/protocolMetadata.ts @@ -42,6 +42,14 @@ const ProtocolMetadata: { [key: string]: { name: string, description: string } } description: `Idle is a decentralized yield automation protocol that aims to step up DeFi by reimagining how risk and yield are managed. This vault is connected to **[Yield Tranches](https://docs.idle.finance/products/yield-tranches) (YTs)**: an innovative DeFi primitive that segments yields and risks to appeal to a diverse range of users, offering two risk-return profiles, Senior and Junior. **Senior YTs withhold part of their yield in exchange for funds coverage**, given by the Junior class’ liquidity. This way, **Senior holders benefit from built-in protection on deposits**. That yield is routed to the Junior side in exchange for first-loss liquidity to cover Senior funds. --- All Idle strategies feature **automatically compounded interest** and **no lock-up periods**.` + }, + pirex: { + name: "Pirex", + description: "Pirex is a product by Redacted which creates liquid wrappers that allow for auto-compounding and the tokenization of future yield/vote events." + }, + sommelier: { + name: "Sommelier", + description: "Provider of automated vaults that find best-in-class yields while mitigating risk." } } diff --git a/lib/vault/getOptionalMetadata.ts b/lib/vault/getOptionalMetadata.ts index 7161cfa..2389b68 100644 --- a/lib/vault/getOptionalMetadata.ts +++ b/lib/vault/getOptionalMetadata.ts @@ -369,6 +369,24 @@ function getOriginMetadata(adapter: Token, asset: Token): OptionalMetadata { } } +function getPirexMetadata(adapter: Token, asset: Token): OptionalMetadata { + return { + protocol: ProtocolMetadata.pirex, + token: { name: asset.symbol, description: "None available" }, + strategy: { name: "Pirex Vault", description: addGenericStrategyDescription("automatedAssetStrategy", "Pirex") }, + resolver: "pirex" + } +} + +function getSommelierMetadata(adapter: Token, asset: Token): OptionalMetadata { + return { + protocol: ProtocolMetadata.sommelier, + token: { name: asset.symbol, description: "None available" }, + strategy: { name: "Sommelier Vault", description: addGenericStrategyDescription("automatedAssetStrategy", "Sommelier") }, + resolver: "sommelier" + } +} + function getEmptyMetadata(adapter: Token, asset: Token): OptionalMetadata { return { token: { name: "Token", description: "Not found" }, @@ -403,6 +421,10 @@ function getFactoryMetadata({ adapter, asset }: { adapter: Token, asset: Token } return getIdleMetadata(adapter, asset) } else if (adapter?.name?.includes("Origin")) { return getOriginMetadata(adapter, asset) + } else if (asset?.name?.includes("Pirex")) { + return getPirexMetadata(adapter, asset) + } else if (adapter?.symbol?.includes("WETH")) { + return getSommelierMetadata(adapter, asset) } return getEmptyMetadata(adapter, asset) } @@ -414,4 +436,4 @@ export default function getOptionalMetadata({ vaultAddress, asset, adapter }: { else { return getFactoryMetadata({ adapter, asset }) } -} \ No newline at end of file +} diff --git a/lib/vault/getVault.ts b/lib/vault/getVault.ts index 7a04660..af2e76c 100644 --- a/lib/vault/getVault.ts +++ b/lib/vault/getVault.ts @@ -2,7 +2,6 @@ import { Address, Chain, ReadContractParameters, createPublicClient, getAddress, import { PublicClient } from "wagmi" import axios from "axios" import { VaultAbi } from "@/lib/constants/abi/Vault" -import { resolvePrice } from "@/lib/resolver/price/price" import { Token, VaultData } from "@/lib/types" import { ADDRESS_ZERO, ERC20Abi, VaultRegistryByChain, VaultRegistyAbi } from "@/lib/constants" import { RPC_URLS, networkMap } from "@/lib/utils/connectors"; @@ -12,6 +11,9 @@ import getVaultName from "@/lib/vault/getVaultName" import getOptionalMetadata from "@/lib/vault/getOptionalMetadata" import { getVeAddresses } from "../utils/addresses" import getGauges, { Gauge } from "../gauges/getGauges" +import { cleanTokenName, cleanTokenSymbol } from "../utils/helpers" +import { ProtocolName, YieldOptions } from "vaultcraft-sdk" +import calculateAPR from "../gauges/calculateGaugeAPR" const { GaugeController: GAUGE_CONTROLLER } = getVeAddresses(); @@ -101,13 +103,26 @@ function prepareTokenContracts(address: Address, account: Address): ReadContract ] } -export async function getVaultsByChain({ chain, account }: { chain: Chain, account?: Address }): Promise { +interface GetVaultsByChainProps { + chain: Chain; + account?: Address; + yieldOptions: YieldOptions +} + +export async function getVaultsByChain({ chain, account, yieldOptions }: GetVaultsByChainProps): Promise { const client = createPublicClient({ chain, transport: http(RPC_URLS[chain.id]) }) const vaults = await getVaultAddresses({ client }) - return getVaults({ vaults, account, client }) + return getVaults({ vaults, account, client, yieldOptions }) } -export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { vaults: Address[], account?: Address, client: PublicClient }): Promise { +interface GetVaultsProps { + vaults: Address[]; + account?: Address; + client: PublicClient; + yieldOptions: YieldOptions +} + +export async function getVaults({ vaults, account = ADDRESS_ZERO, client, yieldOptions }: GetVaultsProps): Promise { const hasAccount = account !== ADDRESS_ZERO // Get vault addresses const results = await client.multicall({ @@ -120,16 +135,18 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va if (i > 0) i = i * 10 const assetsPerShare = Number(results[i + 6]) > 0 ? Number(results[i + 5]) / Number(results[i + 6]) : Number(1e-9) const fees = results[i + 7] as [BigInt, BigInt, BigInt, BigInt] + const vaultToken: Token = { + address: getAddress(vault), + name: String(results[i + 0]), + symbol: String(results[i + 1]), + decimals: Number(results[i + 2]), + logoURI: "/images/tokens/pop.svg", + balance: hasAccount ? Number(results[i + 9]) : 0, + price: 0 // @dev will be added in a later step + } return { address: getAddress(vault), - vault: { - address: getAddress(vault), - name: String(results[i + 0]), - symbol: String(results[i + 1]), - decimals: Number(results[i + 2]), - logoURI: "/images/tokens/pop.svg", - balance: hasAccount ? Number(results[i + 9]) : 0 - }, + vault: { ...vaultToken, symbol: cleanTokenSymbol(vaultToken) }, assetAddress: getAddress(results[i + 3] as string), adapterAddress: getAddress(results[i + 4] as string), totalAssets: Number(results[i + 5]), @@ -176,6 +193,8 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va ...entry, asset: { ...asset, + name: cleanTokenName(asset), + symbol: cleanTokenSymbol(asset), logoURI: getAssetIcon({ asset, adapter, chainId: client.chain.id }) }, adapter @@ -219,10 +238,26 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va tvl: (entry.totalSupply * pricePerShare) / (10 ** entry.asset.decimals) } }) + + // Add apy + metadata = await Promise.all(metadata.map(async (entry, i) => { + let apy = 0; + try { + const vaultYield = await yieldOptions.getApy({ + chainId: entry.chainId, + protocol: entry.metadata.optionalMetadata.resolver as ProtocolName, + asset: entry.asset.address + }) + apy = vaultYield.total + } catch (e) { } + return { ...entry, apy, totalApy: apy } + })) + + // Add gauges if (client.chain.id === 1) { const gauges = await getGauges({ address: GAUGE_CONTROLLER, account: account, publicClient: client }) - metadata = metadata.map((entry, i) => { + metadata = await Promise.all(metadata.map(async (entry, i) => { const foundGauge = gauges.find((gauge: Gauge) => gauge.lpToken === entry.address) const gauge = foundGauge ? { address: foundGauge.address, @@ -234,107 +269,25 @@ export async function getVaults({ vaults, account = ADDRESS_ZERO, client }: { va price: entry.pricePerShare * 1e9, } : undefined + let gaugeMinApy; + let gaugeMaxApy; + let totalApy = entry.totalApy; + if (!!gauge) { + const gaugeApr = await calculateAPR({ vaultPrice: entry.vault.price, gauge: gauge.address, publicClient: client }) + gaugeMinApy = gaugeApr[0]; + gaugeMaxApy = gaugeApr[1]; + totalApy += gaugeApr[1]; + } + return { ...entry, - gauge + gauge, + gaugeMinApy, + gaugeMaxApy, + totalApy } - }) + })) } return metadata as unknown as VaultData[] -} - - -export async function getVault({ vault, account = ADDRESS_ZERO, client }: { vault: Address, account?: Address, client: PublicClient }): Promise { - const hasAccount = account !== ADDRESS_ZERO - - const results = await client.multicall({ - contracts: prepareVaultContract(vault, account), - allowFailure: false - }) - const registryMetadata = await client.readContract(prepareRegistryContract(VaultRegistryByChain[client.chain.id], vault)) as unknown as string[] - const vaultName = await getVaultName({ address: getAddress(vault), cid: registryMetadata[3] }) - - const price = await resolvePrice({ chainId: client.chain.id, client: client, address: results[3] as Address, resolver: 'llama' }) - const assetsPerShare = Number(results[6]) > 0 ? Number(results[5]) / Number(results[6]) : Number(1e-9) - const pricePerShare = assetsPerShare * price - const fees = results[7] as [BigInt, BigInt, BigInt, BigInt] - - // Add token and adapter metadata - const assetAndAdapterMeta = await client.multicall({ - contracts: [...prepareTokenContracts(results[3] as Address, account), ...prepareTokenContracts(results[4] as Address, account)].flat(), - allowFailure: false - }) - const asset = { - address: getAddress(results[3] as string), - name: String(assetAndAdapterMeta[0]), - symbol: String(assetAndAdapterMeta[1]), - decimals: Number(results[2]) - 9, - logoURI: "", - balance: hasAccount ? Number(assetAndAdapterMeta[2]) : 0, - price: price - } - const adapter = { - address: getAddress(results[4] as string), - name: String(assetAndAdapterMeta[3]), - symbol: String(assetAndAdapterMeta[4]), - decimals: Number(results[2]), - logoURI: "/images/tokens/pop.svg", // wont be used, just here for consistency, - balance: 0, // wont be used, just here for consistency, - price: 0, // wont be used, just here for consistency, - } - const result = { - address: getAddress(vault), - vault: { - address: getAddress(vault), - name: String(results[0]), - symbol: String(results[1]), - decimals: Number(results[2]), - logoURI: "/images/tokens/pop.svg", - balance: hasAccount ? Number(results[9]) : 0, - price: pricePerShare * 1e9, // @dev -- normalize vault price for previews (watch this if errors occur) - }, - asset: { ...asset, logoURI: getAssetIcon({ asset, adapter, chainId: client.chain.id }) }, - adapter, - totalAssets: Number(results[5]), - totalSupply: Number(results[6]), - assetsPerShare: assetsPerShare, - assetPrice: price, - pricePerShare: pricePerShare, - tvl: (Number(results[6]) * pricePerShare) / (10 ** (Number(results[2]) - 9)), - fees: { - deposit: Number(fees[0]), - withdrawal: Number(fees[1]), - management: Number(fees[2]), - performance: Number(fees[3]), - }, - depositLimit: Number(results[8]), - metadata: { - creator: registryMetadata[2] as Address, - cid: registryMetadata[3] as string, - vaultName: vaultName, - optionalMetadata: getOptionalMetadata({ vaultAddress: getAddress(vault), asset: asset, adapter: adapter }) - }, - chainId: client.chain.id - } - - // Add gauges - if (client.chain.id === 1) { - const { - GaugeController: GAUGE_CONTROLLER, - } = getVeAddresses(); - const gauges = await getGauges({ address: GAUGE_CONTROLLER, publicClient: client }) - const foundGauge = gauges.find((gauge: Gauge) => gauge.lpToken === result.address) - // @ts-ignore - result.gauge = foundGauge ? { - address: foundGauge.address, - name: `${result.vault.name}-gauge`, - symbol: `st-${result.vault.name}`, - decimals: foundGauge.decimals, - logoURI: "/images/tokens/pop.svg", // wont be used, just here for consistency - balance: foundGauge.balance, - price: result.pricePerShare * 1e9, - } : undefined - } - return result; } \ No newline at end of file diff --git a/package.json b/package.json index 6216a62..077b127 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "slick-carousel": "^1.8.1", "tailwind-scrollbar-hide": "^1.1.7", "tailwindcss": "^3.2.6", - "vaultcraft-sdk": "0.1.15", + "vaultcraft-sdk": "0.1.16", "viem": "1.18.9", "wagmi": "1.4.5" }, diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 27620a0..588b14e 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -21,6 +21,7 @@ import { ERC20Abi, VaultAbi } from "@/lib/constants"; import { getVaultNetworthByChain } from "@/lib/getNetworth"; import { useAtom } from "jotai"; import { vaultsAtom } from "@/lib/atoms/vaults"; +import VaultsSorting, { VAULT_SORTING_TYPE } from "@/components/vault/VaultsSorting"; export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2fD2C18f79F93eF299B20B681Ab2a61f5F28A6fF", "0xDFf04Efb38465369fd1A2E8B40C364c22FfEA340", "0xd4D442AC311d918272911691021E6073F620eb07", //@dev for some reason the live 3Crypto yVault isnt picked up by the yearnAdapter nor the yearnFactoryAdapter @@ -30,11 +31,12 @@ export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2 "0x860b717B360378E44A241b23d8e8e171E0120fF0", // R/Dai "0xBae30fBD558A35f147FDBaeDbFF011557d3C8bd2", // 50OHM - 50 DAI "0x759281a408A48bfe2029D259c23D7E848A7EA1bC", // yCRV + "0xa6fcC7813d9D394775601aD99874c9f8e95BAd78", // Automated Pool Token - Oracle Vault 3 ] const { oVCX } = getVeAddresses(); -const NETWORKS_SUPPORTING_ZAP = [1] +const NETWORKS_SUPPORTING_ZAP = [1, 137, 10, 42161, 56] export interface MutateTokenBalanceProps { inputToken: Address; @@ -66,6 +68,7 @@ const Vaults: NextPage = () => { const { data: oBal } = useBalance({ chainId: 1, address: account, token: oVCX, watch: true }) const [searchString, handleSearch] = useState(""); + const [sortingType, setSortingType] = useState(VAULT_SORTING_TYPE.none) useEffect(() => { async function getVaults() { @@ -173,6 +176,30 @@ const Vaults: NextPage = () => { setVaults(newVaultState) } + const sortByAscendingTvl = () => { + const sortedVaults = [...vaults].sort((a, b) => b.tvl - a.tvl); + setSortingType(VAULT_SORTING_TYPE.mostTvl) + setVaults(sortedVaults) + } + + const sortByDescendingTvl = () => { + const sortedVaults = [...vaults].sort((a, b) => a.tvl - b.tvl); + setSortingType(VAULT_SORTING_TYPE.lessTvl) + setVaults(sortedVaults) + } + + const sortByAscendingApy = () => { + const sortedVaults = [...vaults].sort((a, b) => b.apy - a.apy); + setSortingType(VAULT_SORTING_TYPE.mostvAPR) + setVaults(sortedVaults) + } + + const sortByDescendingApy = () => { + const sortedVaults = [...vaults].sort((a, b) => a.apy - b.apy); + setSortingType(VAULT_SORTING_TYPE.lessvAPR) + setVaults(sortedVaults) + } + return (
@@ -244,17 +271,20 @@ const Vaults: NextPage = () => {
-
+
chain.id)} selectNetwork={selectNetwork} /> -
- - handleSearch(e.target.value.toLowerCase())} - defaultValue={searchString} - /> +
+
+ + handleSearch(e.target.value.toLowerCase())} + defaultValue={searchString} + /> +
+
diff --git a/yarn.lock b/yarn.lock index 64627bd..d072e88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,9 +23,9 @@ integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== "@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.2": - version "7.23.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" - integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.4.tgz#36fa1d2b36db873d25ec631dcc4923fdc1cf2e2e" + integrity sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg== dependencies: regenerator-runtime "^0.14.0" @@ -95,10 +95,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d" - integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w== +"@eslint/js@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.54.0.tgz#4fab9a2ff7860082c304f750e94acd644cf984cf" + integrity sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ== "@headlessui/react@^1.7.10": version "1.7.17" @@ -460,9 +460,9 @@ "@parcel/watcher-win32-x64" "2.3.0" "@rainbow-me/rainbowkit@^1.0.11": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@rainbow-me/rainbowkit/-/rainbowkit-1.2.0.tgz#8ddcb3acef5408ef375e3df349429144aa230e12" - integrity sha512-XjdeX31GwFdRR/1rCRqPXiO94nbq2qOlnaox5P4K/KMRIUwyelKzak27uWw8Krmor/Hcrd5FisfepGDS0tUfEA== + version "1.3.0" + resolved "https://registry.yarnpkg.com/@rainbow-me/rainbowkit/-/rainbowkit-1.3.0.tgz#b5546a6b530bbe1dac13b88708ab17d4164327fa" + integrity sha512-y5/JZIdYjqc84QFqKc1AhOHctnFC7quaDE3K8bueGfa0TgyrXcA6XgN3Dko530b3sxJJiTgvu2LxWlNUg8Felg== dependencies: "@vanilla-extract/css" "1.9.1" "@vanilla-extract/dynamic" "2.0.2" @@ -483,9 +483,9 @@ rc-util "^5.24.4" "@rc-component/trigger@^1.18.0": - version "1.18.1" - resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-1.18.1.tgz#149881ace55943f0b74ae0470dc9f05b8f0b5d51" - integrity sha512-bAcxJJ1Y+EJVgn8BRik7d8JjjAPND5zKkHQ3159zeR0gVoG4Z0RgEDAiXFFoie3/WpoJ9dRJyjrIpnH4Ef7PEg== + version "1.18.2" + resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-1.18.2.tgz#dc52c4c66fa8aaccaf0710498f2429fc05454e3b" + integrity sha512-jRLYgFgjLEPq3MvS87fIhcfuywFSRDaDrYw1FLku7Cm4esszvzTbA0JBsyacAyLrK9rF3TiHFcvoEDMzoD3CTA== dependencies: "@babel/runtime" "^7.23.2" "@rc-component/portal" "^1.1.0" @@ -495,9 +495,9 @@ rc-util "^5.38.0" "@rushstack/eslint-patch@^1.3.3": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz#5f1b518ec5fa54437c0b7c4a821546c64fed6922" - integrity sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA== + version "1.6.0" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.6.0.tgz#1898e7a7b943680d757417a47fb10f5fcc230b39" + integrity sha512-2/U3GXA6YiPYQDLGwtGlnNgKYBSwCFIHf8Y9LUY5VATHdtbLlU0Y1R3QoBnT0aB4qv/BEiVVsj7LJXoQCgJ2vA== "@safe-global/safe-apps-provider@^0.17.1": version "0.17.1" @@ -558,9 +558,9 @@ buffer "~6.0.3" "@solana/web3.js@^1.70.1": - version "1.87.5" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.87.5.tgz#74df3f19ef65e3a419bd1810f500f8e51f4ab63b" - integrity sha512-hy5RVGVw8eXq//g41mIFhk5Jx4QH1CwbkPiQn/3MmHp6VD2HBRVMMZUSGUhYZxbK7NoIjQUsiv4MOlnl3VaUag== + version "1.87.6" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.87.6.tgz#6744cfc5f4fc81e0f58241c0a92648a7320bb3bf" + integrity sha512-LkqsEBgTZztFiccZZXnawWa8qNCATEqE97/d0vIwjTclmVlc8pBpD1DmjfVHtZ1HS5fZorFlVhXfpwnCNDZfyg== dependencies: "@babel/runtime" "^7.23.2" "@noble/curves" "^1.2.0" @@ -720,9 +720,9 @@ tslib "^2.4.0" "@tailwindcss/forms@^0.5.6": - version "0.5.6" - resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.6.tgz#29c6c2b032b363e0c5110efed1499867f6d7e868" - integrity sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA== + version "0.5.7" + resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.7.tgz#db5421f062a757b5f828bc9286ba626c6685e821" + integrity sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw== dependencies: mini-svg-data-uri "^1.2.3" @@ -790,9 +790,9 @@ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/node@*", "@types/node@^20.2.5": - version "20.9.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.0.tgz#bfcdc230583aeb891cf51e73cfdaacdd8deae298" - integrity sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw== + version "20.9.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.4.tgz#cc8f970e869c26834bdb7ed480b30ede622d74c7" + integrity sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA== dependencies: undici-types "~5.26.4" @@ -812,28 +812,28 @@ integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== "@types/prop-types@*": - version "15.7.10" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.10.tgz#892afc9332c4d62a5ea7e897fe48ed2085bbb08a" - integrity sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A== + version "15.7.11" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563" + integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng== "@types/react@^18.0.9": - version "18.2.37" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.37.tgz#0f03af69e463c0f19a356c2660dbca5d19c44cae" - integrity sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw== + version "18.2.38" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.38.tgz#3605ca41d3daff2c434e0b98d79a2469d4c2dd52" + integrity sha512-cBBXHzuPtQK6wNthuVMV6IjHAFkdl/FOPFIlkd81/Cd1+IqkHu/A+w4g43kaQQoYHik/ruaQBDL72HyCy1vuMw== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" csstype "^3.0.2" "@types/scheduler@*": - version "0.16.6" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.6.tgz#eb26db6780c513de59bee0b869ef289ad3068711" - integrity sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA== + version "0.16.8" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff" + integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A== "@types/trusted-types@^2.0.2": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.6.tgz#d12451beaeb9c3838f12024580dc500b7e88b0ad" - integrity sha512-HYtNooPvUY9WAVRBr4u+4Qa9fYD1ze2IUlAD3HoA6oehn1taGwBx3Oa52U4mTslTS+GAExKpaFu39Y5xUEwfjg== + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== "@types/ws@^7.4.4": version "7.4.7" @@ -843,48 +843,48 @@ "@types/node" "*" "@typescript-eslint/parser@^5.4.2 || ^6.0.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.10.0.tgz#578af79ae7273193b0b6b61a742a2bc8e02f875a" - integrity sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog== - dependencies: - "@typescript-eslint/scope-manager" "6.10.0" - "@typescript-eslint/types" "6.10.0" - "@typescript-eslint/typescript-estree" "6.10.0" - "@typescript-eslint/visitor-keys" "6.10.0" + version "6.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.12.0.tgz#9fb21ed7d88065a4a2ee21eb80b8578debb8217c" + integrity sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg== + dependencies: + "@typescript-eslint/scope-manager" "6.12.0" + "@typescript-eslint/types" "6.12.0" + "@typescript-eslint/typescript-estree" "6.12.0" + "@typescript-eslint/visitor-keys" "6.12.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz#b0276118b13d16f72809e3cecc86a72c93708540" - integrity sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg== +"@typescript-eslint/scope-manager@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz#5833a16dbe19cfbad639d4d33bcca5e755c7044b" + integrity sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw== dependencies: - "@typescript-eslint/types" "6.10.0" - "@typescript-eslint/visitor-keys" "6.10.0" + "@typescript-eslint/types" "6.12.0" + "@typescript-eslint/visitor-keys" "6.12.0" -"@typescript-eslint/types@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.10.0.tgz#f4f0a84aeb2ac546f21a66c6e0da92420e921367" - integrity sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg== +"@typescript-eslint/types@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.12.0.tgz#ffc5297bcfe77003c8b7b545b51c2505748314ac" + integrity sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q== -"@typescript-eslint/typescript-estree@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz#667381eed6f723a1a8ad7590a31f312e31e07697" - integrity sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg== +"@typescript-eslint/typescript-estree@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz#764ccc32598549e5b48ec99e3b85f89b1385310c" + integrity sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw== dependencies: - "@typescript-eslint/types" "6.10.0" - "@typescript-eslint/visitor-keys" "6.10.0" + "@typescript-eslint/types" "6.12.0" + "@typescript-eslint/visitor-keys" "6.12.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/visitor-keys@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz#b9eaf855a1ac7e95633ae1073af43d451e8f84e3" - integrity sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg== +"@typescript-eslint/visitor-keys@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz#5877950de42a0f3344261b7a1eee15417306d7e9" + integrity sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw== dependencies: - "@typescript-eslint/types" "6.10.0" + "@typescript-eslint/types" "6.12.0" eslint-visitor-keys "^3.4.1" "@ungap/structured-clone@^1.2.0": @@ -1082,9 +1082,9 @@ ws "^7.5.1" "@walletconnect/keyvaluestorage@^1.0.2": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.0.tgz#782ad09af71e5241147fd7479f8814bd8ab8bb38" - integrity sha512-CjDBs1WmLGstYRoxWx9oAskTKj1deu7gvPycxZo2jYMa85hAYe762AITKWW1i2OJ8y9+5WJTGDAy3inVl8pjtw== + version "1.1.1" + resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz#dd2caddabfbaf80f6b8993a0704d8b83115a1842" + integrity sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA== dependencies: "@walletconnect/safe-json" "^1.0.1" idb-keyval "^6.2.1" @@ -1554,9 +1554,9 @@ axios@^0.21.1: follow-redirects "^1.14.0" axios@^1.3.6, axios@^1.5.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.1.tgz#76550d644bf0a2d469a01f9244db6753208397d7" - integrity sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g== + version "1.6.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" + integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" @@ -1716,9 +1716,9 @@ camelcase@^5.0.0: integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: - version "1.0.30001561" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da" - integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw== + version "1.0.30001564" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001564.tgz#eaa8bbc58c0cbccdcb7b41186df39dd2ba591889" + integrity sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg== chalk@^4.0.0, chalk@^4.1.1: version "4.1.2" @@ -1744,9 +1744,9 @@ chokidar@^3.5.3: fsevents "~2.3.2" citty@^0.1.3, citty@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/citty/-/citty-0.1.4.tgz#91091be06ae4951dffa42fd443de7fe72245f2e0" - integrity sha512-Q3bK1huLxzQrvj7hImJ7Z1vKYJRPQCDnd0EjXfHMidcjecGOMuLrmuQmtWmFkuKLcMThlGh1yCKG8IEc6VeNXQ== + version "0.1.5" + resolved "https://registry.yarnpkg.com/citty/-/citty-0.1.5.tgz#fe37ceae5dc764af75eb2fece99d2bf527ea4e50" + integrity sha512-AS7n5NSc0OQVMV9v6wt3ByujNIrne0/cTjiC2MYqhvao57VNfiuVksTSr2p17nVOhEr2KtqiAkGwHcgMC/qUuQ== dependencies: consola "^3.2.3" @@ -1828,9 +1828,9 @@ commander@^4.0.0: integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== component-emitter@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + version "1.3.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17" + integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== concat-map@0.0.1: version "0.0.1" @@ -1977,7 +1977,7 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0, de has-property-descriptors "^1.0.0" object-keys "^1.1.1" -defu@^6.1.2: +defu@^6.1.2, defu@^6.1.3: version "6.1.3" resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.3.tgz#6d7f56bc61668e844f9f593ace66fd67ef1205fd" integrity sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ== @@ -2002,7 +2002,7 @@ dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== -destr@^2.0.1: +destr@^2.0.1, destr@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.2.tgz#8d3c0ee4ec0a76df54bc8b819bca215592a8c218" integrity sha512-65AlobnZMiCET00KaFFjUefxDX0khFA/E4myqZ7a6Sq1yZtR8+FVIvilVX66vF2uobSumxooYZChiRPCKNqhmg== @@ -2079,9 +2079,9 @@ duplexify@^4.1.2: stream-shift "^1.0.0" electron-to-chromium@^1.4.535: - version "1.4.580" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.580.tgz#2f8f70f70733a6be1fb6f31de1224e6dc4bb196d" - integrity sha512-T5q3pjQon853xxxHUq3ZP68ZpvJHuSMY2+BZaW3QzjS4HvNuvsMmZ/+lU+nCrftre1jFZ+OSlExynXWBihnXzw== + version "1.4.592" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.592.tgz#1ffd49ba3da3da3077ea20014b066c910d50c913" + integrity sha512-D3NOkROIlF+d5ixnz7pAf3Lu/AuWpd6AYgI9O67GQXMXTcCP1gJQRotOq35eQy5Sb4hez33XH1YdTtILA7Udww== emoji-regex@^8.0.0: version "8.0.0" @@ -2391,14 +2391,14 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.15.0: - version "8.53.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.53.0.tgz#14f2c8244298fcae1f46945459577413ba2697ce" - integrity sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag== + version "8.54.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.54.0.tgz#588e0dd4388af91a2e8fa37ea64924074c783537" + integrity sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.3" - "@eslint/js" "8.53.0" + "@eslint/js" "8.54.0" "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -2677,9 +2677,9 @@ find-up@^5.0.0: path-exists "^4.0.0" flat-cache@^3.0.4: - version "3.1.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b" - integrity sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q== + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: flatted "^3.2.9" keyv "^4.5.3" @@ -2908,17 +2908,17 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -h3@^1.7.1, h3@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/h3/-/h3-1.8.2.tgz#69ea8ca0285c1bb268cd08b9a7017e02939f88b7" - integrity sha512-1Ca0orJJlCaiFY68BvzQtP2lKLk46kcLAxVM8JgYbtm2cUg6IY7pjpYgWMwUvDO9QI30N5JAukOKoT8KD3Q0PQ== +h3@^1.8.1, h3@^1.8.2: + version "1.9.0" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.9.0.tgz#c5f512a93026df9837db6f30c9ef51135dd46752" + integrity sha512-+F3ZqrNV/CFXXfZ2lXBINHi+rM4Xw3CDC5z2CDK3NMPocjonKipGLLDSkrqY9DOrioZNPTIdDMWfQKm//3X2DA== dependencies: cookie-es "^1.0.0" - defu "^6.1.2" - destr "^2.0.1" - iron-webcrypto "^0.10.1" + defu "^6.1.3" + destr "^2.0.2" + iron-webcrypto "^1.0.0" radix3 "^1.1.0" - ufo "^1.3.0" + ufo "^1.3.2" uncrypto "^0.1.3" unenv "^1.7.4" @@ -3018,9 +3018,9 @@ ieee754@^1.2.1: integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore@^5.2.0: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + version "5.3.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" + integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== import-fresh@^3.2.1: version "3.3.0" @@ -3084,10 +3084,10 @@ ioredis@^5.3.2: redis-parser "^3.0.0" standard-as-callback "^2.1.0" -iron-webcrypto@^0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-0.10.1.tgz#cab8636a468685533a8521bfd7f06b19b7174809" - integrity sha512-QGOS8MRMnj/UiOa+aMIgfyHcvkhqNUsUxb1XzskENvbo+rEfp6TOwqd1KPuDzXC4OnGHcMSVxDGRoilqB8ViqA== +iron-webcrypto@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.0.0.tgz#e3b689c0c61b434a0a4cb82d0aeabbc8b672a867" + integrity sha512-anOK1Mktt8U1Xi7fCM3RELTuYbnFikQY5VtrDj7kPgpejV7d43tWKhzgioO0zpkazLEL/j/iayRqnJhrGfqUsg== is-arguments@^1.0.4: version "1.1.1" @@ -3477,17 +3477,22 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lilconfig@^2.0.5, lilconfig@^2.1.0: +lilconfig@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== +lilconfig@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.0.0.tgz#f8067feb033b5b74dab4602a5f5029420be749bc" + integrity sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -listhen@^1.2.2: +listhen@^1.5.5: version "1.5.5" resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.5.5.tgz#58915512af70f770aa3e9fb19367adf479bb58c4" integrity sha512-LXe8Xlyh3gnxdv4tSjTjscD1vpr/2PRpzq8YIaMJgyKzRG8wdISlWVWnGThJfHnlJ6hmLt2wq1yeeix0TEbuoA== @@ -3581,10 +3586,10 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -lru-cache@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" - integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g== +lru-cache@^10.0.2: + version "10.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484" + integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag== lru-cache@^6.0.0: version "6.0.0" @@ -3822,7 +3827,7 @@ node-cache@^5.1.2: dependencies: clone "2.x" -node-fetch-native@^1.2.0, node-fetch-native@^1.4.0: +node-fetch-native@^1.4.0, node-fetch-native@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.4.1.tgz#5a336e55b4e1b1e72b9927da09fecd2b374c9be5" integrity sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w== @@ -3840,9 +3845,9 @@ node-forge@^1.3.1: integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.6.1" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.1.tgz#24b6d075e5e391b8d5539d98c7fc5c210cac8a3e" - integrity sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ== + version "4.7.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.7.0.tgz#749f0033590b2a89ac8edb5e0775f95f5ae86d15" + integrity sha512-PbZERfeFdrHQOOXiAKOY0VPbykZy90ndPKk0d+CFDegTKmWp1VgOTz2xACVbr1BjCWxrQp68CXtvNsveFhqDJg== node-releases@^2.0.13: version "2.0.13" @@ -3941,7 +3946,7 @@ object.values@^1.1.6, object.values@^1.1.7: define-properties "^1.2.0" es-abstract "^1.22.1" -ofetch@^1.1.1: +ofetch@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.3.tgz#588cb806a28e5c66c2c47dd8994f9059a036d8c0" integrity sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg== @@ -4160,12 +4165,12 @@ postcss-js@^4.0.1: camelcase-css "^2.0.1" postcss-load-config@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.1.tgz#152383f481c2758274404e4962743191d73875bd" - integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA== + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" + integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== dependencies: - lilconfig "^2.0.5" - yaml "^2.1.1" + lilconfig "^3.0.0" + yaml "^2.3.4" postcss-nested@^6.0.1: version "6.0.1" @@ -4197,9 +4202,9 @@ postcss@8.4.31, postcss@^8.4.23: source-map-js "^1.0.2" preact@^10.12.0, preact@^10.5.9: - version "10.18.2" - resolved "https://registry.yarnpkg.com/preact/-/preact-10.18.2.tgz#e3aeccc292aebbc2e0b76ed76570aa61dd5f75e4" - integrity sha512-X/K43vocUHDg0XhWVmTTMbec4LT/iBMh+csCEqJk+pJqegaXsvjdqN80ZZ3L+93azWCnWCZ+WGwYb8SplxeNjA== + version "10.19.2" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.19.2.tgz#841797620dba649aaac1f8be42d37c3202dcea8b" + integrity sha512-UA9DX/OJwv6YwP9Vn7Ti/vF80XL+YA5H2l7BpCtUr3ya8LWHFzpiO5R+N7dN16ujpIxhekRFuOOF82bXX7K/lg== prelude-ls@^1.2.1: version "1.2.1" @@ -4571,9 +4576,9 @@ rimraf@^3.0.2: glob "^7.1.3" rpc-websockets@^7.5.1: - version "7.6.2" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.6.2.tgz#ed82f21ea8290f26d73f10d0dc0f9425dc364b81" - integrity sha512-+M1fOYMPxvOQDHbSItkD/an4fRwPZ1Nft1zv48G84S0TyChG2A1GXmjWkbs3o2NxW+q36H9nM2uLo5yojTrPaA== + version "7.8.0" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.8.0.tgz#1bcf571f65c51803e81f0824e9540a0da35a5287" + integrity sha512-AStkq6KDvSAmA4WiwlK1pDvj/33BWmExTATUokC0v+NhWekXSTNzXS5OGXeYwq501/pj6lBZMofg/h4dx4/tCg== dependencies: "@babel/runtime" "^7.17.2" eventemitter3 "^4.0.7" @@ -4746,9 +4751,9 @@ standard-as-callback@^2.1.0: integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== std-env@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.4.3.tgz#326f11db518db751c83fd58574f449b7c3060910" - integrity sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q== + version "3.5.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.5.0.tgz#83010c9e29bd99bf6f605df87c19012d82d63b97" + integrity sha512-JGUEaALvL0Mf6JCfYnJOTcobY+Nc7sG/TemDRBqCA0wEr4DER7zDchaaixTlmOxAjG1uRJmX82EQcxwTQTkqVA== stream-browserify@^3.0.0: version "3.0.0" @@ -5130,10 +5135,10 @@ ua-parser-js@^1.0.35: resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.37.tgz#b5dc7b163a5c1f0c510b08446aed4da92c46373f" integrity sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ== -ufo@^1.2.0, ufo@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.1.tgz#e085842f4627c41d4c1b60ebea1f75cdab4ce86b" - integrity sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw== +ufo@^1.3.0, ufo@^1.3.1, ufo@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.2.tgz#c7d719d0628a1c80c006d2240e0d169f6e3c0496" + integrity sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA== uint8arrays@^3.0.0, uint8arrays@^3.1.0: version "3.1.1" @@ -5163,32 +5168,32 @@ undici-types@~5.26.4: integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== unenv@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.7.4.tgz#a0e5a78de2c7c3c4563c06ba9763c96c59db3333" - integrity sha512-fjYsXYi30It0YCQYqLOcT6fHfMXsBr2hw9XC7ycf8rTG7Xxpe3ZssiqUnD0khrjiZEmkBXWLwm42yCSCH46fMw== + version "1.8.0" + resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.8.0.tgz#0f860d5278405700bd95d47b23bc01f3a735d68c" + integrity sha512-uIGbdCWZfhRRmyKj1UioCepQ0jpq638j/Cf0xFTn4zD1nGJ2lSdzYHLzfdXN791oo/0juUiSWW1fBklXMTsuqg== dependencies: consola "^3.2.3" - defu "^6.1.2" + defu "^6.1.3" mime "^3.0.0" - node-fetch-native "^1.4.0" + node-fetch-native "^1.4.1" pathe "^1.1.1" unstorage@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.9.0.tgz#0c1977f4e769a48344339ac97ec3f2feea94d43d" - integrity sha512-VpD8ZEYc/le8DZCrny3bnqKE4ZjioQxBRnWE+j5sGNvziPjeDlaS1NaFFHzl/kkXaO3r7UaF8MGQrs14+1B4pQ== + version "1.10.1" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.10.1.tgz#bf8cc00a406e40a6293e893da9807057d95875b0" + integrity sha512-rWQvLRfZNBpF+x8D3/gda5nUCQL2PgXy2jNG4U7/Rc9BGEv9+CAJd0YyGCROUBKs9v49Hg8huw3aih5Bf5TAVw== dependencies: anymatch "^3.1.3" chokidar "^3.5.3" - destr "^2.0.1" - h3 "^1.7.1" + destr "^2.0.2" + h3 "^1.8.2" ioredis "^5.3.2" - listhen "^1.2.2" - lru-cache "^10.0.0" + listhen "^1.5.5" + lru-cache "^10.0.2" mri "^1.2.0" - node-fetch-native "^1.2.0" - ofetch "^1.1.1" - ufo "^1.2.0" + node-fetch-native "^1.4.1" + ofetch "^1.3.3" + ufo "^1.3.1" untun@^0.1.2: version "0.1.2" @@ -5289,10 +5294,10 @@ valtio@1.11.2: proxy-compare "2.5.1" use-sync-external-store "1.2.0" -vaultcraft-sdk@0.1.15: - version "0.1.15" - resolved "https://registry.yarnpkg.com/vaultcraft-sdk/-/vaultcraft-sdk-0.1.15.tgz#2844e8d6c1be08f85084426f0805a825fa13ca16" - integrity sha512-nCpP0xOiE3yCpfKhud0+VCPP4twwfTodoSan6SvJbflVy9kLzBSQPIRU27H4KiDC9yIZEe11MHVHkLfhWfcXrA== +vaultcraft-sdk@0.1.16: + version "0.1.16" + resolved "https://registry.yarnpkg.com/vaultcraft-sdk/-/vaultcraft-sdk-0.1.16.tgz#10e3d450a71f475b56b9d2eed6aff0fb67e8aa0e" + integrity sha512-JeZg49XSMz4DkqTXBsgzWo+XcheZ6I94LMT1mKYY6VXkPQ24Nocipt5FnV8J/1c+8BkW1dJ535L9QwGcnBkn0Q== dependencies: "@curvefi/api" "2.44.0" axios "^1.5.0" @@ -5300,7 +5305,7 @@ vaultcraft-sdk@0.1.15: node-cache "^5.1.2" viem "^1.5.3" -viem@1.18.9, viem@^1.0.0, viem@^1.5.3: +viem@1.18.9: version "1.18.9" resolved "https://registry.yarnpkg.com/viem/-/viem-1.18.9.tgz#8be8fe3148b1c6c3bccc853001df98f91a8aeb30" integrity sha512-eAXtoTwAFA3YEgjTYMb5ZTQrDC0UPx5qyZ4sv90TirVKepcM9mBPksTkC1SSWya0UdxhBmhEBL/CiYMjmGCTWg== @@ -5314,6 +5319,20 @@ viem@1.18.9, viem@^1.0.0, viem@^1.5.3: isows "1.0.3" ws "8.13.0" +viem@^1.0.0, viem@^1.5.3: + version "1.19.7" + resolved "https://registry.yarnpkg.com/viem/-/viem-1.19.7.tgz#815d100c37ed1dda56809bbbb1c1ca4a7982f5f7" + integrity sha512-NFCqU73CTHML9K7G3K8hnDJ9VjHJbH822Z6U2jUGNr0g5486EHMW0gtwnk6ivFP+ru5UewmUKwEvO0p5m0rvnA== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@scure/bip32" "1.3.2" + "@scure/bip39" "1.2.1" + abitype "0.9.8" + isows "1.0.3" + ws "8.13.0" + wagmi@1.4.5: version "1.4.5" resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-1.4.5.tgz#65ccf763e17892871196b6e5b188e29f0b08d3df" @@ -5458,7 +5477,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^2.1.1: +yaml@^2.3.4: version "2.3.4" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== From 800f4504316390216863354a81cca6aaacaf42a0 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 23 Nov 2023 12:15:04 +0100 Subject: [PATCH 64/84] added migration link --- components/navbar/NavbarLinks.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/navbar/NavbarLinks.tsx b/components/navbar/NavbarLinks.tsx index e88b4b2..216e222 100644 --- a/components/navbar/NavbarLinks.tsx +++ b/components/navbar/NavbarLinks.tsx @@ -14,6 +14,10 @@ const links: { label: string, url: string, onClick?: Function }[] = [ label: "Stats", url: "/stats" }, + { + label: "Pop to VCX Migration", + url: "/migration" + }, { label: "VaultCraft", url: "https://vaultcraft.io/", From 9e93e5e2f975c2d683d1c9e98f0b34ef4fb2a51e Mon Sep 17 00:00:00 2001 From: RedVeil Date: Sat, 25 Nov 2023 12:37:19 +0100 Subject: [PATCH 65/84] contract addresses 1.0.5 --- lib/utils/addresses/index.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/utils/addresses/index.ts b/lib/utils/addresses/index.ts index fca4d85..42feb2d 100644 --- a/lib/utils/addresses/index.ts +++ b/lib/utils/addresses/index.ts @@ -1,23 +1,23 @@ import { veAddresses } from "lib/types"; const VeAddresses = { - VCX: "0x27af2Cf1C25114eF3b9bb43Fcef601dC6D959226", - WETH_VCX_LP: "0xCE8D4Ad8Cce1240EcBc49385BAF4c399A7F353F9", - VE_VCX:"0x38D7a3C69727f6f03B62137aF314f40c458847aE", + VCX: "0xcE246eEa10988C495B4A90a905Ee9237a0f91543", + WETH_VCX_LP: "0x577A7f7EE659Aa14Dc16FD384B3F8078E23F1920", + VE_VCX:"0x0aB4bC35Ef33089B9082Ca7BB8657D7c4E819a1A", + oVCX: "0xaFa52E3860b4371ab9d8F08E801E9EA1027C0CA2", POP: "0xD0Cd466b34A24fcB2f87676278AF2005Ca8A78c4", WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", - BalancerPool: "0xCE8D4Ad8Cce1240EcBc49385BAF4c399A7F353F9", // Same as WETH_VCX_LP - BalancerOracle: "0xd516B712Ad41D766c2DB1564bcaf449B0803ba6B", - oVCX: "0x9BAc7db83a9F24D1a2B983a20973bBF458f866c4", + BalancerPool: "0x577A7f7EE659Aa14Dc16FD384B3F8078E23F1920", // Same as WETH_VCX_LP + BalancerOracle: "0xe2871224b413F55c5a2Fd21E49bD63A52e339b03", VaultRegistry: "0x007318Dc89B314b47609C684260CfbfbcD412864", - BoostV2: "0xE7D70eFAe8a9267B257af4C2548Bb6363d2a241b", - Minter: "0x180A9F8D68aa23D0f98Bd48a68171B822dC15481", - TokenAdmin: "0xeDe48B54943404af051AacCb2eeCD6c6a1381C24", - VotingEscrow: "0x38D7a3C69727f6f03B62137aF314f40c458847aE", // Same as VE_VCX - GaugeController: "0xbaB926cf31a96a6D5c2f0f1A9B3336470E01d0ed", - GaugeFactory: "0x9B7E8f663b3F8F5cC3adee0aA288872Dc142485B", - SmartWalletChecker: "0xCC007029f46C20D6290E6Fee9dD1808DcDb6FC5b", - VotingEscrowDelegation: "0x69F4baB8F9fA325F64D1353fa89455aB0d38E0d5", + BoostV2: "0xa2E88993a0f0dc6e6020431477f3A70c86109bBf", + Minter: "0x49f095B38eE6d8541758af51c509332e7793D4b0", + TokenAdmin: "0x03d103c547B43b5a76df7e652BD0Bb61bE0BD70d", + VotingEscrow: "0x0aB4bC35Ef33089B9082Ca7BB8657D7c4E819a1A", // Same as VE_VCX + GaugeController: "0xD57d8EEC36F0Ba7D8Fd693B9D97e02D8353EB1F4", + GaugeFactory: "0x32a33CC9dC61352E70cb557927E5F9544ddb0a26", + SmartWalletChecker: "0x8427155770f7e6b973249E2f9D140a495aBE4f90", + VotingEscrowDelegation: "0x9B12C90BAd388B7e417271eb20678D1a7759507c", VaultRouter: "0x8aed8Ea73044910760E8957B6c5b28Ac51f8f809", FeeDistributor: "0x2661cdddb673DDcF2e0bc0dD7Fd432fCF1fe9e74" }; From ce86689571af368935769279cf67438ebbd589ca Mon Sep 17 00:00:00 2001 From: RedVeil Date: Mon, 27 Nov 2023 09:26:09 +0100 Subject: [PATCH 66/84] updated balancer link --- components/vepop/modals/lock/LockPopInterface.tsx | 2 +- components/vepop/modals/manage/IncreaseStakeInterface.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/vepop/modals/lock/LockPopInterface.tsx b/components/vepop/modals/lock/LockPopInterface.tsx index b71b2fb..4f8d5f6 100644 --- a/components/vepop/modals/lock/LockPopInterface.tsx +++ b/components/vepop/modals/lock/LockPopInterface.tsx @@ -72,7 +72,7 @@ export default function LockPopInterface({ amountState, daysState }: LockPopInte errorMessage={errorMessage} allowInput tokenList={[]} - getTokenUrl="https://app.balancer.fi/#/ethereum/pool/0xce8d4ad8cce1240ecbc49385baf4c399a7f353f9000200000000000000000628" + getTokenUrl="https://app.balancer.fi/#/ethereum/pool/0x577a7f7ee659aa14dc16fd384b3f8078e23f1920000200000000000000000633 " />
diff --git a/components/vepop/modals/manage/IncreaseStakeInterface.tsx b/components/vepop/modals/manage/IncreaseStakeInterface.tsx index 51c54e6..908dbf2 100644 --- a/components/vepop/modals/manage/IncreaseStakeInterface.tsx +++ b/components/vepop/modals/manage/IncreaseStakeInterface.tsx @@ -55,7 +55,7 @@ export default function IncreaseStakeInterface({ amountState, lockedBal }: Incre errorMessage={errorMessage} allowInput tokenList={[]} - getTokenUrl="https://app.balancer.fi/#/ethereum/pool/0xce8d4ad8cce1240ecbc49385baf4c399a7f353f9000200000000000000000628" + getTokenUrl="https://app.balancer.fi/#/ethereum/pool/0x577a7f7ee659aa14dc16fd384b3f8078e23f1920000200000000000000000633 " />
From d7bf79ba89d15a772e70a45197bf199058c99012 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Mon, 27 Nov 2023 12:21:34 +0100 Subject: [PATCH 67/84] fixed vault inputs --- components/vault/VaultInputs.tsx | 46 +++++++++++++++++++--------- lib/utils/connectors.ts | 2 +- lib/utils/formatBigNumber.ts | 12 +++++++- pages/experimental/vaults.tsx | 52 +++++++++++++++++++++++++------- pages/vaults.tsx | 38 +++++++++++++++++------ 5 files changed, 112 insertions(+), 38 deletions(-) diff --git a/components/vault/VaultInputs.tsx b/components/vault/VaultInputs.tsx index a103c5e..5e639b5 100644 --- a/components/vault/VaultInputs.tsx +++ b/components/vault/VaultInputs.tsx @@ -26,7 +26,7 @@ interface VaultInputsProps { } export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId, mutateTokenBalance }: VaultInputsProps): JSX.Element { - const publicClient = usePublicClient(); + const publicClient = usePublicClient({ chainId }); const { data: walletClient } = useWalletClient() const { address: account } = useAccount(); const { chain } = useNetwork(); @@ -70,81 +70,96 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId setInputToken(!!gauge ? gauge : vault); setOutputToken(asset) setIsDeposit(false) - setAction(!!gauge ? ActionType.UnstakeAndWithdraw : ActionType.Withdrawal) + const newAction = !!gauge ? ActionType.UnstakeAndWithdraw : ActionType.Withdrawal + setAction(newAction) + setSteps(getActionSteps(newAction)) } else { // Switch to Deposit setInputToken(asset); setOutputToken(!!gauge ? gauge : vault) setIsDeposit(true) - setAction(!!gauge ? ActionType.DepositAndStake : ActionType.Deposit) + const newAction = !!gauge ? ActionType.DepositAndStake : ActionType.Deposit + setAction(newAction) + setSteps(getActionSteps(newAction)) } } function handleTokenSelect(input: Token, output: Token): void { + setInputToken(input); + setOutputToken(output) + switch (input.address) { case asset.address: switch (output.address) { case asset.address: // error - break + return case vault.address: setAction(ActionType.Deposit) setSteps(getActionSteps(ActionType.Deposit)) + return case gauge?.address: setAction(ActionType.DepositAndStake) setSteps(getActionSteps(ActionType.DepositAndStake)) + return default: // error - break + return } case vault.address: switch (output.address) { case asset.address: setAction(ActionType.Withdrawal) setSteps(getActionSteps(ActionType.Withdrawal)) + return case vault.address: // error - break + return case gauge?.address: setAction(ActionType.Stake) setSteps(getActionSteps(ActionType.Stake)) + return default: setAction(ActionType.ZapWithdrawal) setSteps(getActionSteps(ActionType.ZapWithdrawal)) + return } case gauge?.address: switch (output.address) { case asset.address: setAction(ActionType.UnstakeAndWithdraw) setSteps(getActionSteps(ActionType.UnstakeAndWithdraw)) + return case vault.address: setAction(ActionType.Unstake) setSteps(getActionSteps(ActionType.Unstake)) + return case gauge?.address: // error - break + return default: setAction(ActionType.ZapUnstakeAndWithdraw) setSteps(getActionSteps(ActionType.ZapUnstakeAndWithdraw)) + return } default: switch (output.address) { case asset.address: // error - break + return case vault.address: setAction(ActionType.ZapDeposit) setSteps(getActionSteps(ActionType.ZapDeposit)) + return case gauge?.address: setAction(ActionType.ZapDepositAndStake) setSteps(getActionSteps(ActionType.ZapDepositAndStake)) + return default: // error - break + return } } - setInputToken(input); - setOutputToken(output) } async function handleMainAction() { @@ -178,10 +193,11 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId currentStep.loading = false currentStep.success = success; currentStep.error = !success; + const newStepCounter = stepCounter + 1 setSteps(stepsCopy) - setStepCounter(stepCounter + 1) + setStepCounter(newStepCounter) - if (stepCounter === steps.length) { + if (newStepCounter === steps.length) { mutateTokenBalance({ inputToken: inputToken.address, outputToken: outputToken.address, vault: vault.address, chainId, account }) // Reset to start setSteps(getActionSteps(action)) @@ -224,7 +240,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId /> setInputToken(option)} + onSelectToken={option => handleTokenSelect(option, !!gauge ? gauge : vault)} onMaxClick={() => handleChangeInput( { currentTarget: { @@ -262,7 +278,7 @@ export default function VaultInputs({ vault, asset, gauge, tokenOptions, chainId
setOutputToken(option)} + onSelectToken={option => handleTokenSelect(!!gauge ? gauge : vault, option)} onMaxClick={() => { }} chainId={chainId} value={(Number(inputBalance) * (Number(inputToken?.price)) / Number(outputToken?.price)) || 0} diff --git a/lib/utils/connectors.ts b/lib/utils/connectors.ts index 87c973e..d6abe8a 100644 --- a/lib/utils/connectors.ts +++ b/lib/utils/connectors.ts @@ -91,4 +91,4 @@ export const RPC_URLS: { [key: number]: string } = { [ChainId.RemoteFork]: `http://localhost:8545`, }; -export const SUPPORTED_NETWORKS = [mainnet, polygon, optimism, arbitrum] \ No newline at end of file +export const SUPPORTED_NETWORKS = [mainnet, polygon, optimism, arbitrum, bsc, localhost] \ No newline at end of file diff --git a/lib/utils/formatBigNumber.ts b/lib/utils/formatBigNumber.ts index 7e2f10d..e84910c 100644 --- a/lib/utils/formatBigNumber.ts +++ b/lib/utils/formatBigNumber.ts @@ -70,6 +70,16 @@ export const NumberFormatter = Intl.NumberFormat("en", { }); export function safeRound(bn: bigint, decimals = 18): bigint { - const roundingValue = parseUnits("1", decimals > 8 ? 8 : 2) + let roundingDecimals = 1; + if (decimals < 2) { + roundingDecimals = 1; + } else if (decimals <= 8) { + roundingDecimals = 2; + } else if (decimals <= 18) { + roundingDecimals = 10 + } else if (decimals === 27) { + roundingDecimals = 20 + } + const roundingValue = parseUnits("1", roundingDecimals) return (bn / roundingValue) * roundingValue } \ No newline at end of file diff --git a/pages/experimental/vaults.tsx b/pages/experimental/vaults.tsx index 481bcdc..666744e 100644 --- a/pages/experimental/vaults.tsx +++ b/pages/experimental/vaults.tsx @@ -21,6 +21,7 @@ import { ERC20Abi, VaultAbi } from "@/lib/constants"; import { getVaultNetworthByChain } from "@/lib/getNetworth"; import { useAtom } from "jotai"; import { vaultsAtom } from "@/lib/atoms/vaults"; +import VaultsSorting, { VAULT_SORTING_TYPE } from "@/components/vault/VaultsSorting"; export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2fD2C18f79F93eF299B20B681Ab2a61f5F28A6fF", "0xDFf04Efb38465369fd1A2E8B40C364c22FfEA340", "0xd4D442AC311d918272911691021E6073F620eb07", //@dev for some reason the live 3Crypto yVault isnt picked up by the yearnAdapter nor the yearnFactoryAdapter @@ -29,7 +30,7 @@ export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2 "0x9E237F8A3319b47934468e0b74F0D5219a967aB8", // yABoosted Balancer "0x860b717B360378E44A241b23d8e8e171E0120fF0", // R/Dai "0xBae30fBD558A35f147FDBaeDbFF011557d3C8bd2", // 50OHM - 50 DAI - "0x759281a408A48bfe2029D259c23D7E848A7EA1bC", // yCRV + "0xa6fcC7813d9D394775601aD99874c9f8e95BAd78", // Automated Pool Token - Oracle Vault 3 ] const { oVCX } = getVeAddresses(); @@ -66,6 +67,7 @@ const Vaults: NextPage = () => { const { data: oBal } = useBalance({ chainId: 1, address: account, token: oVCX, watch: true }) const [searchString, handleSearch] = useState(""); + const [sortingType, setSortingType] = useState(VAULT_SORTING_TYPE.none) useEffect(() => { async function getVaults() { @@ -173,6 +175,30 @@ const Vaults: NextPage = () => { setVaults(newVaultState) } + const sortByAscendingTvl = () => { + const sortedVaults = [...vaults].sort((a, b) => b.tvl - a.tvl); + setSortingType(VAULT_SORTING_TYPE.mostTvl) + setVaults(sortedVaults) + } + + const sortByDescendingTvl = () => { + const sortedVaults = [...vaults].sort((a, b) => a.tvl - b.tvl); + setSortingType(VAULT_SORTING_TYPE.lessTvl) + setVaults(sortedVaults) + } + + const sortByAscendingApy = () => { + const sortedVaults = [...vaults].sort((a, b) => b.apy - a.apy); + setSortingType(VAULT_SORTING_TYPE.mostvAPR) + setVaults(sortedVaults) + } + + const sortByDescendingApy = () => { + const sortedVaults = [...vaults].sort((a, b) => a.apy - b.apy); + setSortingType(VAULT_SORTING_TYPE.lessvAPR) + setVaults(sortedVaults) + } + return (
@@ -244,20 +270,24 @@ const Vaults: NextPage = () => {
-
+
chain.id)} selectNetwork={selectNetwork} /> -
- - handleSearch(e.target.value.toLowerCase())} - defaultValue={searchString} - /> +
+
+ + handleSearch(e.target.value.toLowerCase())} + defaultValue={searchString} + /> +
+
+
{(vaults.length > 0 && Object.keys(availableZapAssets).length > 0) ? vaults.filter(vault => selectedNetworks.includes(vault.chainId)).filter(vault => !HIDDEN_VAULTS.includes(vault.address)).map((vault) => { return ( diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 588b14e..5e60cd3 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -23,15 +23,33 @@ import { useAtom } from "jotai"; import { vaultsAtom } from "@/lib/atoms/vaults"; import VaultsSorting, { VAULT_SORTING_TYPE } from "@/components/vault/VaultsSorting"; -export const HIDDEN_VAULTS = ["0xb6cED1C0e5d26B815c3881038B88C829f39CE949", "0x2fD2C18f79F93eF299B20B681Ab2a61f5F28A6fF", - "0xDFf04Efb38465369fd1A2E8B40C364c22FfEA340", "0xd4D442AC311d918272911691021E6073F620eb07", //@dev for some reason the live 3Crypto yVault isnt picked up by the yearnAdapter nor the yearnFactoryAdapter - "0x8bd3D95Ec173380AD546a4Bd936B9e8eCb642de1", // Sample Stargate Vault - "0xcBb5A4a829bC086d062e4af8Eba69138aa61d567", // yOhmFrax factory - "0x9E237F8A3319b47934468e0b74F0D5219a967aB8", // yABoosted Balancer - "0x860b717B360378E44A241b23d8e8e171E0120fF0", // R/Dai - "0xBae30fBD558A35f147FDBaeDbFF011557d3C8bd2", // 50OHM - 50 DAI - "0x759281a408A48bfe2029D259c23D7E848A7EA1bC", // yCRV - "0xa6fcC7813d9D394775601aD99874c9f8e95BAd78", // Automated Pool Token - Oracle Vault 3 +const FLAGSHIP_VAULTS = [ + // eth + "0x6cE9c05E159F8C4910490D8e8F7a63e95E6CEcAF", // DAI IdleJunior + "0x52Aef3ea0D3F93766D255A1bb0aA7F1C4885E622", // USDC IdleJunior + "0x3D04Aade5388962C9A4f83B636a3a8ED63ea5b4D", // USDT IdleJunior + "0xdC266B3D2c62Ce094ff4E12DC52399c430283417", // pCVX Pirex + "0x6B2c5ef7FB59e6A1Ad79a4dB65234fb7bDDcaD6b", // oETH-LP Beefy + "0xD211486ed1A04A176E588b67dd3A30a7dE164C0B", // WETH-AURA Beefy + "0x61f313C98ebAd818442CBEE2A196720C8986Cdf4", // MIM-LP Beefy + "0xe1489Af32c45c51f94Acdb3F36B7032A82F6f55D", // WETH Sommelier + "0x759281a408A48bfe2029D259c23D7E848A7EA1bC", // yCRV Yearn + // op + "0x5Df527eb4cE7dE09f8e966F9bbc9bc4Edbc7f458", // USDT IdleSenior + "0x78C44B3A63b94d2EFc98c2Cc9701F9BEE1b6a56A", // USDT IdleJunior + "0x5372c5AF5f078f2d4B5dbBE4377b2f0225f2863A", // USDC IdleSenior + "0x4E564bC61Cf97737cE110c7929b17963E9232aE9", // USDC IdleJunior + "0x400a838eeA2ec6Daf6fA30d7Bc60505f0CecCec1", // wstETH/WETH Beefy + "0x5D45accb18A88895aCac95F13a2882C273E22e3A", // USDC/VELO Beefy + "0x740dc6c1eA74BbbadCCA0aB6253319e200c421a5", // STG/USDC Beefy + "0x48b2Bc0C40F4483EC982408F06Dc0E1e111D966b", // USDC/DOLA Beefy + "0x1F01c6bFDE973be1573AbFC1B6b1dFb1D8F22A86", // wstETH/OP Beefy + "0x0825bb2F6Ce26af1652584F1Da9e55e54015904A", // OP/USDC Beefy + // arb + "0x36EC2111A68350dBb722B872963F05992dd08E42", // Hop USDC Beefy + "0xfC2193ac4E8145E192bC3d9Db9407A4aE0Dc4DF8", // Hop DAI Beefy + "0x54d921B6397731222aB0b898bAE58c948d187Cd1", // StakedGlp Beefy + "0x1225354B00372c531e1c39ECe1cec548358926bb", // pGMX Pirex ] const { oVCX } = getVeAddresses(); @@ -289,7 +307,7 @@ const Vaults: NextPage = () => {
- {(vaults.length > 0 && Object.keys(availableZapAssets).length > 0) ? vaults.filter(vault => selectedNetworks.includes(vault.chainId)).filter(vault => !HIDDEN_VAULTS.includes(vault.address)).map((vault) => { + {(vaults.length > 0 && Object.keys(availableZapAssets).length > 0) ? vaults.filter(vault => selectedNetworks.includes(vault.chainId)).filter(vault => FLAGSHIP_VAULTS.includes(vault.address)).map((vault) => { return ( Date: Mon, 27 Nov 2023 12:59:26 +0100 Subject: [PATCH 68/84] cVCX to oVCX --- pages/stats.tsx | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/pages/stats.tsx b/pages/stats.tsx index a956524..de11c4d 100644 --- a/pages/stats.tsx +++ b/pages/stats.tsx @@ -88,7 +88,6 @@ export default function Vaults() { }[] totalRevenue: number cPopRevenue: number - publicGoodFunding: number weekCexVolume: number weekDexVolume: number walletsPopMoreZero: number @@ -122,7 +121,6 @@ export default function Vaults() { tvlMonthByMonth: [], totalRevenue: 0, cPopRevenue: 0, - publicGoodFunding: 0, weekCexVolume: 0, weekDexVolume: 0, walletsPopMoreZero: 0, @@ -496,11 +494,11 @@ export default function Vaults() {

Coming Soon {/*statistics.vePop.toLocaleString()*/}

-

cVCX emissions

+

oVCX emissions

Coming Soon {/*statistics.cPopEmissions.toLocaleString()*/}

-

cVCX exercised

+

oVCX exercised

Coming Soon {/*(statistics.cPopExercised * 100).toLocaleString() %*/}

@@ -541,17 +539,13 @@ export default function Vaults() {

Coming Soon

-

cVCX Revenue

+

oVCX Revenue

Coming Soon {/*statistics.cPopRevenue.toLocaleString()*/}

Total Users

{statistics.walletsPopMoreZero.toLocaleString()}

-
-

Public Good Funding

-

${statistics.publicGoodFunding.toLocaleString()}

-

7 Day Cex Volume

${statistics.weekCexVolume.toLocaleString()}

From 0543fc06a755cb227a896139d22616f4f6ca3934 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Mon, 27 Nov 2023 13:28:46 +0100 Subject: [PATCH 69/84] update sdk to minor 17 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 077b127..fb5e999 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "slick-carousel": "^1.8.1", "tailwind-scrollbar-hide": "^1.1.7", "tailwindcss": "^3.2.6", - "vaultcraft-sdk": "0.1.16", + "vaultcraft-sdk": "0.1.17", "viem": "1.18.9", "wagmi": "1.4.5" }, diff --git a/yarn.lock b/yarn.lock index d072e88..a3ccb4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5294,10 +5294,10 @@ valtio@1.11.2: proxy-compare "2.5.1" use-sync-external-store "1.2.0" -vaultcraft-sdk@0.1.16: - version "0.1.16" - resolved "https://registry.yarnpkg.com/vaultcraft-sdk/-/vaultcraft-sdk-0.1.16.tgz#10e3d450a71f475b56b9d2eed6aff0fb67e8aa0e" - integrity sha512-JeZg49XSMz4DkqTXBsgzWo+XcheZ6I94LMT1mKYY6VXkPQ24Nocipt5FnV8J/1c+8BkW1dJ535L9QwGcnBkn0Q== +vaultcraft-sdk@0.1.17: + version "0.1.17" + resolved "https://registry.yarnpkg.com/vaultcraft-sdk/-/vaultcraft-sdk-0.1.17.tgz#5419bceedab0ab35c26d72b50cc04f32df3feb18" + integrity sha512-oN/RTWmMXENqfRrMsMdVu/nm4iD7kRMvbsKxSyCcfgm1vG0yAsr/1ZyV3NLxUIVFQ078tKV+PvDwVIuzup6ofg== dependencies: "@curvefi/api" "2.44.0" axios "^1.5.0" From 11cd6a13000b1b62f5eac41e22e7e4663d387a4a Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 28 Nov 2023 12:21:15 +0100 Subject: [PATCH 70/84] added zap assets for op --- lib/constants/assets.ts | 476 +++++++++++++++++++++++++++++++------- lib/vault/getAssetIcon.ts | 9 +- 2 files changed, 398 insertions(+), 87 deletions(-) diff --git a/lib/constants/assets.ts b/lib/constants/assets.ts index 079d65d..522ca60 100644 --- a/lib/constants/assets.ts +++ b/lib/constants/assets.ts @@ -1,11 +1,12 @@ -import { TokenConstant } from "../types"; +import { Asset } from "../types"; -const assets: TokenConstant[] = [ +const assets: Asset[] = [ { - "chains": [1, 1337, 42161], + "chains": [1, 1337, 10, 42161], "address": { "1": "0x6B175474E89094C44Da98b954EedeAC495271d0F", "1337": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "10": "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1", "42161": "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1" }, "name": "Dai Stablecoin", @@ -14,11 +15,12 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/DAI.png" }, { - "chains": [1, 1337, 42161, 137], + "chains": [1, 1337, 10, 42161, 137], "address": { "1": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "1337": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "42161": "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", + "10": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85", "137": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174" }, "name": "USD Coin", @@ -27,10 +29,11 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/USDC.png" }, { - "chains": [1, 1337, 42161], + "chains": [1, 1337, 10, 42161], "address": { "1": "0xdAC17F958D2ee523a2206206994597C13D831ec7", "1337": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "10": "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58", "42161": "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8" }, "name": "Tether USD", @@ -51,19 +54,20 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/FRAX.png" }, { - "chains": [1, 1337, 42161], + "chains": [1, 1337, 10, 42161], "address": { "1": "0x5f98805A4E8be255a32880FDeC7F6728C6568bA0", "1337": "0x5f98805A4E8be255a32880FDeC7F6728C6568bA0", + "10": "0xc40F949F8a4e094D1b49a23ea9241D289B7b2819", "42161": "0x93b346b6BC2548dA6A1E7d98E9a421B42541425b" }, - "name": "LUSD Stablecoin", + "name": "LUSD", "symbol": "LUSD", "decimals": 18, "logoURI": "https://cdn.furucombo.app/assets/img/token/LUSD.png" }, { - "chains": [1], + "chains": [], "address": { "1": "0x99D8a9C45b2ecA8864373A26D1459e3Dff1e17F3", "1337": "0x99D8a9C45b2ecA8864373A26D1459e3Dff1e17F3", @@ -75,21 +79,11 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/MIM.png" }, { - "chains": [1, 1337], - "address": { - "1": "0x57Ab1ec28D129707052df4dF418D58a2D46d5f51", - "1337": "0x57Ab1ec28D129707052df4dF418D58a2D46d5f51" - }, - "name": "Synth USD", - "symbol": "sUSD", - "decimals": 18, - "logoURI": "https://etherscan.io/token/images/SynthetixsUSD_32.png" - }, - { - "chains": [1, 1337, 42161], + "chains": [1, 1337, 10, 42161], "address": { "1": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", "1337": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "10": "0x68f180fcCe6836688e9084f035309E29Bf0A2095", "42161": "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f" }, "name": "Wrapped BTC", @@ -98,10 +92,11 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/WBTC.png" }, { - "chains": [1, 1337, 42161], + "chains": [1, 1337, 10, 42161], "address": { "1": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "1337": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "10": "0x4200000000000000000000000000000000000006", "42161": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1" }, "name": "Wrapped Ether", @@ -110,18 +105,18 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/WETH.svg" }, { - "chains": [1, 1337], + "chains": [], "address": { - "1": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84", - "1337": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84" + "1": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0", + "1337": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0" }, - "name": "Staked Ether", - "symbol": "stETH", + "name": "Matic Token", + "symbol": "MATIC", "decimals": 18, - "logoURI": "https://cdn.furucombo.app/assets/img/token/stETH.svg" + "logoURI": "https://cdn.furucombo.app/assets/img/token/MATIC.png" }, { - "chains": [1], + "chains": [], "address": { "1": "0x383518188C0C6d7730D91b2c03a03C837814a899", "1337": "0x383518188C0C6d7730D91b2c03a03C837814a899" @@ -131,50 +126,6 @@ const assets: TokenConstant[] = [ "decimals": 9, "logoURI": "https://cdn.furucombo.app/assets/img/token/OHM.png" }, - { - "chains": [1, 1337], - "address": { - "1": "0x2a8e1e676ec238d8a992307b495b45b3feaa5e86", - "1337": "0x2a8e1e676ec238d8a992307b495b45b3feaa5e86" - }, - "name": "Origin Dollar", - "symbol": "oUSD", - "decimals": 18, - "logoURI": "https://icons.llamao.fi/icons/protocols/origin-dollar" - }, - { - "chains": [1, 1337], - "address": { - "1": "0x856c4efb76c1d1ae02e20ceb03a2a6a08b0b8dc3", - "1337": "0x856c4efb76c1d1ae02e20ceb03a2a6a08b0b8dc3" - }, - "name": "Origin Ether", - "symbol": "oETH", - "decimals": 18, - "logoURI": "https://icons.llamao.fi/icons/protocols/origin-ether" - }, - { - "chains": [1, 1337], - "address": { - "1": "0xD533a949740bb3306d119CC777fa900bA034cd52", - "1337": "0xD533a949740bb3306d119CC777fa900bA034cd52" - }, - "name": "Curve", - "symbol": "CRV", - "decimals": 18, - "logoURI": "https://etherscan.io/token/images/Curvefi_32.png" - }, - { - "chains": [1, 1337], - "address": { - "1": "0xba100000625a3754423978a60c9317c58a424e3D", - "1337": "0xba100000625a3754423978a60c9317c58a424e3D" - }, - "name": "Balancer", - "symbol": "BAL", - "decimals": 18, - "logoURI": "https://etherscan.io/token/images/Balancer_32.png" - }, { "chains": [1, 1337], "address": { @@ -211,7 +162,7 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/USDT.png" }, { - "chains": [1], + "chains": [], "address": { "1": "0xfA0F307783AC21C39E939ACFF795e27b650F6e68", "1337": "0xfA0F307783AC21C39E939ACFF795e27b650F6e68", @@ -223,7 +174,7 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/FRAX.png" }, { - "chains": [1], + "chains": [], "address": { "1": "0xE8F55368C82D38bbbbDb5533e7F56AfC2E978CC2", "1337": "0xE8F55368C82D38bbbbDb5533e7F56AfC2E978CC2", @@ -235,7 +186,7 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/LUSD.png" }, { - "chains": [], + "chains": [42161], "address": { "42161": "0x68f5d998F00bB2460511021741D098c05721d8fF" }, @@ -245,7 +196,7 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/DAI.png" }, { - "chains": [], + "chains": [42161], "address": { "42161": "0xB67c014FA700E69681a673876eb8BAFAA36BFf71" }, @@ -276,15 +227,58 @@ const assets: TokenConstant[] = [ "logoURI": "https://cdn.furucombo.app/assets/img/token/WETH.svg" }, { - "chains": [], + "chains": [1, 1337], "address": { - "1": "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0", - "1337": "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0" + "1": "0x2a8e1e676ec238d8a992307b495b45b3feaa5e86", + "1337": "0x2a8e1e676ec238d8a992307b495b45b3feaa5e86" }, - "name": "Matic", + "name": "Origin Dollar", + "symbol": "oUSD", + "decimals": 18, + "logoURI": "https://icons.llamao.fi/icons/protocols/origin-dollar" + }, + { + "chains": [1, 1337], + "address": { + "1": "0x856c4efb76c1d1ae02e20ceb03a2a6a08b0b8dc3", + "1337": "0x856c4efb76c1d1ae02e20ceb03a2a6a08b0b8dc3" + }, + "name": "Origin Ether", "symbol": "oETH", "decimals": 18, - "logoURI": "https://icons.llamao.fi/icons/chains/rsz_polygon" + "logoURI": "/images/tokens/oEth.png" + }, + { + "chains": [1, 1337], + "address": { + "1": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84", + "1337": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84" + }, + "name": "Staked Ether", + "symbol": "stETH", + "decimals": 18, + "logoURI": "https://cdn.furucombo.app/assets/img/token/stETH.svg" + }, + { + "chains": [1, 1337], + "address": { + "1": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0", + "1337": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0" + }, + "name": "Wrapped Staked Ether", + "symbol": "wstETH", + "decimals": 18, + "logoURI": "https://cdn.furucombo.app/assets/img/token/stETH.svg" + }, + { + "chains": [1], + "address": { + "1": "0x514910771AF9Ca656af840dff83E8264EcF986CA" + }, + "name": "Chainlink", + "symbol": "LINK", + "decimals": 18, + "logoURI": "https://etherscan.io/token/images/chainlinktoken_32.png?v=6" }, { "chains": [1, 1337], @@ -292,10 +286,328 @@ const assets: TokenConstant[] = [ "1": "0x76FCf0e8C7Ff37A47a799FA2cd4c13cDe0D981C9", "1337": "0x76FCf0e8C7Ff37A47a799FA2cd4c13cDe0D981C9" }, - "name": "OHM / DAI LP ", + "name": "OHM / DAI LP", "symbol": "b-ohm-dai-lp", "decimals": 18, "logoURI": "https://cdn.furucombo.app/assets/img/token/OHM.png" + }, + { + "chains": [1, 1337], + "address": { + "1": "0xFCc5c47bE19d06BF83eB04298b026F81069ff65b", + "1337": "0xFCc5c47bE19d06BF83eB04298b026F81069ff65b" + }, + "name": "yCRV", + "symbol": "yCRV", + "decimals": 18, + "logoURI": "https://etherscan.io/token/images/yearncrvnew_32.png" + }, + { + "chains": [1], + "address": { + "1": "0x3175df0976dfa876431c2e9ee6bc45b65d3473cc" + }, + "name": "FRAX / USDC LP", + "symbol": "crvFRAX", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, { + "chains": [1], + "address": { + "1": "0x06325440d014e39736583c165c2963ba99faf14e" + }, + "name": "ETH / stETH LP", + "symbol": "steCRV", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, { + "chains": [1], + "address": { + "1": "0x6c3f90f043a72fa612cbac8115ee7e52bde6e490" + }, + "name": "3Pool", + "symbol": "3CRV", + "decimals": 18, + "logoURI": "https://etherscan.io/token/images/3pool_32.png" + }, { + "chains": [1], + "address": { + "1": "0xf43211935c781d5ca1a41d2041f397b8a7366c7a" + }, + "name": "ETH / frxETH LP ", + "symbol": "crvFrxETH", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0xc4ad29ba4b3c580e6d59105fff484999997675ff" + }, + "name": "TryCripto2", + "symbol": "crv3crypto", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x94b17476a93b3262d87b9a326965d1e91f9c13e7" + }, + "name": "ETH / OETH LP", + "symbol": "crvOETH", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x21e27a5e5513d6e65c4f830167390997aa84843a" + }, + "name": "stETH-ng", + "symbol": "crvStETH-ng", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0xb30da2376f63de30b42dc055c93fa474f31330a5" + }, + "name": "alUSDFRAXBP", + "symbol": "alUSD FRAX USDC", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x4dece678ceceb27446b35c672dc7d61f30bad69e" + }, + "name": "crvUSD/USDC", + "symbol": "USDC crvUSD", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x390f3595bca2df7d23783dfd126427cceb997bf4" + }, + "name": "crvUSD/USDT", + "symbol": "USDT crvUSD", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0xf5f5b97624542d72a9e06f04804bf81baa15e2b4" + }, + "name": "TricryptoUSDT", + "symbol": "USDT WBTC ETH", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x7f86bf177dd4f3494b841a37e810a34dd56c829b" + }, + "name": "TricryptoUSDC", + "symbol": "USDC WBTC ETH", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x971add32ea87f10bd192671630be3be8a11b8623" + }, + "name": "cvxCrv/Crv", + "symbol": "CRV cvxCRV", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x4704ab1fb693ce163f7c9d3a31b3ff4eaf797714" + }, + "name": "FPI2Pool", + "symbol": "FRAX FPI", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x5a6a4d54456819380173272a5e8e9b9904bdf41b" + }, + "name": "mim", + "symbol": "MIM DAI USDC USDT", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0xc9c32cd16bf7efb85ff14e0c8603cc90f6f2ee49" + }, + "name": "Bean", + "symbol": "BEAN DAI USDC USDT", + "decimals": 18, + "logoURI": "https://etherscan.io/token/images/bean3crv_32.png" + }, + { + "chains": [1], + "address": { + "1": "0xed279fdd11ca84beef15af5d39bb4d4bee23f0ca" + }, + "name": "lusd", + "symbol": "LUSD DAI USDC USDT", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0xc25a3a3b969415c80451098fa907ec722572917f" + }, + "name": "susd", + "symbol": "DAI USDC USDT sUSD", + "decimals": 18, + "logoURI": "https://etherscan.io/token/images/Curvefi_sCrv_32.png" + }, + { + "chains": [1], + "address": { + "1": "0xfd2a8fa60abd58efe3eee34dd494cd491dc14900" + }, + "name": "aave", + "symbol": "DAI USDC USDT", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0xe57180685e3348589e9521aa53af0bcd497e884d" + }, + "name": "DOLA/FRAXBP", + "symbol": "DOLA FRAX USDC", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x43b4fdfd4ff969587185cdb6f0bd875c5fc83f8c" + }, + "name": "alusd", + "symbol": "alUSD DAI USDC USDT", + "decimals": 18, + "logoURI": "/images/icons/curve-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x5c6Ee304399DBdB9C8Ef030aB642B10820DB8F56" + }, + "name": "Bal 80 Eth 20", + "symbol": "BAL WETH", + "decimals": 18, + "logoURI": "/images/icons/balancer-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x1E19CF2D73a72Ef1332C882F20534B6519Be0276" + }, + "name": "rETH wETH", + "symbol": "rETH WETH", + "decimals": 18, + "logoURI": "/images/icons/balancer-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x20a61B948E33879ce7F23e535CC7BAA3BC66c5a9" + }, + "name": "R DAI", + "symbol": "R DAI", + "decimals": 18, + "logoURI": "/images/icons/balancer-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x42ED016F826165C2e5976fe5bC3df540C5aD0Af7" + }, + "name": "wstETH sfrxETH rETH", + "symbol": "wstETH sfrxETH rETH", + "decimals": 18, + "logoURI": "/images/icons/balancer-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x1ee442b5326009Bb18F2F472d3e0061513d1A0fF" + }, + "name": "BADGER 50 rETH 50", + "symbol": "BADGER rETH", + "decimals": 18, + "logoURI": "/images/icons/balancer-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x87a867f5D240a782d43D90b6B06DEa470F3f8F22" + }, + "name": "wstETH 50 COMP 50", + "symbol": "wstETH COMP", + "decimals": 18, + "logoURI": "/images/icons/balancer-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x3ff3a210e57cFe679D9AD1e9bA6453A716C56a2e" + }, + "name": "USDC 50 STG 50", + "symbol": "USDC STG", + "decimals": 18, + "logoURI": "/images/icons/balancer-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x3dd0843A028C86e0b760b1A76929d1C5Ef93a2dd" + }, + "name": "AuraBAL Stable Pool", + "symbol": "B-80BAL-20WETH auraBAL", + "decimals": 18, + "logoURI": "/images/icons/balancer-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0xE7e2c68d3b13d905BBb636709cF4DfD21076b9D2" + }, + "name": "WETH swETH", + "symbol": "WETH swETH", + "decimals": 18, + "logoURI": "/images/icons/balancer-lp.png" + }, + { + "chains": [1], + "address": { + "1": "0x32296969Ef14EB0c6d29669C550D4a0449130230" + }, + "name": "wstETH WETH", + "symbol": "wstETH WETH", + "decimals": 18, + "logoURI": "/images/icons/balancer-lp.png" } ] export default assets; \ No newline at end of file diff --git a/lib/vault/getAssetIcon.ts b/lib/vault/getAssetIcon.ts index eac6c56..3b4c13f 100644 --- a/lib/vault/getAssetIcon.ts +++ b/lib/vault/getAssetIcon.ts @@ -69,18 +69,17 @@ function getProtocolIcon(asset: Token, adapter: Token, chainId: number): string // TODO fill this with curve lp icon return undefined; } - else if (adapter?.name?.includes("Stargate") || asset?.name?.includes("STG") || asset?.symbol?.includes("STG") || asset?.symbol?.includes("S*")) { + else if (adapter?.name?.includes("Velodrome") || asset?.symbol?.includes("vAMM")) { // TODO fill this with curve lp icon + return "/images/tokens/velodrome-lp.svg"; + } + else if (adapter?.name?.includes("Stargate") || asset?.name?.includes("STG") || asset?.symbol?.includes("STG") || asset?.symbol?.includes("S*")) { return getIconFromTokenListBySymbol(asset?.symbol?.includes("*") ? asset?.symbol?.split("*")[1] : asset?.symbol?.split(" ")[1], chainId); } else if (adapter?.name?.includes("Sushi")) { // TODO fill this with curve lp icon return undefined; } - else if (adapter?.name?.includes("Velodrome")) { - // TODO fill this with curve lp icon - return "/images/tokens/velodrome-lp.svg"; - } else if (adapter?.name?.includes("Yearn")) { // TODO fill this with curve lp icon return undefined; From d9540b6c90ee3ed3a4be37ad066d93e5b6e586ad Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 28 Nov 2023 16:38:58 +0100 Subject: [PATCH 71/84] fixed typing issue --- pages/stats.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/stats.tsx b/pages/stats.tsx index de11c4d..6ff8e31 100644 --- a/pages/stats.tsx +++ b/pages/stats.tsx @@ -471,7 +471,7 @@ export default function Vaults() {
Logo
-

VCXCORN

+

VCX

Liquid VCX market (Mainnet only)

From 407f8ab7066e03b24fd4941a8b9f3adaef1266cb Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 28 Nov 2023 16:43:17 +0100 Subject: [PATCH 72/84] added bridged usdc to op --- lib/constants/assets.ts | 12 +++++++++++- lib/types.ts | 10 +++++++++- lib/utils/getZapAssets.ts | 6 +++--- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/constants/assets.ts b/lib/constants/assets.ts index 522ca60..e5417ae 100644 --- a/lib/constants/assets.ts +++ b/lib/constants/assets.ts @@ -1,4 +1,4 @@ -import { Asset } from "../types"; +import { Asset } from "@/lib/types"; const assets: Asset[] = [ { @@ -28,6 +28,16 @@ const assets: Asset[] = [ "decimals": 6, "logoURI": "https://cdn.furucombo.app/assets/img/token/USDC.png" }, + { + "chains": [10], + "address": { + "10": "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", + }, + "name": "USD Coin Bridged", + "symbol": "USDC.e", + "decimals": 6, + "logoURI": "https://cdn.furucombo.app/assets/img/token/USDC.png" + }, { "chains": [1, 1337, 10, 42161], "address": { diff --git a/lib/types.ts b/lib/types.ts index 53670a3..b25aceb 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -33,7 +33,15 @@ export type veAddresses = { FeeDistributor: Address; }; - +export type Asset = { + chains: number[]; + address: { [key: string]: Address }; + name: string; + symbol: string; + decimals: number; + logoURI: string; + apy?: number; +}; export type TokenConstant = { chains: number[]; diff --git a/lib/utils/getZapAssets.ts b/lib/utils/getZapAssets.ts index f60e38e..4da6351 100644 --- a/lib/utils/getZapAssets.ts +++ b/lib/utils/getZapAssets.ts @@ -5,7 +5,7 @@ import axios from "axios"; import { RPC_URLS, networkMap } from "@/lib/utils/connectors"; import { ERC20Abi } from "@/lib/constants"; -const symbolsToSelect = ["DAI", "USDC", "USDT", "LUSD", "WETH", "WBTC"] +const symbolsToSelect = ["DAI", "USDC", "USDC.e", "USDT", "LUSD", "WETH", "WBTC"] export default async function getZapAssets({ chain, account }: { chain: Chain, account?: Address }): Promise { const selected = assets.filter(asset => asset.chains.includes(chain.id)).filter(asset => symbolsToSelect.includes(asset.symbol)) @@ -47,8 +47,8 @@ export default async function getZapAssets({ chain, account }: { chain: Chain, a export async function getAvailableZapAssets(chainId: number) { const defiTokens = (await axios.get('https://enso-scrape.s3.us-east-2.amazonaws.com/output/backend/defiTokens.json')).data - .filter((entry: any) => entry.chainId === chainId).map((entry: any) => getAddress(entry.tokenAddress)) + .filter((entry: any) => entry.chainId === chainId).map((entry: any) => getAddress(entry.tokenAddress)) const baseTokens = (await axios.get('https://enso-scrape.s3.us-east-2.amazonaws.com/output/backend/baseTokens.json')).data - .filter((entry: any) => entry.chainId === chainId).map((entry: any) => getAddress(entry.address)) + .filter((entry: any) => entry.chainId === chainId).map((entry: any) => getAddress(entry.address)) return [...baseTokens, ...defiTokens] } \ No newline at end of file From 4e1bdb87d6caa48a9ce19403594a6cda3280fc2b Mon Sep 17 00:00:00 2001 From: RedVeil Date: Tue, 28 Nov 2023 17:12:44 +0100 Subject: [PATCH 73/84] removed hop arb vaults --- pages/vaults.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 5e60cd3..042331c 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -46,8 +46,6 @@ const FLAGSHIP_VAULTS = [ "0x1F01c6bFDE973be1573AbFC1B6b1dFb1D8F22A86", // wstETH/OP Beefy "0x0825bb2F6Ce26af1652584F1Da9e55e54015904A", // OP/USDC Beefy // arb - "0x36EC2111A68350dBb722B872963F05992dd08E42", // Hop USDC Beefy - "0xfC2193ac4E8145E192bC3d9Db9407A4aE0Dc4DF8", // Hop DAI Beefy "0x54d921B6397731222aB0b898bAE58c948d187Cd1", // StakedGlp Beefy "0x1225354B00372c531e1c39ECe1cec548358926bb", // pGMX Pirex ] From c67b97f67738938f7d987ce89c0d39f73b90fa20 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 29 Nov 2023 12:45:09 +0100 Subject: [PATCH 74/84] removed FeeDistributor --- lib/utils/addresses/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/utils/addresses/index.ts b/lib/utils/addresses/index.ts index 42feb2d..33e6837 100644 --- a/lib/utils/addresses/index.ts +++ b/lib/utils/addresses/index.ts @@ -18,8 +18,7 @@ const VeAddresses = { GaugeFactory: "0x32a33CC9dC61352E70cb557927E5F9544ddb0a26", SmartWalletChecker: "0x8427155770f7e6b973249E2f9D140a495aBE4f90", VotingEscrowDelegation: "0x9B12C90BAd388B7e417271eb20678D1a7759507c", - VaultRouter: "0x8aed8Ea73044910760E8957B6c5b28Ac51f8f809", - FeeDistributor: "0x2661cdddb673DDcF2e0bc0dD7Fd432fCF1fe9e74" + VaultRouter: "0x8aed8Ea73044910760E8957B6c5b28Ac51f8f809" }; export function getVeAddresses(): veAddresses { From fd292aa43a8de9dcfe98e1e39378170bf77048c0 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 29 Nov 2023 13:05:09 +0100 Subject: [PATCH 75/84] fixed some token icons, removed bsc as supported network --- lib/constants/assets.ts | 56 +++++++++++++++++----------------- lib/constants/index.ts | 8 ++--- lib/utils/connectors.ts | 2 +- public/images/tokens/oEth.png | Bin 0 -> 2026 bytes 4 files changed, 33 insertions(+), 33 deletions(-) create mode 100644 public/images/tokens/oEth.png diff --git a/lib/constants/assets.ts b/lib/constants/assets.ts index e5417ae..75c94f7 100644 --- a/lib/constants/assets.ts +++ b/lib/constants/assets.ts @@ -320,7 +320,7 @@ const assets: Asset[] = [ "name": "FRAX / USDC LP", "symbol": "crvFRAX", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], "address": { @@ -329,7 +329,7 @@ const assets: Asset[] = [ "name": "ETH / stETH LP", "symbol": "steCRV", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], "address": { @@ -347,7 +347,7 @@ const assets: Asset[] = [ "name": "ETH / frxETH LP ", "symbol": "crvFrxETH", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -357,7 +357,7 @@ const assets: Asset[] = [ "name": "TryCripto2", "symbol": "crv3crypto", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -367,7 +367,7 @@ const assets: Asset[] = [ "name": "ETH / OETH LP", "symbol": "crvOETH", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -377,7 +377,7 @@ const assets: Asset[] = [ "name": "stETH-ng", "symbol": "crvStETH-ng", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -387,7 +387,7 @@ const assets: Asset[] = [ "name": "alUSDFRAXBP", "symbol": "alUSD FRAX USDC", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -397,7 +397,7 @@ const assets: Asset[] = [ "name": "crvUSD/USDC", "symbol": "USDC crvUSD", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -407,7 +407,7 @@ const assets: Asset[] = [ "name": "crvUSD/USDT", "symbol": "USDT crvUSD", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -417,7 +417,7 @@ const assets: Asset[] = [ "name": "TricryptoUSDT", "symbol": "USDT WBTC ETH", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -427,7 +427,7 @@ const assets: Asset[] = [ "name": "TricryptoUSDC", "symbol": "USDC WBTC ETH", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -437,7 +437,7 @@ const assets: Asset[] = [ "name": "cvxCrv/Crv", "symbol": "CRV cvxCRV", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -447,7 +447,7 @@ const assets: Asset[] = [ "name": "FPI2Pool", "symbol": "FRAX FPI", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -457,7 +457,7 @@ const assets: Asset[] = [ "name": "mim", "symbol": "MIM DAI USDC USDT", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -477,7 +477,7 @@ const assets: Asset[] = [ "name": "lusd", "symbol": "LUSD DAI USDC USDT", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -497,7 +497,7 @@ const assets: Asset[] = [ "name": "aave", "symbol": "DAI USDC USDT", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -507,7 +507,7 @@ const assets: Asset[] = [ "name": "DOLA/FRAXBP", "symbol": "DOLA FRAX USDC", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -517,7 +517,7 @@ const assets: Asset[] = [ "name": "alusd", "symbol": "alUSD DAI USDC USDT", "decimals": 18, - "logoURI": "/images/icons/curve-lp.png" + "logoURI": "/images/tokens/curve-lp.png" }, { "chains": [1], @@ -527,7 +527,7 @@ const assets: Asset[] = [ "name": "Bal 80 Eth 20", "symbol": "BAL WETH", "decimals": 18, - "logoURI": "/images/icons/balancer-lp.png" + "logoURI": "/images/tokens/balancer-lp.png" }, { "chains": [1], @@ -537,7 +537,7 @@ const assets: Asset[] = [ "name": "rETH wETH", "symbol": "rETH WETH", "decimals": 18, - "logoURI": "/images/icons/balancer-lp.png" + "logoURI": "/images/tokens/balancer-lp.png" }, { "chains": [1], @@ -547,7 +547,7 @@ const assets: Asset[] = [ "name": "R DAI", "symbol": "R DAI", "decimals": 18, - "logoURI": "/images/icons/balancer-lp.png" + "logoURI": "/images/tokens/balancer-lp.png" }, { "chains": [1], @@ -557,7 +557,7 @@ const assets: Asset[] = [ "name": "wstETH sfrxETH rETH", "symbol": "wstETH sfrxETH rETH", "decimals": 18, - "logoURI": "/images/icons/balancer-lp.png" + "logoURI": "/images/tokens/balancer-lp.png" }, { "chains": [1], @@ -567,7 +567,7 @@ const assets: Asset[] = [ "name": "BADGER 50 rETH 50", "symbol": "BADGER rETH", "decimals": 18, - "logoURI": "/images/icons/balancer-lp.png" + "logoURI": "/images/tokens/balancer-lp.png" }, { "chains": [1], @@ -577,7 +577,7 @@ const assets: Asset[] = [ "name": "wstETH 50 COMP 50", "symbol": "wstETH COMP", "decimals": 18, - "logoURI": "/images/icons/balancer-lp.png" + "logoURI": "/images/tokens/balancer-lp.png" }, { "chains": [1], @@ -587,7 +587,7 @@ const assets: Asset[] = [ "name": "USDC 50 STG 50", "symbol": "USDC STG", "decimals": 18, - "logoURI": "/images/icons/balancer-lp.png" + "logoURI": "/images/tokens/balancer-lp.png" }, { "chains": [1], @@ -597,7 +597,7 @@ const assets: Asset[] = [ "name": "AuraBAL Stable Pool", "symbol": "B-80BAL-20WETH auraBAL", "decimals": 18, - "logoURI": "/images/icons/balancer-lp.png" + "logoURI": "/images/tokens/balancer-lp.png" }, { "chains": [1], @@ -607,7 +607,7 @@ const assets: Asset[] = [ "name": "WETH swETH", "symbol": "WETH swETH", "decimals": 18, - "logoURI": "/images/icons/balancer-lp.png" + "logoURI": "/images/tokens/balancer-lp.png" }, { "chains": [1], @@ -617,7 +617,7 @@ const assets: Asset[] = [ "name": "wstETH WETH", "symbol": "wstETH WETH", "decimals": 18, - "logoURI": "/images/icons/balancer-lp.png" + "logoURI": "/images/tokens/balancer-lp.png" } ] export default assets; \ No newline at end of file diff --git a/lib/constants/index.ts b/lib/constants/index.ts index d0019bb..575e6f3 100644 --- a/lib/constants/index.ts +++ b/lib/constants/index.ts @@ -1,7 +1,7 @@ export * from "./abi"; import assets from "@/lib/constants/assets"; import { Token } from "../types"; -import { Address } from "viem"; +import { Address, maxInt256, maxUint256, zeroAddress } from "viem"; export function getAssetsByChain(chainId: number): Token[] { return assets.filter((asset) => asset.chains.includes(chainId)).map((asset) => { @@ -34,9 +34,9 @@ export const PopStakingByChain: { [key: number]: Address } = { 10: "0x3Fcc4eA703054453D8697b58C5CB2585F8883C05" } -export const ADDRESS_ZERO: Address = "0x0000000000000000000000000000000000000000" -export const MAX_INT256 = BigInt(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) -export const MAX_UINT256 = BigInt(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) +export const ADDRESS_ZERO = zeroAddress +export const MAX_INT256 = maxInt256 +export const MAX_UINT256 = maxUint256 export const MINUS_ONE = BigInt(-0x01) export const ZERO = BigInt(0) export const ROUNDING_VALUE = 10_000; \ No newline at end of file diff --git a/lib/utils/connectors.ts b/lib/utils/connectors.ts index d6abe8a..87c973e 100644 --- a/lib/utils/connectors.ts +++ b/lib/utils/connectors.ts @@ -91,4 +91,4 @@ export const RPC_URLS: { [key: number]: string } = { [ChainId.RemoteFork]: `http://localhost:8545`, }; -export const SUPPORTED_NETWORKS = [mainnet, polygon, optimism, arbitrum, bsc, localhost] \ No newline at end of file +export const SUPPORTED_NETWORKS = [mainnet, polygon, optimism, arbitrum] \ No newline at end of file diff --git a/public/images/tokens/oEth.png b/public/images/tokens/oEth.png new file mode 100644 index 0000000000000000000000000000000000000000..1a707f572c926f7f73f3e02188c90b1b1f69f06c GIT binary patch literal 2026 zcmVD1flm5yI%9@+In8pwG_v`Ze6cGv*qJTJRoS=E>zl%hZg=0W36?cl-Di#46RC?387RY7BrcdWc z#Qw&hbiw+R6N0mXG$z)j&jwJ_{E(5o)tA;Na7B9qsoe_Yz5J#cHffRTA$E30Z6!Og z2lm3AQIJ}9mIawffy>_FOY1Jc=^M2FR-*pJj}ENv#GcsOkOPHGs7ykWP&wWTk=SyY zhXyQB9*gGeG>N^Rof-3O4YD1<^;x8h(tS>fO^!HQfL7lcvRtJ%SE}^d3Y7+Zuh6@z zRT@?r|4bsF0BL9vvimJoM%#iL#$nI2P;CW=35N#AdYdzlk2ZK|<-rjBdRC)d=QPT$ z^b>=VyAX|g|qG<>oZGsfT&8w%=@FPGN^mq?Ri%Dwd0wJ=?O zNObNt(Xksur3XSZxJ03A4oJvA33oERYZ zuXDakIluVH!y57hiSDXISMC#?x<&NPDwXnf`s;x+2G(G$lO{7}>84K2lY%4GsO@3^ zdo7R)t!$rYj#=-eh^7m~rxGAKQXQdhcKGSNH7Z@W8xcUh{@F(*`vdi~i8W3j!ISVq z1SnHcp#V2&N1zq*WJBP3FO=z?SBnV?vF!Cnf;6;L6>q=wM38DE{r*oUgW}q-GKDrA ztrgE&HThw=y}1XnuOj0>UK_>)Y_9%`l`JH4NAt389H|b+garBPXPdn=AZi)}!Yu|@ zBSm7G8e8Fw`Rqj2s1+o95`j}Uy73!nQRHkcMg}ZVvs{@)vfJ6b9vZ|8P2CYK+7}Sl zQ6LOiuF#+VhN1w?r~bYk7C~bO-*7Y-XKuWp9YC1bC@?a)RCA%8bJ8CCp~ABHg*y>y zGs7&i+`9vUQfkCB0pi<&KLWyR!rbf%R-fE;E|id8Q3YXtU~{3cbkZRECtZ19Zaj@6 z)ksf>x=S1whIy+QK*;n2;cvssOtLOHP#e34H6U|4Uqq>wecmjaOLs2b!foETn5>ixc5T6 zuKQ}6pAK9J3y=mt%!{nu!aV`{V4auVkDAhIVjr7$#9GxBV5g{w*;-){Bu*Mk6eP@3 zw3P{Y?r#C&`jO^U1?ceg2wlDxp`zad!tYA<*V4vgL3(AGE*QVfAc-)^ClMq%%{cR5 z9L?M{Y3BL4GD!hVfP(o%Wx|E%TU>e_W*$7xl=S)!`t{+Z@rA@r2bxK<(oE)j#qFfQ zl&HU1iMm)2wSFIdgv^5b2d{=ji3Jm1eW1}B3=}~Hp%usCiF$lOqLwX0&Dd}NZ;{(j zs`Jp{I;n2N8gG2S4u2=v_ zXcFdTU!hC)A~AsbE{BAV!hhk9wROllVX?5(EEZaeVj7a%(h~TVboMqdtki znam{@v;=?DeNJVd5xUQT8wlyoV(pX$$}J;H^)kvW474=#u7NW^ECfiaCanWkKiTNx zD3qCcG!7EtOarYE-BC2LmT8R!E^#VYB?6YQ6~6Sisv2c>!vIb4hELXo2|j!#PojdV zAXhU)r)!{5qTT1i&`4~32e(weYfxak&y;QkF=mB{m>-(In~1w^=;S(M%!(c$lOLJ3&HT*Z2cN& zg_FDp9JBLfzaE-o7NK^QV`rbm4fJdDevC8iJkH4nBt0;4JPjY*F|sSYY29M2kN*Rt zu4Tx~PNwyNQMkvK8tubE> z1#vBnCp9K-_qRr+fpe?*H-ud8ZwTDWEK=O4m?m;j(iB<$0We}+lOk+mvH$=807*qo IM6N<$f~^;}761SM literal 0 HcmV?d00001 From 0129531703ae43d4262fbb3d13026e405445be9c Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 29 Nov 2023 13:40:59 +0100 Subject: [PATCH 76/84] fixed usdt approval --- lib/approve.ts | 6 +- lib/constants/abi/USDT.ts | 282 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 lib/constants/abi/USDT.ts diff --git a/lib/approve.ts b/lib/approve.ts index e17f97c..72fbe51 100644 --- a/lib/approve.ts +++ b/lib/approve.ts @@ -1,7 +1,8 @@ -import { Address, PublicClient, WalletClient } from "viem" +import { Address, PublicClient, WalletClient, getAddress } from "viem" import { ERC20Abi } from "@/lib/constants" import { showErrorToast, showLoadingToast, showSuccessToast } from "@/lib/toasts" import { Clients, SimulationResponse, Token } from "@/lib/types"; +import { UsdtAbi } from "./constants/abi/USDT"; interface HandleAllowanceProps { token: Address; @@ -61,7 +62,8 @@ async function simulateApprove({ address, account, spender, publicClient }: Simu const { request } = await publicClient.simulateContract({ account, address, - abi: ERC20Abi, + // @ts-ignore -- for some reason viem is not happy when the two abis are slightly different + abi: address === "0xdAC17F958D2ee523a2206206994597C13D831ec7" ? UsdtAbi : ERC20Abi, // USDT doesnt return a bool on approval functionName: 'approve', args: [spender, BigInt("115792089237316195423570985008687907853269984665640")] }) diff --git a/lib/constants/abi/USDT.ts b/lib/constants/abi/USDT.ts new file mode 100644 index 0000000..f5faf25 --- /dev/null +++ b/lib/constants/abi/USDT.ts @@ -0,0 +1,282 @@ +export const UsdtAbi = [ + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "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": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] as const \ No newline at end of file From 9591908d6e777b9caf5173bc608da86324d36127 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 29 Nov 2023 14:30:35 +0100 Subject: [PATCH 77/84] adjusted stats subtitle --- pages/stats.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/stats.tsx b/pages/stats.tsx index 6ff8e31..2097236 100644 --- a/pages/stats.tsx +++ b/pages/stats.tsx @@ -439,7 +439,7 @@ export default function Vaults() {

Popcorn Statistics

-

Total Stats start from 23 June 2023.

+

Total Stats start from 30 November 2023

From 8af949925001ba39f810c2a2dd9fd2cfdeaf88c8 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Wed, 29 Nov 2023 22:43:21 +0100 Subject: [PATCH 78/84] updated redeployed addresses --- lib/utils/addresses/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/addresses/index.ts b/lib/utils/addresses/index.ts index 33e6837..2387d7d 100644 --- a/lib/utils/addresses/index.ts +++ b/lib/utils/addresses/index.ts @@ -15,9 +15,9 @@ const VeAddresses = { TokenAdmin: "0x03d103c547B43b5a76df7e652BD0Bb61bE0BD70d", VotingEscrow: "0x0aB4bC35Ef33089B9082Ca7BB8657D7c4E819a1A", // Same as VE_VCX GaugeController: "0xD57d8EEC36F0Ba7D8Fd693B9D97e02D8353EB1F4", - GaugeFactory: "0x32a33CC9dC61352E70cb557927E5F9544ddb0a26", + GaugeFactory: "0x3bd6418e90653945f781e3717D8F9404565444F6", SmartWalletChecker: "0x8427155770f7e6b973249E2f9D140a495aBE4f90", - VotingEscrowDelegation: "0x9B12C90BAd388B7e417271eb20678D1a7759507c", + VotingEscrowDelegation: "0xafE32869CAf311585647ADcD79050B83DbCF94C8", VaultRouter: "0x8aed8Ea73044910760E8957B6c5b28Ac51f8f809" }; From 46ae00641c75785d16024ff83ce46c94ac1696e4 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Thu, 30 Nov 2023 11:16:04 +0100 Subject: [PATCH 79/84] updated social-links --- components/SocialMediaLinks.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/components/SocialMediaLinks.tsx b/components/SocialMediaLinks.tsx index cc8700e..60e2ec2 100644 --- a/components/SocialMediaLinks.tsx +++ b/components/SocialMediaLinks.tsx @@ -1,28 +1,24 @@ import DiscordIcon from "@/components/svg/socialMedia/DiscordIcon"; import MediumIcon from "@/components/svg/socialMedia/MediumIcon"; import RedditIcon from "@/components/svg/socialMedia/RedditIcon"; -import TelegramIcon from "@/components/svg/socialMedia/TelegramIcon"; import TwitterIcon from "@/components/svg/socialMedia/TwitterIcon"; import YoutubeIcon from "@/components/svg/socialMedia/YoutubeIcon"; export default function SocialMediaLinks() { return <> - + - + - - - - + - + - + From 06baa412fd089a33703700f1fbfca47dffd7326d Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 1 Dec 2023 10:27:16 +0100 Subject: [PATCH 80/84] filter broken gauge --- lib/gauges/getGauges.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/gauges/getGauges.ts b/lib/gauges/getGauges.ts index ea178bf..c0aa4cf 100644 --- a/lib/gauges/getGauges.ts +++ b/lib/gauges/getGauges.ts @@ -21,7 +21,7 @@ export default async function getGauges({ address, account = ADDRESS_ZERO, publi abi: GaugeControllerAbi } as const - const gauges = await publicClient.multicall({ + let gauges = await publicClient.multicall({ contracts: Array(Number(nGauges)).fill(undefined).map((item, idx) => { return { ...gaugeController, @@ -31,6 +31,8 @@ export default async function getGauges({ address, account = ADDRESS_ZERO, publi }), allowFailure: false }) as Address[] + // @dev Deployment script ran out of gas and somehow added a random address into the gauges which now breaks these calls + gauges = gauges.filter(gauge => gauge !== "0x38098e3600665168eBE4d827D24D0416efC24799"); const areGaugesKilled = await publicClient.multicall({ contracts: gauges.map((gauge: Address) => { From 6573dbc3c1bdb28556b5b1ff8c0a4ebbecc85fe0 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 1 Dec 2023 10:28:14 +0100 Subject: [PATCH 81/84] using mim yearn instead of mim beefy --- pages/vaults.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/vaults.tsx b/pages/vaults.tsx index 042331c..c5f74f4 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -31,7 +31,7 @@ const FLAGSHIP_VAULTS = [ "0xdC266B3D2c62Ce094ff4E12DC52399c430283417", // pCVX Pirex "0x6B2c5ef7FB59e6A1Ad79a4dB65234fb7bDDcaD6b", // oETH-LP Beefy "0xD211486ed1A04A176E588b67dd3A30a7dE164C0B", // WETH-AURA Beefy - "0x61f313C98ebAd818442CBEE2A196720C8986Cdf4", // MIM-LP Beefy + "0x61f313C98ebAd818442CBEE2A196720C8986Cdf4", // MIM Yearn "0xe1489Af32c45c51f94Acdb3F36B7032A82F6f55D", // WETH Sommelier "0x759281a408A48bfe2029D259c23D7E848A7EA1bC", // yCRV Yearn // op From 0b65133f32b3a8088fcf1ff98383a1d396847b65 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 1 Dec 2023 10:52:09 +0100 Subject: [PATCH 82/84] now replaced mim vault --- pages/vaults.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/vaults.tsx b/pages/vaults.tsx index c5f74f4..6a8fa86 100644 --- a/pages/vaults.tsx +++ b/pages/vaults.tsx @@ -31,7 +31,7 @@ const FLAGSHIP_VAULTS = [ "0xdC266B3D2c62Ce094ff4E12DC52399c430283417", // pCVX Pirex "0x6B2c5ef7FB59e6A1Ad79a4dB65234fb7bDDcaD6b", // oETH-LP Beefy "0xD211486ed1A04A176E588b67dd3A30a7dE164C0B", // WETH-AURA Beefy - "0x61f313C98ebAd818442CBEE2A196720C8986Cdf4", // MIM Yearn + "0xA3cd112fFb1E3A358EF270a07F5901FF0fD1CD0f", // MIM Yearn "0xe1489Af32c45c51f94Acdb3F36B7032A82F6f55D", // WETH Sommelier "0x759281a408A48bfe2029D259c23D7E848A7EA1bC", // yCRV Yearn // op From 8f0571a64b459dffc09f12e4670a8d05d9fda196 Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 1 Dec 2023 10:53:58 +0100 Subject: [PATCH 83/84] reading apy from defi-db --- components/page/Page.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/page/Page.tsx b/components/page/Page.tsx index bab9718..7701db7 100644 --- a/components/page/Page.tsx +++ b/components/page/Page.tsx @@ -17,11 +17,10 @@ import { useAccount } from "wagmi"; async function setUpYieldOptions() { const ttl = 360_000; const provider = new CachedProvider(); - await provider.initialize("https://raw.githubusercontent.com/Popcorn-Limited/apy-data/main/apy-data.json"); + await provider.initialize("https://raw.githubusercontent.com/Popcorn-Limited/defi-db/main/apy-data.json"); return new YieldOptions({ provider, ttl }); } - export default function Page({ children }: { children: JSX.Element }): JSX.Element { const { pathname } = useRouter(); const { address: account } = useAccount() From ac75cd67e4e65bdca8fa1e801a546c53f656329c Mon Sep 17 00:00:00 2001 From: RedVeil Date: Fri, 1 Dec 2023 11:19:38 +0100 Subject: [PATCH 84/84] sorting shows apy instead of apr --- components/vault/VaultsSorting.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/vault/VaultsSorting.tsx b/components/vault/VaultsSorting.tsx index 4656777..87511b1 100644 --- a/components/vault/VaultsSorting.tsx +++ b/components/vault/VaultsSorting.tsx @@ -119,7 +119,7 @@ export default function VaultsSorting( `} onClick={sortingMostApy} > - Most vAPR + Most vAPY
)}