Skip to content

Commit 346bdb9

Browse files
committed
fix: default resolveChain to mainnet, add resolveRpcUrl helper
- Add resolveRpcUrl() that consolidates RPC URL resolution: explicit flag → MPPX_RPC_URL env → RPC_URL env → undefined. Replaces 5 scattered inline patterns across cli.ts, tempo.ts, and utils.ts. - resolveChain() now uses resolveRpcUrl() internally, so env vars are always respected. Default is tempoMainnet (not testnet). - Add tests for both resolveRpcUrl and resolveChain defaults.
1 parent f086276 commit 346bdb9

4 files changed

Lines changed: 88 additions & 14 deletions

File tree

src/cli/cli.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
printResponseHeaders,
3333
prompt,
3434
resolveChain,
35+
resolveRpcUrl,
3536
} from './utils.js'
3637

3738
const packageJson = createRequire(import.meta.url)('../../package.json') as {
@@ -516,8 +517,9 @@ const account = Cli.create('account', {
516517
? link(`${explorerUrl}/address/${acct.address}`, acct.address)
517518
: acct.address
518519
console.log(pc.dim(`Address ${addrDisplay}`))
519-
resolveChain(c.options)
520-
.then((chain) => createClient({ chain, transport: http(c.options.rpcUrl) }))
520+
const rpcUrl = resolveRpcUrl(c.options.rpcUrl)
521+
resolveChain({ rpcUrl })
522+
.then((chain) => createClient({ chain, transport: http(rpcUrl) }))
521523
.then((client) =>
522524
import('viem/tempo').then(({ Actions }) =>
523525
Actions.faucet.fund(client, { account: acct }).catch(() => {}),
@@ -629,8 +631,9 @@ const account = Cli.create('account', {
629631
return c.error({ code: 'ACCOUNT_NOT_FOUND', message: 'No account found.', exitCode: 69 })
630632
}
631633
const acct = privateKeyToAccount(key as `0x${string}`)
632-
const chain = await resolveChain(c.options)
633-
const client = createClient({ chain, transport: http(c.options.rpcUrl) })
634+
const rpcUrl = resolveRpcUrl(c.options.rpcUrl)
635+
const chain = await resolveChain({ rpcUrl })
636+
const client = createClient({ chain, transport: http(rpcUrl) })
634637
console.log(`Funding "${accountName}" on ${chainName(chain)}`)
635638
try {
636639
const { Actions } = await import('viem/tempo')
@@ -711,8 +714,8 @@ const account = Cli.create('account', {
711714
})
712715
}
713716
const address = tempoEntry.wallet_address as Address
714-
const rpcUrl = c.options.rpcUrl ?? (process.env.MPPX_RPC_URL || undefined)
715-
const chain = rpcUrl ? await resolveChain({ rpcUrl }) : tempoMainnet
717+
const rpcUrl = resolveRpcUrl(c.options.rpcUrl)
718+
const chain = await resolveChain({ rpcUrl })
716719
const explorerUrl = chain.blockExplorers?.default?.url
717720
const addrDisplay = explorerUrl
718721
? link(`${explorerUrl}/address/${address}`, address)
@@ -744,8 +747,8 @@ const account = Cli.create('account', {
744747
return c.error({ code: 'ACCOUNT_NOT_FOUND', message: 'No account found.', exitCode: 69 })
745748
}
746749
const acct = privateKeyToAccount(key as `0x${string}`)
747-
const rpcUrl = c.options.rpcUrl ?? (process.env.MPPX_RPC_URL || undefined)
748-
const chain = rpcUrl ? await resolveChain({ rpcUrl }) : tempoMainnet
750+
const rpcUrl = resolveRpcUrl(c.options.rpcUrl)
751+
const chain = await resolveChain({ rpcUrl })
749752
const explorerUrl = chain.blockExplorers?.default?.url
750753
const addrDisplay = explorerUrl
751754
? link(`${explorerUrl}/address/${acct.address}`, acct.address)

src/cli/plugins/tempo.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
link,
2525
pc,
2626
resolveChain,
27+
resolveRpcUrl,
2728
} from '../utils.js'
2829
import { createPlugin, type Plugin } from './plugin.js'
2930

@@ -67,7 +68,7 @@ export function tempo() {
6768
useTempoCliSign = true
6869
const tempoEntry = resolveTempoAccount(accountName)
6970
if (tempoEntry) {
70-
const rpcUrl = options.rpcUrl ?? process.env.RPC_URL
71+
const rpcUrl = resolveRpcUrl(options.rpcUrl)
7172
client = createClient({
7273
chain: await resolveChain({ rpcUrl }),
7374
transport: http(rpcUrl),
@@ -107,7 +108,7 @@ export function tempo() {
107108
} else account = privateKeyToAccount(privateKey as `0x${string}`)
108109

109110
if (!useTempoCliSign && account) {
110-
const rpcUrl = options.rpcUrl ?? process.env.RPC_URL
111+
const rpcUrl = resolveRpcUrl(options.rpcUrl)
111112
client = createClient({
112113
chain: await resolveChain({ rpcUrl }),
113114
transport: http(rpcUrl),

src/cli/utils.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { tempo as tempoMainnet, tempoModerato } from 'viem/chains'
2+
import { afterEach, describe, expect, test, vi } from 'vp/test'
3+
4+
import { resolveChain, resolveRpcUrl } from './utils.js'
5+
6+
describe('resolveRpcUrl', () => {
7+
afterEach(() => {
8+
delete process.env.MPPX_RPC_URL
9+
delete process.env.RPC_URL
10+
})
11+
12+
test('returns explicit value when provided', () => {
13+
process.env.MPPX_RPC_URL = 'https://env.example.com'
14+
expect(resolveRpcUrl('https://explicit.example.com')).toBe('https://explicit.example.com')
15+
})
16+
17+
test('falls back to MPPX_RPC_URL env var', () => {
18+
process.env.MPPX_RPC_URL = 'https://mppx.example.com'
19+
process.env.RPC_URL = 'https://rpc.example.com'
20+
expect(resolveRpcUrl()).toBe('https://mppx.example.com')
21+
})
22+
23+
test('falls back to RPC_URL env var when MPPX_RPC_URL is not set', () => {
24+
process.env.RPC_URL = 'https://rpc.example.com'
25+
expect(resolveRpcUrl()).toBe('https://rpc.example.com')
26+
})
27+
28+
test('returns undefined when nothing is set', () => {
29+
expect(resolveRpcUrl()).toBeUndefined()
30+
})
31+
32+
test('trims whitespace from env vars', () => {
33+
process.env.MPPX_RPC_URL = ' https://mppx.example.com '
34+
expect(resolveRpcUrl()).toBe('https://mppx.example.com')
35+
})
36+
37+
test('skips empty MPPX_RPC_URL and falls back to RPC_URL', () => {
38+
process.env.MPPX_RPC_URL = ' '
39+
process.env.RPC_URL = 'https://rpc.example.com'
40+
expect(resolveRpcUrl()).toBe('https://rpc.example.com')
41+
})
42+
})
43+
44+
describe('resolveChain', () => {
45+
afterEach(() => {
46+
delete process.env.MPPX_RPC_URL
47+
delete process.env.RPC_URL
48+
})
49+
50+
test('defaults to tempo mainnet when no rpcUrl is provided', async () => {
51+
const chain = await resolveChain()
52+
expect(chain.id).toBe(tempoMainnet.id)
53+
})
54+
55+
test('defaults to tempo mainnet when rpcUrl is undefined', async () => {
56+
const chain = await resolveChain({ rpcUrl: undefined })
57+
expect(chain.id).toBe(tempoMainnet.id)
58+
})
59+
60+
test('does not default to testnet', async () => {
61+
const chain = await resolveChain()
62+
expect(chain.id).not.toBe(tempoModerato.id)
63+
})
64+
})

src/cli/utils.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,17 +221,23 @@ export function fmtBalance(
221221
return `${dec ? `${formatted}.${dec}` : formatted} ${sym}`
222222
}
223223

224+
/** Resolve RPC URL from explicit option, then MPPX_RPC_URL, then RPC_URL env vars. */
225+
export function resolveRpcUrl(explicit?: string | undefined): string | undefined {
226+
return explicit ?? (process.env.MPPX_RPC_URL?.trim() || process.env.RPC_URL?.trim() || undefined)
227+
}
228+
224229
export async function resolveChain(opts: { rpcUrl?: string | undefined } = {}): Promise<Chain> {
225-
if (!opts.rpcUrl) return tempoModerato
230+
const rpcUrl = resolveRpcUrl(opts.rpcUrl)
231+
if (!rpcUrl) return tempoMainnet
226232
const { getChainId } = await import('viem/actions')
227-
const chainId = await getChainId(createClient({ transport: http(opts.rpcUrl) }))
233+
const chainId = await getChainId(createClient({ transport: http(rpcUrl) }))
228234
const allExports = Object.values(await import('viem/chains')) as unknown[]
229235
const candidates = allExports.filter(
230236
(c): c is Chain =>
231237
typeof c === 'object' && c !== null && 'id' in c && (c as Chain).id === chainId,
232238
)
233239
const found = candidates.find((c) => 'serializers' in c && c.serializers) ?? candidates[0]
234-
if (!found) throw new Error(`Unknown chain ID ${chainId} from RPC ${opts.rpcUrl}`)
240+
if (!found) throw new Error(`Unknown chain ID ${chainId} from RPC ${rpcUrl}`)
235241
return found
236242
}
237243

@@ -306,7 +312,7 @@ export async function fetchBalanceLines(
306312

307313
const mainnetClient = createClient({
308314
chain: tempoMainnet,
309-
transport: http(process.env.MPPX_RPC_URL || undefined),
315+
transport: http(resolveRpcUrl()),
310316
})
311317
const mainnetExplorerUrl = tempoMainnet.blockExplorers?.default?.url
312318
const mainnetResults = await Promise.all(

0 commit comments

Comments
 (0)