diff --git a/.env.sample b/.env.sample index 64f70e58f..03a0ce897 100644 --- a/.env.sample +++ b/.env.sample @@ -5,8 +5,6 @@ ALCHEMY_KEY= ETHERSCAN_KEY= POCKET_KEY= GITHUB_TOKEN= -MONGODB_URI= -MONGODB_COMMENTS_DB= USE_CACHE=true REDIS_URL= MIGRATION_WEBHOOK_URL= diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index b8d5fbf01..7a135b16e 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -19,8 +19,6 @@ jobs: runs-on: ubuntu-latest env: INFURA_KEY: ${{ secrets.INFURA_KEY }} - MONGODB_COMMENTS_DB: ${{ secrets.MONGODB_COMMENTS_DB }} - MONGODB_URI: ${{ secrets.MONGODB_URI }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} POCKET_KEY: ${{ secrets.POCKET_KEY }} @@ -43,7 +41,7 @@ jobs: - name: Build sdk run: yarn build-sdk - - run: yarn exec playwright install --with-deps + - run: yarn exec playwright install --with-deps - name: Run E2E Test run: yarn run e2e ${{ matrix.test }} diff --git a/README.md b/README.md index 11d2739e8..ceb30d976 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,6 @@ The tag and versioning should be done on develop, and then merged to master thro The portal seeks to rely on on-chain data as much as possible and to minimize reliance on data stored on centralized servers. However, due to the large volume of data that is relevant to Maker governance, fetching this data from on-chain is both time and resource-intensive. In order to improve the user's experience, some reliance on third-party services has been added, and we recommend a few configuration steps for optimal use. These services include: - [GitHub](https://github.com/makerdao/community/tree/master/governance) for storing markdown related to [polls](https://github.com/makerdao/community/tree/master/governance/polls), [executives](https://github.com/makerdao/community/tree/master/governance/votes), and [aligned delegates](https://github.com/makerdao/community/tree/master/governance/delegates) -- MongoDB for storing comments related to votes on polls and executives #### Network providers @@ -87,10 +86,6 @@ The following configuration values can be added to the `.env` file: - Set `GITHUB_TOKEN` to fetch polls, executives, and aligned delegates information from GitHub (optionally set `GITHUB_TOKEN_2` and `GITHUB_TOKEN_3`) -- Set `MONGODB_URI` to a full MongoDB uri (ex: `mongodb+srv://...`) - -- Set `MONGODB_COMMENTS_DB` the MongoDB db name to be used for vote comments - - Set `USE_CACHE` to true if you want to use cache, if `REDIS_URL` is set it will use REDIS otherwise filesystem cache - Set `GASLESS_DISABLED` to `true` to disable gasless voting in UI (pre-check endpoint will fail) diff --git a/lib/config.ts b/lib/config.ts index f892d1393..362f26f12 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -13,8 +13,6 @@ type SystemConfig = { ETHERSCAN_KEY: string; POCKET_KEY: string; TRACING_RPC_NODE: string; - MONGODB_URI: string; - MONGODB_COMMENTS_DB: string; NODE_ENV: 'development' | 'production' | 'test'; GITHUB_TOKEN: string; GITHUB_TOKEN_2: string; @@ -44,8 +42,6 @@ export const config: SystemConfig = { ETHERSCAN_KEY: process.env.ETHERSCAN_KEY || '', POCKET_KEY: process.env.POCKET_KEY || '', TRACING_RPC_NODE: process.env.TRACING_RPC_NODE || '', - MONGODB_URI: process.env.MONGODB_URI || '', - MONGODB_COMMENTS_DB: process.env.MONGODB_COMMENTS_DB || '', NODE_ENV: process.env.NODE_ENV || 'development', GITHUB_TOKEN: process.env.GITHUB_TOKEN || '', GITHUB_TOKEN_2: process.env.GITHUB_TOKEN_2 || '', diff --git a/lib/theme/icons.js b/lib/theme/icons.js index 849e23dd7..baa5f0f48 100644 --- a/lib/theme/icons.js +++ b/lib/theme/icons.js @@ -1338,29 +1338,6 @@ export const icons = { ) }, - yourComment: { - viewBox: '0 0 12 12', - path: ( - - - - - - ) - }, 'Gnosis Safe': { viewBox: '0 0 20 20', path: ( diff --git a/modules/address/components/Address.tsx b/modules/address/components/Address.tsx index 5d79be46f..dd0b104cb 100644 --- a/modules/address/components/Address.tsx +++ b/modules/address/components/Address.tsx @@ -11,6 +11,8 @@ import { formatAddress } from 'lib/utils'; import { useWeb3 } from 'modules/web3/hooks/useWeb3'; import { getENS } from 'modules/web3/helpers/ens'; import React, { useEffect, useState } from 'react'; +import { getDefaultProvider } from 'modules/web3/helpers/getDefaultProvider'; +import { SupportedNetworks } from 'modules/web3/constants/networks'; export const Address = React.memo(function Address({ address, @@ -19,14 +21,15 @@ export const Address = React.memo(function Address({ address: string; maxLength?: number; }): React.ReactElement { - const { provider } = useWeb3(); const [addressFormated, setAddressFormatted] = useState(formatAddress(address || '').toLowerCase()); async function fetchENSName() { - if (!address || !provider) { + if (!address) { return; } + const provider = getDefaultProvider(SupportedNetworks.MAINNET); + const ens = await getENS({ address, provider }); ens ? setAddressFormatted(ens) : setAddressFormatted(formatAddress(address).toLowerCase()); diff --git a/modules/address/components/AddressDelegatedTo.tsx b/modules/address/components/AddressDelegatedTo.tsx index 5dc5a3b35..0b333ce4d 100644 --- a/modules/address/components/AddressDelegatedTo.tsx +++ b/modules/address/components/AddressDelegatedTo.tsx @@ -37,7 +37,7 @@ const CollapsableRow = ({ delegate, network, bpi, totalDelegated }: CollapsableR const { address, lockAmount, events } = delegate; const sortedEvents = events.sort((prev, next) => (prev.blockTimestamp > next.blockTimestamp ? -1 : 1)); - const formattedDate = formatDateWithTime(delegate.expirationDate); + const formattedDate = delegate.expirationDate ? formatDateWithTime(delegate.expirationDate) : ''; const dateText = delegate.isExpired ? `This contract expired ${formattedDate}` : `This contract will expire ${formattedDate}`; @@ -84,7 +84,7 @@ const CollapsableRow = ({ delegate, network, bpi, totalDelegated }: CollapsableR {expanded && ( - {sortedEvents.map(({ blockTimestamp, lockAmount }) => { + {sortedEvents.map(({ blockTimestamp, lockAmount, isLockstake }) => { return ( 0 ? ' MKR' : ''}`} + + + {isLockstake ? '(Seal)' : ''} + ); })} diff --git a/modules/address/components/AddressDetail.tsx b/modules/address/components/AddressDetail.tsx index 5d1b460f9..8bfa23d23 100644 --- a/modules/address/components/AddressDetail.tsx +++ b/modules/address/components/AddressDetail.tsx @@ -20,7 +20,6 @@ import { AddressMKRDelegatedStats } from './AddressMKRDelegatedStats'; import AddressIconBox from './AddressIconBox'; import { useWeb3 } from 'modules/web3/hooks/useWeb3'; import { ErrorBoundary } from 'modules/app/components/ErrorBoundary'; -import AccountComments from 'modules/comments/components/AccountComments'; import Tabs from 'modules/app/components/Tabs'; import { useDelegatedTo } from 'modules/delegates/hooks/useDelegatedTo'; import { InternalLink } from 'modules/app/components/InternalLink'; @@ -43,7 +42,7 @@ export function AddressDetail({ addressInfo }: { addressInfo: AddressApiResponse const { data: delegatedToData } = useDelegatedTo(addressInfo.address, network); - const tabTitles = ['Account Details', 'Comments']; + const tabTitles = ['Account Details']; const tabPanels = [ @@ -134,9 +133,6 @@ export function AddressDetail({ addressInfo }: { addressInfo: AddressApiResponse )} - , - - ]; diff --git a/modules/app/components/DateWithHover.tsx b/modules/app/components/DateWithHover.tsx index 6d39038cd..2529eec1a 100644 --- a/modules/app/components/DateWithHover.tsx +++ b/modules/app/components/DateWithHover.tsx @@ -16,12 +16,15 @@ export function DateWithHover({ timeago, label }: { - date: Date | string | number; + date?: Date | string | number | null; timeago?: boolean; label?: string; }): React.ReactElement { + if (!date) { + return N/A; + } return ( - + {timeago ? `${formatTimeAgo(date ?? '')}` : `${formatDateWithTime(date ?? '')}`} ); diff --git a/modules/comments/api/getCommentTransaction.ts b/modules/comments/api/getCommentTransaction.ts deleted file mode 100644 index da3a28337..000000000 --- a/modules/comments/api/getCommentTransaction.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import { ethers } from 'ethers'; -import logger from 'lib/logger'; -import { FIVE_MINUTES_IN_MS } from 'modules/app/constants/time'; -import { cacheGet, cacheSet } from 'modules/cache/cache'; -import { SupportedNetworks } from 'modules/web3/constants/networks'; -import { CommentFromDB, Comment } from '../types/comments'; - -export async function getCommentTransactionStatus( - network: SupportedNetworks, - provider: ethers.providers.JsonRpcProvider, - comment: CommentFromDB | Comment -): Promise<{ completed: boolean; isValid: boolean }> { - const txHash = comment.txHash; - const cacheKey = `transaction-comment-${txHash}`; - - const cachedResponse = await cacheGet(cacheKey, network); - if (cachedResponse) { - return JSON.parse(cachedResponse); - } - - try { - const transaction = txHash ? await provider.getTransaction(txHash as string) : null; - const isValid = !!transaction; - - const completed = transaction && transaction.confirmations > 10; - const response = { completed: !!completed, isValid: !!isValid }; - - cacheSet(cacheKey, JSON.stringify(response), network, FIVE_MINUTES_IN_MS); - return response; - } catch (e) { - logger.error(`Error fetching comment transcation: ${txHash}`); - return { - completed: false, - isValid: false - }; - } -} diff --git a/modules/comments/api/getCommentsByAddress.ts b/modules/comments/api/getCommentsByAddress.ts deleted file mode 100644 index eb4ca5759..000000000 --- a/modules/comments/api/getCommentsByAddress.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import connectToDatabase from 'modules/db/helpers/connectToDatabase'; -import { getGaslessNetwork, getGaslessProvider, getProvider } from 'modules/web3/helpers/chain'; -import { getAddressInfo } from 'modules/address/api/getAddressInfo'; -import invariant from 'tiny-invariant'; -import { CommentFromDB, CommentsAPIResponseItem } from '../types/comments'; -import { markdownToHtml } from 'lib/markdown'; -import { getCommentTransactionStatus } from './getCommentTransaction'; -import { SupportedNetworks } from 'modules/web3/constants/networks'; - -export async function getCommentsByAddress( - address: string, - network: SupportedNetworks -): Promise<{ - comments: CommentsAPIResponseItem[]; -}> { - const { db, client } = await connectToDatabase; - - invariant(await client.isConnected(), 'mongo client failed to connect'); - - const addressInfo = await getAddressInfo(address, network); - const addresses = [address.toLowerCase()]; - - if (addressInfo.delegateInfo?.previous?.address) { - addresses.push(addressInfo.delegateInfo?.previous?.voteDelegateAddress.toLowerCase()); - } - const gaslessNetwork = getGaslessNetwork(network); - // decending sort - const commentsFromDB: CommentFromDB[] = await db - .collection('comments') - .find({ voterAddress: { $in: addresses }, network: { $in: [network, gaslessNetwork] } }) - .sort({ date: -1 }) - .toArray(); - const provider = await getProvider(network); - const gaslessProvider = await getGaslessProvider(network); - - const comments: CommentsAPIResponseItem[] = await Promise.all( - commentsFromDB.map(async comment => { - const { _id, ...rest } = comment; - const commentBody = await markdownToHtml(comment.comment, true); - // verify tx ownership - const { completed, isValid } = await getCommentTransactionStatus( - network, - comment.gaslessNetwork ? gaslessProvider : provider, - comment - ); - - const item: CommentsAPIResponseItem = { - comment: { - ...rest, - comment: commentBody - }, - isValid, - completed, - - address: addressInfo - }; - - return item; - }) - ); - - return { - comments: comments.filter(i => i.isValid) - }; -} diff --git a/modules/comments/api/getExecutiveComments.ts b/modules/comments/api/getExecutiveComments.ts deleted file mode 100644 index da4b1f50b..000000000 --- a/modules/comments/api/getExecutiveComments.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import { SupportedNetworks } from 'modules/web3/constants/networks'; -import invariant from 'tiny-invariant'; -import uniqBy from 'lodash/uniqBy'; -import { getAddressInfo } from 'modules/address/api/getAddressInfo'; -import { - ExecutiveComment, - ExecutiveCommentFromDB, - ExecutiveCommentsAPIResponseItem -} from '../types/comments'; -import connectToDatabase from 'modules/db/helpers/connectToDatabase'; -import { markdownToHtml } from 'lib/markdown'; -import { networkNameToChainId } from 'modules/web3/helpers/chain'; -import { getRPCFromChainID } from 'modules/web3/helpers/getRPC'; -import { ethers } from 'ethers'; -import { getCommentTransactionStatus } from './getCommentTransaction'; -export async function getExecutiveComments( - spellAddress: string, - network: SupportedNetworks -): Promise { - const { db, client } = await connectToDatabase; - - invariant(await client.isConnected(), 'mongo client failed to connect'); - - const collection = db.collection('comments'); - // decending sort - const commentsFromDB: ExecutiveCommentFromDB[] = await collection - .find({ spellAddress, network, commentType: 'executive' }) - .sort({ date: -1 }) - .toArray(); - - const comments: ExecutiveComment[] = await Promise.all( - commentsFromDB.map(async comment => { - const { _id, voterAddress, ...rest } = comment; - - const commentBody = await markdownToHtml(comment.comment, true); - return { - ...rest, - comment: commentBody, - voterAddress: voterAddress.toLowerCase() - }; - }) - ); - - // only return the latest comment from each address - const uniqueComments = uniqBy(comments, 'voterAddress'); - const rpcUrl = getRPCFromChainID(networkNameToChainId(network)); - const provider = await new ethers.providers.JsonRpcProvider(rpcUrl); - - const promises = uniqueComments.map(async (comment: ExecutiveComment) => { - // verify tx ownership - const { completed, isValid } = await getCommentTransactionStatus(network, provider, comment); - - return { - comment, - address: await getAddressInfo(comment.voterAddress, network), - isValid, - completed - }; - }); - - const response = await Promise.all(promises); - - return response.filter(i => i.isValid) as ExecutiveCommentsAPIResponseItem[]; -} diff --git a/modules/comments/api/getPollComments.ts b/modules/comments/api/getPollComments.ts deleted file mode 100644 index dea989a6a..000000000 --- a/modules/comments/api/getPollComments.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import connectToDatabase from 'modules/db/helpers/connectToDatabase'; -import { SupportedNetworks } from 'modules/web3/constants/networks'; -import { getAddressInfo } from 'modules/address/api/getAddressInfo'; -import invariant from 'tiny-invariant'; -import { PollComment, PollCommentFromDB, PollCommentsAPIResponseItem } from '../types/comments'; -import uniqBy from 'lodash/uniqBy'; -import { markdownToHtml } from 'lib/markdown'; -import { getCommentTransactionStatus } from './getCommentTransaction'; -import { getGaslessProvider, getProvider } from 'modules/web3/helpers/chain'; -export async function getPollComments( - pollId: number, - network: SupportedNetworks -): Promise { - const { db, client } = await connectToDatabase; - - invariant(await client.isConnected(), 'mongo client failed to connect'); - const collection = db.collection('comments'); - // decending sort - const commentsFromDB: PollCommentFromDB[] = await collection - .find({ pollId, network, commentType: 'poll' }) - .sort({ date: -1 }) - .toArray(); - - const provider = await getProvider(network); - const gaslessProvider = await getGaslessProvider(network); - const comments: PollComment[] = await Promise.all( - commentsFromDB.map(async comment => { - const { _id, voterAddress, ...rest } = comment; - - const commentBody = await markdownToHtml(comment.comment, true); - return { - ...rest, - comment: commentBody, - voterAddress: voterAddress.toLowerCase() - }; - }) - ); - - // only return the latest comment from each address - const uniqueComments = uniqBy(comments, 'voterAddress'); - - const promises = uniqueComments.map(async (comment: PollComment) => { - // verify tx ownership - const { completed, isValid } = await getCommentTransactionStatus( - network, - comment.gaslessNetwork ? gaslessProvider : provider, - comment - ); - - return { - comment, - isValid, - completed, - address: await getAddressInfo(comment.voterAddress, network) - }; - }); - - const response = await Promise.all(promises); - - return response.filter(i => i.isValid) as PollCommentsAPIResponseItem[]; -} diff --git a/modules/comments/api/insertExecutiveComment.ts b/modules/comments/api/insertExecutiveComment.ts deleted file mode 100644 index 09a5cdc59..000000000 --- a/modules/comments/api/insertExecutiveComment.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import connectToDatabase from 'modules/db/helpers/connectToDatabase'; -import invariant from 'tiny-invariant'; -import { ExecutiveComment } from '../types/comments'; - -export async function insertExecutiveComment(newComment: ExecutiveComment): Promise { - // query db - const { db, client } = await connectToDatabase; - - invariant(await client.isConnected(), 'Mongo client failed to connect'); - - const collection = db.collection('comments'); - - await collection.insertOne({ - ...newComment, - commentType: 'executive' - }); - - return newComment; -} diff --git a/modules/comments/api/insertPollingComments.ts b/modules/comments/api/insertPollingComments.ts deleted file mode 100644 index 255f8ebd1..000000000 --- a/modules/comments/api/insertPollingComments.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import logger from 'lib/logger'; -import connectToDatabase from 'modules/db/helpers/connectToDatabase'; -import invariant from 'tiny-invariant'; -import { PollComment } from '../types/comments'; - -export async function insertPollComments(comments: PollComment[]): Promise { - // query db - const { db, client } = await connectToDatabase; - - invariant(await client.isConnected(), 'Mongo client failed to connect'); - - const collection = db.collection('comments'); - - try { - await collection.insertMany( - comments - .filter(c => c.comment.length > 0) - .map(comment => { - return { - ...comment, - comment: comment.comment.substring(0, 1500), - commentType: 'poll' - }; - }) - ); - logger.debug(`insertPollComments Inserted ${comments.length} comments.`); - } catch (e) { - logger.error( - `insertPollComments: A MongoBulkWriteException occurred, but there are ${e.result.result.nInserted} successfully processed documents.` - ); - } - - return comments; -} diff --git a/modules/comments/api/nonce.ts b/modules/comments/api/nonce.ts deleted file mode 100644 index 9f69a1d55..000000000 --- a/modules/comments/api/nonce.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -// Generates a nonce for an address and stores it on the DB. -// We use this nonce to verify the message - -import connectToDatabase from 'modules/db/helpers/connectToDatabase'; -import invariant from 'tiny-invariant'; -import { v4 as uuidv4 } from 'uuid'; - -export async function generateNonce(address: string): Promise { - const { db, client } = await connectToDatabase; - invariant(await client.isConnected(), 'mongo client failed to connect'); - - const collection = db.collection('comment-nonces'); - - // If we have a previous nonce, use that. - const previousNonce = await collection.findOne({ - address: address.toLowerCase() - }); - - if (previousNonce) { - return previousNonce.nonce; - } - - // Create a new nonce structure for the DB - const uid = uuidv4(); - const nonce = `/${address}/${uid}`; // The nonce identifier that the user will sign - - // Insert new nonce - await collection.insertOne({ - uid, - nonce, - address: address.toLowerCase(), - createdAt: Date.now() - }); - return nonce; -} - -// Removes all nonces for an address -export async function removeNonces(address: string): Promise { - const { db, client } = await connectToDatabase; - invariant(await client.isConnected(), 'mongo client failed to connect'); - - const collection = db.collection('comment-nonces'); - - await collection.remove({ - address: address.toLowerCase() - }); -} - -export async function getNonce(address: string): Promise<{ - uid: string; - nonce: string; - address: string; -}> { - const { db, client } = await connectToDatabase; - invariant(await client.isConnected(), 'mongo client failed to connect'); - - const collection = db.collection('comment-nonces'); - - return await collection.findOne({ - address: address.toLowerCase() - }); -} diff --git a/modules/comments/api/verifyCommentParameters.ts b/modules/comments/api/verifyCommentParameters.ts deleted file mode 100644 index 4bd40ca25..000000000 --- a/modules/comments/api/verifyCommentParameters.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import { ethers } from 'ethers'; -import { SupportedNetworks } from 'modules/web3/constants/networks'; -import invariant from 'tiny-invariant'; -import { getNonce, removeNonces } from './nonce'; -import { networkNameToChainId } from 'modules/web3/helpers/chain'; -import { getContracts } from 'modules/web3/helpers/getContracts'; -import { ZERO_ADDRESS } from 'modules/web3/constants/addresses'; -import { getDelegateContractAddress } from 'modules/delegates/helpers/getDelegateContractAddress'; - -export async function verifyCommentParameters( - hotAddress: string, - voterAddress: string, - signedMessage: string, - txHash: string, - network: SupportedNetworks -): Promise<'delegate' | 'proxy' | 'normal'> { - invariant(hotAddress && hotAddress.length > 0, 'Invalid voter address'); - invariant(network && network.length > 0, 'Network not supported'); - invariant(txHash && txHash.length > 0, 'Missing verification data'); - - // Check nonce exist in db - // Returns the address + uuid - const nonceDB = await getNonce(hotAddress); - - // Missing nonce means that someone is trying to send a message without the api generating a valid nonce first - invariant(!!nonceDB, 'Invalid data'); - - // verify signature ownership and check that the signed nonce corresponds to the one in db - invariant( - ethers.utils.verifyMessage(nonceDB.nonce, signedMessage).toLowerCase() === - ethers.utils.getAddress(hotAddress).toLowerCase(), - 'invalid message signature' - ); - - // Verify that the voter address is either the hotAddress, the vote delegate address or the vote proxy address - const contracts = getContracts(networkNameToChainId(network), undefined, undefined, true); - - const [proxyAddressCold, proxyAddressHot] = await Promise.all([ - contracts.voteProxyFactory.coldMap(hotAddress), - contracts.voteProxyFactory.hotMap(hotAddress) - ]); - - // We get the vote proxy address and verify that, in case that it exists, is equal to the voter address - let voteProxyAddress = ''; - - // if account belongs to a hot or cold map, get proxy contract address - if (proxyAddressCold !== ZERO_ADDRESS) { - voteProxyAddress = proxyAddressCold; - } else if (proxyAddressHot !== ZERO_ADDRESS) { - voteProxyAddress = proxyAddressHot; - } - - const vdAddress = await getDelegateContractAddress(contracts, hotAddress); - - const voterAddressIsNotRelatedToHotAddress = - voterAddress.toLowerCase() !== voteProxyAddress.toLowerCase() && - voterAddress.toLowerCase() !== vdAddress?.toLowerCase() && - voterAddress.toLowerCase() !== hotAddress.toLowerCase(); - - invariant(!voterAddressIsNotRelatedToHotAddress, 'Invalid voting address'); - - // Validation is good, we delete the nonces for this address - await removeNonces(hotAddress); - - return vdAddress ? 'delegate' : voteProxyAddress ? 'proxy' : 'normal'; -} diff --git a/modules/comments/components/AccountComments.tsx b/modules/comments/components/AccountComments.tsx deleted file mode 100644 index 3efb58a44..000000000 --- a/modules/comments/components/AccountComments.tsx +++ /dev/null @@ -1,97 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import { useWeb3 } from 'modules/web3/hooks/useWeb3'; -import useSWR from 'swr'; -import { Box, Text } from 'theme-ui'; -import Skeleton from 'modules/app/components/SkeletonThemed'; -import { CommentsAPIResponseItem } from '../types/comments'; -import { formatDateWithTime } from 'lib/datetime'; -import { InternalLink } from 'modules/app/components/InternalLink'; - -export default function AccountComments({ address }: { address: string }): React.ReactElement { - const { network } = useWeb3(); - - const { data, error, isValidating } = useSWR<{ - comments: CommentsAPIResponseItem[]; - }>(`/api/comments/${address}?network=${network}`); - - return ( - - {isValidating && !data && ( - - - - - - - - - - - - )} - {error && ( - - Unable to load comments. - - )} - {data && data.comments.length === 0 && ( - - No comments found. - - )} - {data && data.comments.length > 0 && ( - - - Comments - {' '} - {data.comments.map(comment => ( - - - {formatDateWithTime(comment.comment.date)} - - - - {comment.comment.commentType === 'executive' && ( - - View Executive - - )} - {comment.comment.commentType === 'poll' && ( - - View Poll - - )} - - - ))} - - )} - - ); -} diff --git a/modules/comments/components/CommentCount.tsx b/modules/comments/components/CommentCount.tsx deleted file mode 100644 index d2a889bac..000000000 --- a/modules/comments/components/CommentCount.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import InternalIcon from 'modules/app/components/Icon'; -import { Text, Flex } from 'theme-ui'; - -export default function CommentCount({ count }: { count: number }): React.ReactElement { - return ( - - - - {count} Comment{count > 1 ? 's' : ''} - - - ); -} diff --git a/modules/comments/components/CommentItem.tsx b/modules/comments/components/CommentItem.tsx deleted file mode 100644 index d0130c48b..000000000 --- a/modules/comments/components/CommentItem.tsx +++ /dev/null @@ -1,104 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import React from 'react'; -import { Flex, Text, Box } from 'theme-ui'; -import { formatDateWithTime } from 'lib/datetime'; -import { useWeb3 } from 'modules/web3/hooks/useWeb3'; -import DelegateAvatarName from 'modules/delegates/components/DelegateAvatarName'; -import AddressIconBox from 'modules/address/components/AddressIconBox'; -import { ParsedExecutiveComments, PollCommentsAPIResponseItemWithWeight } from '../types/comments'; -import { InternalLink } from 'modules/app/components/InternalLink'; -import { formatValue } from 'lib/string'; -import EtherscanLink from 'modules/web3/components/EtherscanLink'; - -export default function CommentItem({ - comment, - votedOption -}: { - comment: PollCommentsAPIResponseItemWithWeight | ParsedExecutiveComments; - votedOption?: React.ReactNode; -}): React.ReactElement { - const { network } = useWeb3(); - - return ( - - - - {comment.address && ( - - {comment.address.isDelegate && comment.address.delegateInfo ? ( - - ) : ( - - - - - - )} - - )} - - - - {formatDateWithTime(comment.comment.date)} - - - {votedOption - ? votedOption - : `Voted with ${formatValue( - comment.comment.voterWeight, - undefined, - undefined, - true, - true - )} MKR`} - - - {comment.comment.txHash && ( - - - - )} - - - - - - ); -} diff --git a/modules/comments/components/CommentTextBox.tsx b/modules/comments/components/CommentTextBox.tsx deleted file mode 100644 index 0ffa49623..000000000 --- a/modules/comments/components/CommentTextBox.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/* - -SPDX-FileCopyrightText: © 2023 Dai Foundation - -SPDX-License-Identifier: AGPL-3.0-or-later - -*/ - -import React from 'react'; -import { Text, Box, Label, Textarea, Flex } from 'theme-ui'; -import { Icon } from '@makerdao/dai-ui-icons'; -import { useWeb3React } from '@web3-react/core'; -import { getConnection } from 'modules/web3/connections'; -import { ConnectionType } from 'modules/web3/constants/wallets'; - -export default function CommentTextBox({ - value, - onChange, - disabled -}: { - value: string; - onChange: (val: string) => void; - disabled?: boolean; -}): React.ReactElement { - const { connector } = useWeb3React(); - const isGnosis = getConnection(connector).type === ConnectionType.GNOSIS_SAFE; - - return ( - - {!isGnosis && ( - - - - -