Skip to content

Commit

Permalink
Overwrite default fallback handler + add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
katspaugh committed Dec 24, 2024
1 parent ecf6f5b commit d41f64d
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 72 deletions.
61 changes: 0 additions & 61 deletions apps/web/.gitignore

This file was deleted.

2 changes: 1 addition & 1 deletion apps/web/src/services/tx/safeUpdateParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const createUpdateSafeTxs = async (safe: SafeInfo, chain: ChainInfo): Pro

// 1.3.0 Safes are updated using a delegate call to a migration contract
if (semverSatisfies(safe.version, '1.3.0')) {
return [createUpdateMigration(chain, safe.fallbackHandler?.value)]
return [createUpdateMigration(chain, safe.version, safe.fallbackHandler?.value)]
}

// For older Safes, we need to create two transactions
Expand Down
42 changes: 38 additions & 4 deletions apps/web/src/utils/__tests__/safe-migrations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ describe('extractMigrationL2MasterCopyAddress', () => {
} as unknown as ChainInfo

it('should create a migration transaction for L1 chain', () => {
const result = createUpdateMigration(mockChain)
const result = createUpdateMigration(mockChain, '1.3.0')

expect(result).toEqual({
operation: OperationType.DelegateCall,
Expand All @@ -336,8 +336,8 @@ describe('extractMigrationL2MasterCopyAddress', () => {
})

it('should create a migration transaction for L2 chain', () => {
const l2Chain = { ...mockChain, l2: true }
const result = createUpdateMigration(l2Chain)
const l2Chain = { ...mockChain, chainId: '137', l2: true }
const result = createUpdateMigration(l2Chain, '1.3.0+L2')

expect(result).toEqual({
operation: OperationType.DelegateCall,
Expand All @@ -348,7 +348,41 @@ describe('extractMigrationL2MasterCopyAddress', () => {
})

it('should throw an error if deployment is not found', () => {
expect(() => createUpdateMigration(mockChainOld)).toThrow('Migration deployment not found')
expect(() => createUpdateMigration(mockChainOld, '1.1.1')).toThrow('Migration deployment not found')
})

it('should overwrite fallback handler if it is the default one', () => {
const result = createUpdateMigration(mockChain, '1.3.0', '0xf48f2B2d2a534e402487b3ee7C18c33Aec0Fe5e4') // 1.3.0 compatibility fallback handler

expect(result).toEqual({
operation: OperationType.DelegateCall,
data: '0xed007fc6',
to: '0x526643F69b81B008F46d95CD5ced5eC0edFFDaC6',
value: '0',
})
})

it('should overwrite L2 fallback handler if it is the default one', () => {
const l2Chain = { ...mockChain, chainId: '137', l2: true }
const result = createUpdateMigration(l2Chain, '1.3.0+L2', '0xf48f2B2d2a534e402487b3ee7C18c33Aec0Fe5e4') // 1.3.0 compatibility fallback handler

expect(result).toEqual({
operation: OperationType.DelegateCall,
data: '0x68cb3d94',
to: '0x526643F69b81B008F46d95CD5ced5eC0edFFDaC6',
value: '0',
})
})

it('should NOT overwrite a custom fallback handler', () => {
const result = createUpdateMigration(mockChain, '1.3.0', '0x526643F69b81B008F46d95CD5ced5eC0edFFDaC6')

expect(result).toEqual({
operation: OperationType.DelegateCall,
data: '0xf6682ab0',
to: '0x526643F69b81B008F46d95CD5ced5eC0edFFDaC6',
value: '0',
})
})
})
})
29 changes: 23 additions & 6 deletions apps/web/src/utils/safe-migrations.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { Safe_to_l2_migration__factory, Safe_migration__factory } from '@/types/contracts'
import { getCompatibilityFallbackHandlerDeployments } from '@safe-global/safe-deployments'
import { type ExtendedSafeInfo } from '@/store/safeInfoSlice'
import { getSafeContractDeployment } from '@/services/contracts/deployments'
import { getSafeContractDeployment, hasMatchingDeployment } from '@/services/contracts/deployments'
import { sameAddress } from './addresses'
import { getSafeToL2MigrationDeployment, getSafeMigrationDeployment } from '@safe-global/safe-deployments'
import { type MetaTransactionData, OperationType, type SafeTransaction } from '@safe-global/safe-core-sdk-types'
import {
type MetaTransactionData,
OperationType,
type SafeTransaction,
type SafeVersion,
} from '@safe-global/safe-core-sdk-types'
import type { ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
import { isValidMasterCopy } from '@/services/contracts/safeContracts'
import { isMultiSendCalldata } from './transaction-calldata'
Expand Down Expand Up @@ -95,9 +101,11 @@ export const prependSafeToL2Migration = (
return __unsafe_createMultiSendTx(newTxs)
}

export const createUpdateMigration = (chain: ChainInfo, fallbackHandler?: string): MetaTransactionData => {
const interfce = Safe_migration__factory.createInterface()

export const createUpdateMigration = (
chain: ChainInfo,
safeVersion: string,
fallbackHandler?: string,
): MetaTransactionData => {
const deployment = getSafeMigrationDeployment({
version: chain.recommendedMasterCopyVersion || LATEST_SAFE_VERSION,
released: true,
Expand All @@ -108,8 +116,15 @@ export const createUpdateMigration = (chain: ChainInfo, fallbackHandler?: string
throw new Error('Migration deployment not found')
}

// Keep fallback handler if it's not a default one
const keepFallbackHandler =
!!fallbackHandler &&
!hasMatchingDeployment(getCompatibilityFallbackHandlerDeployments, fallbackHandler, chain.chainId, [
safeVersion as SafeVersion,
])

const method = (
fallbackHandler
keepFallbackHandler
? chain.l2
? 'migrateL2Singleton'
: 'migrateSingleton'
Expand All @@ -118,6 +133,8 @@ export const createUpdateMigration = (chain: ChainInfo, fallbackHandler?: string
: 'migrateWithFallbackHandler'
) as 'migrateSingleton' // apease typescript

const interfce = Safe_migration__factory.createInterface()

const tx: MetaTransactionData = {
operation: OperationType.DelegateCall, // delegate call required
data: interfce.encodeFunctionData(method),
Expand Down

0 comments on commit d41f64d

Please sign in to comment.