Skip to content
This repository has been archived by the owner on Jul 30, 2024. It is now read-only.

Fix: wrong denom check at RegsterCoin and remove IBC-related tests #6

Merged
merged 7 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
351 changes: 0 additions & 351 deletions x/erc20/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -964,354 +964,3 @@ func (suite *KeeperTestSuite) TestWrongPairOwnerERC20NativeCoin() {
})
}
}

func (suite *KeeperTestSuite) TestConvertCoinNativeIBCVoucher() {
testCases := []struct {
name string
mint int64
burn int64
malleate func(common.Address)
extra func()
expPass bool
selfdestructed bool
}{
{
"ok - sufficient funds",
100,
10,
func(common.Address) {},
func() {},
true,
false,
},
{
"ok - equal funds",
10,
10,
func(common.Address) {},
func() {},
true,
false,
},
{
"ok - suicided contract",
10,
10,
func(erc20 common.Address) {
stateDb := suite.StateDB()
ok := stateDb.Suicide(erc20)
suite.Require().True(ok)
suite.Require().NoError(stateDb.Commit())
},
func() {},
true,
true,
},
{
"fail - insufficient funds",
0,
10,
func(common.Address) {},
func() {},
false,
false,
},
{
"fail - minting disabled",
100,
10,
func(common.Address) {
params := types.DefaultParams()
params.EnableErc20 = false
suite.app.Erc20Keeper.SetParams(suite.ctx, params)
},
func() {},
false,
false,
},
{
"fail - deleted module account - force fail", 100, 10, func(common.Address) {},
func() {
acc := suite.app.AccountKeeper.GetAccount(suite.ctx, types.ModuleAddress.Bytes())
suite.app.AccountKeeper.RemoveAccount(suite.ctx, acc)
}, false, false,
},
{
"fail - force evm fail", 100, 10, func(common.Address) {},
func() {
mockEVMKeeper := &MockEVMKeeper{}
sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName)
suite.Require().True(found)
suite.app.Erc20Keeper = keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper)

existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1}
balance := make([]uint8, 32)
mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil)
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once()
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error"))
mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil)
}, false, false,
},
{
"fail - force evm balance error", 100, 10, func(common.Address) {},
func() {
mockEVMKeeper := &MockEVMKeeper{}
sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName)
suite.Require().True(found)
suite.app.Erc20Keeper = keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper)

existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1}
balance := make([]uint8, 32)
mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil)
// first balance of
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once()
// convert coin
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil).Once()
// second balance of
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, fmt.Errorf("third")).Once()
// Extra call on test
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil)
mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil)
}, false, false,
},
{
"fail - force balance error", 100, 10, func(common.Address) {},
func() {
mockEVMKeeper := &MockEVMKeeper{}
sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName)
suite.Require().True(found)
suite.app.Erc20Keeper = keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper)

existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1}
balance := make([]uint8, 32)
mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil)
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Times(4)
mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil)
}, false, false,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.mintFeeCollector = true
suite.SetupTest()
metadata, pair := suite.setupRegisterIBCVoucher()
suite.Require().NotNil(metadata)
erc20 := pair.GetERC20Contract()
tc.malleate(erc20)
suite.Commit()

ctx := sdk.WrapSDKContext(suite.ctx)
coins := sdk.NewCoins(sdk.NewCoin(ibcBase, sdk.NewInt(tc.mint)))
sender := sdk.AccAddress(suite.address.Bytes())
msg := types.NewMsgConvertCoin(
sdk.NewCoin(ibcBase, sdk.NewInt(tc.burn)),
suite.address,
sender,
)

suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, coins)
suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, sender, coins)

tc.extra()
res, err := suite.app.Erc20Keeper.ConvertCoin(ctx, msg)
expRes := &types.MsgConvertCoinResponse{}
suite.Commit()
balance := suite.BalanceOf(common.HexToAddress(pair.Erc20Address), suite.address)
cosmosBalance := suite.app.BankKeeper.GetBalance(suite.ctx, sender, metadata.Base)

if tc.expPass {
suite.Require().NoError(err, tc.name)

acc := suite.app.EvmKeeper.GetAccountWithoutBalance(suite.ctx, erc20)
if tc.selfdestructed {
suite.Require().Nil(acc, "expected contract to be destroyed")
} else {
suite.Require().NotNil(acc)
}

if tc.selfdestructed || !acc.IsContract() {
id := suite.app.Erc20Keeper.GetTokenPairID(suite.ctx, erc20.String())
_, found := suite.app.Erc20Keeper.GetTokenPair(suite.ctx, id)
suite.Require().False(found)
} else {
suite.Require().Equal(expRes, res)
suite.Require().Equal(cosmosBalance.Amount.Int64(), sdk.NewInt(tc.mint-tc.burn).Int64())
suite.Require().Equal(balance.(*big.Int).Int64(), big.NewInt(tc.burn).Int64())
}
} else {
suite.Require().Error(err, tc.name)
}
})
}
suite.mintFeeCollector = false
}

func (suite *KeeperTestSuite) TestConvertERC20NativeIBCVoucher() {
testCases := []struct {
name string
mint int64
burn int64
reconvert int64
malleate func()
expPass bool
}{
{"ok - sufficient funds", 100, 10, 5, func() {}, true},
{"ok - equal funds", 10, 10, 10, func() {}, true},
{"fail - insufficient funds", 10, 1, 5, func() {}, false},
{"fail ", 10, 1, -5, func() {}, false},
{
"fail - deleted module account - force fail", 100, 10, 5,
func() {
acc := suite.app.AccountKeeper.GetAccount(suite.ctx, types.ModuleAddress.Bytes())
suite.app.AccountKeeper.RemoveAccount(suite.ctx, acc)
},
false,
},
{
"fail - force evm fail", 100, 10, 5,
func() {
mockEVMKeeper := &MockEVMKeeper{}
sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName)
suite.Require().True(found)
suite.app.Erc20Keeper = keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper)

existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1}
balance := make([]uint8, 32)
mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil)
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once()
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error"))
mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil)
},
false,
},
{
"fail - force fail second balance", 100, 10, 5,
func() {
mockEVMKeeper := &MockEVMKeeper{}
sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName)
suite.Require().True(found)
suite.app.Erc20Keeper = keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper)

existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1}
balance := make([]uint8, 32)
mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil)
// first balance of
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once()
// convert coin
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil).Once()
// second balance of
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, fmt.Errorf("third")).Once()
// Extra call on test
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil)
mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil)
},
false,
},
{
"fail - force fail second balance", 100, 10, 5,
func() {
mockEVMKeeper := &MockEVMKeeper{}
sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName)
suite.Require().True(found)
suite.app.Erc20Keeper = keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper)

existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1}
balance := make([]uint8, 32)
mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil)
// first balance of
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once()
// convert coin
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil).Once()
// second balance of
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once()
// Extra call on test
mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil)
mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil)
},
false,
},
{
"fail - force fail unescrow", 100, 10, 5,
func() {
mockBankKeeper := &MockBankKeeper{}
sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName)
suite.Require().True(found)
suite.app.Erc20Keeper = keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, mockBankKeeper, suite.app.EvmKeeper)

mockBankKeeper.On("SendCoinsFromModuleToAccount", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("failed to unescrow"))
mockBankKeeper.On("BlockedAddr", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(false)
mockBankKeeper.On("GetBalance", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sdk.Coin{Denom: "coin", Amount: sdk.OneInt()})
},
false,
},
{
"fail - force fail balance after transfer", 100, 10, 5,
func() {
mockBankKeeper := &MockBankKeeper{}
sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName)
suite.Require().True(found)
suite.app.Erc20Keeper = keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, mockBankKeeper, suite.app.EvmKeeper)

mockBankKeeper.On("SendCoinsFromModuleToAccount", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
mockBankKeeper.On("BlockedAddr", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(false)
mockBankKeeper.On("GetBalance", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sdk.Coin{Denom: ibcBase, Amount: sdk.OneInt()})
},
false,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.mintFeeCollector = true
suite.SetupTest()
metadata, pair := suite.setupRegisterIBCVoucher()
suite.Require().NotNil(metadata)
suite.Require().NotNil(pair)

// Precondition: Convert Coin to ERC20
coins := sdk.NewCoins(sdk.NewCoin(ibcBase, sdk.NewInt(tc.mint)))
sender := sdk.AccAddress(suite.address.Bytes())
suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, coins)
suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, sender, coins)
msg := types.NewMsgConvertCoin(
sdk.NewCoin(ibcBase, sdk.NewInt(tc.burn)),
suite.address,
sender,
)

ctx := sdk.WrapSDKContext(suite.ctx)
_, err := suite.app.Erc20Keeper.ConvertCoin(ctx, msg)
suite.Require().NoError(err, tc.name)
suite.Commit()
balance := suite.BalanceOf(common.HexToAddress(pair.Erc20Address), suite.address)
cosmosBalance := suite.app.BankKeeper.GetBalance(suite.ctx, sender, metadata.Base)
suite.Require().Equal(cosmosBalance.Amount.Int64(), sdk.NewInt(tc.mint-tc.burn).Int64())
suite.Require().Equal(balance, big.NewInt(tc.burn))

// Convert ERC20s back to Coins
ctx = sdk.WrapSDKContext(suite.ctx)
contractAddr := common.HexToAddress(pair.Erc20Address)
msgConvertERC20 := types.NewMsgConvertERC20(
sdk.NewInt(tc.reconvert),
sender,
contractAddr,
suite.address,
)

tc.malleate()
res, err := suite.app.Erc20Keeper.ConvertERC20(ctx, msgConvertERC20)
expRes := &types.MsgConvertERC20Response{}
suite.Commit()
balance = suite.BalanceOf(contractAddr, suite.address)
cosmosBalance = suite.app.BankKeeper.GetBalance(suite.ctx, sender, pair.Denom)
if tc.expPass {
suite.Require().NoError(err, tc.name)
suite.Require().Equal(expRes, res)
suite.Require().Equal(cosmosBalance.Amount.Int64(), sdk.NewInt(tc.mint-tc.burn+tc.reconvert).Int64())
suite.Require().Equal(balance.(*big.Int).Int64(), big.NewInt(tc.burn-tc.reconvert).Int64())
} else {
suite.Require().Error(err, tc.name)
}
})
}
suite.mintFeeCollector = false
}
2 changes: 1 addition & 1 deletion x/erc20/keeper/proposals.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (k Keeper) RegisterCoin(
}

// Check if denomination is already registered
if k.IsDenomRegistered(ctx, coinMetadata.Name) {
if k.IsDenomRegistered(ctx, coinMetadata.Base) {
return nil, sdkerrors.Wrapf(
types.ErrTokenPairAlreadyExists, "coin denomination already registered: %s", coinMetadata.Name,
)
Expand Down
Loading
Loading