From 0e3ab43d31b6d34978266e35a3f4d138c56fd44c Mon Sep 17 00:00:00 2001 From: Kevin Yang <5478483+k-yang@users.noreply.github.com> Date: Tue, 21 Jan 2025 14:20:45 -0800 Subject: [PATCH] fix(evm): ensure stateDB is nil after tx execution (#2173) * fix(evm): ensure stateDB is nil after tx execution * Update CHANGELOG.md * test: add smart contract test (precompile sendToBank then ERC20 transfer) --- CHANGELOG.md | 1 + ...PrecompileSendToBankThenERC20Transfer.json | 60 +++++++++++ ...tPrecompileSendToBankThenERC20Transfer.sol | 25 +++++ x/evm/embeds/embeds.go | 9 ++ x/evm/embeds/package-lock.json | 4 +- x/evm/keeper/funtoken_from_coin.go | 5 +- x/evm/keeper/funtoken_from_coin_test.go | 101 +++++++++++++++++- x/evm/keeper/funtoken_from_erc20.go | 5 +- x/evm/keeper/msg_server.go | 17 +-- x/evm/precompile/funtoken.go | 1 - x/evm/precompile/wasm.go | 5 - 11 files changed, 214 insertions(+), 19 deletions(-) create mode 100644 x/evm/embeds/artifacts/contracts/TestPrecompileSendToBankThenERC20Transfer.sol/TestPrecompileSendToBankThenERC20Transfer.json create mode 100644 x/evm/embeds/contracts/TestPrecompileSendToBankThenERC20Transfer.sol diff --git a/CHANGELOG.md b/CHANGELOG.md index d29c3c7ff..1943730db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,6 +85,7 @@ needed to include double quotes around the hexadecimal string. - [#2169](https://github.com/NibiruChain/nibiru/pull/2169) - fix(evm): Better handling erc20 metadata - [#2170](https://github.com/NibiruChain/nibiru/pull/2170) - chore: Remove redundant allowUnprotectedTxs - [#2172](https://github.com/NibiruChain/nibiru/pull/2172) - chore: close iterator in IterateEpochInfo +- [#2173](https://github.com/NibiruChain/nibiru/pull/2173) - fix(evm): clear `StateDB` between calls #### Nibiru EVM | Before Audit 2 - 2024-12-06 diff --git a/x/evm/embeds/artifacts/contracts/TestPrecompileSendToBankThenERC20Transfer.sol/TestPrecompileSendToBankThenERC20Transfer.json b/x/evm/embeds/artifacts/contracts/TestPrecompileSendToBankThenERC20Transfer.sol/TestPrecompileSendToBankThenERC20Transfer.json new file mode 100644 index 000000000..ba4e68635 --- /dev/null +++ b/x/evm/embeds/artifacts/contracts/TestPrecompileSendToBankThenERC20Transfer.sol/TestPrecompileSendToBankThenERC20Transfer.json @@ -0,0 +1,60 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "TestPrecompileSendToBankThenERC20Transfer", + "sourceName": "contracts/TestPrecompileSendToBankThenERC20Transfer.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_erc20", + "type": "address" + }, + { + "internalType": "string", + "name": "_recipient", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "attack", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "erc20", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "recipient", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b5060405162000d8c38038062000d8c833981810160405281019062000037919062000289565b816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600190816200008891906200053a565b50505062000621565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620000d282620000a5565b9050919050565b620000e481620000c5565b8114620000f057600080fd5b50565b6000815190506200010481620000d9565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200015f8262000114565b810181811067ffffffffffffffff8211171562000181576200018062000125565b5b80604052505050565b60006200019662000091565b9050620001a4828262000154565b919050565b600067ffffffffffffffff821115620001c757620001c662000125565b5b620001d28262000114565b9050602081019050919050565b60005b83811015620001ff578082015181840152602081019050620001e2565b60008484015250505050565b6000620002226200021c84620001a9565b6200018a565b9050828152602081018484840111156200024157620002406200010f565b5b6200024e848285620001df565b509392505050565b600082601f8301126200026e576200026d6200010a565b5b8151620002808482602086016200020b565b91505092915050565b60008060408385031215620002a357620002a26200009b565b5b6000620002b385828601620000f3565b925050602083015167ffffffffffffffff811115620002d757620002d6620000a0565b5b620002e58582860162000256565b9150509250929050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200034257607f821691505b602082108103620003585762000357620002fa565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003c27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000383565b620003ce868362000383565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006200041b620004156200040f84620003e6565b620003f0565b620003e6565b9050919050565b6000819050919050565b6200043783620003fa565b6200044f620004468262000422565b84845462000390565b825550505050565b600090565b6200046662000457565b620004738184846200042c565b505050565b5b818110156200049b576200048f6000826200045c565b60018101905062000479565b5050565b601f821115620004ea57620004b4816200035e565b620004bf8462000373565b81016020851015620004cf578190505b620004e7620004de8562000373565b83018262000478565b50505b505050565b600082821c905092915050565b60006200050f60001984600802620004ef565b1980831691505092915050565b60006200052a8383620004fc565b9150826002028217905092915050565b6200054582620002ef565b67ffffffffffffffff81111562000561576200056062000125565b5b6200056d825462000329565b6200057a8282856200049f565b600060209050601f831160018114620005b257600084156200059d578287015190505b620005a985826200051c565b86555062000619565b601f198416620005c2866200035e565b60005b82811015620005ec57848901518255600182019150602085019450602081019050620005c5565b868310156200060c578489015162000608601f891682620004fc565b8355505b6001600288020188555050505b505050505050565b61075b80620006316000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806366d003ac14610046578063785e9e86146100645780639e5faafc14610082575b600080fd5b61004e61008c565b60405161005b91906103b6565b60405180910390f35b61006c61011a565b6040516100799190610457565b60405180910390f35b61008a61013e565b005b60018054610099906104a1565b80601f01602080910402602001604051908101604052809291908181526020018280546100c5906104a1565b80156101125780601f106100e757610100808354040283529160200191610112565b820191906000526020600020905b8154815290600101906020018083116100f557829003601f168201915b505050505081565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161019a91906104f3565b602060405180830381865afa1580156101b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101db9190610549565b905061080073ffffffffffffffffffffffffffffffffffffffff1663e77a47bf60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff168360016040518463ffffffff1660e01b815260040161023d9392919061061e565b6020604051808303816000875af115801561025c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102809190610549565b5060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61dead60016040518363ffffffff1660e01b81526004016102df929190610697565b6020604051808303816000875af11580156102fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032291906106f8565b5050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610360578082015181840152602081019050610345565b60008484015250505050565b6000601f19601f8301169050919050565b600061038882610326565b6103928185610331565b93506103a2818560208601610342565b6103ab8161036c565b840191505092915050565b600060208201905081810360008301526103d0818461037d565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061041d610418610413846103d8565b6103f8565b6103d8565b9050919050565b600061042f82610402565b9050919050565b600061044182610424565b9050919050565b61045181610436565b82525050565b600060208201905061046c6000830184610448565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806104b957607f821691505b6020821081036104cc576104cb610472565b5b50919050565b60006104dd826103d8565b9050919050565b6104ed816104d2565b82525050565b600060208201905061050860008301846104e4565b92915050565b600080fd5b6000819050919050565b61052681610513565b811461053157600080fd5b50565b6000815190506105438161051d565b92915050565b60006020828403121561055f5761055e61050e565b5b600061056d84828501610534565b91505092915050565b61057f81610513565b82525050565b60008190508160005260206000209050919050565b600081546105a7816104a1565b6105b18186610331565b945060018216600081146105cc57600181146105e257610615565b60ff198316865281151560200286019350610615565b6105eb85610585565b60005b8381101561060d578154818901526001820191506020810190506105ee565b808801955050505b50505092915050565b600060608201905061063360008301866104e4565b6106406020830185610576565b8181036040830152610652818461059a565b9050949350505050565b6000819050919050565b600061068161067c6106778461065c565b6103f8565b610513565b9050919050565b61069181610666565b82525050565b60006040820190506106ac60008301856104e4565b6106b96020830184610688565b9392505050565b60008115159050919050565b6106d5816106c0565b81146106e057600080fd5b50565b6000815190506106f2816106cc565b92915050565b60006020828403121561070e5761070d61050e565b5b600061071c848285016106e3565b9150509291505056fea26469706673582212208ef08251d818031ab4c74d22a618b6305b406be371abda8aeb6b83c46f6c195a64736f6c63430008180033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806366d003ac14610046578063785e9e86146100645780639e5faafc14610082575b600080fd5b61004e61008c565b60405161005b91906103b6565b60405180910390f35b61006c61011a565b6040516100799190610457565b60405180910390f35b61008a61013e565b005b60018054610099906104a1565b80601f01602080910402602001604051908101604052809291908181526020018280546100c5906104a1565b80156101125780601f106100e757610100808354040283529160200191610112565b820191906000526020600020905b8154815290600101906020018083116100f557829003601f168201915b505050505081565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161019a91906104f3565b602060405180830381865afa1580156101b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101db9190610549565b905061080073ffffffffffffffffffffffffffffffffffffffff1663e77a47bf60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff168360016040518463ffffffff1660e01b815260040161023d9392919061061e565b6020604051808303816000875af115801561025c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102809190610549565b5060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61dead60016040518363ffffffff1660e01b81526004016102df929190610697565b6020604051808303816000875af11580156102fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032291906106f8565b5050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610360578082015181840152602081019050610345565b60008484015250505050565b6000601f19601f8301169050919050565b600061038882610326565b6103928185610331565b93506103a2818560208601610342565b6103ab8161036c565b840191505092915050565b600060208201905081810360008301526103d0818461037d565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061041d610418610413846103d8565b6103f8565b6103d8565b9050919050565b600061042f82610402565b9050919050565b600061044182610424565b9050919050565b61045181610436565b82525050565b600060208201905061046c6000830184610448565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806104b957607f821691505b6020821081036104cc576104cb610472565b5b50919050565b60006104dd826103d8565b9050919050565b6104ed816104d2565b82525050565b600060208201905061050860008301846104e4565b92915050565b600080fd5b6000819050919050565b61052681610513565b811461053157600080fd5b50565b6000815190506105438161051d565b92915050565b60006020828403121561055f5761055e61050e565b5b600061056d84828501610534565b91505092915050565b61057f81610513565b82525050565b60008190508160005260206000209050919050565b600081546105a7816104a1565b6105b18186610331565b945060018216600081146105cc57600181146105e257610615565b60ff198316865281151560200286019350610615565b6105eb85610585565b60005b8381101561060d578154818901526001820191506020810190506105ee565b808801955050505b50505092915050565b600060608201905061063360008301866104e4565b6106406020830185610576565b8181036040830152610652818461059a565b9050949350505050565b6000819050919050565b600061068161067c6106778461065c565b6103f8565b610513565b9050919050565b61069181610666565b82525050565b60006040820190506106ac60008301856104e4565b6106b96020830184610688565b9392505050565b60008115159050919050565b6106d5816106c0565b81146106e057600080fd5b50565b6000815190506106f2816106cc565b92915050565b60006020828403121561070e5761070d61050e565b5b600061071c848285016106e3565b9150509291505056fea26469706673582212208ef08251d818031ab4c74d22a618b6305b406be371abda8aeb6b83c46f6c195a64736f6c63430008180033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/x/evm/embeds/contracts/TestPrecompileSendToBankThenERC20Transfer.sol b/x/evm/embeds/contracts/TestPrecompileSendToBankThenERC20Transfer.sol new file mode 100644 index 000000000..d54dc54a3 --- /dev/null +++ b/x/evm/embeds/contracts/TestPrecompileSendToBankThenERC20Transfer.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "./IFunToken.sol"; + +contract TestPrecompileSendToBankThenERC20Transfer { + IERC20 public erc20; + string public recipient; + + constructor(address _erc20, string memory _recipient) { + erc20 = IERC20(_erc20); + recipient = _recipient; + } + + function attack() public { + // transfer this contract's entire balance to the recipient + uint balance = erc20.balanceOf(address(this)); + // sendToBank should reduce balance to zero + FUNTOKEN_PRECOMPILE.sendToBank(address(erc20), balance, recipient); + + // this call should fail because of the balance is zero + erc20.transfer(0x000000000000000000000000000000000000dEaD, 1); + } +} diff --git a/x/evm/embeds/embeds.go b/x/evm/embeds/embeds.go index 8bd093e34..f08e26b5d 100644 --- a/x/evm/embeds/embeds.go +++ b/x/evm/embeds/embeds.go @@ -45,6 +45,8 @@ var ( testRandom []byte //go:embed artifacts/contracts/MKR.sol/DSToken.json testMetadataBytes32 []byte + //go:embed artifacts/contracts/TestPrecompileSendToBankThenERC20Transfer.sol/TestPrecompileSendToBankThenERC20Transfer.json + testPrecompileSendToBankThenERC20Transfer []byte ) var ( @@ -148,6 +150,12 @@ var ( Name: "MKR.sol", EmbedJSON: testMetadataBytes32, } + + // SmartContract_TestPrecompileSendToBankThenERC20Transfer is a test contract that sends to bank then calls ERC20 transfer + SmartContract_TestPrecompileSendToBankThenERC20Transfer = CompiledEvmContract{ + Name: "TestPrecompileSendToBankThenERC20Transfer.sol", + EmbedJSON: testPrecompileSendToBankThenERC20Transfer, + } ) func init() { @@ -166,6 +174,7 @@ func init() { SmartContract_TestERC20TransferWithFee.MustLoad() SmartContract_TestRandom.MustLoad() SmartContract_TestBytes32Metadata.MustLoad() + SmartContract_TestPrecompileSendToBankThenERC20Transfer.MustLoad() } type CompiledEvmContract struct { diff --git a/x/evm/embeds/package-lock.json b/x/evm/embeds/package-lock.json index 149b1ef1b..99bb2520b 100644 --- a/x/evm/embeds/package-lock.json +++ b/x/evm/embeds/package-lock.json @@ -1,12 +1,12 @@ { "name": "@nibiruchain/solidity", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@nibiruchain/solidity", - "version": "0.0.1", + "version": "0.0.2", "license": "MIT", "dependencies": { "@openzeppelin/contracts": "^4.9.0" diff --git a/x/evm/keeper/funtoken_from_coin.go b/x/evm/keeper/funtoken_from_coin.go index abfddd2ec..294d72964 100644 --- a/x/evm/keeper/funtoken_from_coin.go +++ b/x/evm/keeper/funtoken_from_coin.go @@ -98,6 +98,9 @@ func (k *Keeper) deployERC20ForBankCoin( if stateDB == nil { stateDB = k.NewStateDB(ctx, txConfig) } + defer func() { + k.Bank.StateDB = nil + }() evmObj := k.NewEVM(ctx, evmMsg, evmCfg, nil /*tracer*/, stateDB) evmResp, err := k.CallContractWithInput( ctx, evmObj, evm.EVM_MODULE_ADDRESS, nil, true /*commit*/, input, Erc20GasLimitDeploy, @@ -110,8 +113,6 @@ func (k *Keeper) deployERC20ForBankCoin( if err != nil { return gethcommon.Address{}, errors.Wrap(err, "failed to commit stateDB") } - // Don't need the StateDB anymore because it's not usable after committing - k.Bank.StateDB = nil ctx.GasMeter().ConsumeGas(evmResp.GasUsed, "deploy erc20 funtoken contract") diff --git a/x/evm/keeper/funtoken_from_coin_test.go b/x/evm/keeper/funtoken_from_coin_test.go index aeaa7f79a..7a75afca6 100644 --- a/x/evm/keeper/funtoken_from_coin_test.go +++ b/x/evm/keeper/funtoken_from_coin_test.go @@ -573,7 +573,6 @@ func (s *FunTokenFromCoinSuite) TestERC20TransferThenPrecompileSend() { // - Module account: 10 NIBI escrowed (which Test contract holds as 10 WNIBI) func (s *FunTokenFromCoinSuite) TestPrecompileSelfCallRevert() { deps := evmtest.NewTestDeps() - evmObj, _ := deps.NewEVM() // Initial setup funToken := s.fundAndCreateFunToken(deps, 10e6) @@ -606,6 +605,7 @@ func (s *FunTokenFromCoinSuite) TestPrecompileSelfCallRevert() { sdk.NewCoins(sdk.NewCoin(evm.EVMBankDenom, sdk.NewInt(10e6))), )) + evmObj, _ := deps.NewEVM() evmtest.FunTokenBalanceAssert{ FunToken: funToken, Account: testContractAddr, @@ -620,6 +620,7 @@ func (s *FunTokenFromCoinSuite) TestPrecompileSelfCallRevert() { charles := evmtest.NewEthPrivAcc() s.T().Log("call test contract") + evmObj, _ = deps.NewEVM() contractInput, err := embeds.SmartContract_TestPrecompileSelfCallRevert.ABI.Pack( "selfCallTransferFunds", alice.EthAddr, @@ -672,6 +673,104 @@ func (s *FunTokenFromCoinSuite) TestPrecompileSelfCallRevert() { }.Assert(s.T(), deps, evmObj) } +// TestPrecompileSelfCallRevert +// 1. Creates a funtoken from coin. +// 2. Calls the test contract +// a. sendToBank +// b. erc20 transfer +// +// INITIAL STATE: +// - Test contract funds: 10 WNIBI +// CONTRACT CALL: +// - Sends 10 WNIBI to Alice, and try to send 1 NIBI to Bob +// EXPECTED: +// - all changes reverted because of not enough balance +// - Test contract funds: 10 WNIBI +// - Alice: 10 WNIBI +// - Bob: 0 NIBI +// - Module account: 10 NIBI escrowed (which Test contract holds as 10 WNIBI) +func (s *FunTokenFromCoinSuite) TestPrecompileSendToBankThenErc20Transfer() { + deps := evmtest.NewTestDeps() + + // Initial setup + funToken := s.fundAndCreateFunToken(deps, 10e6) + + s.T().Log("Deploy Test Contract") + deployResp, err := evmtest.DeployContract( + &deps, + embeds.SmartContract_TestPrecompileSendToBankThenERC20Transfer, + funToken.Erc20Addr.Address, + deps.Sender.NibiruAddr.String(), + ) + s.Require().NoError(err) + testContractAddr := deployResp.ContractAddr + + s.T().Log("Convert bank coin to erc-20: give test contract 10 WNIBI (erc20)") + _, err = deps.EvmKeeper.ConvertCoinToEvm( + sdk.WrapSDKContext(deps.Ctx), + &evm.MsgConvertCoinToEvm{ + Sender: deps.Sender.NibiruAddr.String(), + BankCoin: sdk.NewCoin(evm.EVMBankDenom, sdk.NewInt(10e6)), + ToEthAddr: eth.EIP55Addr{Address: testContractAddr}, + }, + ) + s.Require().NoError(err) + + // Create Alice and Bob. Contract will try to send Alice native coins and + // send Bob ERC20 tokens. + alice := evmtest.NewEthPrivAcc() + bob := evmtest.NewEthPrivAcc() + + s.T().Log("call test contract") + contractInput, err := embeds.SmartContract_TestPrecompileSendToBankThenERC20Transfer.ABI.Pack( + "attack", + ) + s.Require().NoError(err) + evmObj, _ := deps.NewEVM() + _, err = deps.EvmKeeper.CallContractWithInput( + deps.Ctx, + evmObj, + deps.Sender.EthAddr, + &testContractAddr, + true, + contractInput, + evmtest.FunTokenGasLimitSendToEvm, + ) + s.Require().ErrorContains(err, "execution reverted") + + evmtest.FunTokenBalanceAssert{ + FunToken: funToken, + Account: alice.EthAddr, + BalanceBank: big.NewInt(0), + BalanceERC20: big.NewInt(0), + Description: "Alice has 0 NIBI / 0 WNIBI", + }.Assert(s.T(), deps, evmObj) + + evmtest.FunTokenBalanceAssert{ + FunToken: funToken, + Account: bob.EthAddr, + BalanceBank: big.NewInt(0), + BalanceERC20: big.NewInt(0), + Description: "Charles has 0 NIBI / 0 WNIBI", + }.Assert(s.T(), deps, evmObj) + + evmtest.FunTokenBalanceAssert{ + FunToken: funToken, + Account: testContractAddr, + BalanceBank: big.NewInt(0), + BalanceERC20: big.NewInt(10e6), + Description: "Test contract has 10 NIBI / 10 WNIBI", + }.Assert(s.T(), deps, evmObj) + + evmtest.FunTokenBalanceAssert{ + FunToken: funToken, + Account: evm.EVM_MODULE_ADDRESS, + BalanceBank: big.NewInt(10e6), + BalanceERC20: big.NewInt(0), + Description: "Module account has 10 NIBI escrowed", + }.Assert(s.T(), deps, evmObj) +} + // fundAndCreateFunToken creates initial setup for tests func (s *FunTokenFromCoinSuite) fundAndCreateFunToken(deps evmtest.TestDeps, unibiAmount int64) evm.FunToken { bankDenom := evm.EVMBankDenom diff --git a/x/evm/keeper/funtoken_from_erc20.go b/x/evm/keeper/funtoken_from_erc20.go index 5eb55ce4a..36c071768 100644 --- a/x/evm/keeper/funtoken_from_erc20.go +++ b/x/evm/keeper/funtoken_from_erc20.go @@ -132,6 +132,9 @@ func (k *Keeper) createFunTokenFromERC20( if stateDB == nil { stateDB = k.NewStateDB(ctx, statedb.NewEmptyTxConfig(gethcommon.BytesToHash(ctx.HeaderHash()))) } + defer func() { + k.Bank.StateDB = nil + }() evmMsg := gethcore.NewMessage( evm.EVM_MODULE_ADDRESS, &erc20, @@ -184,8 +187,6 @@ func (k *Keeper) createFunTokenFromERC20( if err != nil { return nil, errors.Wrap(err, "failed to commit stateDB") } - // Don't need the StateDB anymore because it's not usable after committing - k.Bank.StateDB = nil return funtoken, k.FunTokens.SafeInsert( ctx, erc20, bankDenom, false, diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 982f798ac..94acd33ac 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -60,6 +60,9 @@ func (k *Keeper) EthereumTx( if stateDB == nil { stateDB = k.NewStateDB(ctx, txConfig) } + defer func() { + k.Bank.StateDB = nil + }() evmObj := k.NewEVM(ctx, evmMsg, evmCfg, nil /*tracer*/, stateDB) evmResp, err = k.ApplyEvmMsg(ctx, evmMsg, evmObj, nil /*tracer*/, true /*commit*/, txConfig.TxHash, false /*fullRefundLeftoverGas*/) if err != nil { @@ -341,8 +344,6 @@ func (k *Keeper) ApplyEvmMsg( if err := evmObj.StateDB.(*statedb.StateDB).Commit(); err != nil { return nil, errors.Wrap(err, "ApplyEvmMsg: failed to commit stateDB") } - // after we commit, the StateDB is no longer usable so we discard it and let the Golang garbage collector dispose of it - k.Bank.StateDB = nil } // Rare case of uint64 gas overflow if msg.Gas() < leftoverGas { @@ -544,10 +545,13 @@ func (k Keeper) convertCoinToEvmBornCoin( true, ) txConfig := k.TxConfig(ctx, gethcommon.Hash{}) - var stateDB *statedb.StateDB = k.Bank.StateDB + stateDB := k.Bank.StateDB if stateDB == nil { stateDB = k.NewStateDB(ctx, txConfig) } + defer func() { + k.Bank.StateDB = nil + }() evmObj := k.NewEVM(ctx, evmMsg, k.GetEVMConfig(ctx), nil /*tracer*/, stateDB) evmResp, err := k.CallContractWithInput( ctx, @@ -572,7 +576,6 @@ func (k Keeper) convertCoinToEvmBornCoin( if err != nil { return nil, errors.Wrap(err, "failed to commit stateDB") } - k.Bank.StateDB = nil _ = ctx.EventManager().EmitTypedEvent(&evm.EventConvertCoinToEvm{ Sender: sender.String(), @@ -596,10 +599,13 @@ func (k Keeper) convertCoinToEvmBornERC20( funTokenMapping evm.FunToken, ) (*evm.MsgConvertCoinToEvmResponse, error) { // needs to run first to populate the StateDB on the BankKeeperExtension - var stateDB *statedb.StateDB = k.Bank.StateDB + stateDB := k.Bank.StateDB if stateDB == nil { stateDB = k.NewStateDB(ctx, k.TxConfig(ctx, gethcommon.Hash{})) } + defer func() { + k.Bank.StateDB = nil + }() erc20Addr := funTokenMapping.Erc20Addr.Address // 1 | Caller transfers Bank Coins to be converted to ERC20 tokens. @@ -664,7 +670,6 @@ func (k Keeper) convertCoinToEvmBornERC20( if err := stateDB.Commit(); err != nil { return nil, errors.Wrap(err, "failed to commit stateDB") } - k.Bank.StateDB = nil // Emit event with the actual amount received _ = ctx.EventManager().EmitTypedEvent(&evm.EventConvertCoinToEvm{ diff --git a/x/evm/precompile/funtoken.go b/x/evm/precompile/funtoken.go index ddce4fe79..6a1aa210b 100644 --- a/x/evm/precompile/funtoken.go +++ b/x/evm/precompile/funtoken.go @@ -59,7 +59,6 @@ func (p precompileFunToken) Run( if err != nil { return nil, err } - p.evmKeeper.Bank.StateDB = startResult.StateDB // Gracefully handles "out of gas" defer HandleOutOfGasPanic(&err)() diff --git a/x/evm/precompile/wasm.go b/x/evm/precompile/wasm.go index 2ecfbd0ae..bfb9ff9d8 100644 --- a/x/evm/precompile/wasm.go +++ b/x/evm/precompile/wasm.go @@ -48,11 +48,6 @@ func (p precompileWasm) Run( abciEventsStartIdx := len(startResult.CacheCtx.EventManager().Events()) - // NOTE: The NibiruBankKeeper needs to reference the current [vm.StateDB] before - // any operation that has the potential to use Bank send methods. This will - // guarantee that [evmkeeper.Keeper.SetAccBalance] journal changes are - // recorded if wei (NIBI) is transferred. - p.Bank.StateDB = startResult.StateDB switch PrecompileMethod(startResult.Method.Name) { case WasmMethod_execute: bz, err = p.execute(startResult, contract.CallerAddress, readonly)