diff --git a/.github/workflows/app-preview.yaml b/.github/workflows/app-preview.yaml
index 9e35c6edf..abdc592d1 100644
--- a/.github/workflows/app-preview.yaml
+++ b/.github/workflows/app-preview.yaml
@@ -1,4 +1,4 @@
-name: Deploy Pilot App
+name: Pilot App
on:
pull_request:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 3a34b3eba..8569fd066 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -45,10 +45,35 @@ jobs:
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --prefer-offline
- run: pnpm test
- - name: 'Report Coverage'
- # Set if: always() to also generate the report if tests are failing
- # Only works if you set `reportOnFailure: true` in your vite config as specified above
- if: always()
- uses: davelosert/vitest-coverage-report-action@v2
+
+ test-utils:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: ./packages/test-utils
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: latest
+ cache: 'pnpm'
+ cache-dependency-path: '**/pnpm-lock.yaml'
+ - run: pnpm install --prefer-offline
+ - run: pnpm test
+
+ pilot-app:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: ./deployables/app
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4
+ - uses: actions/setup-node@v4
with:
- working-directory: packages/ui
+ node-version: latest
+ cache: 'pnpm'
+ cache-dependency-path: '**/pnpm-lock.yaml'
+ - run: pnpm install --prefer-offline
+ - run: pnpm test
diff --git a/deployables/app/app/entry.server.tsx b/deployables/app/app/entry.server.tsx
index 336d56fa1..3a58b1722 100644
--- a/deployables/app/app/entry.server.tsx
+++ b/deployables/app/app/entry.server.tsx
@@ -3,8 +3,6 @@ import { renderToReadableStream } from 'react-dom/server'
import type { AppLoadContext, EntryContext } from 'react-router'
import { ServerRouter } from 'react-router'
-const ABORT_DELAY = 5_000
-
export default async function handleRequest(
request: Request,
responseStatusCode: number,
diff --git a/deployables/app/app/root.tsx b/deployables/app/app/root.tsx
index 6a75d11f5..1791388c9 100644
--- a/deployables/app/app/root.tsx
+++ b/deployables/app/app/root.tsx
@@ -11,14 +11,14 @@ import './app.css'
export function Layout({ children }: { children: React.ReactNode }) {
return (
-
+
-
+
{children}
diff --git a/deployables/app/app/routes.ts b/deployables/app/app/routes.ts
index 5aa26e1e5..d90783a97 100644
--- a/deployables/app/app/routes.ts
+++ b/deployables/app/app/routes.ts
@@ -1,3 +1,6 @@
-import { type RouteConfig, index } from '@react-router/dev/routes'
+import { type RouteConfig, index, route } from '@react-router/dev/routes'
-export default [index('routes/index.tsx')] satisfies RouteConfig
+export default [
+ index('routes/index.tsx'),
+ route('/edit-route', 'routes/edit-route.tsx'),
+] satisfies RouteConfig
diff --git a/deployables/app/app/routes/edit-route.spec.ts b/deployables/app/app/routes/edit-route.spec.ts
new file mode 100644
index 000000000..92af3b20b
--- /dev/null
+++ b/deployables/app/app/routes/edit-route.spec.ts
@@ -0,0 +1,21 @@
+import { render } from '@/test-utils'
+import { screen } from '@testing-library/react'
+import { createMockExecutionRoute } from '@zodiac/test-utils'
+import { describe, expect, it } from 'vitest'
+import EditRoute, { loader } from './edit-route'
+
+describe('Edit route', () => {
+ it('shows the name of a route', async () => {
+ const route = createMockExecutionRoute({ label: 'Test route' })
+
+ await render(
+ '/edit-route',
+ { path: '/edit-route', Component: EditRoute, loader },
+ { searchParams: { route: btoa(JSON.stringify(route)) } },
+ )
+
+ expect(screen.getByRole('textbox', { name: 'Label' })).toHaveValue(
+ 'Test route',
+ )
+ })
+})
diff --git a/deployables/app/app/routes/edit-route.tsx b/deployables/app/app/routes/edit-route.tsx
new file mode 100644
index 000000000..54a6d39a4
--- /dev/null
+++ b/deployables/app/app/routes/edit-route.tsx
@@ -0,0 +1,32 @@
+import { invariantResponse } from '@epic-web/invariant'
+import { executionRouteSchema } from '@zodiac/schema'
+import { TextInput } from '@zodiac/ui'
+import type { Route } from './+types/edit-route'
+
+export const loader = ({ request }: Route.LoaderArgs) => {
+ const url = new URL(request.url)
+
+ const routeData = url.searchParams.get('route')
+
+ invariantResponse(routeData != null, 'Missing "route" parameter')
+
+ const decodedData = Buffer.from(routeData, 'base64')
+
+ try {
+ const rawJson = JSON.parse(decodedData.toString())
+
+ return { route: executionRouteSchema.parse(rawJson) }
+ } catch {
+ throw new Response(null, { status: 400 })
+ }
+}
+
+const EditRoute = ({ loaderData }: Route.ComponentProps) => {
+ return (
+ <>
+
+ >
+ )
+}
+
+export default EditRoute
diff --git a/deployables/app/package.json b/deployables/app/package.json
index cbc58a086..f60d189b8 100644
--- a/deployables/app/package.json
+++ b/deployables/app/package.json
@@ -6,29 +6,41 @@
"build": "react-router build",
"dev": "react-router dev",
"start": "wrangler dev",
- "check-types": "react-router typegen && tsc -b"
+ "check-types": "react-router typegen && tsc -b",
+ "test": "vitest"
},
"dependencies": {
+ "@epic-web/invariant": "^1.0.0",
"@react-router/node": "^7.1.1",
"@react-router/serve": "^7.1.1",
+ "@zodiac/schema": "workspace:*",
+ "@zodiac/ui": "workspace:*",
"isbot": "^5.1.17",
"react": "^19.0.0",
"react-dom": "^19.0.0",
- "react-router": "^7.1.1"
+ "react-router": "^7.1.1",
+ "zod": "^3.23.8"
},
"devDependencies": {
"@cloudflare/workers-types": "4.20241230.0",
"@hiogawa/vite-node-miniflare": "0.1.1",
"@react-router/dev": "^7.1.1",
+ "@testing-library/jest-dom": "^6.4.6",
+ "@testing-library/react": "^16.0.1",
+ "@testing-library/user-event": "14.5.2",
"@types/node": "^22.0.0",
"@types/react": "^19.0.1",
"@types/react-dom": "^19.0.1",
+ "@vitest/coverage-v8": "2.1.8",
+ "@zodiac/test-utils": "workspace:*",
"autoprefixer": "^10.4.20",
+ "eslint": "^9.7.0",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.16",
"typescript": "^5.7.2",
"vite": "^5.4.11",
"vite-tsconfig-paths": "^5.1.4",
+ "vitest": "2.1.8",
"wrangler": "^3.87.0"
}
}
\ No newline at end of file
diff --git a/deployables/app/tailwind.config.ts b/deployables/app/tailwind.config.ts
index 2e66b027a..585a5e9f1 100644
--- a/deployables/app/tailwind.config.ts
+++ b/deployables/app/tailwind.config.ts
@@ -1,7 +1,10 @@
import type { Config } from 'tailwindcss'
export default {
- content: ['./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}'],
+ content: [
+ './app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}',
+ '../../packages/ui/**/*.tsx',
+ ],
theme: {
extend: {
fontFamily: {
diff --git a/deployables/app/test-utils/index.ts b/deployables/app/test-utils/index.ts
new file mode 100644
index 000000000..5a3c950b2
--- /dev/null
+++ b/deployables/app/test-utils/index.ts
@@ -0,0 +1 @@
+export { render } from './render'
diff --git a/deployables/app/test-utils/render.tsx b/deployables/app/test-utils/render.tsx
new file mode 100644
index 000000000..5b96c5e97
--- /dev/null
+++ b/deployables/app/test-utils/render.tsx
@@ -0,0 +1,14 @@
+import {
+ renderFramework,
+ type FrameworkRoute,
+ type RenderOptions,
+ type RouteModule,
+} from '@zodiac/test-utils'
+
+export function render(
+ currentPath: string,
+ route: FrameworkRoute,
+ options: RenderOptions,
+) {
+ return renderFramework(currentPath, route, options)
+}
diff --git a/deployables/app/tsconfig.cloudflare.json b/deployables/app/tsconfig.cloudflare.json
index a80f6076b..15f2baaec 100644
--- a/deployables/app/tsconfig.cloudflare.json
+++ b/deployables/app/tsconfig.cloudflare.json
@@ -2,10 +2,12 @@
"extends": "./tsconfig.json",
"include": [
".react-router/types/**/*",
+ "vitest.setup.ts",
"app/**/*",
"app/**/.server/**/*",
"app/**/.client/**/*",
- "workers/**/*"
+ "workers/**/*",
+ "test-utils/**/*"
],
"compilerOptions": {
"composite": true,
@@ -19,7 +21,8 @@
"baseUrl": ".",
"rootDirs": [".", "./.react-router/types"],
"paths": {
- "~/*": ["./app/*"]
+ "~/*": ["./app/*"],
+ "@/test-utils": ["./test-utils/index.ts"]
},
"esModuleInterop": true,
"resolveJsonModule": true
diff --git a/deployables/app/tsconfig.json b/deployables/app/tsconfig.json
index d7ce9e49b..437daa14f 100644
--- a/deployables/app/tsconfig.json
+++ b/deployables/app/tsconfig.json
@@ -9,6 +9,9 @@
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"strict": true,
- "noEmit": true
+ "noEmit": true,
+ "paths": {
+ "@/test-utils": ["./test-utils/index.ts"]
+ }
}
}
diff --git a/deployables/app/vite.config.ts b/deployables/app/vite.config.ts
index 4980f60ee..6ff8a5347 100644
--- a/deployables/app/vite.config.ts
+++ b/deployables/app/vite.config.ts
@@ -1,5 +1,5 @@
-import { vitePluginViteNodeMiniflare } from '@hiogawa/vite-node-miniflare'
import { reactRouter } from '@react-router/dev/vite'
+import { cloudflareDevProxy } from '@react-router/dev/vite/cloudflare'
import autoprefixer from 'autoprefixer'
import tailwindcss from 'tailwindcss'
import { defineConfig } from 'vite'
@@ -20,7 +20,7 @@ export default defineConfig(({ isSsrBuild }) => ({
},
ssr: {
target: 'webworker',
- noExternal: true,
+ // noExternal: true,
resolve: {
conditions: ['workerd', 'browser'],
},
@@ -36,13 +36,14 @@ export default defineConfig(({ isSsrBuild }) => ({
},
},
plugins: [
- vitePluginViteNodeMiniflare({
- entry: './workers/app.ts',
- miniflareOptions: (options) => {
- options.compatibilityDate = '2024-11-18'
- options.compatibilityFlags = ['nodejs_compat']
- },
- }),
+ cloudflareDevProxy(),
+ // vitePluginViteNodeMiniflare({
+ // entry: './workers/app.ts',
+ // miniflareOptions: (options) => {
+ // options.compatibilityDate = '2024-11-18'
+ // options.compatibilityFlags = ['nodejs_compat']
+ // },
+ // }),
reactRouter(),
tsconfigPaths(),
],
diff --git a/deployables/app/vitest.config.ts b/deployables/app/vitest.config.ts
new file mode 100644
index 000000000..d90392d49
--- /dev/null
+++ b/deployables/app/vitest.config.ts
@@ -0,0 +1,35 @@
+///
+
+import { fileURLToPath } from 'url'
+import { defineConfig } from 'vitest/config'
+import tsConfig from './tsconfig.json'
+
+const alias = Object.entries(tsConfig.compilerOptions.paths).reduce(
+ (result, [key, value]) => ({
+ ...result,
+ [key]: fileURLToPath(new URL(value[0], import.meta.url)),
+ }),
+ {},
+)
+
+const { CI } = process.env
+
+export default defineConfig({
+ test: {
+ alias,
+ environment: 'happy-dom',
+ setupFiles: ['./vitest.setup.ts'],
+ include: ['./app/**/*.{spec,test}.{ts,tsx}'],
+ mockReset: true,
+ clearMocks: true,
+
+ coverage: {
+ skipFull: true,
+ enabled: CI != null,
+ reportOnFailure: CI != null,
+ reporter: CI ? ['json', 'json-summary'] : undefined,
+ include: ['**/app/**/*.{ts,tsx}'],
+ exclude: ['**/src/**/*.spec.{ts,tsx}'],
+ },
+ },
+})
diff --git a/deployables/app/vitest.setup.ts b/deployables/app/vitest.setup.ts
new file mode 100644
index 000000000..a9d0dd31a
--- /dev/null
+++ b/deployables/app/vitest.setup.ts
@@ -0,0 +1 @@
+import '@testing-library/jest-dom/vitest'
diff --git a/deployables/app/workers/app.ts b/deployables/app/workers/app.ts
index 91082f988..afb93e6c4 100644
--- a/deployables/app/workers/app.ts
+++ b/deployables/app/workers/app.ts
@@ -5,9 +5,7 @@ declare global {
}
declare module 'react-router' {
- export interface AppLoadContext {
- VALUE_FROM_CLOUDFLARE: string
- }
+ export interface AppLoadContext {}
}
const requestHandler = createRequestHandler(
@@ -18,8 +16,6 @@ const requestHandler = createRequestHandler(
export default {
fetch(request, env) {
- return requestHandler(request, {
- VALUE_FROM_CLOUDFLARE: 'Hello from Cloudflare',
- })
+ return requestHandler(request)
},
} satisfies ExportedHandler
diff --git a/deployables/app/wrangler.toml b/deployables/app/wrangler.toml
index 693e892ee..e719f4d4c 100644
--- a/deployables/app/wrangler.toml
+++ b/deployables/app/wrangler.toml
@@ -1,6 +1,7 @@
workers_dev = true
name = "pilot-app"
compatibility_date = "2024-11-18"
+compatibility_flags = ["nodejs_compat"]
main = "./build/server/index.js"
assets = { directory = "./build/client/" }
diff --git a/deployables/extension/package.json b/deployables/extension/package.json
index 8e11f0ff3..aade620d5 100644
--- a/deployables/extension/package.json
+++ b/deployables/extension/package.json
@@ -104,6 +104,8 @@
"react-router": "7.1.1",
"react-stick": "^5.0.6",
"zod": "^3.23.8",
- "@zodiac/ui": "workspace:*"
+ "@zodiac/ui": "workspace:*",
+ "@zodiac/schema": "workspace:*",
+ "@zodiac/chains": "workspace:*"
}
}
\ No newline at end of file
diff --git a/deployables/extension/src/chains/const.ts b/deployables/extension/src/chains/const.ts
deleted file mode 100644
index 10b90aeef..000000000
--- a/deployables/extension/src/chains/const.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-/* spell-checker: disable */
-
-import type { HexAddress } from '@/types'
-import type { ChainId, PrefixedAddress } from 'ser-kit'
-
-export const ZERO_ADDRESS: HexAddress =
- '0x0000000000000000000000000000000000000000'
-export const ETH_ZERO_ADDRESS: PrefixedAddress =
- 'eth:0x0000000000000000000000000000000000000000'
-export const EOA_ZERO_ADDRESS: PrefixedAddress =
- 'eoa:0x0000000000000000000000000000000000000000'
-
-export const RPC: Record = {
- 1: 'https://airlock.gnosisguild.org/api/v1/1/rpc',
- 10: 'https://airlock.gnosisguild.org/api/v1/10/rpc',
- 100: 'https://airlock.gnosisguild.org/api/v1/100/rpc',
- 137: 'https://airlock.gnosisguild.org/api/v1/137/rpc',
- 8453: 'https://airlock.gnosisguild.org/api/v1/8453/rpc',
- 42161: 'https://airlock.gnosisguild.org/api/v1/42161/rpc',
- 43114: 'https://airlock.gnosisguild.org/api/v1/43114/rpc',
- 11155111: 'https://airlock.gnosisguild.org/api/v1/11155111/rpc',
-}
-
-export const EXPLORER_URL: Record = {
- 1: 'https://etherscan.io',
- 10: 'https://optimistic.etherscan.io',
- 100: 'https://gnosisscan.io',
- 137: 'https://polygonscan.com',
- 8453: 'https://basescan.org',
- 42161: 'https://arbiscan.io',
- 43114: 'https://snowtrace.io',
- 11155111: 'https://sepolia.etherscan.io',
-}
-
-export const EXPLORER_API_URL: Record = {
- 1: 'https://api.etherscan.io/api',
- 10: 'https://api-optimistic.etherscan.io/api',
- 100: 'https://api.gnosisscan.io/api',
- 137: 'https://api.polygonscan.com/api',
- 8453: 'https://api.basescan.org/api',
- 42161: 'https://api.arbiscan.io/api',
- 43114: 'https://api.snowtrace.io/api',
- 11155111: 'https://api-sepolia.etherscan.io/api',
-}
-
-export const EXPLORER_API_KEY: Record = {
- 1: 'N53BKW6ABNX7CNUK8QIXGRAQS2NME92YAN',
- 10: 'SM2FQ62U49I6H9V9CCEGFS34QGBK4IIJPH',
- 100: 'W575K6DTMSTVB7UFUSNW7GWQ4UWUARTJ7Z',
- 137: 'NM937M1IZXVQ6QVDXS73XMF8JSAB677JWQ',
- 8453: 'KCC7EQHE17IAQZA9TICUS6BQTJGZUDRNIY',
- 42161: 'SJ5BEYBBC3DNSKTH5BAEPFJXUZDAJ133UI',
- 43114: 'notrequired',
- 11155111: 'N53BKW6ABNX7CNUK8QIXGRAQS2NME92YAN',
-}
-
-export const CHAIN_PREFIX: Record = {
- 1: 'eth',
- 10: 'oeth',
- 100: 'gno',
- 137: 'matic',
- 8453: 'base',
- 42161: 'arb1',
- 43114: 'avax',
- 11155111: 'sep',
-}
-
-export const CHAIN_CURRENCY: Record = {
- 1: 'ETH',
- 10: 'ETH',
- 100: 'xDAI',
- 137: 'MATIC',
- 8453: 'ETH',
- 42161: 'ETH',
- 43114: 'AVAX',
- 11155111: 'ETH',
-}
-
-export const CHAIN_NAME: Record = {
- 1: 'Ethereum',
- 10: 'Optimism',
- 100: 'Gnosis',
- 137: 'Polygon',
- 8453: 'Base',
- 42161: 'Arbitrum One',
- 43114: 'Avalanche C-Chain',
- 11155111: 'Sepolia',
-}
diff --git a/deployables/extension/src/inject/bridge/useProviderBridge.spec.tsx b/deployables/extension/src/inject/bridge/useProviderBridge.spec.tsx
index f67adecba..24fab8910 100644
--- a/deployables/extension/src/inject/bridge/useProviderBridge.spec.tsx
+++ b/deployables/extension/src/inject/bridge/useProviderBridge.spec.tsx
@@ -1,4 +1,3 @@
-import { ZERO_ADDRESS } from '@/chains'
import { InjectedProviderMessageTyp } from '@/messages'
import {
chromeMock,
@@ -10,6 +9,7 @@ import {
} from '@/test-utils'
import type { Eip1193Provider } from '@/types'
import { cleanup, waitFor } from '@testing-library/react'
+import { ZERO_ADDRESS } from '@zodiac/chains'
import { toQuantity } from 'ethers'
import type { PropsWithChildren } from 'react'
import type { ChainId } from 'ser-kit'
diff --git a/deployables/extension/src/panel/execution-routes/createRoute.ts b/deployables/extension/src/panel/execution-routes/createRoute.ts
index df7c6c1cb..2e2a41255 100644
--- a/deployables/extension/src/panel/execution-routes/createRoute.ts
+++ b/deployables/extension/src/panel/execution-routes/createRoute.ts
@@ -1,5 +1,5 @@
-import { ETH_ZERO_ADDRESS } from '@/chains'
import { ProviderType } from '@/types'
+import { ETH_ZERO_ADDRESS } from '@zodiac/chains'
import { nanoid } from 'nanoid'
import { saveRoute } from './saveRoute'
diff --git a/deployables/extension/src/panel/execution-routes/useRouteConnect.ts b/deployables/extension/src/panel/execution-routes/useRouteConnect.ts
index 2ae5ba52e..dc756a978 100644
--- a/deployables/extension/src/panel/execution-routes/useRouteConnect.ts
+++ b/deployables/extension/src/panel/execution-routes/useRouteConnect.ts
@@ -1,6 +1,6 @@
-import { getChainId } from '@/chains'
import { isConnected, useInjectedWallet, useWalletConnect } from '@/providers'
import { type ExecutionRoute, ProviderType } from '@/types'
+import { getChainId } from '@zodiac/chains'
import { ZeroAddress } from 'ethers'
import { useCallback } from 'react'
import { parsePrefixedAddress } from 'ser-kit'
diff --git a/deployables/extension/src/panel/execution-routes/useRouteProvider.ts b/deployables/extension/src/panel/execution-routes/useRouteProvider.ts
index f0dad0053..bf5766dc4 100644
--- a/deployables/extension/src/panel/execution-routes/useRouteProvider.ts
+++ b/deployables/extension/src/panel/execution-routes/useRouteProvider.ts
@@ -1,10 +1,10 @@
-import { getChainId } from '@/chains'
import {
getEip1193ReadOnlyProvider,
useInjectedWallet,
useWalletConnect,
} from '@/providers'
import { type ExecutionRoute, ProviderType } from '@/types'
+import { getChainId } from '@zodiac/chains'
export const useRouteProvider = (route: ExecutionRoute) => {
const injectedWallet = useInjectedWallet()
diff --git a/deployables/extension/src/panel/integrations/safe/kits.ts b/deployables/extension/src/panel/integrations/safe/kits.ts
index f5fae9230..8255d3e9e 100644
--- a/deployables/extension/src/panel/integrations/safe/kits.ts
+++ b/deployables/extension/src/panel/integrations/safe/kits.ts
@@ -1,6 +1,6 @@
-import { RPC } from '@/chains'
import SafeApiKit from '@safe-global/api-kit'
import Safe from '@safe-global/protocol-kit'
+import { RPC } from '@zodiac/chains'
import type { ChainId } from 'ser-kit'
export const TX_SERVICE_URL: Record = {
diff --git a/deployables/extension/src/panel/pages/$activeRouteId/ActiveRoute.spec.ts b/deployables/extension/src/panel/pages/$activeRouteId/ActiveRoute.spec.ts
index ceee5ccc2..ff2fa34ca 100644
--- a/deployables/extension/src/panel/pages/$activeRouteId/ActiveRoute.spec.ts
+++ b/deployables/extension/src/panel/pages/$activeRouteId/ActiveRoute.spec.ts
@@ -1,8 +1,8 @@
-import { EOA_ZERO_ADDRESS } from '@/chains'
import { getRoute } from '@/execution-routes'
import { useDisconnectWalletConnectIfNeeded } from '@/providers'
import { mockRoute, randomAddress, render } from '@/test-utils'
import { waitFor } from '@testing-library/react'
+import { EOA_ZERO_ADDRESS } from '@zodiac/chains'
import { describe, expect, it, vi } from 'vitest'
import { action, ActiveRoute, loader } from './ActiveRoute'
diff --git a/deployables/extension/src/panel/pages/$activeRouteId/transactions/ContractAddress/index.tsx b/deployables/extension/src/panel/pages/$activeRouteId/transactions/ContractAddress/index.tsx
index c91d0ae3d..10cea19c1 100644
--- a/deployables/extension/src/panel/pages/$activeRouteId/transactions/ContractAddress/index.tsx
+++ b/deployables/extension/src/panel/pages/$activeRouteId/transactions/ContractAddress/index.tsx
@@ -1,4 +1,4 @@
-import { EXPLORER_URL } from '@/chains'
+import { EXPLORER_URL } from '@zodiac/chains'
import { AddressInput, GhostLinkButton } from '@zodiac/ui'
import { getAddress } from 'ethers'
import { SquareArrowOutUpRight } from 'lucide-react'
diff --git a/deployables/extension/src/panel/pages/$activeRouteId/transactions/Submit.tsx b/deployables/extension/src/panel/pages/$activeRouteId/transactions/Submit.tsx
index ca07fddf1..7ba314447 100644
--- a/deployables/extension/src/panel/pages/$activeRouteId/transactions/Submit.tsx
+++ b/deployables/extension/src/panel/pages/$activeRouteId/transactions/Submit.tsx
@@ -1,4 +1,3 @@
-import { CHAIN_NAME, EXPLORER_URL, getChainId } from '@/chains'
import { useExecutionRoute, useRouteConnect } from '@/execution-routes'
import { usePilotIsReady } from '@/port-handling'
import { getReadOnlyProvider } from '@/providers'
@@ -12,6 +11,7 @@ import {
decodeRolesV2Error,
} from '@/utils'
import { invariant } from '@epic-web/invariant'
+import { CHAIN_NAME, EXPLORER_URL, getChainId } from '@zodiac/chains'
import {
errorToast,
Modal,
diff --git a/deployables/extension/src/panel/pages/$activeRouteId/transactions/Transaction.tsx b/deployables/extension/src/panel/pages/$activeRouteId/transactions/Transaction.tsx
index 5c25f6a70..0f480f59e 100644
--- a/deployables/extension/src/panel/pages/$activeRouteId/transactions/Transaction.tsx
+++ b/deployables/extension/src/panel/pages/$activeRouteId/transactions/Transaction.tsx
@@ -1,7 +1,7 @@
-import { CHAIN_CURRENCY, getChainId } from '@/chains'
import { useExecutionRoute } from '@/execution-routes'
import type { TransactionState } from '@/state'
import type { ExecutionRoute } from '@/types'
+import { CHAIN_CURRENCY, getChainId } from '@zodiac/chains'
import { CopyToClipboard, Divider, TextInput, ToggleButton } from '@zodiac/ui'
import { formatEther, Fragment } from 'ethers'
import { useState } from 'react'
diff --git a/deployables/extension/src/panel/pages/$activeRouteId/transactions/Transactions.tsx b/deployables/extension/src/panel/pages/$activeRouteId/transactions/Transactions.tsx
index 3e018c997..779133908 100644
--- a/deployables/extension/src/panel/pages/$activeRouteId/transactions/Transactions.tsx
+++ b/deployables/extension/src/panel/pages/$activeRouteId/transactions/Transactions.tsx
@@ -1,4 +1,3 @@
-import { getChainId } from '@/chains'
import { useExecutionRoute } from '@/execution-routes'
import { useProviderBridge } from '@/inject-bridge'
import { usePilotIsReady } from '@/port-handling'
@@ -7,6 +6,7 @@ import { useProvider } from '@/providers-ui'
import { useDispatch, useTransactions } from '@/state'
import { useGloballyApplicableTranslation } from '@/transaction-translation'
import { invariant } from '@epic-web/invariant'
+import { getChainId } from '@zodiac/chains'
import { CopyToClipboard, GhostButton, Info, Page } from '@zodiac/ui'
import { RefreshCcw } from 'lucide-react'
import { useEffect, useRef } from 'react'
diff --git a/deployables/extension/src/panel/pages/routes/edit.$routeId/ChainSelect.tsx b/deployables/extension/src/panel/pages/routes/edit.$routeId/ChainSelect.tsx
index 3a2da2f80..9963de2a2 100644
--- a/deployables/extension/src/panel/pages/routes/edit.$routeId/ChainSelect.tsx
+++ b/deployables/extension/src/panel/pages/routes/edit.$routeId/ChainSelect.tsx
@@ -1,5 +1,5 @@
-import { CHAIN_NAME } from '@/chains'
import { invariant } from '@epic-web/invariant'
+import { CHAIN_NAME } from '@zodiac/chains'
import { Select } from '@zodiac/ui'
import type { ChainId } from 'ser-kit'
diff --git a/deployables/extension/src/panel/pages/routes/edit.$routeId/EditRoute.tsx b/deployables/extension/src/panel/pages/routes/edit.$routeId/EditRoute.tsx
index 58a786cf3..8b6fad2ef 100644
--- a/deployables/extension/src/panel/pages/routes/edit.$routeId/EditRoute.tsx
+++ b/deployables/extension/src/panel/pages/routes/edit.$routeId/EditRoute.tsx
@@ -1,4 +1,3 @@
-import { EOA_ZERO_ADDRESS } from '@/chains'
import {
getLastUsedRouteId,
getRoute,
@@ -26,6 +25,7 @@ import {
} from '@/zodiac'
import { invariantResponse } from '@epic-web/invariant'
import { KnownContracts } from '@gnosis.pm/zodiac'
+import { EOA_ZERO_ADDRESS } from '@zodiac/chains'
import {
Breadcrumbs,
Error,
diff --git a/deployables/extension/src/panel/pages/routes/edit.$routeId/useSafeDelegates.ts b/deployables/extension/src/panel/pages/routes/edit.$routeId/useSafeDelegates.ts
index 854a51a97..d35a4ab50 100644
--- a/deployables/extension/src/panel/pages/routes/edit.$routeId/useSafeDelegates.ts
+++ b/deployables/extension/src/panel/pages/routes/edit.$routeId/useSafeDelegates.ts
@@ -1,8 +1,8 @@
-import { getChainId } from '@/chains'
import { useRouteProvider } from '@/execution-routes'
import { initSafeApiKit } from '@/safe'
import type { ExecutionRoute } from '@/types'
import { validateAddress } from '@/utils'
+import { getChainId } from '@zodiac/chains'
import { useEffect, useState } from 'react'
import type { ChainId } from 'ser-kit'
diff --git a/deployables/extension/src/panel/pages/routes/edit.$routeId/useSafesWithOwner.ts b/deployables/extension/src/panel/pages/routes/edit.$routeId/useSafesWithOwner.ts
index 0527f8db3..4edd42a04 100644
--- a/deployables/extension/src/panel/pages/routes/edit.$routeId/useSafesWithOwner.ts
+++ b/deployables/extension/src/panel/pages/routes/edit.$routeId/useSafesWithOwner.ts
@@ -1,7 +1,7 @@
-import { getChainId } from '@/chains'
import { initSafeApiKit } from '@/safe'
import type { ExecutionRoute } from '@/types'
import { validateAddress } from '@/utils'
+import { getChainId } from '@zodiac/chains'
import { useEffect, useState } from 'react'
import type { ChainId } from 'ser-kit'
diff --git a/deployables/extension/src/panel/pages/routes/edit.$routeId/wallet/ConnectWallet.tsx b/deployables/extension/src/panel/pages/routes/edit.$routeId/wallet/ConnectWallet.tsx
index 7f9f7e759..5329a3ce8 100644
--- a/deployables/extension/src/panel/pages/routes/edit.$routeId/wallet/ConnectWallet.tsx
+++ b/deployables/extension/src/panel/pages/routes/edit.$routeId/wallet/ConnectWallet.tsx
@@ -1,10 +1,10 @@
-import { getChainId } from '@/chains'
import {
type InjectedWalletContextT,
type WalletConnectResult,
isConnected as isConnectedBase,
} from '@/providers'
import { type ExecutionRoute, ProviderType } from '@/types'
+import { getChainId } from '@zodiac/chains'
import { ZeroAddress } from 'ethers'
import { type ChainId, parsePrefixedAddress } from 'ser-kit'
import { InjectedWallet, InjectedWalletConnect } from './injectedWallet'
diff --git a/deployables/extension/src/panel/pages/routes/edit.$routeId/wallet/SwitchChain.tsx b/deployables/extension/src/panel/pages/routes/edit.$routeId/wallet/SwitchChain.tsx
index f1fcc0604..50d3ad18c 100644
--- a/deployables/extension/src/panel/pages/routes/edit.$routeId/wallet/SwitchChain.tsx
+++ b/deployables/extension/src/panel/pages/routes/edit.$routeId/wallet/SwitchChain.tsx
@@ -1,4 +1,4 @@
-import { CHAIN_NAME } from '@/chains'
+import { CHAIN_NAME } from '@zodiac/chains'
import { SecondaryButton, Warning } from '@zodiac/ui'
import type { PropsWithChildren } from 'react'
import type { ChainId } from 'ser-kit'
diff --git a/deployables/extension/src/panel/pages/routes/list/ListRoutes.spec.ts b/deployables/extension/src/panel/pages/routes/list/ListRoutes.spec.ts
index 20c5f0e55..5a2713f0d 100644
--- a/deployables/extension/src/panel/pages/routes/list/ListRoutes.spec.ts
+++ b/deployables/extension/src/panel/pages/routes/list/ListRoutes.spec.ts
@@ -1,4 +1,3 @@
-import { ETH_ZERO_ADDRESS, ZERO_ADDRESS } from '@/chains'
import { getRoutes, saveLastUsedRouteId } from '@/execution-routes'
import {
connectMockWallet,
@@ -10,6 +9,7 @@ import {
} from '@/test-utils'
import { screen, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
+import { ETH_ZERO_ADDRESS, ZERO_ADDRESS } from '@zodiac/chains'
import { expectRouteToBe } from '@zodiac/test-utils'
import { describe, expect, it } from 'vitest'
import { action, ListRoutes, loader } from './ListRoutes'
diff --git a/deployables/extension/src/panel/providers-ui/ProvideProvider.tsx b/deployables/extension/src/panel/providers-ui/ProvideProvider.tsx
index decd4dbce..8f0fd42bb 100644
--- a/deployables/extension/src/panel/providers-ui/ProvideProvider.tsx
+++ b/deployables/extension/src/panel/providers-ui/ProvideProvider.tsx
@@ -1,8 +1,8 @@
-import { getChainId } from '@/chains'
import { useExecutionRoute } from '@/execution-routes'
import { ForkProvider } from '@/providers'
import type { Eip1193Provider } from '@/types'
import { invariant } from '@epic-web/invariant'
+import { getChainId } from '@zodiac/chains'
import { AbiCoder, BrowserProvider, id, TransactionReceipt } from 'ethers'
import {
createContext,
diff --git a/deployables/extension/src/panel/providers/fork-provider/readOnlyProvider.ts b/deployables/extension/src/panel/providers/fork-provider/readOnlyProvider.ts
index 70212424c..b42c1f9cd 100644
--- a/deployables/extension/src/panel/providers/fork-provider/readOnlyProvider.ts
+++ b/deployables/extension/src/panel/providers/fork-provider/readOnlyProvider.ts
@@ -1,5 +1,5 @@
-import { RPC } from '@/chains'
import type { JsonRpcRequest } from '@/types'
+import { RPC } from '@zodiac/chains'
import { JsonRpcProvider, toQuantity } from 'ethers'
import EventEmitter from 'events'
import type { ChainId } from 'ser-kit'
diff --git a/deployables/extension/src/panel/providers/injected-provider/useConnectProvider.tsx b/deployables/extension/src/panel/providers/injected-provider/useConnectProvider.tsx
index 4947c0852..43aa7d505 100644
--- a/deployables/extension/src/panel/providers/injected-provider/useConnectProvider.tsx
+++ b/deployables/extension/src/panel/providers/injected-provider/useConnectProvider.tsx
@@ -1,6 +1,6 @@
-import { CHAIN_CURRENCY, CHAIN_NAME, EXPLORER_URL, RPC } from '@/chains'
import type { Eip1193Provider } from '@/types'
import { invariant } from '@epic-web/invariant'
+import { CHAIN_CURRENCY, CHAIN_NAME, EXPLORER_URL, RPC } from '@zodiac/chains'
import { infoToast } from '@zodiac/ui'
import { useEffect, useState } from 'react'
import type { ChainId } from 'ser-kit'
diff --git a/deployables/extension/src/panel/providers/wallet-connect/useDisconnectWalletConnectIfNeeded.spec.ts b/deployables/extension/src/panel/providers/wallet-connect/useDisconnectWalletConnectIfNeeded.spec.ts
index 29ed7c53d..a121fefb7 100644
--- a/deployables/extension/src/panel/providers/wallet-connect/useDisconnectWalletConnectIfNeeded.spec.ts
+++ b/deployables/extension/src/panel/providers/wallet-connect/useDisconnectWalletConnectIfNeeded.spec.ts
@@ -1,6 +1,6 @@
-import { ETH_ZERO_ADDRESS } from '@/chains'
import { createMockRoute, renderHook } from '@/test-utils'
import { ProviderType } from '@/types'
+import { ETH_ZERO_ADDRESS } from '@zodiac/chains'
import { sleepTillIdle } from '@zodiac/test-utils'
import { describe, expect, it, vi } from 'vitest'
import { useDisconnectWalletConnectIfNeeded } from './useDisconnectWalletConnectIfNeeded'
diff --git a/deployables/extension/src/panel/providers/wallet-connect/useWalletConnectProvider.ts b/deployables/extension/src/panel/providers/wallet-connect/useWalletConnectProvider.ts
index 05d1b7812..dc2842376 100644
--- a/deployables/extension/src/panel/providers/wallet-connect/useWalletConnectProvider.ts
+++ b/deployables/extension/src/panel/providers/wallet-connect/useWalletConnectProvider.ts
@@ -1,5 +1,5 @@
-import { RPC } from '@/chains'
import { invariant } from '@epic-web/invariant'
+import { RPC } from '@zodiac/chains'
import { useEffect, useState } from 'react'
import {
WALLETCONNECT_PROJECT_ID,
diff --git a/deployables/extension/src/panel/transactionTranslations/useApplicableTranslation.ts b/deployables/extension/src/panel/transactionTranslations/useApplicableTranslation.ts
index 2fafc74ef..884c2ccac 100644
--- a/deployables/extension/src/panel/transactionTranslations/useApplicableTranslation.ts
+++ b/deployables/extension/src/panel/transactionTranslations/useApplicableTranslation.ts
@@ -1,9 +1,9 @@
-import { getChainId } from '@/chains'
import { useExecutionRoute } from '@/execution-routes'
import { ForkProvider } from '@/providers'
import { useProvider } from '@/providers-ui'
import { type TransactionState, useDispatch, useTransactions } from '@/state'
import { invariant } from '@epic-web/invariant'
+import { getChainId } from '@zodiac/chains'
import { useCallback, useEffect, useState } from 'react'
import {
type ChainId,
diff --git a/deployables/extension/src/panel/transactionTranslations/useGloballyApplicableTranslation.ts b/deployables/extension/src/panel/transactionTranslations/useGloballyApplicableTranslation.ts
index 644f4290d..65bbea8fe 100644
--- a/deployables/extension/src/panel/transactionTranslations/useGloballyApplicableTranslation.ts
+++ b/deployables/extension/src/panel/transactionTranslations/useGloballyApplicableTranslation.ts
@@ -1,8 +1,8 @@
-import { getChainId } from '@/chains'
import { useExecutionRoute } from '@/execution-routes'
import { ForkProvider } from '@/providers'
import { useProvider } from '@/providers-ui'
import { type TransactionState, useDispatch, useTransactions } from '@/state'
+import { getChainId } from '@zodiac/chains'
import { useCallback, useEffect } from 'react'
import {
type ChainId,
diff --git a/deployables/extension/src/types.ts b/deployables/extension/src/types.ts
index abc2448a8..922f4881b 100644
--- a/deployables/extension/src/types.ts
+++ b/deployables/extension/src/types.ts
@@ -1,10 +1,13 @@
-import type { ChainId, Route as CompleteRoute, PrefixedAddress } from 'ser-kit'
+import type {
+ ExecutionRoute as BaseExecutionRoute,
+ HexAddress,
+ ProviderType,
+} from '@zodiac/schema'
+import type { ChainId } from 'ser-kit'
import type { SupportedModuleType } from './panel/integrations/zodiac/types'
-export enum ProviderType {
- WalletConnect,
- InjectedWallet,
-}
+export { ProviderType } from '@zodiac/schema'
+export type { HexAddress } from '@zodiac/schema'
export interface LegacyConnection {
id: string
@@ -27,16 +30,7 @@ export interface LegacyConnection {
lastUsed?: number
}
-interface PartialExecutionRoute {
- id: string
- initiator: PrefixedAddress | undefined
- avatar: PrefixedAddress
- waypoints: CompleteRoute['waypoints'] | undefined
-}
-
-export type ExecutionRoute = PartialExecutionRoute & {
- providerType: ProviderType
- label: string
+export type ExecutionRoute = BaseExecutionRoute & {
lastUsed?: number
}
@@ -66,5 +60,3 @@ export interface TransactionData {
data?: HexAddress
from?: HexAddress
}
-
-export type HexAddress = `0x${string}`
diff --git a/deployables/extension/test-utils/creators/createTransaction.ts b/deployables/extension/test-utils/creators/createTransaction.ts
index 773f4ee3b..f12a3ae60 100644
--- a/deployables/extension/test-utils/creators/createTransaction.ts
+++ b/deployables/extension/test-utils/creators/createTransaction.ts
@@ -1,5 +1,5 @@
-import { ZERO_ADDRESS } from '@/chains'
import { ExecutionStatus, type TransactionState } from '@/state'
+import { ZERO_ADDRESS } from '@zodiac/chains'
import { nanoid } from 'nanoid'
export const createTransaction = (
diff --git a/deployables/extension/test-utils/creators/index.ts b/deployables/extension/test-utils/creators/index.ts
index b149ffe96..27cd03387 100644
--- a/deployables/extension/test-utils/creators/index.ts
+++ b/deployables/extension/test-utils/creators/index.ts
@@ -1,9 +1,12 @@
+export {
+ createMockExecutionRoute as createMockRoute,
+ createRoleWaypoint,
+ createStartingWaypoint,
+ randomAddress,
+ randomPrefixedAddress,
+} from '@zodiac/test-utils'
export { createMockPort } from './createMockPort'
-export { createMockRoute } from './createMockRoute'
export { createMockTab } from './createMockTab'
export type { MockTab } from './createMockTab'
export { createMockWebRequest } from './createMockWebRequest'
-export { createRoleWaypoint } from './createRoleWaypoint'
-export { createStartingWaypoint } from './createStartingWaypoint'
export { createTransaction } from './createTransaction'
-export { randomAddress, randomPrefixedAddress } from './randomHex'
diff --git a/deployables/extension/tsconfig.json b/deployables/extension/tsconfig.json
index c359f2c8b..d1ccd22e9 100644
--- a/deployables/extension/tsconfig.json
+++ b/deployables/extension/tsconfig.json
@@ -22,7 +22,6 @@
"@/utils": ["./src/utils/index.ts"],
"@/types": ["./src/types.ts"],
"@/const": ["./src/const.ts"],
- "@/chains": ["./src/chains/index.ts"],
"@/execution-routes": ["./src/panel/execution-routes/index.ts"],
"@/state": ["./src/panel/state/index.tsx"],
"@/providers": ["./src/panel/providers/index.ts"],
diff --git a/packages/chains/package.json b/packages/chains/package.json
new file mode 100644
index 000000000..6705e915e
--- /dev/null
+++ b/packages/chains/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@zodiac/chains",
+ "private": true,
+ "type": "module",
+ "license": "UNLICENSED",
+ "sideEffects": false,
+ "packageManager": "pnpm@9.15.3",
+ "exports": {
+ ".": {
+ "types": "./src/index.ts",
+ "import": "./src/index.ts"
+ }
+ },
+ "dependencies": {
+ "@epic-web/invariant": "^1.0.0",
+ "@zodiac/schema": "workspace:*"
+ },
+ "peerDependencies": {
+ "ser-kit": "1.0.7"
+ },
+ "devDependencies": {
+ "ser-kit": "1.0.7"
+ }
+}
\ No newline at end of file
diff --git a/packages/chains/src/const.ts b/packages/chains/src/const.ts
new file mode 100644
index 000000000..6e0c5d463
--- /dev/null
+++ b/packages/chains/src/const.ts
@@ -0,0 +1,98 @@
+/* spell-checker: disable */
+import type { HexAddress } from '@zodiac/schema'
+import type { ChainId, PrefixedAddress } from 'ser-kit'
+
+export const ZERO_ADDRESS: HexAddress =
+ '0x0000000000000000000000000000000000000000'
+export const ETH_ZERO_ADDRESS: PrefixedAddress =
+ 'eth:0x0000000000000000000000000000000000000000'
+export const EOA_ZERO_ADDRESS: PrefixedAddress =
+ 'eoa:0x0000000000000000000000000000000000000000'
+
+enum Chain {
+ ETH = 1,
+ OETH = 10,
+ GNO = 100,
+ SEP = 11155111,
+ MATIC = 137,
+ ARB1 = 42161,
+ AVAX = 43114,
+ BASE = 8453,
+}
+
+export const RPC: Record = {
+ [Chain.ETH]: 'https://airlock.gnosisguild.org/api/v1/1/rpc',
+ [Chain.OETH]: 'https://airlock.gnosisguild.org/api/v1/10/rpc',
+ [Chain.GNO]: 'https://airlock.gnosisguild.org/api/v1/100/rpc',
+ [Chain.MATIC]: 'https://airlock.gnosisguild.org/api/v1/137/rpc',
+ [Chain.BASE]: 'https://airlock.gnosisguild.org/api/v1/8453/rpc',
+ [Chain.ARB1]: 'https://airlock.gnosisguild.org/api/v1/42161/rpc',
+ [Chain.AVAX]: 'https://airlock.gnosisguild.org/api/v1/43114/rpc',
+ [Chain.SEP]: 'https://airlock.gnosisguild.org/api/v1/11155111/rpc',
+}
+
+export const EXPLORER_URL: Record = {
+ [Chain.ETH]: 'https://etherscan.io',
+ [Chain.OETH]: 'https://optimistic.etherscan.io',
+ [Chain.GNO]: 'https://gnosisscan.io',
+ [Chain.MATIC]: 'https://polygonscan.com',
+ [Chain.BASE]: 'https://basescan.org',
+ [Chain.ARB1]: 'https://arbiscan.io',
+ [Chain.AVAX]: 'https://snowtrace.io',
+ [Chain.SEP]: 'https://sepolia.etherscan.io',
+}
+
+export const EXPLORER_API_URL: Record = {
+ [Chain.ETH]: 'https://api.etherscan.io/api',
+ [Chain.OETH]: 'https://api-optimistic.etherscan.io/api',
+ [Chain.GNO]: 'https://api.gnosisscan.io/api',
+ [Chain.MATIC]: 'https://api.polygonscan.com/api',
+ [Chain.BASE]: 'https://api.basescan.org/api',
+ [Chain.ARB1]: 'https://api.arbiscan.io/api',
+ [Chain.AVAX]: 'https://api.snowtrace.io/api',
+ [Chain.SEP]: 'https://api-sepolia.etherscan.io/api',
+}
+
+export const EXPLORER_API_KEY: Record = {
+ [Chain.ETH]: 'N53BKW6ABNX7CNUK8QIXGRAQS2NME92YAN',
+ [Chain.OETH]: 'SM2FQ62U49I6H9V9CCEGFS34QGBK4IIJPH',
+ [Chain.GNO]: 'W575K6DTMSTVB7UFUSNW7GWQ4UWUARTJ7Z',
+ [Chain.MATIC]: 'NM937M1IZXVQ6QVDXS73XMF8JSAB677JWQ',
+ [Chain.BASE]: 'KCC7EQHE17IAQZA9TICUS6BQTJGZUDRNIY',
+ [Chain.ARB1]: 'SJ5BEYBBC3DNSKTH5BAEPFJXUZDAJ133UI',
+ [Chain.AVAX]: 'notrequired',
+ [Chain.SEP]: 'N53BKW6ABNX7CNUK8QIXGRAQS2NME92YAN',
+}
+
+export const CHAIN_PREFIX: Record = {
+ [Chain.ETH]: 'eth',
+ [Chain.OETH]: 'oeth',
+ [Chain.GNO]: 'gno',
+ [Chain.MATIC]: 'matic',
+ [Chain.BASE]: 'base',
+ [Chain.ARB1]: 'arb1',
+ [Chain.AVAX]: 'avax',
+ [Chain.SEP]: 'sep',
+}
+
+export const CHAIN_CURRENCY: Record = {
+ [Chain.ETH]: 'ETH',
+ [Chain.OETH]: 'ETH',
+ [Chain.GNO]: 'xDAI',
+ [Chain.MATIC]: 'MATIC',
+ [Chain.BASE]: 'ETH',
+ [Chain.ARB1]: 'ETH',
+ [Chain.AVAX]: 'AVAX',
+ [Chain.SEP]: 'ETH',
+}
+
+export const CHAIN_NAME: Record = {
+ [Chain.ETH]: 'Ethereum',
+ [Chain.OETH]: 'Optimism',
+ [Chain.GNO]: 'Gnosis',
+ [Chain.MATIC]: 'Polygon',
+ [Chain.BASE]: 'Base',
+ [Chain.ARB1]: 'Arbitrum One',
+ [Chain.AVAX]: 'Avalanche C-Chain',
+ [Chain.SEP]: 'Sepolia',
+}
diff --git a/deployables/extension/src/chains/getChainId.ts b/packages/chains/src/getChainId.ts
similarity index 100%
rename from deployables/extension/src/chains/getChainId.ts
rename to packages/chains/src/getChainId.ts
diff --git a/deployables/extension/src/chains/index.ts b/packages/chains/src/index.ts
similarity index 100%
rename from deployables/extension/src/chains/index.ts
rename to packages/chains/src/index.ts
diff --git a/packages/chains/tsconfig.json b/packages/chains/tsconfig.json
new file mode 100644
index 000000000..438144816
--- /dev/null
+++ b/packages/chains/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "target": "ES2023",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "verbatimModuleSyntax": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "downlevelIteration": true
+ },
+ "include": ["./src/**/*"]
+}
diff --git a/packages/schema/package.json b/packages/schema/package.json
new file mode 100644
index 000000000..8c84149af
--- /dev/null
+++ b/packages/schema/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "@zodiac/schema",
+ "private": true,
+ "type": "module",
+ "license": "UNLICENSED",
+ "sideEffects": false,
+ "packageManager": "pnpm@9.15.3",
+ "exports": {
+ ".": {
+ "types": "./src/index.ts",
+ "import": "./src/index.ts"
+ }
+ },
+ "dependencies": {
+ "ser-kit": "1.0.7",
+ "zod": "^3.23.8"
+ }
+}
\ No newline at end of file
diff --git a/packages/schema/src/index.ts b/packages/schema/src/index.ts
new file mode 100644
index 000000000..208dfaf60
--- /dev/null
+++ b/packages/schema/src/index.ts
@@ -0,0 +1,2 @@
+export { ProviderType, executionRouteSchema } from './routeSchema'
+export type { ExecutionRoute, HexAddress } from './routeSchema'
diff --git a/packages/schema/src/routeSchema.ts b/packages/schema/src/routeSchema.ts
new file mode 100644
index 000000000..24b077e0c
--- /dev/null
+++ b/packages/schema/src/routeSchema.ts
@@ -0,0 +1,128 @@
+import { chains, type PrefixedAddress } from 'ser-kit'
+import { z } from 'zod'
+
+const chainIdSchema = z.union([
+ z.literal(chains[0].chainId),
+ z.literal(chains[1].chainId),
+ z.literal(chains[2].chainId),
+ z.literal(chains[3].chainId),
+ z.literal(chains[4].chainId),
+ z.literal(chains[5].chainId),
+ z.literal(chains[6].chainId),
+ z.literal(chains[7].chainId),
+])
+
+export type HexAddress = `0x${string}`
+
+const isHexAddress = (value: string): value is HexAddress =>
+ value.startsWith('0x') && value.length > 2
+
+const addressSchema = z.custom(
+ (value) => typeof value === 'string' && isHexAddress(value),
+)
+
+const prefixedAddressSchema = z.custom((value) => {
+ if (typeof value !== 'string') {
+ return false
+ }
+
+ const [prefix, address] = value.split(':')
+
+ if (!isHexAddress(address)) {
+ return false
+ }
+
+ return chains.some(({ shortName }) => prefix === shortName)
+})
+
+const safeSchema = z.object({
+ type: z.literal('SAFE'),
+ address: addressSchema,
+ prefixedAddress: prefixedAddressSchema,
+ chain: chainIdSchema,
+ threshold: z.number(),
+})
+
+const rolesSchema = z.object({
+ type: z.literal('ROLES'),
+ address: addressSchema,
+ prefixedAddress: prefixedAddressSchema,
+ chain: chainIdSchema,
+ multisend: addressSchema.array(),
+ version: z.union([z.literal(1), z.literal(2)]),
+})
+
+const delaySchema = z.object({
+ type: z.literal('DELAY'),
+ address: addressSchema,
+ prefixedAddress: prefixedAddressSchema,
+ chain: chainIdSchema,
+})
+
+const ownConnectionSchema = z.object({
+ type: z.literal('OWNS'),
+ from: prefixedAddressSchema,
+})
+
+const isEnabledConnectionSchema = z.object({
+ type: z.literal('IS_ENABLED'),
+ from: prefixedAddressSchema,
+})
+
+const isMemberConnectionSchema = z.object({
+ type: z.literal('IS_MEMBER'),
+ roles: z.string().array(),
+ defaultRole: z.string().optional(),
+ from: prefixedAddressSchema,
+})
+
+const contractSchema = z.discriminatedUnion('type', [
+ safeSchema,
+ rolesSchema,
+ delaySchema,
+])
+
+const waypointSchema = z.object({
+ account: contractSchema,
+ connection: z.discriminatedUnion('type', [
+ ownConnectionSchema,
+ isEnabledConnectionSchema,
+ isMemberConnectionSchema,
+ ]),
+})
+
+const eoaSchema = z.object({
+ type: z.literal('EOA'),
+ address: addressSchema,
+ prefixedAddress: prefixedAddressSchema,
+})
+
+const startingPointSchema = z.object({
+ account: z.discriminatedUnion('type', [
+ eoaSchema,
+ safeSchema,
+ rolesSchema,
+ delaySchema,
+ ]),
+})
+
+export enum ProviderType {
+ WalletConnect,
+ InjectedWallet,
+}
+
+const walletConnectType = z.literal(ProviderType.WalletConnect)
+const injectedProviderType = z.literal(ProviderType.InjectedWallet)
+
+const providerTypeSchema = z.union([walletConnectType, injectedProviderType])
+
+export const executionRouteSchema = z.object({
+ id: z.string(),
+ label: z.string(),
+ providerType: providerTypeSchema,
+ avatar: prefixedAddressSchema,
+ initiator: prefixedAddressSchema.optional(),
+ waypoints: z.tuple([startingPointSchema]).rest(waypointSchema).optional(),
+})
+
+export type ExecutionRoute = z.infer
diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json
index ae514e52c..39564938c 100644
--- a/packages/test-utils/package.json
+++ b/packages/test-utils/package.json
@@ -5,6 +5,7 @@
"license": "UNLICENSED",
"sideEffects": false,
"packageManager": "pnpm@9.15.3",
+ "scripts": {"test": "vitest"},
"exports": {
".": {
"types": "./src/index.ts",
@@ -14,14 +15,19 @@
"dependencies": {
"@epic-web/invariant": "^1.0.0",
"@testing-library/react": "^16.0.1",
+ "@zodiac/schema": "workspace:*",
+ "@zodiac/chains": "workspace:*",
"vitest": "2.1.8"
},
"peerDependencies": {
"react": "19.0.0",
- "react-router": "7.1.1"
+ "react-router": "7.1.1",
+ "ser-kit": "1.0.7"
},
"devDependencies": {
+ "@types/node": "^22.10.5",
"@types/react": "^19.0.3",
- "@types/react-dom": "^19.0.2"
+ "@types/react-dom": "^19.0.2",
+ "ser-kit": "1.0.7"
}
}
\ No newline at end of file
diff --git a/packages/test-utils/src/InspectRoute.tsx b/packages/test-utils/src/InspectRoute.tsx
new file mode 100644
index 000000000..88ee2e2e9
--- /dev/null
+++ b/packages/test-utils/src/InspectRoute.tsx
@@ -0,0 +1,12 @@
+import { useLocation } from 'react-router'
+
+export const InspectRoute = () => {
+ const location = useLocation()
+
+ return (
+
+ )
+}
diff --git a/deployables/extension/test-utils/creators/createMockRoute.ts b/packages/test-utils/src/creators/createMockExecutionRoute.ts
similarity index 75%
rename from deployables/extension/test-utils/creators/createMockRoute.ts
rename to packages/test-utils/src/creators/createMockExecutionRoute.ts
index d4c0a5407..98e4675a4 100644
--- a/deployables/extension/test-utils/creators/createMockRoute.ts
+++ b/packages/test-utils/src/creators/createMockExecutionRoute.ts
@@ -1,10 +1,10 @@
-import { ETH_ZERO_ADDRESS, ZERO_ADDRESS } from '@/chains'
-import { type ExecutionRoute, ProviderType } from '@/types'
+import { ETH_ZERO_ADDRESS, ZERO_ADDRESS } from '@zodiac/chains'
+import { ProviderType, type ExecutionRoute } from '@zodiac/schema'
import { randomUUID } from 'crypto'
import { AccountType, formatPrefixedAddress } from 'ser-kit'
import { randomHex } from './randomHex'
-export const createMockRoute = (
+export const createMockExecutionRoute = (
route: Partial = {},
): ExecutionRoute => ({
id: randomUUID(),
diff --git a/deployables/extension/test-utils/creators/createRoleWaypoint.ts b/packages/test-utils/src/creators/createRoleWaypoint.ts
similarity index 93%
rename from deployables/extension/test-utils/creators/createRoleWaypoint.ts
rename to packages/test-utils/src/creators/createRoleWaypoint.ts
index bd288802b..45c2f1aa7 100644
--- a/deployables/extension/test-utils/creators/createRoleWaypoint.ts
+++ b/packages/test-utils/src/creators/createRoleWaypoint.ts
@@ -1,4 +1,4 @@
-import type { HexAddress } from '@/types'
+import type { HexAddress } from '@zodiac/schema'
import {
AccountType,
ConnectionType,
diff --git a/deployables/extension/test-utils/creators/createStartingWaypoint.ts b/packages/test-utils/src/creators/createStartingWaypoint.ts
similarity index 100%
rename from deployables/extension/test-utils/creators/createStartingWaypoint.ts
rename to packages/test-utils/src/creators/createStartingWaypoint.ts
diff --git a/packages/test-utils/src/creators/index.ts b/packages/test-utils/src/creators/index.ts
new file mode 100644
index 000000000..4003fcad3
--- /dev/null
+++ b/packages/test-utils/src/creators/index.ts
@@ -0,0 +1,4 @@
+export { createMockExecutionRoute } from './createMockExecutionRoute'
+export { createRoleWaypoint } from './createRoleWaypoint'
+export { createStartingWaypoint } from './createStartingWaypoint'
+export { randomAddress, randomHex, randomPrefixedAddress } from './randomHex'
diff --git a/deployables/extension/test-utils/creators/randomHex.ts b/packages/test-utils/src/creators/randomHex.ts
similarity index 92%
rename from deployables/extension/test-utils/creators/randomHex.ts
rename to packages/test-utils/src/creators/randomHex.ts
index 7f1adaf96..8467b97c8 100644
--- a/deployables/extension/test-utils/creators/randomHex.ts
+++ b/packages/test-utils/src/creators/randomHex.ts
@@ -1,4 +1,4 @@
-import type { HexAddress } from '@/types'
+import type { HexAddress } from '@zodiac/schema'
import { formatPrefixedAddress, type ChainId } from 'ser-kit'
export const randomHex = (size: number): HexAddress => {
diff --git a/packages/test-utils/src/getCurrentPath.spec.ts b/packages/test-utils/src/getCurrentPath.spec.ts
new file mode 100644
index 000000000..1076979d7
--- /dev/null
+++ b/packages/test-utils/src/getCurrentPath.spec.ts
@@ -0,0 +1,8 @@
+import { describe, expect, it } from 'vitest'
+import { getCurrentPath } from './getCurrentPath'
+
+describe('getCurrentPath', () => {
+ it('is possible to append string values', () => {
+ expect(getCurrentPath('/path', { key: 'value' })).toEqual('/path?key=value')
+ })
+})
diff --git a/packages/test-utils/src/getCurrentPath.ts b/packages/test-utils/src/getCurrentPath.ts
new file mode 100644
index 000000000..6c0b759ae
--- /dev/null
+++ b/packages/test-utils/src/getCurrentPath.ts
@@ -0,0 +1,17 @@
+export type SearchParams = Record
+
+export const getCurrentPath = (path: string, searchParams: SearchParams) => {
+ const url = new URL(path, 'http://localhost')
+
+ Object.entries(searchParams).forEach(([key, value]) => {
+ if (value == null) {
+ url.searchParams.delete(key)
+ } else if (typeof value === 'number') {
+ url.searchParams.set(key, value.toString())
+ } else {
+ url.searchParams.set(key, value)
+ }
+ })
+
+ return `${url.pathname}${url.search}`
+}
diff --git a/packages/test-utils/src/index.ts b/packages/test-utils/src/index.ts
index 3ef191fb2..d8d93ad45 100644
--- a/packages/test-utils/src/index.ts
+++ b/packages/test-utils/src/index.ts
@@ -1,5 +1,8 @@
+export * from './creators'
export { expectRouteToBe, render } from './render'
export type { RenderOptions, Route } from './render'
+export { renderFramework } from './renderFramework'
+export type { FrameworkRoute, RouteModule } from './renderFramework'
export { renderHook } from './renderHook'
export type { RenderHookOptions } from './renderHook'
export { sleepTillIdle } from './sleepTillIdle'
diff --git a/packages/test-utils/src/render.tsx b/packages/test-utils/src/render.tsx
index 117d0d299..bc177a79a 100644
--- a/packages/test-utils/src/render.tsx
+++ b/packages/test-utils/src/render.tsx
@@ -4,10 +4,10 @@ import type { ComponentType } from 'react'
import {
createMemoryRouter,
RouterProvider,
- useLocation,
type ActionFunction,
type LoaderFunction,
} from 'react-router'
+import { InspectRoute } from './InspectRoute'
import { TestElement, waitForTestElement } from './TestElement'
import { sleepTillIdle } from './sleepTillIdle'
@@ -25,13 +25,31 @@ export type RenderOptions = Parameters[1] & {
* `expectRouteToBe` helper from the render result.
*/
inspectRoutes?: string[]
+ /**
+ * Search params that should be added to the current route.
+ * You can also include them in the route but this way is usually
+ * more readable.
+ */
+ searchParams?: Record
}
export const render = async (
currentPath: string,
routes: Route[],
- { inspectRoutes = [], ...options }: RenderOptions = {},
+ { inspectRoutes = [], searchParams = {}, ...options }: RenderOptions = {},
) => {
+ const url = new URL(currentPath, 'http://localhost')
+
+ Object.entries(searchParams).forEach(([key, value]) => {
+ if (value == null) {
+ url.searchParams.delete(key)
+ } else if (typeof value === 'number') {
+ url.searchParams.set(key, value.toString())
+ } else {
+ url.searchParams.set(key, value)
+ }
+ })
+
const router = createMemoryRouter(
[
{
@@ -61,17 +79,6 @@ export const render = async (
return result
}
-const InspectRoute = () => {
- const location = useLocation()
-
- return (
-
- )
-}
-
export const expectRouteToBe = (expectedPathName: string) =>
waitFor(() => {
const testElement = screen.getByTestId('test-route-element-id')
diff --git a/packages/test-utils/src/renderFramework.tsx b/packages/test-utils/src/renderFramework.tsx
new file mode 100644
index 000000000..07e3c0097
--- /dev/null
+++ b/packages/test-utils/src/renderFramework.tsx
@@ -0,0 +1,107 @@
+import { render, type RenderResult } from '@testing-library/react'
+import type { ComponentType } from 'react'
+import { createRoutesStub, useLoaderData, useParams } from 'react-router'
+import type {
+ CreateActionData,
+ CreateComponentProps,
+ CreateLoaderData,
+ CreateServerLoaderArgs,
+} from 'react-router/route-module'
+import { getCurrentPath } from './getCurrentPath'
+import { InspectRoute } from './InspectRoute'
+import type { RenderOptions } from './render'
+import { sleepTillIdle } from './sleepTillIdle'
+import { TestElement, waitForTestElement } from './TestElement'
+
+type Func = (...args: any[]) => unknown
+
+export type RouteModule = {
+ meta?: Func
+ links?: Func
+ headers?: Func
+ loader?: Func
+ clientLoader?: Func
+ action?: Func
+ clientAction?: Func
+ HydrateFallback?: unknown
+ default?: unknown
+ ErrorBoundary?: unknown
+ [key: string]: unknown
+}
+
+type Info = {
+ parents: [
+ {
+ parents: []
+ id: 'root'
+ file: 'root.tsx'
+ path: ''
+ params: {} & { [key: string]: string | undefined }
+ module: Module
+ loaderData: CreateLoaderData<{}>
+ actionData: CreateActionData<{}>
+ },
+ ]
+ id: any
+ file: any
+ path: any
+ params: {} & { [key: string]: string | undefined }
+ module: Module
+ loaderData: CreateLoaderData
+ actionData: CreateActionData
+}
+
+export type FrameworkRoute<
+ Module extends RouteModule,
+ Loader extends Func | undefined = Module['loader'],
+> = {
+ path: string
+ Component: ComponentType>>
+ loader?: Loader extends Func
+ ? (args: CreateServerLoaderArgs>) => ReturnType
+ : never
+}
+
+export async function renderFramework(
+ currentPath: string,
+ route: FrameworkRoute,
+ { inspectRoutes = [], searchParams = {}, ...options }: RenderOptions,
+): Promise {
+ const Stub = createRoutesStub([
+ {
+ path: '/',
+ Component: TestElement,
+ children: [
+ {
+ path: route.path,
+ // @ts-expect-error
+ loader: route.loader,
+ Component() {
+ const loaderData = useLoaderData()
+ const params = useParams()
+
+ return (
+
+ )
+ },
+ },
+
+ ...inspectRoutes.map((path) => ({ path, Component: InspectRoute })),
+ ],
+ },
+ ])
+
+ const result = render(
+ ,
+ options,
+ )
+
+ await waitForTestElement()
+ await sleepTillIdle()
+
+ return result
+}
diff --git a/packages/test-utils/tsconfig.json b/packages/test-utils/tsconfig.json
index 7e86d78c2..438144816 100644
--- a/packages/test-utils/tsconfig.json
+++ b/packages/test-utils/tsconfig.json
@@ -10,7 +10,7 @@
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "ESNext",
- "moduleResolution": "Node",
+ "moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c05fbf65e..b0c16488f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -34,12 +34,21 @@ importers:
deployables/app:
dependencies:
+ '@epic-web/invariant':
+ specifier: ^1.0.0
+ version: 1.0.0
'@react-router/node':
specifier: ^7.1.1
version: 7.1.1(react-router@7.1.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(typescript@5.7.3)
'@react-router/serve':
specifier: ^7.1.1
version: 7.1.1(react-router@7.1.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(typescript@5.7.3)
+ '@zodiac/schema':
+ specifier: workspace:*
+ version: link:../../packages/schema
+ '@zodiac/ui':
+ specifier: workspace:*
+ version: link:../../packages/ui
isbot:
specifier: ^5.1.17
version: 5.1.21
@@ -52,6 +61,9 @@ importers:
react-router:
specifier: ^7.1.1
version: 7.1.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ zod:
+ specifier: ^3.23.8
+ version: 3.24.1
devDependencies:
'@cloudflare/workers-types':
specifier: 4.20241230.0
@@ -62,6 +74,15 @@ importers:
'@react-router/dev':
specifier: ^7.1.1
version: 7.1.1(@react-router/serve@7.1.1(react-router@7.1.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(typescript@5.7.3))(@types/node@22.10.5)(babel-plugin-macros@3.1.0)(jiti@2.4.1)(less@4.2.1)(lightningcss@1.28.2)(react-router@7.1.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(sass@1.82.0)(stylus@0.62.0)(typescript@5.7.3)(vite@5.4.11(@types/node@22.10.5)(less@4.2.1)(lightningcss@1.28.2)(sass@1.82.0)(stylus@0.62.0))(wrangler@3.100.0(@cloudflare/workers-types@4.20241230.0)(bufferutil@4.0.8)(utf-8-validate@5.0.10))(yaml@2.6.1)
+ '@testing-library/jest-dom':
+ specifier: ^6.4.6
+ version: 6.6.3
+ '@testing-library/react':
+ specifier: ^16.0.1
+ version: 16.1.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.2(@types/react@19.0.4))(@types/react@19.0.4)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@testing-library/user-event':
+ specifier: 14.5.2
+ version: 14.5.2(@testing-library/dom@10.4.0)
'@types/node':
specifier: ^22.0.0
version: 22.10.5
@@ -71,9 +92,18 @@ importers:
'@types/react-dom':
specifier: ^19.0.1
version: 19.0.2(@types/react@19.0.4)
+ '@vitest/coverage-v8':
+ specifier: 2.1.8
+ version: 2.1.8(vitest@2.1.8(@types/node@22.10.5)(happy-dom@16.5.3)(less@4.2.1)(lightningcss@1.28.2)(sass@1.82.0)(stylus@0.62.0))
+ '@zodiac/test-utils':
+ specifier: workspace:*
+ version: link:../../packages/test-utils
autoprefixer:
specifier: ^10.4.20
version: 10.4.20(postcss@8.4.49)
+ eslint:
+ specifier: ^9.7.0
+ version: 9.17.0(jiti@2.4.1)
postcss:
specifier: ^8.4.49
version: 8.4.49
@@ -89,6 +119,9 @@ importers:
vite-tsconfig-paths:
specifier: ^5.1.4
version: 5.1.4(typescript@5.7.3)(vite@5.4.11(@types/node@22.10.5)(less@4.2.1)(lightningcss@1.28.2)(sass@1.82.0)(stylus@0.62.0))
+ vitest:
+ specifier: 2.1.8
+ version: 2.1.8(@types/node@22.10.5)(happy-dom@16.5.3)(less@4.2.1)(lightningcss@1.28.2)(sass@1.82.0)(stylus@0.62.0)
wrangler:
specifier: ^3.87.0
version: 3.100.0(@cloudflare/workers-types@4.20241230.0)(bufferutil@4.0.8)(utf-8-validate@5.0.10)
@@ -177,6 +210,12 @@ importers:
'@headlessui/react':
specifier: ^2.2.0
version: 2.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@zodiac/chains':
+ specifier: workspace:*
+ version: link:../../packages/chains
+ '@zodiac/schema':
+ specifier: workspace:*
+ version: link:../../packages/schema
'@zodiac/ui':
specifier: workspace:*
version: link:../../packages/ui
@@ -480,6 +519,28 @@ importers:
specifier: 3.100.0
version: 3.100.0(@cloudflare/workers-types@4.20241230.0)(bufferutil@4.0.8)(utf-8-validate@5.0.10)
+ packages/chains:
+ dependencies:
+ '@epic-web/invariant':
+ specifier: ^1.0.0
+ version: 1.0.0
+ '@zodiac/schema':
+ specifier: workspace:*
+ version: link:../schema
+ devDependencies:
+ ser-kit:
+ specifier: 1.0.7
+ version: 1.0.7(bufferutil@4.0.8)(typescript@5.7.3)(utf-8-validate@5.0.10)(zod@3.24.1)
+
+ packages/schema:
+ dependencies:
+ ser-kit:
+ specifier: 1.0.7
+ version: 1.0.7(bufferutil@4.0.8)(typescript@5.7.3)(utf-8-validate@5.0.10)(zod@3.24.1)
+ zod:
+ specifier: ^3.23.8
+ version: 3.24.1
+
packages/test-utils:
dependencies:
'@epic-web/invariant':
@@ -488,6 +549,12 @@ importers:
'@testing-library/react':
specifier: ^16.0.1
version: 16.1.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.2(@types/react@19.0.4))(@types/react@19.0.4)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@zodiac/chains':
+ specifier: workspace:*
+ version: link:../chains
+ '@zodiac/schema':
+ specifier: workspace:*
+ version: link:../schema
react:
specifier: 19.0.0
version: 19.0.0
@@ -498,12 +565,18 @@ importers:
specifier: 2.1.8
version: 2.1.8(@types/node@22.10.5)(happy-dom@16.5.3)(less@4.2.1)(lightningcss@1.28.2)(sass@1.82.0)(stylus@0.62.0)
devDependencies:
+ '@types/node':
+ specifier: ^22.10.5
+ version: 22.10.5
'@types/react':
specifier: ^19.0.3
version: 19.0.4
'@types/react-dom':
specifier: ^19.0.2
version: 19.0.2(@types/react@19.0.4)
+ ser-kit:
+ specifier: 1.0.7
+ version: 1.0.7(bufferutil@4.0.8)(typescript@5.7.3)(utf-8-validate@5.0.10)(zod@3.24.1)
packages/ui:
dependencies:
@@ -5972,9 +6045,6 @@ packages:
resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==}
engines: {node: '>=10'}
- pkg-types@1.2.1:
- resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==}
-
pkg-types@1.3.0:
resolution: {integrity: sha512-kS7yWjVFCkIw9hqdJBoMxDdzEngmkr5FXeWZZfQ6GoYacjVnsW6l2CcYW/0ThD0vF4LPJgVYnrg4d0uuhwYQbg==}
@@ -10381,7 +10451,7 @@ snapshots:
'@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0)
'@vanilla-extract/babel-plugin-debug-ids': 1.2.0
'@vanilla-extract/css': 1.17.0(babel-plugin-macros@3.1.0)
- esbuild: 0.17.6
+ esbuild: 0.17.19
eval: 0.1.8
find-up: 5.0.0
javascript-stringify: 2.1.0
@@ -13433,7 +13503,7 @@ snapshots:
isomorphic-timers-promises@1.0.1: {}
- isows@1.0.6(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)):
+ isows@1.0.6(ws@8.18.0):
dependencies:
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
@@ -13665,7 +13735,7 @@ snapshots:
local-pkg@0.5.1:
dependencies:
mlly: 1.7.3
- pkg-types: 1.2.1
+ pkg-types: 1.3.0
locate-path@5.0.0:
dependencies:
@@ -14505,11 +14575,11 @@ snapshots:
ox@0.6.0(typescript@5.7.3)(zod@3.24.1):
dependencies:
'@adraffy/ens-normalize': 1.11.0
- '@noble/curves': 1.7.0
- '@noble/hashes': 1.6.1
- '@scure/bip32': 1.6.0
- '@scure/bip39': 1.5.0
- abitype: 1.0.7(typescript@5.7.3)(zod@3.24.1)
+ '@noble/curves': 1.8.0
+ '@noble/hashes': 1.7.0
+ '@scure/bip32': 1.6.1
+ '@scure/bip39': 1.5.1
+ abitype: 1.0.8(typescript@5.7.3)(zod@3.24.1)
eventemitter3: 5.0.1
optionalDependencies:
typescript: 5.7.3
@@ -14680,12 +14750,6 @@ snapshots:
dependencies:
find-up: 5.0.0
- pkg-types@1.2.1:
- dependencies:
- confbox: 0.1.8
- mlly: 1.7.3
- pathe: 1.1.2
-
pkg-types@1.3.0:
dependencies:
confbox: 0.1.8
@@ -16200,7 +16264,7 @@ snapshots:
'@scure/bip32': 1.6.0
'@scure/bip39': 1.5.0
abitype: 1.0.7(typescript@5.7.3)(zod@3.24.1)
- isows: 1.0.6(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))
+ isows: 1.0.6(ws@8.18.0)
ox: 0.6.0(typescript@5.7.3)(zod@3.24.1)
webauthn-p256: 0.0.10
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)