-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a38e26a
commit 96e9486
Showing
7 changed files
with
207 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,124 @@ | ||
import { ethers } from 'ethers'; | ||
import { providers } from 'ethers'; | ||
|
||
let configuration = { | ||
type ProviderFactory = (network: string | undefined) => providers.Provider | string; | ||
|
||
let warned = false; | ||
/** | ||
* @param network the network to connect to | ||
* @param defaultFactory the defaultFactory to use as fallback if needed | ||
*/ | ||
type CurrentProviderFactory = ( | ||
network: string | undefined, | ||
defaultFactory: ProviderFactory, | ||
) => providers.Provider | string; | ||
|
||
/** | ||
* Default API_KEYS configuration, can be overriden using initPaymentDetectionApiKeys | ||
*/ | ||
let providersApiKeys: Record<string, string | (() => string)> = { | ||
// fallback to Ethers v4 default projectId | ||
infura: process.env.RN_INFURA_KEY || '7d0d81d0919f4f05b9ab6634be01ee73', | ||
infura: () => process.env.RN_INFURA_KEY || '7d0d81d0919f4f05b9ab6634be01ee73', | ||
}; | ||
|
||
export const initPaymentDetectionProvider = (config: Partial<typeof configuration>) => { | ||
configuration = { ...configuration, ...config }; | ||
/** | ||
* @param defaultProviderOptions Default Provider Options as specified in https://docs.ethers.io/v5/api/providers/#providers-getDefaultProvider */ | ||
export const initPaymentDetectionApiKeys = ( | ||
defaultProviderOptions?: typeof providersApiKeys, | ||
): void => { | ||
providersApiKeys = { ...providersApiKeys, ...defaultProviderOptions }; | ||
}; | ||
|
||
export const getDefaultProvider = (network?: string | ethers.providers.Network | undefined) => { | ||
if (network === 'private') { | ||
return new ethers.providers.JsonRpcProvider(); | ||
/** | ||
* Define default URLs for networks supported by Request payment detection but not by ethers' Infura Provider | ||
*/ | ||
const networkRpcs: Record<string, string> = { | ||
private: providers.JsonRpcProvider.defaultUrl(), | ||
matic: 'https://rpc-mainnet.matic.network/', | ||
}; | ||
|
||
/** | ||
* @see getDefaultProvider | ||
* @param network | ||
*/ | ||
const defaultProviderFactory: ProviderFactory = (network: string | undefined) => { | ||
if (!network) { | ||
network = 'homestead'; | ||
} | ||
if (configuration.infura) { | ||
return new ethers.providers.InfuraProvider(network, process.env.RN_INFURA_KEY); | ||
|
||
// Returns environment variable override | ||
const envVar = process?.env ? process.env[`RN_WEB3_RPC_URL_${network.toUpperCase()}`] : null; | ||
if (envVar) { | ||
return envVar; | ||
} | ||
|
||
return ethers.getDefaultProvider(network); | ||
// check default RPCs | ||
if (networkRpcs[network]) { | ||
return networkRpcs[network]; | ||
} | ||
|
||
// use infura, if supported | ||
try { | ||
// try getting the URL for the given network. Will throw if not supported. | ||
providers.InfuraProvider.getUrl(providers.getNetwork(network), {}); | ||
const apiKey = | ||
typeof providersApiKeys.infura === 'function' | ||
? providersApiKeys.infura() | ||
: providersApiKeys.infura; | ||
|
||
if (!apiKey && !warned) { | ||
console.warn(`No API Key specified for Infura, using ethers default API key. | ||
This is not recommended for Production environments. | ||
To override Infura's default api key, use RN_INFURA_KEY environment variable, or call | ||
initPaymentDetectionApiKeys({ infura: () => "myApiKey" }); | ||
`); | ||
warned = true; | ||
} | ||
return new providers.InfuraProvider(network, apiKey); | ||
} catch (e) { | ||
// suppress errors | ||
} | ||
|
||
if (!warned) { | ||
console.warn( | ||
`No provider is specified for network ${network}, using ethers default provider. | ||
This is not recommended for Production environments. | ||
Use setProviderFactory to override the default provider`, | ||
); | ||
warned = true; | ||
} | ||
// use getDefaultProvider to keep the original behaviour | ||
return providers.getDefaultProvider(network, providersApiKeys); | ||
}; | ||
|
||
/** | ||
* Defines the behaviour to obtain a Provider for a given Network. | ||
* May be overriden using setProviderFactory | ||
*/ | ||
let currentProviderFactory: CurrentProviderFactory = defaultProviderFactory; | ||
|
||
/** | ||
* Override the default providerFactory, which relies mainly on Infura. | ||
* @param providerFactory if not specify, will reset to the default factory | ||
*/ | ||
export const setProviderFactory = (providerFactory?: CurrentProviderFactory): void => { | ||
currentProviderFactory = providerFactory || defaultProviderFactory; | ||
}; | ||
|
||
/** | ||
* Returns a Web3 Provider for the given `network`. | ||
* | ||
* Configuration options: | ||
* - Specify `RN_WEB3_RPC_URL_[NETWORK]` environment variable to override the default behaviour | ||
* - Specify `RN_INFURA_KEY` to override the default Infura API KEY (recommended) | ||
* - Use `initPaymentDetectionApiKeys` to override Infura API KEY when `RN_INFURA_KEY` is not usable | ||
* - Use `setProviderFactory` for more complex configurations with multiple networks | ||
* | ||
* @param network the blockchain network. See https://chainid.network/chains.json `network` field for reference | ||
*/ | ||
export const getDefaultProvider = (network?: string): providers.Provider => { | ||
const provider = currentProviderFactory(network, defaultProviderFactory); | ||
if (typeof provider === 'string') { | ||
return new providers.JsonRpcProvider(provider); | ||
} | ||
return provider; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { providers } from 'ethers'; | ||
import { getDefaultProvider, initPaymentDetectionApiKeys, setProviderFactory } from '../src'; | ||
|
||
describe('getDefaultProvider', () => { | ||
afterEach(() => { | ||
// reset the provider factory | ||
setProviderFactory(); | ||
}); | ||
|
||
it('Defaults to Infura Mainnet', async () => { | ||
const provider = getDefaultProvider(); | ||
|
||
expect(provider).toBeInstanceOf(providers.InfuraProvider); | ||
await expect(provider.getNetwork()).resolves.toMatchObject({ chainId: 1 }); | ||
}); | ||
|
||
it('Can take a standard network', async () => { | ||
const provider = getDefaultProvider('rinkeby'); | ||
|
||
expect(provider).toBeInstanceOf(providers.InfuraProvider); | ||
await expect(provider.getNetwork()).resolves.toMatchObject({ chainId: 4 }); | ||
}); | ||
|
||
it('Can take a private network', async () => { | ||
const provider = getDefaultProvider('private') as providers.JsonRpcProvider; | ||
|
||
expect(provider).toBeInstanceOf(providers.JsonRpcProvider); | ||
expect(provider.connection.url).toBe('http://localhost:8545'); | ||
}); | ||
|
||
it('Can take a non-standard network', async () => { | ||
const provider = getDefaultProvider('matic'); | ||
|
||
expect(provider).toBeInstanceOf(providers.JsonRpcProvider); | ||
await expect(provider.getNetwork()).resolves.toMatchObject({ chainId: 137 }); | ||
}); | ||
|
||
it('Throws on non-supported network', () => { | ||
expect(() => getDefaultProvider('bitcoin')).toThrowError( | ||
'unsupported getDefaultProvider network', | ||
); | ||
}); | ||
|
||
it('Can override the RPC configuration for an existing network', async () => { | ||
expect(getDefaultProvider('matic')).toBeInstanceOf(providers.JsonRpcProvider); | ||
expect((getDefaultProvider('matic') as providers.JsonRpcProvider).connection.url).toBe( | ||
'https://rpc-mainnet.matic.network/', | ||
); | ||
setProviderFactory(() => 'http://matic.fake'); | ||
expect(getDefaultProvider('matic')).toBeInstanceOf(providers.JsonRpcProvider); | ||
expect((getDefaultProvider('matic') as providers.JsonRpcProvider).connection.url).toBe( | ||
'http://matic.fake', | ||
); | ||
}); | ||
|
||
it('Can override the RPC configuration for a new network', async () => { | ||
expect(() => getDefaultProvider('xdai')).toThrowError('unsupported getDefaultProvider network'); | ||
setProviderFactory((network, defaultFactory) => { | ||
if (network === 'xdai') { | ||
return 'http://xdaichain.fake'; | ||
} | ||
return defaultFactory(network); | ||
}); | ||
expect(getDefaultProvider('xdai')).toBeInstanceOf(providers.JsonRpcProvider); | ||
expect((getDefaultProvider('xdai') as providers.JsonRpcProvider).connection.url).toBe( | ||
'http://xdaichain.fake', | ||
); | ||
// still works for standard providers | ||
expect((getDefaultProvider('rinkeby') as providers.JsonRpcProvider).connection.url).toMatch( | ||
/https:\/\/rinkeby\.infura.*/, | ||
); | ||
}); | ||
|
||
it('Can override the api key for a standard provider', async () => { | ||
initPaymentDetectionApiKeys({ | ||
infura: 'foo-bar', | ||
}); | ||
|
||
const provider = getDefaultProvider() as providers.InfuraProvider; | ||
expect(provider.connection.url).toEqual('https://mainnet.infura.io/v3/foo-bar'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters