diff --git a/package.json b/package.json index 8e4adfd2d6..fa0e34252b 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "@safe-global/api-kit": "^2.4.4", "@safe-global/protocol-kit": "^4.1.0", "@safe-global/safe-apps-sdk": "^9.1.0", - "@safe-global/safe-deployments": "^1.37.8", + "@safe-global/safe-deployments": "^1.37.10", "@safe-global/safe-gateway-typescript-sdk": "3.22.3-beta.13", "@safe-global/safe-modules-deployments": "^2.2.1", "@sentry/react": "^7.91.0", diff --git a/src/components/new-safe/create/logic/index.test.ts b/src/components/new-safe/create/logic/index.test.ts index 7bebdf8b22..148bfd2c65 100644 --- a/src/components/new-safe/create/logic/index.test.ts +++ b/src/components/new-safe/create/logic/index.test.ts @@ -9,7 +9,6 @@ import { relaySafeCreation, getRedirect, createNewUndeployedSafeWithoutSalt, - SAFE_TO_L2_SETUP_INTERFACE, } from '@/components/new-safe/create/logic/index' import { relayTransaction } from '@safe-global/safe-gateway-typescript-sdk' import { toBeHex } from 'ethers' @@ -28,13 +27,15 @@ import { type FEATURES as GatewayFeatures } from '@safe-global/safe-gateway-type import { chainBuilder } from '@/tests/builders/chains' import { type ReplayedSafeProps } from '@/store/slices' import { faker } from '@faker-js/faker' -import { ECOSYSTEM_ID_ADDRESS, SAFE_TO_L2_SETUP_ADDRESS } from '@/config/constants' +import { ECOSYSTEM_ID_ADDRESS } from '@/config/constants' import { getFallbackHandlerDeployment, getProxyFactoryDeployment, getSafeL2SingletonDeployment, getSafeSingletonDeployment, + getSafeToL2SetupDeployment, } from '@safe-global/safe-deployments' +import { Safe_to_l2_setup__factory } from '@/types/contracts' const provider = new JsonRpcProvider(undefined, { name: 'ethereum', chainId: 1 }) @@ -44,6 +45,10 @@ const latestSafeVersion = getLatestSafeVersion( .build(), ) +const safeToL2SetupDeployment = getSafeToL2SetupDeployment() +const safeToL2SetupAddress = safeToL2SetupDeployment?.defaultAddress +const safeToL2SetupInterface = Safe_to_l2_setup__factory.createInterface() + describe('create/logic', () => { describe('createNewSafeViaRelayer', () => { const owner1 = toBeHex('0x1', 20) @@ -285,6 +290,10 @@ describe('create/logic', () => { owners: [faker.finance.ethereumAddress()], threshold: 1, } + const safeL2SingletonDeployment = getSafeL2SingletonDeployment({ + version: '1.4.1', + network: '137', + })?.defaultAddress expect( createNewUndeployedSafeWithoutSalt( '1.4.1', @@ -300,10 +309,10 @@ describe('create/logic', () => { safeAccountConfig: { ...safeSetup, fallbackHandler: getFallbackHandlerDeployment({ version: '1.4.1', network: '137' })?.defaultAddress, - to: SAFE_TO_L2_SETUP_ADDRESS, - data: SAFE_TO_L2_SETUP_INTERFACE.encodeFunctionData('setupToL2', [ - getSafeL2SingletonDeployment({ version: '1.4.1', network: '137' })?.defaultAddress, - ]), + to: safeToL2SetupAddress, + data: + safeL2SingletonDeployment && + safeToL2SetupInterface.encodeFunctionData('setupToL2', [safeL2SingletonDeployment]), paymentReceiver: ECOSYSTEM_ID_ADDRESS, }, safeVersion: '1.4.1', diff --git a/src/components/new-safe/create/logic/index.ts b/src/components/new-safe/create/logic/index.ts index 19d8249215..df20ff92ab 100644 --- a/src/components/new-safe/create/logic/index.ts +++ b/src/components/new-safe/create/logic/index.ts @@ -1,5 +1,5 @@ import type { SafeVersion } from '@safe-global/safe-core-sdk-types' -import { Interface, type Eip1193Provider, type Provider } from 'ethers' +import { type Eip1193Provider, type Provider } from 'ethers' import semverSatisfies from 'semver/functions/satisfies' import { getSafeInfo, type SafeInfo, type ChainInfo, relayTransaction } from '@safe-global/safe-gateway-typescript-sdk' @@ -19,12 +19,13 @@ import { getProxyFactoryDeployment, getSafeL2SingletonDeployment, getSafeSingletonDeployment, + getSafeToL2SetupDeployment, } from '@safe-global/safe-deployments' -import { ECOSYSTEM_ID_ADDRESS, SAFE_TO_L2_SETUP_ADDRESS } from '@/config/constants' +import { ECOSYSTEM_ID_ADDRESS } from '@/config/constants' import type { ReplayedSafeProps, UndeployedSafeProps } from '@/store/slices' import { activateReplayedSafe, isPredictedSafeProps } from '@/features/counterfactual/utils' import { getSafeContractDeployment } from '@/services/contracts/deployments' -import { Safe__factory, Safe_proxy_factory__factory } from '@/types/contracts' +import { Safe__factory, Safe_proxy_factory__factory, Safe_to_l2_setup__factory } from '@/types/contracts' import { createWeb3 } from '@/hooks/wallets/web3' import { hasMultiChainCreationFeatures } from '@/components/welcome/MyAccounts/utils/multiChainSafe' @@ -90,8 +91,6 @@ export const computeNewSafeAddress = async ( }) } -export const SAFE_TO_L2_SETUP_INTERFACE = new Interface(['function setupToL2(address l2Singleton)']) - export const encodeSafeSetupCall = (safeAccountConfig: ReplayedSafeProps['safeAccountConfig']) => { return Safe__factory.createInterface().encodeFunctionData('setup', [ safeAccountConfig.owners, @@ -226,6 +225,10 @@ export const createNewUndeployedSafeWithoutSalt = ( throw new Error('No Safe deployment found') } + const safeToL2SetupDeployment = getSafeToL2SetupDeployment({ version: '1.4.1', network: chain.chainId }) + const safeToL2SetupAddress = safeToL2SetupDeployment?.networkAddresses[chain.chainId] + const safeToL2SetupInterface = Safe_to_l2_setup__factory.createInterface() + // Only do migration if the chain supports multiChain deployments. const includeMigration = hasMultiChainCreationFeatures(chain) && semverSatisfies(safeVersion, '>=1.4.1') @@ -238,8 +241,8 @@ export const createNewUndeployedSafeWithoutSalt = ( threshold: safeAccountConfig.threshold, owners: safeAccountConfig.owners, fallbackHandler: fallbackHandlerAddress, - to: includeMigration ? SAFE_TO_L2_SETUP_ADDRESS : ZERO_ADDRESS, - data: includeMigration ? SAFE_TO_L2_SETUP_INTERFACE.encodeFunctionData('setupToL2', [safeL2Address]) : EMPTY_DATA, + to: includeMigration && safeToL2SetupAddress ? safeToL2SetupAddress : ZERO_ADDRESS, + data: includeMigration ? safeToL2SetupInterface.encodeFunctionData('setupToL2', [safeL2Address]) : EMPTY_DATA, paymentReceiver: ECOSYSTEM_ID_ADDRESS, }, safeVersion, diff --git a/src/components/transactions/TxDetails/TxData/DecodedData/SingleTxDecoded/index.tsx b/src/components/transactions/TxDetails/TxData/DecodedData/SingleTxDecoded/index.tsx index f8c0252eb4..dfe3114835 100644 --- a/src/components/transactions/TxDetails/TxData/DecodedData/SingleTxDecoded/index.tsx +++ b/src/components/transactions/TxDetails/TxData/DecodedData/SingleTxDecoded/index.tsx @@ -8,7 +8,8 @@ import accordionCss from '@/styles/accordion.module.css' import CodeIcon from '@mui/icons-material/Code' import DecodedData from '@/components/transactions/TxDetails/TxData/DecodedData' import { sameAddress } from '@/utils/addresses' -import { SAFE_TO_L2_MIGRATION_ADDRESS } from '@/config/constants' +import { getSafeToL2MigrationDeployment } from '@safe-global/safe-deployments' +import { useCurrentChain } from '@/hooks/useChains' type SingleTxDecodedProps = { tx: InternalTransaction @@ -20,12 +21,16 @@ type SingleTxDecodedProps = { } export const SingleTxDecoded = ({ tx, txData, actionTitle, variant, expanded, onChange }: SingleTxDecodedProps) => { + const chain = useCurrentChain() const isNativeTransfer = tx.value !== '0' && (!tx.data || isEmptyHexData(tx.data)) const method = tx.dataDecoded?.method || (isNativeTransfer ? 'native transfer' : 'contract interaction') const addressInfo = txData.addressInfoIndex?.[tx.to] const name = addressInfo?.name + const safeToL2MigrationDeployment = getSafeToL2MigrationDeployment() + const safeToL2MigrationAddress = chain && safeToL2MigrationDeployment?.networkAddresses[chain.chainId] + const singleTxData = { to: { value: tx.to }, value: tx.value, @@ -33,7 +38,7 @@ export const SingleTxDecoded = ({ tx, txData, actionTitle, variant, expanded, on dataDecoded: tx.dataDecoded, hexData: tx.data ?? undefined, addressInfoIndex: txData.addressInfoIndex, - trustedDelegateCallTarget: sameAddress(tx.to, SAFE_TO_L2_MIGRATION_ADDRESS), // We only trusted a nested Migration + trustedDelegateCallTarget: sameAddress(tx.to, safeToL2MigrationAddress), // We only trusted a nested Migration } return ( diff --git a/src/config/constants.ts b/src/config/constants.ts index 24dcc554f5..f1039e0143 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -1,4 +1,3 @@ -import { Interface } from 'ethers' import chains from './chains' export const IS_PRODUCTION = process.env.NEXT_PUBLIC_IS_PRODUCTION === 'true' @@ -110,11 +109,5 @@ export const REDEFINE_ARTICLE = 'https://safe.mirror.xyz/rInLWZwD_sf7enjoFerj6FI export const CHAINALYSIS_OFAC_CONTRACT = '0x40c57923924b5c5c5455c48d93317139addac8fb' -// TODO: Get from safe-deployments once available -export const SAFE_TO_L2_MIGRATION_ADDRESS = '0x7Baec386CAF8e02B0BB4AFc98b4F9381EEeE283C' -export const SAFE_TO_L2_INTERFACE = new Interface(['function migrateToL2(address l2Singleton)']) - export const ECOSYSTEM_ID_ADDRESS = process.env.NEXT_PUBLIC_ECOSYSTEM_ID_ADDRESS || '0x0000000000000000000000000000000000000000' - -export const SAFE_TO_L2_SETUP_ADDRESS = '0x80E0d1577aD3d982BF2F49aAB00BfA161AA763c4' diff --git a/src/features/counterfactual/ActivateAccountFlow.tsx b/src/features/counterfactual/ActivateAccountFlow.tsx index c7f7944fea..0954722c42 100644 --- a/src/features/counterfactual/ActivateAccountFlow.tsx +++ b/src/features/counterfactual/ActivateAccountFlow.tsx @@ -31,8 +31,8 @@ import { sameAddress } from '@/utils/addresses' import { useEstimateSafeCreationGas } from '@/components/new-safe/create/useEstimateSafeCreationGas' import useIsWrongChain from '@/hooks/useIsWrongChain' import NetworkWarning from '@/components/new-safe/create/NetworkWarning' -import { SAFE_TO_L2_SETUP_ADDRESS } from '@/config/constants' import CheckWallet from '@/components/common/CheckWallet' +import { getSafeToL2SetupDeployment } from '@safe-global/safe-deployments' const useActivateAccount = (undeployedSafe: UndeployedSafe | undefined) => { const chain = useCurrentChain() @@ -84,7 +84,7 @@ const ActivateAccountFlow = () => { const safeAccountConfig = undeployedSafe && isPredictedSafeProps(undeployedSafe?.props) ? undeployedSafe?.props.safeAccountConfig : undefined - const isMultichainSafe = sameAddress(safeAccountConfig?.to, SAFE_TO_L2_SETUP_ADDRESS) + const ownerAddresses = undeployedSafeSetup?.owners || [] const [minRelays] = useLeastRemainingRelays(ownerAddresses) @@ -96,6 +96,10 @@ const ActivateAccountFlow = () => { const { owners, threshold, safeVersion } = undeployedSafeSetup + const safeToL2SetupDeployment = getSafeToL2SetupDeployment({ version: '1.4.1', network: chain?.chainId }) + const safeToL2SetupAddress = safeToL2SetupDeployment?.defaultAddress + const isMultichainSafe = sameAddress(safeAccountConfig?.to, safeToL2SetupAddress) + const onSubmit = (txHash?: string) => { trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.activate_without_tx }) trackEvent({ ...TX_EVENTS.EXECUTE, label: TX_TYPES.activate_without_tx }) diff --git a/src/utils/__tests__/transactions.test.ts b/src/utils/__tests__/transactions.test.ts index 4f7fccf782..d9d7c91713 100644 --- a/src/utils/__tests__/transactions.test.ts +++ b/src/utils/__tests__/transactions.test.ts @@ -16,18 +16,22 @@ import { getMultiSendDeployment, getSafeL2SingletonDeployment, getSafeSingletonDeployment, + getSafeToL2MigrationDeployment, } from '@safe-global/safe-deployments' import type Safe from '@safe-global/protocol-kit' import { encodeMultiSendData } from '@safe-global/protocol-kit' -import { Multi_send__factory } from '@/types/contracts' +import { Multi_send__factory, Safe_to_l2_migration__factory } from '@/types/contracts' import { faker } from '@faker-js/faker' import { getAndValidateSafeSDK } from '@/services/tx/tx-sender/sdk' import { decodeMultiSendData } from '@safe-global/protocol-kit/dist/src/utils' import { checksumAddress } from '../addresses' -import { SAFE_TO_L2_MIGRATION_ADDRESS, SAFE_TO_L2_INTERFACE } from '@/config/constants' jest.mock('@/services/tx/tx-sender/sdk') +const safeToL2MigrationDeployment = getSafeToL2MigrationDeployment() +const safeToL2MigrationAddress = safeToL2MigrationDeployment?.defaultAddress +const safeToL2MigrationInterface = Safe_to_l2_migration__factory.createInterface() + describe('transactions', () => { const mockGetAndValidateSdk = getAndValidateSafeSDK as jest.MockedFunction @@ -312,20 +316,21 @@ describe('transactions', () => { }) it('should not modify tx if the tx already migrates', () => { + const safeL2SingletonDeployment = getSafeL2SingletonDeployment()?.defaultAddress + const safeTx = safeTxBuilder() .with({ data: safeTxDataBuilder() .with({ nonce: 0, - to: SAFE_TO_L2_MIGRATION_ADDRESS, - data: SAFE_TO_L2_INTERFACE.encodeFunctionData('migrateToL2', [ - getSafeL2SingletonDeployment()?.defaultAddress, - ]), + to: safeToL2MigrationAddress, + data: + safeL2SingletonDeployment && + safeToL2MigrationInterface.encodeFunctionData('migrateToL2', [safeL2SingletonDeployment]), }) .build(), }) .build() - const safeInfo = extendedSafeInfoBuilder() .with({ implementationVersionState: ImplementationVersionState.UNKNOWN, @@ -335,34 +340,32 @@ describe('transactions', () => { }, }) .build() - expect( prependSafeToL2Migration(safeTx, safeInfo, chainBuilder().with({ l2: true, chainId: '10' }).build()), ).resolves.toEqual(safeTx) - const multiSendSafeTx = safeTxBuilder() .with({ data: safeTxDataBuilder() .with({ nonce: 0, to: getMultiSendDeployment()?.defaultAddress, - data: Multi_send__factory.createInterface().encodeFunctionData('multiSend', [ - encodeMultiSendData([ - { - value: '0', - operation: 1, - to: SAFE_TO_L2_MIGRATION_ADDRESS, - data: SAFE_TO_L2_INTERFACE.encodeFunctionData('migrateToL2', [ - getSafeL2SingletonDeployment()?.defaultAddress, - ]), - }, + data: + safeToL2MigrationAddress && + safeL2SingletonDeployment && + Multi_send__factory.createInterface().encodeFunctionData('multiSend', [ + encodeMultiSendData([ + { + value: '0', + operation: 1, + to: safeToL2MigrationAddress, + data: safeToL2MigrationInterface.encodeFunctionData('migrateToL2', [safeL2SingletonDeployment]), + }, + ]), ]), - ]), }) .build(), }) .build() - expect( prependSafeToL2Migration(multiSendSafeTx, safeInfo, chainBuilder().with({ l2: true, chainId: '10' }).build()), ).resolves.toEqual(multiSendSafeTx) @@ -402,14 +405,16 @@ describe('transactions', () => { expect(modifiedTx?.data.to).toEqual(getMultiSendDeployment()?.defaultAddress) const decodedMultiSend = decodeMultiSendData(modifiedTx!.data.data) expect(decodedMultiSend).toHaveLength(2) + const safeL2SingletonDeployment = getSafeL2SingletonDeployment()?.defaultAddress + expect(decodedMultiSend).toEqual([ { - to: SAFE_TO_L2_MIGRATION_ADDRESS, + to: safeToL2MigrationAddress, value: '0', operation: 1, - data: SAFE_TO_L2_INTERFACE.encodeFunctionData('migrateToL2', [ - getSafeL2SingletonDeployment()?.defaultAddress, - ]), + data: + safeL2SingletonDeployment && + safeToL2MigrationInterface.encodeFunctionData('migrateToL2', [safeL2SingletonDeployment]), }, { to: checksumAddress(safeTx.data.to), diff --git a/src/utils/transaction-guards.ts b/src/utils/transaction-guards.ts index fa219e780e..a26fd9a226 100644 --- a/src/utils/transaction-guards.ts +++ b/src/utils/transaction-guards.ts @@ -58,7 +58,8 @@ import { sameAddress } from '@/utils/addresses' import type { NamedAddress } from '@/components/new-safe/create/types' import type { RecoveryQueueItem } from '@/features/recovery/services/recovery-state' import { ethers } from 'ethers' -import { SAFE_TO_L2_MIGRATION_ADDRESS, SAFE_TO_L2_INTERFACE } from '@/config/constants' +import { getSafeToL2MigrationDeployment } from '@safe-global/safe-deployments' +import { Safe_to_l2_migration__factory } from '@/types/contracts' export const isTxQueued = (value: TransactionStatus): boolean => { return [TransactionStatus.AWAITING_CONFIRMATIONS, TransactionStatus.AWAITING_EXECUTION].includes(value) @@ -88,8 +89,12 @@ export const isModuleDetailedExecutionInfo = (value?: DetailedExecutionInfo): va } export const isMigrateToL2TxData = (value: TransactionData | undefined): boolean => { - if (sameAddress(value?.to.value, SAFE_TO_L2_MIGRATION_ADDRESS)) { - const migrateToL2Selector = SAFE_TO_L2_INTERFACE.getFunction('migrateToL2')?.selector + const safeToL2MigrationDeployment = getSafeToL2MigrationDeployment() + const safeToL2MigrationAddress = safeToL2MigrationDeployment?.defaultAddress + const safeToL2MigrationInterface = Safe_to_l2_migration__factory.createInterface() + + if (sameAddress(value?.to.value, safeToL2MigrationAddress)) { + const migrateToL2Selector = safeToL2MigrationInterface?.getFunction('migrateToL2')?.selector return migrateToL2Selector && value?.hexData ? value.hexData?.startsWith(migrateToL2Selector) : false } return false @@ -100,12 +105,15 @@ export const isMigrateToL2MultiSend = (decodedData: DecodedDataResponse | undefi const innerTxs = decodedData.parameters[0].valueDecoded const firstInnerTx = innerTxs[0] if (firstInnerTx) { + const safeToL2MigrationDeployment = getSafeToL2MigrationDeployment() + const safeToL2MigrationAddress = safeToL2MigrationDeployment?.defaultAddress + return ( firstInnerTx.dataDecoded?.method === 'migrateToL2' && firstInnerTx.dataDecoded.parameters.length === 1 && firstInnerTx.dataDecoded?.parameters?.[0]?.type === 'address' && typeof firstInnerTx.dataDecoded?.parameters[0].value === 'string' && - sameAddress(firstInnerTx.to, SAFE_TO_L2_MIGRATION_ADDRESS) + sameAddress(firstInnerTx.to, safeToL2MigrationAddress) ) } } @@ -149,7 +157,10 @@ export const isOrderTxInfo = (value: TransactionInfo): value is Order => { } export const isMigrateToL2TxInfo = (value: TransactionInfo): value is Custom => { - return isCustomTxInfo(value) && sameAddress(value.to.value, SAFE_TO_L2_MIGRATION_ADDRESS) + const safeToL2MigrationDeployment = getSafeToL2MigrationDeployment() + const safeToL2MigrationAddress = safeToL2MigrationDeployment?.defaultAddress + + return isCustomTxInfo(value) && sameAddress(value.to.value, safeToL2MigrationAddress) } export const isSwapOrderTxInfo = (value: TransactionInfo): value is SwapOrder => { diff --git a/src/utils/transactions.ts b/src/utils/transactions.ts index 9ee2c70604..ee89fd1259 100644 --- a/src/utils/transactions.ts +++ b/src/utils/transactions.ts @@ -29,7 +29,7 @@ import type { SafeTransaction, TransactionOptions } from '@safe-global/safe-core import { FEATURES, hasFeature } from '@/utils/chains' import uniqBy from 'lodash/uniqBy' import { Errors, logError } from '@/services/exceptions' -import { Multi_send__factory } from '@/types/contracts' +import { Multi_send__factory, Safe_to_l2_migration__factory } from '@/types/contracts' import { toBeHex, AbiCoder } from 'ethers' import { type BaseTransaction } from '@safe-global/safe-apps-sdk' import { id } from 'ethers' @@ -40,8 +40,8 @@ import { sameAddress } from './addresses' import { isMultiSendCalldata } from './transaction-calldata' import { decodeMultiSendData } from '@safe-global/protocol-kit/dist/src/utils' import { __unsafe_createMultiSendTx } from '@/services/tx/tx-sender' -import { SAFE_TO_L2_MIGRATION_ADDRESS, SAFE_TO_L2_INTERFACE } from '@/config/constants' import { getOriginPath } from './url' +import { getSafeToL2MigrationDeployment } from '@safe-global/safe-deployments' export const makeTxFromDetails = (txDetails: TransactionDetails): Transaction => { const getMissingSigners = ({ @@ -342,11 +342,19 @@ export const prependSafeToL2Migration = ( const safeL2Deployment = getSafeContractDeployment(chain, safe.version) const safeL2DeploymentAddress = safeL2Deployment?.networkAddresses[chain.chainId] + const safeToL2MigrationDeployment = getSafeToL2MigrationDeployment({ network: chain?.chainId }) if (!safeL2DeploymentAddress) { throw new Error('No L2 MasterCopy found') } + if (!safeToL2MigrationDeployment) { + throw new Error('No safe to L2 migration contract found') + } + + const safeToL2MigrationAddress = safeToL2MigrationDeployment.defaultAddress + const safeToL2MigrationInterface = Safe_to_l2_migration__factory.createInterface() + if (sameAddress(safe.implementation.value, safeL2DeploymentAddress)) { // Safe already has the correct L2 masterCopy // This should in theory never happen if the implementationState is valid @@ -364,7 +372,7 @@ export const prependSafeToL2Migration = ( internalTxs = [{ to: safeTx.data.to, operation: safeTx.data.operation, value: safeTx.data.value, data: txData }] } - if (sameAddress(internalTxs[0]?.to, SAFE_TO_L2_MIGRATION_ADDRESS)) { + if (sameAddress(internalTxs[0]?.to, safeToL2MigrationAddress)) { // We already migrate. Nothing to do. return Promise.resolve(safeTx) } @@ -373,8 +381,8 @@ export const prependSafeToL2Migration = ( const newTxs: MetaTransactionData[] = [ { operation: 1, // DELEGATE CALL REQUIRED - data: SAFE_TO_L2_INTERFACE.encodeFunctionData('migrateToL2', [safeL2DeploymentAddress]), - to: SAFE_TO_L2_MIGRATION_ADDRESS, + data: safeToL2MigrationInterface.encodeFunctionData('migrateToL2', [safeL2DeploymentAddress]), + to: safeToL2MigrationAddress, value: '0', }, ...internalTxs, diff --git a/yarn.lock b/yarn.lock index e8d88c2f15..798791c14d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4279,7 +4279,14 @@ dependencies: abitype "^1.0.2" -"@safe-global/safe-deployments@^1.37.3", "@safe-global/safe-deployments@^1.37.8": +"@safe-global/safe-deployments@^1.37.10": + version "1.37.10" + resolved "https://registry.yarnpkg.com/@safe-global/safe-deployments/-/safe-deployments-1.37.10.tgz#2f61a25bd479332821ba2e91a575237d77406ec3" + integrity sha512-lcxX9CV+xdcLs4dF6Cx18zDww5JyqaX6RdcvU0o/34IgJ4Wjo3J/RNzJAoMhurCAfTGr+0vyJ9V13Qo50AR6JA== + dependencies: + semver "^7.6.2" + +"@safe-global/safe-deployments@^1.37.3": version "1.37.8" resolved "https://registry.yarnpkg.com/@safe-global/safe-deployments/-/safe-deployments-1.37.8.tgz#5d51a57e4c3a9274ce09d8fe7fbe1265a1aaf4c4" integrity sha512-BT34eqSJ1K+4xJgJVY3/Yxg8TRTEvFppkt4wcirIPGCgR4/j06HptHPyDdmmqTuvih8wi8OpFHi0ncP+cGlXWA==