Skip to content

Commit

Permalink
tests(erc20): adjust transfer from unit tests to not rely on own acco…
Browse files Browse the repository at this point in the history
…unt spending (evmos#2098)

* adjust transfer from unit tests which were relying on own account transfers

* address linter
  • Loading branch information
MalteHerrmann authored Nov 29, 2023
1 parent 150b2e9 commit fa90228
Showing 1 changed file with 67 additions and 15 deletions.
82 changes: 67 additions & 15 deletions precompiles/erc20/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package erc20_test

import (
"math/big"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/evmos/evmos/v15/precompiles/erc20"
"github.com/evmos/evmos/v15/precompiles/testutil"
Expand All @@ -12,8 +14,9 @@ import (
)

var (
tokenDenom = "xmpl"
// XMPLCoin is a dummy coin used for testing purposes.
XMPLCoin = sdk.NewCoins(sdk.NewCoin("xmpl", sdk.NewInt(1e18)))
XMPLCoin = sdk.NewCoins(sdk.NewInt64Coin(tokenDenom, 1e18))
// toAddr is a dummy address used for testing purposes.
toAddr = utiltx.GenerateAddress()
)
Expand Down Expand Up @@ -71,15 +74,14 @@ func (s *PrecompileTestSuite) TestTransfer() {
return []interface{}{toAddr, big.NewInt(100)}
},
func() {
toAddrBalance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), toAddr.Bytes(), "xmpl")
toAddrBalance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), toAddr.Bytes(), tokenDenom)
s.Require().Equal(big.NewInt(100), toAddrBalance.Amount.BigInt(), "expected toAddr to have 100 XMPL")
},
false,
"",
},
}

//nolint: dupl
for _, tc := range testcases {
tc := tc
s.Run(tc.name, func() {
Expand Down Expand Up @@ -109,8 +111,11 @@ func (s *PrecompileTestSuite) TestTransfer() {

func (s *PrecompileTestSuite) TestTransferFrom() {
method := s.precompile.Methods[erc20.TransferFromMethod]
// fromAddr is the address of the keyring account used for testing.
fromAddr := s.keyring.GetKey(0).Addr
// owner of the tokens
owner := s.keyring.GetKey(0)
// spender of the tokens
spender := s.keyring.GetKey(1)

testcases := []struct {
name string
malleate func() []interface{}
Expand All @@ -121,7 +126,7 @@ func (s *PrecompileTestSuite) TestTransferFrom() {
{
"fail - negative amount",
func() []interface{} {
return []interface{}{fromAddr, toAddr, big.NewInt(-1)}
return []interface{}{owner.Addr, toAddr, big.NewInt(-1)}
},
func() {},
true,
Expand All @@ -139,7 +144,7 @@ func (s *PrecompileTestSuite) TestTransferFrom() {
{
"fail - invalid to address",
func() []interface{} {
return []interface{}{fromAddr, "", big.NewInt(100)}
return []interface{}{owner.Addr, "", big.NewInt(100)}
},
func() {},
true,
Expand All @@ -148,49 +153,96 @@ func (s *PrecompileTestSuite) TestTransferFrom() {
{
"fail - invalid amount",
func() []interface{} {
return []interface{}{fromAddr, toAddr, ""}
return []interface{}{owner.Addr, toAddr, ""}
},
func() {},
true,
"invalid amount",
},
{
"fail - not enough allowance",
func() []interface{} {
return []interface{}{owner.Addr, toAddr, big.NewInt(100)}
},
func() {},
true,
erc20.ErrInsufficientAllowance.Error(),
},
{
"fail - not enough balance",
func() []interface{} {
return []interface{}{fromAddr, toAddr, big.NewInt(2e18)}
expiration := time.Now().Add(time.Hour)
err := s.network.App.AuthzKeeper.SaveGrant(
s.network.GetContext(),
spender.AccAddr,
owner.AccAddr,
&banktypes.SendAuthorization{SpendLimit: sdk.Coins{sdk.Coin{Denom: s.tokenDenom, Amount: sdk.NewInt(5e18)}}},
&expiration,
)
s.Require().NoError(err, "failed to save grant")

return []interface{}{owner.Addr, toAddr, big.NewInt(2e18)}
},
func() {},
true,
erc20.ErrTransferAmountExceedsBalance.Error(),
},
{
"pass",
"pass - spend on behalf of other account",
func() []interface{} {
expiration := time.Now().Add(time.Hour)
err := s.network.App.AuthzKeeper.SaveGrant(
s.network.GetContext(),
spender.AccAddr,
owner.AccAddr,
&banktypes.SendAuthorization{SpendLimit: sdk.Coins{sdk.Coin{Denom: tokenDenom, Amount: sdk.NewInt(300)}}},
&expiration,
)
s.Require().NoError(err, "failed to save grant")

return []interface{}{owner.Addr, toAddr, big.NewInt(100)}
},
func() {
toAddrBalance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), toAddr.Bytes(), tokenDenom)
s.Require().Equal(big.NewInt(100), toAddrBalance.Amount.BigInt(), "expected toAddr to have 100 XMPL")
},
false,
"",
},
{
"pass - spend on behalf of own account",
func() []interface{} {
return []interface{}{fromAddr, toAddr, big.NewInt(100)}
// Mint some coins to the module account and then send to the spender address
err := s.network.App.BankKeeper.MintCoins(s.network.GetContext(), erc20types.ModuleName, XMPLCoin)
s.Require().NoError(err, "failed to mint coins")
err = s.network.App.BankKeeper.SendCoinsFromModuleToAccount(s.network.GetContext(), erc20types.ModuleName, spender.AccAddr, XMPLCoin)
s.Require().NoError(err, "failed to send coins from module to account")

// NOTE: no authorization is necessary to spend on behalf of the same account
return []interface{}{spender.Addr, toAddr, big.NewInt(100)}
},
func() {
toAddrBalance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), toAddr.Bytes(), "xmpl")
toAddrBalance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), toAddr.Bytes(), tokenDenom)
s.Require().Equal(big.NewInt(100), toAddrBalance.Amount.BigInt(), "expected toAddr to have 100 XMPL")
},
false,
"",
},
}

//nolint: dupl
for _, tc := range testcases {
tc := tc
s.Run(tc.name, func() {
s.SetupTest()
stateDB := s.network.GetStateDB()

var contract *vm.Contract
contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), fromAddr, s.precompile, 0)
contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), spender.Addr, s.precompile, 0)

// Mint some coins to the module account and then send to the from address
err := s.network.App.BankKeeper.MintCoins(s.network.GetContext(), erc20types.ModuleName, XMPLCoin)
s.Require().NoError(err, "failed to mint coins")
err = s.network.App.BankKeeper.SendCoinsFromModuleToAccount(s.network.GetContext(), erc20types.ModuleName, fromAddr.Bytes(), XMPLCoin)
err = s.network.App.BankKeeper.SendCoinsFromModuleToAccount(s.network.GetContext(), erc20types.ModuleName, owner.AccAddr, XMPLCoin)
s.Require().NoError(err, "failed to send coins from module to account")

_, err = s.precompile.TransferFrom(ctx, contract, stateDB, &method, tc.malleate())
Expand Down

0 comments on commit fa90228

Please sign in to comment.