99 bank "github.com/cosmos/cosmos-sdk/x/bank/types"
1010 gethabi "github.com/ethereum/go-ethereum/accounts/abi"
1111 gethcommon "github.com/ethereum/go-ethereum/common"
12- "github.com/ethereum/go-ethereum/core/tracing"
1312 "github.com/ethereum/go-ethereum/core/vm"
1413
1514 bankkeeper "github.com/NibiruChain/nibiru/v2/x/bank/keeper"
@@ -22,7 +21,10 @@ import (
2221 tftypes "github.com/NibiruChain/nibiru/v2/x/tokenfactory/types"
2322)
2423
25- var _ vm.PrecompiledContract = (* precompileFunToken )(nil )
24+ var (
25+ _ vm.PrecompiledContract = (* precompileFunToken )(nil )
26+ _ vm.DynamicPrecompile = (* precompileFunToken )(nil )
27+ )
2628
2729// Precompile address for "IFunToken.sol", the contract that
2830// enables transfers of ERC20 tokens to "nibi" addresses as bank coins
@@ -52,7 +54,6 @@ const (
5254 FunTokenMethod_getErc20Address PrecompileMethod = "getErc20Address"
5355)
5456
55- // Run runs the precompiled contract
5657func (p precompileFunToken ) Run (
5758 evmObj * vm.EVM ,
5859 trueCaller gethcommon.Address ,
@@ -64,13 +65,50 @@ func (p precompileFunToken) Run(
6465 // isDelegatedCall: Flag to add conditional logic specific to delegate calls
6566 isDelegatedCall bool ,
6667) (bz []byte , err error ) {
68+ bz , _ , err = p .DynamicRun (evmObj , trueCaller , contract , readonly , isDelegatedCall )
69+ return bz , err
70+ }
71+
72+ // DynamicRun runs the precompiled contract and returns the gas cost.
73+ func (p precompileFunToken ) DynamicRun (
74+ evmObj * vm.EVM ,
75+ trueCaller gethcommon.Address ,
76+ // Note that we use "trueCaller" here to differentiate between a delegate
77+ // caller ("parent.CallerAddress" in geth) and "contract.CallerAddress"
78+ // because these two addresses may differ.
79+ contract * vm.Contract ,
80+ readonly bool ,
81+ // isDelegatedCall: Flag to add conditional logic specific to delegate calls
82+ isDelegatedCall bool ,
83+ ) (bz []byte , gasCost uint64 , err error ) {
6784 defer func () {
6885 err = ErrPrecompileRun (err , p )
6986 }()
7087 startResult , err := OnRunStart (evmObj , contract .Input , p .ABI (), contract .Gas )
7188 if err != nil {
72- return nil , err
89+ return nil , 0 , err
7390 }
91+ defer func () {
92+ // Recover OOG panics as ErrOutOfGas; other panics become an error.
93+ var (
94+ oog bool // true if panic was out-of-gas
95+ perr error // ErrOutOfGas for OOG, or formatted error for unexpected panic
96+ )
97+ panicInfo := recover ()
98+ if panicInfo != nil {
99+ oog , perr = evm .ParseOOGPanic (panicInfo , func (p interface {}) string {
100+ return fmt .Sprintf ("unexpected panic in precompile: %v" , p )
101+ })
102+ }
103+ if oog {
104+ gasCost = startResult .Ctx .GasMeter ().GasConsumed ()
105+ err = perr
106+ return
107+ } else if perr != nil {
108+ err = perr
109+ return
110+ }
111+ }()
74112
75113 abciEventsStartIdx := len (startResult .Ctx .EventManager ().Events ())
76114
@@ -96,14 +134,13 @@ func (p precompileFunToken) Run(
96134 err = fmt .Errorf ("invalid method called with name \" %s\" " , method .Name )
97135 return
98136 }
99- // Gas consumed by a local gas meter
100- contract .UseGas (
101- startResult .Ctx .GasMeter ().GasConsumed (),
102- evmObj .Config .Tracer ,
103- tracing .GasChangeCallPrecompiledContract ,
104- )
137+ // Gas consumed by a local gas meter (the one in startResult.Ctx from OnRunStart).
138+ // Gas consumed is guaranteed to be less than the gas limit (contract.Gas) because
139+ // the gas meter was initialized inside of the setup function, OnRunStart. The EVM
140+ // applies it via the returned gasCost from DynamicRun.
141+ gasCost = startResult .Ctx .GasMeter ().GasConsumed ()
105142 if err != nil {
106- return nil , err
143+ return nil , gasCost , err
107144 }
108145
109146 // Emit extra events for the EVM if this is a transaction
@@ -117,7 +154,7 @@ func (p precompileFunToken) Run(
117154 )
118155 }
119156
120- return bz , err
157+ return bz , gasCost , err
121158}
122159
123160func PrecompileFunToken (keepers keepers.PublicKeepers ) NibiruCustomPrecompile {
0 commit comments