Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(evm): commit temporary state on precompile start, avoiding bug stemming from uncommitted, dirty journal entries in the EVM StateDB #2086

Merged
merged 17 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 29 additions & 16 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### State Machine Breaking
### Nibiru EVM

#### For next mainnet version
#### Nibiru EVM | Before Audit 2 [Nov, 2024]

The codebase went through a third-party [Code4rena
Zenith](https://code4rena.com/zenith) Audit, running from 2024-10-07 until
2024-11-01 and including both a primary review period and mitigation/remission
period. This section describes code changes that occured after that audit in
preparation for a second audit starting in November 2024.

- [#2074](https://github.com/NibiruChain/nibiru/pull/2074) - fix(evm-keeper): better utilize ERC20 metadata during FunToken creation. The bank metadata for a new FunToken mapping ties a connection between the Bank Coin's `DenomUnit` and the ERC20 contract metadata like the name, decimals, and symbol. This change brings parity between EVM wallets, such as MetaMask, and Interchain wallets like Keplr and Leap.
- [#2076](https://github.com/NibiruChain/nibiru/pull/2076) - fix(evm-gas-fees):
Use effective gas price in RefundGas and make sure that units are properly
reflected on all occurences of "base fee" in the codebase. This fixes [#2059](https://github.com/NibiruChain/nibiru/issues/2059)
and the [related comments from @Unique-Divine and @berndartmueller](https://github.com/NibiruChain/nibiru/issues/2059#issuecomment-2408625724).
- [#2084](https://github.com/NibiruChain/nibiru/pull/2084) - feat(evm-forge): foundry support and template for Nibiru EVM develoment
- [#2086](https://github.com/NibiruChain/nibiru/pull/2086) - fix(evm-precompiles): It is possible for the `Run` function of a custom precompile to retrieve stale state because EVM state changes can occur before the precompile is called that are recorded as entries in the StateDB journal for the transaction without being reflected in the `sdk.Context`. This pull request makes sure that state is committed as expected.
- [#2088](https://github.com/NibiruChain/nibiru/pull/2088) - refactor(evm): remove outdated comment and improper error message text

- [#1766](https://github.com/NibiruChain/nibiru/pull/1766) - refactor(app-wasmext)!: remove wasmbinding `CosmosMsg::Custom` bindings.
- [#1776](https://github.com/NibiruChain/nibiru/pull/1776) - feat(inflation): make inflation params a collection and add commands to update them
- [#1872](https://github.com/NibiruChain/nibiru/pull/1872) - chore(math): use cosmossdk.io/math to replace sdk types
- [#1874](https://github.com/NibiruChain/nibiru/pull/1874) - chore(proto): remove the proto stringer as per Cosmos SDK migration guidelines
- [#1932](https://github.com/NibiruChain/nibiru/pull/1932) - fix(gosdk): fix keyring import functions

#### Nibiru EVM
#### Nibiru EVM | Before Audit 1 - 2024-10-18

- [#1837](https://github.com/NibiruChain/nibiru/pull/1837) - feat(eth): protos, eth types, and evm module types
- [#1838](https://github.com/NibiruChain/nibiru/pull/1838) - feat(eth): Go-ethereum, crypto, encoding, and unit tests for evm/types
Expand All @@ -70,7 +80,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1909](https://github.com/NibiruChain/nibiru/pull/1909) - chore(evm): set is_london true by default and removed from config
- [#1911](https://github.com/NibiruChain/nibiru/pull/1911) - chore(evm): simplified config by removing old eth forks
- [#1912](https://github.com/NibiruChain/nibiru/pull/1912) - test(evm): unit tests for evm_ante
- [#1914](https://github.com/NibiruChain/nibiru/pull/1914) - refactor(evm): Remove dead code and document non-EVM ante handler- [#1917](https://github.com/NibiruChain/nibiru/pull/1917) - test(e2e-evm): TypeScript support. Type generation from compiled contracts. Formatter for TS code.
- [#1914](https://github.com/NibiruChain/nibiru/pull/1914) - refactor(evm): Remove dead code and document non-EVM ante handler
- [#1917](https://github.com/NibiruChain/nibiru/pull/1917) - test(e2e-evm): TypeScript support. Type generation from compiled contracts. Formatter for TS code.
- [#1922](https://github.com/NibiruChain/nibiru/pull/1922) - feat(evm): tracer option is read from the config.
- [#1936](https://github.com/NibiruChain/nibiru/pull/1936) - feat(evm): EVM fungible token protobufs and encoding tests
Expand Down Expand Up @@ -128,15 +138,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#2060](https://github.com/NibiruChain/nibiru/pull/2060) - fix(evm-precompiles): add assertNumArgs validation
- [#2056](https://github.com/NibiruChain/nibiru/pull/2056) - feat(evm): add oracle precompile
- [#2065](https://github.com/NibiruChain/nibiru/pull/2065) - refactor(evm)!: Refactor out dead code from the evm.Params
- [#2073](https://github.com/NibiruChain/nibiru/pull/2073) - fix(evm-keeper): better utilize ERC20 metadata during FunToken creation
- [#2076](https://github.com/NibiruChain/nibiru/pull/2076) - fix(evm-gas-fees):
Use effective gas price in RefundGas and make sure that units are properly
reflected on all occurences of "base fee" in the codebase. This fixes [#2059](https://github.com/NibiruChain/nibiru/issues/2059)
and the [related comments from @Unique-Divine and @berndartmueller](https://github.com/NibiruChain/nibiru/issues/2059#issuecomment-2408625724).
- [#2084](https://github.com/NibiruChain/nibiru/pull/2084) - feat(evm-forge): foundry support and template for Nibiru EVM develoment
- [#2088](https://github.com/NibiruChain/nibiru/pull/2088) - refactor(evm): remove outdated comment and improper error message text


### State Machine Breaking (Other)

#### For next mainnet version

- [#1766](https://github.com/NibiruChain/nibiru/pull/1766) - refactor(app-wasmext)!: remove wasmbinding `CosmosMsg::Custom` bindings.
- [#1776](https://github.com/NibiruChain/nibiru/pull/1776) - feat(inflation): make inflation params a collection and add commands to update them
- [#1872](https://github.com/NibiruChain/nibiru/pull/1872) - chore(math): use cosmossdk.io/math to replace sdk types
- [#1874](https://github.com/NibiruChain/nibiru/pull/1874) - chore(proto): remove the proto stringer as per Cosmos SDK migration guidelines
- [#1932](https://github.com/NibiruChain/nibiru/pull/1932) - fix(gosdk): fix keyring import functions

#### Dapp modules: perp, spot, oracle, etc

- [#1573](https://github.com/NibiruChain/nibiru/pull/1573) - feat(perp): Close markets and compute settlement price
Expand Down
12 changes: 10 additions & 2 deletions x/evm/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,17 @@
func NewExecErrorWithReason(revertReason []byte) *RevertError {
result := common.CopyBytes(revertReason)
reason, errUnpack := abi.UnpackRevert(result)
err := errors.New("execution reverted")

var err error
errPrefix := "execution reverted"

Check warning on line 79 in x/evm/errors.go

View check run for this annotation

Codecov / codecov/patch

x/evm/errors.go#L77-L79

Added lines #L77 - L79 were not covered by tests
if errUnpack == nil {
err = fmt.Errorf("execution reverted: %v", reason)
reasonStr := reason
err = fmt.Errorf("%s with reason \"%v\"", errPrefix, reasonStr)
} else if string(result) != "" {
reasonStr := string(result)
err = fmt.Errorf("%s with reason \"%v\"", errPrefix, reasonStr)
} else {
err = errors.New(errPrefix)

Check warning on line 87 in x/evm/errors.go

View check run for this annotation

Codecov / codecov/patch

x/evm/errors.go#L81-L87

Added lines #L81 - L87 were not covered by tests
}
return &RevertError{
error: err,
Expand Down
8 changes: 7 additions & 1 deletion x/evm/evmtest/erc20.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
) {
actualBalance, err := deps.EvmKeeper.ERC20().BalanceOf(erc20, account, deps.Ctx)
assert.NoError(t, err)
assert.Zero(t, expectedBalance.Cmp(actualBalance), "expected %s, got %s", expectedBalance, actualBalance)
assert.Equal(t, expectedBalance.String(), actualBalance.String(), "expected %s, got %s", expectedBalance, actualBalance)
}

// CreateFunTokenForBankCoin: Uses the "TestDeps.Sender" account to create a
Expand Down Expand Up @@ -99,3 +99,9 @@
actualBalance := deps.App.BankKeeper.GetBalance(deps.Ctx, bech32Addr, denom).Amount.BigInt()
assert.Zero(t, expectedBalance.Cmp(actualBalance), "expected %s, got %s", expectedBalance, actualBalance)
}

// BigPow multiplies "amount" by 10 to the "pow10Exp".
func BigPow(amount *big.Int, pow10Exp uint8) (powAmount *big.Int) {
pow10 := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(pow10Exp)), nil)
return new(big.Int).Mul(amount, pow10)

Check warning on line 106 in x/evm/evmtest/erc20.go

View check run for this annotation

Codecov / codecov/patch

x/evm/evmtest/erc20.go#L104-L106

Added lines #L104 - L106 were not covered by tests
}
6 changes: 6 additions & 0 deletions x/evm/evmtest/test_deps.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package evmtest

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"

gethcommon "github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -54,3 +56,7 @@ func (deps TestDeps) StateDB() *statedb.StateDB {
func (deps *TestDeps) GethSigner() gethcore.Signer {
return gethcore.LatestSignerForChainID(deps.App.EvmKeeper.EthChainID(deps.Ctx))
}

func (deps TestDeps) GoCtx() context.Context {
return sdk.WrapSDKContext(deps.Ctx)
}
90 changes: 70 additions & 20 deletions x/evm/evmtest/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

srvconfig "github.com/NibiruChain/nibiru/v2/app/server/config"

"github.com/cosmos/cosmos-sdk/crypto/keyring"

"github.com/NibiruChain/nibiru/v2/x/evm"
"github.com/NibiruChain/nibiru/v2/x/evm/embeds"
)
Expand Down Expand Up @@ -123,7 +125,9 @@
To: &recipient,
Nonce: (*hexutil.Uint64)(&nonce),
}
ethTxMsg, err := GenerateAndSignEthTxMsg(txArgs, deps)
ethTxMsg, gethSigner, krSigner, err := GenerateEthTxMsgAndSigner(txArgs, deps, deps.Sender)
require.NoError(t, err)
err = ethTxMsg.Sign(gethSigner, krSigner)

Check warning on line 130 in x/evm/evmtest/tx.go

View check run for this annotation

Codecov / codecov/patch

x/evm/evmtest/tx.go#L128-L130

Added lines #L128 - L130 were not covered by tests
k-yang marked this conversation as resolved.
Show resolved Hide resolved
require.NoError(t, err)

resp, err := deps.App.EvmKeeper.EthereumTx(sdk.WrapSDKContext(deps.Ctx), ethTxMsg)
Expand Down Expand Up @@ -153,18 +157,20 @@
bytecodeForCall := append(contract.Bytecode, packedArgs...)

nonce := deps.StateDB().GetNonce(deps.Sender.EthAddr)
msgEthTx, err := GenerateAndSignEthTxMsg(
ethTxMsg, gethSigner, krSigner, err := GenerateEthTxMsgAndSigner(
evm.JsonTxArgs{
Nonce: (*hexutil.Uint64)(&nonce),
Input: (*hexutil.Bytes)(&bytecodeForCall),
From: &deps.Sender.EthAddr,
}, deps,
}, deps, deps.Sender,
)
if err != nil {
return nil, errors.Wrap(err, "failed to generate and sign eth tx msg")
} else if err := ethTxMsg.Sign(gethSigner, krSigner); err != nil {
return nil, errors.Wrap(err, "failed to generate and sign eth tx msg")

Check warning on line 170 in x/evm/evmtest/tx.go

View check run for this annotation

Codecov / codecov/patch

x/evm/evmtest/tx.go#L170

Added line #L170 was not covered by tests
Comment on lines +160 to +170
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Error Handling Improvement

In the DeployContract function, error handling can be streamlined by checking for the error immediately after the function call.

Apply this diff to enhance error handling:

 ethTxMsg, gethSigner, krSigner, err := GenerateEthTxMsgAndSigner(
 	evm.JsonTxArgs{
 		Nonce: (*hexutil.Uint64)(&nonce),
 		Input: (*hexutil.Bytes)(&bytecodeForCall),
 		From:  &deps.Sender.EthAddr,
-	}, deps, deps.Sender,
-)
-if err != nil {
-	return nil, errors.Wrap(err, "failed to generate and sign eth tx msg")
-} else if err := ethTxMsg.Sign(gethSigner, krSigner); err != nil {
+	}, deps, deps.Sender)
+if err != nil {
+	return nil, errors.Wrap(err, "failed to generate eth tx msg")
+}
+if err := ethTxMsg.Sign(gethSigner, krSigner); err != nil {
 	return nil, errors.Wrap(err, "failed to sign eth tx msg")
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ethTxMsg, gethSigner, krSigner, err := GenerateEthTxMsgAndSigner(
evm.JsonTxArgs{
Nonce: (*hexutil.Uint64)(&nonce),
Input: (*hexutil.Bytes)(&bytecodeForCall),
From: &deps.Sender.EthAddr,
}, deps,
}, deps, deps.Sender,
)
if err != nil {
return nil, errors.Wrap(err, "failed to generate and sign eth tx msg")
} else if err := ethTxMsg.Sign(gethSigner, krSigner); err != nil {
return nil, errors.Wrap(err, "failed to generate and sign eth tx msg")
ethTxMsg, gethSigner, krSigner, err := GenerateEthTxMsgAndSigner(
evm.JsonTxArgs{
Nonce: (*hexutil.Uint64)(&nonce),
Input: (*hexutil.Bytes)(&bytecodeForCall),
From: &deps.Sender.EthAddr,
}, deps, deps.Sender)
if err != nil {
return nil, errors.Wrap(err, "failed to generate eth tx msg")
}
if err := ethTxMsg.Sign(gethSigner, krSigner); err != nil {
return nil, errors.Wrap(err, "failed to sign eth tx msg")
}
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 161-161: x/evm/evmtest/tx.go#L161
Added line #L161 was not covered by tests


[warning] 166-166: x/evm/evmtest/tx.go#L166
Added line #L166 was not covered by tests


[warning] 170-171: x/evm/evmtest/tx.go#L170-L171
Added lines #L170 - L171 were not covered by tests

}

resp, err := deps.App.EvmKeeper.EthereumTx(sdk.WrapSDKContext(deps.Ctx), msgEthTx)
resp, err := deps.App.EvmKeeper.EthereumTx(sdk.WrapSDKContext(deps.Ctx), ethTxMsg)
if err != nil {
return nil, errors.Wrap(err, "failed to execute ethereum tx")
}
Expand All @@ -174,7 +180,7 @@

return &DeployContractResult{
TxResp: resp,
EthTxMsg: msgEthTx,
EthTxMsg: ethTxMsg,
ContractData: contract,
Nonce: nonce,
ContractAddr: crypto.CreateAddress(deps.Sender.EthAddr, nonce),
Expand All @@ -184,15 +190,19 @@
// DeployAndExecuteERC20Transfer deploys contract, executes transfer and returns tx hash
func DeployAndExecuteERC20Transfer(
deps *TestDeps, t *testing.T,
) (erc20Transfer *evm.MsgEthereumTx, predecessors []*evm.MsgEthereumTx) {
) (
erc20Transfer *evm.MsgEthereumTx,
predecessors []*evm.MsgEthereumTx,
contractAddr gethcommon.Address,
) {
// TX 1: Deploy ERC-20 contract
deployResp, err := DeployContract(deps, embeds.SmartContract_TestERC20)
require.NoError(t, err)
contractData := deployResp.ContractData
nonce := deployResp.Nonce

// Contract address is deterministic
contractAddress := crypto.CreateAddress(deps.Sender.EthAddr, nonce)
contractAddr = crypto.CreateAddress(deps.Sender.EthAddr, nonce)
deps.App.Commit()
predecessors = []*evm.MsgEthereumTx{
deployResp.EthTxMsg,
Expand All @@ -206,27 +216,67 @@
nonce = deps.StateDB().GetNonce(deps.Sender.EthAddr)
txArgs := evm.JsonTxArgs{
From: &deps.Sender.EthAddr,
To: &contractAddress,
To: &contractAddr,
Nonce: (*hexutil.Uint64)(&nonce),
Data: (*hexutil.Bytes)(&input),
}
erc20Transfer, err = GenerateAndSignEthTxMsg(txArgs, deps)
erc20Transfer, gethSigner, krSigner, err := GenerateEthTxMsgAndSigner(txArgs, deps, deps.Sender)
require.NoError(t, err)
err = erc20Transfer.Sign(gethSigner, krSigner)
onikonychev marked this conversation as resolved.
Show resolved Hide resolved
require.NoError(t, err)

resp, err := deps.App.EvmKeeper.EthereumTx(sdk.WrapSDKContext(deps.Ctx), erc20Transfer)
resp, err := deps.App.EvmKeeper.EthereumTx(deps.GoCtx(), erc20Transfer)
require.NoError(t, err)
require.Empty(t, resp.VmError)

return erc20Transfer, predecessors
return erc20Transfer, predecessors, contractAddr
}

// GenerateAndSignEthTxMsg estimates gas, sets gas limit and sings the tx
func GenerateAndSignEthTxMsg(
jsonTxArgs evm.JsonTxArgs, deps *TestDeps,
) (*evm.MsgEthereumTx, error) {
func CallContractTx(
deps *TestDeps,
contractAddr gethcommon.Address,
input []byte,
sender EthPrivKeyAcc,
) (ethTxMsg *evm.MsgEthereumTx, resp *evm.MsgEthereumTxResponse, err error) {
nonce := deps.StateDB().GetNonce(sender.EthAddr)
ethTxMsg, gethSigner, krSigner, err := GenerateEthTxMsgAndSigner(evm.JsonTxArgs{
From: &sender.EthAddr,
To: &contractAddr,
Nonce: (*hexutil.Uint64)(&nonce),
Data: (*hexutil.Bytes)(&input),
}, deps, sender)
if err != nil {
err = fmt.Errorf("CallContract error during tx generation: %w", err)
return
}

Check warning on line 251 in x/evm/evmtest/tx.go

View check run for this annotation

Codecov / codecov/patch

x/evm/evmtest/tx.go#L249-L251

Added lines #L249 - L251 were not covered by tests

err = ethTxMsg.Sign(gethSigner, krSigner)
if err != nil {
err = fmt.Errorf("CallContract error during signature: %w", err)
return
}

Check warning on line 257 in x/evm/evmtest/tx.go

View check run for this annotation

Codecov / codecov/patch

x/evm/evmtest/tx.go#L255-L257

Added lines #L255 - L257 were not covered by tests

resp, err = deps.EvmKeeper.EthereumTx(deps.GoCtx(), ethTxMsg)
return ethTxMsg, resp, err
}

// GenerateEthTxMsgAndSigner estimates gas, sets gas limit and returns signer for
// the tx.
//
// Usage:
//
// ```go
// evmTxMsg, gethSigner, krSigner, _ := GenerateEthTxMsgAndSigner(
// jsonTxArgs, &deps, sender,
// )
// err := evmTxMsg.Sign(gethSigner, sender.KeyringSigner)
// ```
func GenerateEthTxMsgAndSigner(
jsonTxArgs evm.JsonTxArgs, deps *TestDeps, sender EthPrivKeyAcc,
) (evmTxMsg *evm.MsgEthereumTx, gethSigner gethcore.Signer, krSigner keyring.Signer, err error) {
estimateArgs, err := json.Marshal(&jsonTxArgs)
if err != nil {
return nil, err
return

Check warning on line 279 in x/evm/evmtest/tx.go

View check run for this annotation

Codecov / codecov/patch

x/evm/evmtest/tx.go#L279

Added line #L279 was not covered by tests
}
res, err := deps.App.EvmKeeper.EstimateGas(
sdk.WrapSDKContext(deps.Ctx),
Expand All @@ -238,13 +288,13 @@
},
)
if err != nil {
return nil, err
return

Check warning on line 291 in x/evm/evmtest/tx.go

View check run for this annotation

Codecov / codecov/patch

x/evm/evmtest/tx.go#L291

Added line #L291 was not covered by tests
}
jsonTxArgs.Gas = (*hexutil.Uint64)(&res.Gas)

msgEthTx := jsonTxArgs.ToMsgEthTx()
gethSigner := gethcore.LatestSignerForChainID(deps.App.EvmKeeper.EthChainID(deps.Ctx))
return msgEthTx, msgEthTx.Sign(gethSigner, deps.Sender.KeyringSigner)
evmTxMsg = jsonTxArgs.ToMsgEthTx()
gethSigner = gethcore.LatestSignerForChainID(deps.App.EvmKeeper.EthChainID(deps.Ctx))
return evmTxMsg, gethSigner, sender.KeyringSigner, nil
}

func TransferWei(
Expand Down
90 changes: 90 additions & 0 deletions x/evm/evmtest/tx_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright (c) 2023-2024 Nibi, Inc.
package evmtest_test

import (
"math/big"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/crypto"

"github.com/NibiruChain/nibiru/v2/x/common/testutil/testapp"
"github.com/NibiruChain/nibiru/v2/x/evm"
"github.com/NibiruChain/nibiru/v2/x/evm/embeds"
"github.com/NibiruChain/nibiru/v2/x/evm/evmtest"
)

func (s *Suite) TestCallContractTx() {
deps := evmtest.NewTestDeps()

s.T().Log("Deploy some ERC20")
deployArgs := []any{"name", "SYMBOL", uint8(18)}
deployResp, err := evmtest.DeployContract(
&deps,
embeds.SmartContract_ERC20Minter,
deployArgs...,
)
s.Require().NoError(err, deployResp)
contractAddr := crypto.CreateAddress(deps.Sender.EthAddr, deployResp.Nonce)
gotContractAddr := deployResp.ContractAddr
s.Require().Equal(contractAddr, gotContractAddr)

s.T().Log("expect zero balance")
{
wantBal := big.NewInt(0)
evmtest.AssertERC20BalanceEqual(
s.T(), deps, contractAddr, deps.Sender.EthAddr, wantBal,
)
}

abi := deployResp.ContractData.ABI
s.T().Log("mint some tokens")
{
amount := big.NewInt(69_420)
to := deps.Sender.EthAddr
callArgs := []any{to, amount}
input, err := abi.Pack(
"mint", callArgs...,
)
s.Require().NoError(err)
_, resp, err := evmtest.CallContractTx(
&deps,
contractAddr,
input,
deps.Sender,
)
s.Require().NoError(err)
s.Require().Empty(resp.VmError)
}

s.T().Log("expect nonzero balance")
{
wantBal := big.NewInt(69_420)
evmtest.AssertERC20BalanceEqual(
s.T(), deps, contractAddr, deps.Sender.EthAddr, wantBal,
)
}
}

func (s *Suite) TestTransferWei() {
deps := evmtest.NewTestDeps()

s.Require().NoError(testapp.FundAccount(
deps.App.BankKeeper,
deps.Ctx,
deps.Sender.NibiruAddr,
sdk.NewCoins(sdk.NewCoin(evm.EVMBankDenom, sdk.NewInt(69_420))),
))

randomAcc := evmtest.NewEthPrivAcc()
to := randomAcc.EthAddr
err := evmtest.TransferWei(&deps, to, evm.NativeToWei(big.NewInt(420)))
s.Require().NoError(err)

evmtest.AssertBankBalanceEqual(
s.T(), deps, evm.EVMBankDenom, deps.Sender.EthAddr, big.NewInt(69_000),
)

s.Run("DeployAndExecuteERC20Transfer", func() {
evmtest.DeployAndExecuteERC20Transfer(&deps, s.T())
})
}
Loading
Loading