@1001-digital/layers.evm 0.0.8 → 1.0.1

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
  }
@@ -1,5 +1,10 @@
1
1
  <template>
2
- <slot :start="start" :step="step" :open="open" name="start"></slot>
2
+ <slot
3
+ :start="start"
4
+ :step="step"
5
+ :open="open"
6
+ name="start"
7
+ ></slot>
3
8
 
4
9
  <Dialog
5
10
  v-model:open="open"
@@ -11,12 +16,21 @@
11
16
 
12
17
  <h1 v-if="text.title[step]">{{ text.title[step] }}</h1>
13
18
 
19
+ <Loading
20
+ v-if="step === 'requesting' || step === 'waiting'"
21
+ spinner
22
+ txt=""
23
+ />
24
+
14
25
  <div class="text">
15
26
  <p v-if="text.lead[step]">{{ text.lead[step] }}</p>
16
27
  <p v-if="error">{{ error }}</p>
17
28
  </div>
18
29
 
19
- <slot :name="step" :cancel="cancel"></slot>
30
+ <slot
31
+ :name="step"
32
+ :cancel="cancel"
33
+ ></slot>
20
34
 
21
35
  <Button
22
36
  v-if="step === 'waiting'"
@@ -24,59 +38,75 @@
24
38
  target="_blank"
25
39
  class="block-explorer"
26
40
  >
27
- <Icon type="loader" class="spin" />
28
- <span>View on Block Explorer</span>
41
+ View on Block Explorer
29
42
  </Button>
30
43
 
31
44
  <Actions v-if="step === 'chain'">
32
- <Button @click="cancel" class="secondary">Cancel</Button>
45
+ <Button
46
+ @click="cancel"
47
+ class="secondary"
48
+ >Cancel</Button
49
+ >
33
50
  </Actions>
34
51
 
35
52
  <Actions v-if="step === 'confirm' || step === 'error'">
36
- <Button @click="cancel" class="secondary">Cancel</Button>
37
- <Button @click="() => initializeRequest()">{{
38
- text.action[step] || "Execute"
39
- }}</Button>
53
+ <Button
54
+ @click="cancel"
55
+ class="secondary"
56
+ >Cancel</Button
57
+ >
58
+ <Button @click="() => initializeRequest()">
59
+ {{ text.action[step] || 'Execute' }}
60
+ </Button>
40
61
  </Actions>
41
62
  </Dialog>
42
63
  </template>
43
64
 
44
65
  <script setup lang="ts">
45
- import { waitForTransactionReceipt, watchChainId } from "@wagmi/core";
46
- import type { Config } from "@wagmi/vue";
47
- import type { TransactionReceipt, Hash } from "viem";
66
+ import { waitForTransactionReceipt, watchChainId } from '@wagmi/core'
67
+ import type { Config } from '@wagmi/vue'
68
+ import type { TransactionReceipt, Hash } from 'viem'
48
69
 
49
70
  interface TextConfig {
50
- title: Record<string, string>;
51
- lead: Record<string, string>;
52
- action: Record<string, string>;
71
+ title: Record<string, string>
72
+ lead: Record<string, string>
73
+ action: Record<string, string>
53
74
  }
54
75
 
55
- const checkChain = useEnsureChainIdCheck();
76
+ type Step =
77
+ | 'idle'
78
+ | 'confirm'
79
+ | 'chain'
80
+ | 'requesting'
81
+ | 'waiting'
82
+ | 'complete'
83
+ | 'error'
84
+
85
+ const checkChain = useEnsureChainIdCheck()
56
86
 
57
- const { $wagmi } = useNuxtApp();
58
- const config = useRuntimeConfig();
87
+ const { $wagmi } = useNuxtApp()
88
+ const blockExplorer = useBlockExplorer()
59
89
 
60
90
  const props = withDefaults(
61
91
  defineProps<{
62
- text?: TextConfig;
63
- request?: () => Promise<Hash>;
64
- delayAfter?: number;
65
- delayAutoclose?: number;
66
- skipConfirmation?: boolean;
67
- autoCloseSuccess?: boolean;
68
- dismissable?: boolean;
92
+ text?: TextConfig
93
+ request?: () => Promise<Hash>
94
+ delayAfter?: number
95
+ delayAutoclose?: number
96
+ skipConfirmation?: boolean
97
+ autoCloseSuccess?: boolean
98
+ dismissable?: boolean
69
99
  }>(),
70
100
  {
71
101
  text: () => ({
72
102
  title: {
73
- confirm: "Confirm Transaction",
103
+ confirm: 'Confirm Transaction',
74
104
  },
75
105
  lead: {
76
- confirm: "Please review and confirm this transaction.",
106
+ confirm: 'Please review and confirm this transaction.',
77
107
  },
78
108
  action: {
79
- confirm: "Execute",
109
+ confirm: 'Execute',
80
110
  },
81
111
  }),
82
112
  delayAfter: 2000,
@@ -85,147 +115,112 @@ const props = withDefaults(
85
115
  autoCloseSuccess: true,
86
116
  dismissable: true,
87
117
  },
88
- );
118
+ )
89
119
 
90
120
  const emit = defineEmits<{
91
- complete: [receipt: TransactionReceipt];
92
- cancel: [];
93
- }>();
121
+ complete: [receipt: TransactionReceipt]
122
+ cancel: []
123
+ }>()
124
+
125
+ const step = ref<Step>('idle')
94
126
 
95
- const open = ref(false);
127
+ const open = computed({
128
+ get: () => step.value !== 'idle',
129
+ set: (v) => {
130
+ if (!v) step.value = 'idle'
131
+ },
132
+ })
96
133
 
97
- const switchChain = ref(false);
98
134
  watchChainId($wagmi as Config, {
99
135
  async onChange() {
100
- if (!switchChain.value) return;
136
+ if (step.value !== 'chain') return
101
137
 
102
138
  if (await checkChain()) {
103
- switchChain.value = false;
104
- initializeRequest();
105
- } else {
106
- switchChain.value = true;
139
+ initializeRequest()
107
140
  }
108
141
  },
109
- });
142
+ })
110
143
 
111
- const cachedRequest = ref(props.request);
144
+ const cachedRequest = ref(props.request)
112
145
  watch(
113
146
  () => props.request,
114
- () => {
115
- cachedRequest.value = props.request;
147
+ (v) => {
148
+ cachedRequest.value = v
116
149
  },
117
- );
118
-
119
- const requesting = ref(false);
120
- const waiting = ref(false);
121
- const complete = ref(false);
122
- const error = ref("");
123
- const tx = ref<Hash | null>(null);
124
- const receipt = ref<TransactionReceipt | null>(null);
125
- const txLink = computed(() => `${config.public.blockExplorer}/tx/${tx.value}`);
126
-
127
- const step = computed(() => {
128
- if (
129
- open.value &&
130
- !requesting.value &&
131
- !switchChain.value &&
132
- !waiting.value &&
133
- !complete.value
134
- ) {
135
- return "confirm";
136
- }
137
-
138
- if (switchChain.value) {
139
- return "chain";
140
- }
141
-
142
- if (requesting.value) {
143
- return "requesting";
144
- }
145
-
146
- if (waiting.value) {
147
- return "waiting";
148
- }
150
+ )
149
151
 
150
- if (complete.value) {
151
- return "complete";
152
- }
153
-
154
- return "error";
155
- });
152
+ const error = ref('')
153
+ const tx = ref<Hash | null>(null)
154
+ const receipt = ref<TransactionReceipt | null>(null)
155
+ const txLink = computed(() => `${blockExplorer}/tx/${tx.value}`)
156
156
 
157
157
  const canDismiss = computed(
158
- () => props.dismissable && step.value !== "requesting",
159
- );
158
+ () =>
159
+ props.dismissable &&
160
+ step.value !== 'requesting' &&
161
+ step.value !== 'waiting',
162
+ )
160
163
 
161
164
  const initializeRequest = async (request = cachedRequest.value) => {
162
- cachedRequest.value = request;
163
- complete.value = false;
164
- open.value = true;
165
- error.value = "";
166
- tx.value = null;
167
- receipt.value = null;
165
+ cachedRequest.value = request
166
+ error.value = ''
167
+ tx.value = null
168
+ receipt.value = null
169
+ step.value = 'confirm'
168
170
 
169
171
  if (!(await checkChain())) {
170
- switchChain.value = true;
171
- return;
172
- } else {
173
- switchChain.value = false;
172
+ step.value = 'chain'
173
+ return
174
174
  }
175
175
 
176
- if (requesting.value) return;
177
-
178
176
  try {
179
- requesting.value = true;
180
- tx.value = await request!();
181
- requesting.value = false;
182
- waiting.value = true;
183
- const [receiptObject] = await Promise.all([
184
- waitForTransactionReceipt($wagmi as Config, { hash: tx.value }),
185
- ]);
186
- await delay(props.delayAfter);
187
- receipt.value = receiptObject;
188
- emit("complete", receiptObject);
189
- complete.value = true;
177
+ step.value = 'requesting'
178
+ tx.value = await request!()
179
+ step.value = 'waiting'
180
+ const receiptObject = await waitForTransactionReceipt($wagmi as Config, {
181
+ hash: tx.value,
182
+ })
183
+ await delay(props.delayAfter)
184
+ receipt.value = receiptObject
185
+ emit('complete', receiptObject)
186
+ step.value = 'complete'
190
187
  } catch (e: unknown) {
191
- const err = e as { cause?: { code?: number }; shortMessage?: string };
188
+ const err = e as { cause?: { code?: number }; shortMessage?: string }
192
189
  if (err?.cause?.code === 4001) {
193
- open.value = false;
190
+ step.value = 'idle'
194
191
  } else {
195
- error.value = err.shortMessage || "Error submitting transaction request.";
192
+ error.value = err.shortMessage || 'Error submitting transaction request.'
193
+ step.value = 'error'
196
194
  }
197
- console.log(e);
195
+ console.log(e)
198
196
  }
199
197
 
200
- requesting.value = false;
201
- waiting.value = false;
202
-
203
- if (props.autoCloseSuccess && step.value === "complete") {
204
- await delay(props.delayAutoclose);
205
- open.value = false;
206
- await delay(300);
198
+ if (props.autoCloseSuccess && step.value === 'complete') {
199
+ await delay(props.delayAutoclose)
200
+ step.value = 'idle'
201
+ await delay(300)
207
202
  }
208
203
 
209
- return receipt.value;
210
- };
204
+ return receipt.value
205
+ }
211
206
 
212
207
  const start = () => {
213
- if (props.skipConfirmation && !open.value) {
214
- initializeRequest();
208
+ if (props.skipConfirmation && step.value === 'idle') {
209
+ initializeRequest()
210
+ return
215
211
  }
216
212
 
217
- open.value = true;
218
- };
213
+ step.value = 'confirm'
214
+ }
219
215
 
220
216
  const cancel = () => {
221
- open.value = false;
222
-
223
- emit("cancel");
224
- };
217
+ step.value = 'idle'
218
+ emit('cancel')
219
+ }
225
220
 
226
221
  defineExpose({
227
222
  initializeRequest,
228
- });
223
+ })
229
224
  </script>
230
225
 
231
226
  <style>
@@ -233,22 +228,11 @@ defineExpose({
233
228
  display: grid;
234
229
  gap: var(--spacer);
235
230
 
236
- .spinner {
237
- width: var(--size-7);
238
- height: var(--size-7);
239
- margin: calc(-1 * var(--size-4)) 0 var(--size-3);
240
- }
241
-
242
231
  .text {
243
232
  width: 100%;
244
233
  height: min-content;
245
234
  }
246
235
 
247
- h1 {
248
- font-size: var(--font-lg);
249
- margin-bottom: var(--size-4);
250
- }
251
-
252
236
  p {
253
237
  white-space: pre-wrap;
254
238
  width: 100%;
@@ -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.1",
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=""