diff --git a/.changeset/odd-ligers-search.md b/.changeset/odd-ligers-search.md new file mode 100644 index 0000000000..6b1ab1429a --- /dev/null +++ b/.changeset/odd-ligers-search.md @@ -0,0 +1,5 @@ +--- +"@evmts/config": minor +--- + +Added autodetection of solc version. solcVersion is no longer required diff --git a/bundlers/config/src/Config.ts b/bundlers/config/src/Config.ts index 48da837a1b..22ea8e638a 100644 --- a/bundlers/config/src/Config.ts +++ b/bundlers/config/src/Config.ts @@ -1,3 +1,4 @@ +import { getDefaultSolcVersion } from './getDefaultSolcVersion' import { expandedString } from './zodUtils' import { isAddress } from 'viem' import { z } from 'zod' @@ -188,9 +189,12 @@ export type ResolvedConfig = { localContracts: Required externalContracts: Required } + export const defaultConfig: ResolvedConfig = { compiler: { - solcVersion: '0.8.20', + get solcVersion() { + return getDefaultSolcVersion() + }, foundryProject: false, remappings: {}, libs: [], diff --git a/bundlers/config/src/defineConfig.spec.ts b/bundlers/config/src/defineConfig.spec.ts index a334ecb456..567f090ec7 100644 --- a/bundlers/config/src/defineConfig.spec.ts +++ b/bundlers/config/src/defineConfig.spec.ts @@ -68,6 +68,36 @@ describe(defineConfig.name, () => { }) }) + it('should default forge command to forge', () => { + const forgeCommandOutput = JSON.stringify({ + solc_version: '0.8.4', + remappings: [], + libs: ['lib1', 'lib2'], + }) + mockExecSync.mockReturnValueOnce(Buffer.from(forgeCommandOutput)) + + const configFactory = () => + ({ + compiler: { + foundryProject: true, + }, + }) as EvmtsConfig + const config = defineConfig(configFactory) + const resolvedConfig = config.configFn('./') + + expect(mockExecSync).toHaveBeenCalledWith('forge config --json') + expect(resolvedConfig).toEqual({ + compiler: { + solcVersion: '0.8.4', + remappings: defaultConfig.compiler.remappings, + foundryProject: true, + libs: ['lib1', 'lib2'], + }, + localContracts: defaultConfig.localContracts, + externalContracts: defaultConfig.externalContracts, + }) + }) + it('should throw error when forge command fails', () => { mockExecSync.mockImplementationOnce(() => { throw new Error() diff --git a/bundlers/config/src/getDefaultSolcVersion.spec.ts b/bundlers/config/src/getDefaultSolcVersion.spec.ts new file mode 100644 index 0000000000..62d8444103 --- /dev/null +++ b/bundlers/config/src/getDefaultSolcVersion.spec.ts @@ -0,0 +1,43 @@ +import { getDefaultSolcVersion } from './getDefaultSolcVersion.js' +import { createRequire } from 'module' +import { + type MockedFunction, + beforeEach, + describe, + expect, + it, + vi, +} from 'vitest' + +let version: string | undefined = '0.8.9' +vi.mock('module', () => ({ + createRequire: vi.fn(), +})) + +const mockCreateRequire = createRequire as MockedFunction +const mockRequire = vi.fn() +const consoleErrorSpy = vi.fn() + +beforeEach(() => { + vi.resetAllMocks() + mockRequire.mockReturnValue({ version }) + mockCreateRequire.mockReturnValue(mockRequire as any) + vi.stubGlobal('console', { + error: consoleErrorSpy, + }) +}) + +describe('getDefaultSolcVersion', () => { + it('should return solc version if available', async () => { + expect(getDefaultSolcVersion()).toBe(version) + }) + + it('should log error and return undefined if version is not available', async () => { + version = undefined + mockRequire.mockReturnValue({ version }) + expect(getDefaultSolcVersion()).toBe(undefined) + expect(consoleErrorSpy).toBeCalledWith( + 'Failed to get solc version! Please install it or specify a version in your config', + ) + }) +}) diff --git a/bundlers/config/src/getDefaultSolcVersion.ts b/bundlers/config/src/getDefaultSolcVersion.ts new file mode 100644 index 0000000000..6fdcb45cbe --- /dev/null +++ b/bundlers/config/src/getDefaultSolcVersion.ts @@ -0,0 +1,13 @@ +import { createRequire } from 'module' + +export const getDefaultSolcVersion = () => { + const moduleRequire = createRequire(import.meta.url ?? __dirname) + const solc = moduleRequire('solc') + const version = solc?.version + if (!version) { + console.error( + 'Failed to get solc version! Please install it or specify a version in your config', + ) + } + return solc?.version +} diff --git a/bundlers/config/src/loadConfig.spec.ts b/bundlers/config/src/loadConfig.spec.ts index 402f646b2b..44e7d907cf 100644 --- a/bundlers/config/src/loadConfig.spec.ts +++ b/bundlers/config/src/loadConfig.spec.ts @@ -1,7 +1,15 @@ import { type EvmtsConfig, defaultConfig, loadConfig } from '.' import * as cp from 'child_process' import * as fs from 'fs' -import { beforeEach, describe, expect, it, vi } from 'vitest' +import { createRequire } from 'module' +import { + type MockedFunction, + beforeEach, + describe, + expect, + it, + vi, +} from 'vitest' const mockTsConfig = () => { return JSON.stringify( @@ -32,6 +40,9 @@ const mockTsConfig = () => { ) } +vi.mock('module', () => ({ + createRequire: vi.fn(), +})) vi.mock('fs', () => ({ readFileSync: vi.fn(), existsSync: vi.fn(), @@ -44,6 +55,12 @@ vi.mock('child_process', () => ({ describe(loadConfig.name, () => { beforeEach(() => { vi.resetAllMocks() + const mockCreateRequire = createRequire as MockedFunction< + typeof createRequire + > + const mockRequire = vi.fn() + mockCreateRequire.mockReturnValue(mockRequire as any) + mockRequire.mockReturnValue({ version: '0.8.42' }) vi.stubGlobal('process', { ...process, env: { ...process.env, ETHERSCAN_KEY: 'MY_ETHERSCAN_KEY' }, @@ -262,7 +279,7 @@ describe(loadConfig.name, () => { "foundryProject": false, "libs": [], "remappings": {}, - "solcVersion": "0.8.20", + "solcVersion": "0.8.42", }, "externalContracts": { "apiKeys": { @@ -298,7 +315,7 @@ describe(loadConfig.name, () => { "foundryProject": false, "libs": [], "remappings": {}, - "solcVersion": "0.8.20", + "solcVersion": "0.8.42", }, "externalContracts": { "apiKeys": { @@ -427,7 +444,7 @@ describe(loadConfig.name, () => { "foundryProject": false, "libs": [], "remappings": {}, - "solcVersion": "0.8.20", + "solcVersion": "0.8.42", }, "externalContracts": { "apiKeys": { diff --git a/bundlers/config/vitest.config.ts b/bundlers/config/vitest.config.ts index babd0ff138..41723bcdad 100644 --- a/bundlers/config/vitest.config.ts +++ b/bundlers/config/vitest.config.ts @@ -6,10 +6,10 @@ export default defineConfig({ include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], coverage: { reporter: ['text', 'json-summary', 'json'], - lines: 99.78, - statements: 99.78, + lines: 100, + statements: 100, functions: 100, - branches: 88.05, + branches: 89.18, thresholdAutoUpdate: true, }, }, diff --git a/examples/next/tsconfig.json b/examples/next/tsconfig.json index c8e46ce505..61b6b166e7 100644 --- a/examples/next/tsconfig.json +++ b/examples/next/tsconfig.json @@ -3,9 +3,6 @@ "plugins": [ { "name": "@evmts/ts-plugin", - "compiler": { - "solcVersion": "0.8.19" - }, "localContracts": { "contracts": [ {