Skip to content

Commit

Permalink
Remove gnosis safe l2 typechain (#1662)
Browse files Browse the repository at this point in the history
* Remove GnosisSafeL2 typechain from TxActions

* Remove GnosisSafeL2 typechain from DaoTxBuilder

* Remove GnosisSafeL2 Typechain from TxBuilderFactory and Builder classes

* Finish removing GnosisSafeL2 Typechain from project

* Remove comment
  • Loading branch information
adamgall authored May 8, 2024
1 parent c8acbc7 commit c15bb0d
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 133 deletions.
35 changes: 22 additions & 13 deletions src/components/Proposals/MultisigProposalDetails/TxActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand All @@ -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' }),
Expand Down
69 changes: 37 additions & 32 deletions src/helpers/crypto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { TypedDataSigner } from '@ethersproject/abstract-signer';
import { Contract, Signer } from 'ethers';
import { Contract } from 'ethers';
import {
hashTypedData,
Hash,
Expand All @@ -14,6 +13,7 @@ import {
isHex,
encodeFunctionData,
Abi,
WalletClient,
} from 'viem';
import { MetaTransaction, SafePostTransaction, SafeTransaction } from '../types/transaction';

Expand Down Expand Up @@ -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 },
Expand Down Expand Up @@ -93,31 +93,42 @@ export const buildSafeTransaction = (template: {
};

export const safeSignTypedData = async (
signer: Signer & TypedDataSigner,
safe: Contract,
walletClient: WalletClient,
contractAddress: Address,
safeTx: SafeTransaction,
chainId?: number,
chainId: number,
): Promise<SafeSignature> => {
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,
};
};

export const buildSafeAPIPost = async (
safeContract: Contract,
signerOrProvider: Signer & TypedDataSigner,
safeAddress: Address,
walletClient: WalletClient,
chainId: number,
template: {
to: Address;
Expand All @@ -132,20 +143,14 @@ export const buildSafeAPIPost = async (
nonce: number;
},
): Promise<SafePostTransaction> => {
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,
Expand All @@ -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,
};
};
Expand Down
46 changes: 19 additions & 27 deletions src/hooks/DAO/proposal/useSubmitProposal.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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 },
Expand Down Expand Up @@ -91,7 +88,7 @@ export default function useSubmitProposal() {
successCallback,
safeAddress,
}: ISubmitProposal) => {
if (!proposalData || !baseContracts) {
if (!proposalData || !baseContracts || !walletClient) {
return;
}
const { multiSendContract } = baseContracts;
Expand Down Expand Up @@ -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();
Expand All @@ -194,13 +185,14 @@ export default function useSubmitProposal() {
}
},
[
signerOrProvider,
safeBaseURL,
chain,
loadDAOProposals,
ipfsClient,
baseContracts,
addressPrefix,
baseContracts,
chain.id,
ipfsClient,
loadDAOProposals,
safeBaseURL,
signerOrProvider,
walletClient,
],
);

Expand All @@ -215,7 +207,7 @@ export default function useSubmitProposal() {
failedToastMessage,
safeAddress,
}: ISubmitAzoriusProposal) => {
if (!proposalData || !provider) {
if (!proposalData) {
return;
}
const toastId = toast(pendingToastMessage, {
Expand Down Expand Up @@ -261,7 +253,7 @@ export default function useSubmitProposal() {
setPendingCreateTx(false);
}
},
[provider, addressPrefix],
[addressPrefix],
);

const submitProposal = useCallback(
Expand Down
Loading

0 comments on commit c15bb0d

Please sign in to comment.