Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/eco.chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,14 @@ export class EcoChains {
getRpcUrlsForChain(chainID: number, opts: RpcOptions = {}): string[] {
const {
isWebSocketEnabled = true,
preferredProviders = [],
preferredProviders = ['alchemy', 'infura'],
useCustomOnly = false,
} = opts
const rpcChain = this.getChain(chainID)

let rpcUrls: string[] = []

// If preferredProviders is specified, use provider priority
// Use provider priority (now defaults to ['alchemy', 'infura'])
if (preferredProviders.length > 0) {
for (const provider of preferredProviders) {
const providerRpcs = rpcChain.rpcUrls[provider]
Expand All @@ -194,7 +194,7 @@ export class EcoChains {
}
}

// If useCustomOnly is false, fallback to default after preferred providers
// Always add default provider as fallback (unless useCustomOnly is true)
if (!useCustomOnly) {
const def = rpcChain.rpcUrls.default
if (def) {
Expand Down
128 changes: 128 additions & 0 deletions src/tests/eco.chains.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,134 @@ describe('Eco Chains', () => {
})
})

it('should return alchemy URLs when alchemyKey is provided for getRpcUrlsForChain', () => {
// Import the actual ethereum chain definition
const { ethereum } = require('../definitions/ethereum')

// Mock extractChain to return the actual ethereum chain
mockViemExtract.mockReturnValue(cloneDeep(ethereum))

const ecoChains = new EcoChains({ alchemyKey: 'test_alchemy_key_123' })
const urls = ecoChains.getRpcUrlsForChain(1) // Ethereum mainnet chain ID

// Should contain the processed alchemy URLs
expect(urls).toContain('https://eth-mainnet.g.alchemy.com/v2/test_alchemy_key_123')
expect(urls).toContain('wss://eth-mainnet.g.alchemy.com/v2/test_alchemy_key_123')
})

describe('default provider priority behavior', () => {
it('should return alchemy, infura, and default URLs in correct order when all keys provided', () => {
const rpcs = getRpcUrls({
default: defaults,
alchemy,
infura,
})
mockViemExtract.mockReturnValue(cloneDeep(rpcs))
const obj = new EcoChains(config)

const urls = obj.getRpcUrlsForChain(1)

const expectedOrder = [
`wss://opt-mainnet.g.alchemy.com/v2/${config.alchemyKey}`,
`https://base-mainnet.g.alchemy.com/v2/${config.alchemyKey}`,
`wss://base-mainnet.g.infura.io/v3/${config.infuraKey}`,
`https://base-mainnet.g.infura.io/v3/${config.infuraKey}`,
'wss://etherscan.io/api',
'https://etherscan.io/api',
]
expect(urls).toEqual(expectedOrder)
})

it('should skip infura when infuraKey not provided but include alchemy and default', () => {
const rpcs = getRpcUrls({
default: defaults,
alchemy,
infura,
})
mockViemExtract.mockReturnValue(cloneDeep(rpcs))
const obj = new EcoChains({ alchemyKey: config.alchemyKey })

const urls = obj.getRpcUrlsForChain(1)

expect(urls).toEqual([
`wss://opt-mainnet.g.alchemy.com/v2/${config.alchemyKey}`,
`https://base-mainnet.g.alchemy.com/v2/${config.alchemyKey}`,
'wss://etherscan.io/api',
'https://etherscan.io/api',
])
expect(urls).not.toContain('${INFURA_API_KEY}')
})

it('should skip alchemy when alchemyKey not provided but include infura and default', () => {
const rpcs = getRpcUrls({
default: defaults,
alchemy,
infura,
})
mockViemExtract.mockReturnValue(cloneDeep(rpcs))
const obj = new EcoChains({ infuraKey: config.infuraKey })

const urls = obj.getRpcUrlsForChain(1)

expect(urls).toEqual([
`wss://base-mainnet.g.infura.io/v3/${config.infuraKey}`,
`https://base-mainnet.g.infura.io/v3/${config.infuraKey}`,
'wss://etherscan.io/api',
'https://etherscan.io/api',
])
expect(urls).not.toContain('${ALCHEMY_API_KEY}')
})

it('should only return default URLs when no API keys provided', () => {
const rpcs = getRpcUrls({
default: defaults,
alchemy,
infura,
})
mockViemExtract.mockReturnValue(cloneDeep(rpcs))
const obj = new EcoChains({})

const urls = obj.getRpcUrlsForChain(1)

expect(urls).toEqual([
'wss://etherscan.io/api',
'https://etherscan.io/api',
])
})

it('should respect useCustomOnly flag with new default behavior', () => {
const rpcs = getRpcUrls({
default: defaults,
alchemy,
infura,
})
mockViemExtract.mockReturnValue(cloneDeep(rpcs))
const obj = new EcoChains(config)

const urls = obj.getRpcUrlsForChain(1, { useCustomOnly: true })

expect(urls).toEqual([
`wss://opt-mainnet.g.alchemy.com/v2/${config.alchemyKey}`,
`https://base-mainnet.g.alchemy.com/v2/${config.alchemyKey}`,
`wss://base-mainnet.g.infura.io/v3/${config.infuraKey}`,
`https://base-mainnet.g.infura.io/v3/${config.infuraKey}`,
])
expect(urls).not.toContain('https://etherscan.io/api')
})

it('should maintain backward compatibility with empty preferredProviders array', () => {
const rpcs = getRpcUrls({ default: defaults, alchemy })
mockViemExtract.mockReturnValue(cloneDeep(rpcs))
const obj = new EcoChains(config)

const urls = obj.getRpcUrlsForChain(1, { preferredProviders: [] })

// Should use old custom + default logic
expect(urls).toContain(`https://base-mainnet.g.alchemy.com/v2/${config.alchemyKey}`)
expect(urls).toContain('https://etherscan.io/api')
})
})

function getRpcUrls(args: any) {
return {
rpcUrls: {
Expand Down
Loading