@1001-digital/layers.evm 0.0.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example ADDED
@@ -0,0 +1,4 @@
1
+ NUXT_PUBLIC_EVM_WALLET_CONNECT_PROJECT_ID=""
2
+ NUXT_PUBLIC_EVM_CHAINS_MAINNET_RPC1=""
3
+ NUXT_PUBLIC_EVM_CHAINS_MAINNET_RPC2=""
4
+ NUXT_PUBLIC_EVM_CHAINS_MAINNET_RPC3=""
@@ -1,5 +1,12 @@
1
1
  export default defineAppConfig({
2
- myLayer: {
3
- name: 'My amazing Nuxt layer (overwritten)'
4
- }
2
+ evm: {
3
+ title: 'EVM Layer Playground',
4
+ defaultChain: 'mainnet',
5
+ chains: {
6
+ mainnet: {
7
+ id: 1,
8
+ blockExplorer: 'https://etherscan.io',
9
+ },
10
+ },
11
+ },
5
12
  })
package/AGENTS.md CHANGED
@@ -22,7 +22,7 @@ Uses modern wagmi 0.4.x patterns:
22
22
  - `useConnectionEffect` (not deprecated `useAccountEffect`)
23
23
  - `useSwitchConnection` (not deprecated `useSwitchAccount`)
24
24
 
25
- Configured chains: mainnet, sepolia, holesky, localhost
25
+ Configured chains: resolved dynamically from `app.config.ts` via `evm.chains` map (supports mainnet, sepolia, holesky, optimism, arbitrum, base, polygon, localhost out of the box)
26
26
 
27
27
  Connectors: injected, coinbaseWallet, metaMask, walletConnect
28
28
 
@@ -37,7 +37,9 @@ Connectors: injected, coinbaseWallet, metaMask, walletConnect
37
37
 
38
38
  ## Composables
39
39
 
40
- - `useMainChainId()` - Get configured chain ID from runtime config
40
+ - `useChainConfig(key?)` - Get `{ id, blockExplorer }` for a named chain (defaults to `defaultChain`)
41
+ - `useMainChainId()` - Get main chain ID from app config
42
+ - `useBlockExplorer(key?)` - Get block explorer URL for a named chain
41
43
  - `useEnsureChainIdCheck()` - Validate/switch chain before transactions
42
44
  - `useBaseURL()` - Get base URL with trailing slash
43
45
  - `useClipboard()` - Copy text to clipboard with copied state
@@ -46,17 +48,29 @@ Connectors: injected, coinbaseWallet, metaMask, walletConnect
46
48
 
47
49
  - `shortAddress(address, length)` - Truncate address for display
48
50
  - `formatETH(value, maxDecimals)` - Format ETH values
51
+ - `resolveChain(id)` - Resolve chain ID to viem Chain object
49
52
 
50
- ## Environment Variables
53
+ ## Configuration
54
+
55
+ Static chain config lives in `app.config.ts` (safe to commit):
56
+
57
+ ```ts
58
+ evm: {
59
+ title: 'My dApp',
60
+ defaultChain: 'mainnet',
61
+ chains: {
62
+ mainnet: { id: 1, blockExplorer: 'https://etherscan.io' },
63
+ },
64
+ }
65
+ ```
66
+
67
+ Sensitive RPC URLs live in `runtimeConfig.public.evm` (env-driven):
51
68
 
52
69
  ```bash
53
- NUXT_PUBLIC_TITLE="App Name"
54
- NUXT_PUBLIC_CHAIN_ID=1
55
- NUXT_PUBLIC_BLOCK_EXPLORER="https://etherscan.io"
56
- NUXT_PUBLIC_RPC1=""
57
- NUXT_PUBLIC_RPC2=""
58
- NUXT_PUBLIC_RPC3=""
59
- NUXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=""
70
+ NUXT_PUBLIC_EVM_WALLET_CONNECT_PROJECT_ID=""
71
+ NUXT_PUBLIC_EVM_CHAINS_MAINNET_RPC1=""
72
+ NUXT_PUBLIC_EVM_CHAINS_MAINNET_RPC2=""
73
+ NUXT_PUBLIC_EVM_CHAINS_MAINNET_RPC3=""
60
74
  ```
61
75
 
62
76
  ## Key directories
package/app/app.config.ts CHANGED
@@ -1,14 +1,30 @@
1
1
  export default defineAppConfig({
2
2
  evm: {
3
- name: 'Hello from Nuxt layer'
4
- }
3
+ title: 'EVM Layer',
4
+ defaultChain: 'mainnet',
5
+ chains: {
6
+ mainnet: {
7
+ id: 1,
8
+ blockExplorer: 'https://etherscan.io',
9
+ },
10
+ },
11
+ },
5
12
  })
6
13
 
14
+ interface EvmChainConfig {
15
+ id?: number
16
+ blockExplorer?: string
17
+ }
18
+
7
19
  declare module '@nuxt/schema' {
8
20
  interface AppConfigInput {
9
21
  evm?: {
10
- /** Project name */
11
- name?: string
22
+ /** App title */
23
+ title?: string
24
+ /** Key into `chains` that serves as the app's primary chain */
25
+ defaultChain?: string
26
+ /** Named chain definitions */
27
+ chains?: Record<string, EvmChainConfig>
12
28
  }
13
29
  }
14
30
  }
@@ -55,7 +55,7 @@ interface TextConfig {
55
55
  const checkChain = useEnsureChainIdCheck();
56
56
 
57
57
  const { $wagmi } = useNuxtApp();
58
- const config = useRuntimeConfig();
58
+ const blockExplorer = useBlockExplorer();
59
59
 
60
60
  const props = withDefaults(
61
61
  defineProps<{
@@ -122,7 +122,7 @@ const complete = ref(false);
122
122
  const error = ref("");
123
123
  const tx = ref<Hash | null>(null);
124
124
  const receipt = ref<TransactionReceipt | null>(null);
125
- const txLink = computed(() => `${config.public.blockExplorer}/tx/${tx.value}`);
125
+ const txLink = computed(() => `${blockExplorer}/tx/${tx.value}`);
126
126
 
127
127
  const step = computed(() => {
128
128
  if (
@@ -1,11 +1,28 @@
1
1
  import { useConnection, useSwitchChain } from '@wagmi/vue'
2
2
 
3
- export const useMainChainId = () => {
4
- const config = useRuntimeConfig()
3
+ interface ChainConfig {
4
+ id?: number
5
+ blockExplorer?: string
6
+ }
7
+
8
+ const getDefaultChainKey = () => useAppConfig().evm?.defaultChain || 'mainnet'
9
+
10
+ export const useChainConfig = (key?: string) => {
11
+ const appConfig = useAppConfig()
12
+ const resolvedKey = key || getDefaultChainKey()
13
+ const chains = appConfig.evm?.chains as Record<string, ChainConfig> | undefined
14
+ const chain = chains?.[resolvedKey]
5
15
 
6
- return config.public.chainId as 1 | 11155111 | 17000 | 1337 | 31337
16
+ return {
17
+ id: chain?.id ?? 1,
18
+ blockExplorer: chain?.blockExplorer ?? 'https://etherscan.io',
19
+ }
7
20
  }
8
21
 
22
+ export const useMainChainId = () => useChainConfig().id
23
+
24
+ export const useBlockExplorer = (key?: string) => useChainConfig(key).blockExplorer
25
+
9
26
  export const useEnsureChainIdCheck = () => {
10
27
  const chainId = useMainChainId()
11
28
  const { switchChain } = useSwitchChain()
@@ -9,14 +9,38 @@ import {
9
9
  type Config,
10
10
  type CreateConnectorFn,
11
11
  } from '@wagmi/vue'
12
- import { mainnet, sepolia, holesky, localhost } from '@wagmi/vue/chains'
13
12
  import { coinbaseWallet, injected, metaMask, walletConnect } from '@wagmi/vue/connectors'
14
- import type { CustomTransport, Transport } from 'viem'
13
+ import type { Chain, Transport } from 'viem'
15
14
 
16
15
  export default defineNuxtPlugin((nuxtApp) => {
17
- const title = nuxtApp.$config.public.title || 'EVM Layer'
18
- const mainChainId = nuxtApp.$config.public.chainId
16
+ const appConfig = useAppConfig()
17
+ const runtimeConfig = nuxtApp.$config.public.evm as {
18
+ walletConnectProjectId: string
19
+ chains: Record<string, { rpc1?: string, rpc2?: string, rpc3?: string }>
20
+ }
21
+
22
+ const title = appConfig.evm?.title || 'EVM Layer'
23
+ const chainEntries = appConfig.evm?.chains || {}
24
+
25
+ // Build chains and transports from config
26
+ const chains: [Chain, ...Chain[]] = [] as unknown as [Chain, ...Chain[]]
27
+ const transports: Record<number, Transport> = {}
19
28
 
29
+ for (const [key, entry] of Object.entries(chainEntries)) {
30
+ const chain = resolveChain(entry.id!)
31
+ chains.push(chain)
32
+
33
+ const rpcs = runtimeConfig.chains?.[key]
34
+ const transportList = []
35
+ if (rpcs?.rpc1) transportList.push(http(rpcs.rpc1))
36
+ if (rpcs?.rpc2) transportList.push(http(rpcs.rpc2))
37
+ if (rpcs?.rpc3) transportList.push(http(rpcs.rpc3))
38
+ transportList.push(http())
39
+
40
+ transports[chain.id] = fallback(transportList)
41
+ }
42
+
43
+ // Connectors
20
44
  const connectors: CreateConnectorFn[] = [
21
45
  injected(),
22
46
  coinbaseWallet({
@@ -33,28 +57,16 @@ export default defineNuxtPlugin((nuxtApp) => {
33
57
  }),
34
58
  ]
35
59
 
36
- if (import.meta.client && nuxtApp.$config.public.walletConnectProjectId)
60
+ if (import.meta.client && runtimeConfig.walletConnectProjectId)
37
61
  connectors.push(
38
62
  walletConnect({
39
- projectId: nuxtApp.$config.public.walletConnectProjectId,
63
+ projectId: runtimeConfig.walletConnectProjectId,
40
64
  showQrModal: false,
41
65
  }),
42
66
  )
43
67
 
44
- const transportDefinitions: CustomTransport | Transport[] = []
45
-
46
- if (nuxtApp.$config.public.rpc1)
47
- transportDefinitions.push(http(nuxtApp.$config.public.rpc1 as string))
48
- if (nuxtApp.$config.public.rpc2)
49
- transportDefinitions.push(http(nuxtApp.$config.public.rpc2 as string))
50
- if (nuxtApp.$config.public.rpc3)
51
- transportDefinitions.push(http(nuxtApp.$config.public.rpc3 as string))
52
- transportDefinitions.push(http())
53
-
54
- const transports = fallback(transportDefinitions)
55
-
56
68
  const wagmiConfig: Config = createConfig({
57
- chains: [mainnet, sepolia, holesky, localhost],
69
+ chains,
58
70
  batch: {
59
71
  multicall: true,
60
72
  },
@@ -63,12 +75,7 @@ export default defineNuxtPlugin((nuxtApp) => {
63
75
  storage: cookieStorage,
64
76
  }),
65
77
  ssr: true,
66
- transports: {
67
- [mainnet.id]: mainChainId == 1 ? transports : http(),
68
- [sepolia.id]: transports,
69
- [holesky.id]: transports,
70
- [localhost.id]: transports,
71
- },
78
+ transports,
72
79
  })
73
80
 
74
81
  nuxtApp.vueApp.use(WagmiPlugin, { config: wagmiConfig }).use(VueQueryPlugin, {})
@@ -0,0 +1,13 @@
1
+ import { defineChain, type Chain } from 'viem'
2
+ import { mainnet, sepolia, holesky, optimism, arbitrum, base, polygon, localhost } from 'viem/chains'
3
+
4
+ const KNOWN: Chain[] = [mainnet, sepolia, holesky, optimism, arbitrum, base, polygon, localhost]
5
+ const byId = new Map<number, Chain>(KNOWN.map(c => [c.id, c]))
6
+
7
+ export const resolveChain = (id: number): Chain =>
8
+ byId.get(id) ?? defineChain({
9
+ id,
10
+ name: `Chain ${id}`,
11
+ nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
12
+ rpcUrls: { default: { http: [] } },
13
+ })
package/nuxt.config.ts CHANGED
@@ -8,13 +8,12 @@ export default defineNuxtConfig({
8
8
 
9
9
  runtimeConfig: {
10
10
  public: {
11
- title: 'EVM Layer',
12
- blockExplorer: 'https://etherscan.io',
13
- chainId: 1,
14
- rpc1: '',
15
- rpc2: '',
16
- rpc3: '',
17
- walletConnectProjectId: '',
11
+ evm: {
12
+ walletConnectProjectId: '',
13
+ chains: {
14
+ mainnet: { rpc1: '', rpc2: '', rpc3: '' },
15
+ },
16
+ },
18
17
  },
19
18
  },
20
19
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@1001-digital/layers.evm",
3
3
  "type": "module",
4
- "version": "0.0.8",
4
+ "version": "1.0.0",
5
5
  "main": "./nuxt.config.ts",
6
6
  "devDependencies": {
7
7
  "@nuxt/eslint": "latest",
@@ -19,6 +19,7 @@
19
19
  "@types/qrcode": "^1.5.6",
20
20
  "@metamask/sdk": "~0.34.0",
21
21
  "@tanstack/vue-query": "^5.92.9",
22
+ "@wagmi/core": "^3.3.2",
22
23
  "@wagmi/vue": "^0.4.15",
23
24
  "@walletconnect/ethereum-provider": "~2.23.4",
24
25
  "qrcode": "^1.5.4",
@@ -1,7 +0,0 @@
1
- NUXT_PUBLIC_TITLE="EVM Layer Playground"
2
- NUXT_PUBLIC_CHAIN_ID=1
3
- NUXT_PUBLIC_BLOCK_EXPLORER="https://etherscan.io"
4
- NUXT_PUBLIC_RPC1=""
5
- NUXT_PUBLIC_RPC2=""
6
- NUXT_PUBLIC_RPC3=""
7
- NUXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=""