From 1490be66ed5402240faf6dd5ff4e9ea992108c04 Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Tue, 11 Aug 2026 02:23:19 +0200 Subject: [PATCH 1/4] fix(precompiles): export solo precompile from ethers entrypoint ETHERS_SOLO_PRECOMPILE_ABI and getSoloPrecompileEthersV6Contract were implemented but never re-exported from src/ethers/index.ts, leaving them unreachable from @sei-js/precompiles and @sei-js/precompiles/ethers. The ethers spec worked around this by importing from '../soloPrecompile' directly; it now resolves through the barrel so the test covers the export path it is meant to. Co-authored-by: Cursor --- .changeset/export-solo-precompile-ethers.md | 5 +++++ .../src/ethers/__tests__/ethersPrecompiles.spec.ts | 3 ++- packages/precompiles/src/ethers/index.ts | 1 + packages/precompiles/src/ethers/soloPrecompile.ts | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .changeset/export-solo-precompile-ethers.md diff --git a/.changeset/export-solo-precompile-ethers.md b/.changeset/export-solo-precompile-ethers.md new file mode 100644 index 000000000..63cd28138 --- /dev/null +++ b/.changeset/export-solo-precompile-ethers.md @@ -0,0 +1,5 @@ +--- +'@sei-js/precompiles': minor +--- + +Export the Solo precompile from the `ethers` entrypoint. `ETHERS_SOLO_PRECOMPILE_ABI` and `getSoloPrecompileEthersV6Contract` were implemented but never re-exported from `src/ethers/index.ts`, so they were unreachable from both `@sei-js/precompiles` and `@sei-js/precompiles/ethers`. diff --git a/packages/precompiles/src/ethers/__tests__/ethersPrecompiles.spec.ts b/packages/precompiles/src/ethers/__tests__/ethersPrecompiles.spec.ts index b0f55d49c..4fd7aaea0 100644 --- a/packages/precompiles/src/ethers/__tests__/ethersPrecompiles.spec.ts +++ b/packages/precompiles/src/ethers/__tests__/ethersPrecompiles.spec.ts @@ -10,6 +10,7 @@ import { ETHERS_ORACLE_PRECOMPILE_ABI, ETHERS_POINTERVIEW_PRECOMPILE_ABI, ETHERS_POINTER_PRECOMPILE_ABI, + ETHERS_SOLO_PRECOMPILE_ABI, ETHERS_STAKING_PRECOMPILE_ABI, ETHERS_WASM_PRECOMPILE_ABI, getAddressPrecompileEthersV6Contract, @@ -21,6 +22,7 @@ import { getOraclePrecompileEthersV6Contract, getPointerPrecompileEthersV6Contract, getPointerviewPrecompileEthersV6Contract, + getSoloPrecompileEthersV6Contract, getStakingPrecompileEthersV6Contract, getWasmPrecompileEthersV6Contract } from '../'; @@ -51,7 +53,6 @@ import { WASM_PRECOMPILE_ABI, WASM_PRECOMPILE_ADDRESS } from '../../precompiles'; -import { ETHERS_SOLO_PRECOMPILE_ABI, getSoloPrecompileEthersV6Contract } from '../soloPrecompile'; const FACTORIES: [string, string, InterfaceAbi, unknown, (runner: ContractRunner) => Contract][] = [ ['ADDRESS', ADDRESS_PRECOMPILE_ADDRESS, ADDRESS_PRECOMPILE_ABI, ETHERS_ADDRESS_PRECOMPILE_ABI, getAddressPrecompileEthersV6Contract], diff --git a/packages/precompiles/src/ethers/index.ts b/packages/precompiles/src/ethers/index.ts index fea8ea58e..bda78cf27 100644 --- a/packages/precompiles/src/ethers/index.ts +++ b/packages/precompiles/src/ethers/index.ts @@ -7,5 +7,6 @@ export * from './jsonPrecompile'; export * from './oraclePrecompile'; export * from './pointerPrecompile'; export * from './pointerviewPrecompile'; +export * from './soloPrecompile'; export * from './stakingPrecompile'; export * from './wasmPrecompile'; diff --git a/packages/precompiles/src/ethers/soloPrecompile.ts b/packages/precompiles/src/ethers/soloPrecompile.ts index 2f1495db5..f074460b3 100644 --- a/packages/precompiles/src/ethers/soloPrecompile.ts +++ b/packages/precompiles/src/ethers/soloPrecompile.ts @@ -26,7 +26,7 @@ export const ETHERS_SOLO_PRECOMPILE_ABI = SOLO_PRECOMPILE_ABI as InterfaceAbi; * ``` * * @param runner A [Provider](https://docs.ethers.org/v6/api/providers/) (read-only) or ethers.Signer to use with the contract. - * @returns The typed contract instance for interacting with the Oracle precompile contract. + * @returns The typed contract instance for interacting with the Solo precompile contract. * @category Contract Factory */ export const getSoloPrecompileEthersV6Contract = (runner: ContractRunner) => { From 44548392afc6cd52afc273b8ba063f3df25aa4c2 Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Tue, 11 Aug 2026 02:28:13 +0200 Subject: [PATCH 2/4] test(precompiles): guard barrel parity across entrypoints The solo export could go missing because nothing asserted the ethers, viem, and precompiles barrels expose the same set. Derives the precompile names from each barrel's ABI constants and compares them, so the next precompile that is added to one barrel and forgotten in another fails the suite instead of shipping. Co-authored-by: Cursor --- .../src/__tests__/barrelParity.spec.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 packages/precompiles/src/__tests__/barrelParity.spec.ts diff --git a/packages/precompiles/src/__tests__/barrelParity.spec.ts b/packages/precompiles/src/__tests__/barrelParity.spec.ts new file mode 100644 index 000000000..c91011d74 --- /dev/null +++ b/packages/precompiles/src/__tests__/barrelParity.spec.ts @@ -0,0 +1,38 @@ +import * as ethersBarrel from '../ethers'; +import * as precompilesBarrel from '../precompiles'; +import * as viemBarrel from '../viem'; + +const precompileNamesFrom = (barrel: Record, prefix: '' | 'ETHERS_' | 'VIEM_'): string[] => { + const pattern = new RegExp(`^${prefix}([A-Z0-9]+)_PRECOMPILE_ABI$`); + + return Object.keys(barrel) + .map((key) => pattern.exec(key)?.[1]) + .filter((name): name is string => name !== undefined) + .sort(); +}; + +describe('Precompile barrel parity', () => { + const precompileNames = precompileNamesFrom(precompilesBarrel, ''); + const ethersNames = precompileNamesFrom(ethersBarrel, 'ETHERS_'); + const viemNames = precompileNamesFrom(viemBarrel, 'VIEM_'); + + // Without this the three comparisons below would pass on three empty sets if the + // ABI naming convention ever changes out from under the pattern above. + it('discovers precompiles in the base barrel', () => { + expect(precompileNames.length).toBeGreaterThan(0); + }); + + it('exposes the same precompiles from the ethers barrel as the base barrel', () => { + expect(ethersNames).toEqual(precompileNames); + }); + + it('exposes the same precompiles from the viem barrel as the base barrel', () => { + expect(viemNames).toEqual(precompileNames); + }); + + it('exposes one ethers contract factory per precompile', () => { + const factories = Object.keys(ethersBarrel).filter((key) => /^get[A-Za-z]+PrecompileEthersV6Contract$/.test(key)); + + expect(factories).toHaveLength(precompileNames.length); + }); +}); From 20a5829d9b4a8aef5cef1f54be50fe3527c87333 Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Tue, 11 Aug 2026 02:40:29 +0200 Subject: [PATCH 3/4] test(precompiles): compare factory names, not just factory count Review feedback on #323. The count assertion passed whenever a factory was added for one precompile and dropped for another, which is the shape of bug this file exists to catch. Factory names map onto the ABI names once the captured segment is uppercased, so compare the sets directly. Also scopes the changeset to the package root: the /ethers subpath is still unresolvable (PLT-841) and the old wording implied this restored it. Co-authored-by: Cursor --- .changeset/export-solo-precompile-ethers.md | 4 +++- packages/precompiles/src/__tests__/barrelParity.spec.ts | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.changeset/export-solo-precompile-ethers.md b/.changeset/export-solo-precompile-ethers.md index 63cd28138..e972d76bd 100644 --- a/.changeset/export-solo-precompile-ethers.md +++ b/.changeset/export-solo-precompile-ethers.md @@ -2,4 +2,6 @@ '@sei-js/precompiles': minor --- -Export the Solo precompile from the `ethers` entrypoint. `ETHERS_SOLO_PRECOMPILE_ABI` and `getSoloPrecompileEthersV6Contract` were implemented but never re-exported from `src/ethers/index.ts`, so they were unreachable from both `@sei-js/precompiles` and `@sei-js/precompiles/ethers`. +Export the Solo precompile from the `ethers` entrypoint. `ETHERS_SOLO_PRECOMPILE_ABI` and `getSoloPrecompileEthersV6Contract` were implemented but never re-exported from `src/ethers/index.ts`, so they were unreachable from the `@sei-js/precompiles` package root. + +The `@sei-js/precompiles/ethers` subpath shown in the doc examples remains unresolvable and is unchanged here — the package still publishes no `exports` map. That is tracked separately. diff --git a/packages/precompiles/src/__tests__/barrelParity.spec.ts b/packages/precompiles/src/__tests__/barrelParity.spec.ts index c91011d74..240b3984c 100644 --- a/packages/precompiles/src/__tests__/barrelParity.spec.ts +++ b/packages/precompiles/src/__tests__/barrelParity.spec.ts @@ -30,9 +30,12 @@ describe('Precompile barrel parity', () => { expect(viemNames).toEqual(precompileNames); }); - it('exposes one ethers contract factory per precompile', () => { - const factories = Object.keys(ethersBarrel).filter((key) => /^get[A-Za-z]+PrecompileEthersV6Contract$/.test(key)); + it('exposes an ethers contract factory for each precompile', () => { + const factories = Object.keys(ethersBarrel) + .map((key) => /^get([A-Za-z]+)PrecompileEthersV6Contract$/.exec(key)?.[1]?.toUpperCase()) + .filter((name): name is string => name !== undefined) + .sort(); - expect(factories).toHaveLength(precompileNames.length); + expect(factories).toEqual(precompileNames); }); }); From 7045788e94cef4f3611b13da087a7823cf55b0d0 Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Tue, 11 Aug 2026 02:46:40 +0200 Subject: [PATCH 4/4] test(precompiles): keep factory and ABI name patterns symmetric Review nit on #323. The ABI capture allows digits but the factory capture did not, so a future precompile like ERC721 would be found by one derivation and dropped by the other, failing as a missing factory rather than as a pattern mismatch. Co-authored-by: Cursor --- packages/precompiles/src/__tests__/barrelParity.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/precompiles/src/__tests__/barrelParity.spec.ts b/packages/precompiles/src/__tests__/barrelParity.spec.ts index 240b3984c..3060fe5d3 100644 --- a/packages/precompiles/src/__tests__/barrelParity.spec.ts +++ b/packages/precompiles/src/__tests__/barrelParity.spec.ts @@ -32,7 +32,7 @@ describe('Precompile barrel parity', () => { it('exposes an ethers contract factory for each precompile', () => { const factories = Object.keys(ethersBarrel) - .map((key) => /^get([A-Za-z]+)PrecompileEthersV6Contract$/.exec(key)?.[1]?.toUpperCase()) + .map((key) => /^get([A-Za-z0-9]+)PrecompileEthersV6Contract$/.exec(key)?.[1]?.toUpperCase()) .filter((name): name is string => name !== undefined) .sort();