@1001-digital/layers.evm 1.0.2 → 1.0.4

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.
@@ -17,25 +17,12 @@
17
17
  <EvmTransactionFlow
18
18
  :request="sendTransaction"
19
19
  :text="{
20
- title: {
21
- confirm: 'Send Transaction',
22
- requesting: 'Requesting...',
23
- waiting: 'Waiting for confirmation...',
24
- complete: 'Transaction Complete!',
25
- error: 'Transaction Error',
26
- },
20
+ title: { confirm: 'Send Transaction' },
27
21
  lead: {
28
22
  confirm:
29
23
  'This will send 0 ETH to your address as a test transaction.',
30
- requesting: 'Please confirm the transaction in your wallet.',
31
- waiting: 'Your transaction is being processed...',
32
- complete: 'Your transaction has been confirmed on-chain.',
33
- error: 'An error occurred while processing your transaction.',
34
- },
35
- action: {
36
- confirm: 'Send Transaction',
37
- error: 'Try Again',
38
24
  },
25
+ action: { confirm: 'Send Transaction' },
39
26
  }"
40
27
  @complete="onTransactionComplete"
41
28
  @cancel="onTransactionCancel"
package/app/app.config.ts CHANGED
@@ -8,6 +8,9 @@ export default defineAppConfig({
8
8
  blockExplorer: 'https://etherscan.io',
9
9
  },
10
10
  },
11
+ ens: {
12
+ mode: 'indexer',
13
+ },
11
14
  },
12
15
  })
13
16
 
@@ -25,6 +28,11 @@ declare module '@nuxt/schema' {
25
28
  defaultChain?: string
26
29
  /** Named chain definitions */
27
30
  chains?: Record<string, EvmChainConfig>
31
+ /** ENS resolution configuration */
32
+ ens?: {
33
+ /** Resolution strategy: 'indexer' queries a ponder-ens API, 'chain' resolves on-chain */
34
+ mode?: 'indexer' | 'chain'
35
+ }
28
36
  }
29
37
  }
30
38
  }
@@ -6,10 +6,11 @@
6
6
 
7
7
  <script setup lang="ts">
8
8
  import type { Address } from 'viem'
9
- import { useConnection, useEnsName } from '@wagmi/vue'
9
+ import { useConnection } from '@wagmi/vue'
10
10
 
11
11
  const props = defineProps<{
12
12
  address?: Address
13
+ mode?: 'indexer' | 'chain'
13
14
  }>()
14
15
  const address = computed(() => props.address)
15
16
 
@@ -19,10 +20,7 @@ const isCurrent = computed<boolean>(
19
20
  () => currentAddress.value?.toLowerCase() === address.value?.toLowerCase(),
20
21
  )
21
22
 
22
- const { data: ens } = useEnsName({
23
- address,
24
- chainId: 1,
25
- })
23
+ const { data: profile } = useEns(address, { mode: computed(() => props.mode) })
26
24
 
27
- const display = computed<string>(() => ens.value || shortAddress(address.value!))
25
+ const display = computed<string>(() => profile.value?.ens || shortAddress(address.value!))
28
26
  </script>
@@ -93,9 +93,9 @@ import type { Config } from '@wagmi/vue'
93
93
  import type { TransactionReceipt, Hash } from 'viem'
94
94
 
95
95
  interface TextConfig {
96
- title: Record<string, string>
97
- lead: Record<string, string>
98
- action: Record<string, string>
96
+ title?: Record<string, string>
97
+ lead?: Record<string, string>
98
+ action?: Record<string, string>
99
99
  }
100
100
 
101
101
  type Step =
@@ -107,6 +107,28 @@ type Step =
107
107
  | 'complete'
108
108
  | 'error'
109
109
 
110
+ const defaultText = {
111
+ title: {
112
+ confirm: 'Confirm Transaction',
113
+ chain: 'Switch Network',
114
+ requesting: 'Requesting',
115
+ waiting: 'Processing',
116
+ complete: 'Complete',
117
+ error: 'Error',
118
+ },
119
+ lead: {
120
+ confirm: 'Please review and confirm this transaction.',
121
+ chain: 'Please switch to the correct network to continue.',
122
+ requesting: 'Requesting transaction signature...',
123
+ waiting: 'Waiting for transaction confirmation...',
124
+ complete: 'Transaction confirmed successfully.',
125
+ },
126
+ action: {
127
+ confirm: 'Execute',
128
+ error: 'Try Again',
129
+ },
130
+ } satisfies TextConfig
131
+
110
132
  const slots = useSlots()
111
133
  const checkChain = useEnsureChainIdCheck()
112
134
 
@@ -124,17 +146,6 @@ const props = withDefaults(
124
146
  dismissable?: boolean
125
147
  }>(),
126
148
  {
127
- text: () => ({
128
- title: {
129
- confirm: 'Confirm Transaction',
130
- },
131
- lead: {
132
- confirm: 'Please review and confirm this transaction.',
133
- },
134
- action: {
135
- confirm: 'Execute',
136
- },
137
- }),
138
149
  delayAfter: 2000,
139
150
  delayAutoclose: 2000,
140
151
  skipConfirmation: false,
@@ -148,6 +159,12 @@ const emit = defineEmits<{
148
159
  cancel: []
149
160
  }>()
150
161
 
162
+ const text = computed<Required<TextConfig>>(() => ({
163
+ title: { ...defaultText.title, ...props.text?.title },
164
+ lead: { ...defaultText.lead, ...props.text?.lead },
165
+ action: { ...defaultText.action, ...props.text?.action },
166
+ }))
167
+
151
168
  const step = ref<Step>('idle')
152
169
 
153
170
  const open = computed({
@@ -0,0 +1,68 @@
1
+ import { getPublicClient } from '@wagmi/core'
2
+ import type { Config } from '@wagmi/vue'
3
+
4
+ interface UseEnsOptions {
5
+ mode?: MaybeRefOrGetter<'indexer' | 'chain' | undefined>
6
+ }
7
+
8
+ function useEnsBase(
9
+ key: string,
10
+ identifier: MaybeRefOrGetter<string | undefined>,
11
+ chainKeys: string[],
12
+ options: UseEnsOptions = {},
13
+ ) {
14
+ const { $wagmi } = useNuxtApp()
15
+ const appConfig = useAppConfig()
16
+ const runtimeConfig = useRuntimeConfig()
17
+
18
+ const mode = computed(() => toValue(options.mode) || appConfig.evm?.ens?.mode || 'indexer')
19
+
20
+ const indexerUrls = computed(() => {
21
+ const ens = (runtimeConfig.public.evm as { ens?: { indexer1?: string, indexer2?: string, indexer3?: string } }).ens
22
+ if (!ens) return []
23
+ return [ens.indexer1, ens.indexer2, ens.indexer3].filter(Boolean) as string[]
24
+ })
25
+
26
+ const strategies = computed(() => {
27
+ const primary = mode.value
28
+ const fallback = primary === 'indexer' ? 'chain' : 'indexer'
29
+ return [primary, fallback] as const
30
+ })
31
+
32
+ return useAsyncData(
33
+ `ens-${key}-${toValue(identifier)}`,
34
+ async () => {
35
+ const id = toValue(identifier)
36
+ if (!id) return null
37
+
38
+ for (const strategy of strategies.value) {
39
+ try {
40
+ if (strategy === 'indexer') {
41
+ if (!indexerUrls.value.length) continue
42
+ return await fetchEnsFromIndexer(id, indexerUrls.value)
43
+ }
44
+
45
+ if (strategy === 'chain') {
46
+ const client = getPublicClient($wagmi as Config, { chainId: 1 })
47
+ if (!client) continue
48
+ return await fetchEnsFromChain(id, client, chainKeys)
49
+ }
50
+ } catch {
51
+ continue
52
+ }
53
+ }
54
+
55
+ return null
56
+ },
57
+ { watch: [() => toValue(identifier)] },
58
+ )
59
+ }
60
+
61
+ export const useEns = (identifier: MaybeRefOrGetter<string | undefined>, options?: UseEnsOptions) =>
62
+ useEnsBase('resolve', identifier, [], options)
63
+
64
+ export const useEnsAvatar = (identifier: MaybeRefOrGetter<string | undefined>, options?: UseEnsOptions) =>
65
+ useEnsBase('avatar', identifier, [...ENS_KEYS_AVATAR], options)
66
+
67
+ export const useEnsProfile = (identifier: MaybeRefOrGetter<string | undefined>, options?: UseEnsOptions) =>
68
+ useEnsBase('profile', identifier, [...ENS_KEYS_PROFILE], options)
@@ -0,0 +1,89 @@
1
+ import type { PublicClient, Address } from 'viem'
2
+ import { isAddress, normalize } from 'viem/ens'
3
+
4
+ export interface EnsProfile {
5
+ address: string
6
+ ens: string | null
7
+ data: {
8
+ avatar: string
9
+ header: string
10
+ description: string
11
+ links: {
12
+ url: string
13
+ email: string
14
+ twitter: string
15
+ github: string
16
+ }
17
+ } | null
18
+ }
19
+
20
+ const TEXT_RECORD_KEYS = ['avatar', 'header', 'description', 'url', 'email', 'com.twitter', 'com.github'] as const
21
+
22
+ function buildData(keys: string[], results: string[]): EnsProfile['data'] {
23
+ const get = (key: string) => {
24
+ const i = keys.indexOf(key)
25
+ return i >= 0 ? results[i] || '' : ''
26
+ }
27
+
28
+ return {
29
+ avatar: get('avatar'),
30
+ header: get('header'),
31
+ description: get('description'),
32
+ links: {
33
+ url: get('url'),
34
+ email: get('email'),
35
+ twitter: get('com.twitter'),
36
+ github: get('com.github'),
37
+ },
38
+ }
39
+ }
40
+
41
+ export async function fetchEnsFromIndexer(
42
+ identifier: string,
43
+ urls: string[],
44
+ ): Promise<EnsProfile> {
45
+ let lastError: Error | undefined
46
+
47
+ for (const url of urls) {
48
+ try {
49
+ return await $fetch<EnsProfile>(`${url}/${identifier}`)
50
+ } catch (err) {
51
+ lastError = err as Error
52
+ }
53
+ }
54
+
55
+ throw lastError ?? new Error('No indexer URLs provided')
56
+ }
57
+
58
+ export async function fetchEnsFromChain(
59
+ identifier: string,
60
+ client: PublicClient,
61
+ keys: string[] = [],
62
+ ): Promise<EnsProfile> {
63
+ const isAddr = isAddress(identifier)
64
+
65
+ let address: string
66
+ let ens: string | null
67
+
68
+ if (isAddr) {
69
+ address = identifier
70
+ ens = await client.getEnsName({ address: identifier as Address }) ?? null
71
+ } else {
72
+ ens = identifier
73
+ const resolved = await client.getEnsAddress({ name: normalize(identifier) })
74
+ if (!resolved) return { address: '', ens, data: null }
75
+ address = resolved
76
+ }
77
+
78
+ if (!ens || !keys.length) return { address, ens: ens ?? null, data: null }
79
+
80
+ const name = normalize(ens)
81
+ const results = await Promise.all(
82
+ keys.map(key => client.getEnsText({ name, key }).catch(() => '')),
83
+ )
84
+
85
+ return { address, ens, data: buildData(keys, results) }
86
+ }
87
+
88
+ export const ENS_KEYS_AVATAR = ['avatar'] as const
89
+ export const ENS_KEYS_PROFILE = [...TEXT_RECORD_KEYS]
package/nuxt.config.ts CHANGED
@@ -13,6 +13,11 @@ export default defineNuxtConfig({
13
13
  chains: {
14
14
  mainnet: { rpc1: '', rpc2: '', rpc3: '' },
15
15
  },
16
+ ens: {
17
+ indexer1: '',
18
+ indexer2: '',
19
+ indexer3: '',
20
+ },
16
21
  },
17
22
  },
18
23
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@1001-digital/layers.evm",
3
3
  "type": "module",
4
- "version": "1.0.2",
4
+ "version": "1.0.4",
5
5
  "main": "./nuxt.config.ts",
6
6
  "devDependencies": {
7
7
  "@nuxt/eslint": "latest",
@@ -10,10 +10,10 @@
10
10
  "nuxt": "^4.3.0",
11
11
  "typescript": "^5.9.3",
12
12
  "vue": "latest",
13
- "@1001-digital/layers.base": "^0.0.19"
13
+ "@1001-digital/layers.base": "^0.0.26"
14
14
  },
15
15
  "peerDependencies": {
16
- "@1001-digital/layers.base": "^0.0.19"
16
+ "@1001-digital/layers.base": "^0.0.26"
17
17
  },
18
18
  "dependencies": {
19
19
  "@types/qrcode": "^1.5.6",