From 94e01ce4e12c36e4d2cc9034fb50a357cde47a49 Mon Sep 17 00:00:00 2001 From: namedotget Date: Thu, 16 Jan 2025 16:53:29 -0600 Subject: [PATCH 1/3] Migrated withdraw to thirdweb v5 --- ui/components/privy/PrivyConnectWallet.tsx | 6 +- ui/lib/utils/hooks/useWithdrawAmount.ts | 12 +- ui/pages/withdraw.tsx | 135 ++++++++++++++------- 3 files changed, 102 insertions(+), 51 deletions(-) diff --git a/ui/components/privy/PrivyConnectWallet.tsx b/ui/components/privy/PrivyConnectWallet.tsx index c95c2a571..6fada6f9b 100644 --- a/ui/components/privy/PrivyConnectWallet.tsx +++ b/ui/components/privy/PrivyConnectWallet.tsx @@ -230,7 +230,11 @@ export function PrivyConnectWallet({ const { login } = useLogin({ onComplete: async ({ user, isNewUser, wasAlreadyAuthenticated }) => { //If the user signs in and wasn't already authenticated, check if they have a citizen NFT and redirect them to their profile or the guest page - if (!wasAlreadyAuthenticated && router.pathname !== '/submit') { + if ( + !wasAlreadyAuthenticated && + router.pathname !== '/submit' && + router.pathname !== '/withdraw' + ) { let citizen try { const citizenContract = await sdk?.getContract( diff --git a/ui/lib/utils/hooks/useWithdrawAmount.ts b/ui/lib/utils/hooks/useWithdrawAmount.ts index c6a319252..257017239 100644 --- a/ui/lib/utils/hooks/useWithdrawAmount.ts +++ b/ui/lib/utils/hooks/useWithdrawAmount.ts @@ -1,5 +1,6 @@ import { BigNumber } from 'ethers' import { useState, useEffect } from 'react' +import { readContract } from 'thirdweb' export default function useWithdrawAmount( votingEscrowDepositorContract: any, @@ -12,11 +13,12 @@ export default function useWithdrawAmount( useEffect(() => { async function fetchWithdrawAmount() { if (!votingEscrowDepositorContract || !userAddress) return - const theWithdrawAmount = await votingEscrowDepositorContract.call( - 'availableToWithdraw', - [userAddress] - ) - setWithdrawAmount(theWithdrawAmount) + const theWithdrawAmount: any = await readContract({ + contract: votingEscrowDepositorContract, + method: 'availableToWithdraw' as string, + params: [userAddress], + }) + setWithdrawAmount(BigNumber.from(theWithdrawAmount)) } fetchWithdrawAmount() diff --git a/ui/pages/withdraw.tsx b/ui/pages/withdraw.tsx index 5f9ea374d..371324478 100644 --- a/ui/pages/withdraw.tsx +++ b/ui/pages/withdraw.tsx @@ -1,5 +1,3 @@ -import { Arbitrum, Sepolia } from '@thirdweb-dev/chains' -import { useAddress, useContract } from '@thirdweb-dev/react' import ERC20 from 'const/abis/ERC20.json' import VotingEscrow from 'const/abis/VotingEscrow.json' import VotingEscrowDepositor from 'const/abis/VotingEscrowDepositor.json' @@ -13,11 +11,16 @@ import { BigNumber } from 'ethers' import { useRouter } from 'next/router' import React, { useContext, useState, useEffect } from 'react' import toast from 'react-hot-toast' +import { prepareContractCall, sendAndConfirmTransaction } from 'thirdweb' +import { useActiveAccount } from 'thirdweb/react' import toastStyle from '../lib/marketplace/marketplace-utils/toastConfig' import useWindowSize from '@/lib/team/use-window-size' -import ChainContext from '@/lib/thirdweb/chain-context' +import { getChainSlug } from '@/lib/thirdweb/chain' +import ChainContextV5 from '@/lib/thirdweb/chain-context-v5' import { useChainDefault } from '@/lib/thirdweb/hooks/useChainDefault' -import { useVMOONEYLock } from '@/lib/tokens/ve-token' +import useContract from '@/lib/thirdweb/hooks/useContract' +import useRead from '@/lib/thirdweb/hooks/useRead' +import { approveToken } from '@/lib/tokens/approve' import useWithdrawAmount from '@/lib/utils/hooks/useWithdrawAmount' import Container from '../components/layout/Container' import ContentLayout from '../components/layout/ContentLayout' @@ -25,38 +28,54 @@ import WebsiteHead from '../components/layout/Head' import StandardButton from '../components/layout/StandardButton' import Asset from '@/components/dashboard/treasury/balance/Asset' import { NoticeFooter } from '@/components/layout/NoticeFooter' +import { PrivyWeb3Button } from '@/components/privy/PrivyWeb3Button' import NetworkSelector from '@/components/thirdweb/NetworkSelector' export default function Withdraw() { useChainDefault() - const userAddress = useAddress() const router = useRouter() - const { selectedChain } = useContext(ChainContext) - const { contract: votingEscrowDepositorContract } = useContract( - VOTING_ESCROW_DEPOSITOR_ADDRESSES[selectedChain.slug], - VotingEscrowDepositor.abi - ) - const { contract: vMooneyContract }: any = useContract( - VMOONEY_ADDRESSES[selectedChain?.slug], - VotingEscrow - ) - const { contract: mooneyContract } = useContract( - MOONEY_ADDRESSES[selectedChain.slug], - ERC20 - ) - const withdrawable = useWithdrawAmount( - votingEscrowDepositorContract, - userAddress - ) + + const account = useActiveAccount() + const address = account?.address + + const { selectedChain } = useContext(ChainContextV5) + const chainSlug = getChainSlug(selectedChain) + + //Contracts + const votingEscrowDepositorContract = useContract({ + address: VOTING_ESCROW_DEPOSITOR_ADDRESSES[chainSlug], + abi: VotingEscrowDepositor.abi, + chain: selectedChain, + }) + const vMooneyContract = useContract({ + address: VMOONEY_ADDRESSES[chainSlug], + abi: VotingEscrow, + chain: selectedChain, + }) + const mooneyContract = useContract({ + address: MOONEY_ADDRESSES[chainSlug], + abi: ERC20, + chain: selectedChain, + }) + + const withdrawable = useWithdrawAmount(votingEscrowDepositorContract, address) const { isMobile } = useWindowSize() - const { data: VMOONEYLock, isLoading: VMOONEYLockLoading } = useVMOONEYLock( - vMooneyContract, - userAddress - ) + + const { data: VMOONEYLock, isLoading: VMOONEYLockLoading } = useRead({ + contract: vMooneyContract, + method: 'locked' as string, + params: [address], + }) + + const { data: mooneyAllowance, isLoading: mooneyAllowanceLoading } = useRead({ + contract: mooneyContract, + method: 'allowance' as string, + params: [address, VMOONEY_ADDRESSES[chainSlug]], + }) const [hasLock, setHasLock] = useState() useEffect(() => { !VMOONEYLockLoading && setHasLock(VMOONEYLock && VMOONEYLock[0] != 0) - }, [VMOONEYLock, VMOONEYLockLoading, userAddress]) + }, [VMOONEYLock, VMOONEYLockLoading, address]) const [hasMoreThanSixMonths, setHasMoreThanSixMonths] = useState(false) @@ -66,23 +85,48 @@ export default function Withdraw() { setHasMoreThanSixMonths( VMOONEYLock && VMOONEYLock[1] != 0 && - BigNumber.from(+new Date() + sixMonths).lte(VMOONEYLock[1] * 1000) + BigNumber.from(+new Date() + sixMonths).lte( + VMOONEYLock?.[1].toString() * 1000 + ) ) - }, [VMOONEYLock, VMOONEYLockLoading, userAddress]) + }, [VMOONEYLock, VMOONEYLockLoading, address, sixMonths]) const handleWithdraw = async () => { try { - await mooneyContract?.call('approve', [ - VMOONEY_ADDRESSES[selectedChain.slug], - withdrawable.toString(), - ]) - await votingEscrowDepositorContract?.call('withdraw') - toast.success('Withdrawal successful!', { - style: toastStyle, + const mooneyAllowanceBigNum = BigNumber.from(mooneyAllowance) + const withdrawableBigNum = BigNumber.from(withdrawable.toString()) + if (!account) throw new Error('No account found') + if (mooneyAllowanceLoading) throw new Error('Loading...') + if ( + mooneyAllowanceBigNum && + withdrawableBigNum && + mooneyAllowanceBigNum.lt(withdrawableBigNum) + ) { + const allowance = withdrawableBigNum.sub(mooneyAllowanceBigNum) + const approveReceipt = await approveToken({ + account, + tokenContract: mooneyContract, + spender: VMOONEY_ADDRESSES[chainSlug], + allowance: allowance, + }) + } + const withdrawTx = prepareContractCall({ + contract: votingEscrowDepositorContract, + method: 'withdraw' as string, + params: [], + }) + const withdrawReceipt = await sendAndConfirmTransaction({ + transaction: withdrawTx, + account, }) - setTimeout(() => { - router.reload() - }, 5000) + if (withdrawReceipt) { + toast.success('Withdrawal successful!', { + style: toastStyle, + }) + setTimeout(() => { + router.reload() + }, 5000) + } } catch (error) { console.error('Error withdrawing:', error) toast.error('Error withdrawing. Please try again.', { @@ -123,21 +167,22 @@ export default function Withdraw() { usd="" /> - {userAddress && hasLock && hasMoreThanSixMonths ? ( + {address && hasLock && hasMoreThanSixMonths ? ( Withdraw Rewards ) : ( - - {hasLock ? 'Extend Lock' : 'Lock MOONEY'} - + action={() => router.push('/lock')} + /> )} From 5c304ed27834d167aa101a26b9baccba156c7d53 Mon Sep 17 00:00:00 2001 From: namedotget Date: Tue, 21 Jan 2025 16:52:04 -0600 Subject: [PATCH 2/3] Added env var --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47c6f5974..c3835a8cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,7 @@ jobs: S3_UPLOAD_BUCKET: ${{secrets.S3_UPLOAD_BUCKET}} S3_UPLOAD_REGION: ${{secrets.S3_UPLOAD_REGION}} IRON_SESSION: ${{secrets.IRON_SESSION}} + TABLELAND_PRIVATE_KEY: ${{secrets.TABLELAND_PRIVATE_KEY}} steps: - name: Checkout uses: actions/checkout@v3 From 23ba3cc7952058c2cdd71203467a7be1b5d35b0b Mon Sep 17 00:00:00 2001 From: namedotget Date: Tue, 21 Jan 2025 17:19:15 -0600 Subject: [PATCH 3/3] Updated test --- .../integration/onboarding/team-image-generator.cy.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ui/cypress/integration/onboarding/team-image-generator.cy.tsx b/ui/cypress/integration/onboarding/team-image-generator.cy.tsx index 3dc914bea..d84a68ca7 100644 --- a/ui/cypress/integration/onboarding/team-image-generator.cy.tsx +++ b/ui/cypress/integration/onboarding/team-image-generator.cy.tsx @@ -1,3 +1,4 @@ +import TestnetProviders from '@/cypress/mock/TestnetProviders' import { PrivyProvider } from '@privy-io/react-auth' import { Sepolia } from '@thirdweb-dev/chains' import { PrivyThirdwebSDKProvider } from '@/lib/privy/PrivyThirdwebSDKProvider' @@ -15,11 +16,9 @@ describe('', () => { } cy.mount( - - - - - + + + ) })