From 353d7069da6b7f6a183065a40b2d58eccbde8370 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 02:36:52 +0530 Subject: [PATCH 01/47] refactor: Update launch store to include my staking contracts --- apps/launch/store/launch.ts | 20 +++++++++++++++++--- apps/launch/types/index.ts | 6 ++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/apps/launch/store/launch.ts b/apps/launch/store/launch.ts index 811cacbe..5bc7aa74 100644 --- a/apps/launch/store/launch.ts +++ b/apps/launch/store/launch.ts @@ -1,16 +1,30 @@ +import { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -interface LaunchState {} +import { MyStakingContract } from 'types/index'; -const initialState: LaunchState = {}; +type LaunchState = { + isMyStakingContractsLoading: boolean; + /** list of my staking contract */ + myStakingContracts: MyStakingContract[]; +}; + +const initialState: LaunchState = { + isMyStakingContractsLoading: true, + myStakingContracts: [], +}; export const launchSlice = createSlice({ name: 'launch', initialState, reducers: { + setStakingContracts: (state, action: PayloadAction) => { + state.myStakingContracts = action.payload; + state.isMyStakingContractsLoading = false; + }, clearState: (state) => {}, }, }); -export const { clearState } = launchSlice.actions; +export const { setStakingContracts, clearState } = launchSlice.actions; export const launchReducer = launchSlice.reducer; diff --git a/apps/launch/types/index.ts b/apps/launch/types/index.ts index e69de29b..a027cd2a 100644 --- a/apps/launch/types/index.ts +++ b/apps/launch/types/index.ts @@ -0,0 +1,6 @@ +export type MyStakingContract = { + name: string; + description: string; + template: string; + isNominated: boolean; +}; From 2fa474b9aba782bac129b12e2ed585dd0cea2d2b Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 03:57:23 +0530 Subject: [PATCH 02/47] refactor: Update import paths for components and hooks in autonolas-registry tests and common-util --- .../components/Layout/styles.jsx | 17 ++++++++++++++++- libs/ui-theme/src/lib/GlobalStyles.tsx | 19 +++++++++++-------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/apps/autonolas-registry/components/Layout/styles.jsx b/apps/autonolas-registry/components/Layout/styles.jsx index 689359f1..86666200 100644 --- a/apps/autonolas-registry/components/Layout/styles.jsx +++ b/apps/autonolas-registry/components/Layout/styles.jsx @@ -1,5 +1,6 @@ -import styled from 'styled-components'; import { Layout } from 'antd'; +import styled from 'styled-components'; + import { COLOR, MEDIA_QUERY } from '@autonolas/frontend-library'; export const CustomLayout = styled(Layout)` @@ -29,6 +30,20 @@ export const CustomLayout = styled(Layout)` } } + /* table */ + .ant-table { + .ant-table-tbody > tr { + > td { + padding: 8px 16px; + .ant-btn { + &:first-child { + padding-left: 0; + } + } + } + } + } + ${MEDIA_QUERY.tabletL} { .site-layout { padding: 0 24px; diff --git a/libs/ui-theme/src/lib/GlobalStyles.tsx b/libs/ui-theme/src/lib/GlobalStyles.tsx index ebf85488..3515e212 100644 --- a/libs/ui-theme/src/lib/GlobalStyles.tsx +++ b/libs/ui-theme/src/lib/GlobalStyles.tsx @@ -84,6 +84,12 @@ export const GlobalStyles = createGlobalStyle` .pl-0 { padding-left: 0px !important; } + .pt-24 { + padding-top: 24px; + } + .pt-48 { + padding-top: 48px; + } .text-start { text-align: start; @@ -91,7 +97,7 @@ export const GlobalStyles = createGlobalStyle` .text-center { text-align: center; } - .text-end { + .text-end { text-align: end; } @@ -151,6 +157,8 @@ export const GlobalStyles = createGlobalStyle` .ant-table-thead { > tr > th { padding: 12px 16px; + color: #4d596a; // TODO: move to theme + background-color: #f2f4f9; // TODO: move to theme &:not(:last-child):not(.ant-table-selection-column):not( .ant-table-row-expand-icon-cell ):not([colspan])::before { @@ -161,11 +169,6 @@ export const GlobalStyles = createGlobalStyle` .ant-table-tbody > tr { > td { padding: 8px 16px; - .ant-btn { - &:first-child { - padding-left: 0; - } - } } &:last-child { td { @@ -216,11 +219,11 @@ export const GlobalStyles = createGlobalStyle` } .next-error-h1 { - color: ${COLOR.BLACK}; + color: ${COLOR.BLACK}; border-color: ${COLOR.BLACK} !important; + div { color: ${COLOR.BLACK}; - } + } } ${MEDIA_QUERY.mobileL} { From 09b03a2ee6cb9bd8606b8b3e48e3198aa854b89f Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 04:15:57 +0530 Subject: [PATCH 03/47] refactor: Remove unnecessary CSS padding in GlobalStyles.tsx --- libs/ui-theme/src/lib/GlobalStyles.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/libs/ui-theme/src/lib/GlobalStyles.tsx b/libs/ui-theme/src/lib/GlobalStyles.tsx index 3515e212..0f2d5481 100644 --- a/libs/ui-theme/src/lib/GlobalStyles.tsx +++ b/libs/ui-theme/src/lib/GlobalStyles.tsx @@ -167,9 +167,6 @@ export const GlobalStyles = createGlobalStyle` } } .ant-table-tbody > tr { - > td { - padding: 8px 16px; - } &:last-child { td { &:first-child { From b86c423b5fb8bca463b34edd1ffa68a6c241e191 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 04:16:13 +0530 Subject: [PATCH 04/47] feat: Add dummy data for my staking contracts in launch store --- apps/launch/store/launch.ts | 24 ++++++++++++++++++++++-- apps/launch/types/index.ts | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/apps/launch/store/launch.ts b/apps/launch/store/launch.ts index 5bc7aa74..2c714257 100644 --- a/apps/launch/store/launch.ts +++ b/apps/launch/store/launch.ts @@ -9,9 +9,29 @@ type LaunchState = { myStakingContracts: MyStakingContract[]; }; +const dummyMyStakingContracts: MyStakingContract[] = [ + { + id: '1', + name: 'Contract #1 Create Prediction Market Modernized', + description: + 'This is the very long description of the contract that targets governors and explains the value of the contract to them. This is the very long description of the contract that targets governors and explains the value of the contract to them.', + template: 'Create Prediction Markets', + isNominated: true, + }, + { + id: '2', + name: 'Contract #2 Create Prediction Market Modernized', + description: + 'lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + template: 'Create Prediction Markets', + isNominated: false, + }, +]; + const initialState: LaunchState = { - isMyStakingContractsLoading: true, - myStakingContracts: [], + isMyStakingContractsLoading: false, + myStakingContracts: dummyMyStakingContracts, + // myStakingContracts: [], }; export const launchSlice = createSlice({ diff --git a/apps/launch/types/index.ts b/apps/launch/types/index.ts index a027cd2a..7bac4428 100644 --- a/apps/launch/types/index.ts +++ b/apps/launch/types/index.ts @@ -1,4 +1,5 @@ export type MyStakingContract = { + id: string; // TODO: check if possible name: string; description: string; template: string; From 88ff22771639421b75b26801774a7ec8e835c1cd Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 04:16:31 +0530 Subject: [PATCH 05/47] refactor: Update MyStakingContracts component to include loading state and create contract functionality --- .../components/MyStakingContracts/index.tsx | 85 +++++++++++++------ 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/apps/launch/components/MyStakingContracts/index.tsx b/apps/launch/components/MyStakingContracts/index.tsx index 82684f3e..a6b6bf80 100644 --- a/apps/launch/components/MyStakingContracts/index.tsx +++ b/apps/launch/components/MyStakingContracts/index.tsx @@ -1,5 +1,5 @@ import { TableOutlined, WalletOutlined } from '@ant-design/icons'; -import { Button, Card, Flex, Typography } from 'antd'; +import { Button, Card, Flex, Spin, Typography } from 'antd'; import Link from 'next/link'; import { useRouter } from 'next/router'; import styled from 'styled-components'; @@ -13,6 +13,7 @@ import { URL } from 'common-util/constants/urls'; import { useAppSelector } from 'store/index'; import { LoginV2 } from '../Login'; +import { List } from './List'; const { Title, Paragraph } = Typography; @@ -21,47 +22,78 @@ const ICON_STYLE = { fontSize: '56px', color: '#A3AEBB' }; const StyledMain = styled.main` display: flex; flex-direction: column; - max-width: 1000px; + max-width: 1200px; margin: 0 auto; `; +const Loader = () => ( + + + +); + const ConnectWallet = () => { return ( - - - - Connect your wallet to allocate your voting power. - - - + <> + + + + + Connect your wallet to allocate your voting power. + + + + ); }; -const StakingContractList = () => { +const CreateContractMessage = () => ( + + Create staking contracts to get agents running in your ecosystem. + +); + +const CreateContractButton = () => { const router = useRouter(); const { networkName } = useAppSelector((state) => state.network); - console.log('networkName', `${networkName}/${URL.myStakingContracts}/create`); return ( + + ); +}; + +const CreateStakingContractMessage = () => ( + <> + You haven’t created any staking contracts yet. - + + +); + +const StakingContractList = () => { + const { isMyStakingContractsLoading, myStakingContracts } = useAppSelector( + (state) => state.launch, ); + + if (isMyStakingContractsLoading) return ; + if (myStakingContracts.length === 0) return ; + return ; }; export const MyStakingContracts = () => { - const { networkId } = useAppSelector((state) => state.network); - const { isConnected: isAccountConnected } = useAccount(); + const { networkId } = useAppSelector((state) => state.network); + const { myStakingContracts } = useAppSelector((state) => state.launch); return ( @@ -71,16 +103,15 @@ export const MyStakingContracts = () => { - - My staking contracts - {isAccountConnected && networkId && <> on {CHAIN_NAMES[networkId]}</>} - + + + My staking contracts + {isAccountConnected && networkId && <> on {CHAIN_NAMES[networkId]}</>} + - - Create staking contracts to get agents running in your ecosystem. - + {myStakingContracts.length > 0 && } + - {/* TODO: Tanya to add staking contracts list */} {match(isAccountConnected) .with(true, () => ) .with(false, () => ) From 6c111c3731f32ea7d1a99f8ec7d734f68acedffe Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 04:16:41 +0530 Subject: [PATCH 06/47] feat: Add MyStakingContracts/List component for displaying staking contracts --- .../components/MyStakingContracts/List.tsx | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 apps/launch/components/MyStakingContracts/List.tsx diff --git a/apps/launch/components/MyStakingContracts/List.tsx b/apps/launch/components/MyStakingContracts/List.tsx new file mode 100644 index 00000000..ab211751 --- /dev/null +++ b/apps/launch/components/MyStakingContracts/List.tsx @@ -0,0 +1,93 @@ +import { InfoCircleOutlined } from '@ant-design/icons'; +import { Alert, Button, Flex, Table, Tooltip, Typography } from 'antd'; +import type { TableProps } from 'antd'; +import Link from 'next/link'; +import React, { FC, useMemo } from 'react'; + +import { URL } from 'common-util/constants/urls'; +import { useAppSelector } from 'store/index'; +import { MyStakingContract } from 'types/index'; + +const { Paragraph } = Typography; + +const useColumns = () => { + const { networkName } = useAppSelector((state) => state.network); + + const columns: TableProps['columns'] = useMemo( + () => [ + { + title: 'Name', + dataIndex: 'name', + key: 'name', + width: '25%', + render: (text, record) => ( + + {text} + + ), + }, + { + title: 'Description', + dataIndex: 'description', + key: 'description', + width: '25%', + render: (text) => ( + + {text} + + ), + }, + { + title: 'Template', + dataIndex: 'template', + key: 'template', + width: '25%', + }, + { + title: ( + <> + Nominated for incentives?  + + + + + ), + key: 'action', + width: '25%', + render: (_, record) => ( + + ), + }, + ], + [networkName], + ); + + return columns; +}; + +export const List: FC = () => { + const { myStakingContracts } = useAppSelector((state) => state.launch); + const listColumns = useColumns(); + + const nonNominatedContracts = myStakingContracts.filter( + (contract) => !contract.isNominated, + ).length; + + return ( + + {nonNominatedContracts > 0 && ( + + )} + + + + ); +}; From ddc39499d7138888ec9503e0ac633ee76d785d8d Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 04:26:02 +0530 Subject: [PATCH 07/47] refactor: Update URL constant for my-staking-contracts and add popover for staking incentives --- apps/launch/common-util/constants/urls.ts | 2 + .../components/MyStakingContracts/List.tsx | 39 +++++++++++++------ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/apps/launch/common-util/constants/urls.ts b/apps/launch/common-util/constants/urls.ts index 54afeec4..b03bcaa6 100644 --- a/apps/launch/common-util/constants/urls.ts +++ b/apps/launch/common-util/constants/urls.ts @@ -5,3 +5,5 @@ export const URL = { paths: 'paths', pageNotFound: 'page-not-found', }; + +export const GOVERN_URL = 'https://govern.olas.network'; \ No newline at end of file diff --git a/apps/launch/components/MyStakingContracts/List.tsx b/apps/launch/components/MyStakingContracts/List.tsx index ab211751..c308f9a7 100644 --- a/apps/launch/components/MyStakingContracts/List.tsx +++ b/apps/launch/components/MyStakingContracts/List.tsx @@ -1,15 +1,34 @@ import { InfoCircleOutlined } from '@ant-design/icons'; -import { Alert, Button, Flex, Table, Tooltip, Typography } from 'antd'; +import { Alert, Button, Flex, Popover, Table, Typography } from 'antd'; import type { TableProps } from 'antd'; import Link from 'next/link'; import React, { FC, useMemo } from 'react'; -import { URL } from 'common-util/constants/urls'; +import { GOVERN_URL, URL } from 'common-util/constants/urls'; import { useAppSelector } from 'store/index'; import { MyStakingContract } from 'types/index'; const { Paragraph } = Typography; +const NominatedForIncentivesPopover = () => ( + + Nominate your contract to make it eligible to receive staking incentives. Staking incentives + are allocated via  + + Govern + + . + + } + > + Nominated for incentives?  + + +); + const useColumns = () => { const { networkName } = useAppSelector((state) => state.network); @@ -44,14 +63,7 @@ const useColumns = () => { width: '25%', }, { - title: ( - <> - Nominated for incentives?  - - - - - ), + title: NominatedForIncentivesPopover, key: 'action', width: '25%', render: (_, record) => ( @@ -87,7 +99,12 @@ export const List: FC = () => { /> )} -
+
record.id} + /> ); }; From d6a81c4792367e6947ce5633ba6f12d38ff2f43b Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 17:30:55 +0530 Subject: [PATCH 08/47] feat: Add useGetMyStakingContracts hook for fetching staking contracts (call with Tanya) --- apps/launch/hooks/useGetMyStakingContracts.ts | 131 ++++++++++++++++++ apps/launch/pages/_app.tsx | 3 + 2 files changed, 134 insertions(+) create mode 100644 apps/launch/hooks/useGetMyStakingContracts.ts diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts new file mode 100644 index 00000000..45697901 --- /dev/null +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -0,0 +1,131 @@ +import { ethers } from 'ethers'; +import { useEffect } from 'react'; +import { AbiItem, Address, parseAbiItem } from 'viem'; +import { mainnet } from 'viem/chains'; +import { useAccount, usePublicClient, useReadContract, useWatchContractEvent } from 'wagmi'; + +import { + STAKING_FACTORY, + STAKING_TOKEN, + VOTE_WEIGHTING, +} from 'libs/util-contracts/src/lib/abiAndAddresses'; + +export const getBytes32FromAddress = (address: Address | string) => { + return ethers.zeroPadValue(address, 32) as Address; +}; + +// const useGetAllNominees = () => { +// const { chainId } = useAccount(); + +// if (!chainId) return []; + +// const { data } = useReadContract({ +// address: (VOTE_WEIGHTING.addresses as Record)[chainId], +// abi: VOTE_WEIGHTING.abi, +// chainId, +// functionName: 'getAllNominees', +// args: [], +// query: { +// select: (data) => { +// const nominees = data as { account: Address; chainId: bigint }[]; +// const nomineesFilteredByChainId = nominees.filter( +// (nominee) => nominee.chainId === BigInt(chainId), +// ); +// // return { implementation, deployer, isEnabled }; + +// return nomineesFilteredByChainId; +// }, +// }, +// }); + +// return data; +// }; + +export const useGetMyStakingContracts = () => { + // const data = useWatchContractEvent({ + // address: STAKING_FACTORY.addresses[1] as Address, + // abi: STAKING_FACTORY.abi, + // eventName: 'InstanceCreated', + // onLogs(logs) { + // console.log('New logs!', logs); + // }, + // }); + // console.log('Data:', data); + // const { chainId } = useAccount(); + const chainId = 1; + + const client = usePublicClient(); + + useEffect(() => { + (async () => { + if (!client) return; + + const logs = await client.getLogs({ + address: STAKING_FACTORY.addresses[1] as Address, + event: parseAbiItem( + 'event InstanceCreated(address indexed, address indexed, address indexed)', + ), + fromBlock: BigInt(0), + toBlock: 'latest', + }); + + console.log('Logs:', logs); + + const updatedLogs = logs.map((log) => { + const convertedArgs = getBytes32FromAddress(log.args[1] as Address); + return convertedArgs; + }); + + console.log('Updated logs:', updatedLogs); + })(); + }, [client]); + + const { data: metadataForFirstEvent } = useReadContract({ + address: '0x7248d855a3d4d17c32Eb0D996A528f7520d2F4A3', // instances[1].address, + abi: STAKING_TOKEN.abi, + chainId, + functionName: 'metadataHash', + args: [], + // query: { + // select: (data) => { + // const nominees = data as { account: Address; chainId: bigint }[]; + // const nomineesFilteredByChainId = nominees.filter( + // (nominee) => nominee.chainId === BigInt(chainId), + // ); + // // return { implementation, deployer, isEnabled }; + + // return nomineesFilteredByChainId; + // }, + // }, + }); + + console.log('Data:', metadataForFirstEvent); + + const { data } = useReadContract({ + // it is only available on mainnet + address: (VOTE_WEIGHTING.addresses as Record)[mainnet.id], + abi: VOTE_WEIGHTING.abi, + chainId: mainnet.id, + functionName: 'getAllNominees', + args: [], + query: { + select: (data) => { + // const nominees = data as { account: Address; chainId: bigint }[]; + // const nomineesFilteredByChainId = nominees.filter( + // (nominee) => nominee.chainId === BigInt(chainId), + // ); + // return { implementation, deployer, isEnabled }; + return data; + // return nomineesFilteredByChainId; + }, + }, + }); + + console.log('Data:', data); +}; + +// export const useGetMyStakingContracts = () => { +// const { chainId } = useAccount(); + +// return +// }; diff --git a/apps/launch/pages/_app.tsx b/apps/launch/pages/_app.tsx index c4808960..7f03ef9f 100644 --- a/apps/launch/pages/_app.tsx +++ b/apps/launch/pages/_app.tsx @@ -6,12 +6,15 @@ import { Provider } from 'react-redux'; import { GlobalStyles } from 'libs/ui-theme/src/lib/GlobalStyles'; import { AutonolasThemeProvider } from 'libs/ui-theme/src/lib/ThemeConfig'; +import { useGetMyStakingContracts } from 'hooks/useGetMyStakingContracts'; + import Layout from '../components/Layout'; import Web3ModalProvider from '../context/Web3ModalProvider'; import { wrapper } from '../store'; const DataProvider: FC = ({ children }) => { // init data + useGetMyStakingContracts(); return <>{children}; }; From 91de9fc9b346d3be52ef4a6965492120d33010ba Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 17:31:09 +0530 Subject: [PATCH 09/47] refactor: Update clip-path attribute to clipPath in LogoSvg component --- apps/launch/components/Layout/Logos.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launch/components/Layout/Logos.tsx b/apps/launch/components/Layout/Logos.tsx index 517ae822..4cec08dc 100644 --- a/apps/launch/components/Layout/Logos.tsx +++ b/apps/launch/components/Layout/Logos.tsx @@ -10,7 +10,7 @@ export const LogoIconSvg = () => ( export const LogoSvg = () => ( - + From 716fedb682057f8498dbbe24a0e5f9a7a9e5e2e2 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 20:14:00 +0530 Subject: [PATCH 10/47] chore: add hooks to fetch my staking contracts --- apps/launch/hooks/useGetMyStakingContracts.ts | 243 ++++++++++-------- apps/launch/store/launch.ts | 22 +- apps/launch/types/index.ts | 2 +- 3 files changed, 144 insertions(+), 123 deletions(-) diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index 45697901..decd7d4f 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -1,131 +1,172 @@ import { ethers } from 'ethers'; -import { useEffect } from 'react'; -import { AbiItem, Address, parseAbiItem } from 'viem'; +import { kebabCase } from 'lodash'; +import { useEffect, useState } from 'react'; +import { Abi, Address, parseAbiItem } from 'viem'; import { mainnet } from 'viem/chains'; -import { useAccount, usePublicClient, useReadContract, useWatchContractEvent } from 'wagmi'; +import { useAccount, usePublicClient, useReadContract, useReadContracts } from 'wagmi'; +import { GATEWAY_URL, HASH_PREFIX } from 'libs/util-constants/src'; import { STAKING_FACTORY, STAKING_TOKEN, VOTE_WEIGHTING, } from 'libs/util-contracts/src/lib/abiAndAddresses'; -export const getBytes32FromAddress = (address: Address | string) => { - return ethers.zeroPadValue(address, 32) as Address; -}; +import { useAppDispatch } from 'store/index'; +import { setStakingContracts } from 'store/launch'; +import { MyStakingContract } from 'types/index'; -// const useGetAllNominees = () => { -// const { chainId } = useAccount(); - -// if (!chainId) return []; - -// const { data } = useReadContract({ -// address: (VOTE_WEIGHTING.addresses as Record)[chainId], -// abi: VOTE_WEIGHTING.abi, -// chainId, -// functionName: 'getAllNominees', -// args: [], -// query: { -// select: (data) => { -// const nominees = data as { account: Address; chainId: bigint }[]; -// const nomineesFilteredByChainId = nominees.filter( -// (nominee) => nominee.chainId === BigInt(chainId), -// ); -// // return { implementation, deployer, isEnabled }; - -// return nomineesFilteredByChainId; -// }, -// }, -// }); - -// return data; -// }; +type Metadata = { name: string; description: string }; -export const useGetMyStakingContracts = () => { - // const data = useWatchContractEvent({ - // address: STAKING_FACTORY.addresses[1] as Address, - // abi: STAKING_FACTORY.abi, - // eventName: 'InstanceCreated', - // onLogs(logs) { - // console.log('New logs!', logs); - // }, - // }); - // console.log('Data:', data); - // const { chainId } = useAccount(); - const chainId = 1; +const getMetadata = async (tokenUri: undefined | null | string) => { + if (!tokenUri) return null; - const client = usePublicClient(); + try { + const uri = `${HASH_PREFIX}${tokenUri.substring(2)}`; + const ipfsUrl = `${GATEWAY_URL}${uri}`; + const response = await fetch(ipfsUrl); + const json = await response.json(); + return json; + } catch (e) { + window.console.error(e); + } - useEffect(() => { - (async () => { - if (!client) return; + return null; +}; - const logs = await client.getLogs({ - address: STAKING_FACTORY.addresses[1] as Address, - event: parseAbiItem( - 'event InstanceCreated(address indexed, address indexed, address indexed)', - ), - fromBlock: BigInt(0), - toBlock: 'latest', - }); +const getBytes32FromAddress = (address: Address | string) => { + return ethers.zeroPadValue(address, 32) as Address; +}; - console.log('Logs:', logs); +const useGetAllNominees = () => { + // it is only available on mainnet, hence hardcoded. + const { data: nominees } = useReadContract({ + address: (VOTE_WEIGHTING.addresses as Record)[mainnet.id], + abi: VOTE_WEIGHTING.abi, + chainId: mainnet.id, + functionName: 'getAllNominees', + args: [], + query: { + select: (data: unknown) => { + const list = data as { account: Address; chainId: bigint }[]; + return list.filter((nominee) => nominee.chainId === BigInt(mainnet.id)); + }, + }, + }); - const updatedLogs = logs.map((log) => { - const convertedArgs = getBytes32FromAddress(log.args[1] as Address); - return convertedArgs; - }); + return nominees; +}; - console.log('Updated logs:', updatedLogs); - })(); - }, [client]); +const useGetMyStakingContractsMetadata = (addresses: Address[]) => { + const [metadata, setMetadata] = useState([]); + const { chainId } = useAccount(); - const { data: metadataForFirstEvent } = useReadContract({ - address: '0x7248d855a3d4d17c32Eb0D996A528f7520d2F4A3', // instances[1].address, - abi: STAKING_TOKEN.abi, + const contracts = addresses.map((address) => ({ + address, + abi: STAKING_TOKEN.abi as Abi, chainId, functionName: 'metadataHash', args: [], - // query: { - // select: (data) => { - // const nominees = data as { account: Address; chainId: bigint }[]; - // const nomineesFilteredByChainId = nominees.filter( - // (nominee) => nominee.chainId === BigInt(chainId), - // ); - // // return { implementation, deployer, isEnabled }; - - // return nomineesFilteredByChainId; - // }, - // }, - }); - - console.log('Data:', metadataForFirstEvent); + })); - const { data } = useReadContract({ - // it is only available on mainnet - address: (VOTE_WEIGHTING.addresses as Record)[mainnet.id], - abi: VOTE_WEIGHTING.abi, - chainId: mainnet.id, - functionName: 'getAllNominees', - args: [], + const { data } = useReadContracts({ + contracts, query: { - select: (data) => { - // const nominees = data as { account: Address; chainId: bigint }[]; - // const nomineesFilteredByChainId = nominees.filter( - // (nominee) => nominee.chainId === BigInt(chainId), - // ); - // return { implementation, deployer, isEnabled }; - return data; - // return nomineesFilteredByChainId; + enabled: addresses.length > 0, + select: async (list) => { + const metadataHashList = list.map((rawData) => rawData.result as string); + const metadataPromise = await Promise.allSettled( + metadataHashList.map(async (hash) => await getMetadata(hash)), + ); + const metadata: Metadata[] = metadataPromise + .filter((item) => item.status === 'fulfilled') + .map((item) => ({ + name: item.value['name'], + description: item.value['description'], + })); + + return metadata; }, }, }); - console.log('Data:', data); + useEffect(() => { + (async () => { + if (!data) return; + + try { + const result = await data; + setMetadata(result); + } catch (error) { + window.console.error(error); + } + })(); + }, [data, addresses]); + + return metadata; +}; + +const useGetInstanceAddresses = () => { + const client = usePublicClient(); + const { chainId } = useAccount(); + + const [instanceAddresses, setInstanceAddresses] = useState([]); + + const currentChainId: 1 | 100 | 137 = chainId as 1 | 100 | 137; // TODO: fix me + + useEffect(() => { + (async () => { + if (!currentChainId) return; + if (!client) return; + + try { + const eventLogs = await client.getLogs({ + address: STAKING_FACTORY.addresses[`${currentChainId}`] as Address, + event: parseAbiItem( + 'event InstanceCreated(address indexed, address indexed, address indexed)', + ), + fromBlock: BigInt(0), + toBlock: 'latest', + }); + + const updatedLogs = eventLogs.map((log) => { + const instanceAddress = log.args[1] as Address; + return instanceAddress; + }); + + setInstanceAddresses(updatedLogs); + } catch (e) { + window.console.error(e); + } + })(); + }, [currentChainId, client]); + + return instanceAddresses; }; -// export const useGetMyStakingContracts = () => { -// const { chainId } = useAccount(); +export const useGetMyStakingContracts = () => { + const dispatch = useAppDispatch(); + const instanceAddresses = useGetInstanceAddresses(); + const myStakingContractsMetadata = useGetMyStakingContractsMetadata(instanceAddresses); + const nominees = useGetAllNominees(); + + const instanceAddressesInBytes32 = instanceAddresses.map((address) => + getBytes32FromAddress(address), + ); -// return -// }; + useEffect(() => { + if (!myStakingContractsMetadata) return; + if (myStakingContractsMetadata.length === 0) return; + + const myStakingContracts: MyStakingContract[] = myStakingContractsMetadata.map((metadata) => ({ + id: kebabCase(metadata.name), + name: metadata.name, + description: metadata.description, + template: 'staking', + isNominated: + nominees?.some((nominee) => instanceAddressesInBytes32.includes(nominee.account)) ?? false, + })); + + dispatch(setStakingContracts(myStakingContracts)); + }, [dispatch, instanceAddressesInBytes32, nominees, myStakingContractsMetadata]); +}; diff --git a/apps/launch/store/launch.ts b/apps/launch/store/launch.ts index 2c714257..bc42122e 100644 --- a/apps/launch/store/launch.ts +++ b/apps/launch/store/launch.ts @@ -9,29 +9,9 @@ type LaunchState = { myStakingContracts: MyStakingContract[]; }; -const dummyMyStakingContracts: MyStakingContract[] = [ - { - id: '1', - name: 'Contract #1 Create Prediction Market Modernized', - description: - 'This is the very long description of the contract that targets governors and explains the value of the contract to them. This is the very long description of the contract that targets governors and explains the value of the contract to them.', - template: 'Create Prediction Markets', - isNominated: true, - }, - { - id: '2', - name: 'Contract #2 Create Prediction Market Modernized', - description: - 'lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - template: 'Create Prediction Markets', - isNominated: false, - }, -]; - const initialState: LaunchState = { isMyStakingContractsLoading: false, - myStakingContracts: dummyMyStakingContracts, - // myStakingContracts: [], + myStakingContracts: [], }; export const launchSlice = createSlice({ diff --git a/apps/launch/types/index.ts b/apps/launch/types/index.ts index 7bac4428..460134ce 100644 --- a/apps/launch/types/index.ts +++ b/apps/launch/types/index.ts @@ -1,5 +1,5 @@ export type MyStakingContract = { - id: string; // TODO: check if possible + id: string; name: string; description: string; template: string; From c55ca7c311de5d4382d8fb750b8f98e9935f7c31 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 20:27:45 +0530 Subject: [PATCH 11/47] refactor: Add ethers utility function for converting address to bytes32 --- apps/launch/common-util/constants/rpcs.ts | 2 ++ .../common-util/constants/stakingContract.ts | 2 +- apps/launch/common-util/constants/urls.ts | 2 +- apps/launch/hooks/useGetMyStakingContracts.ts | 32 ++++++++----------- apps/launch/pages/_app.tsx | 1 - apps/launch/store/launch.ts | 6 ++-- libs/util-functions/src/index.ts | 1 + libs/util-functions/src/lib/ethers.ts | 6 ++++ 8 files changed, 28 insertions(+), 24 deletions(-) create mode 100644 libs/util-functions/src/lib/ethers.ts diff --git a/apps/launch/common-util/constants/rpcs.ts b/apps/launch/common-util/constants/rpcs.ts index 23ca4281..5672c6ab 100644 --- a/apps/launch/common-util/constants/rpcs.ts +++ b/apps/launch/common-util/constants/rpcs.ts @@ -1,5 +1,7 @@ import { RPC_URLS } from 'libs/util-constants/src'; +export type SupportedChain = 1 | 100 | 137; // TODO: make it dynamic + export const LAUNCH_RPC_URLS: Record = { 1: RPC_URLS[1], 100: RPC_URLS[100], diff --git a/apps/launch/common-util/constants/stakingContract.ts b/apps/launch/common-util/constants/stakingContract.ts index ec54a5a5..d02b40e5 100644 --- a/apps/launch/common-util/constants/stakingContract.ts +++ b/apps/launch/common-util/constants/stakingContract.ts @@ -1,6 +1,6 @@ import { ethers } from 'ethers'; import { Address } from 'viem'; -import { arbitrum, base, celo, gnosis, goerli, mainnet, optimism, polygon } from 'viem/chains'; +import { arbitrum, base, celo, gnosis, mainnet, optimism, polygon } from 'viem/chains'; export const CONTRACT_TEMPLATES = [ { diff --git a/apps/launch/common-util/constants/urls.ts b/apps/launch/common-util/constants/urls.ts index b03bcaa6..ad8f2601 100644 --- a/apps/launch/common-util/constants/urls.ts +++ b/apps/launch/common-util/constants/urls.ts @@ -6,4 +6,4 @@ export const URL = { pageNotFound: 'page-not-found', }; -export const GOVERN_URL = 'https://govern.olas.network'; \ No newline at end of file +export const GOVERN_URL = 'https://govern.olas.network'; diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index decd7d4f..316c0423 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -1,4 +1,3 @@ -import { ethers } from 'ethers'; import { kebabCase } from 'lodash'; import { useEffect, useState } from 'react'; import { Abi, Address, parseAbiItem } from 'viem'; @@ -11,9 +10,12 @@ import { STAKING_TOKEN, VOTE_WEIGHTING, } from 'libs/util-contracts/src/lib/abiAndAddresses'; +import { getBytes32FromAddress } from 'libs/util-functions/src'; +import { SupportedChain } from 'common-util/constants/rpcs'; +import { CONTRACT_TEMPLATES } from 'common-util/constants/stakingContract'; import { useAppDispatch } from 'store/index'; -import { setStakingContracts } from 'store/launch'; +import { setMyStakingContracts } from 'store/launch'; import { MyStakingContract } from 'types/index'; type Metadata = { name: string; description: string }; @@ -34,10 +36,6 @@ const getMetadata = async (tokenUri: undefined | null | string) => { return null; }; -const getBytes32FromAddress = (address: Address | string) => { - return ethers.zeroPadValue(address, 32) as Address; -}; - const useGetAllNominees = () => { // it is only available on mainnet, hence hardcoded. const { data: nominees } = useReadContract({ @@ -58,8 +56,8 @@ const useGetAllNominees = () => { }; const useGetMyStakingContractsMetadata = (addresses: Address[]) => { - const [metadata, setMetadata] = useState([]); const { chainId } = useAccount(); + const [metadata, setMetadata] = useState([]); const contracts = addresses.map((address) => ({ address, @@ -74,7 +72,7 @@ const useGetMyStakingContractsMetadata = (addresses: Address[]) => { query: { enabled: addresses.length > 0, select: async (list) => { - const metadataHashList = list.map((rawData) => rawData.result as string); + const metadataHashList = list.map(({ result }) => result as string); const metadataPromise = await Promise.allSettled( metadataHashList.map(async (hash) => await getMetadata(hash)), ); @@ -112,7 +110,7 @@ const useGetInstanceAddresses = () => { const [instanceAddresses, setInstanceAddresses] = useState([]); - const currentChainId: 1 | 100 | 137 = chainId as 1 | 100 | 137; // TODO: fix me + const currentChainId = chainId as SupportedChain; useEffect(() => { (async () => { @@ -129,12 +127,9 @@ const useGetInstanceAddresses = () => { toBlock: 'latest', }); - const updatedLogs = eventLogs.map((log) => { - const instanceAddress = log.args[1] as Address; - return instanceAddress; - }); - - setInstanceAddresses(updatedLogs); + // log.args[1] is the instance address + const addresses = eventLogs.map((log) => log.args[1] as Address); + setInstanceAddresses(addresses); } catch (e) { window.console.error(e); } @@ -157,16 +152,17 @@ export const useGetMyStakingContracts = () => { useEffect(() => { if (!myStakingContractsMetadata) return; if (myStakingContractsMetadata.length === 0) return; + if (!nominees) return; const myStakingContracts: MyStakingContract[] = myStakingContractsMetadata.map((metadata) => ({ id: kebabCase(metadata.name), name: metadata.name, description: metadata.description, - template: 'staking', + template: CONTRACT_TEMPLATES[0].title, isNominated: - nominees?.some((nominee) => instanceAddressesInBytes32.includes(nominee.account)) ?? false, + nominees.some((nominee) => instanceAddressesInBytes32.includes(nominee.account)) ?? false, })); - dispatch(setStakingContracts(myStakingContracts)); + dispatch(setMyStakingContracts(myStakingContracts)); }, [dispatch, instanceAddressesInBytes32, nominees, myStakingContractsMetadata]); }; diff --git a/apps/launch/pages/_app.tsx b/apps/launch/pages/_app.tsx index 7f03ef9f..ac5d0833 100644 --- a/apps/launch/pages/_app.tsx +++ b/apps/launch/pages/_app.tsx @@ -13,7 +13,6 @@ import Web3ModalProvider from '../context/Web3ModalProvider'; import { wrapper } from '../store'; const DataProvider: FC = ({ children }) => { - // init data useGetMyStakingContracts(); return <>{children}; diff --git a/apps/launch/store/launch.ts b/apps/launch/store/launch.ts index bc42122e..75b3ec54 100644 --- a/apps/launch/store/launch.ts +++ b/apps/launch/store/launch.ts @@ -10,7 +10,7 @@ type LaunchState = { }; const initialState: LaunchState = { - isMyStakingContractsLoading: false, + isMyStakingContractsLoading: true, myStakingContracts: [], }; @@ -18,7 +18,7 @@ export const launchSlice = createSlice({ name: 'launch', initialState, reducers: { - setStakingContracts: (state, action: PayloadAction) => { + setMyStakingContracts: (state, action: PayloadAction) => { state.myStakingContracts = action.payload; state.isMyStakingContractsLoading = false; }, @@ -26,5 +26,5 @@ export const launchSlice = createSlice({ }, }); -export const { setStakingContracts, clearState } = launchSlice.actions; +export const { setMyStakingContracts, clearState } = launchSlice.actions; export const launchReducer = launchSlice.reducer; diff --git a/libs/util-functions/src/index.ts b/libs/util-functions/src/index.ts index e2e4e74c..cf3bd994 100644 --- a/libs/util-functions/src/index.ts +++ b/libs/util-functions/src/index.ts @@ -3,3 +3,4 @@ export * from './lib/sendTransaction'; export * from './lib/sendTransaction/helpers'; export * from './lib/notifications'; export * from './lib/requests'; +export * from './lib/ethers'; diff --git a/libs/util-functions/src/lib/ethers.ts b/libs/util-functions/src/lib/ethers.ts new file mode 100644 index 00000000..a99750f5 --- /dev/null +++ b/libs/util-functions/src/lib/ethers.ts @@ -0,0 +1,6 @@ +import { ethers } from 'ethers'; +import { Address } from 'viem'; + +export const getBytes32FromAddress = (address: Address | string) => { + return ethers.zeroPadValue(address, 32) as Address; +}; From 4341e8f28f41c5824424e12f231edacb3d60edf8 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 20:40:20 +0530 Subject: [PATCH 12/47] refactor: Update MyStakingContracts List component to display a success tag when a contract is nominated --- .../components/MyStakingContracts/List.tsx | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/apps/launch/components/MyStakingContracts/List.tsx b/apps/launch/components/MyStakingContracts/List.tsx index c308f9a7..bcf14b4b 100644 --- a/apps/launch/components/MyStakingContracts/List.tsx +++ b/apps/launch/components/MyStakingContracts/List.tsx @@ -1,5 +1,5 @@ -import { InfoCircleOutlined } from '@ant-design/icons'; -import { Alert, Button, Flex, Popover, Table, Typography } from 'antd'; +import { CheckCircleOutlined, InfoCircleOutlined } from '@ant-design/icons'; +import { Alert, Button, Flex, Popover, Table, Tag, Typography } from 'antd'; import type { TableProps } from 'antd'; import Link from 'next/link'; import React, { FC, useMemo } from 'react'; @@ -66,11 +66,20 @@ const useColumns = () => { title: NominatedForIncentivesPopover, key: 'action', width: '25%', - render: (_, record) => ( - - ), + render: (_, record) => { + return ( + + {record.isNominated ? ( + + +  Nominated + + ) : ( + + )} + + ); + }, }, ], [networkName], From cb815f567dfb5ceadd2d39f74b0021d7004594b0 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 20:40:33 +0530 Subject: [PATCH 13/47] refactor: Update MyStakingContracts component to use GOVERN_URL instead of URL.myStakingContracts --- apps/launch/components/MyStakingContracts/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/launch/components/MyStakingContracts/index.tsx b/apps/launch/components/MyStakingContracts/index.tsx index a6b6bf80..7497f122 100644 --- a/apps/launch/components/MyStakingContracts/index.tsx +++ b/apps/launch/components/MyStakingContracts/index.tsx @@ -9,7 +9,7 @@ import { useAccount } from 'wagmi'; import { UNICODE_SYMBOLS } from 'libs/util-constants/src'; import { CHAIN_NAMES } from 'libs/util-constants/src'; -import { URL } from 'common-util/constants/urls'; +import { GOVERN_URL, URL } from 'common-util/constants/urls'; import { useAppSelector } from 'store/index'; import { LoginV2 } from '../Login'; @@ -97,7 +97,7 @@ export const MyStakingContracts = () => { return ( - + Explore all nominated staking contracts on Olas Govern  {UNICODE_SYMBOLS.EXTERNAL_LINK} From 095e3ae10216d53294f2089511fa7b3ebf39a5f4 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 20:57:40 +0530 Subject: [PATCH 14/47] refactor: Add nominate contract functionality to MyStakingContracts List component --- apps/launch/common-util/constants/urls.ts | 1 + .../components/MyStakingContracts/List.tsx | 8 ++- .../MyStakingContracts/NominateContract.tsx | 54 +++++++++++++++++++ apps/launch/pages/nominate-contract.tsx | 3 ++ 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 apps/launch/components/MyStakingContracts/NominateContract.tsx create mode 100644 apps/launch/pages/nominate-contract.tsx diff --git a/apps/launch/common-util/constants/urls.ts b/apps/launch/common-util/constants/urls.ts index ad8f2601..f64ac358 100644 --- a/apps/launch/common-util/constants/urls.ts +++ b/apps/launch/common-util/constants/urls.ts @@ -2,6 +2,7 @@ export const URL = { myStakingContracts: 'my-staking-contracts', createContract: 'my-staking-contracts/create', + nominateContract: 'nominate-contract', paths: 'paths', pageNotFound: 'page-not-found', }; diff --git a/apps/launch/components/MyStakingContracts/List.tsx b/apps/launch/components/MyStakingContracts/List.tsx index bcf14b4b..c9463df5 100644 --- a/apps/launch/components/MyStakingContracts/List.tsx +++ b/apps/launch/components/MyStakingContracts/List.tsx @@ -2,6 +2,7 @@ import { CheckCircleOutlined, InfoCircleOutlined } from '@ant-design/icons'; import { Alert, Button, Flex, Popover, Table, Tag, Typography } from 'antd'; import type { TableProps } from 'antd'; import Link from 'next/link'; +import { useRouter } from 'next/router'; import React, { FC, useMemo } from 'react'; import { GOVERN_URL, URL } from 'common-util/constants/urls'; @@ -30,6 +31,7 @@ const NominatedForIncentivesPopover = () => ( ); const useColumns = () => { + const router = useRouter(); const { networkName } = useAppSelector((state) => state.network); const columns: TableProps['columns'] = useMemo( @@ -75,14 +77,16 @@ const useColumns = () => {  Nominated ) : ( - + )} ); }, }, ], - [networkName], + [networkName, router], ); return columns; diff --git a/apps/launch/components/MyStakingContracts/NominateContract.tsx b/apps/launch/components/MyStakingContracts/NominateContract.tsx new file mode 100644 index 00000000..a97dd4bb --- /dev/null +++ b/apps/launch/components/MyStakingContracts/NominateContract.tsx @@ -0,0 +1,54 @@ +import { Card, Flex, Typography } from 'antd'; +import React from 'react'; +import styled from 'styled-components'; + +import { COLOR } from 'libs/ui-theme/src'; + +import { LogoSvg } from '../Layout/Logos'; + +const { Title, Paragraph, Text } = Typography; + +const StyledMain = styled.main` + display: flex; + flex-direction: column; + max-width: 1000px; + margin: 0 auto; +`; + +const LogoContainer = styled.div` + margin: 0; + text-align: center; + scale: 1.4; +`; + +const PurpleDot = styled.div` + width: 8px; + height: 8px; + border-radius: 50%; + background-color: ${COLOR.PRIMARY}; + display: inline-block; + margin-right: 8px; +`; + +// TODO: Tanya to check +export const NominatedContract = () => { + return ( + + + + + + + + Nominating staking contract... + + Contract #1 Create Prediction Market Modernized on Gnosis chain + + + +  Waiting for transaction... + + + + ); +}; diff --git a/apps/launch/pages/nominate-contract.tsx b/apps/launch/pages/nominate-contract.tsx new file mode 100644 index 00000000..eeba795c --- /dev/null +++ b/apps/launch/pages/nominate-contract.tsx @@ -0,0 +1,3 @@ +import { NominatedContract } from '../components/MyStakingContracts/NominateContract'; + +export default NominatedContract; From 0a45d9c21d7dc8648d7a3b3b24063318491572e8 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Wed, 19 Jun 2024 22:17:17 +0530 Subject: [PATCH 15/47] refactor: Improve useGetMyStakingContractsMetadata hook to handle errors and filter out empty metadata --- apps/launch/hooks/useGetMyStakingContracts.ts | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index 316c0423..138daca5 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -73,17 +73,24 @@ const useGetMyStakingContractsMetadata = (addresses: Address[]) => { enabled: addresses.length > 0, select: async (list) => { const metadataHashList = list.map(({ result }) => result as string); - const metadataPromise = await Promise.allSettled( - metadataHashList.map(async (hash) => await getMetadata(hash)), - ); - const metadata: Metadata[] = metadataPromise - .filter((item) => item.status === 'fulfilled') - .map((item) => ({ - name: item.value['name'], - description: item.value['description'], - })); - - return metadata; + try { + const metadataList = await Promise.allSettled( + metadataHashList.map((hash) => getMetadata(hash)), + ); + + const results: Metadata[] = []; + for (const response of metadataList) { + if (response.status === 'fulfilled' && response.value) { + results.push(response.value); + } + } + + return results.filter((metadata) => !!metadata); + } catch (error) { + window.console.error(error); + } + + return []; }, }, }); From ea60f05335e5f5ee7868779db0b5e103273d5cc1 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Thu, 20 Jun 2024 15:38:59 +0530 Subject: [PATCH 16/47] chore: address Tanya's review comments --- .../components/MyStakingContracts/index.tsx | 14 ++--- apps/launch/hooks/useGetMyStakingContracts.ts | 54 +++++++++++-------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/apps/launch/components/MyStakingContracts/index.tsx b/apps/launch/components/MyStakingContracts/index.tsx index 7497f122..92139237 100644 --- a/apps/launch/components/MyStakingContracts/index.tsx +++ b/apps/launch/components/MyStakingContracts/index.tsx @@ -1,7 +1,6 @@ import { TableOutlined, WalletOutlined } from '@ant-design/icons'; import { Button, Card, Flex, Spin, Typography } from 'antd'; import Link from 'next/link'; -import { useRouter } from 'next/router'; import styled from 'styled-components'; import { match } from 'ts-pattern'; import { useAccount } from 'wagmi'; @@ -54,16 +53,11 @@ const CreateContractMessage = () => ( ); const CreateContractButton = () => { - const router = useRouter(); const { networkName } = useAppSelector((state) => state.network); - return ( - + + + ); }; @@ -106,7 +100,7 @@ export const MyStakingContracts = () => { My staking contracts - {isAccountConnected && networkId && <> on {CHAIN_NAMES[networkId]}} + {isAccountConnected && networkId ? ` on ${CHAIN_NAMES[networkId]}` : ''} {myStakingContracts.length > 0 && } diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index 138daca5..526e3676 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -14,7 +14,7 @@ import { getBytes32FromAddress } from 'libs/util-functions/src'; import { SupportedChain } from 'common-util/constants/rpcs'; import { CONTRACT_TEMPLATES } from 'common-util/constants/stakingContract'; -import { useAppDispatch } from 'store/index'; +import { useAppDispatch, useAppSelector } from 'store/index'; import { setMyStakingContracts } from 'store/launch'; import { MyStakingContract } from 'types/index'; @@ -43,12 +43,8 @@ const useGetAllNominees = () => { abi: VOTE_WEIGHTING.abi, chainId: mainnet.id, functionName: 'getAllNominees', - args: [], query: { - select: (data: unknown) => { - const list = data as { account: Address; chainId: bigint }[]; - return list.filter((nominee) => nominee.chainId === BigInt(mainnet.id)); - }, + select: (data: unknown) => data as { account: Address; chainId: bigint }[], }, }); @@ -64,7 +60,6 @@ const useGetMyStakingContractsMetadata = (addresses: Address[]) => { abi: STAKING_TOKEN.abi as Abi, chainId, functionName: 'metadataHash', - args: [], })); const { data } = useReadContracts({ @@ -113,20 +108,20 @@ const useGetMyStakingContractsMetadata = (addresses: Address[]) => { const useGetInstanceAddresses = () => { const client = usePublicClient(); - const { chainId } = useAccount(); + const { networkId } = useAppSelector((state) => state.network); const [instanceAddresses, setInstanceAddresses] = useState([]); - const currentChainId = chainId as SupportedChain; + const currentNetworkId = networkId as SupportedChain; useEffect(() => { (async () => { - if (!currentChainId) return; + if (!currentNetworkId) return; if (!client) return; try { const eventLogs = await client.getLogs({ - address: STAKING_FACTORY.addresses[`${currentChainId}`] as Address, + address: STAKING_FACTORY.addresses[`${currentNetworkId}`] as Address, event: parseAbiItem( 'event InstanceCreated(address indexed, address indexed, address indexed)', ), @@ -141,7 +136,7 @@ const useGetInstanceAddresses = () => { window.console.error(e); } })(); - }, [currentChainId, client]); + }, [currentNetworkId, client]); return instanceAddresses; }; @@ -151,6 +146,7 @@ export const useGetMyStakingContracts = () => { const instanceAddresses = useGetInstanceAddresses(); const myStakingContractsMetadata = useGetMyStakingContractsMetadata(instanceAddresses); const nominees = useGetAllNominees(); + const { myStakingContracts } = useAppSelector((state) => state.launch); const instanceAddressesInBytes32 = instanceAddresses.map((address) => getBytes32FromAddress(address), @@ -161,15 +157,27 @@ export const useGetMyStakingContracts = () => { if (myStakingContractsMetadata.length === 0) return; if (!nominees) return; - const myStakingContracts: MyStakingContract[] = myStakingContractsMetadata.map((metadata) => ({ - id: kebabCase(metadata.name), - name: metadata.name, - description: metadata.description, - template: CONTRACT_TEMPLATES[0].title, - isNominated: - nominees.some((nominee) => instanceAddressesInBytes32.includes(nominee.account)) ?? false, - })); - - dispatch(setMyStakingContracts(myStakingContracts)); - }, [dispatch, instanceAddressesInBytes32, nominees, myStakingContractsMetadata]); + // TODO: Mohan to check + // if myStakingContracts is already set, do not update it + if (myStakingContracts.length !== 0) return; + + const myStakingContractsList: MyStakingContract[] = myStakingContractsMetadata.map( + (metadata) => ({ + id: kebabCase(metadata.name), + name: metadata.name, + description: metadata.description, + template: CONTRACT_TEMPLATES[0].title, + isNominated: + nominees.some((nominee) => instanceAddressesInBytes32.includes(nominee.account)) ?? false, + }), + ); + + dispatch(setMyStakingContracts(myStakingContractsList)); + }, [ + dispatch, + instanceAddressesInBytes32, + nominees, + myStakingContractsMetadata, + myStakingContracts, + ]); }; From 1f8672e26cd8e0cbd4f5c5d4a2dbcfa261f00d80 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Thu, 20 Jun 2024 15:46:52 +0530 Subject: [PATCH 17/47] refactor: Hide menu on certain pages in Layout component --- apps/launch/components/Layout/index.tsx | 35 ++++++++++++++++--------- libs/ui-theme/src/lib/GlobalStyles.tsx | 2 +- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/apps/launch/components/Layout/index.tsx b/apps/launch/components/Layout/index.tsx index 740399bb..6d597017 100644 --- a/apps/launch/components/Layout/index.tsx +++ b/apps/launch/components/Layout/index.tsx @@ -1,9 +1,11 @@ import { Layout as AntdLayout } from 'antd'; import dynamic from 'next/dynamic'; +import { useRouter } from 'next/router'; import { FC, ReactNode } from 'react'; -import { LoginV2 } from '../Login'; +import { URL } from 'common-util/constants/urls'; +import { LoginV2 } from '../Login'; import { LogoSvg } from './Logos'; import { SwitchNetworkSelect } from './SwitchNetworkSelect'; import { CustomLayout, Logo, OlasHeader, RightMenu } from './styles'; @@ -17,21 +19,28 @@ interface LayoutProps { children?: ReactNode; } +const pagesWithoutMenu = [URL.nominateContract]; + const Layout: FC = ({ children }) => { + const router = useRouter(); + const isMenuHidden = pagesWithoutMenu.some((page) => router.pathname.includes(page)); + return ( - - - - - - - - - - - - + {isMenuHidden ? null : ( + + + + + + + + + + + )} + +
{children}
diff --git a/libs/ui-theme/src/lib/GlobalStyles.tsx b/libs/ui-theme/src/lib/GlobalStyles.tsx index 0f2d5481..7add791e 100644 --- a/libs/ui-theme/src/lib/GlobalStyles.tsx +++ b/libs/ui-theme/src/lib/GlobalStyles.tsx @@ -61,7 +61,7 @@ export const GlobalStyles = createGlobalStyle` margin-top: 16px; } .mt-24 { - margin-top: 24px; + margin-top: 24px !important; } .mt-48 { margin-top: 48px; From bfc737ff72ef69cc383f8048c2720a724b49b6ea Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Thu, 20 Jun 2024 16:15:43 +0530 Subject: [PATCH 18/47] refactor: Update useGetMyStakingContractsMetadata hook to handle errors and filter out empty metadata --- apps/launch/hooks/useGetMyStakingContracts.ts | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index 526e3676..9b7e2335 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -1,4 +1,3 @@ -import { kebabCase } from 'lodash'; import { useEffect, useState } from 'react'; import { Abi, Address, parseAbiItem } from 'viem'; import { mainnet } from 'viem/chains'; @@ -53,7 +52,7 @@ const useGetAllNominees = () => { const useGetMyStakingContractsMetadata = (addresses: Address[]) => { const { chainId } = useAccount(); - const [metadata, setMetadata] = useState([]); + const [metadata, setMetadata] = useState<(Metadata | null)[]>([]); const contracts = addresses.map((address) => ({ address, @@ -73,14 +72,19 @@ const useGetMyStakingContractsMetadata = (addresses: Address[]) => { metadataHashList.map((hash) => getMetadata(hash)), ); - const results: Metadata[] = []; + const results: (Metadata | null)[] = []; for (const response of metadataList) { if (response.status === 'fulfilled' && response.value) { results.push(response.value); + } else { + // to maintain the order of the addresses, push null + // Eg: if the metadata for the 2nd address is not available or failed to fetch, + // push null at 2nd index + results.push(null); } } - return results.filter((metadata) => !!metadata); + return results; } catch (error) { window.console.error(error); } @@ -157,24 +161,30 @@ export const useGetMyStakingContracts = () => { if (myStakingContractsMetadata.length === 0) return; if (!nominees) return; - // TODO: Mohan to check // if myStakingContracts is already set, do not update it if (myStakingContracts.length !== 0) return; - const myStakingContractsList: MyStakingContract[] = myStakingContractsMetadata.map( - (metadata) => ({ - id: kebabCase(metadata.name), - name: metadata.name, - description: metadata.description, - template: CONTRACT_TEMPLATES[0].title, - isNominated: - nominees.some((nominee) => instanceAddressesInBytes32.includes(nominee.account)) ?? false, - }), - ); + const myStakingContractsList: MyStakingContract[] = myStakingContractsMetadata + .map((metadata, index) => { + if (!metadata) return null; + + return { + id: instanceAddresses[index], + name: metadata.name, + description: metadata.description, + template: CONTRACT_TEMPLATES[0].title, + isNominated: + nominees.some((nominee) => instanceAddressesInBytes32.includes(nominee.account)) ?? + false, + }; + }) + // filter out null values (ie. contracts without metadata - failed to fetch or not available) + .filter((contract) => contract !== null); dispatch(setMyStakingContracts(myStakingContractsList)); }, [ dispatch, + instanceAddresses, instanceAddressesInBytes32, nominees, myStakingContractsMetadata, From 876e720e85d90998eb8e77298b20561256efe39e Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Thu, 20 Jun 2024 18:41:07 +0530 Subject: [PATCH 19/47] refactor: Filter out null values in useGetMyStakingContracts and fix build fail --- apps/launch/hooks/useGetMyStakingContracts.ts | 2 +- apps/launch/types/index.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index 9b7e2335..6da10f60 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -179,7 +179,7 @@ export const useGetMyStakingContracts = () => { }; }) // filter out null values (ie. contracts without metadata - failed to fetch or not available) - .filter((contract) => contract !== null); + .filter((c): c is MyStakingContract => c !== null); dispatch(setMyStakingContracts(myStakingContractsList)); }, [ diff --git a/apps/launch/types/index.ts b/apps/launch/types/index.ts index 460134ce..06828039 100644 --- a/apps/launch/types/index.ts +++ b/apps/launch/types/index.ts @@ -1,5 +1,7 @@ +import { Address } from "viem"; + export type MyStakingContract = { - id: string; + id: Address; name: string; description: string; template: string; From 79077db308f1ec461eeb9ba8add2e778eb897ac6 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Thu, 20 Jun 2024 18:43:25 +0530 Subject: [PATCH 20/47] refactor: Update useGetMyStakingContracts to use ChainId instead of SupportedChain --- apps/launch/hooks/useGetMyStakingContracts.ts | 4 ++-- .../src/lib/abiAndAddresses/stakingFactory.js | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index 6da10f60..888efd8b 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -11,7 +11,7 @@ import { } from 'libs/util-contracts/src/lib/abiAndAddresses'; import { getBytes32FromAddress } from 'libs/util-functions/src'; -import { SupportedChain } from 'common-util/constants/rpcs'; +import { ChainId } from 'common-util/constants/stakingContract'; import { CONTRACT_TEMPLATES } from 'common-util/constants/stakingContract'; import { useAppDispatch, useAppSelector } from 'store/index'; import { setMyStakingContracts } from 'store/launch'; @@ -116,7 +116,7 @@ const useGetInstanceAddresses = () => { const [instanceAddresses, setInstanceAddresses] = useState([]); - const currentNetworkId = networkId as SupportedChain; + const currentNetworkId = networkId as ChainId; useEffect(() => { (async () => { diff --git a/libs/util-contracts/src/lib/abiAndAddresses/stakingFactory.js b/libs/util-contracts/src/lib/abiAndAddresses/stakingFactory.js index cd6fd286..62818e52 100644 --- a/libs/util-contracts/src/lib/abiAndAddresses/stakingFactory.js +++ b/libs/util-contracts/src/lib/abiAndAddresses/stakingFactory.js @@ -1,9 +1,15 @@ +import { arbitrum, base, celo, gnosis, mainnet, optimism, polygon } from "viem/chains"; + export const STAKING_FACTORY = { contractName: 'StakingFactory', addresses: { - 1: '0xC3f601fB1cAA6452fC60eC3887784421d20AE5DB', - 100: '0x9F3408C6f34bfB6B0eC73F34f2845A8C703374C6', - 137: '0xdbe987b33321B65695EB54F54ca486994F300FDb', + [mainnet.id]: '0xC3f601fB1cAA6452fC60eC3887784421d20AE5DB', + [optimism.id]: '', + [gnosis.id]: '0x9F3408C6f34bfB6B0eC73F34f2845A8C703374C6', + [polygon.id]: '0xdbe987b33321B65695EB54F54ca486994F300FDb', + [base.id]: '', + [arbitrum.id]: '', + [celo.id]: '', }, abi: [ { From 2b0acccdf585772edde8697bbb10e3fdb16dd3bb Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Thu, 20 Jun 2024 18:50:31 +0530 Subject: [PATCH 21/47] refactor: Update useGetMyStakingContracts to use ChainId instead of SupportedChain --- .../common-util/constants/stakingContract.ts | 14 ++++++++++++++ apps/launch/hooks/useGetMyStakingContracts.ts | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/launch/common-util/constants/stakingContract.ts b/apps/launch/common-util/constants/stakingContract.ts index d02b40e5..357fffff 100644 --- a/apps/launch/common-util/constants/stakingContract.ts +++ b/apps/launch/common-util/constants/stakingContract.ts @@ -102,3 +102,17 @@ export const STAKING_TOKEN_ADDRESSES: Addresses = { export const isSupportedChainId = (chainId: number): chainId is ChainId => { return chainId in IMPLEMENTATION_ADDRESSES; }; + +type BlockNumber = { + [key in ChainId]: number; +}; + +export const blockNumbers: BlockNumber = { + [mainnet.id]: 20009952, + [optimism.id]: 0, + [gnosis.id]: 34225443, + [polygon.id]: 57751430, + [base.id]: 0, + [arbitrum.id]: 0, + [celo.id]: 0, +}; diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index 888efd8b..851b863f 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -11,7 +11,7 @@ import { } from 'libs/util-contracts/src/lib/abiAndAddresses'; import { getBytes32FromAddress } from 'libs/util-functions/src'; -import { ChainId } from 'common-util/constants/stakingContract'; +import { ChainId, blockNumbers } from 'common-util/constants/stakingContract'; import { CONTRACT_TEMPLATES } from 'common-util/constants/stakingContract'; import { useAppDispatch, useAppSelector } from 'store/index'; import { setMyStakingContracts } from 'store/launch'; @@ -129,7 +129,7 @@ const useGetInstanceAddresses = () => { event: parseAbiItem( 'event InstanceCreated(address indexed, address indexed, address indexed)', ), - fromBlock: BigInt(0), + fromBlock: BigInt(blockNumbers[currentNetworkId]), toBlock: 'latest', }); From b174b5e12cefd203902e24b56e89ff8aaa953fa7 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Thu, 20 Jun 2024 20:13:47 +0530 Subject: [PATCH 22/47] chore: renames --- apps/launch/common-util/constants/rpcs.ts | 2 -- apps/launch/common-util/constants/stakingContract.ts | 4 ++-- apps/launch/hooks/useGetMyStakingContracts.ts | 8 ++++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/launch/common-util/constants/rpcs.ts b/apps/launch/common-util/constants/rpcs.ts index 5672c6ab..23ca4281 100644 --- a/apps/launch/common-util/constants/rpcs.ts +++ b/apps/launch/common-util/constants/rpcs.ts @@ -1,7 +1,5 @@ import { RPC_URLS } from 'libs/util-constants/src'; -export type SupportedChain = 1 | 100 | 137; // TODO: make it dynamic - export const LAUNCH_RPC_URLS: Record = { 1: RPC_URLS[1], 100: RPC_URLS[100], diff --git a/apps/launch/common-util/constants/stakingContract.ts b/apps/launch/common-util/constants/stakingContract.ts index 357fffff..8165777e 100644 --- a/apps/launch/common-util/constants/stakingContract.ts +++ b/apps/launch/common-util/constants/stakingContract.ts @@ -103,11 +103,11 @@ export const isSupportedChainId = (chainId: number): chainId is ChainId => { return chainId in IMPLEMENTATION_ADDRESSES; }; -type BlockNumber = { +type BlockNumbers = { [key in ChainId]: number; }; -export const blockNumbers: BlockNumber = { +export const blockNumbers: BlockNumbers = { [mainnet.id]: 20009952, [optimism.id]: 0, [gnosis.id]: 34225443, diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index 851b863f..40cb2ef6 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -77,9 +77,9 @@ const useGetMyStakingContractsMetadata = (addresses: Address[]) => { if (response.status === 'fulfilled' && response.value) { results.push(response.value); } else { - // to maintain the order of the addresses, push null + // To maintain the order of the addresses, push null. // Eg: if the metadata for the 2nd address is not available or failed to fetch, - // push null at 2nd index + // push null at 2nd index results.push(null); } } @@ -133,7 +133,7 @@ const useGetInstanceAddresses = () => { toBlock: 'latest', }); - // log.args[1] is the instance address + // log.args[1] = instance address const addresses = eventLogs.map((log) => log.args[1] as Address); setInstanceAddresses(addresses); } catch (e) { @@ -179,7 +179,7 @@ export const useGetMyStakingContracts = () => { }; }) // filter out null values (ie. contracts without metadata - failed to fetch or not available) - .filter((c): c is MyStakingContract => c !== null); + .filter((contract): contract is MyStakingContract => contract !== null); dispatch(setMyStakingContracts(myStakingContractsList)); }, [ From b75b923f4e1f5bd02c1f9619d62942a9d7af18e7 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Thu, 20 Jun 2024 19:51:56 +0400 Subject: [PATCH 23/47] Fix defining is nominated --- .../MyStakingContracts/Create/index.tsx | 2 ++ .../launch/components/MyStakingContracts/List.tsx | 15 +++++++-------- apps/launch/hooks/useGetMyStakingContracts.ts | 5 ++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/launch/components/MyStakingContracts/Create/index.tsx b/apps/launch/components/MyStakingContracts/Create/index.tsx index fc0b7869..9d6268a2 100644 --- a/apps/launch/components/MyStakingContracts/Create/index.tsx +++ b/apps/launch/components/MyStakingContracts/Create/index.tsx @@ -111,6 +111,8 @@ export const CreateStakingContract = () => { const result = await createStakingContract({ implementation, initPayload, account }); + console.log('result', result); + if (result) { // TODO: once request contracts list task is done, need to update // the staking contracts list with result.events.InstanceCreated data diff --git a/apps/launch/components/MyStakingContracts/List.tsx b/apps/launch/components/MyStakingContracts/List.tsx index c9463df5..f82c4c96 100644 --- a/apps/launch/components/MyStakingContracts/List.tsx +++ b/apps/launch/components/MyStakingContracts/List.tsx @@ -31,7 +31,6 @@ const NominatedForIncentivesPopover = () => ( ); const useColumns = () => { - const router = useRouter(); const { networkName } = useAppSelector((state) => state.network); const columns: TableProps['columns'] = useMemo( @@ -42,9 +41,7 @@ const useColumns = () => { key: 'name', width: '25%', render: (text, record) => ( - - {text} - + {text} ), }, { @@ -77,16 +74,18 @@ const useColumns = () => {  Nominated ) : ( - + + + )} ); }, }, ], - [networkName, router], + [networkName], ); return columns; diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index 40cb2ef6..dc3d7769 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -169,13 +169,12 @@ export const useGetMyStakingContracts = () => { if (!metadata) return null; return { - id: instanceAddresses[index], + id: instanceAddressesInBytes32[index], name: metadata.name, description: metadata.description, template: CONTRACT_TEMPLATES[0].title, isNominated: - nominees.some((nominee) => instanceAddressesInBytes32.includes(nominee.account)) ?? - false, + nominees.findIndex((item) => item.account === instanceAddressesInBytes32[index]) !== -1, }; }) // filter out null values (ie. contracts without metadata - failed to fetch or not available) From 1cd801e2910b97bce7476f7fa6cadaf246f7a497 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Thu, 20 Jun 2024 20:26:34 +0400 Subject: [PATCH 24/47] Add nominate tx --- apps/launch/common-util/functions/web3.ts | 15 ++++ .../components/MyStakingContracts/List.tsx | 2 +- .../MyStakingContracts/NominateContract.tsx | 54 ------------ apps/launch/components/NominateContract.tsx | 84 +++++++++++++++++++ apps/launch/hooks/useGetMyStakingContracts.ts | 5 +- apps/launch/pages/nominate-contract.tsx | 3 - apps/launch/pages/nominate-contract/[id].tsx | 3 + apps/launch/types/index.ts | 3 +- 8 files changed, 109 insertions(+), 60 deletions(-) delete mode 100644 apps/launch/components/MyStakingContracts/NominateContract.tsx create mode 100644 apps/launch/components/NominateContract.tsx delete mode 100644 apps/launch/pages/nominate-contract.tsx create mode 100644 apps/launch/pages/nominate-contract/[id].tsx diff --git a/apps/launch/common-util/functions/web3.ts b/apps/launch/common-util/functions/web3.ts index bb0bb98f..28dc33a3 100644 --- a/apps/launch/common-util/functions/web3.ts +++ b/apps/launch/common-util/functions/web3.ts @@ -63,6 +63,7 @@ type CreateContractParams = { initPayload: string; account: Address; }; + export const createStakingContract = async ({ implementation, initPayload, @@ -74,3 +75,17 @@ export const createStakingContract = async ({ return result; }; + +type AddNomineeParams = { + address: Address; + chainId: number; + account: Address; +}; + +export const addNominee = async ({ address, chainId, account }: AddNomineeParams) => { + const contract = getVoteWeightingContract(); + const createFn = contract.methods.addNomineeEVM(address, chainId); + const result = await sendTransaction(createFn, account); + + return result; +}; diff --git a/apps/launch/components/MyStakingContracts/List.tsx b/apps/launch/components/MyStakingContracts/List.tsx index f82c4c96..fcba474b 100644 --- a/apps/launch/components/MyStakingContracts/List.tsx +++ b/apps/launch/components/MyStakingContracts/List.tsx @@ -74,7 +74,7 @@ const useColumns = () => {  Nominated ) : ( - + diff --git a/apps/launch/components/MyStakingContracts/NominateContract.tsx b/apps/launch/components/MyStakingContracts/NominateContract.tsx deleted file mode 100644 index a97dd4bb..00000000 --- a/apps/launch/components/MyStakingContracts/NominateContract.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Card, Flex, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { COLOR } from 'libs/ui-theme/src'; - -import { LogoSvg } from '../Layout/Logos'; - -const { Title, Paragraph, Text } = Typography; - -const StyledMain = styled.main` - display: flex; - flex-direction: column; - max-width: 1000px; - margin: 0 auto; -`; - -const LogoContainer = styled.div` - margin: 0; - text-align: center; - scale: 1.4; -`; - -const PurpleDot = styled.div` - width: 8px; - height: 8px; - border-radius: 50%; - background-color: ${COLOR.PRIMARY}; - display: inline-block; - margin-right: 8px; -`; - -// TODO: Tanya to check -export const NominatedContract = () => { - return ( - - - - - - - - Nominating staking contract... - - Contract #1 Create Prediction Market Modernized on Gnosis chain - - - -  Waiting for transaction... - - - - ); -}; diff --git a/apps/launch/components/NominateContract.tsx b/apps/launch/components/NominateContract.tsx new file mode 100644 index 00000000..37c3a21a --- /dev/null +++ b/apps/launch/components/NominateContract.tsx @@ -0,0 +1,84 @@ +import { Card, Flex, Typography } from 'antd'; +import { useParams } from 'next/navigation'; +import React, { useEffect } from 'react'; +import styled from 'styled-components'; +import { mainnet } from 'viem/chains'; +import { useAccount, useSwitchChain } from 'wagmi'; + +import { COLOR } from 'libs/ui-theme/src'; + +import { addNominee } from 'common-util/functions'; +import { LogoSvg } from 'components/Layout/Logos'; +import { useAppSelector } from 'store/index'; + +const { Title, Paragraph, Text } = Typography; + +const StyledMain = styled.main` + display: flex; + flex-direction: column; + max-width: 1000px; + margin: 0 auto; +`; + +const LogoContainer = styled.div` + margin: 0; + text-align: center; + scale: 1.4; +`; + +const PurpleDot = styled.div` + width: 8px; + height: 8px; + border-radius: 50%; + background-color: ${COLOR.PRIMARY}; + display: inline-block; + margin-right: 8px; +`; + +export const NominatedContract = () => { + const params = useParams<{ id: string }>(); + const id = params?.id; + + const { myStakingContracts } = useAppSelector((state) => state.launch); + + const contractIndex = myStakingContracts.findIndex((item) => item.id === id); + + const { chainId, address: account } = useAccount(); + const { switchChainAsync } = useSwitchChain(); + + useEffect(() => { + if (chainId !== mainnet.id) { + switchChainAsync({ chainId: mainnet.id }); + // TODO: need to do something if user rejects switching, e.g. show alert? + } else { + const contract = myStakingContracts[contractIndex]; + if (!contract) return; + if (!account) return; + + addNominee({ address: contract.id, chainId: contract.chainId, account }); + } + }, [chainId]); + + // TODO: move to separate component + if (contractIndex === -1) return null; + + return ( + + + + + + + Nominating staking contract... + {`Contract #${contractIndex + 1} ${ + myStakingContracts[contractIndex]?.name + }`} + + + +  Waiting for transaction... + + + + ); +}; diff --git a/apps/launch/hooks/useGetMyStakingContracts.ts b/apps/launch/hooks/useGetMyStakingContracts.ts index dc3d7769..275f5fd4 100644 --- a/apps/launch/hooks/useGetMyStakingContracts.ts +++ b/apps/launch/hooks/useGetMyStakingContracts.ts @@ -152,6 +152,8 @@ export const useGetMyStakingContracts = () => { const nominees = useGetAllNominees(); const { myStakingContracts } = useAppSelector((state) => state.launch); + const { networkId } = useAppSelector((state) => state.network); + const instanceAddressesInBytes32 = instanceAddresses.map((address) => getBytes32FromAddress(address), ); @@ -169,7 +171,8 @@ export const useGetMyStakingContracts = () => { if (!metadata) return null; return { - id: instanceAddressesInBytes32[index], + id: instanceAddresses[index], + chainId: networkId, name: metadata.name, description: metadata.description, template: CONTRACT_TEMPLATES[0].title, diff --git a/apps/launch/pages/nominate-contract.tsx b/apps/launch/pages/nominate-contract.tsx deleted file mode 100644 index eeba795c..00000000 --- a/apps/launch/pages/nominate-contract.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { NominatedContract } from '../components/MyStakingContracts/NominateContract'; - -export default NominatedContract; diff --git a/apps/launch/pages/nominate-contract/[id].tsx b/apps/launch/pages/nominate-contract/[id].tsx new file mode 100644 index 00000000..8598421e --- /dev/null +++ b/apps/launch/pages/nominate-contract/[id].tsx @@ -0,0 +1,3 @@ +import { NominatedContract } from '../../components/NominateContract'; + +export default NominatedContract; diff --git a/apps/launch/types/index.ts b/apps/launch/types/index.ts index 06828039..7e61ba4f 100644 --- a/apps/launch/types/index.ts +++ b/apps/launch/types/index.ts @@ -1,7 +1,8 @@ -import { Address } from "viem"; +import { Address } from 'viem'; export type MyStakingContract = { id: Address; + chainId: number; name: string; description: string; template: string; From acd076bbe2226c48752780be8db525a74bc8cb1b Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Fri, 21 Jun 2024 18:03:31 +0530 Subject: [PATCH 25/47] chore: move useHandleRoute hook to _app.jsx --- .../hooks}/useHandleRoute.tsx | 0 apps/launch/components/Layout/SwitchNetworkSelect/index.tsx | 5 ----- apps/launch/pages/_app.tsx | 2 ++ 3 files changed, 2 insertions(+), 5 deletions(-) rename apps/launch/{components/Layout/SwitchNetworkSelect => common-util/hooks}/useHandleRoute.tsx (100%) diff --git a/apps/launch/components/Layout/SwitchNetworkSelect/useHandleRoute.tsx b/apps/launch/common-util/hooks/useHandleRoute.tsx similarity index 100% rename from apps/launch/components/Layout/SwitchNetworkSelect/useHandleRoute.tsx rename to apps/launch/common-util/hooks/useHandleRoute.tsx diff --git a/apps/launch/components/Layout/SwitchNetworkSelect/index.tsx b/apps/launch/components/Layout/SwitchNetworkSelect/index.tsx index bf2a73f4..0c7c189d 100644 --- a/apps/launch/components/Layout/SwitchNetworkSelect/index.tsx +++ b/apps/launch/components/Layout/SwitchNetworkSelect/index.tsx @@ -10,8 +10,6 @@ import { PAGES_TO_LOAD_WITH_CHAIN_ID, } from 'common-util/config/supportedChains'; -import { useHandleRoute } from './useHandleRoute'; - const networkSelectOptions = ALL_SUPPORTED_CHAINS.map((e) => ({ label: e.networkDisplayName, value: e.networkName, @@ -25,9 +23,6 @@ export const SwitchNetworkSelect: FC = () => { const chainName = (router?.query?.network || 'ethereum') as string; - // handle the routing - useHandleRoute(); - return (