From edd9275a8974a41adcf355e0db907934421907c1 Mon Sep 17 00:00:00 2001 From: Adam Gall Date: Wed, 8 May 2024 15:54:48 -0400 Subject: [PATCH 1/5] Remove GnosisSafeL2 typechain from TxActions --- .../MultisigProposalDetails/TxActions.tsx | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/components/Proposals/MultisigProposalDetails/TxActions.tsx b/src/components/Proposals/MultisigProposalDetails/TxActions.tsx index e9b2944464..7d14b235d1 100644 --- a/src/components/Proposals/MultisigProposalDetails/TxActions.tsx +++ b/src/components/Proposals/MultisigProposalDetails/TxActions.tsx @@ -4,8 +4,9 @@ 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 { Hex, getAddress, getContract, isHex } from 'viem'; +import { useWalletClient } from 'wagmi'; +import GnosisSafeL2Abi from '../../../assets/abi/GnosisSafeL2'; import { BACKGROUND_SEMI_TRANSPARENT } from '../../../constants/common'; import { buildSafeTransaction, buildSignatureBytes, EIP712_SAFE_TX_TYPE } from '../../../helpers'; import { logError } from '../../../helpers/errorLogging'; @@ -34,9 +35,11 @@ export function TxActions({ proposal }: { proposal: MultisigProposal }) { const { t } = useTranslation(['proposal', 'common', 'transaction']); const [asyncRequest, asyncRequestPending] = useAsyncRequest(); - const [contractCall, contractCallPending] = useTransaction(); + const [contractCall, contractCallPending, contractCallViem] = useTransaction(); const loadSafeMultisigProposals = useSafeMultisigProposals(); const baseContracts = useSafeContracts(); + const { data: walletClient } = useWalletClient(); + if (user.votingWeight === 0n) return <>; const multisigTx = proposal.transaction as SafeMultisigTransactionWithTransfersResponse; @@ -140,11 +143,17 @@ export function TxActions({ proposal }: { proposal: MultisigProposal }) { !signerOrProvider || !safe?.address || !multisigTx.confirmations || - (multisigTx.data && !isHex(multisigTx.data)) + (multisigTx.data && !isHex(multisigTx.data)) || + !walletClient ) { return; } - const safeContract = GnosisSafeL2__factory.connect(safe.address, signerOrProvider); + + const safeContract = getContract({ + abi: GnosisSafeL2Abi, + address: getAddress(safe.address), + client: walletClient, + }); const safeTx = buildSafeTransaction({ ...multisigTx, to: getAddress(multisigTx.to), @@ -163,20 +172,20 @@ export function TxActions({ proposal }: { proposal: MultisigProposal }) { }; }), ); - contractCall({ + contractCallViem({ contractFn: () => - safeContract.execTransaction( + safeContract.write.execTransaction([ safeTx.to, safeTx.value, safeTx.data, safeTx.operation, - safeTx.safeTxGas, - safeTx.baseGas, - safeTx.gasPrice, - safeTx.gasToken, - safeTx.refundReceiver, + BigInt(safeTx.safeTxGas), + BigInt(safeTx.baseGas), + BigInt(safeTx.gasPrice), + getAddress(safeTx.gasToken), + getAddress(safeTx.refundReceiver), signatures, - ), + ]), failedMessage: t('failedExecute', { ns: 'transaction' }), pendingMessage: t('pendingExecute', { ns: 'transaction' }), successMessage: t('successExecute', { ns: 'transaction' }), From 0a98bd9337486f78c5e08dedb37d05ab42310f99 Mon Sep 17 00:00:00 2001 From: Adam Gall Date: Wed, 8 May 2024 15:54:48 -0400 Subject: [PATCH 2/5] Remove GnosisSafeL2 typechain from DaoTxBuilder --- src/models/DaoTxBuilder.ts | 4 ++-- src/models/helpers/fractalModuleData.ts | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/models/DaoTxBuilder.ts b/src/models/DaoTxBuilder.ts index 2e65ca68c5..ca50f19db2 100644 --- a/src/models/DaoTxBuilder.ts +++ b/src/models/DaoTxBuilder.ts @@ -220,9 +220,9 @@ export class DaoTxBuilder extends BaseTxBuilder { const { enableFractalModuleTx, deployFractalModuleTx }: FractalModuleData = fractalModuleData( this.baseContracts.fractalModuleMasterCopyContract, getAddress(this.moduleProxyFactoryAddress), - this.safeContract!, + getAddress(this.safeContract.address), this.saltNum, - this.parentAddress, + !this.parentAddress ? undefined : getAddress(this.parentAddress), ); this.enableFractalModuleTx = enableFractalModuleTx; diff --git a/src/models/helpers/fractalModuleData.ts b/src/models/helpers/fractalModuleData.ts index 78cca40d4b..f81e3afb9c 100644 --- a/src/models/helpers/fractalModuleData.ts +++ b/src/models/helpers/fractalModuleData.ts @@ -9,9 +9,9 @@ import { keccak256, encodePacked, } from 'viem'; +import GnosisSafeL2Abi from '../../assets/abi/GnosisSafeL2'; import ModuleProxyFactoryAbi from '../../assets/abi/ModuleProxyFactory'; -import { GnosisSafeL2 } from '../../assets/typechain-types/usul/@gnosis.pm/safe-contracts/contracts'; -import { buildContractCall, buildContractCallViem } from '../../helpers/crypto'; +import { buildContractCallViem } from '../../helpers/crypto'; import { SafeTransaction } from '../../types'; import { generateContractByteCodeLinear, generateSalt } from './utils'; @@ -24,17 +24,17 @@ export interface FractalModuleData { export const fractalModuleData = ( fractalModuleMasterCopyContract: FractalModule, moduleProxyFactoryAddress: Address, - safeContract: GnosisSafeL2, + safeAddress: Address, saltNum: bigint, - parentAddress?: string, + parentAddress?: Address, ): FractalModuleData => { const fractalModuleCalldata = FractalModule__factory.createInterface().encodeFunctionData( 'setUp', [ encodeAbiParameters(parseAbiParameters(['address, address, address, address[]']), [ - getAddress(parentAddress ?? safeContract.address), // Owner -- Parent DAO or safe contract - getAddress(safeContract.address), // Avatar - getAddress(safeContract.address), // Target + parentAddress ?? safeAddress, // Owner -- Parent DAO or safe contract + safeAddress, // Avatar + safeAddress, // Target [], // Authorized Controllers ]), ], @@ -65,8 +65,9 @@ export const fractalModuleData = ( bytecodeHash: keccak256(encodePacked(['bytes'], [fractalByteCodeLinear])), }); - const enableFractalModuleTx = buildContractCall( - safeContract, + const enableFractalModuleTx = buildContractCallViem( + GnosisSafeL2Abi, + safeAddress, 'enableModule', [predictedFractalModuleAddress], 0, From 07696c881a8bac26c41b45b3c05b3505ed33240e Mon Sep 17 00:00:00 2001 From: Adam Gall Date: Wed, 8 May 2024 15:54:48 -0400 Subject: [PATCH 3/5] Remove GnosisSafeL2 Typechain from TxBuilderFactory and Builder classes --- src/models/AzoriusTxBuilder.ts | 38 +++++++++++++++++------------- src/models/DaoTxBuilder.ts | 21 +++++++++-------- src/models/FreezeGuardTxBuilder.ts | 23 +++++++++++++----- src/models/MultisigTxBuilder.ts | 20 ++++++++++------ src/models/TxBuilderFactory.ts | 20 +++++++--------- 5 files changed, 71 insertions(+), 51 deletions(-) diff --git a/src/models/AzoriusTxBuilder.ts b/src/models/AzoriusTxBuilder.ts index 7334cb4999..d22cbad6a0 100644 --- a/src/models/AzoriusTxBuilder.ts +++ b/src/models/AzoriusTxBuilder.ts @@ -20,10 +20,10 @@ import { encodeFunctionData, PublicClient, } from 'viem'; +import GnosisSafeL2Abi from '../assets/abi/GnosisSafeL2'; import ModuleProxyFactoryAbi from '../assets/abi/ModuleProxyFactory'; import VotesERC20Abi from '../assets/abi/VotesERC20'; import VotesERC20WrapperAbi from '../assets/abi/VotesERC20Wrapper'; -import { GnosisSafeL2 } from '../assets/typechain-types/usul/@gnosis.pm/safe-contracts/contracts'; import { SENTINEL_ADDRESS } from '../constants/common'; import { buildContractCall, buildContractCallViem, getRandomBytes } from '../helpers'; import { @@ -39,7 +39,7 @@ import { BaseTxBuilder } from './BaseTxBuilder'; import { generateContractByteCodeLinear, generateSalt } from './helpers/utils'; export class AzoriusTxBuilder extends BaseTxBuilder { - private readonly safeContract: GnosisSafeL2; + private readonly safeContractAddress: Address; private encodedSetupTokenData: Hex | undefined; private encodedSetupERC20WrapperData: Hex | undefined; @@ -72,7 +72,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { baseContracts: BaseContracts, azoriusContracts: AzoriusContracts, daoData: AzoriusERC20DAO | AzoriusERC721DAO, - safeContract: GnosisSafeL2, + safeContractAddress: Address, votesERC20WrapperMasterCopyAddress: string, votesERC20MasterCopyAddress: string, moduleProxyFactoryAddress: Address, @@ -89,7 +89,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { parentTokenAddress, ); - this.safeContract = safeContract; + this.safeContractAddress = safeContractAddress; this.tokenNonce = getRandomBytes(); this.claimNonce = getRandomBytes(); @@ -139,8 +139,9 @@ export class AzoriusTxBuilder extends BaseTxBuilder { public buildRemoveOwners(owners: string[]): SafeTransaction[] { const removeOwnerTxs = owners.map(owner => - buildContractCall( - this.safeContract!, + buildContractCallViem( + GnosisSafeL2Abi, + this.safeContractAddress, 'removeOwner', [this.baseContracts.multiSendContract.address, owner, 1], 0, @@ -164,8 +165,9 @@ export class AzoriusTxBuilder extends BaseTxBuilder { } public buildEnableAzoriusModuleTx(): SafeTransaction { - return buildContractCall( - this.safeContract!, + return buildContractCallViem( + GnosisSafeL2Abi, + this.safeContractAddress, 'enableModule', [this.azoriusContract!.address], 0, @@ -174,8 +176,9 @@ export class AzoriusTxBuilder extends BaseTxBuilder { } public buildAddAzoriusContractAsOwnerTx(): SafeTransaction { - return buildContractCall( - this.safeContract!, + return buildContractCallViem( + GnosisSafeL2Abi, + this.safeContractAddress, 'addOwnerWithThreshold', [this.azoriusContract!.address, 1], 0, @@ -184,8 +187,9 @@ export class AzoriusTxBuilder extends BaseTxBuilder { } public buildRemoveMultiSendOwnerTx(): SafeTransaction { - return buildContractCall( - this.safeContract!, + return buildContractCallViem( + GnosisSafeL2Abi, + this.safeContractAddress, 'removeOwner', [this.azoriusContract!.address, this.baseContracts.multiSendContract.address, 1], 0, @@ -339,7 +343,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { // Send any un-allocated tokens to the Safe Treasury if (azoriusGovernanceDaoData.tokenSupply > tokenAllocationSum) { // TODO -- verify this doesn't need to be the predicted safe address (that they are the same) - tokenAllocationsOwners.push(getAddress(this.safeContract.address)); + tokenAllocationsOwners.push(this.safeContractAddress); tokenAllocationsValues.push(azoriusGovernanceDaoData.tokenSupply - tokenAllocationSum); } @@ -391,7 +395,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { parseAbiParameters('uint32, address, address, address, uint256'), [ 0, // `deadlineBlock`, 0 means never expires, currently no UI for setting this in the app. - getAddress(this.safeContract.address), + this.safeContractAddress, getAddress(this.parentTokenAddress), getAddress(this.predictedTokenAddress), azoriusGovernanceDaoData.parentAllocationAmount, @@ -435,7 +439,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { const encodedStrategyInitParams = encodeAbiParameters( parseAbiParameters('address, address, address, uint32, uint256, uint256, uint256'), [ - getAddress(this.safeContract.address), // owner + this.safeContractAddress, // owner getAddress(this.predictedTokenAddress), // governance token SENTINEL_ADDRESS, // Azorius module Number(azoriusGovernanceDaoData.votingPeriod), @@ -480,7 +484,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { 'address, address[], uint256[], address, uint32, uint256, uint256, uint256', ), [ - getAddress(this.safeContract.address), // owner + this.safeContractAddress, // owner daoData.nfts.map(nft => nft.tokenAddress!), // governance tokens addresses daoData.nfts.map(nft => nft.tokenWeight), // governance tokens weights SENTINEL_ADDRESS, // Azorius module @@ -525,7 +529,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { // TODO - verify we can use safe contract address private setPredictedAzoriusAddress() { const azoriusGovernanceDaoData = this.daoData as AzoriusGovernanceDAO; - const safeContractAddress = getAddress(this.safeContract.address); + const safeContractAddress = this.safeContractAddress; const encodedInitAzoriusData = encodeAbiParameters( parseAbiParameters(['address, address, address, address[], uint32, uint32']), [ diff --git a/src/models/DaoTxBuilder.ts b/src/models/DaoTxBuilder.ts index ca50f19db2..44cacb9dd2 100644 --- a/src/models/DaoTxBuilder.ts +++ b/src/models/DaoTxBuilder.ts @@ -1,9 +1,9 @@ import { ethers } from 'ethers'; -import { PublicClient, getAddress, zeroAddress } from 'viem'; +import { Address, PublicClient, getAddress, zeroAddress } from 'viem'; import FractalRegistryAbi from '../assets/abi/FractalRegistry'; +import GnosisSafeL2Abi from '../assets/abi/GnosisSafeL2'; import KeyValuePairsAbi from '../assets/abi/KeyValuePairs'; -import { GnosisSafeL2 } from '../assets/typechain-types/usul/@gnosis.pm/safe-contracts/contracts'; -import { buildContractCall, buildContractCallViem, encodeMultiSend } from '../helpers'; +import { buildContractCallViem, encodeMultiSend } from '../helpers'; import { BaseContracts, SafeMultisigDAO, @@ -24,7 +24,7 @@ export class DaoTxBuilder extends BaseTxBuilder { // Safe Data private readonly createSafeTx: SafeTransaction; - private readonly safeContract: GnosisSafeL2; + private readonly safeContractAddress: Address; private readonly parentStrategyType?: VotingStrategyType; private readonly parentStrategyAddress?: string; @@ -46,7 +46,7 @@ export class DaoTxBuilder extends BaseTxBuilder { daoData: SafeMultisigDAO | AzoriusERC20DAO | AzoriusERC721DAO, saltNum: bigint, createSafeTx: SafeTransaction, - safeContract: GnosisSafeL2, + safeContractAddress: Address, txBuilderFactory: TxBuilderFactory, keyValuePairsAddress: string, fractalRegistryAddress: string, @@ -67,7 +67,7 @@ export class DaoTxBuilder extends BaseTxBuilder { ); this.createSafeTx = createSafeTx; - this.safeContract = safeContract; + this.safeContractAddress = safeContractAddress; this.txBuilderFactory = txBuilderFactory; this.saltNum = saltNum; this.parentStrategyType = parentStrategyType; @@ -192,7 +192,7 @@ export class DaoTxBuilder extends BaseTxBuilder { freezeGuardTxBuilder.buildDeployZodiacModuleTx(), freezeGuardTxBuilder.buildFreezeVotingSetupTx(), freezeGuardTxBuilder.buildDeployFreezeGuardTx(), - freezeGuardTxBuilder.buildSetGuardTx(this.safeContract), + freezeGuardTxBuilder.buildSetGuardTxSafe(this.safeContractAddress), ]); } @@ -220,7 +220,7 @@ export class DaoTxBuilder extends BaseTxBuilder { const { enableFractalModuleTx, deployFractalModuleTx }: FractalModuleData = fractalModuleData( this.baseContracts.fractalModuleMasterCopyContract, getAddress(this.moduleProxyFactoryAddress), - getAddress(this.safeContract.address), + this.safeContractAddress, this.saltNum, !this.parentAddress ? undefined : getAddress(this.parentAddress), ); @@ -257,8 +257,9 @@ export class DaoTxBuilder extends BaseTxBuilder { private buildExecInternalSafeTx(signatures: string): SafeTransaction { const safeInternalTx = encodeMultiSend(this.internalTxs); - return buildContractCall( - this.safeContract!, + return buildContractCallViem( + GnosisSafeL2Abi, + this.safeContractAddress, 'execTransaction', [ this.baseContracts.multiSendContract.address, // to diff --git a/src/models/FreezeGuardTxBuilder.ts b/src/models/FreezeGuardTxBuilder.ts index 48875e604c..7a70c767a6 100644 --- a/src/models/FreezeGuardTxBuilder.ts +++ b/src/models/FreezeGuardTxBuilder.ts @@ -21,8 +21,8 @@ import { isHex, PublicClient, } from 'viem'; +import GnosisSafeL2Abi from '../assets/abi/GnosisSafeL2'; import ModuleProxyFactoryAbi from '../assets/abi/ModuleProxyFactory'; -import { GnosisSafeL2 } from '../assets/typechain-types/usul/@gnosis.pm/safe-contracts/contracts'; import { buildContractCall, buildContractCallViem } from '../helpers'; import { BaseContracts, @@ -39,7 +39,7 @@ export class FreezeGuardTxBuilder extends BaseTxBuilder { private readonly saltNum; // Safe Data - private readonly safeContract: GnosisSafeL2; + private readonly safeContractAddress: Address; // Freeze Voting Data private freezeVotingType: any; @@ -63,7 +63,7 @@ export class FreezeGuardTxBuilder extends BaseTxBuilder { publicClient: PublicClient, baseContracts: BaseContracts, daoData: SubDAO, - safeContract: GnosisSafeL2, + safeContractAddress: Address, saltNum: bigint, parentAddress: Address, moduleProxyFactoryAddress: Address, @@ -84,7 +84,7 @@ export class FreezeGuardTxBuilder extends BaseTxBuilder { parentTokenAddress, ); - this.safeContract = safeContract; + this.safeContractAddress = safeContractAddress; this.saltNum = saltNum; this.azoriusAddress = azoriusAddress; this.strategyAddress = strategyAddress; @@ -151,10 +151,21 @@ export class FreezeGuardTxBuilder extends BaseTxBuilder { ); } - public buildSetGuardTx(contract: GnosisSafeL2 | Azorius): SafeTransaction { + public buildSetGuardTx(contract: Azorius): SafeTransaction { return buildContractCall(contract, 'setGuard', [this.freezeGuardAddress], 0, false); } + public buildSetGuardTxSafe(safeAddress: Address): SafeTransaction { + return buildContractCallViem( + GnosisSafeL2Abi, + safeAddress, + 'setGuard', + [this.freezeGuardAddress], + 0, + false, + ); + } + public buildDeployFreezeGuardTx() { return buildContractCallViem( ModuleProxyFactoryAbi, @@ -246,7 +257,7 @@ export class FreezeGuardTxBuilder extends BaseTxBuilder { Number(subDaoData.executionPeriod), // Execution Period getAddress(this.parentAddress), // Owner -- Parent DAO getAddress(this.freezeVotingAddress), // Freeze Voting - getAddress(this.safeContract.address), // Safe + this.safeContractAddress, // Safe ]), ], ); diff --git a/src/models/MultisigTxBuilder.ts b/src/models/MultisigTxBuilder.ts index 89cac1fd6c..5139cd463d 100644 --- a/src/models/MultisigTxBuilder.ts +++ b/src/models/MultisigTxBuilder.ts @@ -1,16 +1,21 @@ -import { GnosisSafeL2 } from '../assets/typechain-types/usul/@gnosis.pm/safe-contracts/contracts'; -import { buildContractCall } from '../helpers'; +import { Address } from 'viem'; +import GnosisSafeL2Abi from '../assets/abi/GnosisSafeL2'; +import { buildContractCallViem } from '../helpers'; import { BaseContracts, SafeMultisigDAO, SafeTransaction } from '../types'; export class MultisigTxBuilder { private baseContracts: BaseContracts; private readonly daoData: SafeMultisigDAO; - private readonly safeContract: GnosisSafeL2; + private readonly safeContractAddress: Address; - constructor(baseContracts: BaseContracts, daoData: SafeMultisigDAO, safeContract: GnosisSafeL2) { + constructor( + baseContracts: BaseContracts, + daoData: SafeMultisigDAO, + safeContractAddress: Address, + ) { this.baseContracts = baseContracts; this.daoData = daoData; - this.safeContract = safeContract; + this.safeContractAddress = safeContractAddress; } public signatures = (): string => { @@ -23,8 +28,9 @@ export class MultisigTxBuilder { }; public buildRemoveMultiSendOwnerTx(): SafeTransaction { - return buildContractCall( - this.safeContract!, + return buildContractCallViem( + GnosisSafeL2Abi, + this.safeContractAddress, 'removeOwner', [ this.daoData.trustedAddresses[this.daoData.trustedAddresses.length - 1], diff --git a/src/models/TxBuilderFactory.ts b/src/models/TxBuilderFactory.ts index d03b807133..fc64d9f701 100644 --- a/src/models/TxBuilderFactory.ts +++ b/src/models/TxBuilderFactory.ts @@ -1,9 +1,7 @@ import { ethers } from 'ethers'; -import { PublicClient, getAddress, getContract } from 'viem'; +import { Address, PublicClient, getAddress, getContract } from 'viem'; import GnosisSafeL2Abi from '../assets/abi/GnosisSafeL2'; import GnosisSafeProxyFactoryAbi from '../assets/abi/GnosisSafeProxyFactory'; -import { GnosisSafeL2 } from '../assets/typechain-types/usul/@gnosis.pm/safe-contracts/contracts'; -import { GnosisSafeL2__factory } from '../assets/typechain-types/usul/factories/@gnosis.pm/safe-contracts/contracts'; import { getRandomBytes } from '../helpers'; import { BaseContracts, @@ -28,7 +26,7 @@ export class TxBuilderFactory extends BaseTxBuilder { // Safe Data public predictedSafeAddress: string | undefined; public createSafeTx: SafeTransaction | undefined; - private safeContract: GnosisSafeL2 | undefined; + private safeContractAddress: Address | undefined; public fallbackHandler: string; private votesERC20WrapperMasterCopyAddress: string; @@ -77,9 +75,9 @@ export class TxBuilderFactory extends BaseTxBuilder { this.moduleProxyFactoryAddress = moduleProxyFactoryAddress; } - public setSafeContract(safeAddress: string) { - const safeContract = GnosisSafeL2__factory.connect(safeAddress, this.signerOrProvider); - this.safeContract = safeContract; + public setSafeContract(safeAddress: Address) { + // const safeContract = GnosisSafeL2__factory.connect(safeAddress, this.signerOrProvider); + this.safeContractAddress = safeAddress; } public async setupSafeData(): Promise { @@ -121,7 +119,7 @@ export class TxBuilderFactory extends BaseTxBuilder { this.daoData, this.saltNum, this.createSafeTx!, - this.safeContract!, + this.safeContractAddress!, this, this.keyValuePairsAddress, this.fractalRegistryAddress, @@ -144,7 +142,7 @@ export class TxBuilderFactory extends BaseTxBuilder { this.publicClient, this.baseContracts, this.daoData as SubDAO, - this.safeContract!, + this.safeContractAddress!, this.saltNum, getAddress(this.parentAddress!), getAddress(this.moduleProxyFactoryAddress), @@ -161,7 +159,7 @@ export class TxBuilderFactory extends BaseTxBuilder { return new MultisigTxBuilder( this.baseContracts, this.daoData as SafeMultisigDAO, - this.safeContract!, + getAddress(this.safeContractAddress!), ); } @@ -172,7 +170,7 @@ export class TxBuilderFactory extends BaseTxBuilder { this.baseContracts, this.azoriusContracts!, this.daoData as AzoriusERC20DAO, - this.safeContract!, + this.safeContractAddress!, this.votesERC20WrapperMasterCopyAddress, this.votesERC20MasterCopyAddress, getAddress(this.moduleProxyFactoryAddress), From dc6ccf812012229f59242b0f8e1a427d47ee34bb Mon Sep 17 00:00:00 2001 From: Adam Gall Date: Wed, 8 May 2024 15:54:48 -0400 Subject: [PATCH 4/5] Finish removing GnosisSafeL2 Typechain from project --- src/helpers/crypto.ts | 69 +++++++++++---------- src/hooks/DAO/proposal/useSubmitProposal.ts | 46 ++++++-------- 2 files changed, 56 insertions(+), 59 deletions(-) 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( From 0c36e406cc15e91600db7ca53f15e4c8bc0c3291 Mon Sep 17 00:00:00 2001 From: Adam Gall Date: Wed, 8 May 2024 15:57:48 -0400 Subject: [PATCH 5/5] Remove comment --- src/models/TxBuilderFactory.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/models/TxBuilderFactory.ts b/src/models/TxBuilderFactory.ts index fc64d9f701..2878b5afd9 100644 --- a/src/models/TxBuilderFactory.ts +++ b/src/models/TxBuilderFactory.ts @@ -76,7 +76,6 @@ export class TxBuilderFactory extends BaseTxBuilder { } public setSafeContract(safeAddress: Address) { - // const safeContract = GnosisSafeL2__factory.connect(safeAddress, this.signerOrProvider); this.safeContractAddress = safeAddress; }