Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: refactor the ERC20 token test suite #789

Merged
merged 2 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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{}
}
zakir-code marked this conversation as resolved.
Show resolved Hide resolved

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