Skip to content

Commit

Permalink
chore: load zodiac modules in loader (#358)
Browse files Browse the repository at this point in the history
* load zodiac modules through loader

* remove useZodiacModules hook

* remove unused code
  • Loading branch information
frontendphil authored Dec 16, 2024
1 parent 18b75c2 commit c1c6a5f
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 174 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { getChainId } from '@/chains'
import { getReadOnlyProvider } from '@/providers'
import type { HexAddress } from '@/types'
import {
Expand All @@ -9,59 +8,26 @@ import {
import { selectorsFromBytecode } from '@shazow/whatsabi'
import { Contract, id, Interface, ZeroAddress } from 'ethers'
import detectProxyTarget from 'evm-proxy-detection'
import { useEffect, useState } from 'react'
import {
type ChainId,
parsePrefixedAddress,
type PrefixedAddress,
} from 'ser-kit'
import { type ChainId } from 'ser-kit'
import type { SupportedModuleType } from './types'

const SUPPORTED_MODULES = [
KnownContracts.DELAY,
KnownContracts.ROLES_V1,
KnownContracts.ROLES_V2,
]
interface Module {
export interface ZodiacModule {
moduleAddress: string
mastercopyAddress?: string // if empty, it's a custom non-proxied deployment
type: SupportedModuleType
modules?: Module[]
}

export const useZodiacModules = (
safeAddress: PrefixedAddress,
): { loading: boolean; isValidSafe: boolean; modules: Module[] } => {
const [loading, setLoading] = useState(false)
const [error, setError] = useState(false)
const [modules, setModules] = useState<Module[]>([])
const chainId = getChainId(safeAddress)
const address = parsePrefixedAddress(safeAddress)

useEffect(() => {
setLoading(true)
setError(false)
fetchModules(address, chainId)
.then((modules) => setModules(modules))
.catch((e) => {
console.error(`Could not fetch modules of Safe ${address}`, e)
setError(true)
})
.finally(() => setLoading(false))
}, [address, chainId])

if (error) {
return { isValidSafe: false, loading, modules: [] }
}

return { loading, isValidSafe: true, modules }
modules?: ZodiacModule[]
}

async function fetchModules(
export async function fetchZodiacModules(
safeOrModifierAddress: HexAddress,
chainId: ChainId,
previous: Set<string> = new Set(),
): Promise<Module[]> {
): Promise<ZodiacModule[]> {
if (safeOrModifierAddress === ZeroAddress) {
return []
}
Expand Down Expand Up @@ -126,11 +92,11 @@ async function fetchModules(
return undefined
}

let modules: Module[] | null = null
let modules: ZodiacModule[] | null = null
if (MODIFIERS.includes(type)) {
// recursively fetch modules from modifier
try {
modules = await fetchModules(moduleAddress, chainId, previous)
modules = await fetchZodiacModules(moduleAddress, chainId, previous)
} catch (e) {
console.error(
`Could not fetch sub modules of ${type} modifier ${moduleAddress}`,
Expand All @@ -150,7 +116,7 @@ async function fetchModules(
)

const result = await Promise.all(enabledAndSupportedModules)
return result.filter((module) => !!module) as Module[]
return result.filter((module) => !!module) as ZodiacModule[]
}

const functionSelectors = (abi: string[]) => {
Expand Down
2 changes: 1 addition & 1 deletion extension/src/panel/integrations/zodiac/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export { fetchZodiacModules, type ZodiacModule } from './fetchZodiacModules'
export {
MULTISEND,
MULTISEND_CALL_ONLY,
queryRolesV1MultiSend,
queryRolesV2MultiSend,
} from './rolesMultisend'
export type { SupportedModuleType } from './types'
export { useZodiacModules } from './useZodiacModules'
29 changes: 14 additions & 15 deletions extension/src/panel/pages/routes/edit.$routeId/EditRoute.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getRoute, getRoutes } from '@/execution-routes'
import { getReadOnlyProvider, useInjectedWallet } from '@/providers'
import { useInjectedWallet } from '@/providers'
import {
expectRouteToBe,
MockProvider,
Expand All @@ -10,12 +10,12 @@ import {
render,
} from '@/test-utils'
import { ProviderType } from '@/types'
import { queryRolesV2MultiSend, useZodiacModules } from '@/zodiac'
import { fetchZodiacModules, queryRolesV2MultiSend } from '@/zodiac'
import { KnownContracts } from '@gnosis.pm/zodiac'
import { screen, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { getAddress } from 'ethers'
import { formatPrefixedAddress } from 'ser-kit'
import { formatPrefixedAddress, splitPrefixedAddress } from 'ser-kit'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { action, EditRoute, loader } from './EditRoute'

Expand All @@ -25,12 +25,10 @@ vi.mock('@/providers', async (importOriginal) => {
return {
...module,

getReadOnlyProvider: vi.fn(module.getReadOnlyProvider),
useInjectedWallet: vi.fn(module.useInjectedWallet),
}
})

const mockGetReadOnlyProvider = vi.mocked(getReadOnlyProvider)
const mockUseInjectedWallet = vi.mocked(useInjectedWallet)

vi.mock('@/zodiac', async (importOriginal) => {
Expand All @@ -39,18 +37,19 @@ vi.mock('@/zodiac', async (importOriginal) => {
return {
...module,

useZodiacModules: vi.fn(module.useZodiacModules),
fetchZodiacModules: vi.fn(module.fetchZodiacModules),
queryRolesV2MultiSend: vi.fn(module.queryRolesV2MultiSend),
}
})

const mockUseZodiacModules = vi.mocked(useZodiacModules)
const mockFetchZodiacModules = vi.mocked(fetchZodiacModules)
const mockQueryRolesV2MultiSend = vi.mocked(queryRolesV2MultiSend)

describe('Edit Zodiac route', () => {
beforeEach(() => {
mockUseInjectedWallet.mockRestore()
mockUseZodiacModules.mockRestore()

mockFetchZodiacModules.mockResolvedValue([])
})

describe('Label', () => {
Expand Down Expand Up @@ -195,11 +194,9 @@ describe('Edit Zodiac route', () => {

const moduleAddress = randomAddress()

mockUseZodiacModules.mockReturnValue({
isValidSafe: true,
loading: false,
modules: [{ moduleAddress, type: KnownContracts.ROLES_V2 }],
})
mockFetchZodiacModules.mockResolvedValue([
{ moduleAddress, type: KnownContracts.ROLES_V2 },
])

mockQueryRolesV2MultiSend.mockResolvedValue({})

Expand Down Expand Up @@ -385,7 +382,7 @@ describe('Edit Zodiac route', () => {

describe('New route', () => {
it('uses the correct chain to fetch zodiac modules', async () => {
mockRoutes({ id: 'new-route' })
const route = await mockRoute({ id: 'new-route' })

await render('/routes/new-route', [
{
Expand All @@ -406,7 +403,9 @@ describe('Edit Zodiac route', () => {
randomAddress(),
)

expect(mockGetReadOnlyProvider).toHaveBeenCalledWith(42161)
const [, avatarAddress] = splitPrefixedAddress(route.avatar)

expect(mockFetchZodiacModules).toHaveBeenCalledWith(avatarAddress, 42161)
})
})

Expand Down
Loading

0 comments on commit c1c6a5f

Please sign in to comment.