Skip to content

Commit

Permalink
fix(Multichain): detect migration txs and mark them as trusted
Browse files Browse the repository at this point in the history
  • Loading branch information
schmanu committed Oct 8, 2024
1 parent 2d811ea commit e8f8e3a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import MethodCall from './MethodCall'
import useSafeAddress from '@/hooks/useSafeAddress'
import { sameAddress } from '@/utils/addresses'
import { DelegateCallWarning } from '@/components/transactions/Warning'
import { isMigrateToL2TxData } from '@/utils/transaction-guards'

interface Props {
txData: TransactionDetails['txData']
Expand Down Expand Up @@ -58,9 +59,11 @@ export const DecodedData = ({ txData, toInfo }: Props): ReactElement | null => {
decodedData = <HexEncodedData title="Data (hex-encoded)" hexData={txData.hexData} />
}

const isL2Migration = isMigrateToL2TxData(txData, chainInfo?.chainId)

return (
<Stack spacing={2}>
{isDelegateCall && <DelegateCallWarning showWarning={!txData.trustedDelegateCallTarget} />}
{isDelegateCall && <DelegateCallWarning showWarning={!txData.trustedDelegateCallTarget && !isL2Migration} />}

{method ? (
<MethodCall contractAddress={toAddress} contractName={name} contractLogo={avatar} method={method} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/transactions/TxDetails/TxData/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const TxData = ({
return <SpendingLimits txData={txDetails.txData} txInfo={txInfo} type={method} />
}

if (isMigrateToL2TxData(txDetails.txData)) {
if (isMigrateToL2TxData(txDetails.txData, chainId)) {
return <MigrationToL2TxData txDetails={txDetails} />
}
return <DecodedData txData={txDetails.txData} toInfo={toInfo} />
Expand Down
44 changes: 40 additions & 4 deletions src/utils/transaction-guards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,12 @@ 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 { getSafeToL2MigrationDeployment } from '@safe-global/safe-deployments'
import { getSafeToL2MigrationDeployment, getMultiSendDeployments } from '@safe-global/safe-deployments'
import { Safe_to_l2_migration__factory } from '@/types/contracts'
import { hasMatchingDeployment } from '@/services/contracts/deployments'
import { isMultiSendCalldata } from './transaction-calldata'
import { decodeMultiSendData } from '@safe-global/protocol-kit/dist/src/utils'
import { OperationType } from '@safe-global/safe-core-sdk-types'

export const isTxQueued = (value: TransactionStatus): boolean => {
return [TransactionStatus.AWAITING_CONFIRMATIONS, TransactionStatus.AWAITING_EXECUTION].includes(value)
Expand Down Expand Up @@ -87,18 +91,50 @@ export const isModuleDetailedExecutionInfo = (value?: DetailedExecutionInfo): va
return value?.type === DetailedExecutionInfoType.MODULE
}

export const isMigrateToL2TxData = (value: TransactionData | undefined): boolean => {
const isMigrateToL2CallData = (value: {
to: string
data: string | undefined
operation?: OperationType | undefined
}) => {
const safeToL2MigrationDeployment = getSafeToL2MigrationDeployment()
const safeToL2MigrationAddress = safeToL2MigrationDeployment?.defaultAddress
const safeToL2MigrationInterface = Safe_to_l2_migration__factory.createInterface()

if (sameAddress(value?.to.value, safeToL2MigrationAddress)) {
if (value.operation === OperationType.DelegateCall && sameAddress(value.to, safeToL2MigrationAddress)) {
const migrateToL2Selector = safeToL2MigrationInterface?.getFunction('migrateToL2')?.selector
return migrateToL2Selector && value?.hexData ? value.hexData?.startsWith(migrateToL2Selector) : false
return migrateToL2Selector && value.data ? value.data.startsWith(migrateToL2Selector) : false
}
return false
}

export const isMigrateToL2TxData = (value: TransactionData | undefined, chainId: string | undefined): boolean => {
if (!value) {
return false
}

if (
chainId &&
value?.hexData &&
isMultiSendCalldata(value?.hexData) &&
hasMatchingDeployment(getMultiSendDeployments, value.to.value, chainId, ['1.3.0', '1.4.1'])
) {
// Its a multiSend to the MultiSend contract (not CallOnly)
const decodedMultiSend = decodeMultiSendData(value.hexData)
const firstTx = decodedMultiSend[0]

// We only trust the tx if the first tx is the only delegateCall
const hasMoreDelegateCalls = decodedMultiSend
.slice(1)
.some((value) => value.operation === OperationType.DelegateCall)

if (!hasMoreDelegateCalls && firstTx && isMigrateToL2CallData(firstTx)) {
return true
}
}

return isMigrateToL2CallData({ to: value.to.value, data: value.hexData, operation: value.operation as 0 | 1 })
}

// TransactionInfo type guards
export const isTransferTxInfo = (value: TransactionInfo): value is Transfer => {
return value.type === TransactionInfoType.TRANSFER || isSwapTransferOrderTxInfo(value)
Expand Down

0 comments on commit e8f8e3a

Please sign in to comment.