Skip to content

Commit

Permalink
test: refactor the ERC20 token test suite (#789)
Browse files Browse the repository at this point in the history
  • Loading branch information
zakir-code authored Oct 29, 2024
1 parent 046e565 commit d2e8338
Show file tree
Hide file tree
Showing 18 changed files with 420 additions and 578 deletions.
5 changes: 2 additions & 3 deletions contract/erc20_abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ import (
"github.com/ethereum/go-ethereum/common"
)

// Deprecated: please use ERC20TokenKeeper
type ERC20ABI struct {
abi abi.ABI
}

func NewERC20ABI() ERC20ABI {
return ERC20ABI{
abi: GetWFX().ABI,
}
return ERC20ABI{}
}

func (e ERC20ABI) PackName() (data []byte, err error) {
Expand Down
104 changes: 76 additions & 28 deletions contract/erc20_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,51 @@ import (
"context"
"math/big"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/evmos/ethermint/x/evm/types"
)

type ERC20TokenKeeper struct {
Caller
abi abi.ABI
from common.Address
abi abi.ABI
}

func NewERC20TokenKeeper(caller Caller) ERC20TokenKeeper {
return ERC20TokenKeeper{
Caller: caller,
abi: GetFIP20().ABI,
// evm module address
from: common.BytesToAddress(authtypes.NewModuleAddress(types.ModuleName).Bytes()),
abi: GetWFX().ABI,
}
}

func (k ERC20TokenKeeper) Owner(ctx context.Context, contractAddr common.Address) (common.Address, error) {
var ownerRes struct{ Value common.Address }
if err := k.QueryContract(ctx, common.Address{}, contractAddr, k.abi, "owner", &ownerRes); err != nil {
return common.Address{}, err
}
return ownerRes.Value, nil
}

func (k ERC20TokenKeeper) Name(ctx context.Context, contractAddr common.Address) (string, error) {
var nameRes struct{ Value string }
if err := k.QueryContract(sdk.UnwrapSDKContext(ctx), k.from, contractAddr, k.abi, "name", &nameRes); err != nil {
if err := k.QueryContract(ctx, common.Address{}, contractAddr, k.abi, "name", &nameRes); err != nil {
return "", err
}
return nameRes.Value, nil
}

func (k ERC20TokenKeeper) Symbol(ctx context.Context, contractAddr common.Address) (string, error) {
var symbolRes struct{ Value string }
if err := k.QueryContract(sdk.UnwrapSDKContext(ctx), k.from, contractAddr, k.abi, "symbol", &symbolRes); err != nil {
if err := k.QueryContract(ctx, common.Address{}, contractAddr, k.abi, "symbol", &symbolRes); err != nil {
return "", err
}
return symbolRes.Value, nil
}

func (k ERC20TokenKeeper) Decimals(ctx context.Context, contractAddr common.Address) (uint8, error) {
var decimalRes struct{ Value uint8 }
if err := k.QueryContract(sdk.UnwrapSDKContext(ctx), k.from, contractAddr, k.abi, "decimals", &decimalRes); err != nil {
if err := k.QueryContract(ctx, common.Address{}, contractAddr, k.abi, "decimals", &decimalRes); err != nil {
return 0, err
}
return decimalRes.Value, nil
Expand All @@ -55,43 +58,88 @@ func (k ERC20TokenKeeper) BalanceOf(ctx context.Context, contractAddr, addr comm
var balanceRes struct {
Value *big.Int
}
if err := k.QueryContract(sdk.UnwrapSDKContext(ctx), k.from, contractAddr, k.abi, "balanceOf", &balanceRes, addr); err != nil {
if err := k.QueryContract(ctx, common.Address{}, contractAddr, k.abi, "balanceOf", &balanceRes, addr); err != nil {
return big.NewInt(0), err
}
return balanceRes.Value, nil
}

func (k ERC20TokenKeeper) TotalSupply(ctx context.Context, contractAddr common.Address) (*big.Int, error) {
var totalSupplyRes struct{ Value *big.Int }
if err := k.QueryContract(sdk.UnwrapSDKContext(ctx), k.from, contractAddr, k.abi, "totalSupply", &totalSupplyRes); err != nil {
if err := k.QueryContract(ctx, common.Address{}, contractAddr, k.abi, "totalSupply", &totalSupplyRes); err != nil {
return nil, err
}
return totalSupplyRes.Value, nil
}

func (k ERC20TokenKeeper) Mint(ctx context.Context, contractAddr, from, receiver common.Address, amount *big.Int) error {
_, err := k.ApplyContract(sdk.UnwrapSDKContext(ctx), from, contractAddr, nil, k.abi, "mint", receiver, amount)
return err
func (k ERC20TokenKeeper) Allowance(ctx context.Context, contractAddr, owner, spender common.Address) (*big.Int, error) {
var allowanceRes struct{ Value *big.Int }
if err := k.QueryContract(ctx, owner, contractAddr, k.abi, "allowance", &allowanceRes, owner, spender); err != nil {
return big.NewInt(0), err
}
return allowanceRes.Value, nil
}

func (k ERC20TokenKeeper) Burn(ctx context.Context, contractAddr, from, account common.Address, amount *big.Int) error {
_, err := k.ApplyContract(sdk.UnwrapSDKContext(ctx), from, contractAddr, nil, k.abi, "burn", account, amount)
return err
func (k ERC20TokenKeeper) unpackRet(method string, res *types.MsgEthereumTxResponse) (*types.MsgEthereumTxResponse, error) {
var result struct{ Value bool }
if err := k.abi.UnpackIntoInterface(&result, method, res.Ret); err != nil {
return res, sdkerrors.ErrInvalidType.Wrapf("failed to unpack transfer: %s", err.Error())
}
if !result.Value {
return res, sdkerrors.ErrLogic.Wrapf("failed to execute %s", method)
}
return res, nil
}

func (k ERC20TokenKeeper) Transfer(ctx context.Context, contractAddr, from, receiver common.Address, amount *big.Int) error {
res, err := k.ApplyContract(sdk.UnwrapSDKContext(ctx), from, contractAddr, nil, k.abi, "transfer", receiver, amount)
func (k ERC20TokenKeeper) Approve(ctx context.Context, contractAddr, from, spender common.Address, amount *big.Int) (*types.MsgEthereumTxResponse, error) {
res, err := k.ApplyContract(ctx, from, contractAddr, nil, k.abi, "approve", spender, amount)
if err != nil {
return err
return nil, err
}
return k.unpackRet("approve", res)
}

// PackMint only used for testing
func (k ERC20TokenKeeper) PackMint(receiver common.Address, amount *big.Int) ([]byte, error) {
return k.abi.Pack("mint", receiver, amount)
}

func (k ERC20TokenKeeper) Mint(ctx context.Context, contractAddr, from, receiver common.Address, amount *big.Int) (*types.MsgEthereumTxResponse, error) {
return k.ApplyContract(ctx, from, contractAddr, nil, k.abi, "mint", receiver, amount)
}

func (k ERC20TokenKeeper) Burn(ctx context.Context, contractAddr, from, account common.Address, amount *big.Int) (*types.MsgEthereumTxResponse, error) {
return k.ApplyContract(ctx, from, contractAddr, nil, k.abi, "burn", account, amount)
}

// Check unpackedRet execution
var unpackedRet struct{ Value bool }
if err = k.abi.UnpackIntoInterface(&unpackedRet, "transfer", res.Ret); err != nil {
return sdkerrors.ErrInvalidType.Wrapf("failed to unpack transfer: %s", err.Error())
func (k ERC20TokenKeeper) Transfer(ctx context.Context, contractAddr, from, receiver common.Address, amount *big.Int) (*types.MsgEthereumTxResponse, error) {
res, err := k.ApplyContract(ctx, from, contractAddr, nil, k.abi, "transfer", receiver, amount)
if err != nil {
return nil, err
}
if !unpackedRet.Value {
return sdkerrors.ErrLogic.Wrap("failed to execute transfer")
return k.unpackRet("transfer", res)
}

func (k ERC20TokenKeeper) TransferFrom(ctx context.Context, contractAddr, from, sender, receiver common.Address, amount *big.Int) (*types.MsgEthereumTxResponse, error) {
res, err := k.ApplyContract(ctx, from, contractAddr, nil, k.abi, "transferFrom", sender, receiver, amount)
if err != nil {
return nil, err
}
return nil
return k.unpackRet("transferFrom", res)
}

func (k ERC20TokenKeeper) TransferOwnership(ctx context.Context, contractAddr, owner, newOwner common.Address) (*types.MsgEthereumTxResponse, error) {
return k.ApplyContract(ctx, owner, contractAddr, nil, k.abi, "transferOwnership", newOwner)
}

func (k ERC20TokenKeeper) Withdraw(ctx context.Context, contractAddr, from, receiver common.Address, amount *big.Int) (*types.MsgEthereumTxResponse, error) {
return k.ApplyContract(ctx, from, contractAddr, nil, k.abi, "withdraw0", receiver, amount)
}

func (k ERC20TokenKeeper) WithdrawToSelf(ctx context.Context, contractAddr, from common.Address, amount *big.Int) (*types.MsgEthereumTxResponse, error) {
return k.ApplyContract(ctx, from, contractAddr, nil, k.abi, "withdraw", from, amount)
}

func (k ERC20TokenKeeper) Deposit(ctx context.Context, contractAddr, from common.Address, amount *big.Int) (*types.MsgEthereumTxResponse, error) {
return k.ApplyContract(ctx, from, contractAddr, amount, k.abi, "deposit")
}
25 changes: 15 additions & 10 deletions contract/precompile.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
Expand All @@ -27,7 +28,7 @@ func EmitEvent(evm *vm.EVM, address common.Address, data []byte, topics []common
}

type ERC20Call struct {
ERC20ABI
abi abi.ABI
evm *vm.EVM
caller vm.AccountRef
contract common.Address
Expand All @@ -40,7 +41,7 @@ func NewERC20Call(evm *vm.EVM, caller, contract common.Address, maxGas uint64) *
defMaxGas = maxGas
}
return &ERC20Call{
ERC20ABI: NewERC20ABI(),
abi: GetWFX().ABI,
evm: evm,
caller: vm.AccountRef(caller),
contract: contract,
Expand All @@ -65,7 +66,7 @@ func (e *ERC20Call) staticCall(data []byte) (ret []byte, err error) {
}

func (e *ERC20Call) Burn(account common.Address, amount *big.Int) error {
data, err := e.ERC20ABI.PackBurn(account, amount)
data, err := e.abi.Pack("burn", account, amount)
if err != nil {
return err
}
Expand All @@ -77,32 +78,36 @@ func (e *ERC20Call) Burn(account common.Address, amount *big.Int) error {
}

func (e *ERC20Call) TransferFrom(from, to common.Address, amount *big.Int) error {
data, err := e.ERC20ABI.PackTransferFrom(from, to, amount)
data, err := e.abi.Pack("transferFrom", from, to, amount)
if err != nil {
return err
}
ret, err := e.call(data)
if err != nil {
return fmt.Errorf("call transferFrom: %s", err.Error())
}
isSuccess, err := e.UnpackTransferFrom(ret)
if err != nil {
return err
var unpackedRet struct{ Value bool }
if err = e.abi.UnpackIntoInterface(&unpackedRet, "transferFrom", ret); err != nil {
return fmt.Errorf("unpack transferFrom: %s", err.Error())
}
if !isSuccess {
if !unpackedRet.Value {
return errors.New("transferFrom failed")
}
return nil
}

func (e *ERC20Call) TotalSupply() (*big.Int, error) {
data, err := e.ERC20ABI.PackTotalSupply()
data, err := e.abi.Pack("totalSupply")
if err != nil {
return nil, err
}
ret, err := e.staticCall(data)
if err != nil {
return nil, fmt.Errorf("StaticCall totalSupply: %s", err.Error())
}
return e.ERC20ABI.UnpackTotalSupply(ret)
var unpackedRet struct{ Value *big.Int }
if err = e.abi.UnpackIntoInterface(&unpackedRet, "totalSupply", ret); err != nil {
return nil, fmt.Errorf("unpack totalSupply: %s", err.Error())
}
return unpackedRet.Value, nil
}
2 changes: 1 addition & 1 deletion scripts/linter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ patternLimits=(
"cross chain:0"
"GetERC1967Proxy:4"
"GetWFX:9"
"GetFIP20:12"
"GetFIP20:10"
)

if ! command -v rg &>/dev/null; then
Expand Down
41 changes: 0 additions & 41 deletions testutil/helpers/bank.go

This file was deleted.

18 changes: 7 additions & 11 deletions testutil/helpers/suite.go → testutil/helpers/base_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package helpers

import (
"fmt"
"math/big"
"time"

sdkmath "cosmossdk.io/math"
Expand All @@ -24,11 +23,9 @@ import (
"github.com/cosmos/ibc-go/v8/modules/core/exported"
ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint"
localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/suite"

"github.com/functionx/fx-core/v8/app"
fxevmkeeper "github.com/functionx/fx-core/v8/contract"
crosschaintypes "github.com/functionx/fx-core/v8/x/crosschain/types"
)

Expand All @@ -39,7 +36,6 @@ type BaseSuite struct {
ValAddr []sdk.ValAddress
App *app.App
Ctx sdk.Context
ERC20Token fxevmkeeper.ERC20TokenKeeper
}

func (s *BaseSuite) SetupTest() {
Expand All @@ -57,7 +53,6 @@ func (s *BaseSuite) SetupTest() {
s.App = setupWithGenesisValSet(s.T(), valSet, valAccounts, valBalances...)
s.Ctx = s.App.GetContextForFinalizeBlock(nil)
s.Ctx = s.Ctx.WithProposer(s.ValSet.Proposer.Address.Bytes())
s.ERC20Token = fxevmkeeper.NewERC20TokenKeeper(s.App.EvmKeeper)
}

func (s *BaseSuite) AddTestSigner(amount ...int64) *Signer {
Expand All @@ -70,6 +65,13 @@ func (s *BaseSuite) AddTestSigner(amount ...int64) *Signer {
return signer
}

func (s *BaseSuite) NewSigner() *Signer {
signer := NewSigner(NewEthPrivKey())
account := s.App.AccountKeeper.NewAccountWithAddress(s.Ctx, signer.AccAddress())
s.App.AccountKeeper.SetAccount(s.Ctx, account)
return signer
}

func (s *BaseSuite) Commit(block ...int64) sdk.Context {
ctx := s.Ctx
lastBlockHeight := s.Ctx.BlockHeight()
Expand Down Expand Up @@ -182,12 +184,6 @@ func (s *BaseSuite) CheckAllBalance(addr sdk.AccAddress, expBal ...sdk.Coin) {
s.Equal(sdk.NewCoins(expBal...).String(), balances.String())
}

func (s *BaseSuite) CheckBalanceOf(contractAddr, address common.Address, expBal *big.Int) {
balanceOf, err := s.ERC20Token.BalanceOf(s.Ctx, contractAddr, address)
s.Require().NoError(err)
s.Equal(expBal.String(), balanceOf.String())
}

func (s *BaseSuite) NewCoin(amounts ...sdkmath.Int) sdk.Coin {
amount := NewRandAmount()
if len(amounts) > 0 && amounts[0].IsPositive() {
Expand Down
File renamed without changes.
Loading

0 comments on commit d2e8338

Please sign in to comment.