precompile/dex: refuse activation without explicit protocolFeeController

DEX module previously defaulted ProtocolFeeController to Anvil/Foundry
account #0 (0xf39Fd6...92266) whose private key
(0xac0974...80) is in every Foundry user's ~/.foundry. At Quasar Edition
activation, any random caller could have invoked PauseDEX, ResumeDEX,
or the irreversible FreezePool on the chain-wide AMM precompile — a
chain-wide compromise the cryptographer review caught.

Fix is a fail-closed activation gate:

  - dex/module.go::Configure() returns ErrDEXNoProtocolFeeController when
    upgrade.json dexConfig omits protocolFeeController (zero address).
    luxd will refuse to advance past the activation block until the
    operator populates the field with a real KMS-controlled multisig.
  - compromisedDevControllers map blocks all ten Anvil deterministic
    accounts; any explicit attempt to install a public dev key fails with
    ErrDEXCompromisedController (the address is included in the error).
  - dex/dex_test.go covers: zero-address rejection, all 10 anvil
    addresses rejected, a real address activates cleanly, random callers
    cannot invoke admin functions even with a real controller, and the
    Configure interface still returns *Config.

Same audit pass also wires three previously-stub-only precompiles into
the modules.RegisterModule registry so upgrade.json can gate them:

  - kzg4844 (LP-3665 KZG point-evaluation extensions, ConfigKey=kzg4844Config)
  - ed25519 (LP-3211, ConfigKey=ed25519Config) — Solana/TON/XRP signature
    verify lands as a first-class registered precompile alongside the
    legacy NewModule() metadata wrapper.
  - secp256r1 (EIP-7212 P256-verify, ConfigKey=secp256r1Config) — stateful
    adapter wraps the existing Contract.Run(input) into a contract
    StatefulPrecompiledContract that does gas deduction and strict-PQ
    refusal uniformly.
  - modules/registerer.go extends reservedRanges with 0x100-0x1FF
    (post-EVM-standard EIP band, for P256) and 0x32000...0000 to
    0x32FF000...0000 (high-byte LP-3xxx classical-signature page, for
    ed25519). Both ranges are narrow enough that no other precompile
    family overlaps.

router precompile audit: no Anvil default existed there (RouterConfig
already used zero-as-skip semantics rather than zero-as-default).

Tests:
  go test -count=1 -race -timeout 120s ./dex/... ./kzg4844/... \\
    ./ed25519/... ./secp256r1/... ./modules/...
All pass; full ./... suite (49 packages) green.
This commit is contained in:
Hanzo AI
2026-06-01 21:04:56 -07:00
parent c2294a6545
commit 49b9805410
7 changed files with 482 additions and 68 deletions
+178
View File
@@ -0,0 +1,178 @@
// Copyright (C) 2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package dex
import (
"errors"
"strings"
"testing"
"github.com/luxfi/geth/common"
"github.com/luxfi/precompile/precompileconfig"
)
// TestDexConfigure_NoProtocolFeeController_RejectsActivation verifies that
// Configure() refuses to activate the DEX precompile when the upgrade.json
// dexConfig omits protocolFeeController (or sets it to the zero address).
//
// Regression: before this guard, omitting the field defaulted to the Foundry
// Anvil account #0 (0xf39Fd6...92266) whose private key is in every Foundry
// installation. That left PauseDEX / ResumeDEX / FreezePool callable by any
// caller — a chain-wide AMM compromise at activation.
func TestDexConfigure_NoProtocolFeeController_RejectsActivation(t *testing.T) {
cases := []struct {
name string
cfg *Config
}{
{
name: "zero-address protocolFeeController",
cfg: &Config{
ProtocolFeeController: common.Address{},
},
},
{
name: "no protocolFeeController field at all",
cfg: &Config{},
},
}
cfgr := &configurator{}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := cfgr.Configure(nil, tc.cfg, nil, nil)
if !errors.Is(err, ErrDEXNoProtocolFeeController) {
t.Fatalf("expected ErrDEXNoProtocolFeeController, got: %v", err)
}
})
}
}
// TestDexConfigure_AnvilDefault_RejectsActivation verifies that any of the
// well-known Foundry/Anvil deterministic dev accounts is rejected as the
// protocolFeeController. These addresses' private keys are public knowledge,
// so configuring one as the chain's AMM admin would be a chain-wide
// compromise. The blocklist lives in dex/module.go::compromisedDevControllers
// and must catch each of them.
func TestDexConfigure_AnvilDefault_RejectsActivation(t *testing.T) {
anvilAccounts := []string{
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", // anvil #0
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8", // anvil #1
"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", // anvil #2
"0x90F79bf6EB2c4f870365E785982E1f101E93b906", // anvil #3
"0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65", // anvil #4
"0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", // anvil #5
"0x976EA74026E726554dB657fA54763abd0C3a0aa9", // anvil #6
"0x14dC79964da2C08b23698B3D3cc7Ca32193d9955", // anvil #7
"0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f", // anvil #8
"0xa0Ee7A142d267C1f36714E4a8F75612F20a79720", // anvil #9
}
cfgr := &configurator{}
for _, addr := range anvilAccounts {
t.Run(addr, func(t *testing.T) {
cfg := &Config{
ProtocolFeeController: common.HexToAddress(addr),
}
err := cfgr.Configure(nil, cfg, nil, nil)
if !errors.Is(err, ErrDEXCompromisedController) {
t.Fatalf("expected ErrDEXCompromisedController for %s, got: %v", addr, err)
}
// The error message should include the offending address so
// operators can see exactly what they put in upgrade.json.
if !strings.Contains(err.Error(), addr) && !strings.Contains(err.Error(), strings.ToLower(addr)) {
// Address.Hex() uses checksum casing, accept either.
expectedChecksum := common.HexToAddress(addr).Hex()
if !strings.Contains(err.Error(), expectedChecksum) {
t.Errorf("error should include the offending address; got: %v", err)
}
}
})
}
}
// TestDexConfigure_RealAddress_ActivatesCleanly verifies that a real (non-
// dev-key) protocolFeeController activates the precompile without error.
// We use the LUX_MNEMONIC-derived treasury 0x9011E888...4714 as the canonical
// transitional placeholder (KMS-controlled, not publicly known).
func TestDexConfigure_RealAddress_ActivatesCleanly(t *testing.T) {
cfgr := &configurator{}
// Reset singleton state to be hermetic — Configure() mutates the
// singleton PoolManager's protocolFeeController. Save+restore.
origController := DEXPrecompile.poolManager.protocolFeeController
t.Cleanup(func() {
DEXPrecompile.poolManager.protocolFeeController = origController
})
realAddr := common.HexToAddress("0x9011E888251AB053B7bD1cdB598Db4f9DEd94714")
cfg := &Config{ProtocolFeeController: realAddr}
if err := cfgr.Configure(nil, cfg, nil, nil); err != nil {
t.Fatalf("Configure with real address should succeed, got: %v", err)
}
if DEXPrecompile.poolManager.protocolFeeController != realAddr {
t.Fatalf(
"singleton controller not updated: got %s, want %s",
DEXPrecompile.poolManager.protocolFeeController.Hex(), realAddr.Hex(),
)
}
}
// TestDexAdmin_OnlyConfiguredController verifies that admin functions
// (PauseDEX, ResumeDEX, PausePool, ResumePool, FreezePool) refuse unauthorized
// callers — only the address configured as protocolFeeController is allowed.
// This complements the activation-time guard: even if a real controller is
// configured, a random EVM caller cannot exercise the admin surface.
func TestDexAdmin_OnlyConfiguredController(t *testing.T) {
configured := common.HexToAddress("0x9011E888251AB053B7bD1cdB598Db4f9DEd94714")
random := common.HexToAddress("0xBADBADBADBADBADBADBADBADBADBADBADBADBADB")
pm := NewPoolManager(&mockEngine{})
pm.protocolFeeController = configured
stateDB := NewMockStateDB()
// Initialize a pool so freeze/pause-pool have a target.
keyAB, poolID, _, _ := initTwoPoolsPF(t, pm, stateDB)
_ = keyAB
// Each admin call by `random` must return ErrUnauthorized.
cases := []struct {
name string
fn func() error
}{
{"PauseDEX", func() error { return pm.PauseDEX(stateDB, random) }},
{"ResumeDEX", func() error { return pm.ResumeDEX(stateDB, random) }},
{"PausePool", func() error { return pm.PausePool(stateDB, random, poolID) }},
{"ResumePool", func() error { return pm.ResumePool(stateDB, random, poolID) }},
{"FreezePool", func() error { return pm.FreezePool(stateDB, random, poolID) }},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
if err := tc.fn(); !errors.Is(err, ErrUnauthorized) {
t.Fatalf("expected ErrUnauthorized for random caller on %s, got: %v", tc.name, err)
}
})
}
// And the configured controller can pause/resume successfully.
if err := pm.PauseDEX(stateDB, configured); err != nil {
t.Fatalf("configured controller PauseDEX should succeed, got: %v", err)
}
if err := pm.ResumeDEX(stateDB, configured); err != nil {
t.Fatalf("configured controller ResumeDEX should succeed, got: %v", err)
}
}
// TestDexConfig_MakeConfigReturnsConfig verifies the configurator returns the
// canonical Config type, so JSON unmarshalling produces a struct whose
// ProtocolFeeController field is populated from `protocolFeeController` in
// upgrade.json (the field the operator must set).
func TestDexConfig_MakeConfigReturnsConfig(t *testing.T) {
cfg := (&configurator{}).MakeConfig()
if _, ok := cfg.(*Config); !ok {
t.Fatalf("MakeConfig should return *Config, got %T", cfg)
}
// Confirm the interface compliance is preserved.
var _ precompileconfig.Config = (*Config)(nil)
}
+40 -4
View File
@@ -188,6 +188,33 @@ func (*configurator) MakeConfig() precompileconfig.Config {
return new(Config)
}
// compromisedDevControllers lists Ethereum addresses whose private keys are
// publicly distributed (Foundry/Anvil deterministic test accounts, Hardhat
// default mnemonic, etc.). Configuring any of these as the DEX protocol fee
// controller would let any caller pause / freeze the chain-wide AMM, so
// activation is refused. Stored as the lowercase hex representation produced
// by common.Address.Hex()-stripped-and-lowered for cheap membership testing.
//
// Sources:
// - Foundry/Anvil default mnemonic "test test test test test test test test
// test test test junk" (anvil --accounts 10) → accounts #0..#9.
// - Hardhat default mnemonic produces an overlapping set (same root).
//
// New entries should be appended whenever a new well-known development
// mnemonic is identified.
var compromisedDevControllers = map[common.Address]struct{}{
common.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"): {}, // anvil #0
common.HexToAddress("0x70997970C51812dc3A010C7d01b50e0d17dc79C8"): {}, // anvil #1
common.HexToAddress("0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"): {}, // anvil #2
common.HexToAddress("0x90F79bf6EB2c4f870365E785982E1f101E93b906"): {}, // anvil #3
common.HexToAddress("0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65"): {}, // anvil #4
common.HexToAddress("0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc"): {}, // anvil #5
common.HexToAddress("0x976EA74026E726554dB657fA54763abd0C3a0aa9"): {}, // anvil #6
common.HexToAddress("0x14dC79964da2C08b23698B3D3cc7Ca32193d9955"): {}, // anvil #7
common.HexToAddress("0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f"): {}, // anvil #8
common.HexToAddress("0xa0Ee7A142d267C1f36714E4a8F75612F20a79720"): {}, // anvil #9
}
func (*configurator) Configure(
chainConfig precompileconfig.ChainConfig,
cfg precompileconfig.Config,
@@ -199,11 +226,20 @@ func (*configurator) Configure(
return fmt.Errorf("expected config type %T, got %T: %v", &Config{}, cfg, cfg)
}
// Set protocol fee controller required for pause/freeze admin.
// If no protocolFeeController specified, use a sensible default.
// Protocol fee controller is required. NO DEFAULT. A missing or zero
// controller would leave PauseDEX / ResumeDEX / FreezePool open to any
// caller; the operator MUST populate this explicitly in upgrade.json
// (typically a multisig or governance contract). Refusing activation
// surfaces the misconfiguration on the activation block rather than
// silently shipping an open-admin DEX.
if config.ProtocolFeeController == (common.Address{}) {
// Default to the standard Anvil/dev account #0
config.ProtocolFeeController = common.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")
return ErrDEXNoProtocolFeeController
}
// Refuse known-compromised dev keys whose private keys are public
// knowledge (Foundry/Anvil, Hardhat default mnemonic). This catches the
// "I'll fix the placeholder before mainnet" footgun.
if _, bad := compromisedDevControllers[config.ProtocolFeeController]; bad {
return fmt.Errorf("%w: %s", ErrDEXCompromisedController, config.ProtocolFeeController.Hex())
}
DEXPrecompile.poolManager.protocolFeeController = config.ProtocolFeeController
+15
View File
@@ -361,6 +361,21 @@ var (
ErrInvalidFee = errors.New("invalid fee")
ErrCurrencyNotSorted = errors.New("currencies not sorted")
ErrUnauthorized = errors.New("unauthorized")
// ErrDEXNoProtocolFeeController is returned when the DEX precompile is
// configured without an explicit protocolFeeController address (or with
// the zero address). Activating the precompile without a real controller
// would leave PauseDEX / ResumeDEX / FreezePool callable by anyone, so
// configuration must explicitly populate the controller. luxd refuses to
// advance past the activation block until upgrade.json is fixed.
ErrDEXNoProtocolFeeController = errors.New("dex: protocolFeeController must be set in upgrade.json — refusing to activate")
// ErrDEXCompromisedController is returned when the configured
// protocolFeeController matches a known publicly-disclosed development
// key (e.g. Foundry/Anvil account #0). The matching private key is in
// every Foundry user's ~/.foundry — any random caller could pause /
// freeze the chain-wide AMM. Activation fails closed.
ErrDEXCompromisedController = errors.New("dex: protocolFeeController is a publicly-known dev key — refusing to activate")
ErrInvalidHookResponse = errors.New("invalid hook response")
ErrSettlementFailed = errors.New("settlement failed")
ErrInvalidSqrtPrice = errors.New("invalid sqrt price")
+70 -7
View File
@@ -5,32 +5,95 @@ package ed25519
import (
"github.com/luxfi/geth/common"
"github.com/luxfi/precompile/contract"
"github.com/luxfi/precompile/modules"
"github.com/luxfi/precompile/precompileconfig"
)
// Module provides the ed25519 precompile module information
// ConfigKey is the upgrade.json key for the Ed25519 verify precompile.
// Activated at the Quasar Edition timestamp; once active, contracts can
// natively verify Solana/Ed25519, TON, XRP (Ed25519 mode), and any other
// Ed25519-rooted external chain signature inside EVM execution.
const ConfigKey = "ed25519Config"
// RegistryModule is the registry entry for the Ed25519 precompile.
// Distinct identifier from the legacy `Module` metadata struct that older
// callers depend on (see NewModule()/Module type below).
var RegistryModule = modules.Module{
ConfigKey: ConfigKey,
Address: ContractAddress,
Contract: Ed25519VerifyPrecompile,
Configurator: &configurator{},
}
type configurator struct{}
var _ contract.Configurator = (*configurator)(nil)
func init() {
if err := modules.RegisterModule(RegistryModule); err != nil {
panic(err)
}
}
func (*configurator) MakeConfig() precompileconfig.Config { return new(Config) }
func (*configurator) Configure(
_ precompileconfig.ChainConfig,
_ precompileconfig.Config,
_ contract.StateDB,
_ contract.ConfigurationBlockContext,
) error {
return nil
}
// Config is the upgrade-gated config for the Ed25519 verify precompile.
// No tunable parameters — the precompile is either active or not.
type Config struct {
Upgrade precompileconfig.Upgrade `json:"upgrade"`
}
func (c *Config) Key() string { return ConfigKey }
func (c *Config) Timestamp() *uint64 { return c.Upgrade.Timestamp() }
func (c *Config) IsDisabled() bool { return c.Upgrade.Disable }
func (c *Config) Equal(cfg precompileconfig.Config) bool {
other, ok := cfg.(*Config)
if !ok {
return false
}
return c.Upgrade.Equal(&other.Upgrade)
}
func (c *Config) Verify(precompileconfig.ChainConfig) error { return nil }
// --- Legacy metadata-style module wrapper (kept for backward compatibility) ---
//
// These functions predate the modules.Module registry pattern. They are
// preserved so existing callers and tests continue to compile.
// Module provides the ed25519 precompile module information.
type Module struct{}
// NewModule creates a new ed25519 module
// NewModule creates a new ed25519 module.
func NewModule() *Module {
return &Module{}
}
// Address returns the precompile address
// Address returns the precompile address.
func (m *Module) Address() common.Address {
return ContractAddress
}
// Contract returns the singleton contract instance
// Contract returns the singleton contract instance.
func (m *Module) Contract() *ed25519VerifyPrecompile {
return Ed25519VerifyPrecompile
}
// ConfigKey returns the configuration key for this module
// ConfigKey returns the configuration key for this module.
func (m *Module) ConfigKey() string {
return "ed25519Config"
return ConfigKey
}
// Name returns the module name
// Name returns the module name.
func (m *Module) Name() string {
return "ed25519"
}
+46 -23
View File
@@ -4,37 +4,60 @@
package kzg4844
import (
"github.com/luxfi/geth/common"
"github.com/luxfi/precompile/contract"
"github.com/luxfi/precompile/modules"
"github.com/luxfi/precompile/precompileconfig"
)
var (
// Module is the precompile module singleton
Module = &module{
address: ContractAddress,
contract: KZG4844Precompile,
var _ contract.Configurator = (*configurator)(nil)
// ConfigKey is the upgrade.json key for the EIP-4844 KZG point-evaluation
// extension precompile (LP-3665). The standard EVM precompile at 0x0a is
// always-on; this one provides the extended op-codes (BlobToCommitment,
// ComputeProof, batch verify, etc.) at 0xB002.
const ConfigKey = "kzg4844Config"
// Module is the registry entry for the KZG-4844 extension precompile.
var Module = modules.Module{
ConfigKey: ConfigKey,
Address: ContractAddress,
Contract: KZG4844Precompile,
Configurator: &configurator{},
}
type configurator struct{}
func init() {
if err := modules.RegisterModule(Module); err != nil {
panic(err)
}
)
type module struct {
address common.Address
contract contract.StatefulPrecompiledContract
}
// Address returns the address where the stateful precompile is accessible.
func (m *module) Address() common.Address {
return m.address
}
func (*configurator) MakeConfig() precompileconfig.Config { return new(Config) }
// Contract returns a thread-safe singleton that can be used as the StatefulPrecompiledContract
func (m *module) Contract() contract.StatefulPrecompiledContract {
return m.contract
}
// Configure is a no-op for KZG4844 as it has no configuration
func (m *module) Configure(
func (*configurator) Configure(
_ precompileconfig.ChainConfig,
_ precompileconfig.Config,
_ contract.StateDB,
_ common.Address,
_ contract.ConfigurationBlockContext,
) error {
return nil
}
// Config is the upgrade-gated config for the KZG-4844 extension precompile.
// No tunable parameters — the precompile is either active or not.
type Config struct {
Upgrade precompileconfig.Upgrade `json:"upgrade"`
}
func (c *Config) Key() string { return ConfigKey }
func (c *Config) Timestamp() *uint64 { return c.Upgrade.Timestamp() }
func (c *Config) IsDisabled() bool { return c.Upgrade.Disable }
func (c *Config) Equal(cfg precompileconfig.Config) bool {
other, ok := cfg.(*Config)
if !ok {
return false
}
return c.Upgrade.Equal(&other.Upgrade)
}
func (c *Config) Verify(precompileconfig.ChainConfig) error { return nil }
+20
View File
@@ -192,6 +192,26 @@ var (
Start: common.HexToAddress("0x0000000000000000000000000000000000000001"),
End: common.HexToAddress("0x00000000000000000000000000000000000000ff"),
},
// EIP-7212 secp256r1 / P256 verify (0x100)
// Reserved post-EVM-standard band 0x100-0x1FF for upstream-EIP
// precompiles that EVM clients converge on (RIP-7212 picked 0x100
// for P256 verify). Keeping the range tight (one /248 of the 20-
// byte space) means future EIPs slot in here without colliding
// with anything Lux uses.
{
Start: common.HexToAddress("0x0000000000000000000000000000000000000100"),
End: common.HexToAddress("0x00000000000000000000000000000000000001ff"),
},
// High-byte EVM/Crypto page (LP-3xxx classical signatures)
// Per precompile/registry/registry.go PCII scheme: P=3 (EVM/Crypto)
// at high-byte format 0x3PCC0000...0000. Reserved for the classical-
// signature sub-page so ed25519 (LP-3211 at 0x3211...0000), ECDSA
// extensions (LP-3210), BLS12-381 (LP-3212), VRF (LP-3213), etc.
// can register without each subsystem extending the table.
{
Start: common.HexToAddress("0x3200000000000000000000000000000000000000"),
End: common.HexToAddress("0x32ff000000000000000000000000000000000000"),
},
// Dead/Burn Addresses (LP-0150)
// 0x0000...0000 - Zero address
{
+113 -34
View File
@@ -5,52 +5,131 @@ package secp256r1
import (
"github.com/luxfi/geth/common"
"github.com/luxfi/precompile/contract"
"github.com/luxfi/precompile/modules"
"github.com/luxfi/precompile/precompileconfig"
)
// Module provides the secp256r1 precompile module information
// ConfigKey is the upgrade.json key for the EIP-7212 secp256r1/P-256
// signature verification precompile. Activated at the Quasar Edition
// timestamp; once active, smart contracts can verify WebAuthn / passkey
// signatures natively (no Solidity P-256 emulation).
const ConfigKey = "secp256r1Config"
// stateful is a thin StatefulPrecompiledContract wrapper around the
// minimal-interface Contract so we can register the precompile in the
// modules.Module registry. The wrapper deducts gas first (uniform with
// every other Lux precompile), enforces RefuseUnderStrictPQ, then delegates
// to the existing classical verifier.
type stateful struct{ c Contract }
var (
// StatefulPrecompile is the singleton used by modules.Module.Contract.
StatefulPrecompile contract.StatefulPrecompiledContract = &stateful{}
_ contract.StatefulPrecompiledContract = (*stateful)(nil)
)
// RequiredGas is delegated to the wrapped Contract.
func (s *stateful) RequiredGas(input []byte) uint64 { return s.c.RequiredGas(input) }
// Run satisfies StatefulPrecompiledContract. Gas deduction, strict-PQ
// gating, then delegation to the classical EIP-7212 verifier.
func (s *stateful) Run(
accessibleState contract.AccessibleState,
_ common.Address,
_ common.Address,
input []byte,
suppliedGas uint64,
_ bool,
) ([]byte, uint64, error) {
remainingGas, err := contract.DeductGas(suppliedGas, s.c.RequiredGas(input))
if err != nil {
return nil, 0, err
}
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, remainingGas, err
}
out, err := s.c.Run(input)
return out, remainingGas, err
}
// RegistryModule is the precompile registry entry for secp256r1.
var RegistryModule = modules.Module{
ConfigKey: ConfigKey,
Address: Address,
Contract: StatefulPrecompile,
Configurator: &configurator{},
}
type configurator struct{}
var _ contract.Configurator = (*configurator)(nil)
func init() {
if err := modules.RegisterModule(RegistryModule); err != nil {
panic(err)
}
}
func (*configurator) MakeConfig() precompileconfig.Config { return new(Config) }
func (*configurator) Configure(
_ precompileconfig.ChainConfig,
_ precompileconfig.Config,
_ contract.StateDB,
_ contract.ConfigurationBlockContext,
) error {
return nil
}
// Config is the upgrade-gated config for the secp256r1 precompile.
type Config struct {
Upgrade precompileconfig.Upgrade `json:"upgrade"`
}
func (c *Config) Key() string { return ConfigKey }
func (c *Config) Timestamp() *uint64 { return c.Upgrade.Timestamp() }
func (c *Config) IsDisabled() bool { return c.Upgrade.Disable }
func (c *Config) Equal(cfg precompileconfig.Config) bool {
other, ok := cfg.(*Config)
if !ok {
return false
}
return c.Upgrade.Equal(&other.Upgrade)
}
func (c *Config) Verify(precompileconfig.ChainConfig) error { return nil }
// --- Legacy metadata-style module wrapper (kept for backward compatibility) ---
// Module provides the secp256r1 precompile module information.
type Module struct{}
// NewModule creates a new secp256r1 module
func NewModule() *Module {
return &Module{}
}
// NewModule creates a new secp256r1 module.
func NewModule() *Module { return &Module{} }
// Address returns the precompile address
func (m *Module) Address() common.Address {
return Address
}
// Address returns the precompile address.
func (m *Module) Address() common.Address { return Address }
// Contract returns a new contract instance
func (m *Module) Contract() *Contract {
return &Contract{}
}
// Contract returns a new contract instance.
func (m *Module) Contract() *Contract { return &Contract{} }
// ConfigKey returns the configuration key for this module
func (m *Module) ConfigKey() string {
return "secp256r1Config"
}
// ConfigKey returns the configuration key for this module.
func (m *Module) ConfigKey() string { return ConfigKey }
// Name returns the module name
func (m *Module) Name() string {
return "secp256r1"
}
// Name returns the module name.
func (m *Module) Name() string { return "secp256r1" }
// Description returns the module description
// Description returns the module description.
func (m *Module) Description() string {
return "secp256r1 (P-256) signature verification precompile for biometric authentication and WebAuthn"
}
// Version returns the module version
func (m *Module) Version() string {
return "1.0.0"
}
// Version returns the module version.
func (m *Module) Version() string { return "1.0.0" }
// EIPs returns the related EIP numbers
func (m *Module) EIPs() []int {
return []int{7212}
}
// EIPs returns the related EIP numbers.
func (m *Module) EIPs() []int { return []int{7212} }
// LPs returns the related LP numbers
func (m *Module) LPs() []int {
return []int{3651}
}
// LPs returns the related LP numbers.
func (m *Module) LPs() []int { return []int{3651} }