Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 0 additions & 6 deletions tests/integration/precompiles/werc20/test_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,6 @@ func (s *PrecompileUnitTestSuite) TestEmitDepositEvent() {
{
name: "mainnet",
chainID: testconstants.ExampleChainID,
}, {
name: "six decimals",
chainID: testconstants.SixDecimalsChainID,
},
}

Expand Down Expand Up @@ -160,9 +157,6 @@ func (s *PrecompileUnitTestSuite) TestEmitWithdrawalEvent() {
{
name: "mainnet",
chainID: testconstants.ExampleChainID,
}, {
name: "six decimals",
chainID: testconstants.SixDecimalsChainID,
},
}

Expand Down
8 changes: 0 additions & 8 deletions tests/integration/testutil/test_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (

func (s *TestSuite) TestWithChainID() {
eighteenDecimalsCoinInfo := testconstants.ExampleChainCoinInfo[testconstants.ExampleChainID]
sixDecimalsCoinInfo := testconstants.ExampleChainCoinInfo[testconstants.SixDecimalsChainID]

testCases := []struct {
name string
Expand All @@ -34,13 +33,6 @@ func (s *TestSuite) TestWithChainID() {
expBaseFee: math.LegacyNewDec(875_000_000),
expCosmosAmount: network.GetInitialAmount(evmtypes.EighteenDecimals),
},
{
name: "6 decimals",
chainID: testconstants.SixDecimalsChainID,
coinInfo: sixDecimalsCoinInfo,
expBaseFee: math.LegacyNewDecWithPrec(875, 6),
expCosmosAmount: network.GetInitialAmount(evmtypes.SixDecimals),
},
}

for _, tc := range testCases {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package erc20

import (
"fmt"
"math/big"
"math/rand"

"github.com/cosmos/evm/contracts"
"github.com/cosmos/evm/x/erc20/types"

"cosmossdk.io/math"

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

// TestRandomizedConvertRoundTripInvariant runs randomized convert sequences and
// asserts that sender coin/token balances always conserve value.
func (s *KeeperTestSuite) TestRandomizedConvertRoundTripInvariant() {
const (
initialMint = int64(5_000)
steps = 50
)

for _, seed := range []int64{1, 7, 42, 777, 2026} {
s.Run(fmt.Sprintf("seed-%d", seed), func() {
s.mintFeeCollector = true
defer func() {
s.mintFeeCollector = false
}()
s.SetupTest()

contractAddr, err := s.setupRegisterERC20Pair(contractMinterBurner)
s.Require().NoError(err)

senderAcc := s.keyring.GetAccAddr(0)
senderHex := s.keyring.GetAddr(0)
denom := types.CreateDenom(contractAddr.String())
total := math.NewInt(initialMint)

_, err = s.MintERC20Token(contractAddr, senderHex, big.NewInt(initialMint))
s.Require().NoError(err)

rng := rand.New(rand.NewSource(seed))
erc20Keeper := s.network.App.GetErc20Keeper()
bankKeeper := s.network.App.GetBankKeeper()
erc20ABI := contracts.ERC20MinterBurnerDecimalsContract.ABI

for i := 0; i < steps; i++ {
ctx := s.network.GetContext()
erc20Bal := erc20Keeper.BalanceOf(ctx, erc20ABI, contractAddr, senderHex)
coinBal := bankKeeper.GetBalance(ctx, senderAcc, denom).Amount

combined := new(big.Int).Add(erc20Bal, coinBal.BigInt())
s.Require().Equal(total.String(), combined.String(), "value should be conserved before step")

convertFromERC20 := rng.Intn(2) == 0
if erc20Bal.Sign() == 0 {
convertFromERC20 = false
}
if coinBal.IsZero() {
convertFromERC20 = true
}

if convertFromERC20 {
max := erc20Bal.Int64()

Check failure on line 65 in tests/integration/x/erc20/test_conversion_invariants_randomized.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

redefines-builtin-id: redefinition of the built-in function max (revive)
amount := int64(rng.Intn(int(max)) + 1)
_, err = erc20Keeper.ConvertERC20(
ctx,
types.NewMsgConvertERC20(math.NewInt(amount), senderAcc, contractAddr, senderHex),
)
s.Require().NoError(err)
} else {
max := coinBal.Int64()

Check failure on line 73 in tests/integration/x/erc20/test_conversion_invariants_randomized.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

redefines-builtin-id: redefinition of the built-in function max (revive)
amount := int64(rng.Intn(int(max)) + 1)
_, err = erc20Keeper.ConvertCoin(
ctx,
types.NewMsgConvertCoin(sdk.NewCoin(denom, math.NewInt(amount)), senderHex, senderAcc),
)
s.Require().NoError(err)
}
}

ctx := s.network.GetContext()
finalERC20Bal := erc20Keeper.BalanceOf(ctx, erc20ABI, contractAddr, senderHex)
finalCoinBal := bankKeeper.GetBalance(ctx, senderAcc, denom).Amount
finalCombined := new(big.Int).Add(finalERC20Bal, finalCoinBal.BigInt())
s.Require().Equal(total.String(), finalCombined.String(), "value should be conserved after sequence")
})
}
}
55 changes: 0 additions & 55 deletions testutil/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,32 +47,13 @@ var ChainsCoinInfo = map[uint64]evmtypes.EvmCoinInfo{ // TODO:VLAD - deduplicate
DisplayDenom: ExampleDisplayDenom,
Decimals: evmtypes.EighteenDecimals.Uint32(),
},
// SixDecimalsChainID provides a chain ID which is being set up with 6 decimals
SixDecimalsChainID.EVMChainID: {
Denom: "utest",
ExtendedDenom: "atest",
DisplayDenom: "test",
Decimals: evmtypes.SixDecimals.Uint32(),
},
// EVMChainID provides a chain ID used for internal testing
config.DefaultEVMChainID: {
Denom: "atest",
ExtendedDenom: "atest",
DisplayDenom: "test",
Decimals: evmtypes.EighteenDecimals.Uint32(),
},
TwelveDecimalsChainID.EVMChainID: {
Denom: "ptest2",
ExtendedDenom: "atest2",
DisplayDenom: "test2",
Decimals: evmtypes.TwelveDecimals.Uint32(),
},
TwoDecimalsChainID.EVMChainID: {
Denom: "ctest3",
ExtendedDenom: "atest3",
DisplayDenom: "test3",
Decimals: evmtypes.TwoDecimals.Uint32(),
},
}

type ChainID struct {
Expand All @@ -90,24 +71,6 @@ var (
EVMChainID: 9001,
}

// SixDecimalsChainID provides a chain ID which is being set up with 6 decimals
SixDecimalsChainID = ChainID{
ChainID: "ossix-2",
EVMChainID: 9002,
}

// TwelveDecimalsChainID provides a chain ID which is being set up with 12 decimals
TwelveDecimalsChainID = ChainID{
ChainID: "ostwelve-3",
EVMChainID: 9003,
}

// TwoDecimalsChainID provides a chain ID which is being set up with 2 decimals
TwoDecimalsChainID = ChainID{
ChainID: "ostwo-4",
EVMChainID: 9004,
}

// ExampleChainCoinInfo provides the coin info for the example chain
//
// It is a map of the chain id and its corresponding EvmCoinInfo
Expand All @@ -120,24 +83,6 @@ var (
DisplayDenom: ExampleDisplayDenom,
Decimals: evmtypes.EighteenDecimals.Uint32(),
},
SixDecimalsChainID: {
Denom: "utest",
ExtendedDenom: "atest",
DisplayDenom: "test",
Decimals: evmtypes.SixDecimals.Uint32(),
},
TwelveDecimalsChainID: {
Denom: "ptest2",
ExtendedDenom: "atest2",
DisplayDenom: "test2",
Decimals: evmtypes.TwelveDecimals.Uint32(),
},
TwoDecimalsChainID: {
Denom: "ctest3",
ExtendedDenom: "atest3",
DisplayDenom: "test3",
Decimals: evmtypes.TwoDecimals.Uint32(),
},
}

// OtherCoinDenoms provides a list of other coin denoms that can be used in tests
Expand Down
17 changes: 14 additions & 3 deletions utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -793,10 +793,21 @@ func TestCalcBaseFee(t *testing.T) {
}

func TestCalcBaseFeeRejectsUnsupportedDecimals(t *testing.T) {
for _, chainID := range []constants.ChainID{constants.TwelveDecimalsChainID, constants.SixDecimalsChainID} {
t.Run(chainID.ChainID, func(t *testing.T) {
for _, tc := range []struct {
name string
decimals uint32
}{
{name: "twelve", decimals: evmtypes.TwelveDecimals.Uint32()},
{name: "six", decimals: evmtypes.SixDecimals.Uint32()},
} {
t.Run(tc.name, func(t *testing.T) {
evmConfigurator := evmtypes.NewEVMConfigurator().
WithEVMCoinInfo(constants.ExampleChainCoinInfo[chainID])
WithEVMCoinInfo(evmtypes.EvmCoinInfo{
Denom: constants.ExampleAttoDenom,
ExtendedDenom: constants.ExampleAttoDenom,
DisplayDenom: "custom",
Decimals: tc.decimals,
})
evmConfigurator.ResetTestConfig()
err := evmConfigurator.Configure()
require.ErrorContains(t, err, "only 18 is supported")
Expand Down
14 changes: 12 additions & 2 deletions x/vm/types/configurator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,18 @@ func TestEVMConfigurator(t *testing.T) {

func TestEVMConfiguratorRejectsNon18Decimals(t *testing.T) {
for _, coinInfo := range []types.EvmCoinInfo{
testconstants.ExampleChainCoinInfo[testconstants.SixDecimalsChainID],
testconstants.ExampleChainCoinInfo[testconstants.TwelveDecimalsChainID],
{
Denom: testconstants.ExampleAttoDenom,
ExtendedDenom: testconstants.ExampleAttoDenom,
DisplayDenom: "custom6",
Decimals: types.SixDecimals.Uint32(),
},
{
Denom: testconstants.ExampleAttoDenom,
ExtendedDenom: testconstants.ExampleAttoDenom,
DisplayDenom: "custom12",
Decimals: types.TwelveDecimals.Uint32(),
},
} {
t.Run(coinInfo.DisplayDenom, func(t *testing.T) {
ec := types.NewEVMConfigurator().WithEVMCoinInfo(coinInfo)
Expand Down
52 changes: 52 additions & 0 deletions x/vm/types/scaling_fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package types_test

import (
"testing"

testconstants "github.com/cosmos/evm/testutil/constants"
evmtypes "github.com/cosmos/evm/x/vm/types"

"cosmossdk.io/math"

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

func FuzzConvertCoinsDenomToExtendedDenomWithEvmParams(f *testing.F) {
f.Add(uint64(0), false)
f.Add(uint64(1), false)
f.Add(uint64(1_000_000_000_000_000_000), true)
f.Add(uint64(42), true)

coinInfo := testconstants.ExampleChainCoinInfo[testconstants.ExampleChainID]
params := evmtypes.Params{
EvmDenom: coinInfo.Denom,
ExtendedDenomOptions: &evmtypes.ExtendedDenomOptions{
ExtendedDenom: coinInfo.ExtendedDenom,
},
}

f.Fuzz(func(t *testing.T, amount uint64, includeOtherDenom bool) {
input := sdk.NewCoins(sdk.NewCoin(coinInfo.Denom, math.NewIntFromUint64(amount)))
if includeOtherDenom {
input = input.Add(sdk.NewCoin("other", math.NewIntFromUint64(amount+1))).Sort()
}
Comment thread
aljo242 marked this conversation as resolved.
Outdated

converted := evmtypes.ConvertCoinsDenomToExtendedDenomWithEvmParams(input, params)
convertedAgain := evmtypes.ConvertCoinsDenomToExtendedDenomWithEvmParams(converted, params)

// Conversion should be idempotent.
if !convertedAgain.Equal(converted) {
t.Fatalf("expected idempotent conversion, got %s then %s", converted, convertedAgain)
}

// EVM coin amount should be preserved under denom relabeling.
if converted.AmountOf(coinInfo.ExtendedDenom).String() != math.NewIntFromUint64(amount).String() {
t.Fatalf("unexpected converted amount: %s", converted.AmountOf(coinInfo.ExtendedDenom))
}

// Non-EVM denoms should be preserved.
if includeOtherDenom && converted.AmountOf("other").String() != math.NewIntFromUint64(amount+1).String() {
t.Fatalf("unexpected non-evm denom amount: %s", converted.AmountOf("other"))
}
})
}
Loading