Skip to content

Commit

Permalink
Merge pull request #111 from DefiLlama/dynamic-env-rpc
Browse files Browse the repository at this point in the history
Pull rpc info from env
  • Loading branch information
g1nt0ki committed Jul 10, 2023
2 parents 367cb24 + ead46d3 commit 183f76a
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 25 deletions.
1 change: 1 addition & 0 deletions src/ChainApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ test("ChainApi - getChainId", async () => {
expect((new ChainApi({ chain: 'arbitrum' })).getChainId()).toEqual(42161);
expect((new ChainApi({ chain: 'optimism' })).getChainId()).toEqual(10);
expect((new ChainApi({ chain: 'solana' })).getChainId()).toEqual(undefined);
expect((new ChainApi({ chain: 'solana' })).provider).toEqual(null);
})

test("ChainApi - call", async () => {
Expand Down
44 changes: 44 additions & 0 deletions src/general.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { getBalance } from "./eth/index";
import { getProvider, setProvider } from "./general";
import { ethers, } from "ethers"

const dummyRPC = 'https://eth.llamarpc.com'

jest.setTimeout(10000);
test("RPC nodes from multiple chains support archive queries", async () => {
Expand All @@ -16,3 +20,43 @@ test("RPC nodes from multiple chains support archive queries", async () => {
}
}
});

test("getProvider default behavior", async () => {
const ethProvider = getProvider("ethereum")
const ethProvider2 = getProvider("ethereum")

expect(ethProvider).toEqual(ethProvider2);
});

test("getProvider - use rpc from env", async () => {
const ethProvider = getProvider("ethereum")
process.env.ETHEREUM_RPC = dummyRPC
const ethProvider2 = getProvider("ethereum")
const ethProvider3 = getProvider("ethereum")

expect(ethProvider).not.toBe(ethProvider2)
expect(ethProvider2).toBe(ethProvider3)
expect((ethProvider3 as any).providerConfigs[0].provider.connection.url).toBe(dummyRPC)
});

test("getProvider - invalid chain", async () => {
const llamaP = getProvider("llama-chain")
expect(llamaP).toBeNull()
});

test("getProvider - chain throws error", async () => {
process.env.SOLANA_RPC = 'https://api.mainnet-beta.solana.com'
const solP = getProvider("solana")
expect(solP).toBeNull()
});

test("getProvider - custom chain", async () => {
const clvRPC = "https://api-para.clover.finance"
const clvObject = new ethers.providers.StaticJsonRpcProvider(clvRPC, { name: "clv-llama-test", chainId: 1024, })
setProvider("clv-llama-test",clvObject)
const clvP = getProvider("clv-llama-test")
const clvPMissing = getProvider("clv-llama-test-not")
expect(clvP).not.toBeNull()
expect(clvPMissing).toBeNull()
expect((clvP as any).connection.url).toBe(clvRPC)
});
80 changes: 55 additions & 25 deletions src/general.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,75 @@
import { debugLog} from './util/debugLog'
import { ethers, BigNumber } from "ethers"
import providerList from './providers.json'

function createProvider(name: string, rpcString: string, chainId: number) {
const rpcList = rpcString.split(',')

function createProvider(name: string, defaultRpc: string, chainId: number) {
if (process.env.HISTORICAL) {
if (chainId === 1) {
console.log("RPC providers set to historical, only the first RPC provider will be used")
}
return new ethers.providers.StaticJsonRpcProvider(
(process.env[name.toUpperCase() + "_RPC"] ?? defaultRpc)?.split(',')[0],
rpcList[0],
{
name,
chainId,
}
)
} else {
return new ethers.providers.FallbackProvider(
(process.env[name.toUpperCase() + "_RPC"] ?? defaultRpc).split(',').map((url, i) => ({
provider: new ethers.providers.StaticJsonRpcProvider(
url,
{
name,
chainId,
}
),
priority: i
})),
1
)
try {
return new ethers.providers.FallbackProvider(
rpcList.map((url, i) => ({
provider: new ethers.providers.StaticJsonRpcProvider(
url,
{
name,
chainId,
}
),
priority: i
})),
1
)
} catch (e) {
debugLog(`Error creating provider for ${name} with RPCs: ${rpcList.join(', ')}`)
// we dont throw errors for chains not present in providers.json, these can be non-evm chains like solana
if ((providerList as any)[name])
throw e
return null
}
}
}

type Provider = ethers.providers.StaticJsonRpcProvider | ethers.providers.FallbackProvider

type ProviderWrapped = {
rpcList: string;
_provider: Provider;
}

export const providers = {} as {
[chain: string]: ethers.providers.BaseProvider;
[chain: string]: ProviderWrapped;
};

Object.entries(providerList).forEach(([name, value]) => {
const { rpc, chainId } = value as any
providers[name] = createProvider(name, rpc.join(','), chainId)
})

export type Chain = string
export function getProvider(chain: Chain = "ethereum"): ethers.providers.BaseProvider {
return providers[chain];
export function getProvider(chain: Chain = "ethereum"): Provider {
// use RPC from env variable if set else use RPC from providers.json
let rpcList: (string | undefined) = process.env[chain.toUpperCase() + "_RPC"]
if (!rpcList) rpcList = (providerList as any)[chain]?.rpc.join(',')
if (!rpcList) {
// in case provider was set using `setProvider` function
if (providers[chain]) return providers[chain]._provider
// @ts-ignore (throwing error here would alter function behavior and have side effects)
return null
}
if (!providers[chain] || providers[chain].rpcList !== rpcList) {
providers[chain] = {
rpcList,
_provider: (createProvider(chain, rpcList, (providerList as any)[chain]?.chainId) as Provider)
}
}
return providers[chain]._provider
}

export const TEN = BigNumber.from(10);
Expand All @@ -59,7 +86,10 @@ export const ETHER_ADDRESS = "0x0000000000000000000000000000000000000000";

export function setProvider(
chain: Chain,
provider: ethers.providers.BaseProvider
provider: Provider
) {
providers[chain] = provider;
providers[chain] = {
rpcList: "",
_provider: provider
}
}

0 comments on commit 183f76a

Please sign in to comment.