diff --git a/src/program.ts b/src/program.ts index 97e7d17..e6f6e90 100644 --- a/src/program.ts +++ b/src/program.ts @@ -73,9 +73,9 @@ import { Invoice, fetchData, fetchDataOptions, - networkConfig, getInstanceByAddress, - subdomains, + getSubdomains, + getConfig, Config, enabledChains, substring, @@ -92,7 +92,6 @@ const TOKEN_PRICE_ORACLE = '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8'; // Where cached events, trees, circuits, and key is saved const STATIC_DIR = process.env.CACHE_DIR || path.join(__dirname, '../static'); const EVENTS_DIR = path.join(STATIC_DIR, './events'); -const TREES_DIR = path.join(STATIC_DIR, './trees'); const MERKLE_WORKER_PATH = process.env.DISABLE_MERKLE_WORKER === 'true' ? undefined : path.join(STATIC_DIR, './merkleTreeWorker.js'); @@ -279,9 +278,11 @@ export async function getProgramRelayer({ }> { const { ethRpc, ethGraph, relayer, disableGraph } = options; - const netConfig = networkConfig[`netId${netId}`]; + const netConfig = getConfig(netId); - const ethConfig = networkConfig[`netId${RELAYER_NETWORK}`]; + const ethConfig = getConfig('1'); + + const subdomains = getSubdomains(); const { aggregatorContract, @@ -460,7 +461,7 @@ export function tornadoProgram() { .action(async (netId: string | number, currency: string, amount: string) => { currency = currency.toLowerCase(); - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const { routerContract, @@ -522,7 +523,7 @@ export function tornadoProgram() { currency = currency.toLowerCase(); const { rpc, accountKey } = options; - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const { multicallContract, @@ -667,7 +668,7 @@ export function tornadoProgram() { const { currency, amount, netId, commitment } = new Invoice(invoiceString); - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const { multicallContract, @@ -782,7 +783,7 @@ export function tornadoProgram() { const { netId, currency, amount, commitmentHex, nullifierHex, nullifier, secret } = deposit; - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const { tornadoSubgraph, @@ -1142,7 +1143,7 @@ export function tornadoProgram() { const deposit = await Deposit.parseNote(note); const { netId, currency, amount, commitmentHex, nullifierHex } = deposit; - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const { tornadoSubgraph, @@ -1275,7 +1276,7 @@ export function tornadoProgram() { const networks = netIdOpts ? [netIdOpts] : enabledChains; for (const netId of networks) { - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const { tornadoSubgraph, registrySubgraph, @@ -1508,7 +1509,7 @@ export function tornadoProgram() { const { options, fetchDataOptions } = await getProgramOptions(cmdOptions); const { rpc } = options; - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const { echoContract, @@ -1628,7 +1629,7 @@ export function tornadoProgram() { accountKey = options.accountKey; } - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const { routerContract, @@ -1707,7 +1708,7 @@ export function tornadoProgram() { const { options, fetchDataOptions } = await getProgramOptions(cmdOptions); const { rpc, token: tokenOpts } = options; - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const { currencyName, multicallContract } = config; @@ -1843,7 +1844,7 @@ export function tornadoProgram() { const { options, fetchDataOptions } = await getProgramOptions(cmdOptions); const { rpc, token: tokenOpts } = options; - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const { currencyName, multicallContract, tornContract, tokens } = config; @@ -1903,7 +1904,7 @@ export function tornadoProgram() { const netId = Number(deserializedTx.chainId); - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const provider = getProgramProvider(netId, rpc, config, { ...fetchDataOptions, @@ -1938,7 +1939,7 @@ export function tornadoProgram() { throw new Error('NetId for the transaction is invalid, this command only supports EIP-155 transactions'); } - const config = networkConfig[`netId${netId}`]; + const config = getConfig(netId); const provider = getProgramProvider(netId, rpc, config, { ...fetchDataOptions, diff --git a/src/services/networkConfig.ts b/src/services/networkConfig.ts index f2197d6..2849ba7 100644 --- a/src/services/networkConfig.ts +++ b/src/services/networkConfig.ts @@ -46,11 +46,7 @@ export type Config = { }; nativeCurrency: string; currencyName: string; - explorerUrl: { - tx: string; - address: string; - block: string; - }; + explorerUrl: string; merkleTreeHeight: number; emptyElement: string; networkName: string; @@ -90,24 +86,6 @@ export type networkConfig = { [key in string]: Config; }; -export const blockSyncInterval = 10000; -export const enabledChains = ['1', '10', '56', '100', '137', '42161', '43114', '11155111']; - -export function getInstanceByAddress({ netId, address }: { netId: number | string; address: string }) { - const { tokens } = networkConfig[`netId${netId}`]; - - for (const [currency, { instanceAddress }] of Object.entries(tokens)) { - for (const [amount, instance] of Object.entries(instanceAddress)) { - if (instance === address) { - return { - amount, - currency, - }; - } - } - } -} - const theGraph = { name: 'Hosted Graph', url: 'https://api.thegraph.com', @@ -117,7 +95,7 @@ const tornado = { url: 'https://tornadocash-rpc.com', }; -export const networkConfig: networkConfig = { +export const defaultConfig: networkConfig = { netId1: { rpcCallRetryAttempt: 15, gasPrices: { @@ -128,11 +106,7 @@ export const networkConfig: networkConfig = { }, nativeCurrency: 'eth', currencyName: 'ETH', - explorerUrl: { - tx: 'https://etherscan.io/tx/', - address: 'https://etherscan.io/address/', - block: 'https://etherscan.io/block/', - }, + explorerUrl: 'https://etherscan.io', merkleTreeHeight: 20, emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', networkName: 'Ethereum Mainnet', @@ -278,11 +252,7 @@ export const networkConfig: networkConfig = { }, nativeCurrency: 'bnb', currencyName: 'BNB', - explorerUrl: { - tx: 'https://bscscan.com/tx/', - address: 'https://bscscan.com/address/', - block: 'https://bscscan.com/block/', - }, + explorerUrl: 'https://bscscan.com', merkleTreeHeight: 20, emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', networkName: 'Binance Smart Chain', @@ -346,11 +316,7 @@ export const networkConfig: networkConfig = { }, nativeCurrency: 'matic', currencyName: 'MATIC', - explorerUrl: { - tx: 'https://polygonscan.com/tx/', - address: 'https://polygonscan.com/address/', - block: 'https://polygonscan.com/block/', - }, + explorerUrl: 'https://polygonscan.com', merkleTreeHeight: 20, emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', networkName: 'Polygon (Matic) Network', @@ -407,11 +373,7 @@ export const networkConfig: networkConfig = { }, nativeCurrency: 'eth', currencyName: 'ETH', - explorerUrl: { - tx: 'https://optimistic.etherscan.io/tx/', - address: 'https://optimistic.etherscan.io/address/', - block: 'https://optimistic.etherscan.io/block/', - }, + explorerUrl: 'https://optimistic.etherscan.io', merkleTreeHeight: 20, emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', networkName: 'Optimism', @@ -476,11 +438,7 @@ export const networkConfig: networkConfig = { }, nativeCurrency: 'eth', currencyName: 'ETH', - explorerUrl: { - tx: 'https://arbiscan.io/tx/', - address: 'https://arbiscan.io/address/', - block: 'https://arbiscan.io/block/', - }, + explorerUrl: 'https://arbiscan.io', merkleTreeHeight: 20, emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', networkName: 'Arbitrum One', @@ -544,11 +502,7 @@ export const networkConfig: networkConfig = { }, nativeCurrency: 'xdai', currencyName: 'xDAI', - explorerUrl: { - tx: 'https://blockscout.com/xdai/mainnet/tx/', - address: 'https://blockscout.com/xdai/mainnet/address/', - block: 'https://blockscout.com/xdai/mainnet/block/', - }, + explorerUrl: 'https://gnosisscan.io', merkleTreeHeight: 20, emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', networkName: 'Gnosis Chain', @@ -612,11 +566,7 @@ export const networkConfig: networkConfig = { }, nativeCurrency: 'avax', currencyName: 'AVAX', - explorerUrl: { - tx: 'https://snowtrace.io/tx/', - address: 'https://snowtrace.io/address/', - block: 'https://snowtrace.io/block/', - }, + explorerUrl: 'https://snowtrace.io', merkleTreeHeight: 20, emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', networkName: 'Avalanche Mainnet', @@ -670,11 +620,7 @@ export const networkConfig: networkConfig = { }, nativeCurrency: 'eth', currencyName: 'SepoliaETH', - explorerUrl: { - tx: 'https://sepolia.etherscan.io/tx/', - address: 'https://sepolia.etherscan.io/address/', - block: 'https://sepolia.etherscan.io/block/', - }, + explorerUrl: 'https://sepolia.etherscan.io', merkleTreeHeight: 20, emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292', networkName: 'Ethereum Sepolia', @@ -742,6 +688,77 @@ export const networkConfig: networkConfig = { }, }; -export const subdomains = enabledChains.map((chain) => networkConfig[`netId${chain}`].ensSubdomainKey); +export const enabledChains = ['1', '10', '56', '100', '137', '42161', '43114', '11155111']; -export default networkConfig; +/** + * Custom config object to extend default config + * + * Inspired by getUrlFunc from ethers.js + * https://github.com/ethers-io/ethers.js/blob/v6/src.ts/utils/fetch.ts#L59 + */ +export let customConfig: networkConfig = {}; + +/** + * Add or override existing network config object + * + * Could be also called on the UI hook so that the UI could allow people to use privacy pools that it hasn't deployed + */ +export function addNetwork(newConfig: networkConfig) { + enabledChains.push( + ...Object.keys(newConfig) + .map((netId) => netId.replace('netId', '')) + .filter((netId) => !enabledChains.includes(netId)), + ); + + customConfig = { + ...customConfig, + ...newConfig, + }; +} + +export function getNetworkConfig(): networkConfig { + // customConfig object + const allConfig = { + ...defaultConfig, + ...customConfig, + }; + + return enabledChains.reduce((acc, curr) => { + acc[`netId${curr}`] = allConfig[`netId${curr}`]; + return acc; + }, {} as networkConfig); +} + +export function getConfig(netId: string | number) { + const allConfig = getNetworkConfig(); + + const chainConfig = allConfig[`netId${netId}`]; + + if (!chainConfig) { + const errMsg = `No config found for ${netId}!`; + throw new Error(errMsg); + } + + return chainConfig; +} + +export function getInstanceByAddress({ netId, address }: { netId: number | string; address: string }) { + const { tokens } = getConfig(netId); + + for (const [currency, { instanceAddress }] of Object.entries(tokens)) { + for (const [amount, instance] of Object.entries(instanceAddress)) { + if (instance === address) { + return { + amount, + currency, + }; + } + } + } +} + +export function getSubdomains() { + const allConfig = getNetworkConfig(); + + return enabledChains.map((chain) => allConfig[`netId${chain}`].ensSubdomainKey); +}