Skip to content

Commit 4b4dee3

Browse files
committed
Add viem fallback client helper
1 parent ec2eb90 commit 4b4dee3

6 files changed

Lines changed: 504 additions & 275 deletions

File tree

packages/core/README.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# @goodwidget/core
2+
3+
Runtime helpers for GoodWidget providers, host detection, wallet context, and viem client setup.
4+
5+
## viem fallback clients
6+
7+
`createViemFallbackClient` wraps viem `createPublicClient` and `createWalletClient` so callers get a fallback HTTP transport built from cached Chainlist RPC URLs for the requested chain.
8+
9+
The helper accepts a small key-value storage adapter. On initialization it reads cached RPC metadata from storage. If the cache is missing or older than 1 day, it starts a background refresh from Chainlist. Client creation waits for that first refresh only when no cached RPCs are available for the requested chain.
10+
11+
```ts
12+
import { createViemFallbackClient } from '@goodwidget/core/viemFallbackClient'
13+
import { celo } from 'viem/chains'
14+
15+
const viemClient = createViemFallbackClient(localStorage, {
16+
onError(error) {
17+
console.warn('RPC refresh failed', error)
18+
},
19+
})
20+
21+
const publicClient = await viemClient.createPublicClient({
22+
chain: celo,
23+
fallbackRpcs: ['https://forno.celo.org'],
24+
})
25+
```
26+
27+
The same helper can create wallet clients. Any viem wallet client option, such as `account`, can be passed through.
28+
29+
```ts
30+
import { privateKeyToAccount } from 'viem/accounts'
31+
import { celo } from 'viem/chains'
32+
33+
const account = privateKeyToAccount('0x...')
34+
35+
const walletClient = await viemClient.createWalletClient({
36+
account,
37+
chain: celo,
38+
fallbackRpcs: ['https://forno.celo.org'],
39+
})
40+
```
41+
42+
If you pass `transport`, the wrapper leaves it unchanged and does not create a fallback transport for that client.
43+
44+
```ts
45+
import { http } from 'viem'
46+
import { celo } from 'viem/chains'
47+
48+
const client = await viemClient.createPublicClient({
49+
chain: celo,
50+
transport: http('https://forno.celo.org'),
51+
})
52+
```
53+
54+
## Storage adapters
55+
56+
The adapter supports browser-style storage and Worker-style KV storage.
57+
58+
```ts
59+
createViemFallbackClient(localStorage)
60+
```
61+
62+
```ts
63+
createViemFallbackClient({
64+
get: (key) => env.KV.get(key, 'json'),
65+
put: (key, value) => env.KV.put(key, value),
66+
})
67+
```
68+
69+
Cached values use this shape:
70+
71+
```ts
72+
type ViemRpcCacheEntry = {
73+
fetchedAt: string
74+
rpcs: Array<{
75+
chainId: number
76+
rpcs: string[]
77+
}>
78+
}
79+
```
80+
81+
Only HTTPS RPC URLs are used. URLs containing Chainlist template placeholders are ignored.
82+
83+
## Options
84+
85+
```ts
86+
createViemFallbackClient(storage, {
87+
cacheKey: 'goodwidget:viem-rpcs',
88+
chainlistRpcsUrl: 'https://chainlist.org/rpcs.json',
89+
refreshIntervalMs: 24 * 60 * 60 * 1000,
90+
fetchTimeoutMs: 10_000,
91+
fetch: globalThis.fetch,
92+
onError: console.warn,
93+
})
94+
```
95+
96+
`chainlistRpcsUrl` is intended for Chainlist's HTTPS RPC JSON endpoint. The helper blocks non-HTTPS URLs and hosts outside the expected Chainlist domain.

packages/core/package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
"types": "./dist/wagmi.d.ts",
1616
"import": "./dist/wagmi.js",
1717
"require": "./dist/wagmi.cjs"
18+
},
19+
"./viemFallbackClient": {
20+
"types": "./dist/viemFallbackClient.d.ts",
21+
"import": "./dist/viemFallbackClient.js",
22+
"require": "./dist/viemFallbackClient.cjs"
1823
}
1924
},
2025
"scripts": {
@@ -35,7 +40,8 @@
3540
},
3641
"dependencies": {
3742
"@goodwidget/ui": "workspace:*",
38-
"tamagui": "1.121.0"
43+
"tamagui": "1.121.0",
44+
"viem": "^2.0.0"
3945
},
4046
"devDependencies": {
4147
"react": "^18.3.0",

packages/core/src/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@ export { GoodWidgetProvider } from './provider'
22
export type { WalletContextValue, HostContextValue, GoodWidgetContextValue } from './provider'
33
export { useWallet, useHost, useGoodWidget } from './hooks'
44
export { detectHost } from './detect'
5+
export { createViemFallbackClient } from './viemFallbackClient'
6+
export type {
7+
CachedChainRpcs,
8+
ViemFallbackClient,
9+
ViemFallbackClientOptions,
10+
ViemFallbackPublicClientParameters,
11+
ViemFallbackStorage,
12+
ViemFallbackWalletClientParameters,
13+
ViemRpcCacheEntry,
14+
} from './viemFallbackClient'
515

616
export type {
717
EIP1193Provider,

0 commit comments

Comments
 (0)