diff --git a/package.json b/package.json
index 59382a2985..9608c5c087 100644
--- a/package.json
+++ b/package.json
@@ -57,7 +57,7 @@
"@safe-global/api-kit": "^2.4.6",
"@safe-global/protocol-kit": "^4.1.1",
"@safe-global/safe-apps-sdk": "^9.1.0",
- "@safe-global/safe-deployments": "^1.37.10",
+ "@safe-global/safe-deployments": "1.37.12",
"@safe-global/safe-client-gateway-sdk": "1.58.0-next-25bba61",
"@safe-global/safe-gateway-typescript-sdk": "3.22.3-beta.15",
"@safe-global/safe-modules-deployments": "^2.2.1",
diff --git a/src/components/common/NetworkSelector/NetworkMultiSelector.tsx b/src/components/common/NetworkSelector/NetworkMultiSelector.tsx
index 5a4fbdcc68..3e57812247 100644
--- a/src/components/common/NetworkSelector/NetworkMultiSelector.tsx
+++ b/src/components/common/NetworkSelector/NetworkMultiSelector.tsx
@@ -9,7 +9,7 @@ import { Controller, useFormContext, useWatch } from 'react-hook-form'
import { useRouter } from 'next/router'
import { getNetworkLink } from '.'
import { SetNameStepFields } from '@/components/new-safe/create/steps/SetNameStep'
-import { getSafeSingletonDeployments } from '@safe-global/safe-deployments'
+import { getSafeSingletonDeployments, getSafeToL2SetupDeployments } from '@safe-global/safe-deployments'
import { getLatestSafeVersion } from '@/utils/chains'
import { hasCanonicalDeployment } from '@/services/contracts/deployments'
import { hasMultiChainCreationFeatures } from '@/features/multichain/utils/utils'
@@ -74,22 +74,33 @@ const NetworkMultiSelector = ({
}
// Check if required deployments are available
- const optionHasCanonicalSingletonDeployment = hasCanonicalDeployment(
- getSafeSingletonDeployments({
- network: optionNetwork.chainId,
- version: getLatestSafeVersion(firstSelectedNetwork),
- }),
- optionNetwork.chainId,
- )
- const selectedHasCanonicalSingletonDeployment = hasCanonicalDeployment(
- getSafeSingletonDeployments({
- network: firstSelectedNetwork.chainId,
- version: getLatestSafeVersion(firstSelectedNetwork),
- }),
- firstSelectedNetwork.chainId,
- )
+ const optionHasCanonicalSingletonDeployment =
+ hasCanonicalDeployment(
+ getSafeSingletonDeployments({
+ network: optionNetwork.chainId,
+ version: getLatestSafeVersion(firstSelectedNetwork),
+ }),
+ optionNetwork.chainId,
+ ) &&
+ hasCanonicalDeployment(
+ getSafeToL2SetupDeployments({ network: optionNetwork.chainId, version: '1.4.1' }),
+ optionNetwork.chainId,
+ )
- // Only 1.4.1 safes with canonical deployment addresses can be deployed as part of a multichain group
+ const selectedHasCanonicalSingletonDeployment =
+ hasCanonicalDeployment(
+ getSafeSingletonDeployments({
+ network: firstSelectedNetwork.chainId,
+ version: getLatestSafeVersion(firstSelectedNetwork),
+ }),
+ firstSelectedNetwork.chainId,
+ ) &&
+ hasCanonicalDeployment(
+ getSafeToL2SetupDeployments({ network: firstSelectedNetwork.chainId, version: '1.4.1' }),
+ firstSelectedNetwork.chainId,
+ )
+
+ // Only 1.4.1 safes with canonical deployment addresses and SafeToL2Setup can be deployed as part of a multichain group
if (!selectedHasCanonicalSingletonDeployment) return !optionIsSelectedNetwork
return !optionHasCanonicalSingletonDeployment
},
@@ -128,7 +139,7 @@ const NetworkMultiSelector = ({
))
}
renderOption={(props, chain, { selected }) => (
-
+
diff --git a/src/components/new-safe/create/logic/index.ts b/src/components/new-safe/create/logic/index.ts
index d7d629eb17..af85829355 100644
--- a/src/components/new-safe/create/logic/index.ts
+++ b/src/components/new-safe/create/logic/index.ts
@@ -228,8 +228,9 @@ export const createNewUndeployedSafeWithoutSalt = (
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')
+ // Only do migration if the chain supports multiChain deployments and has a SafeToL2Setup deployment
+ const includeMigration =
+ hasMultiChainCreationFeatures(chain) && semverSatisfies(safeVersion, '>=1.4.1') && Boolean(safeToL2SetupAddress)
const masterCopy = includeMigration ? safeL1Address : chain.l2 ? safeL2Address : safeL1Address
diff --git a/src/components/transactions/TxDetails/TxData/MigrationToL2TxData/index.tsx b/src/components/transactions/TxDetails/TxData/MigrationToL2TxData/index.tsx
index 636769abc7..2d4a106297 100644
--- a/src/components/transactions/TxDetails/TxData/MigrationToL2TxData/index.tsx
+++ b/src/components/transactions/TxDetails/TxData/MigrationToL2TxData/index.tsx
@@ -14,6 +14,7 @@ import ErrorMessage from '@/components/tx/ErrorMessage'
import { useSafeSDK } from '@/hooks/coreSDK/safeCoreSDK'
import { MigrateToL2Information } from '@/components/tx/SignOrExecuteForm/MigrateToL2Information'
import { Box } from '@mui/material'
+import { isMultisigDetailedExecutionInfo } from '@/utils/transaction-guards'
export const MigrationToL2TxData = ({ txDetails }: { txDetails: TransactionDetails }) => {
const readOnlyProvider = useWeb3ReadOnly()
@@ -47,19 +48,24 @@ export const MigrationToL2TxData = ({ txDetails }: { txDetails: TransactionDetai
if (!execTxArgs || execTxArgs.length < 10) {
return undefined
}
- return createTx({
- to: execTxArgs[0],
- value: execTxArgs[1].toString(),
- data: execTxArgs[2],
- operation: Number(execTxArgs[3]),
- safeTxGas: execTxArgs[4].toString(),
- baseGas: execTxArgs[5].toString(),
- gasPrice: execTxArgs[6].toString(),
- gasToken: execTxArgs[7].toString(),
- refundReceiver: execTxArgs[8],
- })
+ return createTx(
+ {
+ to: execTxArgs[0],
+ value: execTxArgs[1].toString(),
+ data: execTxArgs[2],
+ operation: Number(execTxArgs[3]),
+ safeTxGas: execTxArgs[4].toString(),
+ baseGas: execTxArgs[5].toString(),
+ gasPrice: execTxArgs[6].toString(),
+ gasToken: execTxArgs[7].toString(),
+ refundReceiver: execTxArgs[8],
+ },
+ isMultisigDetailedExecutionInfo(txDetails.detailedExecutionInfo)
+ ? txDetails.detailedExecutionInfo.nonce
+ : undefined,
+ )
}
- }, [readOnlyProvider, txDetails.txHash, chain, safe.version, sdk])
+ }, [txDetails.txHash, txDetails.detailedExecutionInfo, chain, sdk, readOnlyProvider, safe.version])
const [decodedRealTx, decodedRealTxError] = useDecodeTx(realSafeTx)
diff --git a/src/features/multichain/hooks/__tests__/useCompatibleNetworks.test.ts b/src/features/multichain/hooks/__tests__/useCompatibleNetworks.test.ts
index 9aa0f7a208..532623a4e6 100644
--- a/src/features/multichain/hooks/__tests__/useCompatibleNetworks.test.ts
+++ b/src/features/multichain/hooks/__tests__/useCompatibleNetworks.test.ts
@@ -31,11 +31,12 @@ describe('useCompatibleNetworks', () => {
beforeAll(() => {
jest.spyOn(useChains, 'default').mockReturnValue({
configs: [
- chainBuilder().with({ chainId: '1' }).build(),
- chainBuilder().with({ chainId: '10' }).build(), // This has the eip155 and then the canonical addresses
- chainBuilder().with({ chainId: '100' }).build(), // This has the canonical and then the eip155 addresses
- chainBuilder().with({ chainId: '324' }).build(), // ZkSync has different addresses for all versions
- chainBuilder().with({ chainId: '480' }).build(), // Worldchain has 1.4.1 but not 1.1.1
+ chainBuilder().with({ chainId: '1', l2: false }).build(),
+ chainBuilder().with({ chainId: '10', l2: true }).build(), // This has the eip155 and then the canonical addresses
+ chainBuilder().with({ chainId: '100', l2: true }).build(), // This has the canonical and then the eip155 addresses
+ chainBuilder().with({ chainId: '324', l2: true }).build(), // ZkSync has different addresses for all versions
+ chainBuilder().with({ chainId: '480', l2: true }).build(), // Worldchain has 1.4.1 but not 1.1.1
+ chainBuilder().with({ chainId: '10200', l2: true }).build(), // Gnosis Chiado has no migration contracts
],
})
})
@@ -68,7 +69,7 @@ describe('useCompatibleNetworks', () => {
expect(result.current.every((config) => config.available)).toEqual(false)
})
- it('should set everything to available except zkSync for 1.4.1 Safes', () => {
+ it('should set everything to available except zkSync and GnosisChain Chiado for 1.4.1 Safes', () => {
const callData = {
owners: [faker.finance.ethereumAddress()],
threshold: 1,
@@ -88,9 +89,9 @@ describe('useCompatibleNetworks', () => {
safeVersion: '1.4.1',
}
const { result } = renderHook(() => useCompatibleNetworks(creationData))
- expect(result.current).toHaveLength(5)
- expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480'])
- expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, true])
+ expect(result.current).toHaveLength(6)
+ expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480', '10200'])
+ expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, true, false])
}
{
@@ -102,9 +103,9 @@ describe('useCompatibleNetworks', () => {
safeVersion: '1.4.1',
}
const { result } = renderHook(() => useCompatibleNetworks(creationData))
- expect(result.current).toHaveLength(5)
- expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480'])
- expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, true])
+ expect(result.current).toHaveLength(6)
+ expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480', '10200'])
+ expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, true, false])
}
})
@@ -120,7 +121,7 @@ describe('useCompatibleNetworks', () => {
paymentReceiver: ECOSYSTEM_ID_ADDRESS,
}
- // 1.3.0, L1 and canonical
+ // 1.3.0, L1 and canonical, not available on Chiado as no migration exists
{
const creationData: ReplayedSafeProps = {
factoryAddress: PROXY_FACTORY_130_DEPLOYMENTS?.canonical?.address!,
@@ -130,9 +131,9 @@ describe('useCompatibleNetworks', () => {
safeVersion: '1.3.0',
}
const { result } = renderHook(() => useCompatibleNetworks(creationData))
- expect(result.current).toHaveLength(5)
- expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480'])
- expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, true])
+ expect(result.current).toHaveLength(6)
+ expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480', '10200'])
+ expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, true, false])
}
// 1.3.0, L2 and canonical
@@ -145,12 +146,12 @@ describe('useCompatibleNetworks', () => {
safeVersion: '1.3.0',
}
const { result } = renderHook(() => useCompatibleNetworks(creationData))
- expect(result.current).toHaveLength(5)
- expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480'])
- expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, true])
+ expect(result.current).toHaveLength(6)
+ expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480', '10200'])
+ expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, true, true])
}
- // 1.3.0, L1 and EIP155 is not available on Worldchain
+ // 1.3.0, L1 and EIP155 is not available on Worldchain and Chiado
{
const creationData: ReplayedSafeProps = {
factoryAddress: PROXY_FACTORY_130_DEPLOYMENTS?.eip155?.address!,
@@ -160,9 +161,9 @@ describe('useCompatibleNetworks', () => {
safeVersion: '1.3.0',
}
const { result } = renderHook(() => useCompatibleNetworks(creationData))
- expect(result.current).toHaveLength(5)
- expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480'])
- expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, false])
+ expect(result.current).toHaveLength(6)
+ expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480', '10200'])
+ expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, false, false])
}
// 1.3.0, L2 and EIP155
@@ -175,9 +176,9 @@ describe('useCompatibleNetworks', () => {
safeVersion: '1.3.0',
}
const { result } = renderHook(() => useCompatibleNetworks(creationData))
- expect(result.current).toHaveLength(5)
- expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480'])
- expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, false])
+ expect(result.current).toHaveLength(6)
+ expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480', '10200'])
+ expect(result.current.map((chain) => chain.available)).toEqual([true, true, true, false, false, false])
}
})
@@ -201,8 +202,8 @@ describe('useCompatibleNetworks', () => {
safeVersion: '1.1.1',
}
const { result } = renderHook(() => useCompatibleNetworks(creationData))
- expect(result.current).toHaveLength(5)
- expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480'])
- expect(result.current.map((chain) => chain.available)).toEqual([false, false, false, false, false])
+ expect(result.current).toHaveLength(6)
+ expect(result.current.map((chain) => chain.chainId)).toEqual(['1', '10', '100', '324', '480', '10200'])
+ expect(result.current.map((chain) => chain.available)).toEqual([false, false, false, false, false, false])
})
})
diff --git a/src/features/multichain/hooks/useCompatibleNetworks.ts b/src/features/multichain/hooks/useCompatibleNetworks.ts
index ded3c949c4..881076dd32 100644
--- a/src/features/multichain/hooks/useCompatibleNetworks.ts
+++ b/src/features/multichain/hooks/useCompatibleNetworks.ts
@@ -1,12 +1,15 @@
import { type ReplayedSafeProps } from '@/features/counterfactual/store/undeployedSafesSlice'
import useChains from '@/hooks/useChains'
-import { hasMatchingDeployment } from '@/services/contracts/deployments'
+import { hasCanonicalDeployment, hasMatchingDeployment } from '@/services/contracts/deployments'
+import { ZERO_ADDRESS } from '@safe-global/protocol-kit/dist/src/utils/constants'
import { type SafeVersion } from '@safe-global/safe-core-sdk-types'
import {
getCompatibilityFallbackHandlerDeployments,
getProxyFactoryDeployments,
getSafeL2SingletonDeployments,
getSafeSingletonDeployments,
+ getSafeToL2MigrationDeployments,
+ getSafeToL2SetupDeployments,
} from '@safe-global/safe-deployments'
import type { ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
@@ -27,21 +30,60 @@ export const useCompatibleNetworks = (
const { masterCopy, factoryAddress, safeAccountConfig } = creation
- const { fallbackHandler } = safeAccountConfig
+ const { fallbackHandler, to } = safeAccountConfig
return configs.map((config) => {
+ const isL1MasterCopy = hasMatchingDeployment(
+ getSafeSingletonDeployments,
+ masterCopy,
+ config.chainId,
+ SUPPORTED_VERSIONS,
+ )
+ const isL2MasterCopy = hasMatchingDeployment(
+ getSafeL2SingletonDeployments,
+ masterCopy,
+ config.chainId,
+ SUPPORTED_VERSIONS,
+ )
+ const masterCopyExists = isL1MasterCopy || isL2MasterCopy
+
+ const proxyFactoryExists = hasMatchingDeployment(
+ getProxyFactoryDeployments,
+ factoryAddress,
+ config.chainId,
+ SUPPORTED_VERSIONS,
+ )
+ const fallbackHandlerExists = hasMatchingDeployment(
+ getCompatibilityFallbackHandlerDeployments,
+ fallbackHandler,
+ config.chainId,
+ SUPPORTED_VERSIONS,
+ )
+
+ // We only need to check that it is nonzero as useSafeCreationData already validates that it is the setupToL2 call otherwise
+ const includesSetupToL2 = to !== ZERO_ADDRESS
+
+ // If the creation includes the setupToL2 call, the contract needs to be deployed on the chain
+ const areSetupToL2ConditionsMet =
+ !includesSetupToL2 ||
+ hasCanonicalDeployment(getSafeToL2SetupDeployments({ network: config.chainId, version: '1.4.1' }), config.chainId)
+
+ // If the masterCopy is L1 on a L2 chain, includes the setupToL2 Call or the Migration contract exists
+ const isMigrationRequired = isL1MasterCopy && !includesSetupToL2 && config.l2
+ const isMigrationPossible = hasCanonicalDeployment(
+ getSafeToL2MigrationDeployments({ network: config.chainId, version: '1.4.1' }),
+ config.chainId,
+ )
+ const areMigrationConditionsMet = !isMigrationRequired || isMigrationPossible
+
return {
...config,
available:
- (hasMatchingDeployment(getSafeSingletonDeployments, masterCopy, config.chainId, SUPPORTED_VERSIONS) ||
- hasMatchingDeployment(getSafeL2SingletonDeployments, masterCopy, config.chainId, SUPPORTED_VERSIONS)) &&
- hasMatchingDeployment(getProxyFactoryDeployments, factoryAddress, config.chainId, SUPPORTED_VERSIONS) &&
- hasMatchingDeployment(
- getCompatibilityFallbackHandlerDeployments,
- fallbackHandler,
- config.chainId,
- SUPPORTED_VERSIONS,
- ),
+ masterCopyExists &&
+ proxyFactoryExists &&
+ fallbackHandlerExists &&
+ areSetupToL2ConditionsMet &&
+ areMigrationConditionsMet,
}
})
}
diff --git a/yarn.lock b/yarn.lock
index 4dcef175cd..81802ca913 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4216,7 +4216,14 @@
dependencies:
abitype "^1.0.2"
-"@safe-global/safe-deployments@^1.37.10", "@safe-global/safe-deployments@^1.37.9":
+"@safe-global/safe-deployments@1.37.12":
+ version "1.37.12"
+ resolved "https://registry.yarnpkg.com/@safe-global/safe-deployments/-/safe-deployments-1.37.12.tgz#c01b0a272991ae0e63a37d506024a809de53c370"
+ integrity sha512-6UM5wS6b0h4Uu2BCK6sWLNC5UYFBd1Xu4YsuZpoSjlo/6UDbbK6lzYVEgtqbsy8p1z2ZO+Z73WgRo3mlh7awig==
+ dependencies:
+ semver "^7.6.2"
+
+"@safe-global/safe-deployments@^1.37.9":
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==
@@ -17238,16 +17245,7 @@ string-length@^4.0.1:
char-regex "^1.0.2"
strip-ansi "^6.0.0"
-"string-width-cjs@npm:string-width@^4.2.0":
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
-string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -17343,14 +17341,7 @@ stringify-object@^3.3.0:
is-obj "^1.0.1"
is-regexp "^1.0.0"
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
-strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -19106,7 +19097,7 @@ workbox-window@7.0.0:
"@types/trusted-types" "^2.0.2"
workbox-core "7.0.0"
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -19124,15 +19115,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
-wrap-ansi@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
- integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"