diff --git a/CHANGELOG.md b/CHANGELOG.md index 90165d117..7b6b49627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,7 +34,7 @@ - [\#609](https://github.com/cosmos/evm/pull/609) Make `erc20Keeper` optional in the EVM keeper - [\#624](https://github.com/cosmos/evm/pull/624) Cleanup unnecessary `fix-revert-gas-refund-height`. - [\#635](https://github.com/cosmos/evm/pull/635) Move DefaultStaticPrecompiles to /evm and allow projects to set it by default alongside the keeper. - +- [\#577](https://github.com/cosmos/evm/pull/577) Cleanup precompiles boilerplate code. ### FEATURES @@ -48,6 +48,7 @@ - [\#477](https://github.com/cosmos/evm/pull/477) Refactor precompile constructors to accept keeper interfaces instead of concrete implementations, breaking the existing `NewPrecompile` function signatures. - [\#594](https://github.com/cosmos/evm/pull/594) Remove all usage of x/params +- [\#577](https://github.com/cosmos/evm/pull/577) Changed the way to create a stateful precompile based on the cmn.Precompile, change `NewPrecompile` to not return error. ## v0.4.1 diff --git a/evmd/tests/ibc/ics20_precompile_transfer_test.go b/evmd/tests/ibc/ics20_precompile_transfer_test.go index cae1ee3cb..fcb1df32c 100644 --- a/evmd/tests/ibc/ics20_precompile_transfer_test.go +++ b/evmd/tests/ibc/ics20_precompile_transfer_test.go @@ -46,14 +46,14 @@ func (suite *ICS20TransferTestSuite) SetupTest() { suite.chainB = suite.coordinator.GetChain(evmibctesting.GetEvmChainID(2)) evmAppA := suite.chainA.App.(*evmd.EVMD) - suite.chainAPrecompile, _ = ics20.NewPrecompile( + suite.chainAPrecompile = ics20.NewPrecompile( evmAppA.BankKeeper, *evmAppA.StakingKeeper, evmAppA.TransferKeeper, evmAppA.IBCKeeper.ChannelKeeper, ) evmAppB := suite.chainB.App.(*evmd.EVMD) - suite.chainBPrecompile, _ = ics20.NewPrecompile( + suite.chainBPrecompile = ics20.NewPrecompile( evmAppB.BankKeeper, *evmAppB.StakingKeeper, evmAppB.TransferKeeper, diff --git a/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go b/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go index 740f8c3d8..27c7c4565 100644 --- a/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go +++ b/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go @@ -47,14 +47,14 @@ func (suite *ICS20TransferV2TestSuite) SetupTest() { suite.chainB = suite.coordinator.GetChain(evmibctesting.GetEvmChainID(2)) evmAppA := suite.chainA.App.(*evmd.EVMD) - suite.chainAPrecompile, _ = ics20.NewPrecompile( + suite.chainAPrecompile = ics20.NewPrecompile( evmAppA.BankKeeper, *evmAppA.StakingKeeper, evmAppA.TransferKeeper, evmAppA.IBCKeeper.ChannelKeeper, ) evmAppB := suite.chainB.App.(*evmd.EVMD) - suite.chainBPrecompile, _ = ics20.NewPrecompile( + suite.chainBPrecompile = ics20.NewPrecompile( evmAppB.BankKeeper, *evmAppB.StakingKeeper, evmAppB.TransferKeeper, diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index ca1f492c6..376eb5357 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -11,13 +11,14 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" cmn "github.com/cosmos/evm/precompiles/common" evmtypes "github.com/cosmos/evm/x/vm/types" storetypes "cosmossdk.io/store/types" + + sdk "github.com/cosmos/cosmos-sdk/types" ) const ( @@ -33,14 +34,27 @@ const ( var _ vm.PrecompiledContract = &Precompile{} -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS +var ( + // Embed abi json file to the executable binary. Needed when importing as dependency. + // + //go:embed abi.json + f embed.FS + ABI abi.ABI +) + +func init() { + var err error + ABI, err = cmn.LoadABI(f, "abi.json") + if err != nil { + panic(err) + } +} // Precompile defines the bank precompile type Precompile struct { cmn.Precompile + + abi.ABI bankKeeper cmn.BankKeeper erc20Keeper cmn.ERC20Keeper } @@ -50,28 +64,19 @@ type Precompile struct { func NewPrecompile( bankKeeper cmn.BankKeeper, erc20Keeper cmn.ERC20Keeper, -) (*Precompile, error) { - newABI, err := cmn.LoadABI(f, "abi.json") - if err != nil { - return nil, err - } - +) *Precompile { // NOTE: we set an empty gas configuration to avoid extra gas costs // during the run execution - p := &Precompile{ + return &Precompile{ Precompile: cmn.Precompile{ - ABI: newABI, KvGasConfig: storetypes.GasConfig{}, TransientKVGasConfig: storetypes.GasConfig{}, + ContractAddress: common.HexToAddress(evmtypes.BankPrecompileAddress), }, + ABI: ABI, bankKeeper: bankKeeper, erc20Keeper: erc20Keeper, } - - // SetAddress defines the address of the bank compile contract. - p.SetAddress(common.HexToAddress(evmtypes.BankPrecompileAddress)) - - return p, nil } // RequiredGas calculates the precompiled contract's base gas rate. @@ -101,40 +106,33 @@ func (p Precompile) RequiredGas(input []byte) uint64 { return 0 } -// Run executes the precompiled contract bank query methods defined in the ABI. -func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, _, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { + return p.RunNativeAction(evm, contract, func(ctx sdk.Context) ([]byte, error) { + return p.Execute(ctx, contract, readonly) + }) +} + +// Execute executes the precompiled contract bank query methods defined in the ABI. +func (p Precompile) Execute(ctx sdk.Context, contract *vm.Contract, readOnly bool) ([]byte, error) { + method, args, err := cmn.SetupABI(p.ABI, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } - // This handles any out of gas errors that may occur during the execution of a precompile query. - // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err)() - + var bz []byte switch method.Name { // Bank queries case BalancesMethod: - bz, err = p.Balances(ctx, contract, method, args) + bz, err = p.Balances(ctx, method, args) case TotalSupplyMethod: - bz, err = p.TotalSupply(ctx, contract, method, args) + bz, err = p.TotalSupply(ctx, method, args) case SupplyOfMethod: - bz, err = p.SupplyOf(ctx, contract, method, args) + bz, err = p.SupplyOf(ctx, method, args) default: return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) } - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - return bz, nil + return bz, err } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/bank/query.go b/precompiles/bank/query.go index 518f8f9d4..a7fc2e8f0 100644 --- a/precompiles/bank/query.go +++ b/precompiles/bank/query.go @@ -5,7 +5,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/core/vm" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -29,7 +28,6 @@ const ( // balanceOf call for each token returned. func (p Precompile) Balances( ctx sdk.Context, - _ *vm.Contract, method *abi.Method, args []interface{}, ) ([]byte, error) { @@ -73,7 +71,6 @@ func (p Precompile) Balances( // call for each token returned. func (p Precompile) TotalSupply( ctx sdk.Context, - _ *vm.Contract, method *abi.Method, _ []interface{}, ) ([]byte, error) { @@ -112,7 +109,6 @@ func (p Precompile) TotalSupply( // stored in the x/bank. func (p Precompile) SupplyOf( ctx sdk.Context, - _ *vm.Contract, method *abi.Method, args []interface{}, ) ([]byte, error) { diff --git a/precompiles/bech32/bech32.go b/precompiles/bech32/bech32.go index a0e1a846b..0d43d7242 100644 --- a/precompiles/bech32/bech32.go +++ b/precompiles/bech32/bech32.go @@ -14,10 +14,21 @@ import ( var _ vm.PrecompiledContract = &Precompile{} -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS +var ( + // Embed abi json file to the executable binary. Needed when importing as dependency. + // + //go:embed abi.json + f embed.FS + ABI abi.ABI +) + +func init() { + var err error + ABI, err = cmn.LoadABI(f, "abi.json") + if err != nil { + panic(err) + } +} // Precompile defines the precompiled contract for Bech32 encoding. type Precompile struct { @@ -28,17 +39,12 @@ type Precompile struct { // NewPrecompile creates a new bech32 Precompile instance as a // PrecompiledContract interface. func NewPrecompile(baseGas uint64) (*Precompile, error) { - newABI, err := cmn.LoadABI(f, "abi.json") - if err != nil { - return nil, err - } - if baseGas == 0 { return nil, fmt.Errorf("baseGas cannot be zero") } return &Precompile{ - ABI: newABI, + ABI: ABI, baseGas: baseGas, }, nil } diff --git a/precompiles/common/precompile.go b/precompiles/common/precompile.go index d095e9704..0904918ea 100644 --- a/precompiles/common/precompile.go +++ b/precompiles/common/precompile.go @@ -15,55 +15,55 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Precompile is a common struct for all precompiles that holds the common data each -// precompile needs to run which includes the ABI, Gas config. +// NativeAction abstract the native execution logic of the stateful precompile, it's passed to the base `Precompile` +// struct, base `Precompile` struct will handle things the native context setup, gas management, panic recovery etc, +// before and after the execution. +// +// It's usually implemented by the precompile itself. +type NativeAction func(ctx sdk.Context) ([]byte, error) + +// Precompile is the base struct for precompiles that requires to access cosmos native storage. type Precompile struct { - abi.ABI KvGasConfig storetypes.GasConfig TransientKVGasConfig storetypes.GasConfig - address common.Address - balanceHandler *BalanceHandler -} - -// Operation is a type that defines if the precompile call -// produced an addition or subtraction of an account's balance -type Operation int8 + ContractAddress common.Address -const ( - Sub Operation = iota - Add -) + // BalanceHandler is optional + BalanceHandler *BalanceHandler +} // RequiredGas calculates the base minimum required gas for a transaction or a query. // It uses the method ID to determine if the input is a transaction or a query and // uses the Cosmos SDK gas config flat cost and the flat per byte cost * len(argBz) to calculate the gas. func (p Precompile) RequiredGas(input []byte, isTransaction bool) uint64 { - argsBz := input[4:] - if isTransaction { - return p.KvGasConfig.WriteCostFlat + (p.KvGasConfig.WriteCostPerByte * uint64(len(argsBz))) + return p.KvGasConfig.WriteCostFlat + (p.KvGasConfig.WriteCostPerByte * uint64(len(input))) } - return p.KvGasConfig.ReadCostFlat + (p.KvGasConfig.ReadCostPerByte * uint64(len(argsBz))) + return p.KvGasConfig.ReadCostFlat + (p.KvGasConfig.ReadCostPerByte * uint64(len(input))) } -// RunSetup runs the initial setup required to run a transaction or a query. -// It returns the sdk Context, EVM stateDB, ABI method, initial gas and calling arguments. -func (p Precompile) RunSetup( - evm *vm.EVM, - contract *vm.Contract, - readOnly bool, - isTransaction func(name *abi.Method) bool, -) (ctx sdk.Context, stateDB *statedb.StateDB, method *abi.Method, gasConfig storetypes.Gas, args []interface{}, err error) { +// Run prepare the native context to execute native action for stateful precompile, +// it manages the snapshot and revert of the multi-store. +func (p Precompile) RunNativeAction(evm *vm.EVM, contract *vm.Contract, action NativeAction) ([]byte, error) { + bz, err := p.runNativeAction(evm, contract, action) + if err != nil { + return ReturnRevertError(evm, err) + } + + return bz, nil +} + +func (p Precompile) runNativeAction(evm *vm.EVM, contract *vm.Contract, action NativeAction) (bz []byte, err error) { stateDB, ok := evm.StateDB.(*statedb.StateDB) if !ok { - return sdk.Context{}, nil, nil, uint64(0), nil, errors.New(ErrNotRunInEvm) + return nil, errors.New(ErrNotRunInEvm) } // get the stateDB cache ctx - ctx, err = stateDB.GetCacheContext() + ctx, err := stateDB.GetCacheContext() if err != nil { - return sdk.Context{}, nil, nil, uint64(0), nil, err + return nil, err } // take a snapshot of the current state before any changes @@ -73,17 +73,61 @@ func (p Precompile) RunSetup( // add precompileCall entry on the stateDB journal // this allows to revert the changes within an evm tx - err = stateDB.AddPrecompileFn(snapshot, events) - if err != nil { - return sdk.Context{}, nil, nil, uint64(0), nil, err + if err := stateDB.AddPrecompileFn(snapshot, events); err != nil { + return nil, err } // commit the current changes in the cache ctx // to get the updated state for the precompile call if err := stateDB.CommitWithCacheCtx(); err != nil { - return sdk.Context{}, nil, nil, uint64(0), nil, err + return nil, err + } + + initialGas := ctx.GasMeter().GasConsumed() + + defer HandleGasError(ctx, contract, initialGas, &err)() + + // set the default SDK gas configuration to track gas usage + // we are changing the gas meter type, so it panics gracefully when out of gas + ctx = ctx.WithGasMeter(storetypes.NewGasMeter(contract.Gas)). + WithKVGasConfig(p.KvGasConfig). + WithTransientKVGasConfig(p.TransientKVGasConfig) + + // we need to consume the gas that was already used by the EVM + ctx.GasMeter().ConsumeGas(initialGas, "creating a new gas meter") + + if p.BalanceHandler != nil { + p.BalanceHandler.BeforeBalanceChange(ctx) + } + + bz, err = action(ctx) + if err != nil { + return bz, err } + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + + if p.BalanceHandler != nil { + if err := p.BalanceHandler.AfterBalanceChange(ctx, stateDB); err != nil { + return nil, err + } + } + + return bz, nil +} + +// SetupABI runs the initial setup required to run a transaction or a query. +// It returns the ABI method, initial gas and calling arguments. +func SetupABI( + api abi.ABI, + contract *vm.Contract, + readOnly bool, + isTransaction func(name *abi.Method) bool, +) (method *abi.Method, args []interface{}, err error) { // NOTE: This is a special case where the calling transaction does not specify a function name. // In this case we default to a `fallback` or `receive` function on the contract. @@ -95,24 +139,24 @@ func (p Precompile) RunSetup( switch { // Case 1: Calldata is empty case isEmptyCallData: - method, err = p.emptyCallData(contract) + method, err = emptyCallData(api, contract) // Case 2: calldata is non-empty but less than 4 bytes needed for a method case isShortCallData: - method, err = p.methodIDCallData() + method, err = methodIDCallData(api) // Case 3: calldata is non-empty and contains the minimum 4 bytes needed for a method case isStandardCallData: - method, err = p.standardCallData(contract) + method, err = standardCallData(api, contract) } if err != nil { - return sdk.Context{}, nil, nil, uint64(0), nil, err + return nil, nil, err } // return error if trying to write to state during a read-only call if readOnly && isTransaction(method) { - return sdk.Context{}, nil, nil, uint64(0), nil, vm.ErrWriteProtection + return nil, nil, vm.ErrWriteProtection } // if the method type is `function` continue looking for arguments @@ -120,23 +164,11 @@ func (p Precompile) RunSetup( argsBz := contract.Input[4:] args, err = method.Inputs.Unpack(argsBz) if err != nil { - return sdk.Context{}, nil, nil, uint64(0), nil, err + return nil, nil, err } } - initialGas := ctx.GasMeter().GasConsumed() - - defer HandleGasError(ctx, contract, initialGas, &err)() - - // set the default SDK gas configuration to track gas usage - // we are changing the gas meter type, so it panics gracefully when out of gas - ctx = ctx.WithGasMeter(storetypes.NewGasMeter(contract.Gas)). - WithKVGasConfig(p.KvGasConfig). - WithTransientKVGasConfig(p.TransientKVGasConfig) - // we need to consume the gas that was already used by the EVM - ctx.GasMeter().ConsumeGas(initialGas, "creating a new gas meter") - - return ctx, stateDB, method, initialGas, args, nil + return method, args, nil } // HandleGasError handles the out of gas panic by resetting the gas meter and returning an error. @@ -162,22 +194,22 @@ func HandleGasError(ctx sdk.Context, contract *vm.Contract, initialGas storetype } func (p Precompile) Address() common.Address { - return p.address + return p.ContractAddress } func (p *Precompile) SetAddress(addr common.Address) { - p.address = addr + p.ContractAddress = addr } // emptyCallData is a helper function that returns the method to be called when the calldata is empty. -func (p Precompile) emptyCallData(contract *vm.Contract) (method *abi.Method, err error) { +func emptyCallData(api abi.ABI, contract *vm.Contract) (method *abi.Method, err error) { switch { // Case 1.1: Send call or transfer tx - 'receive' is called if present and value is transferred - case contract.Value().Sign() > 0 && p.HasReceive(): - return &p.Receive, nil + case contract.Value().Sign() > 0 && api.HasReceive(): + return &api.Receive, nil // Case 1.2: Either 'receive' is not present, or no value is transferred - call 'fallback' if present - case p.HasFallback(): - return &p.Fallback, nil + case api.HasFallback(): + return &api.Fallback, nil // Case 1.3: Neither 'receive' nor 'fallback' are present - return error default: return nil, vm.ErrExecutionReverted @@ -185,39 +217,39 @@ func (p Precompile) emptyCallData(contract *vm.Contract) (method *abi.Method, er } // methodIDCallData is a helper function that returns the method to be called when the calldata is less than 4 bytes. -func (p Precompile) methodIDCallData() (method *abi.Method, err error) { +func methodIDCallData(api abi.ABI) (method *abi.Method, err error) { // Case 2.2: calldata contains less than 4 bytes needed for a method and 'fallback' is not present - return error - if !p.HasFallback() { + if !api.HasFallback() { return nil, vm.ErrExecutionReverted } // Case 2.1: calldata contains less than 4 bytes needed for a method - 'fallback' is called if present - return &p.Fallback, nil + return &api.Fallback, nil } // standardCallData is a helper function that returns the method to be called when the calldata is 4 bytes or more. -func (p Precompile) standardCallData(contract *vm.Contract) (method *abi.Method, err error) { +func standardCallData(api abi.ABI, contract *vm.Contract) (method *abi.Method, err error) { methodID := contract.Input[:4] // NOTE: this function iterates over the method map and returns // the method with the given ID - method, err = p.MethodById(methodID) + method, err = api.MethodById(methodID) // Case 3.1 calldata contains a non-existing method ID, and `fallback` is not present - return error - if err != nil && !p.HasFallback() { + if err != nil && !api.HasFallback() { return nil, err } // Case 3.2: calldata contains a non-existing method ID - 'fallback' is called if present - if err != nil && p.HasFallback() { - return &p.Fallback, nil + if err != nil && api.HasFallback() { + return &api.Fallback, nil } return method, nil } -func (p *Precompile) GetBalanceHandler() *BalanceHandler { - return p.balanceHandler +func (p Precompile) GetBalanceHandler() *BalanceHandler { + return p.BalanceHandler } func (p *Precompile) SetBalanceHandler(bankKeeper BankKeeper) { - p.balanceHandler = NewBalanceHandler(bankKeeper) + p.BalanceHandler = NewBalanceHandler(bankKeeper) } diff --git a/precompiles/distribution/distribution.go b/precompiles/distribution/distribution.go index 7457412f5..4de83614d 100644 --- a/precompiles/distribution/distribution.go +++ b/precompiles/distribution/distribution.go @@ -6,7 +6,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" cmn "github.com/cosmos/evm/precompiles/common" @@ -15,19 +14,33 @@ import ( "cosmossdk.io/core/address" storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" ) var _ vm.PrecompiledContract = &Precompile{} -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS +var ( + // Embed abi json file to the executable binary. Needed when importing as dependency. + // + //go:embed abi.json + f embed.FS + ABI abi.ABI +) + +func init() { + var err error + ABI, err = cmn.LoadABI(f, "abi.json") + if err != nil { + panic(err) + } +} // Precompile defines the precompiled contract for distribution. type Precompile struct { cmn.Precompile + + abi.ABI distributionKeeper cmn.DistributionKeeper distributionMsgServer distributiontypes.MsgServer distributionQuerier distributiontypes.QueryServer @@ -44,32 +57,21 @@ func NewPrecompile( stakingKeeper cmn.StakingKeeper, bankKeeper cmn.BankKeeper, addrCdc address.Codec, -) (*Precompile, error) { - newAbi, err := cmn.LoadABI(f, "abi.json") - if err != nil { - return nil, fmt.Errorf("error loading the distribution ABI %s", err) - } - - p := &Precompile{ +) *Precompile { + return &Precompile{ Precompile: cmn.Precompile{ - ABI: newAbi, KvGasConfig: storetypes.KVGasConfig(), TransientKVGasConfig: storetypes.TransientGasConfig(), + ContractAddress: common.HexToAddress(evmtypes.DistributionPrecompileAddress), + BalanceHandler: cmn.NewBalanceHandler(bankKeeper), }, + ABI: ABI, stakingKeeper: stakingKeeper, distributionKeeper: distributionKeeper, distributionMsgServer: distributionMsgServer, distributionQuerier: distributionQuerier, addrCdc: addrCdc, } - - // SetAddress defines the address of the distribution compile contract. - p.SetAddress(common.HexToAddress(evmtypes.DistributionPrecompileAddress)) - - // Set the balance handler for the precompile. - p.SetBalanceHandler(bankKeeper) - - return p, nil } // RequiredGas calculates the precompiled contract's base gas rate. @@ -92,28 +94,19 @@ func (p Precompile) RequiredGas(input []byte) uint64 { return p.Precompile.RequiredGas(input, p.IsTransaction(method)) } -// Run executes the precompiled contract distribution methods defined in the ABI. -func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - bz, err = p.run(evm, contract, readOnly) - if err != nil { - return cmn.ReturnRevertError(evm, err) - } - - return bz, nil +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { + return p.RunNativeAction(evm, contract, func(ctx sdk.Context) ([]byte, error) { + return p.Execute(ctx, evm.StateDB, contract, readonly) + }) } -func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) +func (p Precompile) Execute(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { + method, args, err := cmn.SetupABI(p.ABI, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } - // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) - - // This handles any out of gas errors that may occur during the execution of a precompile tx or query. - // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + var bz []byte switch method.Name { // Custom transactions @@ -149,24 +142,11 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ bz, err = p.DelegatorWithdrawAddress(ctx, contract, method, args) case CommunityPoolMethod: bz, err = p.CommunityPool(ctx, contract, method, args) + default: + return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) } - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - // Process the native balance changes after the method execution. - if err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil { - return nil, err - } - - return bz, nil + return bz, err } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/erc20/erc20.go b/precompiles/erc20/erc20.go index 7a1575f5f..a78efcd4b 100644 --- a/precompiles/erc20/erc20.go +++ b/precompiles/erc20/erc20.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" ibcutils "github.com/cosmos/evm/ibc" @@ -39,16 +38,29 @@ const ( GasAllowance = 3_225 ) -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS +var ( + // Embed abi json file to the executable binary. Needed when importing as dependency. + // + //go:embed abi.json + f embed.FS + ABI abi.ABI +) + +func init() { + var err error + ABI, err = cmn.LoadABI(f, abiPath) + if err != nil { + panic(err) + } +} var _ vm.PrecompiledContract = &Precompile{} // Precompile defines the precompiled contract for ERC-20. type Precompile struct { cmn.Precompile + + abi.ABI tokenPair erc20types.TokenPair transferKeeper ibcutils.TransferKeeper erc20Keeper Erc20Keeper @@ -69,26 +81,20 @@ func NewPrecompile( bankKeeper cmn.BankKeeper, erc20Keeper Erc20Keeper, transferKeeper ibcutils.TransferKeeper, - erc20ABI abi.ABI, -) (*Precompile, error) { - p := &Precompile{ +) *Precompile { + return &Precompile{ Precompile: cmn.Precompile{ - ABI: erc20ABI, KvGasConfig: storetypes.GasConfig{}, TransientKVGasConfig: storetypes.GasConfig{}, + ContractAddress: tokenPair.GetERC20Contract(), + BalanceHandler: cmn.NewBalanceHandler(bankKeeper), }, + ABI: ABI, tokenPair: tokenPair, BankKeeper: bankKeeper, erc20Keeper: erc20Keeper, transferKeeper: transferKeeper, } - // Address defines the address of the ERC-20 precompile contract. - p.SetAddress(p.tokenPair.GetERC20Contract()) - - // Set the balance handler for the precompile. - p.SetBalanceHandler(bankKeeper) - - return p, nil } // RequiredGas calculates the contract gas used for the @@ -133,17 +139,13 @@ func (p Precompile) RequiredGas(input []byte) uint64 { } } -// Run executes the precompiled contract ERC-20 methods defined in the ABI. -func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - bz, err = p.run(evm, contract, readOnly) - if err != nil { - return cmn.ReturnRevertError(evm, err) - } - - return bz, nil +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { + return p.RunNativeAction(evm, contract, func(ctx sdk.Context) ([]byte, error) { + return p.Execute(ctx, evm.StateDB, contract, readonly) + }) } -func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { +func (p Precompile) Execute(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { // ERC20 precompiles cannot receive funds because they are not managed by an // EOA and will not be possible to recover funds sent to an instance of // them.This check is a safety measure because currently funds cannot be @@ -152,35 +154,12 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ return nil, fmt.Errorf(ErrCannotReceiveFunds, contract.Value().String()) } - ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + method, args, err := cmn.SetupABI(p.ABI, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } - // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) - - // This handles any out of gas errors that may occur during the execution of a precompile tx or query. - // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err)() - - bz, err = p.HandleMethod(ctx, contract, stateDB, method, args) - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - // Process the native balance changes after the method execution. - if err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil { - return nil, err - } - - return bz, nil + return p.HandleMethod(ctx, contract, stateDB, method, args) } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/gov/gov.go b/precompiles/gov/gov.go index 619c1e9be..949baf6e7 100644 --- a/precompiles/gov/gov.go +++ b/precompiles/gov/gov.go @@ -6,14 +6,12 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" cmn "github.com/cosmos/evm/precompiles/common" evmtypes "github.com/cosmos/evm/x/vm/types" "cosmossdk.io/core/address" - "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" @@ -23,26 +21,33 @@ import ( var _ vm.PrecompiledContract = &Precompile{} -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS +var ( + // Embed abi json file to the executable binary. Needed when importing as dependency. + // + //go:embed abi.json + f embed.FS + ABI abi.ABI +) + +func init() { + var err error + ABI, err = cmn.LoadABI(f, "abi.json") + if err != nil { + panic(err) + } +} // Precompile defines the precompiled contract for gov. type Precompile struct { cmn.Precompile + + abi.ABI govMsgServer govtypes.MsgServer govQuerier govtypes.QueryServer codec codec.Codec addrCdc address.Codec } -// LoadABI loads the gov ABI from the embedded abi.json file -// for the gov precompile. -func LoadABI() (abi.ABI, error) { - return cmn.LoadABI(f, "abi.json") -} - // NewPrecompile creates a new gov Precompile instance as a // PrecompiledContract interface. func NewPrecompile( @@ -51,31 +56,20 @@ func NewPrecompile( bankKeeper cmn.BankKeeper, codec codec.Codec, addrCdc address.Codec, -) (*Precompile, error) { - abi, err := LoadABI() - if err != nil { - return nil, err - } - - p := &Precompile{ +) *Precompile { + return &Precompile{ Precompile: cmn.Precompile{ - ABI: abi, KvGasConfig: storetypes.KVGasConfig(), TransientKVGasConfig: storetypes.TransientGasConfig(), + ContractAddress: common.HexToAddress(evmtypes.GovPrecompileAddress), + BalanceHandler: cmn.NewBalanceHandler(bankKeeper), }, + ABI: ABI, govMsgServer: govMsgServer, govQuerier: govQuerier, codec: codec, addrCdc: addrCdc, } - - // SetAddress defines the address of the gov precompiled contract. - p.SetAddress(common.HexToAddress(evmtypes.GovPrecompileAddress)) - - // Set the balance handler for the precompile. - p.SetBalanceHandler(bankKeeper) - - return p, nil } // RequiredGas calculates the precompiled contract's base gas rate. @@ -95,28 +89,19 @@ func (p Precompile) RequiredGas(input []byte) uint64 { return p.Precompile.RequiredGas(input, p.IsTransaction(method)) } -// Run executes the precompiled contract gov methods defined in the ABI. -func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - bz, err = p.run(evm, contract, readOnly) - if err != nil { - return cmn.ReturnRevertError(evm, err) - } - - return bz, nil +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { + return p.RunNativeAction(evm, contract, func(ctx sdk.Context) ([]byte, error) { + return p.Execute(ctx, evm.StateDB, contract, readonly) + }) } -func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) +func (p Precompile) Execute(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { + method, args, err := cmn.SetupABI(p.ABI, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } - // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) - - // This handles any out of gas errors that may occur during the execution of a precompile tx or query. - // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + var bz []byte switch method.Name { // gov transactions @@ -154,23 +139,7 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) } - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - // Process the native balance changes after the method execution. - err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB) - if err != nil { - return nil, err - } - - return bz, nil + return bz, err } // IsTransaction checks if the given method name corresponds to a transaction or query. @@ -183,8 +152,3 @@ func (Precompile) IsTransaction(method *abi.Method) bool { return false } } - -// Logger returns a precompile-specific logger. -func (p Precompile) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("evm extension", "gov") -} diff --git a/precompiles/ics20/ics20.go b/precompiles/ics20/ics20.go index 73f8b177d..59aaa5428 100644 --- a/precompiles/ics20/ics20.go +++ b/precompiles/ics20/ics20.go @@ -6,13 +6,14 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" cmn "github.com/cosmos/evm/precompiles/common" evmtypes "github.com/cosmos/evm/x/vm/types" storetypes "cosmossdk.io/store/types" + + sdk "github.com/cosmos/cosmos-sdk/types" ) // PrecompileAddress of the ICS-20 EVM extension in hex format. @@ -20,13 +21,26 @@ const PrecompileAddress = "0x0000000000000000000000000000000000000802" var _ vm.PrecompiledContract = &Precompile{} -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS +var ( + // Embed abi json file to the executable binary. Needed when importing as dependency. + // + //go:embed abi.json + f embed.FS + ABI abi.ABI +) + +func init() { + var err error + ABI, err = cmn.LoadABI(f, "abi.json") + if err != nil { + panic(err) + } +} type Precompile struct { cmn.Precompile + + abi.ABI bankKeeper cmn.BankKeeper stakingKeeper cmn.StakingKeeper transferKeeper cmn.TransferKeeper @@ -40,31 +54,20 @@ func NewPrecompile( stakingKeeper cmn.StakingKeeper, transferKeeper cmn.TransferKeeper, channelKeeper cmn.ChannelKeeper, -) (*Precompile, error) { - newAbi, err := cmn.LoadABI(f, "abi.json") - if err != nil { - return nil, err - } - - p := &Precompile{ +) *Precompile { + return &Precompile{ Precompile: cmn.Precompile{ - ABI: newAbi, KvGasConfig: storetypes.KVGasConfig(), TransientKVGasConfig: storetypes.TransientGasConfig(), + ContractAddress: common.HexToAddress(evmtypes.ICS20PrecompileAddress), + BalanceHandler: cmn.NewBalanceHandler(bankKeeper), }, + ABI: ABI, bankKeeper: bankKeeper, transferKeeper: transferKeeper, channelKeeper: channelKeeper, stakingKeeper: stakingKeeper, } - - // SetAddress defines the address of the ICS-20 compile contract. - p.SetAddress(common.HexToAddress(evmtypes.ICS20PrecompileAddress)) - - // Set the balance handler for the precompile. - p.SetBalanceHandler(bankKeeper) - - return p, nil } // RequiredGas calculates the precompiled contract's base gas rate. @@ -85,28 +88,19 @@ func (p Precompile) RequiredGas(input []byte) uint64 { return p.Precompile.RequiredGas(input, p.IsTransaction(method)) } -// Run executes the precompiled contract IBC transfer methods defined in the ABI. -func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - bz, err = p.run(evm, contract, readOnly) - if err != nil { - return cmn.ReturnRevertError(evm, err) - } - - return bz, nil +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { + return p.RunNativeAction(evm, contract, func(ctx sdk.Context) ([]byte, error) { + return p.Execute(ctx, evm.StateDB, contract, readonly) + }) } -func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) +func (p Precompile) Execute(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { + method, args, err := cmn.SetupABI(p.ABI, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } - // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) - - // This handles any out of gas errors that may occur during the execution of a precompile tx or query. - // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + var bz []byte switch method.Name { // ICS20 transactions @@ -123,22 +117,7 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) } - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - // Process the native balance changes after the method execution. - if err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil { - return nil, err - } - - return bz, nil + return bz, err } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/slashing/slashing.go b/precompiles/slashing/slashing.go index f5287ce44..14813338a 100644 --- a/precompiles/slashing/slashing.go +++ b/precompiles/slashing/slashing.go @@ -6,7 +6,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" cmn "github.com/cosmos/evm/precompiles/common" @@ -23,26 +22,33 @@ import ( var _ vm.PrecompiledContract = &Precompile{} -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS +var ( + // Embed abi json file to the executable binary. Needed when importing as dependency. + // + //go:embed abi.json + f embed.FS + ABI abi.ABI +) + +func init() { + var err error + ABI, err = cmn.LoadABI(f, "abi.json") + if err != nil { + panic(err) + } +} // Precompile defines the precompiled contract for slashing. type Precompile struct { cmn.Precompile + + abi.ABI slashingKeeper cmn.SlashingKeeper slashingMsgServer slashingtypes.MsgServer consCodec runtime.ConsensusAddressCodec valCodec runtime.ValidatorAddressCodec } -// LoadABI loads the slashing ABI from the embedded abi.json file -// for the slashing precompile. -func LoadABI() (abi.ABI, error) { - return cmn.LoadABI(f, "abi.json") -} - // NewPrecompile creates a new slashing Precompile instance as a // PrecompiledContract interface. func NewPrecompile( @@ -50,31 +56,20 @@ func NewPrecompile( slashingMsgServer slashingtypes.MsgServer, bankKeeper cmn.BankKeeper, valCdc, consCdc address.Codec, -) (*Precompile, error) { - abi, err := LoadABI() - if err != nil { - return nil, err - } - - p := &Precompile{ +) *Precompile { + return &Precompile{ Precompile: cmn.Precompile{ - ABI: abi, KvGasConfig: storetypes.KVGasConfig(), TransientKVGasConfig: storetypes.TransientGasConfig(), + ContractAddress: common.HexToAddress(evmtypes.SlashingPrecompileAddress), + BalanceHandler: cmn.NewBalanceHandler(bankKeeper), }, + ABI: ABI, slashingKeeper: slashingKeeper, slashingMsgServer: slashingMsgServer, valCodec: valCdc, consCodec: consCdc, } - - // SetAddress defines the address of the slashing precompiled contract. - p.SetAddress(common.HexToAddress(evmtypes.SlashingPrecompileAddress)) - - // Set the balance handler for the precompile. - p.SetBalanceHandler(bankKeeper) - - return p, nil } // RequiredGas calculates the precompiled contract's base gas rate. @@ -94,28 +89,19 @@ func (p Precompile) RequiredGas(input []byte) uint64 { return p.Precompile.RequiredGas(input, p.IsTransaction(method)) } -// Run executes the precompiled contract slashing methods defined in the ABI. -func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - bz, err = p.run(evm, contract, readOnly) - if err != nil { - return cmn.ReturnRevertError(evm, err) - } - - return bz, nil +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { + return p.RunNativeAction(evm, contract, func(ctx sdk.Context) ([]byte, error) { + return p.Execute(ctx, evm.StateDB, contract, readonly) + }) } -func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) +func (p Precompile) Execute(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { + method, args, err := cmn.SetupABI(p.ABI, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } - // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) - - // This handles any out of gas errors that may occur during the execution of a precompile tx or query. - // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + var bz []byte switch method.Name { // slashing transactions @@ -132,22 +118,7 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) } - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - // Process the native balance changes after the method execution. - if err := p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil { - return nil, err - } - - return bz, nil + return bz, err } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go index 78aad51f1..04ace5b85 100644 --- a/precompiles/staking/staking.go +++ b/precompiles/staking/staking.go @@ -2,10 +2,10 @@ package staking import ( "embed" + "fmt" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" cmn "github.com/cosmos/evm/precompiles/common" @@ -21,26 +21,33 @@ import ( var _ vm.PrecompiledContract = &Precompile{} -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS +var ( + // Embed abi json file to the executable binary. Needed when importing as dependency. + // + //go:embed abi.json + f embed.FS + ABI abi.ABI +) + +func init() { + var err error + ABI, err = cmn.LoadABI(f, "abi.json") + if err != nil { + panic(err) + } +} // Precompile defines the precompiled contract for staking. type Precompile struct { cmn.Precompile + + abi.ABI stakingKeeper cmn.StakingKeeper stakingMsgServer stakingtypes.MsgServer stakingQuerier stakingtypes.QueryServer addrCdc address.Codec } -// LoadABI loads the staking ABI from the embedded abi.json file -// for the staking precompile. -func LoadABI() (abi.ABI, error) { - return cmn.LoadABI(f, "abi.json") -} - // NewPrecompile creates a new staking Precompile instance as a // PrecompiledContract interface. func NewPrecompile( @@ -49,30 +56,20 @@ func NewPrecompile( stakingQuerier stakingtypes.QueryServer, bankKeeper cmn.BankKeeper, addrCdc address.Codec, -) (*Precompile, error) { - abi, err := LoadABI() - if err != nil { - return nil, err - } - - p := &Precompile{ +) *Precompile { + return &Precompile{ Precompile: cmn.Precompile{ - ABI: abi, KvGasConfig: storetypes.KVGasConfig(), TransientKVGasConfig: storetypes.TransientGasConfig(), + ContractAddress: common.HexToAddress(evmtypes.StakingPrecompileAddress), + BalanceHandler: cmn.NewBalanceHandler(bankKeeper), }, + ABI: ABI, stakingKeeper: stakingKeeper, stakingMsgServer: stakingMsgServer, stakingQuerier: stakingQuerier, addrCdc: addrCdc, } - // SetAddress defines the address of the staking precompiled contract. - p.SetAddress(common.HexToAddress(evmtypes.StakingPrecompileAddress)) - - // Set the balance handler for the precompile. - p.SetBalanceHandler(bankKeeper) - - return p, nil } // RequiredGas returns the required bare minimum gas to execute the precompile. @@ -93,27 +90,19 @@ func (p Precompile) RequiredGas(input []byte) uint64 { return p.Precompile.RequiredGas(input, p.IsTransaction(method)) } -// Run executes the precompiled contract staking methods defined in the ABI. -func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - bz, err = p.run(evm, contract, readOnly) - if err != nil { - return cmn.ReturnRevertError(evm, err) - } - return bz, nil +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { + return p.RunNativeAction(evm, contract, func(ctx sdk.Context) ([]byte, error) { + return p.Execute(ctx, evm.StateDB, contract, readonly) + }) } -func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) +func (p Precompile) Execute(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { + method, args, err := cmn.SetupABI(p.ABI, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } - // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) - - // This handles any out of gas errors that may occur during the execution of a precompile tx or query. - // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + var bz []byte switch method.Name { // Staking transactions @@ -142,24 +131,11 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ bz, err = p.Redelegation(ctx, method, contract, args) case RedelegationsMethod: bz, err = p.Redelegations(ctx, method, contract, args) + default: + return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) } - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - // Process the native balance changes after the method execution. - if err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil { - return nil, err - } - - return bz, nil + return bz, err } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/types/defaults.go b/precompiles/types/defaults.go index b64570365..49cb44125 100644 --- a/precompiles/types/defaults.go +++ b/precompiles/types/defaults.go @@ -100,18 +100,15 @@ func DefaultStaticPrecompiles( panic(fmt.Errorf("failed to instantiate bech32 precompile: %w", err)) } - stakingPrecompile, err := stakingprecompile.NewPrecompile( + stakingPrecompile := stakingprecompile.NewPrecompile( stakingKeeper, stakingkeeper.NewMsgServerImpl(&stakingKeeper), stakingkeeper.NewQuerier(&stakingKeeper), bankKeeper, options.AddressCodec, ) - if err != nil { - panic(fmt.Errorf("failed to instantiate staking precompile: %w", err)) - } - distributionPrecompile, err := distprecompile.NewPrecompile( + distributionPrecompile := distprecompile.NewPrecompile( distributionKeeper, distributionkeeper.NewMsgServerImpl(distributionKeeper), distributionkeeper.NewQuerier(distributionKeeper), @@ -119,46 +116,31 @@ func DefaultStaticPrecompiles( bankKeeper, options.AddressCodec, ) - if err != nil { - panic(fmt.Errorf("failed to instantiate distribution precompile: %w", err)) - } - ibcTransferPrecompile, err := ics20precompile.NewPrecompile( + ibcTransferPrecompile := ics20precompile.NewPrecompile( bankKeeper, stakingKeeper, transferKeeper, channelKeeper, ) - if err != nil { - panic(fmt.Errorf("failed to instantiate ICS20 precompile: %w", err)) - } - bankPrecompile, err := bankprecompile.NewPrecompile(bankKeeper, erc20Keeper) - if err != nil { - panic(fmt.Errorf("failed to instantiate bank precompile: %w", err)) - } + bankPrecompile := bankprecompile.NewPrecompile(bankKeeper, erc20Keeper) - govPrecompile, err := govprecompile.NewPrecompile( + govPrecompile := govprecompile.NewPrecompile( govkeeper.NewMsgServerImpl(&govKeeper), govkeeper.NewQueryServer(&govKeeper), bankKeeper, codec, options.AddressCodec, ) - if err != nil { - panic(fmt.Errorf("failed to instantiate gov precompile: %w", err)) - } - slashingPrecompile, err := slashingprecompile.NewPrecompile( + slashingPrecompile := slashingprecompile.NewPrecompile( slashingKeeper, slashingkeeper.NewMsgServerImpl(slashingKeeper), bankKeeper, options.ValidatorAddrCodec, options.ConsensusAddrCodec, ) - if err != nil { - panic(fmt.Errorf("failed to instantiate slashing precompile: %w", err)) - } // Stateless precompiles precompiles[bech32Precompile.Address()] = bech32Precompile diff --git a/precompiles/werc20/werc20.go b/precompiles/werc20/werc20.go index 514eb717b..b9e67623e 100644 --- a/precompiles/werc20/werc20.go +++ b/precompiles/werc20/werc20.go @@ -2,27 +2,37 @@ package werc20 import ( "embed" - "fmt" "slices" "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" ibcutils "github.com/cosmos/evm/ibc" cmn "github.com/cosmos/evm/precompiles/common" erc20 "github.com/cosmos/evm/precompiles/erc20" erc20types "github.com/cosmos/evm/x/erc20/types" + + sdk "github.com/cosmos/cosmos-sdk/types" ) // abiPath defines the path to the WERC-20 precompile ABI JSON file. const abiPath = "abi.json" -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS +var ( + // Embed abi json file to the executable binary. Needed when importing as dependency. + // + //go:embed abi.json + f embed.FS + ABI abi.ABI +) + +func init() { + var err error + ABI, err = cmn.LoadABI(f, abiPath) + if err != nil { + panic(err) + } +} var _ vm.PrecompiledContract = &Precompile{} @@ -38,12 +48,6 @@ const ( WithdrawRequiredGas uint64 = 9207 ) -// LoadABI loads the IWERC20 ABI from the embedded abi.json file -// for the werc20 precompile. -func LoadABI() (abi.ABI, error) { - return cmn.LoadABI(f, abiPath) -} - // NewPrecompile creates a new WERC20 Precompile instance implementing the // PrecompiledContract interface. This type wraps around the ERC20 Precompile // instance to provide additional methods. @@ -52,25 +56,15 @@ func NewPrecompile( bankKeeper cmn.BankKeeper, erc20Keeper Erc20Keeper, transferKeeper ibcutils.TransferKeeper, - erc20ABI abi.ABI, - werc20ABI abi.ABI, -) (*Precompile, error) { - erc20Precompile, err := erc20.NewPrecompile(tokenPair, bankKeeper, erc20Keeper, transferKeeper, erc20ABI) - if err != nil { - return nil, fmt.Errorf("error instantiating the ERC20 precompile: %w", err) - } +) *Precompile { + erc20Precompile := erc20.NewPrecompile(tokenPair, bankKeeper, erc20Keeper, transferKeeper) // use the IWERC20 ABI - erc20Precompile.ABI = werc20ABI + erc20Precompile.ABI = ABI return &Precompile{ Precompile: erc20Precompile, - }, nil -} - -// Address returns the address of the WERC20 precompiled contract. -func (p Precompile) Address() common.Address { - return p.Precompile.Address() + } } // RequiredGas calculates the contract gas use. @@ -100,29 +94,19 @@ func (p Precompile) RequiredGas(input []byte) uint64 { } } -// Run executes the precompiled contract WERC20 methods defined in the ABI. -func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - bz, err = p.run(evm, contract, readOnly) - if err != nil { - return cmn.ReturnRevertError(evm, err) - } - - return bz, nil +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { + return p.RunNativeAction(evm, contract, func(ctx sdk.Context) ([]byte, error) { + return p.Execute(ctx, evm.StateDB, contract, readonly) + }) } -func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) +func (p Precompile) Execute(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Contract, readOnly bool) ([]byte, error) { + method, args, err := cmn.SetupABI(p.ABI, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } - // Start the balance change handler before executing the precompile. - p.GetBalanceHandler().BeforeBalanceChange(ctx) - - // This handles any out of gas errors that may occur during the execution of - // a precompile tx or query. It avoids panics and returns the out of gas error so - // the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + var bz []byte switch { case method.Type == abi.Fallback, @@ -136,22 +120,7 @@ func (p Precompile) run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ bz, err = p.HandleMethod(ctx, contract, stateDB, method, args) } - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - // Process the native balance changes after the method execution. - if err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil { - return nil, err - } - - return bz, nil + return bz, err } // IsTransaction returns true if the given method name correspond to a diff --git a/tests/integration/precompiles/bank/test_query.go b/tests/integration/precompiles/bank/test_query.go index e4f750666..d7dc3a0e4 100644 --- a/tests/integration/precompiles/bank/test_query.go +++ b/tests/integration/precompiles/bank/test_query.go @@ -110,7 +110,6 @@ func (s *PrecompileTestSuite) TestBalances() { bz, err := s.precompile.Balances( ctx, - nil, &method, tc.malleate(), ) @@ -167,7 +166,6 @@ func (s *PrecompileTestSuite) TestTotalSupply() { tc.malleate() bz, err := s.precompile.TotalSupply( ctx, - nil, &method, nil, ) @@ -262,7 +260,6 @@ func (s *PrecompileTestSuite) TestSupplyOf() { bz, err := s.precompile.SupplyOf( ctx, - nil, &method, tc.malleate(), ) diff --git a/tests/integration/precompiles/bank/test_utils.go b/tests/integration/precompiles/bank/test_utils.go index 0099a21ac..4f322d630 100644 --- a/tests/integration/precompiles/bank/test_utils.go +++ b/tests/integration/precompiles/bank/test_utils.go @@ -21,25 +21,19 @@ import ( // setupBankPrecompile is a helper function to set up an instance of the Bank precompile for // a given token denomination. func (s *PrecompileTestSuite) setupBankPrecompile() *bank.Precompile { - precompile, err := bank.NewPrecompile( + return bank.NewPrecompile( s.network.App.GetBankKeeper(), *s.network.App.GetErc20Keeper(), ) - - s.Require().NoError(err, "failed to create bank precompile") - - return precompile } // setupBankPrecompile is a helper function to set up an instance of the Bank precompile for // a given token denomination. func (is *IntegrationTestSuite) setupBankPrecompile() *bank.Precompile { - precompile, err := bank.NewPrecompile( + return bank.NewPrecompile( is.network.App.GetBankKeeper(), *is.network.App.GetErc20Keeper(), ) - Expect(err).ToNot(HaveOccurred(), "failed to create bank precompile") - return precompile } // mintAndSendXMPLCoin is a helper function to mint and send a coin to a given address. diff --git a/tests/integration/precompiles/distribution/test_integration.go b/tests/integration/precompiles/distribution/test_integration.go index 53500a6b6..c59bc6cde 100644 --- a/tests/integration/precompiles/distribution/test_integration.go +++ b/tests/integration/precompiles/distribution/test_integration.go @@ -1346,8 +1346,7 @@ func TestPrecompileIntegrationTestSuite(t *testing.T, create network.CreateEvmAp Expect(cAcc.IsContract()).To(BeTrue(), "account should be a contract") // Contract delegate - stkPrecompile, err := s.getStakingPrecompile() - Expect(err).To(BeNil(), "error while getting staking precompile: %v", err) + stkPrecompile := s.getStakingPrecompile() // make a delegation with contract as delegator logCheck := testutil.LogCheckArgs{ ExpPass: true, @@ -1870,8 +1869,7 @@ func TestPrecompileIntegrationTestSuite(t *testing.T, create network.CreateEvmAp Expect(err).To(BeNil()) Expect(s.network.NextBlock()).To(BeNil()) - stkPrecompile, err := s.getStakingPrecompile() - Expect(err).To(BeNil()) + stkPrecompile := s.getStakingPrecompile() // make a delegation with contract as delegator logCheck := testutil.LogCheckArgs{ ExpPass: true, @@ -2057,8 +2055,7 @@ func TestPrecompileIntegrationTestSuite(t *testing.T, create network.CreateEvmAp Expect(err).To(BeNil()) Expect(s.network.NextBlock()).To(BeNil()) - stkPrecompile, err := s.getStakingPrecompile() - Expect(err).To(BeNil()) + stkPrecompile := s.getStakingPrecompile() // make a delegation with contract as delegator logCheck := testutil.LogCheckArgs{ ExpPass: true, @@ -2324,8 +2321,7 @@ func TestPrecompileIntegrationTestSuite(t *testing.T, create network.CreateEvmAp Expect(err).To(BeNil()) Expect(s.network.NextBlock()).To(BeNil()) - stkPrecompile, err := s.getStakingPrecompile() - Expect(err).To(BeNil()) + stkPrecompile := s.getStakingPrecompile() // make a delegation with contract as delegator logCheck := testutil.LogCheckArgs{ ExpPass: true, diff --git a/tests/integration/precompiles/distribution/test_setup.go b/tests/integration/precompiles/distribution/test_setup.go index 57b15cb85..6f219b5a5 100644 --- a/tests/integration/precompiles/distribution/test_setup.go +++ b/tests/integration/precompiles/distribution/test_setup.go @@ -130,7 +130,7 @@ func (s *PrecompileTestSuite) SetupTest() { s.grpcHandler = grpcHandler s.keyring = keyring s.network = nw - s.precompile, err = distribution.NewPrecompile( + s.precompile = distribution.NewPrecompile( s.network.App.GetDistrKeeper(), distrkeeper.NewMsgServerImpl(s.network.App.GetDistrKeeper()), distrkeeper.NewQuerier(s.network.App.GetDistrKeeper()), @@ -138,7 +138,4 @@ func (s *PrecompileTestSuite) SetupTest() { s.network.App.GetBankKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), ) - if err != nil { - panic(err) - } } diff --git a/tests/integration/precompiles/distribution/test_utils.go b/tests/integration/precompiles/distribution/test_utils.go index 13ddda323..adbece8b4 100644 --- a/tests/integration/precompiles/distribution/test_utils.go +++ b/tests/integration/precompiles/distribution/test_utils.go @@ -82,7 +82,7 @@ func (s *PrecompileTestSuite) fundAccountWithBaseDenom(ctx sdk.Context, addr sdk return s.network.App.GetBankKeeper().SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, coins) } -func (s *PrecompileTestSuite) getStakingPrecompile() (*staking.Precompile, error) { +func (s *PrecompileTestSuite) getStakingPrecompile() *staking.Precompile { return staking.NewPrecompile( *s.network.App.GetStakingKeeper(), stakingkeeper.NewMsgServerImpl(s.network.App.GetStakingKeeper()), diff --git a/tests/integration/precompiles/erc20/test_setup.go b/tests/integration/precompiles/erc20/test_setup.go index d6d2fad43..a79ee864a 100644 --- a/tests/integration/precompiles/erc20/test_setup.go +++ b/tests/integration/precompiles/erc20/test_setup.go @@ -68,13 +68,9 @@ func (s *PrecompileTestSuite) SetupTest() { s.precompile, err = s.setupERC20Precompile(s.tokenDenom) s.Require().NoError(err) - erc20ABI, err := erc20.LoadABI() - s.Require().NoError(err) - // Instantiate the precompile2 with the bond denom (the token pair was already set up in genesis). tokenPairID := s.network.App.GetErc20Keeper().GetDenomMap(s.network.GetContext(), bondDenom) tokenPair, found := s.network.App.GetErc20Keeper().GetTokenPair(s.network.GetContext(), tokenPairID) s.Require().True(found) - s.precompile2, err = erc20.NewPrecompile(tokenPair, s.network.App.GetBankKeeper(), s.network.App.GetErc20Keeper(), s.network.App.GetTransferKeeper(), erc20ABI) - s.Require().NoError(err) + s.precompile2 = erc20.NewPrecompile(tokenPair, s.network.App.GetBankKeeper(), s.network.App.GetErc20Keeper(), s.network.App.GetTransferKeeper()) } diff --git a/tests/integration/precompiles/erc20/test_utils.go b/tests/integration/precompiles/erc20/test_utils.go index 31e75c6b3..e68530faa 100644 --- a/tests/integration/precompiles/erc20/test_utils.go +++ b/tests/integration/precompiles/erc20/test_utils.go @@ -171,19 +171,12 @@ func (is *IntegrationTestSuite) setupERC20Precompile(denom string, tokenPairs [] tokenPair = tp } - erc20ABI, err := erc20.LoadABI() - Expect(err).To(BeNil()) - - precompile, err := erc20.NewPrecompile( + return erc20.NewPrecompile( tokenPair, is.network.App.GetBankKeeper(), is.network.App.GetErc20Keeper(), is.network.App.GetTransferKeeper(), - erc20ABI, ) - Expect(err).ToNot(HaveOccurred(), "failed to set up %q erc20 precompile", tokenPair.Denom) - - return precompile } // setupERC20PrecompileForTokenPair is a helper function to set up an instance of the ERC20 precompile for @@ -192,26 +185,16 @@ func (is *IntegrationTestSuite) setupERC20Precompile(denom string, tokenPairs [] func setupERC20PrecompileForTokenPair( unitNetwork network.UnitTestNetwork, tokenPair erc20types.TokenPair, ) (*erc20.Precompile, error) { - erc20ABI, err := erc20.LoadABI() - if err != nil { - return nil, err - } - precompile, err := erc20.NewPrecompile( + precompile := erc20.NewPrecompile( tokenPair, unitNetwork.App.GetBankKeeper(), unitNetwork.App.GetErc20Keeper(), unitNetwork.App.GetTransferKeeper(), - erc20ABI, ) - if err != nil { - return nil, errorsmod.Wrapf(err, "failed to create %q erc20 precompile", tokenPair.Denom) - } - - err = unitNetwork.App.GetErc20Keeper().EnableDynamicPrecompile( + if err := unitNetwork.App.GetErc20Keeper().EnableDynamicPrecompile( unitNetwork.GetContext(), precompile.Address(), - ) - if err != nil { + ); err != nil { return nil, errorsmod.Wrapf(err, "failed to add %q erc20 precompile to EVM extensions", tokenPair.Denom) } @@ -224,20 +207,12 @@ func setupERC20PrecompileForTokenPair( func (is *IntegrationTestSuite) setupNewERC20PrecompileForTokenPair( tokenPair erc20types.TokenPair, ) (*erc20.Precompile, error) { - erc20ABI, err := erc20.LoadABI() - if err != nil { - return nil, err - } - precompile, err := erc20.NewPrecompile( + precompile := erc20.NewPrecompile( tokenPair, is.network.App.GetBankKeeper(), is.network.App.GetErc20Keeper(), is.network.App.GetTransferKeeper(), - erc20ABI, ) - if err != nil { - return nil, errorsmod.Wrapf(err, "failed to create %q erc20 precompile", tokenPair.Denom) - } // Update the params via gov proposal if err := is.network.App.GetErc20Keeper().EnableDynamicPrecompile(is.network.GetContext(), precompile.Address()); err != nil { diff --git a/tests/integration/precompiles/gov/test_setup.go b/tests/integration/precompiles/gov/test_setup.go index 312f91b47..69216147e 100644 --- a/tests/integration/precompiles/gov/test_setup.go +++ b/tests/integration/precompiles/gov/test_setup.go @@ -138,13 +138,11 @@ func (s *PrecompileTestSuite) SetupTest() { s.network = nw govKeeper := s.network.App.GetGovKeeper() - if s.precompile, err = gov.NewPrecompile( + s.precompile = gov.NewPrecompile( govkeeper.NewMsgServerImpl(&govKeeper), govkeeper.NewQueryServer(&govKeeper), s.network.App.GetBankKeeper(), s.network.App.AppCodec(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), - ); err != nil { - panic(err) - } + ) } diff --git a/tests/integration/precompiles/ics20/test_setup.go b/tests/integration/precompiles/ics20/test_setup.go index 462e7c6b7..cd90158c5 100644 --- a/tests/integration/precompiles/ics20/test_setup.go +++ b/tests/integration/precompiles/ics20/test_setup.go @@ -43,7 +43,7 @@ func (s *PrecompileTestSuite) SetupTest() { s.chainB = s.coordinator.GetChain(evmibctesting.GetEvmChainID(2)) evmAppA := s.chainA.App.(evm.EvmApp) - s.chainAPrecompile, _ = ics20.NewPrecompile( + s.chainAPrecompile = ics20.NewPrecompile( evmAppA.GetBankKeeper(), *evmAppA.GetStakingKeeper(), evmAppA.GetTransferKeeper(), @@ -51,7 +51,7 @@ func (s *PrecompileTestSuite) SetupTest() { ) s.chainABondDenom, _ = evmAppA.GetStakingKeeper().BondDenom(s.chainA.GetContext()) evmAppB := s.chainB.App.(evm.EvmApp) - s.chainBPrecompile, _ = ics20.NewPrecompile( + s.chainBPrecompile = ics20.NewPrecompile( evmAppB.GetBankKeeper(), *evmAppB.GetStakingKeeper(), evmAppB.GetTransferKeeper(), diff --git a/tests/integration/precompiles/slashing/test_setup.go b/tests/integration/precompiles/slashing/test_setup.go index f5118c5e6..faef7a821 100644 --- a/tests/integration/precompiles/slashing/test_setup.go +++ b/tests/integration/precompiles/slashing/test_setup.go @@ -36,7 +36,6 @@ func NewPrecompileTestSuite(create network.CreateEvmApp, options ...network.Conf func (s *PrecompileTestSuite) SetupTest() { keyring := testkeyring.New(3) - var err error options := []network.ConfigOption{ network.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), network.WithValidatorOperators([]sdk.AccAddress{ @@ -55,13 +54,11 @@ func (s *PrecompileTestSuite) SetupTest() { s.grpcHandler = grpcHandler s.keyring = keyring - if s.precompile, err = slashing.NewPrecompile( + s.precompile = slashing.NewPrecompile( s.network.App.GetSlashingKeeper(), slashingkeeper.NewMsgServerImpl(s.network.App.GetSlashingKeeper()), s.network.App.GetBankKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()), address.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()), - ); err != nil { - panic(err) - } + ) } diff --git a/tests/integration/precompiles/staking/test_setup.go b/tests/integration/precompiles/staking/test_setup.go index cb4e04d63..764d22559 100644 --- a/tests/integration/precompiles/staking/test_setup.go +++ b/tests/integration/precompiles/staking/test_setup.go @@ -81,13 +81,11 @@ func (s *PrecompileTestSuite) SetupTest() { s.keyring = keyring s.network = nw - if s.precompile, err = staking.NewPrecompile( + s.precompile = staking.NewPrecompile( *s.network.App.GetStakingKeeper(), stakingkeeper.NewMsgServerImpl(s.network.App.GetStakingKeeper()), stakingkeeper.NewQuerier(s.network.App.GetStakingKeeper()), s.network.App.GetBankKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), - ); err != nil { - panic(err) - } + ) } diff --git a/tests/integration/precompiles/staking/test_staking.go b/tests/integration/precompiles/staking/test_staking.go index d8b5149dc..f66a2ba1a 100644 --- a/tests/integration/precompiles/staking/test_staking.go +++ b/tests/integration/precompiles/staking/test_staking.go @@ -92,7 +92,7 @@ func (s *PrecompileTestSuite) TestRequiredGas() { s.Require().NoError(err) return input }, - 7760, + 0x1ec8, }, { "success - undelegate transaction with correct gas estimation", @@ -106,7 +106,7 @@ func (s *PrecompileTestSuite) TestRequiredGas() { s.Require().NoError(err) return input }, - 7760, + 0x1ec8, }, } @@ -381,7 +381,7 @@ func (s *PrecompileTestSuite) TestRun() { s.Require().NoError(err, "failed to pack input") return input }, - 1, // use gas > 0 to avoid doing gas estimation + 19103, // use enough gas to avoid out of gas error true, false, "write protection", @@ -391,7 +391,7 @@ func (s *PrecompileTestSuite) TestRun() { func(_ keyring.Key) []byte { return []byte("invalid") }, - 1, // use gas > 0 to avoid doing gas estimation + 19103, // use enough gas to avoid out of gas error false, false, "no method with id", diff --git a/tests/integration/precompiles/werc20/test_events.go b/tests/integration/precompiles/werc20/test_events.go index 8d1a3be45..5f3308746 100644 --- a/tests/integration/precompiles/werc20/test_events.go +++ b/tests/integration/precompiles/werc20/test_events.go @@ -8,7 +8,6 @@ import ( "github.com/stretchr/testify/suite" cmn "github.com/cosmos/evm/precompiles/common" - "github.com/cosmos/evm/precompiles/erc20" "github.com/cosmos/evm/precompiles/werc20" testconstants "github.com/cosmos/evm/testutil/constants" "github.com/cosmos/evm/testutil/integration/evm/factory" @@ -73,20 +72,12 @@ func (s *PrecompileUnitTestSuite) SetupTest(chainID testconstants.ChainID) { s.Require().True(found, "expected wevmos precompile to be registered in the tokens map") s.Require().Equal(s.precompileAddrHex, tokenPair.Erc20Address, "expected a different address of the contract") - erc20ABI, err := erc20.LoadABI() - s.Require().NoError(err) - werc20ABI, err := werc20.LoadABI() - s.Require().NoError(err) - - precompile, err := werc20.NewPrecompile( + precompile := werc20.NewPrecompile( tokenPair, s.network.App.GetBankKeeper(), s.network.App.GetErc20Keeper(), s.network.App.GetTransferKeeper(), - erc20ABI, - werc20ABI, ) - s.Require().NoError(err, "failed to instantiate the werc20 precompile") s.Require().NotNil(precompile) s.precompile = precompile } diff --git a/tests/integration/precompiles/werc20/test_integration.go b/tests/integration/precompiles/werc20/test_integration.go index 3185954d7..9dfbf865c 100644 --- a/tests/integration/precompiles/werc20/test_integration.go +++ b/tests/integration/precompiles/werc20/test_integration.go @@ -161,20 +161,12 @@ func TestPrecompileIntegrationTestSuite(t *testing.T, create network.CreateEvmAp erc20types.OWNER_MODULE, ) - erc20ABI, err := erc20.LoadABI() - Expect(err).To(BeNil()) - werc20ABI, err := werc20.LoadABI() - Expect(err).To(BeNil()) - - precompile, err := werc20.NewPrecompile( + precompile := werc20.NewPrecompile( tokenPair, is.network.App.GetBankKeeper(), is.network.App.GetErc20Keeper(), is.network.App.GetTransferKeeper(), - erc20ABI, - werc20ABI, ) - Expect(err).ToNot(HaveOccurred(), "failed to instantiate the werc20 precompile") is.precompile = precompile // Setup of the contract calling into the precompile to tests revert diff --git a/x/erc20/keeper/keeper.go b/x/erc20/keeper/keeper.go index ce800a645..1123b25d4 100644 --- a/x/erc20/keeper/keeper.go +++ b/x/erc20/keeper/keeper.go @@ -3,10 +3,6 @@ package keeper import ( "fmt" - "github.com/ethereum/go-ethereum/accounts/abi" - - "github.com/cosmos/evm/precompiles/erc20" - "github.com/cosmos/evm/precompiles/werc20" "github.com/cosmos/evm/x/erc20/types" transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" @@ -29,10 +25,6 @@ type Keeper struct { evmKeeper types.EVMKeeper stakingKeeper types.StakingKeeper transferKeeper *transferkeeper.Keeper - - // cached abis - erc20ABI abi.ABI - werc20ABI abi.ABI } // NewKeeper creates new instances of the erc20 Keeper @@ -51,16 +43,6 @@ func NewKeeper( panic(err) } - erc20ABI, err := erc20.LoadABI() - if err != nil { - panic(err) - } - - werc20ABI, err := werc20.LoadABI() - if err != nil { - panic(err) - } - return Keeper{ authority: authority, storeKey: storeKey, @@ -70,8 +52,6 @@ func NewKeeper( evmKeeper: evmKeeper, stakingKeeper: sk, transferKeeper: transferKeeper, - erc20ABI: erc20ABI, - werc20ABI: werc20ABI, } } diff --git a/x/erc20/keeper/precompiles.go b/x/erc20/keeper/precompiles.go index 9daa52414..95e40d8f0 100644 --- a/x/erc20/keeper/precompiles.go +++ b/x/erc20/keeper/precompiles.go @@ -62,10 +62,10 @@ func (k Keeper) InstantiateERC20Precompile(ctx sdk.Context, contractAddr common. } if hasWrappedMethods { - return werc20.NewPrecompile(pair, k.bankKeeper, k, *k.transferKeeper, k.erc20ABI, k.werc20ABI) + return werc20.NewPrecompile(pair, k.bankKeeper, k, *k.transferKeeper), nil } - return erc20.NewPrecompile(pair, k.bankKeeper, k, *k.transferKeeper, k.erc20ABI) + return erc20.NewPrecompile(pair, k.bankKeeper, k, *k.transferKeeper), nil } // RegisterCodeHash checks if a new precompile already exists and registers the code hash it is not