Skip to content

Commit

Permalink
Merge pull request #1597 from decentdao/refactor/replace-solidityKecc…
Browse files Browse the repository at this point in the history
…ak256
  • Loading branch information
adamgall authored May 4, 2024
2 parents 1985843 + bb133f5 commit b1d9cf6
Show file tree
Hide file tree
Showing 65 changed files with 2,211 additions and 673 deletions.
1,138 changes: 1,138 additions & 0 deletions src/assets/abi/GnosisSafeL2.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/components/DaoCreator/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const initialState: CreatorFormState = {
erc721Token: {
nfts: [
{
tokenAddress: '',
tokenAddress: undefined,
tokenWeight: {
value: '',
},
Expand Down
24 changes: 16 additions & 8 deletions src/components/DaoCreator/formComponents/AzoriusNFTDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Flex, Box, Text } from '@chakra-ui/react';
import { ethers } from 'ethers';
import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { erc721Abi, isAddress } from 'viem';
import { erc721Abi, getContract, isAddress } from 'viem';
import { usePublicClient, useWalletClient } from 'wagmi';
import useDisplayName from '../../../hooks/utils/useDisplayName';
import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider';
import { BigIntValuePair, ERC721TokenConfig } from '../../../types';
import { BarLoader } from '../../ui/loaders/BarLoader';

Expand All @@ -25,20 +24,29 @@ export default function AzoriusNFTDetail({
const [tokenDetails, setTokenDetails] = useState<TokenDetails>();
const { t } = useTranslation('daoCreate');

const provider = useEthersProvider();
const publicClient = usePublicClient();
const { data: walletClient } = useWalletClient();

const { displayName } = useDisplayName(tokenDetails?.address, true);

useEffect(() => {
const loadNFTDetails = async () => {
if (hasAddressError) {
if (hasAddressError || !publicClient) {
return;
}

setLoading(true);
try {
if (nft.tokenAddress && isAddress(nft.tokenAddress)) {
const tokenContract = new ethers.Contract(nft.tokenAddress, erc721Abi, provider);
const [name, symbol] = await Promise.all([tokenContract.name(), tokenContract.symbol()]);
const tokenContract = getContract({
address: nft.tokenAddress,
abi: erc721Abi,
client: { public: publicClient, wallet: walletClient },
});
const [name, symbol] = await Promise.all([
tokenContract.read.name(),
tokenContract.read.symbol(),
]);
setTokenDetails({
name,
symbol,
Expand All @@ -54,7 +62,7 @@ export default function AzoriusNFTDetail({
};

loadNFTDetails();
}, [hasAddressError, nft, provider]);
}, [hasAddressError, nft, publicClient, walletClient]);

const showData = !!tokenDetails && !loading && !hasAddressError;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function AzoriusNFTDetails(props: ICreationStepProps) {
const handleAddNFT = () => {
setFieldValue('erc721Token.nfts', [
...values.erc721Token.nfts,
{ tokenAddress: '', tokenWeight: { value: '' } },
{ tokenAddress: undefined, tokenWeight: { value: '' } },
]);
};

Expand Down Expand Up @@ -74,7 +74,7 @@ export default function AzoriusNFTDetails(props: ICreationStepProps) {
>
)?.[i];
const addressErrorMessage =
nftError?.tokenAddress && nft.tokenAddress.length
nftError?.tokenAddress && nft.tokenAddress?.length
? nftError.tokenAddress
: undefined;
const weightErrorMessage =
Expand Down Expand Up @@ -202,7 +202,7 @@ export default function AzoriusNFTDetails(props: ICreationStepProps) {
>
)?.[i];
const addressErrorMessage =
nftError?.tokenAddress && nft.tokenAddress.length
nftError?.tokenAddress && nft.tokenAddress?.length
? nftError.tokenAddress
: undefined;
return (
Expand Down
32 changes: 22 additions & 10 deletions src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Box, Flex, Input, RadioGroup, Text } from '@chakra-ui/react';
import { LabelWrapper } from '@decent-org/fractal-ui';
import { ethers } from 'ethers';
import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { erc20Abi, isAddress, zeroAddress } from 'viem';
import { erc20Abi, getContract, isAddress, zeroAddress } from 'viem';
import { usePublicClient, useWalletClient } from 'wagmi';
import { BACKGROUND_SEMI_TRANSPARENT } from '../../../constants/common';
import { createAccountSubstring } from '../../../hooks/utils/useDisplayName';
import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider';
import { TokenCreationType, ICreationStepProps } from '../../../types';
import SupportTooltip from '../../ui/badges/SupportTooltip';
import ContentBoxTitle from '../../ui/containers/ContentBox/ContentBoxTitle';
Expand Down Expand Up @@ -41,23 +40,35 @@ export function AzoriusTokenDetails(props: ICreationStepProps) {
} = props;

const { t } = useTranslation('daoCreate');
const provider = useEthersProvider();
const { data: walletClient } = useWalletClient();
const publicClient = usePublicClient();

const { checkVotesToken } = usePrepareFormData();
const [isImportedVotesToken, setIsImportedVotesToken] = useState(false);

const updateImportFields = useCallback(async () => {
if (!publicClient) {
return;
}
const importAddress = values.erc20Token.tokenImportAddress;
const importError = errors?.erc20Token?.tokenImportAddress;
if (importAddress && !importError && isAddress(importAddress)) {
const isVotesToken = await checkVotesToken(importAddress);
const tokenContract = new ethers.Contract(importAddress, erc20Abi, provider);
const name: string = await tokenContract.name();
const symbol: string = await tokenContract.symbol();
const decimals: number = await tokenContract.decimals();
const tokenContract = getContract({
address: importAddress,
abi: erc20Abi,
client: { wallet: walletClient, public: publicClient },
});
const [name, symbol, decimals] = await Promise.all([
tokenContract.read.name(),
tokenContract.read.symbol(),
tokenContract.read.decimals(),
]);

// @dev: this turns "total supply" into the human-readable form (without decimals)
const totalSupply: number = (await tokenContract.totalSupply()) / 10 ** decimals;
const totalSupply = Number(
(await tokenContract.read.totalSupply()) / 10n ** BigInt(decimals),
);

setFieldValue(
'erc20Token.tokenSupply',
Expand All @@ -83,7 +94,8 @@ export function AzoriusTokenDetails(props: ICreationStepProps) {
checkVotesToken,
errors?.erc20Token?.tokenImportAddress,
setFieldValue,
provider,
publicClient,
walletClient,
values.erc20Token.tokenImportAddress,
]);

Expand Down
16 changes: 8 additions & 8 deletions src/components/DaoCreator/hooks/usePrepareFormData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IVotes__factory } from '@fractal-framework/fractal-contracts';

import { useCallback } from 'react';
import { getAddress } from 'viem';
import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider';
import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner';
import {
Expand Down Expand Up @@ -74,8 +74,8 @@ export function usePrepareFormData() {
}: SafeMultisigDAO & FreezeGuardConfigParam) => {
const resolvedAddresses = await Promise.all(
trustedAddresses.map(async inputValue => {
if (couldBeENS(inputValue)) {
const resolvedAddress = await signer!.resolveName(inputValue);
if (couldBeENS(inputValue) && signer) {
const resolvedAddress = await signer.resolveName(inputValue);
return resolvedAddress;
}
return inputValue;
Expand Down Expand Up @@ -114,8 +114,8 @@ export function usePrepareFormData() {
const resolvedTokenAllocations = await Promise.all(
tokenAllocations.map(async allocation => {
let address = allocation.address;
if (couldBeENS(address)) {
address = await signer!.resolveName(allocation.address);
if (couldBeENS(address) && signer) {
address = await signer.resolveName(allocation.address);
}
return { amount: allocation.amount.bigintValue!, address: address };
}),
Expand Down Expand Up @@ -163,7 +163,7 @@ export function usePrepareFormData() {
}: AzoriusERC721DAO<BigIntValuePair> & FreezeGuardConfigParam): Promise<
AzoriusERC721DAO | undefined
> => {
if (provider) {
if (provider && signer) {
let freezeGuardData;
if (freezeGuard) {
freezeGuardData = await prepareFreezeGuardData(freezeGuard);
Expand All @@ -172,8 +172,8 @@ export function usePrepareFormData() {
const resolvedNFTs = await Promise.all(
nfts.map(async nft => {
let address = nft.tokenAddress;
if (couldBeENS(address)) {
address = await signer!.resolveName(nft.tokenAddress);
if (couldBeENS(address) && nft.tokenAddress) {
address = getAddress(await signer.resolveName(nft.tokenAddress));
}
return {
tokenAddress: address,
Expand Down
10 changes: 9 additions & 1 deletion src/components/ProposalBuilder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Formik, FormikProps } from 'formik';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify';
import { BACKGROUND_SEMI_TRANSPARENT } from '../../constants/common';
import { DAO_ROUTES, BASE_ROUTES } from '../../constants/routes';
import useSubmitProposal from '../../hooks/DAO/proposal/useSubmitProposal';
Expand Down Expand Up @@ -61,7 +62,11 @@ export default function ProposalBuilder({
initialValues={initialValues}
enableReinitialize
onSubmit={async values => {
if (canUserCreateProposal) {
if (!canUserCreateProposal) {
toast(t('errorNotProposer', { ns: 'common' }));
}

try {
const proposalData = await prepareProposalData(values);
if (proposalData) {
submitProposal({
Expand All @@ -73,6 +78,9 @@ export default function ProposalBuilder({
successCallback,
});
}
} catch (e) {
console.error(e);
toast(t('encodingFailedMessage', { ns: 'proposal' }));
}
}}
>
Expand Down
55 changes: 44 additions & 11 deletions src/components/Proposals/MultisigProposalDetails/TxActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TypedDataSigner } from '@ethersproject/abstract-signer';
import { SafeMultisigTransactionWithTransfersResponse } from '@safe-global/safe-service-client';
import { Signer } from 'ethers';
import { useTranslation } from 'react-i18next';
import { Hex, getAddress, isHex } from 'viem';
import { GnosisSafeL2__factory } from '../../../assets/typechain-types/usul/factories/@gnosis.pm/safe-contracts/contracts';
import { BACKGROUND_SEMI_TRANSPARENT } from '../../../constants/common';
import { buildSafeTransaction, buildSignatureBytes, EIP712_SAFE_TX_TYPE } from '../../../helpers';
Expand Down Expand Up @@ -43,12 +44,16 @@ export function TxActions({ proposal }: { proposal: MultisigProposal }) {
if (!multisigTx) return null;

const signTransaction = async () => {
if (!signerOrProvider || !safe?.address) {
if (!signerOrProvider || !safe?.address || (multisigTx.data && !isHex(multisigTx.data))) {
return;
}
try {
const safeTx = buildSafeTransaction({
...multisigTx,
to: getAddress(multisigTx.to),
value: BigInt(multisigTx.value),
data: multisigTx.data as Hex | undefined,
operation: multisigTx.operation as 0 | 1,
});

asyncRequest({
Expand All @@ -73,17 +78,31 @@ export function TxActions({ proposal }: { proposal: MultisigProposal }) {

const timelockTransaction = async () => {
try {
if (!multisigTx.confirmations || !baseContracts || !freezeGuardContractAddress) {
if (
!multisigTx.confirmations ||
!baseContracts ||
!freezeGuardContractAddress ||
(multisigTx.data && !isHex(multisigTx.data))
) {
return;
}
const safeTx = buildSafeTransaction({
...multisigTx,
to: getAddress(multisigTx.to),
value: BigInt(multisigTx.value),
data: multisigTx.data as Hex | undefined,
operation: multisigTx.operation as 0 | 1,
});
const signatures = buildSignatureBytes(
multisigTx.confirmations.map(confirmation => ({
signer: confirmation.owner,
data: confirmation.signature,
})),
multisigTx.confirmations.map(confirmation => {
if (!isHex(confirmation.signature)) {
throw new Error('Confirmation signature is malfunctioned');
}
return {
signer: confirmation.owner,
data: confirmation.signature,
};
}),
);
const freezeGuard = baseContracts.multisigFreezeGuardMasterCopyContract.asSigner.attach(
freezeGuardContractAddress,
Expand Down Expand Up @@ -117,18 +136,32 @@ export function TxActions({ proposal }: { proposal: MultisigProposal }) {

const executeTransaction = async () => {
try {
if (!signerOrProvider || !safe?.address || !multisigTx.confirmations) {
if (
!signerOrProvider ||
!safe?.address ||
!multisigTx.confirmations ||
(multisigTx.data && !isHex(multisigTx.data))
) {
return;
}
const safeContract = GnosisSafeL2__factory.connect(safe.address, signerOrProvider);
const safeTx = buildSafeTransaction({
...multisigTx,
to: getAddress(multisigTx.to),
value: BigInt(multisigTx.value),
data: multisigTx.data as Hex | undefined,
operation: multisigTx.operation as 0 | 1,
});
const signatures = buildSignatureBytes(
multisigTx.confirmations.map(confirmation => ({
signer: confirmation.owner,
data: confirmation.signature,
})),
multisigTx.confirmations.map(confirmation => {
if (!isHex(confirmation.signature)) {
throw new Error('Confirmation signature is malfunctioned');
}
return {
signer: confirmation.owner,
data: confirmation.signature,
};
}),
);
contractCall({
contractFn: () =>
Expand Down
26 changes: 15 additions & 11 deletions src/components/pages/DAOTreasury/hooks/useSendAssets.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SafeBalanceUsdResponse } from '@safe-global/safe-service-client';
import { ethers } from 'ethers';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { encodeAbiParameters, parseAbiParameters, isAddress, getAddress, Hex } from 'viem';
import useSubmitProposal from '../../../../hooks/DAO/proposal/useSubmitProposal';
import { ProposalExecuteData } from '../../../../types';
import { formatCoin } from '../../../../utils/numberFormats';
Expand All @@ -14,7 +14,7 @@ const useSendAssets = ({
}: {
transferAmount: bigint;
asset: SafeBalanceUsdResponse;
destinationAddress: string;
destinationAddress: string | undefined;
nonce: number | undefined;
}) => {
const { submitProposal } = useSubmitProposal();
Expand All @@ -30,18 +30,22 @@ const useSendAssets = ({
asset?.token?.symbol,
);

const funcSignature = 'function transfer(address to, uint256 value)';
const calldatas = [
new ethers.utils.Interface([funcSignature]).encodeFunctionData('transfer', [
destinationAddress,
transferAmount,
]),
];
let calldatas = ['0x' as Hex];
let target =
isEth && destinationAddress ? getAddress(destinationAddress) : getAddress(asset.tokenAddress);
if (!isEth && destinationAddress && isAddress(destinationAddress)) {
calldatas = [
encodeAbiParameters(parseAbiParameters('address, uint256'), [
destinationAddress,
transferAmount,
]),
];
}

const proposalData: ProposalExecuteData = {
targets: [isEth ? destinationAddress : asset.tokenAddress],
targets: [target],
values: [isEth ? transferAmount : 0n],
calldatas: isEth ? ['0x'] : calldatas,
calldatas,
metaData: {
title: t(isEth ? 'Send Eth' : 'Send Token', { ns: 'proposalMetadata' }),
description: description,
Expand Down
Loading

0 comments on commit b1d9cf6

Please sign in to comment.