diff --git a/gre/config.ts b/gre/config.ts index 14e4008ac..9899f6d13 100644 --- a/gre/config.ts +++ b/gre/config.ts @@ -7,7 +7,7 @@ import { HttpNetworkConfig } from 'hardhat/types/config' import { GraphRuntimeEnvironmentOptions } from './type-extensions' import { GREPluginError } from './helpers/error' -import GraphNetwork from './helpers/network' +import GraphNetwork, { counterpartName } from './helpers/network' import { createProvider } from 'hardhat/internal/core/providers/construction' import { EthersProviderWrapper } from '@nomiclabs/hardhat-ethers/internal/ethers-provider-wrapper' @@ -217,7 +217,7 @@ function getNetworkConfig( chainId: number, mainNetworkName: string, ): (NetworkConfig & { name: string }) | undefined { - let candidateNetworks = Object.keys(networks) + const candidateNetworks = Object.keys(networks) .map((n) => ({ ...networks[n], name: n })) .filter((n) => n.chainId === chainId) @@ -226,14 +226,26 @@ function getNetworkConfig( `Found multiple networks with chainId ${chainId}, trying to use main network name to desambiguate`, ) - candidateNetworks = candidateNetworks.filter((n) => n.name === mainNetworkName) + const filteredByMainNetworkName = candidateNetworks.filter((n) => n.name === mainNetworkName) - if (candidateNetworks.length === 1) { - return candidateNetworks[0] + if (filteredByMainNetworkName.length === 1) { + logDebug(`Found network with chainId ${chainId} and name ${mainNetworkName}`) + return filteredByMainNetworkName[0] } else { - throw new GREPluginError( - `Found multiple networks with chainID ${chainId}. This is not supported!`, + logWarn(`Could not desambiguate with main network name, trying secondary network name`) + const secondaryNetworkName = counterpartName(mainNetworkName) + const filteredBySecondaryNetworkName = candidateNetworks.filter( + (n) => n.name === secondaryNetworkName, ) + + if (filteredBySecondaryNetworkName.length === 1) { + logDebug(`Found network with chainId ${chainId} and name ${mainNetworkName}`) + return filteredBySecondaryNetworkName[0] + } else { + throw new GREPluginError( + `Could not desambiguate network with chainID ${chainId}. Use case not supported!`, + ) + } } } else if (candidateNetworks.length === 1) { return candidateNetworks[0] @@ -242,7 +254,7 @@ function getNetworkConfig( } } -function getNetworkName( +export function getNetworkName( networks: NetworksConfig, chainId: number, mainNetworkName: string, diff --git a/gre/helpers/network.ts b/gre/helpers/network.ts index 5fc2829ff..4530904b6 100644 --- a/gre/helpers/network.ts +++ b/gre/helpers/network.ts @@ -16,15 +16,32 @@ const chainMap = new MapWithGetKey([ [1337, 412346], // Localhost - Arbitrum Localhost ]) +// Hardhat network names as per our convention +const nameMap = new MapWithGetKey([ + ['mainnet', 'arbitrum-one'], // Ethereum Mainnet - Arbitrum One + ['rinkeby', 'arbitrum-rinkeby'], // Ethereum Rinkeby - Arbitrum Rinkeby + ['goerli', 'arbitrum-goerli'], // Ethereum Goerli - Arbitrum Goerli + ['localnitrol1', 'localnitrol2'], // Arbitrum testnode L1 - Arbitrum testnode L2 +]) + export const l1Chains = Array.from(chainMap.keys()) export const l2Chains = Array.from(chainMap.values()) export const chains = [...l1Chains, ...l2Chains] +export const l1ChainNames = Array.from(nameMap.keys()) +export const l2ChainNames = Array.from(nameMap.values()) +export const chainNames = [...l1ChainNames, ...l2ChainNames] + export const isL1 = (chainId: number): boolean => l1Chains.includes(chainId) export const isL2 = (chainId: number): boolean => l2Chains.includes(chainId) export const isSupported = (chainId: number | undefined): boolean => chainId !== undefined && chains.includes(chainId) +export const isL1Name = (name: string): boolean => l1ChainNames.includes(name) +export const isL2Name = (name: string): boolean => l2ChainNames.includes(name) +export const isSupportedName = (name: string | undefined): boolean => + name !== undefined && chainNames.includes(name) + export const l1ToL2 = (chainId: number): number | undefined => chainMap.get(chainId) export const l2ToL1 = (chainId: number): number | undefined => chainMap.getKey(chainId) export const counterpart = (chainId: number): number | undefined => { @@ -32,6 +49,13 @@ export const counterpart = (chainId: number): number | undefined => { return isL1(chainId) ? l1ToL2(chainId) : l2ToL1(chainId) } +export const l1ToL2Name = (name: string): string | undefined => nameMap.get(name) +export const l2ToL1Name = (name: string): string | undefined => nameMap.getKey(name) +export const counterpartName = (name: string): string | undefined => { + if (!isSupportedName(name)) return + return isL1Name(name) ? l1ToL2Name(name) : l2ToL1Name(name) +} + export default { l1Chains, l2Chains, diff --git a/gre/test/config.test.ts b/gre/test/config.test.ts index d206220e6..de6287e2e 100644 --- a/gre/test/config.test.ts +++ b/gre/test/config.test.ts @@ -1,7 +1,13 @@ import { expect } from 'chai' import { useEnvironment } from './helpers' -import { getAddressBookPath, getChains, getGraphConfigPaths, getProviders } from '../config' +import { + getAddressBookPath, + getChains, + getGraphConfigPaths, + getNetworkName, + getProviders, +} from '../config' import path from 'path' describe('GRE init functions', function () { @@ -104,6 +110,36 @@ describe('GRE init functions', function () { }) }) + describe('getProviders with graph-config-desambiguate project', function () { + useEnvironment('graph-config-desambiguate', 'localnitrol1') + + it('should use main network name to desambiguate if multiple chains are defined with same chainId', async function () { + const { l1Provider, l2Provider } = getProviders(this.hre, 1337, 412346, true) + expect(l1Provider).to.be.an('object') + expect(l2Provider).to.be.an('object') + + const l1NetworkName = getNetworkName(this.hre.config.networks, 1337, 'localnitrol1') + const l2NetworkName = getNetworkName(this.hre.config.networks, 412346, 'localnitrol1') + expect(l1NetworkName).to.equal('localnitrol1') + expect(l2NetworkName).to.equal('localnitrol2') + }) + }) + + describe('getProviders with graph-config-desambiguate project', function () { + useEnvironment('graph-config-desambiguate', 'localnitrol2') + + it('should use secondary network name to desambiguate if multiple chains are defined with same chainId', async function () { + const { l1Provider, l2Provider } = getProviders(this.hre, 1337, 412346, true) + expect(l1Provider).to.be.an('object') + expect(l2Provider).to.be.an('object') + + const l1NetworkName = getNetworkName(this.hre.config.networks, 1337, 'localnitrol2') + const l2NetworkName = getNetworkName(this.hre.config.networks, 412346, 'localnitrol2') + expect(l1NetworkName).to.equal('localnitrol1') + expect(l2NetworkName).to.equal('localnitrol2') + }) + }) + describe('getGraphConfigPaths with graph-config-full project', function () { useEnvironment('graph-config-full') diff --git a/gre/test/fixture-projects/graph-config-desambiguate/hardhat.config.ts b/gre/test/fixture-projects/graph-config-desambiguate/hardhat.config.ts new file mode 100644 index 000000000..485ed8665 --- /dev/null +++ b/gre/test/fixture-projects/graph-config-desambiguate/hardhat.config.ts @@ -0,0 +1,59 @@ +import '../../../gre' + +module.exports = { + paths: { + graph: '../../files', + }, + solidity: '0.8.9', + defaultNetwork: 'hardhat', + networks: { + hardhat: { + chainId: 1337, + }, + localhost: { + chainId: 1337, + url: `http://localhost:8545`, + }, + localnitrol1: { + chainId: 1337, + url: `http://localhost:8545`, + }, + localnitrol2: { + chainId: 412346, + url: `http://localhost:8547`, + }, + mainnet: { + chainId: 1, + graphConfig: 'config/graph.mainnet.yml', + url: `https://mainnet.infura.io/v3/123456`, + }, + 'arbitrum-one': { + chainId: 42161, + url: 'https://arb1.arbitrum.io/rpc', + graphConfig: 'config/graph.arbitrum-goerli.yml', + }, + goerli: { + chainId: 5, + url: `https://goerli.infura.io/v3/123456`, + graphConfig: 'config/graph.goerli.yml', + }, + 'arbitrum-goerli': { + chainId: 421613, + url: 'https://goerli-rollup.arbitrum.io/rpc', + graphConfig: 'config/graph.arbitrum-goerli.yml', + }, + rinkeby: { + chainId: 4, + url: `https://goerli.infura.io/v3/123456`, + }, + 'arbitrum-rinkeby': { + chainId: 421611, + url: `https://goerli.infura.io/v3/123456`, + }, + }, + graph: { + addressBook: 'addresses-hre.json', + l1GraphConfig: 'config/graph.hre.yml', + l2GraphConfig: 'config/graph.arbitrum-hre.yml', + }, +} diff --git a/gre/test/helpers.ts b/gre/test/helpers.ts index f0875a002..81c97cd9b 100644 --- a/gre/test/helpers.ts +++ b/gre/test/helpers.ts @@ -20,5 +20,6 @@ export function useEnvironment(fixtureProjectName: string, network?: string): vo afterEach('Resetting hardhat', function () { resetHardhatContext() + delete process.env.HARDHAT_NETWORK }) }