diff --git a/apps/web/.env b/apps/web/.env index 42056ac7..dab1da86 100644 --- a/apps/web/.env +++ b/apps/web/.env @@ -4,4 +4,4 @@ NEXT_PUBLIC_UPLOAD_API=https://upload-api.zora.co NEXT_PUBLIC_IPFS_GATEWAY=https://ipfs.decentralized-content.com NEXT_PUBLIC_CHAIN_ID=5 -NEXT_PUBLIC_NETWORK_TYPE=mainnet +NEXT_PUBLIC_NETWORK_TYPE=testnet diff --git a/apps/web/package.json b/apps/web/package.json index 99a4e9b1..49649b56 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -21,7 +21,7 @@ "@farcaster/hub-nodejs": "^0.8.0", "@fontsource/inter": "4.5.10", "@fontsource/londrina-solid": "^4.5.9", - "@rainbow-me/rainbowkit": "^0.12.15", + "@rainbow-me/rainbowkit": "^1.0.8", "@sentry/nextjs": "^7.15.0", "@types/lodash": "^4.14.186", "@types/react-portal": "^4.0.4", @@ -29,7 +29,6 @@ "@vanilla-extract/next-plugin": "^2.0.2", "@vanilla-extract/recipes": "^0.2.5", "@vercel/og": "^0.4.0", - "@wagmi/core": "0.10.15", "@zoralabs/nouns-protocol": "1.2.0", "@zoralabs/zord": "workspace:*", "analytics": "workspace:*", @@ -64,7 +63,8 @@ "remark-gfm": "^3.0.1", "swr": "^1.3.0", "tinycolor2": "^1.4.2", - "wagmi": "0.12.17", + "viem": "^1.6.0", + "wagmi": "1.3.10", "yup": "^0.32.9", "zustand": "^4.3.3" }, @@ -91,7 +91,7 @@ "eslint-config-custom": "workspace:*", "jsdom": "^20.0.1", "tsconfig": "workspace:*", - "typescript": "^4.9.4", + "typescript": "^5.1.6", "vite": "^4.1.4", "vite-plugin-svgr": "^2.4.0", "vitest": "^0.27.3" diff --git a/apps/web/src/components/BridgeModal/BridgeForm.tsx b/apps/web/src/components/BridgeModal/BridgeForm.tsx index 575595e0..8e98f871 100644 --- a/apps/web/src/components/BridgeModal/BridgeForm.tsx +++ b/apps/web/src/components/BridgeModal/BridgeForm.tsx @@ -1,12 +1,12 @@ import { useConnectModal } from '@rainbow-me/rainbowkit' -import { sendTransaction } from '@wagmi/core' import { Box, Button, Flex, Heading, Text } from '@zoralabs/zord' -import { parseEther } from 'ethers/lib/utils.js' import { Formik } from 'formik' import Image from 'next/image' import Link from 'next/link' import { useState } from 'react' +import { parseEther } from 'viem' import { useAccount, useBalance, useNetwork, useSwitchNetwork } from 'wagmi' +import { sendTransaction, waitForTransaction } from 'wagmi/actions' import Input from 'src/components/Input/Input' import { L2ChainType, PUBLIC_L1_BRIDGE_ADDRESS } from 'src/constants/addresses' @@ -59,14 +59,11 @@ export const BridgeForm = () => { setLoading(true) try { - const { wait } = await sendTransaction({ - request: { - to: PUBLIC_L1_BRIDGE_ADDRESS[l2Chain.id as L2ChainType], - value: parseEther(values.amount.toString()), - }, - mode: 'recklesslyUnprepared', + const { hash } = await sendTransaction({ + to: PUBLIC_L1_BRIDGE_ADDRESS[l2Chain.id as L2ChainType], + value: parseEther(values.amount.toString()), }) - await wait() + await waitForTransaction({ hash }) } catch (err) { console.log('err', err) } finally { diff --git a/apps/web/src/components/ContractButton.tsx b/apps/web/src/components/ContractButton.tsx index a77b78c5..1e7cf8d7 100644 --- a/apps/web/src/components/ContractButton.tsx +++ b/apps/web/src/components/ContractButton.tsx @@ -30,7 +30,7 @@ export const ContractButton = ({ const handleClickWithValidation = () => { if (!userAddress) return openConnectModal?.() - if (canUserBridge && userBalance?.value.eq(0)) return openBridgeModal() + if (canUserBridge && userBalance?.decimals === 0) return openBridgeModal() if (userChain?.id !== appChain.id) return handleSwitchNetwork() handleClick() } diff --git a/apps/web/src/components/Fields/SmartInput.tsx b/apps/web/src/components/Fields/SmartInput.tsx index 799f1d63..f848efb5 100644 --- a/apps/web/src/components/Fields/SmartInput.tsx +++ b/apps/web/src/components/Fields/SmartInput.tsx @@ -6,7 +6,6 @@ import useSWR from 'swr' import { Icon } from 'src/components/Icon' import SWR_KEYS from 'src/constants/swrKeys' -import { useLayoutStore } from 'src/stores' import { getEnsName } from 'src/utils/ens' import { isEmpty } from 'src/utils/helpers' @@ -62,11 +61,9 @@ const SmartInput: React.FC = ({ disableWheelEvent = type === 'number', isAddress, }) => { - const { provider } = useLayoutStore() - const { data: ensName } = useSWR( isAddress ? [SWR_KEYS.ENS, value] : null, - async () => await getEnsName(value as string, provider) + async () => await getEnsName(value as string) ) /* diff --git a/apps/web/src/data/contract/chains.ts b/apps/web/src/data/contract/chains.ts index c45866f1..dd67cb23 100644 --- a/apps/web/src/data/contract/chains.ts +++ b/apps/web/src/data/contract/chains.ts @@ -13,20 +13,18 @@ const TESTNET_CHAINS = [mainnet, goerli, optimismGoerli, baseGoerli, zoraGoerli] const AVAILIBLE_CHAINS = PUBLIC_IS_TESTNET ? TESTNET_CHAINS : MAINNET_CHAINS -const { chains, provider } = configureChains( +const { chains, publicClient } = configureChains( [...AVAILIBLE_CHAINS], [ alchemyProvider({ apiKey: process.env.NEXT_PUBLIC_ALCHEMY_ID as string, - stallTimeout: 1000, }), jsonRpcProvider({ rpc: (chain) => ({ http: RPC_URL[chain.id as CHAIN_ID], }), - stallTimeout: 1000, }), ] ) -export { chains, provider } +export { chains, publicClient } diff --git a/apps/web/src/data/contract/client.ts b/apps/web/src/data/contract/config.ts similarity index 69% rename from apps/web/src/data/contract/client.ts rename to apps/web/src/data/contract/config.ts index f0630cb6..435c80e9 100644 --- a/apps/web/src/data/contract/client.ts +++ b/apps/web/src/data/contract/config.ts @@ -1,9 +1,9 @@ import { getDefaultWallets } from '@rainbow-me/rainbowkit' -import { createClient } from 'wagmi' +import { createConfig } from 'wagmi' import { PUBLIC_WALLLET_CONNECT_PROJECT_ID } from 'src/constants/walletconnect' -import { chains, provider } from './chains' +import { chains, publicClient } from './chains' const { connectors } = getDefaultWallets({ appName: 'Nouns builder', @@ -11,8 +11,8 @@ const { connectors } = getDefaultWallets({ projectId: PUBLIC_WALLLET_CONNECT_PROJECT_ID, }) -export const client = createClient({ +export const config = createConfig({ autoConnect: true, connectors, - provider, + publicClient, }) diff --git a/apps/web/src/data/contract/requests/getBids.ts b/apps/web/src/data/contract/requests/getBids.ts deleted file mode 100644 index 39aa5034..00000000 --- a/apps/web/src/data/contract/requests/getBids.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { getContract } from '@wagmi/core' -import { ethers } from 'ethers' - -import { auctionAbi } from 'src/data/contract/abis' -import { CHAIN_ID } from 'src/typings' - -import { getProvider } from '../../../utils/provider' - -export interface Bid { - id: number - bidder: string - amount: string - transactionHash: string -} - -const readAuctionBidEvents = async ( - chainId: CHAIN_ID, - auctionAddress: string -): Promise => { - const provider = getProvider(chainId) - const contract = getContract({ - abi: auctionAbi, - address: auctionAddress, - signerOrProvider: provider, - }) - - // reading all 'AuctionBid' events from block 0 to latest block - // an idea could be to get block number of previous tokens mint and start from there - const auctionEvents = await contract.queryFilter('AuctionBid', 0, 'latest') - - return auctionEvents.map((event) => { - return { - id: parseInt(event.args?.tokenId?._hex, 16), - bidder: event.args?.bidder, - amount: ethers.utils.formatEther(event.args?.amount), - transactionHash: event.transactionHash, - } - }) -} - -async function getBids( - chainId: CHAIN_ID, - auction: string, - tokenId: string | number -): Promise { - try { - const events = await readAuctionBidEvents(chainId, auction) - - return events - ?.filter((event) => event.id === Number(tokenId)) - .sort((a, b) => (Number(a.amount) > Number(b.amount) ? -1 : 1)) - } catch (err) { - console.warn(err) - return [] - } -} - -export default getBids diff --git a/apps/web/src/data/contract/requests/getDAOAddresses.ts b/apps/web/src/data/contract/requests/getDAOAddresses.ts index 7fdabb72..3bb55869 100644 --- a/apps/web/src/data/contract/requests/getDAOAddresses.ts +++ b/apps/web/src/data/contract/requests/getDAOAddresses.ts @@ -1,8 +1,9 @@ -import { readContract } from '@wagmi/core' import { ethers } from 'ethers' +import { readContract } from 'wagmi/actions' import { PUBLIC_MANAGER_ADDRESS } from 'src/constants/addresses' import { AddressType, CHAIN_ID } from 'src/typings' +import { unpackOptionalArray } from 'src/utils/helpers' import { managerAbi } from '../abis' @@ -15,6 +16,8 @@ const getDAOAddresses = async (chainId: CHAIN_ID, tokenAddress: AddressType) => chainId, }) + const [metadata, auction, treasury, governor] = unpackOptionalArray(addresses, 4) + const hasMissingAddresses = Object.values(addresses).includes( ethers.constants.AddressZero ) @@ -22,10 +25,10 @@ const getDAOAddresses = async (chainId: CHAIN_ID, tokenAddress: AddressType) => return { token: tokenAddress, - auction: addresses.auction, - governor: addresses.governor, - metadata: addresses.metadata, - treasury: addresses.treasury, + auction, + governor, + metadata, + treasury, } } diff --git a/apps/web/src/data/contract/requests/getPropertyItemsCount.ts b/apps/web/src/data/contract/requests/getPropertyItemsCount.ts index 8a2c76b6..163d9433 100644 --- a/apps/web/src/data/contract/requests/getPropertyItemsCount.ts +++ b/apps/web/src/data/contract/requests/getPropertyItemsCount.ts @@ -1,5 +1,4 @@ -import { readContract, readContracts } from '@wagmi/core' -import { BigNumber } from 'ethers' +import { readContract, readContracts } from 'wagmi/actions' import { AddressType, CHAIN_ID } from 'src/typings' @@ -13,7 +12,7 @@ export const getPropertyItemsCount = async ( const propertiesCount = await readContract({ ...baseParams, functionName: 'propertiesCount', - }).then((x) => x.toNumber()) + }).then((x) => Number(x)) const contracts = Array(propertiesCount) .fill(0) @@ -26,11 +25,12 @@ export const getPropertyItemsCount = async ( }) const propertyItemsCount = (await readContracts({ + allowFailure: false, contracts, - })) as BigNumber[] + })) as bigint[] return { propertiesCount, - propertyItemsCount: propertyItemsCount.map((x) => x.toNumber()), + propertyItemsCount: propertyItemsCount.map((x) => Number(x)), } } diff --git a/apps/web/src/data/contract/requests/getProposalState.ts b/apps/web/src/data/contract/requests/getProposalState.ts index eb0d1a45..44014b2d 100644 --- a/apps/web/src/data/contract/requests/getProposalState.ts +++ b/apps/web/src/data/contract/requests/getProposalState.ts @@ -1,4 +1,4 @@ -import { readContract } from '@wagmi/core' +import { readContract } from 'wagmi/actions' import { AddressType, BytesType, CHAIN_ID } from 'src/typings' diff --git a/apps/web/src/data/contract/requests/getToken.ts b/apps/web/src/data/contract/requests/getToken.ts index bedccc20..de54d836 100644 --- a/apps/web/src/data/contract/requests/getToken.ts +++ b/apps/web/src/data/contract/requests/getToken.ts @@ -1,7 +1,6 @@ import * as Sentry from '@sentry/nextjs' -import { readContract } from '@wagmi/core' -import { BigNumber } from 'ethers' import { base64 } from 'ethers/lib/utils' +import { readContract } from 'wagmi/actions' import { tokenAbi } from 'src/data/contract/abis' import { @@ -30,7 +29,7 @@ const readTokenContractData = async ( abi: tokenAbi, address: tokenAddress, functionName: 'tokenURI', - args: [BigNumber.from(id)], + args: [BigInt(id)], chainId, }) diff --git a/apps/web/src/data/contract/server.client.ts b/apps/web/src/data/contract/server.client.ts deleted file mode 100644 index 8402b0dd..00000000 --- a/apps/web/src/data/contract/server.client.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createClient } from 'wagmi' - -import { provider } from './chains' - -createClient({ - provider, -}) diff --git a/apps/web/src/data/contract/server.config.ts b/apps/web/src/data/contract/server.config.ts new file mode 100644 index 00000000..f0199ca9 --- /dev/null +++ b/apps/web/src/data/contract/server.config.ts @@ -0,0 +1,7 @@ +import { createConfig } from 'wagmi' + +import { publicClient } from './chains' + +createConfig({ + publicClient, +}) diff --git a/apps/web/src/data/subgraph/requests/getBids.ts b/apps/web/src/data/subgraph/requests/getBids.ts new file mode 100644 index 00000000..6633a580 --- /dev/null +++ b/apps/web/src/data/subgraph/requests/getBids.ts @@ -0,0 +1,25 @@ +import * as Sentry from '@sentry/nextjs' +import { formatEther } from 'viem' + +import { CHAIN_ID } from 'src/typings' + +import { SDK } from '../client' +import { AuctionBidFragment } from '../sdk.generated' + +export const getBids = async (chainId: CHAIN_ID, collection: string, tokenId: string) => { + try { + return SDK.connect(chainId) + .auctionBids({ id: `${collection.toLowerCase()}:${tokenId}` }) + .then((x) => + x.auction?.bids?.map((bid: AuctionBidFragment) => ({ + ...bid, + amount: formatEther(bid.amount), + })) + ) + } catch (error) { + console.error(error) + Sentry.captureException(error) + await Sentry.flush(2000) + return undefined + } +} diff --git a/apps/web/src/hooks/useEnsData.ts b/apps/web/src/hooks/useEnsData.ts index 6b3e65c4..ebd0bdd9 100644 --- a/apps/web/src/hooks/useEnsData.ts +++ b/apps/web/src/hooks/useEnsData.ts @@ -10,7 +10,7 @@ export const useEnsData = (address?: string) => { }) const { data: ensAvatar } = useEnsAvatar({ - address: address as `0x${string}`, + name: ensName, chainId: CHAIN_ID.ETHEREUM, }) diff --git a/apps/web/src/hooks/useVotes.ts b/apps/web/src/hooks/useVotes.ts index bedffa64..31f2de7d 100644 --- a/apps/web/src/hooks/useVotes.ts +++ b/apps/web/src/hooks/useVotes.ts @@ -17,23 +17,24 @@ export const useVotes = ({ }) => { const { data, isLoading } = useContractReads({ enabled: !!collectionAddress && !!governorAddress && !!signerAddress, + allowFailure: false, contracts: [ { - address: collectionAddress, + address: collectionAddress as AddressType, abi: tokenAbi, functionName: 'getVotes', args: [signerAddress as AddressType], chainId, }, { - address: collectionAddress, + address: collectionAddress as AddressType, abi: tokenAbi, functionName: 'delegates', args: [signerAddress as AddressType], chainId, }, { - address: governorAddress, + address: governorAddress as AddressType, abi: governorAbi, functionName: 'proposalThreshold', chainId, @@ -54,8 +55,8 @@ export const useVotes = ({ return { isLoading, isDelegating: delegates !== signerAddress, - isOwner: votes.toNumber() > 0, - hasThreshold: votes.toNumber() > proposalThreshold.toNumber(), - proposalVotesRequired: proposalThreshold.toNumber() + 1, + isOwner: votes > 0, + hasThreshold: votes > proposalThreshold, + proposalVotesRequired: proposalThreshold + BigInt(1), } } diff --git a/apps/web/src/layouts/LayoutWrapper.tsx b/apps/web/src/layouts/LayoutWrapper.tsx index 5589f0b6..12c4a7f3 100644 --- a/apps/web/src/layouts/LayoutWrapper.tsx +++ b/apps/web/src/layouts/LayoutWrapper.tsx @@ -2,34 +2,20 @@ import { Box, Stack } from '@zoralabs/zord' import { isBlocked } from 'blocklist' import { useRouter } from 'next/router' import React, { ReactNode } from 'react' -import { useSigner } from 'wagmi' +import { useAccount } from 'wagmi' import { Skull } from 'src/components/Skull' import { PUBLIC_DEFAULT_CHAINS } from 'src/constants/defaultChains' -import { useDaoStore } from 'src/modules/dao' import { useLayoutStore } from 'src/stores' import { useChainStore } from 'src/stores/useChainStore' -import { getProvider } from 'src/utils/provider' import { DefaultLayout } from './DefaultLayout' export function LayoutWrapper({ children }: { children: ReactNode }) { - const { data: signer, status } = useSigner() - const { setSigner, setProvider, setSignerAddress } = useLayoutStore() const { setIsMobile } = useLayoutStore() - const { addresses } = useDaoStore() - const { chain, setChain } = useChainStore() + const { setChain } = useChainStore() const { query } = useRouter() - - // store signer, signerAddress and provider in store - React.useEffect(() => { - if (status === 'success') { - setProvider(signer?.provider ?? getProvider(chain.id)) - setSigner(signer) - //@ts-ignore - setSignerAddress(signer?._address) - } - }, [status, chain.id, signer, setProvider, addresses, setSigner, setSignerAddress]) + const { address } = useAccount() // add mobile flag to layout store React.useEffect(() => { @@ -58,8 +44,7 @@ export function LayoutWrapper({ children }: { children: ReactNode }) { setIsMobile(window.innerWidth <= 768) } - //@ts-ignore - if (isBlocked(signer?._address)) + if (isBlocked(address)) return ( diff --git a/apps/web/src/modules/auction/components/Auction.tsx b/apps/web/src/modules/auction/components/Auction.tsx index 455c8b81..2752bb9e 100644 --- a/apps/web/src/modules/auction/components/Auction.tsx +++ b/apps/web/src/modules/auction/components/Auction.tsx @@ -1,15 +1,14 @@ -import { readContract } from '@wagmi/core' import { Flex, Grid } from '@zoralabs/zord' -import { formatEther } from 'ethers/lib/utils.js' import React, { Fragment, ReactNode } from 'react' import useSWR from 'swr' +import { readContract } from 'wagmi/actions' import SWR_KEYS from 'src/constants/swrKeys' import { auctionAbi } from 'src/data/contract/abis' import { TokenWithWinner } from 'src/data/contract/requests/getToken' -import { SDK } from 'src/data/subgraph/client' -import { AuctionBidFragment } from 'src/data/subgraph/sdk.generated' +import { getBids } from 'src/data/subgraph/requests/getBids' import { AddressType, Chain } from 'src/typings' +import { unpackOptionalArray } from 'src/utils/helpers' import { useAuctionEvents } from '../hooks' import { auctionGrid, auctionWrapper } from './Auction.css' @@ -50,8 +49,12 @@ export const Auction: React.FC = ({ { revalidateOnFocus: true } ) - const isTokenActiveAuction = - !auction?.settled && !!auction?.tokenId && auction.tokenId.eq(token.id) + const [tokenId, highestBid, highestBidder, _, endTime, settled] = unpackOptionalArray( + auction, + 6 + ) + + const isTokenActiveAuction = !settled && !!tokenId && tokenId.toString() == token.id useAuctionEvents({ chainId: chain.id, @@ -61,16 +64,8 @@ export const Auction: React.FC = ({ }) const { data: bids } = useSWR( - [SWR_KEYS.AUCTION_BIDS, chain.id, auctionAddress, token.id], - () => - SDK.connect(chain.id) - .auctionBids({ id: `${collection.toLowerCase()}:${token.id}` }) - .then((x) => - x.auction?.bids?.map((bid: AuctionBidFragment) => ({ - ...bid, - amount: formatEther(bid.amount), - })) - ) + [SWR_KEYS.AUCTION_BIDS, chain.id, collection, token.id], + () => getBids(chain.id, collection, token.id) ) return ( @@ -91,7 +86,7 @@ export const Auction: React.FC = ({ name={name} collection={collection} tokenId={Number(token.id)} - currentAuction={auction?.tokenId.toNumber()} + currentAuction={Number(tokenId)} /> {isTokenActiveAuction && !!auction && ( @@ -99,9 +94,9 @@ export const Auction: React.FC = ({ chain={chain} tokenId={token.id} auctionAddress={auctionAddress} - bid={auction.highestBid} - owner={auction.highestBidder} - endTime={auction.endTime} + bid={highestBid} + owner={highestBidder} + endTime={endTime} bids={bids || []} /> )} diff --git a/apps/web/src/modules/auction/components/AuctionPaused.tsx b/apps/web/src/modules/auction/components/AuctionPaused.tsx index 8dbbd806..0d945d3c 100644 --- a/apps/web/src/modules/auction/components/AuctionPaused.tsx +++ b/apps/web/src/modules/auction/components/AuctionPaused.tsx @@ -3,7 +3,8 @@ import Link from 'next/link' import { useRouter } from 'next/router' import { useMemo } from 'react' import useSWR from 'swr' -import { useContract, useContractRead } from 'wagmi' +import { encodeFunctionData } from 'viem' +import { useContractRead } from 'wagmi' import { Icon } from 'src/components/Icon' import SWR_KEYS from 'src/constants/swrKeys' @@ -22,7 +23,7 @@ export const AuctionPaused = () => { const LIMIT = 20 const { auction } = useDaoStore((x) => x.addresses) - const auctionContract = useContract({ abi: auctionAbi, address: auction }) + const { data: paused } = useContractRead({ abi: auctionAbi, address: auction, @@ -36,10 +37,17 @@ export const AuctionPaused = () => { ) const pausedProposal = useMemo(() => { - if (!(paused && auctionContract)) return undefined + if (!(paused && auction)) return undefined + + const pauseCalldata = encodeFunctionData({ + abi: auctionAbi, + functionName: 'pause', + }) - const pauseCalldata = auctionContract.interface.encodeFunctionData('pause') - const unpauseCalldata = auctionContract.interface.encodeFunctionData('unpause') + const unpauseCalldata = encodeFunctionData({ + abi: auctionAbi, + functionName: 'unpause', + }) return data?.proposals.find((proposal) => { if (proposal.state !== ProposalState.Executed) return false @@ -57,7 +65,7 @@ export const AuctionPaused = () => { if (isPausing && !isUnpausing) return proposal }) - }, [paused, data?.proposals, auctionContract]) + }, [paused, data?.proposals]) if (!paused) return null diff --git a/apps/web/src/modules/auction/components/CurrentAuction/CurrentAuction.tsx b/apps/web/src/modules/auction/components/CurrentAuction/CurrentAuction.tsx index ca047313..2ec0c68b 100644 --- a/apps/web/src/modules/auction/components/CurrentAuction/CurrentAuction.tsx +++ b/apps/web/src/modules/auction/components/CurrentAuction/CurrentAuction.tsx @@ -1,5 +1,5 @@ import dayjs from 'dayjs' -import { BigNumber, ethers } from 'ethers' +import { ethers } from 'ethers' import React, { Fragment, useState } from 'react' import { AuctionBidFragment } from 'src/data/subgraph/sdk.generated' @@ -26,7 +26,7 @@ export const CurrentAuction = ({ chain: Chain tokenId: string auctionAddress: string - bid?: BigNumber + bid?: bigint owner?: string endTime?: number bids: AuctionBidFragment[] diff --git a/apps/web/src/modules/auction/components/CurrentAuction/PlaceBid.tsx b/apps/web/src/modules/auction/components/CurrentAuction/PlaceBid.tsx index d9502a57..48209684 100644 --- a/apps/web/src/modules/auction/components/CurrentAuction/PlaceBid.tsx +++ b/apps/web/src/modules/auction/components/CurrentAuction/PlaceBid.tsx @@ -1,23 +1,16 @@ -import { prepareWriteContract, writeContract } from '@wagmi/core' import { Box, Button, Flex } from '@zoralabs/zord' -import { BigNumber, ethers } from 'ethers' import React, { Fragment, memo, useState } from 'react' import { useSWRConfig } from 'swr' -import { - Address, - useAccount, - useBalance, - useContractReads, - useNetwork, - useSigner, -} from 'wagmi' +import { parseEther } from 'viem' +import { Address, useAccount, useBalance, useContractReads, useNetwork } from 'wagmi' +import { prepareWriteContract, waitForTransaction, writeContract } from 'wagmi/actions' import { ContractButton } from 'src/components/ContractButton' import SWR_KEYS from 'src/constants/swrKeys' import { auctionAbi } from 'src/data/contract/abis' -import getBids from 'src/data/contract/requests/getBids' +import { getBids } from 'src/data/subgraph/requests/getBids' import { useDaoStore } from 'src/modules/dao' -import { Chain } from 'src/typings' +import { AddressType, Chain } from 'src/typings' import { unpackOptionalArray } from 'src/utils/helpers' import { formatCryptoVal } from 'src/utils/numbers' @@ -27,11 +20,10 @@ import { auctionActionButtonVariants, bidForm, bidInput } from '../Auction.css' interface PlaceBidProps { chain: Chain tokenId: string - highestBid?: BigNumber + highestBid?: bigint } export const PlaceBid = ({ chain, highestBid, tokenId }: PlaceBidProps) => { - const { data: signer } = useSigner() const { address } = useAccount() const { chain: wagmiChain } = useNetwork() const { data: balance } = useBalance({ address: address, chainId: chain.id }) @@ -43,10 +35,11 @@ export const PlaceBid = ({ chain, highestBid, tokenId }: PlaceBidProps) => { const auctionContractParams = { abi: auctionAbi, - address: addresses.auction, + address: addresses.auction as AddressType, chainId: chain.id, } const { data } = useContractReads({ + allowFailure: false, contracts: [ { ...auctionContractParams, functionName: 'reservePrice' }, { ...auctionContractParams, functionName: 'minBidIncrement' }, @@ -61,7 +54,7 @@ export const PlaceBid = ({ chain, highestBid, tokenId }: PlaceBidProps) => { }) const handleCreateBid = async () => { - if (!isMinBid || !bidAmount || !signer || creatingBid) return + if (!isMinBid || !bidAmount || creatingBid) return try { setCreatingBid(true) @@ -70,15 +63,14 @@ export const PlaceBid = ({ chain, highestBid, tokenId }: PlaceBidProps) => { abi: auctionAbi, address: addresses.auction as Address, functionName: 'createBid', - signer: signer, - args: [BigNumber.from(tokenId)], - overrides: { value: ethers.utils.parseEther(bidAmount) }, + args: [BigInt(tokenId)], + value: parseEther(bidAmount), }) - const { wait } = await writeContract(config) - await wait() + const tx = await writeContract(config) + if (tx?.hash) await waitForTransaction({ hash: tx.hash }) - await mutate([SWR_KEYS.AUCTION_BIDS, chain.id, addresses.auction, tokenId], () => - getBids(chain.id, addresses.auction as string, tokenId) + await mutate([SWR_KEYS.AUCTION_BIDS, chain.id, addresses.token, tokenId], () => + getBids(chain.id, addresses.token!, tokenId) ) } catch (error) { console.error(error) diff --git a/apps/web/src/modules/auction/components/CurrentAuction/Settle.tsx b/apps/web/src/modules/auction/components/CurrentAuction/Settle.tsx index f66971db..b3971f96 100644 --- a/apps/web/src/modules/auction/components/CurrentAuction/Settle.tsx +++ b/apps/web/src/modules/auction/components/CurrentAuction/Settle.tsx @@ -1,11 +1,7 @@ import { Button, Flex } from '@zoralabs/zord' import React, { useState } from 'react' -import { - useContractRead, - useContractWrite, - usePrepareContractWrite, - useSigner, -} from 'wagmi' +import { useContractRead, useContractWrite, usePrepareContractWrite } from 'wagmi' +import { waitForTransaction } from 'wagmi/actions' import { ContractButton } from 'src/components/ContractButton' import { auctionAbi } from 'src/data/contract/abis' @@ -20,7 +16,6 @@ interface SettleProps { } export const Settle = ({ isEnding }: SettleProps) => { - const { data: signer } = useSigner() const chain = useChainStore((x) => x.chain) const addresses = useDaoStore((state) => state.addresses) @@ -44,14 +39,12 @@ export const Settle = ({ isEnding }: SettleProps) => { const [settling, setSettling] = useState(false) const handleSettle = async () => { - if (!signer) return - if (!!error) return setSettling(true) try { - const txn = await writeAsync?.() - await txn?.wait() + const tx = await writeAsync?.() + if (tx?.hash) await waitForTransaction({ hash: tx.hash }) setSettling(false) } catch (error) { setSettling(false) diff --git a/apps/web/src/modules/auction/hooks/useAuctionEvents.ts b/apps/web/src/modules/auction/hooks/useAuctionEvents.ts index 9d876997..1c06c298 100644 --- a/apps/web/src/modules/auction/hooks/useAuctionEvents.ts +++ b/apps/web/src/modules/auction/hooks/useAuctionEvents.ts @@ -1,12 +1,11 @@ -import { readContract } from '@wagmi/core' -import { BigNumber } from 'ethers' import { useRouter } from 'next/router' import { useSWRConfig } from 'swr' import { useContractEvent } from 'wagmi' +import { readContract } from 'wagmi/actions' import SWR_KEYS from 'src/constants/swrKeys' import { auctionAbi } from 'src/data/contract/abis' -import getBids from 'src/data/contract/requests/getBids' +import { getBids } from 'src/data/subgraph/requests/getBids' import { useDaoStore } from 'src/modules/dao' import { AddressType, CHAIN_ID } from 'src/typings' @@ -30,9 +29,7 @@ export const useAuctionEvents = ({ abi: auctionAbi, eventName: 'AuctionCreated', chainId, - listener: async (id) => { - const tokenId = BigNumber.from(id._hex).toNumber() - + listener: async (logs) => { await mutate([SWR_KEYS.AUCTION, chainId, auction], () => readContract({ abi: auctionAbi, @@ -42,8 +39,10 @@ export const useAuctionEvents = ({ }) ) + const tokenId = logs[0].args.tokenId as bigint + await mutate([SWR_KEYS.AUCTION_BIDS, chainId, auction, tokenId], () => - getBids(chainId, auction as string, tokenId) + getBids(chainId, collection, tokenId.toString()) ) await router.push(`/dao/${router.query.network}/${collection}/${tokenId}`) diff --git a/apps/web/src/modules/auction/hooks/useMinBidIncrement.test.ts b/apps/web/src/modules/auction/hooks/useMinBidIncrement.test.ts index d629edac..dc337c8c 100644 --- a/apps/web/src/modules/auction/hooks/useMinBidIncrement.test.ts +++ b/apps/web/src/modules/auction/hooks/useMinBidIncrement.test.ts @@ -1,5 +1,4 @@ import { renderHook } from '@testing-library/react' -import { BigNumber } from 'ethers' import { useMinBidIncrement } from './useMinBidIncrement' @@ -7,7 +6,7 @@ describe('calculate min bid increment', () => { it('should return the default min bid amount given and undefined reserve price or undefined min bid increment', () => { const { result } = renderHook(() => useMinBidIncrement({ - highestBid: BigNumber.from('0x00'), + highestBid: BigInt('0x00'), reservePrice: undefined, minBidIncrement: undefined, }) @@ -18,9 +17,9 @@ describe('calculate min bid increment', () => { it('should return the default min bid amount given an undefined reserve price', () => { const { result } = renderHook(() => useMinBidIncrement({ - highestBid: BigNumber.from('0x00'), + highestBid: BigInt('0x00'), reservePrice: undefined, - minBidIncrement: BigNumber.from('0x0a'), + minBidIncrement: BigInt('0x0a'), }) ) expect(result.current.minBidAmount).toBe(0.0001) @@ -29,8 +28,8 @@ describe('calculate min bid increment', () => { it('should return the default min bid amount given an undefined min bid increment', () => { const { result } = renderHook(() => useMinBidIncrement({ - highestBid: BigNumber.from('0x00'), - reservePrice: BigNumber.from('0xb1a2bc2ec50000'), + highestBid: BigInt('0x00'), + reservePrice: BigInt('0xb1a2bc2ec50000'), minBidIncrement: undefined, }) ) @@ -40,9 +39,9 @@ describe('calculate min bid increment', () => { it('should return the default min bid amount given a reserve price of 0 and highest bid of 0', () => { const { result } = renderHook(() => useMinBidIncrement({ - highestBid: BigNumber.from('0x00'), - reservePrice: BigNumber.from('0x00'), - minBidIncrement: BigNumber.from('0x0a'), + highestBid: BigInt('0x00'), + reservePrice: BigInt('0x00'), + minBidIncrement: BigInt('0x0a'), }) ) expect(result.current.minBidAmount).toBe(0.0001) @@ -51,9 +50,9 @@ describe('calculate min bid increment', () => { it('should return the min bid amount as the reserve price given 0 for highest bid', () => { const { result } = renderHook(() => useMinBidIncrement({ - highestBid: BigNumber.from('0x00'), - reservePrice: BigNumber.from('0xb1a2bc2ec50000'), - minBidIncrement: BigNumber.from('0x0a'), + highestBid: BigInt('0x00'), + reservePrice: BigInt('0xb1a2bc2ec50000'), + minBidIncrement: BigInt('0x0a'), }) ) expect(result.current.minBidAmount).toBe(0.05) @@ -64,8 +63,8 @@ describe('calculate min bid increment', () => { useMinBidIncrement({ //@ts-ignore highestBid: undefined, - reservePrice: BigNumber.from('0xb1a2bc2ec50000'), - minBidIncrement: BigNumber.from('0x0a'), + reservePrice: BigInt('0xb1a2bc2ec50000'), + minBidIncrement: BigInt('0x0a'), }) ) expect(result.current.minBidAmount).toBe(0.05) @@ -74,9 +73,9 @@ describe('calculate min bid increment', () => { it('should return an incremental min bid amount given a current highest bid and min bid increment', () => { const { result } = renderHook(() => useMinBidIncrement({ - highestBid: BigNumber.from('0xb1a2bc2ec50000'), - reservePrice: BigNumber.from('0xb1a2bc2ec50000'), - minBidIncrement: BigNumber.from('0x0a'), + highestBid: BigInt('0xb1a2bc2ec50000'), + reservePrice: BigInt('0xb1a2bc2ec50000'), + minBidIncrement: BigInt('0x0a'), }) ) expect(result.current.minBidAmount).toBe(0.055) @@ -85,9 +84,9 @@ describe('calculate min bid increment', () => { it('should return an incremental min bid amount given a current highest bid with a 0 reserve price', () => { const { result } = renderHook(() => useMinBidIncrement({ - highestBid: BigNumber.from('0xb1a2bc2ec50000'), - reservePrice: BigNumber.from('0x00'), - minBidIncrement: BigNumber.from('0x0a'), + highestBid: BigInt('0xb1a2bc2ec50000'), + reservePrice: BigInt('0x00'), + minBidIncrement: BigInt('0x0a'), }) ) expect(result.current.minBidAmount).toBe(0.055) diff --git a/apps/web/src/modules/auction/hooks/useMinBidIncrement.ts b/apps/web/src/modules/auction/hooks/useMinBidIncrement.ts index 400b29d0..a2c1c348 100644 --- a/apps/web/src/modules/auction/hooks/useMinBidIncrement.ts +++ b/apps/web/src/modules/auction/hooks/useMinBidIncrement.ts @@ -1,4 +1,4 @@ -import { BigNumber, ethers } from 'ethers' +import { formatEther } from 'viem' const DEFAULT_MIN_BID_AMOUNT = 0.0001 @@ -7,30 +7,29 @@ export const useMinBidIncrement = ({ reservePrice, minBidIncrement, }: { - highestBid?: BigNumber - reservePrice?: BigNumber - minBidIncrement?: BigNumber + highestBid?: bigint + reservePrice?: bigint + minBidIncrement?: bigint }) => { if ( - !reservePrice || - !minBidIncrement || + reservePrice === undefined || + minBidIncrement === undefined || // force default min bid amount given reserve price of 0 and no current bids - (BigNumber.from(reservePrice).isZero() && BigNumber.from(highestBid).isZero()) + (reservePrice === BigInt(0) && highestBid === BigInt(0)) ) { return { minBidAmount: DEFAULT_MIN_BID_AMOUNT, } } - if (!highestBid || BigNumber.from(highestBid).isZero()) { + if (!highestBid || highestBid === BigInt(0)) { return { - minBidAmount: Number(ethers.utils.formatEther(reservePrice)), + minBidAmount: Number(formatEther(reservePrice)), } } - const currBid = BigNumber.from(highestBid) - const minBidRawAmount = currBid.mul(minBidIncrement).div(100).add(currBid) - const minBidFormattedAmount = Number(ethers.utils.formatEther(minBidRawAmount)) + const minBidRawAmount = (highestBid * minBidIncrement) / BigInt(100) + highestBid + const minBidFormattedAmount = Number(formatEther(minBidRawAmount)) return { minBidAmount: minBidFormattedAmount, diff --git a/apps/web/src/modules/create-dao/components/AllocationForm/AllocationForm.tsx b/apps/web/src/modules/create-dao/components/AllocationForm/AllocationForm.tsx index 14eef978..6edf6b0e 100644 --- a/apps/web/src/modules/create-dao/components/AllocationForm/AllocationForm.tsx +++ b/apps/web/src/modules/create-dao/components/AllocationForm/AllocationForm.tsx @@ -2,6 +2,7 @@ import { Button, Flex } from '@zoralabs/zord' import { FieldArray, Form, Formik, FormikProps } from 'formik' import sum from 'lodash/sum' import React, { useRef, useState } from 'react' +import { useAccount } from 'wagmi' import { shallow } from 'zustand/shallow' import { @@ -9,7 +10,6 @@ import { defaultFormButtonWithPrev, } from 'src/components/Fields/styles.css' import { Icon } from 'src/components/Icon' -import { useLayoutStore } from 'src/stores' import { useChainStore } from 'src/stores/useChainStore' import { CHAIN_ID } from 'src/typings' import { getEnsAddress } from 'src/utils/ens' @@ -63,20 +63,14 @@ export const AllocationForm: React.FC = ({ title }) => { shallow ) - const { signerAddress } = useLayoutStore( - (state) => ({ - signerAddress: state.signerAddress, - provider: state.provider, - }), - shallow - ) + const { address } = useAccount() // should always default to the current signer address given this field is disabled const initialFounderValues = founderAllocation.length === 0 ? [ { - founderAddress: signerAddress || '', + founderAddress: address || '', allocationPercentage: '', endDate: '', admin: true, @@ -84,7 +78,7 @@ export const AllocationForm: React.FC = ({ title }) => { ] : [ { - founderAddress: signerAddress || '', + founderAddress: address || '', allocationPercentage: founderAllocation[0].allocationPercentage, endDate: founderAllocation[0].endDate, admin: true, @@ -125,7 +119,7 @@ export const AllocationForm: React.FC = ({ title }) => { setActiveSection(activeSection + 1) } - if (!signerAddress) return null + if (!address) return null return ( <> @@ -136,7 +130,7 @@ export const AllocationForm: React.FC = ({ title }) => { innerRef={formRef} validateOnMount={true} validateOnChange={true} - validationSchema={validationSchemaFounderAllocation(signerAddress)} + validationSchema={validationSchemaFounderAllocation(address)} onSubmit={handleSubmit} > {(formik) => ( diff --git a/apps/web/src/modules/create-dao/components/ReviewAndDeploy/ReviewAndDeploy.tsx b/apps/web/src/modules/create-dao/components/ReviewAndDeploy/ReviewAndDeploy.tsx index 949af648..cd5c6d5e 100644 --- a/apps/web/src/modules/create-dao/components/ReviewAndDeploy/ReviewAndDeploy.tsx +++ b/apps/web/src/modules/create-dao/components/ReviewAndDeploy/ReviewAndDeploy.tsx @@ -1,13 +1,15 @@ +import { Box, Flex, atoms } from '@zoralabs/zord' +import { ethers } from 'ethers' +import { getFetchableUrl } from 'ipfs-service' +import React, { useState } from 'react' +import { getAddress, parseEther } from 'viem' +import { useAccount } from 'wagmi' import { WriteContractUnpreparedArgs, prepareWriteContract, + waitForTransaction, writeContract, -} from '@wagmi/core' -import { Box, Flex, atoms } from '@zoralabs/zord' -import { BigNumber, ethers } from 'ethers' -import { getFetchableUrl } from 'ipfs-service' -import React, { useState } from 'react' -import { useSigner } from 'wagmi' +} from 'wagmi/actions' import { ContractButton } from 'src/components/ContractButton' import { defaultBackButton } from 'src/components/Fields/styles.css' @@ -54,12 +56,12 @@ const DEPLOYMENT_ERROR = { } export const ReviewAndDeploy: React.FC = ({ title }) => { - const { data: signer } = useSigner() const [isPendingTransaction, setIsPendingTransaction] = useState(false) const [hasConfirmedTerms, setHasConfirmedTerms] = useState(false) const [hasConfirmedChain, setHasConfirmedChain] = useState(false) const [deploymentError, setDeploymentError] = useState() const chain = useChainStore((x) => x.chain) + const { address } = useAccount() const { founderAllocation, @@ -87,8 +89,8 @@ export const ReviewAndDeploy: React.FC = ({ title }) => { ...contributionAllocation, ].map(({ founderAddress, allocationPercentage: allocation, endDate }) => ({ wallet: founderAddress as AddressType, - ownershipPct: allocation ? BigNumber.from(allocation) : BigNumber.from(0), - vestExpiry: BigNumber.from(Math.floor(new Date(endDate).getTime() / 1000)), + ownershipPct: allocation ? BigInt(allocation) : BigInt(0), + vestExpiry: BigInt(Math.floor(new Date(endDate).getTime() / 1000)), })) const abiCoder = new ethers.utils.AbiCoder() @@ -108,31 +110,27 @@ export const ReviewAndDeploy: React.FC = ({ title }) => { const auctionParams = { reservePrice: auctionSettings.auctionReservePrice - ? ethers.utils.parseEther(auctionSettings.auctionReservePrice.toString()) - : ethers.utils.parseEther('0'), + ? parseEther(auctionSettings.auctionReservePrice.toString()) + : parseEther('0'), duration: auctionSettings?.auctionDuration - ? BigNumber.from(toSeconds(auctionSettings?.auctionDuration)) - : BigNumber.from('86400'), + ? BigInt(toSeconds(auctionSettings?.auctionDuration)) + : BigInt('86400'), } const govParams = { - timelockDelay: BigNumber.from(toSeconds({ days: 2 }).toString()), - votingDelay: BigNumber.from(toSeconds(auctionSettings.votingDelay)), - votingPeriod: BigNumber.from(toSeconds(auctionSettings.votingPeriod)), + timelockDelay: BigInt(toSeconds({ days: 2 }).toString()), + votingDelay: BigInt(toSeconds(auctionSettings.votingDelay)), + votingPeriod: BigInt(toSeconds(auctionSettings.votingPeriod)), proposalThresholdBps: auctionSettings?.proposalThreshold - ? BigNumber.from( - Number((Number(auctionSettings?.proposalThreshold) * 100).toFixed(2)) - ) - : BigNumber.from('0'), + ? BigInt(Number((Number(auctionSettings?.proposalThreshold) * 100).toFixed(2))) + : BigInt('0'), quorumThresholdBps: auctionSettings?.quorumThreshold - ? BigNumber.from( - Number((Number(auctionSettings?.quorumThreshold) * 100).toFixed(2)) - ) - : BigNumber.from('0'), + ? BigInt(Number((Number(auctionSettings?.quorumThreshold) * 100).toFixed(2))) + : BigInt('0'), vetoer: vetoPower === true - ? ethers.utils.getAddress(vetoerAddress as AddressType) - : ethers.utils.getAddress(NULL_ADDRESS), + ? getAddress(vetoerAddress as AddressType) + : getAddress(NULL_ADDRESS), } const handleDeploy = async () => { @@ -147,8 +145,7 @@ export const ReviewAndDeploy: React.FC = ({ title }) => { return } - const signerAddress = await signer?.getAddress() - if (founderParams[0].wallet !== signerAddress) { + if (founderParams[0].wallet !== address) { setDeploymentError(DEPLOYMENT_ERROR.MISMATCHING_SIGNER) return } @@ -171,11 +168,10 @@ export const ReviewAndDeploy: React.FC = ({ title }) => { chainId: chain.id, abi: managerAbi, functionName: 'deploy', - signer: signer, args: [founderParams, tokenParams, auctionParams, govParams], }) - const { wait } = await writeContract(config) - transaction = await wait() + const tx = await writeContract(config) + if (tx.hash) transaction = await waitForTransaction({ hash: tx.hash }) } catch (e) { console.log('e', e) setIsPendingTransaction(false) @@ -357,7 +353,7 @@ export const ReviewAndDeploy: React.FC = ({ title }) => { handleClick={handleDeploy} w={'100%'} disabled={ - !signer || + !address || !hasConfirmedTerms || !hasConfirmedChain || isPendingTransaction diff --git a/apps/web/src/modules/create-dao/components/ReviewAndDeploy/SuccessfulDeploy.tsx b/apps/web/src/modules/create-dao/components/ReviewAndDeploy/SuccessfulDeploy.tsx index 707eac28..34ef5560 100644 --- a/apps/web/src/modules/create-dao/components/ReviewAndDeploy/SuccessfulDeploy.tsx +++ b/apps/web/src/modules/create-dao/components/ReviewAndDeploy/SuccessfulDeploy.tsx @@ -1,8 +1,8 @@ -import { prepareWriteContract, writeContract } from '@wagmi/core' import { Box, Flex, Paragraph, Text } from '@zoralabs/zord' import { useRouter } from 'next/router' import React, { useState } from 'react' -import { useContract, useContractRead, useSigner } from 'wagmi' +import { useAccount, useContractRead } from 'wagmi' +import { prepareWriteContract, waitForTransaction, writeContract } from 'wagmi/actions' import { ContractButton } from 'src/components/ContractButton' import CopyButton from 'src/components/CopyButton/CopyButton' @@ -43,15 +43,10 @@ export const SuccessfulDeploy: React.FC = ({ const { general, ipfsUpload, orderedLayers, setFulfilledSections, resetForm } = useFormStore() const chain = useChainStore((x) => x.chain) - const { data: signer } = useSigner() const { addresses, setAddresses } = useDaoStore() - const metadataContract = useContract({ - abi: metadataAbi, - address: addresses.metadata, - signerOrProvider: signer, - }) const [isPendingTransaction, setIsPendingTransaction] = useState(false) const [deploymentError, setDeploymentError] = useState() + const { address } = useAccount() const { data: tokenOwner } = useContractRead({ enabled: !!token, @@ -93,8 +88,7 @@ export const SuccessfulDeploy: React.FC = ({ return } - const signerAddress = await signer?.getAddress() - if (tokenOwner !== signerAddress) { + if (tokenOwner !== address) { setDeploymentError(DEPLOYMENT_ERROR.MISMATCHING_SIGNER) return } @@ -109,8 +103,8 @@ export const SuccessfulDeploy: React.FC = ({ chainId: chain.id, args: [transaction.names, transaction.items, transaction.data], }) - const { wait } = await writeContract(config) - await wait() + const tx = await writeContract(config) + await waitForTransaction({ hash: tx.hash }) } catch (err) { console.warn(err) setIsPendingTransaction(false) @@ -227,7 +221,7 @@ export const SuccessfulDeploy: React.FC = ({ size={'lg'} borderRadius={'curved'} className={isPendingTransaction ? deployPendingButtonStyle : undefined} - disabled={!transactions || isPendingTransaction || !metadataContract} + disabled={!transactions || isPendingTransaction} handleClick={handleDeployMetadata} w={'100%'} mt={'x8'} diff --git a/apps/web/src/modules/create-dao/utils/transformFileProperties.test.ts b/apps/web/src/modules/create-dao/utils/transformFileProperties.test.ts index 0941e166..4a8d6e71 100644 --- a/apps/web/src/modules/create-dao/utils/transformFileProperties.test.ts +++ b/apps/web/src/modules/create-dao/utils/transformFileProperties.test.ts @@ -1,4 +1,3 @@ -import { BigNumber } from 'ethers' import { describe, expect, it } from 'vitest' import { IPFSUpload } from 'src/hooks' @@ -62,7 +61,7 @@ describe('Transform Properties', () => { expect(fileProperties[0].names).toEqual([trait]) expect(fileProperties[0].items).toHaveLength(1) expect(fileProperties[0].items[0]).toEqual({ - propertyId: BigNumber.from(0), + propertyId: BigInt(0), name: ipfsUpload.name.replace('.png', ''), isNewProperty: true, }) @@ -146,25 +145,25 @@ describe('Transform Properties', () => { expect(fileProperties[0].names).toHaveLength(1) expect(fileProperties[0].items).toHaveLength(10) for (var item of fileProperties[0].items) { - expect(item.propertyId).toEqual(BigNumber.from(0)) + expect(item.propertyId).toEqual(BigInt(0)) expect(item.isNewProperty).toEqual(true) } expect(fileProperties[1].items).toHaveLength(10) expect(fileProperties[1].names).toHaveLength(1) for (var item of fileProperties[1].items.slice(0, 2)) { - expect(item.propertyId).toEqual(BigNumber.from(0)) // 0th element in the total list of names + expect(item.propertyId).toEqual(BigInt(0)) // 0th element in the total list of names expect(item.isNewProperty).toEqual(false) } for (var item of fileProperties[1].items.slice(2)) { - expect(item.propertyId).toEqual(BigNumber.from(0)) // 0th element in this transactions list of names + expect(item.propertyId).toEqual(BigInt(0)) // 0th element in this transactions list of names expect(item.isNewProperty).toEqual(true) } expect(fileProperties[2].items).toHaveLength(4) expect(fileProperties[2].names).toHaveLength(0) for (var item of fileProperties[2].items) { - expect(item.propertyId).toEqual(BigNumber.from(1)) // 1st elemenet in the total list of names + expect(item.propertyId).toEqual(BigInt(1)) // 1st elemenet in the total list of names expect(item.isNewProperty).toEqual(false) } }) diff --git a/apps/web/src/modules/create-dao/utils/transformFileProperties.ts b/apps/web/src/modules/create-dao/utils/transformFileProperties.ts index 405eabe5..0b4a8089 100644 --- a/apps/web/src/modules/create-dao/utils/transformFileProperties.ts +++ b/apps/web/src/modules/create-dao/utils/transformFileProperties.ts @@ -1,4 +1,3 @@ -import { BigNumber } from 'ethers' import { normalizeIPFSUrl } from 'ipfs-service' import { IPFSUpload } from 'src/hooks' @@ -6,7 +5,7 @@ import { IPFSUpload } from 'src/hooks' import { OrderedTraits } from '../../../components/Artwork/LayerBox' export interface PropertyItem { - propertyId: BigNumber + propertyId: bigint name: string isNewProperty: boolean } @@ -29,7 +28,7 @@ function uploadsToPropertyItems( ): PropertyItem[] { return uploads.map((upload) => { return { - propertyId: BigNumber.from(traitIndex), + propertyId: BigInt(traitIndex), name: upload.name.substring(0, upload.name.lastIndexOf('.')), isNewProperty, } diff --git a/apps/web/src/modules/create-proposal/components/ReviewProposalForm/ReviewProposalForm.tsx b/apps/web/src/modules/create-proposal/components/ReviewProposalForm/ReviewProposalForm.tsx index 8c6509cb..c21ddb5b 100644 --- a/apps/web/src/modules/create-proposal/components/ReviewProposalForm/ReviewProposalForm.tsx +++ b/apps/web/src/modules/create-proposal/components/ReviewProposalForm/ReviewProposalForm.tsx @@ -1,10 +1,10 @@ -import { prepareWriteContract, writeContract } from '@wagmi/core' import { Box, Flex } from '@zoralabs/zord' import axios from 'axios' import { Field, FieldProps, Formik } from 'formik' import { useRouter } from 'next/router' import React, { useState } from 'react' -import { useContractRead, useSigner } from 'wagmi' +import { useAccount, useContractRead } from 'wagmi' +import { prepareWriteContract, waitForTransaction, writeContract } from 'wagmi/actions' import { ContractButton } from 'src/components/ContractButton' import TextInput from 'src/components/Fields/TextInput' @@ -40,11 +40,10 @@ export const ReviewProposalForm = ({ transactions, }: ReviewProposalProps) => { const router = useRouter() - const { data: signer } = useSigner() const addresses = useDaoStore((state) => state.addresses) const chain = useChainStore((x) => x.chain) //@ts-ignore - const signerAddress = signer?._address + const { address } = useAccount() const { clearProposal } = useProposalStore() const [error, setError] = useState() @@ -56,10 +55,10 @@ export const ReviewProposalForm = ({ const { data: votes, isLoading } = useContractRead({ address: addresses?.token as AddressType, abi: tokenAbi, - enabled: !!signerAddress, + enabled: !!address, functionName: 'getVotes', chainId: chain.id, - args: [signerAddress as AddressType], + args: [address as AddressType], }) const { data: proposalThreshold, isLoading: thresholdIsLoading } = useContractRead({ @@ -75,18 +74,10 @@ export const ReviewProposalForm = ({ setSimulationError(undefined) setSimulations([]) - try { - const isWrongNetwork = - (await signer?.provider?.getCode(addresses.auction || '')) === '0x' - } catch (e) { - setError(ERROR_CODE.WRONG_NETWORK) - return - } - - if (!proposalThreshold) return + if (proposalThreshold === undefined) return - const votesToNumber = votes ? votes.toNumber() : 0 - const doesNotHaveEnoughVotes = votesToNumber <= proposalThreshold.toNumber() + const votesToNumber = votes ? Number(votes) : 0 + const doesNotHaveEnoughVotes = votesToNumber <= Number(proposalThreshold) if (doesNotHaveEnoughVotes) { setError(ERROR_CODE.NOT_ENOUGH_VOTES) return @@ -108,7 +99,7 @@ export const ReviewProposalForm = ({ treasuryAddress: addresses?.treasury, chainId: chain.id, calldatas: calldata, - values: transactionValues, + values: transactionValues.map((x) => x.toString()), targets, }) .then((res) => res.data) @@ -149,10 +140,10 @@ export const ReviewProposalForm = ({ args: [params.targets, params.values, params.calldatas, params.description], }) - const { wait } = await writeContract(config) + const { hash } = await writeContract(config) setProposing(true) - await wait() + await waitForTransaction({ hash }) router .push({ @@ -177,12 +168,13 @@ export const ReviewProposalForm = ({ setError(err.message) } }, - [signer, router, addresses, proposalThreshold, votes, clearProposal] + [router, addresses, proposalThreshold, votes, clearProposal] ) if (isLoading || thresholdIsLoading) return null - const tokensNeeded = proposalThreshold && proposalThreshold.toNumber() + 1 + const tokensNeeded = + proposalThreshold !== undefined ? Number(proposalThreshold) + 1 : undefined return ( @@ -239,7 +231,7 @@ export const ReviewProposalForm = ({ handleClick={() => formik.submitForm()} > {'Submit Proposal'} - {votes && ( + {!!votes && ( - {votes.toNumber()} Votes + {Number(votes)} Votes )} @@ -260,7 +252,7 @@ export const ReviewProposalForm = ({ - You must have {tokensNeeded}{' '} + You must have {Number(tokensNeeded)}{' '} {!!tokensNeeded && tokensNeeded > 1 ? 'votes' : 'vote'} to submit a proposal diff --git a/apps/web/src/modules/create-proposal/components/SelectTransactionType/AdminNav.tsx b/apps/web/src/modules/create-proposal/components/SelectTransactionType/AdminNav.tsx index e25d85be..7eceb641 100644 --- a/apps/web/src/modules/create-proposal/components/SelectTransactionType/AdminNav.tsx +++ b/apps/web/src/modules/create-proposal/components/SelectTransactionType/AdminNav.tsx @@ -7,6 +7,7 @@ import { Icon } from 'src/components/Icon' import { auctionAbi } from 'src/data/contract/abis' import { useDaoStore } from 'src/modules/dao' import { useChainStore } from 'src/stores/useChainStore' +import { unpackOptionalArray } from 'src/utils/helpers' const AdminNav = () => { const router = useRouter() @@ -21,13 +22,15 @@ const AdminNav = () => { enabled: !!addresses?.auction, }) + const [tokenId] = unpackOptionalArray(auction, 6) + const handleNavigation = async () => { await router.push({ pathname: `/dao/[network]/[token]/[tokenId]`, query: { network: router.query?.network, token: router.query?.token, - tokenId: auction?.tokenId?.toNumber(), + tokenId: Number(tokenId), tab: 'admin', }, }) diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/Airdrop/AirdropForm.test.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/Airdrop/AirdropForm.test.tsx index 7f36e74c..ea988785 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/Airdrop/AirdropForm.test.tsx +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/Airdrop/AirdropForm.test.tsx @@ -27,11 +27,7 @@ describe('Airdrop form with errors', () => { fireEvent.change(amountInput, { target: { value: 0 } }) fireEvent.focusOut(amountInput) - await waitFor(() => - expect( - screen.getByText('This address or ENS domain is not valid') - ).toBeInTheDocument() - ) + await waitFor(() => expect(screen.getByText('Invalid address')).toBeInTheDocument()) await waitFor(() => expect(screen.getByText('Must be at least 1 token')).toBeInTheDocument() ) diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/ABI/ABI.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/ABI/ABI.tsx index 87574086..00c34400 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/ABI/ABI.tsx +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/ABI/ABI.tsx @@ -3,7 +3,6 @@ import { ethers } from 'ethers' import React from 'react' import { useCustomTransactionStore } from 'src/modules/create-proposal' -import { useLayoutStore } from 'src/stores' import { AddressType } from 'src/typings' import { CustomTransactionForm } from '../CustomTransactionForm' @@ -11,21 +10,17 @@ import { fields, validateABI } from './fields' export const ABI = () => { const { customTransaction, composeCustomTransaction } = useCustomTransactionStore() - const { provider } = useLayoutStore() const initialValues = { transactionCustomABI: customTransaction?.customABI || '', } - const { signer } = useLayoutStore() - const submitCallback = React.useCallback( (values: { transactionCustomABI: string }) => { try { - if (!!signer && !!customTransaction.address && !!values.transactionCustomABI) { + if (customTransaction.address && values.transactionCustomABI) { const contract = new ethers.Contract( customTransaction.address, - values.transactionCustomABI || '[]', - signer + values.transactionCustomABI || '[]' ) composeCustomTransaction({ ...customTransaction, @@ -58,7 +53,7 @@ export const ABI = () => { submitCallback(values)} /> diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/ABI/fields.ts b/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/ABI/fields.ts index cfa2b5d0..81947479 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/ABI/fields.ts +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/ABI/fields.ts @@ -1,4 +1,3 @@ -import { Provider } from '@ethersproject/abstract-provider' import * as Yup from 'yup' import { TEXTAREA } from 'src/components/Fields/types' @@ -13,7 +12,7 @@ export const fields = [ }, ] -export const validateABI = (provider: Provider | undefined) => +export const validateABI = () => Yup.object().shape({ transactionCustomABI: Yup.string().test( 'isABI', diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/Summary/Summary.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/Summary/Summary.tsx index b230183a..a86e701d 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/Summary/Summary.tsx +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/CustomTransaction/forms/Summary/Summary.tsx @@ -4,7 +4,6 @@ import React from 'react' import CopyButton from 'src/components/CopyButton/CopyButton' import { useCustomTransactionStore } from 'src/modules/create-proposal' -import { useLayoutStore } from 'src/stores/useLayoutStore' import { getEnsAddress } from 'src/utils/ens' import { RAW_DATA_KEY, matchTypeParameters, normalizePathName } from 'src/utils/formABI' import { walletSnippet } from 'src/utils/helpers' @@ -19,7 +18,6 @@ interface SummaryProps { } export const Summary: React.FC = ({ setIsOpen }) => { - const { signer, provider } = useLayoutStore() const { customTransaction, composeCustomTransaction, previous } = useCustomTransactionStore() @@ -38,12 +36,11 @@ export const Summary: React.FC = ({ setIsOpen }) => { return rawData[1] } - if (!signer || !customTransaction?.contract?.abi) return + if (!customTransaction?.contract?.abi) return const contract = new ethers.Contract( customTransaction?.address, - customTransaction?.contract?.abi, - signer + customTransaction?.contract?.abi ) const args: [string, string][] = customTransaction.arguments @@ -87,7 +84,7 @@ export const Summary: React.FC = ({ setIsOpen }) => { console.error(err) return } - }, [customTransaction, signer]) + }, [customTransaction]) /* @@ -96,7 +93,7 @@ export const Summary: React.FC = ({ setIsOpen }) => { */ const handleAddTransaction = React.useCallback(async () => { - const address = await getEnsAddress(customTransaction.address, provider) + const address = await getEnsAddress(customTransaction.address) if (!calldata) { if (customTransaction.address && customTransaction.value) { composeCustomTransaction({ diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/Droposal/Droposal.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/Droposal/Droposal.tsx index c358a352..526c1a6e 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/Droposal/Droposal.tsx +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/Droposal/Droposal.tsx @@ -1,7 +1,6 @@ import { Stack } from '@zoralabs/zord' -import { BigNumber, ethers } from 'ethers' import { FormikHelpers } from 'formik' -import { useContract } from 'wagmi' +import { encodeFunctionData, parseEther } from 'viem' import { PUBLIC_ZORA_NFT_CREATOR } from 'src/constants/addresses' import { zoraNFTCreatorAbi } from 'src/data/contract/abis/ZoraNFTCreator' @@ -13,16 +12,14 @@ import { AddressType } from 'src/typings' import { DroposalForm } from './DroposalForm' import { DroposalFormValues } from './DroposalForm.schema' -const UINT_64_MAX = BigNumber.from('18446744073709551615') -const UINT_32_MAX = BigNumber.from('4294967295') +const UINT_64_MAX = BigInt('18446744073709551615') +const UINT_32_MAX = BigInt('4294967295') +const HASH_ZERO = + '0x0000000000000000000000000000000000000000000000000000000000000000' as `0x${string}` export const Droposal: React.FC = () => { const addTransaction = useProposalStore((state) => state.addTransaction) const chain = useChainStore((x) => x.chain) - const zoraNFTCreatorContract = useContract({ - abi: zoraNFTCreatorAbi, - address: chain && PUBLIC_ZORA_NFT_CREATOR[chain.id], - }) const handleDroposalTransaction = ( values: DroposalFormValues, @@ -47,37 +44,39 @@ export const Droposal: React.FC = () => { } = values const royaltyBPS = royaltyPercentage * 100 - const salesConfig = [ - ethers.utils.parseEther((publicSalePrice || 0).toString()), - maxSalePurchasePerAddress || UINT_32_MAX, - BigNumber.from(Math.floor(new Date(publicSaleStart).getTime() / 1000)), - BigNumber.from(Math.floor(new Date(publicSaleEnd).getTime() / 1000)), - 0, // presaleStart - 0, // presaleEnd - ethers.constants.HashZero, // presaleMerkleRoot - ] + const salesConfig = { + publicSalePrice: parseEther((publicSalePrice || 0).toString()), + maxSalePurchasePerAddress: maxSalePurchasePerAddress + ? maxSalePurchasePerAddress + : Number(UINT_32_MAX), + publicSaleStart: BigInt(Math.floor(new Date(publicSaleStart).getTime() / 1000)), + publicSaleEnd: BigInt(Math.floor(new Date(publicSaleEnd).getTime() / 1000)), + presaleStart: BigInt(0), // presaleStart + presaleEnd: BigInt(0), // presaleEnd + presaleMerkleRoot: HASH_ZERO, // presaleMerkleRoot + } const animationUri = mediaType?.startsWith('image') ? '' : mediaUrl const imageUri = mediaType?.startsWith('image') ? mediaUrl : coverUrl const createEdition = { target: PUBLIC_ZORA_NFT_CREATOR[chain.id] as AddressType, functionSignature: 'createEdition()', - calldata: - zoraNFTCreatorContract?.interface.encodeFunctionData( - 'createEdition(string,string,uint64,uint16,address,address,(uint104,uint32,uint64,uint64,uint64,uint64,bytes32),string,string,string)', - [ - name, - symbol, - editionSize || UINT_64_MAX, - royaltyBPS, - fundsRecipient, - defaultAdmin, - salesConfig, - description, - animationUri, - imageUri, - ] - ) || '', + calldata: encodeFunctionData({ + abi: zoraNFTCreatorAbi, + functionName: 'createEdition', + args: [ + name, + symbol, + BigInt(editionSize) || UINT_64_MAX, + royaltyBPS, + fundsRecipient as AddressType, + defaultAdmin as AddressType, + salesConfig, + description, + animationUri, + imageUri, + ], + }), value: '', } @@ -92,10 +91,7 @@ export const Droposal: React.FC = () => { return ( - + ) } diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/PauseAuctions/PauseAuctions.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/PauseAuctions/PauseAuctions.tsx index b3d00dc2..4995c89c 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/PauseAuctions/PauseAuctions.tsx +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/PauseAuctions/PauseAuctions.tsx @@ -1,5 +1,6 @@ import { Box, Button, Paragraph } from '@zoralabs/zord' -import { useContract, useContractRead } from 'wagmi' +import { encodeFunctionData } from 'viem' +import { useContractRead } from 'wagmi' import { auctionAbi } from 'src/data/contract/abis' import { TransactionType } from 'src/modules/create-proposal/constants' @@ -12,7 +13,6 @@ export const PauseAuctions = () => { const { auction } = useDaoStore((state) => state.addresses) const addTransaction = useProposalStore((state) => state.addTransaction) const chain = useChainStore((x) => x.chain) - const auctionContract = useContract({ abi: auctionAbi, address: auction }) const { data: paused } = useContractRead({ abi: auctionAbi, address: auction, @@ -24,7 +24,10 @@ export const PauseAuctions = () => { const pause = { target: auction as AddressType, functionSignature: 'pause()', - calldata: auctionContract?.interface.encodeFunctionData('pause') || '', + calldata: encodeFunctionData({ + abi: auctionAbi, + functionName: 'pause', + }), value: '', } @@ -56,7 +59,7 @@ export const PauseAuctions = () => { w={'100%'} type="button" onClick={handlePauseAuctionsTransaction} - disabled={paused || typeof auctionContract === 'undefined'} + disabled={paused} > Add Transaction to Queue diff --git a/apps/web/src/modules/create-proposal/components/TransactionForm/SendEth/SendEth.tsx b/apps/web/src/modules/create-proposal/components/TransactionForm/SendEth/SendEth.tsx index e174a664..31206e76 100644 --- a/apps/web/src/modules/create-proposal/components/TransactionForm/SendEth/SendEth.tsx +++ b/apps/web/src/modules/create-proposal/components/TransactionForm/SendEth/SendEth.tsx @@ -1,7 +1,7 @@ import { Box, Button, Flex } from '@zoralabs/zord' -import { ethers } from 'ethers' import { Form, Formik } from 'formik' import type { FormikHelpers } from 'formik' +import { getAddress } from 'viem' import { useBalance } from 'wagmi' import { Icon } from 'src/components/Icon' @@ -47,7 +47,7 @@ export const SendEth = () => { transactions: [ { functionSignature: 'sendEth(address)', - target: ethers.utils.getAddress(target), + target: getAddress(target), value, calldata: '0x', }, diff --git a/apps/web/src/modules/create-proposal/hooks/useAvailableUpgrade.ts b/apps/web/src/modules/create-proposal/hooks/useAvailableUpgrade.ts index 48c33034..b10aae4d 100644 --- a/apps/web/src/modules/create-proposal/hooks/useAvailableUpgrade.ts +++ b/apps/web/src/modules/create-proposal/hooks/useAvailableUpgrade.ts @@ -1,11 +1,11 @@ -import { Contract } from 'ethers' import intersection from 'lodash/intersection' import isNil from 'lodash/isNil' import isUndefined from 'lodash/isUndefined' import lt from 'lodash/lt' import pickBy from 'lodash/pickBy' import useSWR from 'swr' -import { useContract, useContractReads } from 'wagmi' +import { encodeFunctionData } from 'viem' +import { useContractReads } from 'wagmi' import { PUBLIC_MANAGER_ADDRESS } from 'src/constants/addresses' import SWR_KEYS from 'src/constants/swrKeys' @@ -55,16 +55,13 @@ export const useAvailableUpgrade = ({ chainId, } - const auctionContract = useContract({ abi: auctionAbi, address: addresses?.auction }) - - const managerContract = useContract(contract) - const { data: proposals } = useSWR( !!addresses?.token ? [SWR_KEYS.PROPOSALS_CALLDATAS, chainId, addresses?.token] : null, () => getProposals(chainId, addresses?.token as string, 100) ) const { data, isLoading, isError } = useContractReads({ + allowFailure: false, enabled: !!addresses?.token, contracts: [ { @@ -168,26 +165,28 @@ export const useAvailableUpgrade = ({ } } - const withPauseUnpause = ( - paused: boolean, - upgrades: Transaction[], - auctionContract?: Contract - ): Transaction[] => { - if (paused || typeof auctionContract === undefined) { + const withPauseUnpause = (paused: boolean, upgrades: Transaction[]): Transaction[] => { + if (paused) { return upgrades } const pause = { target: addresses?.auction as AddressType, functionSignature: 'pause()', - calldata: auctionContract?.interface.encodeFunctionData('pause') || '', + calldata: encodeFunctionData({ + abi: auctionAbi, + functionName: 'pause', + }), value: '', } const unpause = { target: addresses?.auction as AddressType, functionSignature: 'unpause()', - calldata: auctionContract?.interface.encodeFunctionData('unpause') || '', + calldata: encodeFunctionData({ + abi: auctionAbi, + functionName: 'unpause', + }), value: '', } @@ -195,17 +194,17 @@ export const useAvailableUpgrade = ({ } const createUpgradeTransactions = ( - upgrades: Record, - managerContract?: Contract + upgrades: Record ): Transaction[] => Object.keys(upgrades).map((contract) => ({ value: '', target: addresses[contract as ContractType] as AddressType, functionSignature: 'upgradeTo(address)', - calldata: - managerContract?.interface?.encodeFunctionData('upgradeTo(address)', [ - managerImplementationAddresses[contract as ContractType], - ]) || '', + calldata: encodeFunctionData({ + abi: managerAbi, + functionName: 'upgradeTo', + args: [managerImplementationAddresses[contract as ContractType]], + }), })) const findActiveUpgradeProposal = ( @@ -231,10 +230,7 @@ export const useAvailableUpgrade = ({ const upgradesNeededForLatestVersion = getUpgradesForVersion(daoVersions, latest) - const upgradeTransactions = createUpgradeTransactions( - upgradesNeededForLatestVersion, - managerContract ?? undefined - ) + const upgradeTransactions = createUpgradeTransactions(upgradesNeededForLatestVersion) const activeUpgradeProposal = findActiveUpgradeProposal( proposals?.proposals, @@ -246,11 +242,7 @@ export const useAvailableUpgrade = ({ const upgrade = { type: TransactionType.UPGRADE, summary: `Upgrade contracts to Nouns Builder v${latest}`, - transactions: withPauseUnpause( - paused, - upgradeTransactions, - auctionContract ?? undefined - ), + transactions: withPauseUnpause(paused, upgradeTransactions), } return { diff --git a/apps/web/src/modules/create-proposal/utils/prepareTransactions.ts b/apps/web/src/modules/create-proposal/utils/prepareTransactions.ts index 9c8f6c33..93ac2f2d 100644 --- a/apps/web/src/modules/create-proposal/utils/prepareTransactions.ts +++ b/apps/web/src/modules/create-proposal/utils/prepareTransactions.ts @@ -1,4 +1,4 @@ -import { BigNumber, utils } from 'ethers' +import { parseEther } from 'viem' import { AddressType } from 'src/typings' @@ -7,7 +7,7 @@ import { BuilderTransaction } from '../stores/useProposalStore' interface ProposalTransactions { calldata: string[] targets: AddressType[] - values: BigNumber[] + values: bigint[] } export const prepareProposalTransactions = ( @@ -20,7 +20,7 @@ export const prepareProposalTransactions = ( const values = flattenedTransactions.map((txn) => { const value = !txn.value ? '0' : txn.value - return utils.parseEther(value.toString()) + return parseEther(value.toString()) }) return { calldata, targets, values } diff --git a/apps/web/src/modules/dao/components/About/About.tsx b/apps/web/src/modules/dao/components/About/About.tsx index 3435522d..b4aadc6a 100644 --- a/apps/web/src/modules/dao/components/About/About.tsx +++ b/apps/web/src/modules/dao/components/About/About.tsx @@ -49,6 +49,7 @@ export const About: React.FC = () => { } const { data: contractData } = useContractReads({ + allowFailure: false, contracts: [ { ...tokenContractParams, functionName: 'name' }, { ...tokenContractParams, functionName: 'totalSupply' }, @@ -137,7 +138,7 @@ export const About: React.FC = () => { address={treasury} /> - + Chain @@ -182,7 +183,7 @@ export const About: React.FC = () => { No founders allocation set. )} - + ) } diff --git a/apps/web/src/modules/dao/components/Activity/Activity.tsx b/apps/web/src/modules/dao/components/Activity/Activity.tsx index 2101127a..2dcfbbf5 100644 --- a/apps/web/src/modules/dao/components/Activity/Activity.tsx +++ b/apps/web/src/modules/dao/components/Activity/Activity.tsx @@ -108,7 +108,7 @@ export const Activity: React.FC = () => { )} {isOwner && !hasThreshold && !isMobile && ( - {proposalVotesRequired} votes required to propose. + {Number(proposalVotesRequired)} votes required to propose. )} {isOwner || isDelegating ? ( diff --git a/apps/web/src/modules/dao/components/Activity/DelegateForm.tsx b/apps/web/src/modules/dao/components/Activity/DelegateForm.tsx index ddabfb2d..94b04a1b 100644 --- a/apps/web/src/modules/dao/components/Activity/DelegateForm.tsx +++ b/apps/web/src/modules/dao/components/Activity/DelegateForm.tsx @@ -1,14 +1,13 @@ -import { prepareWriteContract, writeContract } from '@wagmi/core' import { Box, Button, Flex } from '@zoralabs/zord' import { Field, Formik, Form as FormikForm } from 'formik' import React, { useState } from 'react' -import { Address, useContract, useSigner } from 'wagmi' +import { Address } from 'wagmi' +import { prepareWriteContract, waitForTransaction, writeContract } from 'wagmi/actions' import { ContractButton } from 'src/components/ContractButton' import SmartInput from 'src/components/Fields/SmartInput' import { Icon } from 'src/components/Icon' import { tokenAbi } from 'src/data/contract/abis' -import { useLayoutStore } from 'src/stores' import { useChainStore } from 'src/stores/useChainStore' import { proposalFormTitle } from 'src/styles/Proposals.css' import { getEnsAddress } from 'src/utils/ens' @@ -28,22 +27,14 @@ interface DelegateFormProps { export const DelegateForm = ({ handleBack, handleUpdate }: DelegateFormProps) => { const [isLoading, setIsLoading] = useState(false) const { addresses } = useDaoStore() - const { provider } = useLayoutStore() const chain = useChainStore((x) => x.chain) - const { data: signer } = useSigner() - - const tokenContract = useContract({ - abi: tokenAbi, - address: addresses.token, - signerOrProvider: signer, - }) const submitCallback = async (values: AddressFormProps) => { if (!values.address || !addresses.token) return setIsLoading(true) try { - const delegate = (await getEnsAddress(values.address, provider)) as Address + const delegate = (await getEnsAddress(values.address)) as Address const config = await prepareWriteContract({ abi: tokenAbi, address: addresses.token, @@ -51,8 +42,8 @@ export const DelegateForm = ({ handleBack, handleUpdate }: DelegateFormProps) => functionName: 'delegate', args: [delegate], }) - const txn = await writeContract(config) - await txn?.wait() + const { hash } = await writeContract(config) + await waitForTransaction({ hash }) handleUpdate(values.address) } catch (e) { @@ -113,7 +104,7 @@ export const DelegateForm = ({ handleBack, handleUpdate }: DelegateFormProps) => submitCallback(values) }} style={{ flex: 'auto' }} - disabled={!dirty || !isValid || !tokenContract} + disabled={!dirty || !isValid} size="lg" > Update delegate diff --git a/apps/web/src/modules/dao/components/Activity/Treasury.tsx b/apps/web/src/modules/dao/components/Activity/Treasury.tsx index 33fb4941..05058442 100644 --- a/apps/web/src/modules/dao/components/Activity/Treasury.tsx +++ b/apps/web/src/modules/dao/components/Activity/Treasury.tsx @@ -1,7 +1,7 @@ import { Box, Flex, Grid, Text } from '@zoralabs/zord' -import { BigNumber, ethers } from 'ethers' import React from 'react' import useSWR from 'swr' +import { formatEther } from 'viem' import { useBalance } from 'wagmi' import SWR_KEYS from 'src/constants/swrKeys' @@ -36,7 +36,7 @@ export const Treasury = () => { SDK.connect(chainId) .totalAuctionSales({ tokenAddress: addresses.token?.toLowerCase() as string }) .then((x) => - x.dao?.totalAuctionSales ? ethers.utils.formatEther(x.dao.totalAuctionSales) : 0 + x.dao?.totalAuctionSales ? formatEther(x.dao.totalAuctionSales) : 0 ) ) @@ -44,8 +44,8 @@ export const Treasury = () => { const ethToUsd = React.useMemo(() => { if (!balance) return 0 - const wei = BigNumber.from(balance.value?._hex) - const eth = ethers.utils.formatEther(wei) + const wei = balance.value + const eth = formatEther(wei) const usd = ((eth as any) * ethUsd).toFixed(2) const usdFormatted = numberFormatter(usd) return usdFormatted diff --git a/apps/web/src/modules/dao/components/AdminForm/AdminForm.schema.ts b/apps/web/src/modules/dao/components/AdminForm/AdminForm.schema.ts index 44f906db..ead8ad6d 100644 --- a/apps/web/src/modules/dao/components/AdminForm/AdminForm.schema.ts +++ b/apps/web/src/modules/dao/components/AdminForm/AdminForm.schema.ts @@ -1,4 +1,3 @@ -import { Provider } from '@ethersproject/abstract-provider' import * as Yup from 'yup' import { TokenAllocation, auctionSettingsValidationSchema } from 'src/modules/create-dao' @@ -29,7 +28,7 @@ export interface AdminFormValues { const twentyFourWeeks = 60 * 60 * 24 * 7 * 24 const tenMinutes = 60 * 10 -export const adminValidationSchema = (provider: Provider | undefined) => +export const adminValidationSchema = () => Yup.object() .concat(auctionSettingsValidationSchema) .concat( diff --git a/apps/web/src/modules/dao/components/AdminForm/AdminForm.tsx b/apps/web/src/modules/dao/components/AdminForm/AdminForm.tsx index cc39502a..206de288 100644 --- a/apps/web/src/modules/dao/components/AdminForm/AdminForm.tsx +++ b/apps/web/src/modules/dao/components/AdminForm/AdminForm.tsx @@ -5,7 +5,8 @@ import { AnimatePresence, motion } from 'framer-motion' import isEqual from 'lodash/isEqual' import { useRouter } from 'next/router' import React, { BaseSyntheticEvent } from 'react' -import { Address, useContract, useContractReads } from 'wagmi' +import { encodeFunctionData } from 'viem' +import { Address, useContractReads } from 'wagmi' import DaysHoursMinsSecs from 'src/components/Fields/DaysHoursMinsSecs' import Radio from 'src/components/Fields/Radio' @@ -23,14 +24,13 @@ import { useProposalStore, } from 'src/modules/create-proposal' import { formValuesToTransactionMap } from 'src/modules/dao/utils/adminFormFieldToTransaction' -import { useLayoutStore } from 'src/stores' import { useChainStore } from 'src/stores/useChainStore' import { sectionWrapperStyle } from 'src/styles/dao.css' import { AddressType } from 'src/typings' import { getEnsAddress } from 'src/utils/ens' import { compareAndReturn, fromSeconds, unpackOptionalArray } from 'src/utils/helpers' -import { DaoContracts, useDaoStore } from '../../stores' +import { useDaoStore } from '../../stores' import { AdminFormValues, adminValidationSchema } from './AdminForm.schema' import { AdminFounderAllocationFields } from './AdminFounderAllocationFields' import { Section } from './Section' @@ -54,12 +54,11 @@ export const AdminForm: React.FC = ({ collectionAddress }) => { const createProposal = useProposalStore((state) => state.createProposal) const addresses = useDaoStore((state) => state.addresses) - const provider = useLayoutStore((state) => state.provider) const chain = useChainStore((x) => x.chain) const auctionContractParams = { abi: auctionAbi, - address: addresses.auction, + address: addresses.auction as Address, } const governorContractParams = { @@ -77,12 +76,8 @@ export const AdminForm: React.FC = ({ collectionAddress }) => { address: addresses?.token as Address, } - const auctionContract = useContract(auctionContractParams) - const governorContract = useContract(governorContractParams) - const metadataContract = useContract(metadataContractParams) - const tokenContract = useContract(tokenContractParams) - const { data } = useContractReads({ + allowFailure: false, contracts: [ { ...auctionContractParams, chainId: chain.id, functionName: 'duration' }, { ...auctionContractParams, chainId: chain.id, functionName: 'reservePrice' }, @@ -122,13 +117,6 @@ export const AdminForm: React.FC = ({ collectionAddress }) => { founders, ] = unpackOptionalArray(data, 12) - const contracts: DaoContracts = { - auctionContract: auctionContract ?? undefined, - governorContract: governorContract ?? undefined, - metadataContract: metadataContract ?? undefined, - tokenContract: tokenContract ?? undefined, - } - const initialValues: AdminFormValues = { /* artwork */ projectDescription: description?.replace(/\\n/g, String.fromCharCode(13, 10)) || '', @@ -142,8 +130,8 @@ export const AdminForm: React.FC = ({ collectionAddress }) => { /* governor */ proposalThreshold: Number(proposalThresholdBps) / 100 || 0, quorumThreshold: Number(quorumVotesBps) / 100 || 0, - votingPeriod: fromSeconds(votingPeriod && Number(votingPeriod)), - votingDelay: fromSeconds(votingDelay && Number(votingDelay)), + votingPeriod: fromSeconds(votingPeriod && BigInt(votingPeriod)), + votingDelay: fromSeconds(votingDelay && BigInt(votingDelay)), founderAllocation: founders?.map((x) => ({ founderAddress: x.wallet, @@ -179,7 +167,10 @@ export const AdminForm: React.FC = ({ collectionAddress }) => { { functionSignature: 'pause()', target: auctionAddress, - calldata: auctionContract?.interface.encodeFunctionData('pause') || '', + calldata: encodeFunctionData({ + abi: auctionAbi, + functionName: 'pause', + }), value: '', }, ], @@ -215,7 +206,7 @@ export const AdminForm: React.FC = ({ collectionAddress }) => { } if (field === 'vetoer') { - value = await getEnsAddress(value as string, provider) + value = await getEnsAddress(value as string) } if (field === 'founderAllocation') { @@ -268,8 +259,7 @@ export const AdminForm: React.FC = ({ collectionAddress }) => { const transactionsWithPauseUnpause = withPauseUnpause( transactions, - addresses?.auction as Address, - auctionContract ?? undefined + addresses?.auction as Address ) createProposal({ @@ -287,7 +277,7 @@ export const AdminForm: React.FC = ({ collectionAddress }) => { handleUpdateSettings(values, formik) } diff --git a/apps/web/src/modules/dao/components/Explore/ExploreMyDaos.tsx b/apps/web/src/modules/dao/components/Explore/ExploreMyDaos.tsx index 79744f60..abc9a437 100644 --- a/apps/web/src/modules/dao/components/Explore/ExploreMyDaos.tsx +++ b/apps/web/src/modules/dao/components/Explore/ExploreMyDaos.tsx @@ -2,10 +2,10 @@ import { Grid } from '@zoralabs/zord' import { ethers } from 'ethers' import React from 'react' import useSWR from 'swr' +import { useAccount } from 'wagmi' import SWR_KEYS from 'src/constants/swrKeys' import { userDaosFilter } from 'src/data/subgraph/requests/exploreQueries' -import { useLayoutStore } from 'src/stores' import { useChainStore } from 'src/stores/useChainStore' import { DaoCard } from '../DaoCard' @@ -15,14 +15,12 @@ import { ExploreSkeleton } from './ExploreSkeleton' import ExploreToolbar from './ExploreToolbar' export const ExploreMyDaos = () => { - const signerAddress = useLayoutStore((state) => state.signerAddress) + const { address } = useAccount() const chain = useChainStore((x) => x.chain) const { data, error, isValidating } = useSWR( - signerAddress - ? [chain.id, SWR_KEYS.DYNAMIC.MY_DAOS_PAGE(signerAddress as string)] - : null, - () => userDaosFilter(chain.id, signerAddress as string), + address ? [chain.id, SWR_KEYS.DYNAMIC.MY_DAOS_PAGE(address as string)] : null, + () => userDaosFilter(chain.id, address as string), { revalidateOnFocus: false } ) diff --git a/apps/web/src/modules/dao/components/Explore/ExploreToolbar.tsx b/apps/web/src/modules/dao/components/Explore/ExploreToolbar.tsx index 2fa99aba..943b376a 100644 --- a/apps/web/src/modules/dao/components/Explore/ExploreToolbar.tsx +++ b/apps/web/src/modules/dao/components/Explore/ExploreToolbar.tsx @@ -2,8 +2,7 @@ import { Box, Flex, Text, vars } from '@zoralabs/zord' import Link from 'next/link' import { useRouter } from 'next/router' import React from 'react' - -import { useLayoutStore } from 'src/stores/useLayoutStore' +import { useAccount } from 'wagmi' import ExploreSortMenu from './ExploreSortMenu' @@ -14,13 +13,13 @@ interface ExploreToolbarProps { const ExploreToolbar: React.FC = ({ title, showSort = false }) => { const router = useRouter() - const signerAddress = useLayoutStore((state) => state.signerAddress) + const { address } = useAccount() return ( @@ -32,7 +31,7 @@ const ExploreToolbar: React.FC = ({ title, showSort = false )} - {signerAddress && ( + {address && ( <> diff --git a/apps/web/src/modules/dao/components/PreAuction.tsx b/apps/web/src/modules/dao/components/PreAuction.tsx index f232bbba..d061a80a 100644 --- a/apps/web/src/modules/dao/components/PreAuction.tsx +++ b/apps/web/src/modules/dao/components/PreAuction.tsx @@ -1,12 +1,14 @@ -import { readContract } from '@wagmi/core' import { Box, Button, Flex, atoms } from '@zoralabs/zord' import Link from 'next/link' import { useRouter } from 'next/router' import React, { useState } from 'react' -import { useContractWrite, usePrepareContractWrite, useSigner } from 'wagmi' +import { useAccount, useContractWrite, usePrepareContractWrite } from 'wagmi' +import { readContract } from 'wagmi/actions' +import { waitForTransaction } from 'wagmi/actions' import { auctionAbi } from 'src/data/contract/abis' import { Chain } from 'src/typings' +import { unpackOptionalArray } from 'src/utils/helpers' import { useDaoStore } from '../stores' import { @@ -23,7 +25,7 @@ interface PreAuctionProps { export const PreAuction: React.FC = ({ chain, collectionAddress }) => { const router = useRouter() - const { data: signer } = useSigner() + const { address } = useAccount() const { addresses } = useDaoStore() const [isLoading, setIsLoading] = useState(false) @@ -32,7 +34,6 @@ export const PreAuction: React.FC = ({ chain, collectionAddress abi: auctionAbi, address: addresses.auction, functionName: 'unpause', - signer: signer, chainId: chain.id, }) @@ -42,8 +43,8 @@ export const PreAuction: React.FC = ({ chain, collectionAddress const handleStartAuction = async () => { setIsLoading(true) try { - const txn = await writeAsync?.() - await txn?.wait() + const tx = await writeAsync?.() + if (tx?.hash) await waitForTransaction({ hash: tx.hash }) setIsLoading(false) } catch (e) { console.error(e) @@ -58,7 +59,7 @@ export const PreAuction: React.FC = ({ chain, collectionAddress chainId: chain.id, }) - const tokenId = auction?.tokenId?.toString() + const [tokenId] = unpackOptionalArray(auction, 6) router.push(`/dao/${router.query.network}/${collectionAddress}/${tokenId}`) } @@ -66,7 +67,7 @@ export const PreAuction: React.FC = ({ chain, collectionAddress