diff --git a/src/helpers/crypto.ts b/src/helpers/crypto.ts index 0718ce498b..33c0c03913 100644 --- a/src/helpers/crypto.ts +++ b/src/helpers/crypto.ts @@ -1,5 +1,4 @@ -import { TypedDataSigner } from '@ethersproject/abstract-signer'; -import { Contract, Signer } from 'ethers'; +import { Contract } from 'ethers'; import { hashTypedData, Hash, @@ -14,6 +13,7 @@ import { isHex, encodeFunctionData, Abi, + WalletClient, } from 'viem'; import { MetaTransaction, SafePostTransaction, SafeTransaction } from '../types/transaction'; @@ -43,12 +43,12 @@ export function getRandomBytes() { } export const calculateSafeTransactionHash = ( - safe: Contract, + safeAddress: Address, safeTx: SafeTransaction, chainId: number, ): string => { return hashTypedData({ - domain: { verifyingContract: getAddress(safe.address), chainId }, + domain: { verifyingContract: safeAddress, chainId }, types: EIP712_SAFE_TX_TYPE, primaryType: 'SafeTx', message: { ...safeTx }, @@ -93,22 +93,33 @@ export const buildSafeTransaction = (template: { }; export const safeSignTypedData = async ( - signer: Signer & TypedDataSigner, - safe: Contract, + walletClient: WalletClient, + contractAddress: Address, safeTx: SafeTransaction, - chainId?: number, + chainId: number, ): Promise => { - if (!chainId && !signer.provider) throw Error('Provider required to retrieve chainId'); - const cid = chainId || (await signer.provider!.getNetwork()).chainId; - const signerAddress = await signer.getAddress(); - const signedData = await signer._signTypedData( - { verifyingContract: safe.address, chainId: cid }, - EIP712_SAFE_TX_TYPE, - safeTx, - ); - if (!isHex(signedData)) { - throw new Error('Error signing message'); - } + if (!walletClient.account) throw new Error("Signer doesn't have account"); + + const signerAddress = walletClient.account.address; + const signedData = await walletClient.signTypedData({ + account: signerAddress, + domain: { verifyingContract: contractAddress, chainId }, + types: EIP712_SAFE_TX_TYPE, + primaryType: 'SafeTx', + message: { + to: safeTx.to, + value: safeTx.value, + data: safeTx.data, + operation: safeTx.operation, + safeTxGas: safeTx.safeTxGas, + baseGas: safeTx.baseGas, + gasPrice: safeTx.gasPrice, + gasToken: safeTx.gasToken, + refundReceiver: safeTx.refundReceiver, + nonce: safeTx.nonce, + }, + }); + return { signer: signerAddress, data: signedData, @@ -116,8 +127,8 @@ export const safeSignTypedData = async ( }; export const buildSafeAPIPost = async ( - safeContract: Contract, - signerOrProvider: Signer & TypedDataSigner, + safeAddress: Address, + walletClient: WalletClient, chainId: number, template: { to: Address; @@ -132,20 +143,14 @@ export const buildSafeAPIPost = async ( nonce: number; }, ): Promise => { - const safeTx = buildSafeTransaction(template); + if (!walletClient.account) throw new Error("Signer doesn't have account"); - const txHash = calculateSafeTransactionHash(safeContract, safeTx, chainId); - const sig = [ - await safeSignTypedData( - signerOrProvider as Signer & TypedDataSigner, - safeContract, - safeTx, - chainId, - ), - ]; + const safeTx = buildSafeTransaction(template); + const txHash = calculateSafeTransactionHash(safeAddress, safeTx, chainId); + const sig = [await safeSignTypedData(walletClient, safeAddress, safeTx, chainId)]; const signatureBytes = buildSignatureBytes(sig); return { - safe: safeContract.address, + safe: safeAddress, to: safeTx.to, value: safeTx.value ? safeTx.value.toString() : '0', data: safeTx.data, @@ -157,7 +162,7 @@ export const buildSafeAPIPost = async ( refundReceiver: safeTx.refundReceiver, nonce: safeTx.nonce, contractTransactionHash: txHash, - sender: await signerOrProvider.getAddress(), + sender: walletClient.account.address, signature: signatureBytes, }; }; diff --git a/src/hooks/DAO/proposal/useSubmitProposal.ts b/src/hooks/DAO/proposal/useSubmitProposal.ts index a62096c0e5..217fcfe891 100644 --- a/src/hooks/DAO/proposal/useSubmitProposal.ts +++ b/src/hooks/DAO/proposal/useSubmitProposal.ts @@ -1,18 +1,15 @@ -import { TypedDataSigner } from '@ethersproject/abstract-signer'; import { Azorius } from '@fractal-framework/fractal-contracts'; import axios from 'axios'; -import { Signer } from 'ethers'; import { useCallback, useMemo, useState } from 'react'; import { toast } from 'react-toastify'; import { isAddress, getAddress, encodeAbiParameters, parseAbiParameters, isHex } from 'viem'; -import { GnosisSafeL2__factory } from '../../../assets/typechain-types/usul/factories/@gnosis.pm/safe-contracts/contracts'; +import { useWalletClient } from 'wagmi'; import { ADDRESS_MULTISIG_METADATA, SENTINEL_ADDRESS } from '../../../constants/common'; import { buildSafeAPIPost, encodeMultiSend } from '../../../helpers'; import { logError } from '../../../helpers/errorLogging'; import { useFractal } from '../../../providers/App/AppProvider'; import useIPFSClient from '../../../providers/App/hooks/useIPFSClient'; import { useSafeAPI } from '../../../providers/App/hooks/useSafeAPI'; -import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; import { MetaTransaction, ProposalExecuteData, CreateProposalMetadata } from '../../../types'; @@ -54,7 +51,7 @@ export default function useSubmitProposal() { const [pendingCreateTx, setPendingCreateTx] = useState(false); const loadDAOProposals = useDAOProposals(); const signer = useEthersSigner(); - const provider = useEthersProvider(); + const { data: walletClient } = useWalletClient(); const { node: { safe, fractalModules }, @@ -91,7 +88,7 @@ export default function useSubmitProposal() { successCallback, safeAddress, }: ISubmitProposal) => { - if (!proposalData || !baseContracts) { + if (!proposalData || !baseContracts || !walletClient) { return; } const { multiSendContract } = baseContracts; @@ -162,21 +159,15 @@ export default function useSubmitProposal() { operation = 0; } - const safeContract = GnosisSafeL2__factory.connect(safeAddress, signerOrProvider); await axios.post( buildSafeApiUrl(safeBaseURL, `/safes/${safeAddress}/multisig-transactions/`), - await buildSafeAPIPost( - safeContract, - signerOrProvider as Signer & TypedDataSigner, - chain.id, - { - to, - value, - data, - operation, - nonce, - }, - ), + await buildSafeAPIPost(getAddress(safeAddress), walletClient, chain.id, { + to, + value, + data, + operation, + nonce, + }), ); await new Promise(resolve => setTimeout(resolve, 1000)); await loadDAOProposals(); @@ -194,13 +185,14 @@ export default function useSubmitProposal() { } }, [ - signerOrProvider, - safeBaseURL, - chain, - loadDAOProposals, - ipfsClient, - baseContracts, addressPrefix, + baseContracts, + chain.id, + ipfsClient, + loadDAOProposals, + safeBaseURL, + signerOrProvider, + walletClient, ], ); @@ -215,7 +207,7 @@ export default function useSubmitProposal() { failedToastMessage, safeAddress, }: ISubmitAzoriusProposal) => { - if (!proposalData || !provider) { + if (!proposalData) { return; } const toastId = toast(pendingToastMessage, { @@ -261,7 +253,7 @@ export default function useSubmitProposal() { setPendingCreateTx(false); } }, - [provider, addressPrefix], + [addressPrefix], ); const submitProposal = useCallback(