-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update Hardhat config to remove the need for boilerplate code (#44)
* Clean up hardhat config generation * Cleaning up * Use process.env.MNEMONIC if it exists for networks config * Ensure hardhat function doesn't throw in non-Node environment * PR feedback * Rename exposed API * Update README * Final review
- Loading branch information
Showing
6 changed files
with
153 additions
and
78 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 |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { CHAINS } from './generated/chains'; | ||
import { toUpperSnakeCase } from './utils/strings'; | ||
import { Chain, HardhatEtherscanConfig, HardhatNetworksConfig } from './types'; | ||
|
||
export function getEnvVariableNames(): string[] { | ||
const hardhatApiKeyEnvNames = CHAINS.filter((chain) => chain.explorer?.api?.key?.required).map((chain) => | ||
etherscanApiKeyName(chain) | ||
); | ||
|
||
return ['MNEMONIC', ...hardhatApiKeyEnvNames]; | ||
} | ||
|
||
export function etherscanApiKeyName(chain: Chain): string { | ||
return `ETHERSCAN_API_KEY_${toUpperSnakeCase(chain.alias)}`; | ||
} | ||
|
||
// https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#multiple-api-keys-and-alternative-block-explorers | ||
export function etherscan(): HardhatEtherscanConfig { | ||
if (typeof window !== 'undefined') { | ||
throw new Error('Cannot be run outside of a Node.js environment'); | ||
} | ||
|
||
return CHAINS.reduce( | ||
(etherscan, chain) => { | ||
if (!chain.explorer || !chain.explorer.api) { | ||
return etherscan; | ||
} | ||
|
||
const apiKey = chain.explorer.api.key; | ||
|
||
const apiKeyEnvName = etherscanApiKeyName(chain); | ||
const apiKeyValue = apiKey.required ? process.env[apiKeyEnvName] || 'NOT_FOUND' : 'DUMMY_VALUE'; | ||
|
||
if (apiKey.hardhatEtherscanAlias) { | ||
etherscan.apiKey[apiKey.hardhatEtherscanAlias] = apiKeyValue; | ||
return etherscan; | ||
} | ||
|
||
etherscan.customChains.push({ | ||
network: chain.alias, | ||
chainId: Number(chain.id), | ||
urls: { | ||
apiURL: chain.explorer.api.url, | ||
browserURL: chain.explorer.browserUrl, | ||
}, | ||
}); | ||
|
||
etherscan.apiKey[chain.alias] = apiKeyValue; | ||
|
||
return etherscan; | ||
}, | ||
{ apiKey: {}, customChains: [] } as HardhatEtherscanConfig | ||
); | ||
} | ||
|
||
export function networks(): HardhatNetworksConfig { | ||
if (typeof window !== 'undefined') { | ||
throw new Error('Cannot be called outside of a Node.js environment'); | ||
} | ||
|
||
return CHAINS.reduce((networks, chain) => { | ||
networks[chain.alias] = { | ||
accounts: { mnemonic: process.env.MNEMONIC || '' }, | ||
chainId: Number(chain.id), | ||
url: chain.providerUrl, | ||
}; | ||
return networks; | ||
}, {} as HardhatNetworksConfig); | ||
} | ||
|
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,56 +1,5 @@ | ||
import { CHAINS } from './generated/chains'; | ||
import { HardhatConfigNetworks, HardhatEtherscanNetworks } from './types'; | ||
|
||
export * from './types'; | ||
|
||
// NOTE: the following file is generated with the generate-chains.ts script | ||
export { CHAINS } from './generated/chains'; | ||
|
||
export function hardhatConfigNetworks(): HardhatConfigNetworks { | ||
return CHAINS.reduce((networks, chain) => { | ||
networks[chain.alias] = { | ||
accounts: { mnemonic: '' }, | ||
chainId: Number(chain.id), | ||
url: chain.providerUrl, | ||
}; | ||
return networks; | ||
}, {} as HardhatConfigNetworks); | ||
} | ||
|
||
export function hardhatEtherscan(): HardhatEtherscanNetworks { | ||
return CHAINS.reduce((etherscan, chain) => { | ||
if (!chain.explorer || !chain.explorer.api) { | ||
return etherscan; | ||
} | ||
|
||
const apiKey = chain.explorer.api.key; | ||
const explorer = chain.explorer; | ||
const apiKeyValue = apiKey.required ? chain.alias : "DUMMY_VALUE"; | ||
|
||
if (apiKey.hardhatEtherscanAlias) { | ||
etherscan.apiKey[apiKey.hardhatEtherscanAlias] = apiKeyValue; | ||
return etherscan; | ||
} | ||
|
||
etherscan.customChains.push({ | ||
network: chain.alias, | ||
chainId: Number(chain.id), | ||
urls: { | ||
apiURL: explorer.api!.url, | ||
browserURL: explorer.browserUrl, | ||
}, | ||
}); | ||
etherscan.apiKey[chain.alias] = apiKeyValue; | ||
|
||
return etherscan; | ||
}, { apiKey: {}, customChains: [] } as HardhatEtherscanNetworks); | ||
} | ||
|
||
export function getEnvVariables(): string[] { | ||
const keys = CHAINS | ||
.filter((chain) => chain.explorer?.api?.key?.required) | ||
.map((chain) => `ETHERSCAN_API_KEY_${chain.alias}`); | ||
|
||
return ['MNEMONIC', ...keys]; | ||
} | ||
|
||
export * as hardhatConfig from './hardhat-config'; | ||
export * from './types'; |
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 |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { describe, test } from 'node:test'; | ||
import assert from 'node:assert/strict'; | ||
import { toUpperSnakeCase } from './strings'; | ||
|
||
describe('toUpperSnakeCase', () => { | ||
test('converts simple words', () => { | ||
const result = toUpperSnakeCase('hello world'); | ||
assert.equal(result, 'HELLO_WORLD'); | ||
}); | ||
|
||
test('keeps numbers in the string', () => { | ||
const result = toUpperSnakeCase('hello world 4'); | ||
assert.equal(result, 'HELLO_WORLD_4'); | ||
}); | ||
|
||
test('trims leading and trailing whtestespaces', () => { | ||
const result = toUpperSnakeCase(' hello world '); | ||
assert.equal(result, 'HELLO_WORLD'); | ||
}); | ||
|
||
test('converts special characters to underscores', () => { | ||
const result = toUpperSnakeCase('hello, world!'); | ||
assert.equal(result, 'HELLO_WORLD'); | ||
}); | ||
|
||
test('converts multiple spaces to single underscores', () => { | ||
const result = toUpperSnakeCase('hello world'); | ||
assert.equal(result, 'HELLO_WORLD'); | ||
}); | ||
|
||
test('returns an empty string when given an empty string', () => { | ||
const result = toUpperSnakeCase(''); | ||
assert.equal(result, ''); | ||
}); | ||
|
||
test('converts mixed case strings', () => { | ||
const result = toUpperSnakeCase('Hello World'); | ||
assert.equal(result, 'HELLO_WORLD'); | ||
}); | ||
}); |
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,9 @@ | ||
export function toUpperSnakeCase(input: string): string { | ||
return input | ||
.trim() | ||
.replace(/\s+/g, ' ') // replace multiple spaces with a single space | ||
.replace(/[^a-zA-Z0-9\s]+/g, '') // remove all non-alphanumeric characters | ||
.split(' ') | ||
.join('_') | ||
.toUpperCase(); | ||
} |