@1001-digital/layers.evm 1.0.6 → 1.0.7

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 CHANGED
@@ -1,4 +1,9 @@
1
1
  NUXT_PUBLIC_EVM_WALLET_CONNECT_PROJECT_ID=""
2
+
2
3
  NUXT_PUBLIC_EVM_CHAINS_MAINNET_RPC1=""
3
4
  NUXT_PUBLIC_EVM_CHAINS_MAINNET_RPC2=""
4
5
  NUXT_PUBLIC_EVM_CHAINS_MAINNET_RPC3=""
6
+
7
+ NUXT_PUBLIC_EVM_ENS_INDEXER1=""
8
+ NUXT_PUBLIC_EVM_ENS_INDEXER2=""
9
+ NUXT_PUBLIC_EVM_ENS_INDEXER3=""
@@ -0,0 +1,36 @@
1
+ import type { WatchStopHandle } from 'vue'
2
+ import { formatEther, formatGwei } from 'viem'
3
+ import { getGasPrice } from '@wagmi/core'
4
+ import { useConfig, useBlockNumber } from '@wagmi/vue'
5
+
6
+ let priceWatcher: WatchStopHandle | null = null
7
+ const price: Ref<bigint> = ref(0n)
8
+
9
+ export const useGasPrice = () => {
10
+ const config = useConfig()
11
+ const { data: blockNumber } = useBlockNumber()
12
+
13
+ const updatePrice = async () => {
14
+ price.value = await getGasPrice(config)
15
+ }
16
+
17
+ if (!priceWatcher) {
18
+ updatePrice()
19
+ priceWatcher = watch(blockNumber, () => updatePrice())
20
+ }
21
+
22
+ const unitPrice = computed(() => ({
23
+ wei: price.value,
24
+ gwei: formatGwei(price.value),
25
+ eth: formatEther(price.value),
26
+
27
+ formatted: {
28
+ gwei: price.value > 2_000_000_000_000n
29
+ ? Math.round(parseFloat(formatGwei(price.value)))
30
+ : parseFloat(formatGwei(price.value)).toFixed(1),
31
+ eth: formatEther(price.value),
32
+ },
33
+ }))
34
+
35
+ return unitPrice
36
+ }
@@ -0,0 +1,103 @@
1
+ import { readContract } from '@wagmi/core'
2
+
3
+ const CHAINLINK_ETH_USD_ABI = [
4
+ {
5
+ inputs: [],
6
+ name: 'latestRoundData',
7
+ outputs: [
8
+ { internalType: 'uint80', name: 'roundId', type: 'uint80' },
9
+ { internalType: 'int256', name: 'answer', type: 'int256' },
10
+ { internalType: 'uint256', name: 'startedAt', type: 'uint256' },
11
+ { internalType: 'uint256', name: 'updatedAt', type: 'uint256' },
12
+ { internalType: 'uint80', name: 'answeredInRound', type: 'uint80' },
13
+ ],
14
+ stateMutability: 'view',
15
+ type: 'function',
16
+ },
17
+ ] as const
18
+
19
+ const CHAINLINK_ETH_USD = '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'
20
+ const STORAGE_KEY = 'evm:price-feed'
21
+ const CACHE_TTL = 3_600 // 1 hour in seconds
22
+
23
+ interface PriceFeedState {
24
+ ethUSDRaw: bigint | null
25
+ lastUpdated: number
26
+ }
27
+
28
+ const state = reactive<PriceFeedState>({
29
+ ethUSDRaw: null,
30
+ lastUpdated: 0,
31
+ })
32
+
33
+ function loadFromStorage() {
34
+ if (!import.meta.client) return
35
+
36
+ try {
37
+ const stored = localStorage.getItem(STORAGE_KEY)
38
+ if (!stored) return
39
+
40
+ const parsed = parseJSON(stored) as PriceFeedState
41
+ if (parsed.ethUSDRaw) state.ethUSDRaw = parsed.ethUSDRaw
42
+ if (parsed.lastUpdated) state.lastUpdated = parsed.lastUpdated
43
+ } catch {
44
+ // Ignore corrupted storage
45
+ }
46
+ }
47
+
48
+ function saveToStorage() {
49
+ if (!import.meta.client) return
50
+
51
+ try {
52
+ localStorage.setItem(STORAGE_KEY, stringifyJSON({
53
+ ethUSDRaw: state.ethUSDRaw,
54
+ lastUpdated: state.lastUpdated,
55
+ }))
56
+ } catch {
57
+ // Ignore storage errors
58
+ }
59
+ }
60
+
61
+ export const usePriceFeed = () => {
62
+ const { $wagmi } = useNuxtApp()
63
+
64
+ // Load cached data on first use
65
+ if (!state.lastUpdated) loadFromStorage()
66
+
67
+ const ethUSD = computed(() => state.ethUSDRaw ? state.ethUSDRaw / BigInt(1e8) : 0n)
68
+ const ethUSC = computed(() => state.ethUSDRaw ? state.ethUSDRaw / BigInt(1e6) : 0n)
69
+ const ethUSDFormatted = computed(() => formatPrice(Number(ethUSC.value) / 100, 2))
70
+
71
+ const weiToUSD = (wei: bigint) => {
72
+ const cents = (wei * (state.ethUSDRaw || 0n)) / (10n ** 18n) / (10n ** 6n)
73
+ return formatPrice(Number(cents) / 100, 2)
74
+ }
75
+
76
+ async function fetchPrice() {
77
+ if (nowInSeconds() - state.lastUpdated < CACHE_TTL) return
78
+
79
+ try {
80
+ const [, answer] = await readContract($wagmi, {
81
+ address: CHAINLINK_ETH_USD,
82
+ abi: CHAINLINK_ETH_USD_ABI,
83
+ functionName: 'latestRoundData',
84
+ chainId: 1,
85
+ })
86
+
87
+ state.ethUSDRaw = answer
88
+ state.lastUpdated = nowInSeconds()
89
+ saveToStorage()
90
+ } catch (error) {
91
+ console.warn('Error fetching ETH/USD price:', error)
92
+ }
93
+ }
94
+
95
+ return {
96
+ ethUSDRaw: computed(() => state.ethUSDRaw),
97
+ ethUSD,
98
+ ethUSC,
99
+ ethUSDFormatted,
100
+ weiToUSD,
101
+ fetchPrice,
102
+ }
103
+ }
@@ -0,0 +1,7 @@
1
+ export default defineNuxtPlugin(() => {
2
+ const priceFeed = usePriceFeed()
3
+
4
+ priceFeed.fetchPrice()
5
+
6
+ setInterval(() => priceFeed.fetchPrice(), 60 * 60 * 1000)
7
+ })
@@ -0,0 +1,15 @@
1
+ const replacer = (_: string, value: unknown) => {
2
+ if (typeof value === 'bigint') return value.toString() + 'n'
3
+ return value
4
+ }
5
+
6
+ const reviver = (_: string, value: unknown) => {
7
+ if (typeof value === 'string' && /^\d+n$/.test(value)) return BigInt(value.slice(0, -1))
8
+ return value
9
+ }
10
+
11
+ export const stringifyJSON = (obj: unknown): string => JSON.stringify(obj, replacer)
12
+ export const parseJSON = (json: string): unknown => JSON.parse(json, reviver)
13
+
14
+ export const formatPrice = (num: number, digits: number = 2) =>
15
+ num?.toLocaleString('en-US', { maximumFractionDigits: digits })
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.6",
4
+ "version": "1.0.7",
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.26"
13
+ "@1001-digital/layers.base": "^0.0.27"
14
14
  },
15
15
  "peerDependencies": {
16
- "@1001-digital/layers.base": "^0.0.26"
16
+ "@1001-digital/layers.base": "^0.0.27"
17
17
  },
18
18
  "dependencies": {
19
19
  "@types/qrcode": "^1.5.6",