Skip to content

Commit

Permalink
fix: tests for evm fun token tx
Browse files Browse the repository at this point in the history
  • Loading branch information
onikonychev committed Jun 29, 2024
2 parents 1931969 + 2c1198d commit 8683f97
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 51 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#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
- [#1946](https://github.com/NibiruChain/nibiru/pull/1946) - feat(evm): tx for creating fun token from coin
- [#1947](https://github.com/NibiruChain/nibiru/pull/1947) - fix(evm): fix FunToken state marshalling

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

Expand Down
6 changes: 3 additions & 3 deletions eth/hex.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type HexAddr string

var _ sdk.CustomProtobufType = (*HexAddr)(nil)

func NewHexAddr(addr EthAddr) HexAddr {
func NewHexAddr(addr gethcommon.Address) HexAddr {
return HexAddr(addr.Hex())
}

Expand Down Expand Up @@ -58,7 +58,7 @@ func (h HexAddr) Valid() error {
return nil
}

func (h HexAddr) ToAddr() EthAddr {
func (h HexAddr) ToAddr() gethcommon.Address {
return gethcommon.HexToAddress(string(h))
}

Expand Down Expand Up @@ -88,7 +88,7 @@ func (h HexAddr) MarshalJSON() ([]byte, error) {
// Implements the gogo proto custom type interface.
// Ref: https://github.com/cosmos/gogoproto/blob/v1.5.0/custom_types.md
func (h *HexAddr) MarshalTo(data []byte) (n int, err error) {
bz := []byte{}
bz := []byte(*h)
copy(data, bz)
hexAddr, err := NewHexAddrFromStr(string(bz))
*h = hexAddr
Expand Down
9 changes: 9 additions & 0 deletions eth/hex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,12 @@ func (s *Suite) TestProtobufEncoding() {
})
}
}

func (s *Suite) TestHexAddrToString() {
hexAddr := eth.HexAddr("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")
s.Equal("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", hexAddr.String())
s.Equal("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", string(hexAddr))

ethAddr := gethcommon.HexToAddress("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")
s.Equal("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", ethAddr.String())
}
32 changes: 13 additions & 19 deletions eth/state_encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,18 @@ func BytesToHex(bz []byte) string {
return fmt.Sprintf("%x", bz)
}

// EthAddr: (alias) 20 byte address of an Ethereum account.
type EthAddr = gethcommon.Address

// EthHash: (alias) 32 byte Keccak256 hash of arbitrary data.
type EthHash = gethcommon.Hash //revive:disable-line:exported

var (
// Implements a `collections.ValueEncoder` for the `[]byte` type
ValueEncoderBytes collections.ValueEncoder[[]byte] = veBytes{}
KeyEncoderBytes collections.KeyEncoder[[]byte] = keBytes{}

// Implements a `collections.ValueEncoder` for an Ethereum address.
ValueEncoderEthAddr collections.ValueEncoder[EthAddr] = veEthAddr{}
ValueEncoderEthAddr collections.ValueEncoder[gethcommon.Address] = veEthAddr{}
// keEthHash: Implements a `collections.KeyEncoder` for an Ethereum address.
KeyEncoderEthAddr collections.KeyEncoder[EthAddr] = keEthAddr{}
KeyEncoderEthAddr collections.KeyEncoder[gethcommon.Address] = keEthAddr{}

// keEthHash: Implements a `collections.KeyEncoder` for an Ethereum hash.
KeyEncoderEthHash collections.KeyEncoder[EthHash] = keEthHash{}
KeyEncoderEthHash collections.KeyEncoder[gethcommon.Hash] = keEthHash{}
)

// collections ValueEncoder[[]byte]
Expand All @@ -43,10 +37,10 @@ func (_ veBytes) Name() string { return "[]byte" }
// veEthAddr: Implements a `collections.ValueEncoder` for an Ethereum address.
type veEthAddr struct{}

func (_ veEthAddr) Encode(value EthAddr) []byte { return value.Bytes() }
func (_ veEthAddr) Decode(bz []byte) EthAddr { return gethcommon.BytesToAddress(bz) }
func (_ veEthAddr) Stringify(value EthAddr) string { return value.Hex() }
func (_ veEthAddr) Name() string { return "EthAddr" }
func (_ veEthAddr) Encode(value gethcommon.Address) []byte { return value.Bytes() }
func (_ veEthAddr) Decode(bz []byte) gethcommon.Address { return gethcommon.BytesToAddress(bz) }
func (_ veEthAddr) Stringify(value gethcommon.Address) string { return value.Hex() }
func (_ veEthAddr) Name() string { return "gethcommon.Address" }

type keBytes struct{}

Expand All @@ -63,17 +57,17 @@ func (_ keBytes) Stringify(key []byte) string { return BytesToHex(key) }
// keEthAddr: Implements a `collections.KeyEncoder` for an Ethereum address.
type keEthAddr struct{}

func (_ keEthAddr) Encode(value EthAddr) []byte { return value.Bytes() }
func (_ keEthAddr) Decode(bz []byte) (int, EthAddr) {
func (_ keEthAddr) Encode(value gethcommon.Address) []byte { return value.Bytes() }
func (_ keEthAddr) Decode(bz []byte) (int, gethcommon.Address) {
return gethcommon.AddressLength, gethcommon.BytesToAddress(bz)
}
func (_ keEthAddr) Stringify(value EthAddr) string { return value.Hex() }
func (_ keEthAddr) Stringify(value gethcommon.Address) string { return value.Hex() }

// keEthHash: Implements a `collections.KeyEncoder` for an Ethereum hash.
type keEthHash struct{}

func (_ keEthHash) Encode(value EthHash) []byte { return value.Bytes() }
func (_ keEthHash) Decode(bz []byte) (int, EthHash) {
func (_ keEthHash) Encode(value gethcommon.Hash) []byte { return value.Bytes() }
func (_ keEthHash) Decode(bz []byte) (int, gethcommon.Hash) {
return gethcommon.HashLength, gethcommon.BytesToHash(bz)
}
func (_ keEthHash) Stringify(value EthHash) string { return value.Hex() }
func (_ keEthHash) Stringify(value gethcommon.Hash) string { return value.Hex() }
4 changes: 2 additions & 2 deletions eth/state_encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (s *Suite) TestEncoderBytes() {
func (s *Suite) TestEncoderEthAddr() {
testCases := []struct {
name string
given eth.EthAddr
given gethcommon.Address
wantPanic bool
}{
{
Expand All @@ -77,7 +77,7 @@ func (s *Suite) TestEncoderEthAddr() {
},
{
name: "Nibiru Bech 32 addr (hypothetically)",
given: eth.EthAddr([]byte("nibi1rlvdjfmxkyfj4tzu73p8m4g2h4y89xccf9622l")),
given: gethcommon.Address([]byte("nibi1rlvdjfmxkyfj4tzu73p8m4g2h4y89xccf9622l")),
},
}
for _, tc := range testCases {
Expand Down
19 changes: 7 additions & 12 deletions x/evm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,24 @@ import (
// tokens that are valid ERC20s with the same address.
// https://github.com/NibiruChain/nibiru/issues/1933
func (fun FunToken) ID() []byte {
return newFunTokenIDFromStr(fun.Erc20Addr.String(), fun.BankDenom)
return NewFunTokenID(fun.Erc20Addr, fun.BankDenom)
}

func NewFunTokenID(erc20 gethcommon.Address, bankDenom string) []byte {
erc20Addr := erc20.Hex()
return newFunTokenIDFromStr(erc20Addr, bankDenom)
func NewFunTokenID(erc20 eth.HexAddr, bankDenom string) []byte {
return tmhash.Sum([]byte(erc20.String() + "|" + bankDenom))
}

func newFunTokenIDFromStr(erc20AddrHex string, bankDenom string) []byte {
return tmhash.Sum([]byte(erc20AddrHex + "|" + bankDenom))
}

func errValidateFunToken(errMsg string) error {
return fmt.Errorf("FunTokenError: %s", errMsg)
func funTokenValidationError(err error) error {
return fmt.Errorf("FunTokenError: %s", err.Error())
}

func (fun FunToken) Validate() error {
if err := sdk.ValidateDenom(fun.BankDenom); err != nil {
return errValidateFunToken(err.Error())
return funTokenValidationError(err)
}

if err := fun.Erc20Addr.Valid(); err != nil {
return errValidateFunToken(err.Error())
return funTokenValidationError(err)
}

return nil
Expand Down
4 changes: 2 additions & 2 deletions x/evm/keeper/evm_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func (k Keeper) SetParams(ctx sdk.Context, params evm.Params) {

// SetState updates contract storage and deletes if the value is empty.
func (state EvmState) SetAccState(
ctx sdk.Context, addr eth.EthAddr, stateKey eth.EthHash, stateValue []byte,
ctx sdk.Context, addr gethcommon.Address, stateKey gethcommon.Hash, stateValue []byte,
) {
if len(stateValue) != 0 {
state.AccState.Insert(ctx, collections.Join(addr, stateKey), stateValue)
Expand All @@ -140,7 +140,7 @@ func (state EvmState) SetAccState(
}

// GetState: Implements `statedb.Keeper` interface: Loads smart contract state.
func (k *Keeper) GetState(ctx sdk.Context, addr eth.EthAddr, stateKey eth.EthHash) eth.EthHash {
func (k *Keeper) GetState(ctx sdk.Context, addr gethcommon.Address, stateKey gethcommon.Hash) gethcommon.Hash {
return gethcommon.BytesToHash(k.EvmState.AccState.GetOr(
ctx,
collections.Join(addr, stateKey),
Expand Down
18 changes: 6 additions & 12 deletions x/evm/keeper/funtoken_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,21 @@ import (

"github.com/NibiruChain/nibiru/eth"
"github.com/NibiruChain/nibiru/x/evm"
funtoken "github.com/NibiruChain/nibiru/x/evm"
)

type (
funtokenPrimaryKeyType = []byte
funtokenValueType = funtoken.FunToken
)

// FunTokenState isolates the key-value stores (collections) for fungible token
// mappings. This struct is written as an extension of the default indexed map to
// add utility functions.
type FunTokenState struct {
collections.IndexedMap[funtokenPrimaryKeyType, funtokenValueType, IndexesFunToken]
collections.IndexedMap[[]byte, evm.FunToken, IndexesFunToken]
}

func NewFunTokenState(
cdc sdkcodec.BinaryCodec,
storeKey storetypes.StoreKey,
) FunTokenState {
primaryKeyEncoder := eth.KeyEncoderBytes
valueEncoder := collections.ProtoValueEncoder[funtokenValueType](cdc)
valueEncoder := collections.ProtoValueEncoder[evm.FunToken](cdc)
idxMap := collections.NewIndexedMap(
storeKey, evm.KeyPrefixFunTokens, primaryKeyEncoder, valueEncoder,
IndexesFunToken{
Expand All @@ -53,8 +47,8 @@ func NewFunTokenState(
return FunTokenState{IndexedMap: idxMap}
}

func (idxs IndexesFunToken) IndexerList() []collections.Indexer[funtokenPrimaryKeyType, funtokenValueType] {
return []collections.Indexer[funtokenPrimaryKeyType, funtokenValueType]{
func (idxs IndexesFunToken) IndexerList() []collections.Indexer[[]byte, evm.FunToken] {
return []collections.Indexer[[]byte, evm.FunToken]{
idxs.ERC20Addr,
idxs.BankDenom,
}
Expand All @@ -66,13 +60,13 @@ type IndexesFunToken struct {
// - indexing key (IK): ERC-20 addr
// - primary key (PK): FunToken ID
// - value (V): FunToken value
ERC20Addr collections.MultiIndex[gethcommon.Address, funtokenPrimaryKeyType, funtokenValueType]
ERC20Addr collections.MultiIndex[gethcommon.Address, []byte, evm.FunToken]

// BankDenom (MultiIndex): Index FunToken by coin denomination
// - indexing key (IK): Coin denom
// - primary key (PK): FunToken ID
// - value (V): FunToken value
BankDenom collections.MultiIndex[string, funtokenPrimaryKeyType, funtokenValueType]
BankDenom collections.MultiIndex[string, []byte, evm.FunToken]
}

// Insert adds an [evm.FunToken] to state with defensive validation. Errors if
Expand Down
82 changes: 82 additions & 0 deletions x/evm/keeper/funtoken_state_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package keeper_test

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

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

func (s *KeeperSuite) TestInsertAndGet() {
deps := evmtest.NewTestDeps()

erc20Addr := gethcommon.HexToAddress("0xAEf9437FF23D48D73271a41a8A094DEc9ac71477")
err := deps.K.FunTokens.SafeInsert(
deps.Ctx,
erc20Addr,
"unibi",
true,
)
s.Require().NoError(err)

// test Get
funToken, err := deps.K.FunTokens.Get(deps.Ctx, evm.NewFunTokenID(eth.NewHexAddr(erc20Addr), "unibi"))
s.Require().NoError(err)
s.Require().Equal(eth.HexAddr("0xAEf9437FF23D48D73271a41a8A094DEc9ac71477"), funToken.Erc20Addr)
s.Require().Equal("unibi", funToken.BankDenom)
s.Require().True(funToken.IsMadeFromCoin)

// iter := deps.K.FunTokens.Indexes.BankDenom.ExactMatch(deps.Ctx, "unibi")
// deps.K.FunTokens.Collect(ctx)
}

func (s *KeeperSuite) TestCollect() {
deps := evmtest.NewTestDeps()

erc20Addr := gethcommon.HexToAddress("0xAEf9437FF23D48D73271a41a8A094DEc9ac71477")
err := deps.K.FunTokens.SafeInsert(
deps.Ctx,
erc20Addr,
"unibi",
true,
)
s.Require().NoError(err)

// test Collect by bank denom
iter := deps.K.FunTokens.Indexes.BankDenom.ExactMatch(deps.Ctx, "unibi")
funTokens := deps.K.FunTokens.Collect(deps.Ctx, iter)
s.Require().Len(funTokens, 1)
s.Require().Equal(eth.HexAddr("0xAEf9437FF23D48D73271a41a8A094DEc9ac71477"), funTokens[0].Erc20Addr)
s.Require().Equal("unibi", funTokens[0].BankDenom)
s.Require().True(funTokens[0].IsMadeFromCoin)

// test Collect by erc20 addr
iter2 := deps.K.FunTokens.Indexes.ERC20Addr.ExactMatch(deps.Ctx, erc20Addr)
funTokens = deps.K.FunTokens.Collect(deps.Ctx, iter2)
s.Require().Len(funTokens, 1)
s.Require().Equal(eth.HexAddr("0xAEf9437FF23D48D73271a41a8A094DEc9ac71477"), funTokens[0].Erc20Addr)
s.Require().Equal("unibi", funTokens[0].BankDenom)
s.Require().True(funTokens[0].IsMadeFromCoin)
}

func (s *KeeperSuite) TestDelete() {
deps := evmtest.NewTestDeps()

erc20Addr := gethcommon.HexToAddress("0xAEf9437FF23D48D73271a41a8A094DEc9ac71477")
err := deps.K.FunTokens.SafeInsert(
deps.Ctx,
erc20Addr,
"unibi",
true,
)
s.Require().NoError(err)

// test Delete
err = deps.K.FunTokens.Delete(deps.Ctx, evm.NewFunTokenID(eth.NewHexAddr(erc20Addr), "unibi"))
s.Require().NoError(err)

// test Get
_, err = deps.K.FunTokens.Get(deps.Ctx, evm.NewFunTokenID(eth.NewHexAddr(erc20Addr), "unibi"))
s.Require().Error(err)
}
2 changes: 1 addition & 1 deletion x/evm/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ func (msg *MsgCreateFunTokenFromCoin) ValidateBasic() error {
return fmt.Errorf("invalid sender: %s", msg.Sender)
}
if err := sdk.ValidateDenom(msg.Denom); err != nil {
return errValidateFunToken(err.Error())
return fmt.Errorf("invalid denom: %s", msg.Denom)
}
return nil
}
Expand Down

0 comments on commit 8683f97

Please sign in to comment.