Skip to content

Commit

Permalink
feat(evm-cli): Add the account query to the EVM command. Cover the CL…
Browse files Browse the repository at this point in the history
…I with tests. (#2002)

* feat(evm-cli): expose account query

* undo commit of events code

* test(evm-cli): more tests

* changelog

* refactor: small edits after self-review

* chore: typo
  • Loading branch information
Unique-Divine authored Aug 27, 2024
1 parent 924f9c4 commit 95ba4af
Show file tree
Hide file tree
Showing 9 changed files with 438 additions and 73 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1997](https://github.com/NibiruChain/nibiru/pull/1997) - refactor(evm): Remove unnecessary params: "enable_call", "enable_create".
- [#2000](https://github.com/NibiruChain/nibiru/pull/2000) - refactor(evm): simplify ERC-20 keeper methods
- [#2001](https://github.com/NibiruChain/nibiru/pull/2001) - refactor(evm): simplify FunToken methods and tests
- [#2002](https://github.com/NibiruChain/nibiru/pull/2002) - feat(evm): Add the account query to the EVM command. Cover the CLI with tests.
- [#2003](https://github.com/NibiruChain/nibiru/pull/2003) - fix(evm): fix FunToken conversions between Cosmos and EVM
- [#2004](https://github.com/NibiruChain/nibiru/pull/2004) - refactor(evm)!: replace `HexAddr` with `EIP55Addr`
- [#2006](https://github.com/NibiruChain/nibiru/pull/2006) - test(evm): e2e tests for eth_* endpoints
- [#2008](https://github.com/NibiruChain/nibiru/pull/2008) - refactor(evm): clean up precompile setups
- [#2008](https://github.com/NibiruChain/nibiru/pull/2008) - refactor(evm): clean up precompile setups
- [#2013](https://github.com/NibiruChain/nibiru/pull/2013) - chore(evm): Set appropriate gas value for the required gas of the "IFunToken.sol" precompile.
- [#2014](https://github.com/NibiruChain/nibiru/pull/2014) - feat(evm): Emit block bloom event in EndBlock hook.

Expand Down
11 changes: 6 additions & 5 deletions app/evmante/evmante_sigverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ func NewEthSigVerificationDecorator(k EVMKeeper) EthSigVerificationDecorator {
}
}

// AnteHandle validates checks that the registered chain id is the same as the one on the message, and
// that the signer address matches the one defined on the message.
// It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work.
// Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user
// won't see the error message.
// AnteHandle validates checks that the registered chain id is the same as the
// one on the message, and that the signer address matches the one defined on the
// message. It's not skipped for RecheckTx, because it set `From` address which
// is critical from other ante handler to work. Failure in RecheckTx will prevent
// tx to be included into block, especially when CheckTx succeed, in which case
// user won't see the error message.
func (esvd EthSigVerificationDecorator) AnteHandle(
ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler,
) (newCtx sdk.Context, err error) {
Expand Down
115 changes: 115 additions & 0 deletions x/evm/cli/cli_setup_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package cli_test

import (
"context"
"io"
"testing"

"github.com/stretchr/testify/suite"

rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock"
sdkclient "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdktestutil "github.com/cosmos/cosmos-sdk/testutil"
sdktestutilcli "github.com/cosmos/cosmos-sdk/testutil/cli"
testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil"

svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"

"github.com/NibiruChain/nibiru/v2/x/evm/cli"
"github.com/NibiruChain/nibiru/v2/x/evm/evmmodule"
)

type Suite struct {
suite.Suite

keyring keyring.Keyring
encCfg testutilmod.TestEncodingConfig
baseCtx sdkclient.Context
clientCtx sdkclient.Context

testAcc sdktestutil.TestAccount
}

func (s *Suite) SetupSuite() {
s.encCfg = testutilmod.MakeTestEncodingConfig(evmmodule.AppModuleBasic{})
s.keyring = keyring.NewInMemory(s.encCfg.Codec)
s.baseCtx = sdkclient.Context{}.
WithKeyring(s.keyring).
WithTxConfig(s.encCfg.TxConfig).
WithCodec(s.encCfg.Codec).
WithClient(sdktestutilcli.MockTendermintRPC{Client: rpcclientmock.Client{}}).
WithAccountRetriever(sdkclient.MockAccountRetriever{}).
WithOutput(io.Discard).
WithChainID("test-chain")

s.clientCtx = s.baseCtx

testAccs := sdktestutil.CreateKeyringAccounts(s.T(), s.keyring, 1)
s.testAcc = testAccs[0]
}

func TestSuite(t *testing.T) {
suite.Run(t, new(Suite))
}

// Flags for broadcasting transactions
func commonTxArgs() []string {
return []string{
"--yes=true", // skip confirmation
"--broadcast-mode=sync",
"--fees=1unibi",
"--chain-id=test-chain",
}
}

type TestCase struct {
name string
args []string
extraArgs []string
wantErr string
}

func (tc TestCase) NewCtx(s *Suite) sdkclient.Context {
return s.baseCtx
}

func (tc TestCase) RunTxCmd(s *Suite) {
s.Run(tc.name, func() {
ctx := svrcmd.CreateExecuteContext(context.Background())

cmd := cli.GetTxCmd()
cmd.SetContext(ctx)
args := append(tc.args, commonTxArgs()...)
cmd.SetArgs(append(args, tc.extraArgs...))

s.Require().NoError(sdkclient.SetCmdClientContextHandler(tc.NewCtx(s), cmd))

err := cmd.Execute()
if tc.wantErr != "" {
s.Require().ErrorContains(err, tc.wantErr)
return
}
s.Require().NoError(err)
})
}

func (tc TestCase) RunQueryCmd(s *Suite) {
s.Run(tc.name, func() {
ctx := svrcmd.CreateExecuteContext(context.Background())

cmd := cli.GetQueryCmd()
cmd.SetContext(ctx)
args := tc.args // don't append common tx args
cmd.SetArgs(append(args, tc.extraArgs...))

s.Require().NoError(sdkclient.SetCmdClientContextHandler(tc.NewCtx(s), cmd))

err := cmd.Execute()
if tc.wantErr != "" {
s.Require().ErrorContains(err, tc.wantErr)
return
}
s.Require().NoError(err)
})
}
173 changes: 173 additions & 0 deletions x/evm/cli/cli_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package cli_test

import (
"fmt"
"math/big"

gethcommon "github.com/ethereum/go-ethereum/common"

"github.com/NibiruChain/nibiru/v2/x/evm"
"github.com/NibiruChain/nibiru/v2/x/evm/evmtest"
)

var (
dummyAccs = evmtest.NewEthPrivAccs(3)
dummyEthAddr = dummyAccs[1].EthAddr.Hex()
dummyFuntoken = evm.NewFunToken(
gethcommon.BigToAddress(big.NewInt(123)),
"ibc/testtoken",
false,
)
)

func (s *Suite) TestCmdConvertCoinToEvm() {
testCases := []TestCase{
{
name: "happy: convert-coin-to-evm",
args: []string{
"convert-coin-to-evm",
dummyEthAddr,
fmt.Sprintf("%d%s", 123, dummyFuntoken.BankDenom),
},
extraArgs: []string{fmt.Sprintf("--from=%s", s.testAcc.Address)},
wantErr: "",
},
{
name: "sad: coin format",
args: []string{
"convert-coin-to-evm",
dummyAccs[1].EthAddr.Hex(),
fmt.Sprintf("%s %d", dummyFuntoken.BankDenom, 123),
},
extraArgs: []string{fmt.Sprintf("--from=%s", s.testAcc.Address)},
wantErr: "invalid decimal coin expression",
},
}

for _, tc := range testCases {
tc.RunTxCmd(s)
}
}

func (s *Suite) TestCmdCreateFunToken() {
testCases := []TestCase{
{
name: "happy: create-funtoken (erc20)",
args: []string{
"create-funtoken",
fmt.Sprintf("--erc20=%s", dummyEthAddr),
},
extraArgs: []string{fmt.Sprintf("--from=%s", s.testAcc.Address)},
wantErr: "",
},
{
name: "happy: create-funtoken (bank coin)",
args: []string{
"create-funtoken",
fmt.Sprintf("--bank-denom=%s", dummyFuntoken.BankDenom),
},
extraArgs: []string{fmt.Sprintf("--from=%s", s.testAcc.Address)},
wantErr: "",
},
{
name: "sad: too many args",
args: []string{
"create-funtoken",
fmt.Sprintf("--erc20=%s", dummyEthAddr),
fmt.Sprintf("--bank-denom=%s", dummyFuntoken.BankDenom),
},
extraArgs: []string{fmt.Sprintf("--from=%s", s.testAcc.Address)},
wantErr: "exactly one of the flags --bank-denom or --erc20 must be specified",
},
}

for _, tc := range testCases {
tc.RunTxCmd(s)
}
}

func (s *Suite) TestCmdQueryAccount() {
testCases := []TestCase{
{
name: "happy: query account (bech32)",
args: []string{
"account",
dummyAccs[0].NibiruAddr.String(),
},
wantErr: "",
},
{
name: "happy: query account (eth hex)",
args: []string{
"account",
dummyAccs[0].EthAddr.Hex(),
},
wantErr: "",
},
{
name: "happy: query account (eth hex) --offline",
args: []string{
"account",
dummyAccs[0].EthAddr.Hex(),
"--offline",
},
wantErr: "",
},
{
name: "happy: query account (bech32) --offline",
args: []string{
"account",
dummyAccs[0].NibiruAddr.String(),
"--offline",
},
wantErr: "",
},
{
name: "sad: too many args",
args: []string{
"funtoken",
"arg1",
"arg2",
},
wantErr: "accepts 1 arg",
},
}

for _, tc := range testCases {
tc.RunQueryCmd(s)
}
}

func (s *Suite) TestCmdQueryFunToken() {
testCases := []TestCase{
{
name: "happy: query funtoken (bank coin denom)",
args: []string{
"funtoken",
dummyFuntoken.BankDenom,
},
wantErr: "",
},
{
name: "happy: query funtoken (erc20 addr)",
args: []string{
"funtoken",
dummyFuntoken.Erc20Addr.String(),
},
wantErr: "",
},
{
name: "sad: too many args",
args: []string{
"funtoken",
"arg1",
"arg2",
},
wantErr: "accepts 1 arg",
},
}

for _, tc := range testCases {
tc.RunQueryCmd(s)
}
}
Loading

0 comments on commit 95ba4af

Please sign in to comment.