diff --git a/src/components/new-safe/create/logic/index.test.ts b/src/components/new-safe/create/logic/index.test.ts index 1a0ac55e53..dc04191981 100644 --- a/src/components/new-safe/create/logic/index.test.ts +++ b/src/components/new-safe/create/logic/index.test.ts @@ -320,5 +320,35 @@ describe('create/logic', () => { factoryAddress: getProxyFactoryDeployment({ version: '1.4.1', network: '137' })?.defaultAddress, }) }) + + it('should use l2 masterCopy and no migration on zkSync', () => { + const safeSetup = { + owners: [faker.finance.ethereumAddress()], + threshold: 1, + } + expect( + createNewUndeployedSafeWithoutSalt( + '1.3.0', + safeSetup, + chainBuilder() + .with({ chainId: '324' }) + // Multichain and 1.4.1 creation is toggled off + .with({ features: [FEATURES.COUNTERFACTUAL] as any }) + .with({ l2: true }) + .build(), + ), + ).toEqual({ + safeAccountConfig: { + ...safeSetup, + fallbackHandler: getFallbackHandlerDeployment({ version: '1.3.0', network: '324' })?.networkAddresses['324'], + to: ZERO_ADDRESS, + data: EMPTY_DATA, + paymentReceiver: ECOSYSTEM_ID_ADDRESS, + }, + safeVersion: '1.3.0', + masterCopy: getSafeL2SingletonDeployment({ version: '1.3.0', network: '324' })?.networkAddresses['324'], + factoryAddress: getProxyFactoryDeployment({ version: '1.3.0', network: '324' })?.networkAddresses['324'], + }) + }) }) }) diff --git a/src/components/new-safe/create/logic/index.ts b/src/components/new-safe/create/logic/index.ts index f6e4475311..8c6ca327c3 100644 --- a/src/components/new-safe/create/logic/index.ts +++ b/src/components/new-safe/create/logic/index.ts @@ -87,7 +87,6 @@ export const computeNewSafeAddress = async ( saltNonce: props.saltNonce, safeVersion: safeVersion ?? getLatestSafeVersion(chain), }, - isL1SafeSingleton: true, }) } @@ -211,7 +210,7 @@ export const createNewUndeployedSafeWithoutSalt = ( version: safeVersion, network: chain.chainId, }) - const fallbackHandlerAddress = fallbackHandlerDeployment?.defaultAddress + const fallbackHandlerAddress = fallbackHandlerDeployment?.networkAddresses[chain.chainId] const safeL2Deployment = getSafeL2SingletonDeployment({ version: safeVersion, network: chain.chainId }) const safeL2Address = safeL2Deployment?.networkAddresses[chain.chainId] diff --git a/src/components/new-safe/create/logic/utils.ts b/src/components/new-safe/create/logic/utils.ts index fbc5a69bc3..bb471f358b 100644 --- a/src/components/new-safe/create/logic/utils.ts +++ b/src/components/new-safe/create/logic/utils.ts @@ -4,18 +4,20 @@ import { sameAddress } from '@/utils/addresses' import { createWeb3ReadOnly, getRpcServiceUrl } from '@/hooks/wallets/web3' import { type ReplayedSafeProps } from '@/store/slices' import { predictAddressBasedOnReplayData } from '@/components/welcome/MyAccounts/utils/multiChainSafe' +import chains from '@/config/chains' +import { computeNewSafeAddress } from '.' export const getAvailableSaltNonce = async ( customRpcs: { [chainId: string]: string }, replayedSafe: ReplayedSafeProps, - chains: ChainInfo[], + chainInfos: ChainInfo[], // All addresses from the sidebar disregarding the chain. This is an optimization to reduce RPC calls knownSafeAddresses: string[], ): Promise => { let isAvailableOnAllChains = true - const allRPCs = chains.map((chain) => { + const allRPCs = chainInfos.map((chain) => { const rpcUrl = customRpcs?.[chain.chainId] || getRpcServiceUrl(chain.rpcUri) // Turn into Eip1993Provider return { @@ -24,7 +26,7 @@ export const getAvailableSaltNonce = async ( } }) - for (const chain of chains) { + for (const chain of chainInfos) { const rpcUrl = allRPCs.find((rpc) => chain.chainId === rpc.chainId)?.rpcUrl if (!rpcUrl) { throw new Error(`No RPC available for ${chain.chainName}`) @@ -33,7 +35,21 @@ export const getAvailableSaltNonce = async ( if (!web3ReadOnly) { throw new Error('Could not initiate RPC') } - const safeAddress = await predictAddressBasedOnReplayData(replayedSafe, web3ReadOnly) + let safeAddress: string + if (chain.chainId === chains['zksync']) { + // ZK-sync is using a different create2 method which is supported by the SDK + safeAddress = await computeNewSafeAddress( + rpcUrl, + { + safeAccountConfig: replayedSafe.safeAccountConfig, + saltNonce: replayedSafe.saltNonce, + }, + chain, + replayedSafe.safeVersion, + ) + } else { + safeAddress = await predictAddressBasedOnReplayData(replayedSafe, web3ReadOnly) + } const isKnown = knownSafeAddresses.some((knownAddress) => sameAddress(knownAddress, safeAddress)) if (isKnown || (await isSmartContract(safeAddress, web3ReadOnly))) { // We found a chain where the nonce is used up @@ -47,7 +63,7 @@ export const getAvailableSaltNonce = async ( return getAvailableSaltNonce( customRpcs, { ...replayedSafe, saltNonce: (Number(replayedSafe.saltNonce) + 1).toString() }, - chains, + chainInfos, knownSafeAddresses, ) } diff --git a/src/components/new-safe/create/steps/ReviewStep/index.tsx b/src/components/new-safe/create/steps/ReviewStep/index.tsx index 79b4686ed4..f9a195c414 100644 --- a/src/components/new-safe/create/steps/ReviewStep/index.tsx +++ b/src/components/new-safe/create/steps/ReviewStep/index.tsx @@ -6,6 +6,7 @@ import { getTotalFeeFormatted } from '@/hooks/useGasPrice' import type { StepRenderProps } from '@/components/new-safe/CardStepper/useCardStepper' import type { NewSafeFormData } from '@/components/new-safe/create' import { + computeNewSafeAddress, createNewSafe, createNewUndeployedSafeWithoutSalt, relaySafeCreation, @@ -47,9 +48,10 @@ import { selectRpc } from '@/store/settingsSlice' import { AppRoutes } from '@/config/routes' import { type ReplayedSafeProps } from '@/store/slices' import { predictAddressBasedOnReplayData } from '@/components/welcome/MyAccounts/utils/multiChainSafe' -import { createWeb3ReadOnly } from '@/hooks/wallets/web3' +import { createWeb3ReadOnly, getRpcServiceUrl } from '@/hooks/wallets/web3' import { type DeploySafeProps } from '@safe-global/protocol-kit' import { updateAddressBook } from '../../logic/address-book' +import chains from '@/config/chains' export const NetworkFee = ({ totalFee, @@ -227,7 +229,21 @@ const ReviewStep = ({ data, onSubmit, onBack, setStep }: StepRenderProps