diff --git a/contract/erc20_abi.go b/contract/erc20_abi.go index 1eed0e48d..8acad6f49 100644 --- a/contract/erc20_abi.go +++ b/contract/erc20_abi.go @@ -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) { diff --git a/contract/erc20_token.go b/contract/erc20_token.go index 956127208..03986594d 100644 --- a/contract/erc20_token.go +++ b/contract/erc20_token.go @@ -4,9 +4,7 @@ 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" @@ -14,22 +12,27 @@ import ( 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 @@ -37,7 +40,7 @@ func (k ERC20TokenKeeper) Name(ctx context.Context, contractAddr common.Address) 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 @@ -45,7 +48,7 @@ func (k ERC20TokenKeeper) Symbol(ctx context.Context, contractAddr common.Addres 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 @@ -55,7 +58,7 @@ 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 @@ -63,35 +66,80 @@ func (k ERC20TokenKeeper) BalanceOf(ctx context.Context, contractAddr, addr comm 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") } diff --git a/contract/precompile.go b/contract/precompile.go index c146e8330..49174982f 100644 --- a/contract/precompile.go +++ b/contract/precompile.go @@ -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" @@ -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 @@ -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, @@ -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 } @@ -77,7 +78,7 @@ 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 } @@ -85,18 +86,18 @@ func (e *ERC20Call) TransferFrom(from, to common.Address, amount *big.Int) error 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 } @@ -104,5 +105,9 @@ func (e *ERC20Call) TotalSupply() (*big.Int, error) { 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 } diff --git a/scripts/linter.sh b/scripts/linter.sh index a294f7f6a..d478f2182 100755 --- a/scripts/linter.sh +++ b/scripts/linter.sh @@ -9,7 +9,7 @@ patternLimits=( "cross chain:0" "GetERC1967Proxy:4" "GetWFX:9" - "GetFIP20:12" + "GetFIP20:10" ) if ! command -v rg &>/dev/null; then diff --git a/testutil/helpers/bank.go b/testutil/helpers/bank.go deleted file mode 100644 index c4b0aaff2..000000000 --- a/testutil/helpers/bank.go +++ /dev/null @@ -1,41 +0,0 @@ -package helpers - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - "github.com/stretchr/testify/require" -) - -type BankSuite struct { - *require.Assertions - ctx sdk.Context - bankKeeper bankkeeper.Keeper -} - -func (s *BankSuite) Init(ass *require.Assertions, ctx sdk.Context, bankKeeper bankkeeper.Keeper) *BankSuite { - s.Assertions = ass - s.ctx = ctx - s.bankKeeper = bankKeeper - return s -} - -func (s *BankSuite) GetTotalSupply() sdk.Coins { - totalSupply, response, err := s.bankKeeper.GetPaginatedTotalSupply(s.ctx, &query.PageRequest{}) - s.NoError(err) - s.NotNil(response) - return totalSupply -} - -func (s *BankSuite) GetSupply(denom string) sdk.Coin { - return s.bankKeeper.GetSupply(s.ctx, denom) -} - -func (s *BankSuite) GetAllBalances(addr sdk.AccAddress) sdk.Coins { - return s.bankKeeper.GetAllBalances(s.ctx, addr) -} - -func (s *BankSuite) SendCoins(fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) { - err := s.bankKeeper.SendCoins(s.ctx, fromAddr, toAddr, amt) - s.NoError(err) -} diff --git a/testutil/helpers/suite.go b/testutil/helpers/base_suite.go similarity index 94% rename from testutil/helpers/suite.go rename to testutil/helpers/base_suite.go index 866d512da..ec85b1dd7 100644 --- a/testutil/helpers/suite.go +++ b/testutil/helpers/base_suite.go @@ -2,7 +2,6 @@ package helpers import ( "fmt" - "math/big" "time" sdkmath "cosmossdk.io/math" @@ -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" ) @@ -39,7 +36,6 @@ type BaseSuite struct { ValAddr []sdk.ValAddress App *app.App Ctx sdk.Context - ERC20Token fxevmkeeper.ERC20TokenKeeper } func (s *BaseSuite) SetupTest() { @@ -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 { @@ -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() @@ -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() { diff --git a/testutil/helpers/suite_test.go b/testutil/helpers/base_suite_test.go similarity index 100% rename from testutil/helpers/suite_test.go rename to testutil/helpers/base_suite_test.go diff --git a/testutil/helpers/contract_base_suite.go b/testutil/helpers/contract_base_suite.go new file mode 100644 index 000000000..95c45ad82 --- /dev/null +++ b/testutil/helpers/contract_base_suite.go @@ -0,0 +1,37 @@ +package helpers + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +type ContractBaseSuite struct { + require *require.Assertions + signer *Signer + contract common.Address +} + +func NewContractBaseSuite(require *require.Assertions, signer *Signer) *ContractBaseSuite { + return &ContractBaseSuite{ + require: require, + signer: signer, + contract: common.Address{}, + } +} + +func (s *ContractBaseSuite) WithContract(addr common.Address) { + s.contract = addr +} + +func (s *ContractBaseSuite) WithSigner(signer *Signer) { + s.signer = signer +} + +func (s *ContractBaseSuite) HexAddress() common.Address { + return s.signer.Address() +} + +func (s *ContractBaseSuite) AccAddress() sdk.AccAddress { + return s.signer.AccAddress() +} diff --git a/testutil/helpers/erc20_token_suite.go b/testutil/helpers/erc20_token_suite.go new file mode 100644 index 000000000..085ebb15f --- /dev/null +++ b/testutil/helpers/erc20_token_suite.go @@ -0,0 +1,171 @@ +package helpers + +import ( + "context" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" + evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/stretchr/testify/require" + + "github.com/functionx/fx-core/v8/contract" + erc20types "github.com/functionx/fx-core/v8/x/erc20/types" + fxevmkeeper "github.com/functionx/fx-core/v8/x/evm/keeper" +) + +type ERC20TokenSuite struct { + *ContractBaseSuite + err error + ERC20TokenKeeper contract.ERC20TokenKeeper + evmKeeper *fxevmkeeper.Keeper +} + +func NewERC20Suite(require *require.Assertions, signer *Signer, evmKeeper *fxevmkeeper.Keeper) ERC20TokenSuite { + return ERC20TokenSuite{ + ContractBaseSuite: NewContractBaseSuite(require, signer), + ERC20TokenKeeper: contract.NewERC20TokenKeeper(evmKeeper), + evmKeeper: evmKeeper, + } +} + +func (s ERC20TokenSuite) WithError(err error) ERC20TokenSuite { + newErc20Suite := s + newErc20Suite.err = err + return newErc20Suite +} + +func (s ERC20TokenSuite) Error(err error) { + if s.err != nil { + s.require.ErrorIs(err, evmtypes.ErrVMExecution.Wrap(s.err.Error())) + return + } + s.require.NoError(err) +} + +func (s ERC20TokenSuite) DeployERC20Token(ctx sdk.Context, symbol string) common.Address { + erc20Contract := contract.GetFIP20() + erc20ModuleAddress := common.BytesToAddress(authtypes.NewModuleAddress(erc20types.ModuleName).Bytes()) + initializeArgs := []interface{}{symbol + " Token", symbol, uint8(18), erc20ModuleAddress} + newContractAddr, err := s.evmKeeper.DeployUpgradableContract(ctx, + s.signer.Address(), erc20Contract.Address, nil, &erc20Contract.ABI, initializeArgs...) + s.require.NoError(err) + s.WithContract(newContractAddr) + return newContractAddr +} + +func (s ERC20TokenSuite) Owner(ctx context.Context) common.Address { + owner, err := s.ERC20TokenKeeper.Owner(ctx, s.contract) + s.Error(err) + return owner +} + +func (s ERC20TokenSuite) Name(ctx context.Context) string { + name, err := s.ERC20TokenKeeper.Name(ctx, s.contract) + s.Error(err) + return name +} + +func (s ERC20TokenSuite) Symbol(ctx context.Context) string { + symbol, err := s.ERC20TokenKeeper.Symbol(ctx, s.contract) + s.Error(err) + return symbol +} + +func (s ERC20TokenSuite) Decimals(ctx context.Context) uint8 { + decimals, err := s.ERC20TokenKeeper.Decimals(ctx, s.contract) + s.Error(err) + return decimals +} + +func (s ERC20TokenSuite) TotalSupply(ctx context.Context) *big.Int { + totalSupply, err := s.ERC20TokenKeeper.TotalSupply(ctx, s.contract) + s.Error(err) + return totalSupply +} + +func (s ERC20TokenSuite) BalanceOf(ctx context.Context, address common.Address) *big.Int { + balance, err := s.ERC20TokenKeeper.BalanceOf(ctx, s.contract, address) + s.Error(err) + return balance +} + +func (s ERC20TokenSuite) Allowance(ctx context.Context, owner, spender common.Address) *big.Int { + allowance, err := s.ERC20TokenKeeper.Allowance(ctx, s.contract, owner, spender) + s.Error(err) + return allowance +} + +func (s ERC20TokenSuite) Approve(ctx context.Context, spender common.Address, amount *big.Int) *evmtypes.MsgEthereumTxResponse { + res, err := s.ERC20TokenKeeper.Approve(ctx, s.contract, s.HexAddress(), spender, amount) + s.Error(err) + return res +} + +func (s ERC20TokenSuite) Transfer(ctx context.Context, recipient common.Address, amount *big.Int) *evmtypes.MsgEthereumTxResponse { + res, err := s.ERC20TokenKeeper.Transfer(ctx, s.contract, s.HexAddress(), recipient, amount) + s.Error(err) + return res +} + +func (s ERC20TokenSuite) TransferFrom(ctx context.Context, sender, recipient common.Address, amount *big.Int) *evmtypes.MsgEthereumTxResponse { + res, err := s.ERC20TokenKeeper.TransferFrom(ctx, s.contract, s.HexAddress(), sender, recipient, amount) + s.Error(err) + return res +} + +func (s ERC20TokenSuite) Mint(ctx context.Context, to common.Address, amount *big.Int) *evmtypes.MsgEthereumTxResponse { + res, err := s.ERC20TokenKeeper.Mint(ctx, s.contract, s.HexAddress(), to, amount) + s.Error(err) + return res +} + +func (s ERC20TokenSuite) Burn(ctx context.Context, from common.Address, amount *big.Int) *evmtypes.MsgEthereumTxResponse { + res, err := s.ERC20TokenKeeper.Burn(ctx, s.contract, s.HexAddress(), from, amount) + s.Error(err) + return res +} + +func (s ERC20TokenSuite) TransferOwnership(ctx context.Context, newOwner common.Address) *evmtypes.MsgEthereumTxResponse { + res, err := s.ERC20TokenKeeper.TransferOwnership(ctx, s.contract, s.HexAddress(), newOwner) + s.Error(err) + return res +} + +func (s ERC20TokenSuite) WithdrawSelf(ctx context.Context, amount *big.Int) *evmtypes.MsgEthereumTxResponse { + res, err := s.ERC20TokenKeeper.Withdraw(ctx, s.contract, s.HexAddress(), s.HexAddress(), amount) + s.Error(err) + return res +} + +func (s ERC20TokenSuite) Withdraw(ctx context.Context, to common.Address, amount *big.Int) *evmtypes.MsgEthereumTxResponse { + res, err := s.ERC20TokenKeeper.Withdraw(ctx, s.contract, s.HexAddress(), to, amount) + s.Error(err) + return res +} + +func (s ERC20TokenSuite) Deposit(ctx context.Context, value *big.Int) *evmtypes.MsgEthereumTxResponse { + res, err := s.ERC20TokenKeeper.Deposit(ctx, s.contract, s.HexAddress(), value) + s.Error(err) + return res +} + +func (s ERC20TokenSuite) OnTest(ctx context.Context, name, symbol string, decimals uint8, totalSupply *big.Int, owner common.Address) { + s.require.Equal(name, s.Name(ctx)) + s.require.Equal(symbol, s.Symbol(ctx)) + s.require.Equal(decimals, s.Decimals(ctx)) + s.require.Equal(totalSupply.String(), s.TotalSupply(ctx).String()) + s.require.Equal(owner.String(), s.Owner(ctx).String()) + + s.require.Equal("0", s.Allowance(ctx, s.HexAddress(), s.HexAddress()).String()) + s.Approve(ctx, s.HexAddress(), big.NewInt(100)) + s.require.Equal("100", s.Allowance(ctx, s.HexAddress(), s.HexAddress()).String()) + + newSigner := NewSigner(NewEthPrivKey()) + + s.Mint(ctx, s.signer.Address(), big.NewInt(200)) + s.Transfer(ctx, newSigner.Address(), big.NewInt(100)) + s.TransferFrom(ctx, s.signer.Address(), newSigner.Address(), big.NewInt(100)) + s.Burn(ctx, newSigner.Address(), big.NewInt(200)) +} diff --git a/x/crosschain/keeper/bridge_call_in_test.go b/x/crosschain/keeper/bridge_call_in_test.go index 5ff7ff948..8fa31cfe8 100644 --- a/x/crosschain/keeper/bridge_call_in_test.go +++ b/x/crosschain/keeper/bridge_call_in_test.go @@ -4,6 +4,7 @@ import ( sdkmath "cosmossdk.io/math" "github.com/ethereum/go-ethereum/common" + "github.com/functionx/fx-core/v8/contract" "github.com/functionx/fx-core/v8/testutil/helpers" "github.com/functionx/fx-core/v8/x/crosschain/types" ) @@ -54,7 +55,10 @@ func (suite *KeeperTestSuite) TestBridgeCallHandler() { suite.Require().NoError(err) if !tc.CallContract { for i, addr := range erc20Addrs { - suite.CheckBalanceOf(addr, tc.Msg.GetToAddr(), tc.Msg.Amounts[i].BigInt()) + erc20Token := contract.NewERC20TokenKeeper(suite.App.EvmKeeper) + balanceOf, err := erc20Token.BalanceOf(suite.Ctx, addr, tc.Msg.GetToAddr()) + suite.Require().NoError(err) + suite.Equal(tc.Msg.Amounts[i].BigInt().String(), balanceOf.String()) } } } else { diff --git a/x/erc20/keeper/convert.go b/x/erc20/keeper/convert.go index 3119c859b..6cc99b22c 100644 --- a/x/erc20/keeper/convert.go +++ b/x/erc20/keeper/convert.go @@ -70,7 +70,7 @@ func (k Keeper) ConvertCoinNativeCoin(ctx context.Context, erc20Token types.ERC2 } erc20Contract := erc20Token.GetERC20Contract() - if err := k.evmErc20Keeper.Mint(ctx, erc20Contract, k.contractOwner, receiver, coin.Amount.BigInt()); err != nil { + if _, err := k.evmErc20Keeper.Mint(ctx, erc20Contract, k.contractOwner, receiver, coin.Amount.BigInt()); err != nil { return err } @@ -90,7 +90,7 @@ func (k Keeper) ConvertCoinNativeERC20(ctx context.Context, erc20Token types.ERC return err } - if err := k.evmErc20Keeper.Transfer(ctx, erc20Token.GetERC20Contract(), k.contractOwner, receiver, coin.Amount.BigInt()); err != nil { + if _, err := k.evmErc20Keeper.Transfer(ctx, erc20Token.GetERC20Contract(), k.contractOwner, receiver, coin.Amount.BigInt()); err != nil { return err } diff --git a/x/erc20/types/expected_keepers.go b/x/erc20/types/expected_keepers.go index 873f89617..93a195f53 100644 --- a/x/erc20/types/expected_keepers.go +++ b/x/erc20/types/expected_keepers.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/evmos/ethermint/x/evm/statedb" + evmtypes "github.com/evmos/ethermint/x/evm/types" ) // AccountKeeper defines the expected interface needed to retrieve account info. @@ -36,9 +37,8 @@ type ERC20TokenKeeper interface { Symbol(ctx context.Context, contractAddr common.Address) (string, error) Decimals(ctx context.Context, contractAddr common.Address) (uint8, error) - Mint(ctx context.Context, contractAddr, from, receiver common.Address, amount *big.Int) error - Burn(ctx context.Context, contractAddr, from, account common.Address, amount *big.Int) error - Transfer(ctx context.Context, contractAddr, from, receiver common.Address, amount *big.Int) error + Mint(ctx context.Context, contractAddr, from, receiver common.Address, amount *big.Int) (*evmtypes.MsgEthereumTxResponse, error) + Transfer(ctx context.Context, contractAddr, from, receiver common.Address, amount *big.Int) (*evmtypes.MsgEthereumTxResponse, error) } // EVMKeeper defines the expected EVM keeper interface used on erc20 diff --git a/x/evm/keeper/contract_code_test.go b/x/evm/keeper/contract_code_test.go index 806a0953b..070d774df 100644 --- a/x/evm/keeper/contract_code_test.go +++ b/x/evm/keeper/contract_code_test.go @@ -40,19 +40,19 @@ func (s *KeeperTestSuite) AssertCode(address common.Address, code []byte) { func (s *KeeperTestSuite) TestKeeper_DeployContract() { erc1967Proxy := contract.GetERC1967Proxy() erc20 := contract.GetFIP20() - singer := s.EVMSuite.HexAddr() - newContractAddr, err := s.App.EvmKeeper.DeployContract(s.Ctx, singer, + sender := s.AddTestSigner().Address() + newContractAddr, err := s.App.EvmKeeper.DeployContract(s.Ctx, sender, erc1967Proxy.ABI, erc1967Proxy.Bin, erc20.Address, []byte{}) s.Require().NoError(err) - s.AssertContractAddr(singer, newContractAddr) + s.AssertContractAddr(sender, newContractAddr) } func (s *KeeperTestSuite) TestKeeper_DeployUpgradableContract() { - singer := s.EVMSuite.HexAddr() - newContractAddr := s.EVMSuite.DeployUpgradableERC20Logic("USD") + erc20Suite := s.NewERC20TokenSuite() + newContractAddr := erc20Suite.DeployERC20Token(s.Ctx, "USD") - s.AssertContractAddr(singer, newContractAddr) + s.AssertContractAddr(erc20Suite.HexAddress(), newContractAddr) } func (s *KeeperTestSuite) TestKeeper_UpdateContractCode_FIP20() { @@ -61,25 +61,26 @@ func (s *KeeperTestSuite) TestKeeper_UpdateContractCode_FIP20() { err := s.App.EvmKeeper.CreateContractWithCode(s.Ctx, fip20.Address, v3TestFIP20Code) s.Require().NoError(err) - s.EVMSuite.DeployUpgradableERC20Logic("USD") - erc20Suite := s.NewERC20Suite() + erc20Suite := s.NewERC20TokenSuite() + erc20Suite.DeployERC20Token(s.Ctx, "USD") - erc20Suite.OnTest("USD Token", "USD", uint8(18), big.NewInt(0), erc20Suite.HexAddr()) + erc20Suite.OnTest(s.Ctx, "USD Token", "USD", uint8(18), big.NewInt(0), erc20Suite.HexAddress()) newSigner := helpers.NewSigner(helpers.NewEthPrivKey()) - erc20Suite.Mint(erc20Suite.HexAddr(), big.NewInt(100), true) - erc20Suite.Transfer(newSigner.Address(), big.NewInt(100), true) + erc20Suite.Mint(s.Ctx, erc20Suite.HexAddress(), big.NewInt(100)) + erc20Suite.Transfer(s.Ctx, newSigner.Address(), big.NewInt(100)) err = s.App.EvmKeeper.UpdateContractCode(s.Ctx, fip20.Address, fip20.Code) s.Require().NoError(err) - erc20Suite.OnTest("USD Token", "USD", uint8(18), big.NewInt(100), erc20Suite.HexAddr()) - erc20Suite.TransferOwnership(newSigner.Address(), true) + erc20Suite.OnTest(s.Ctx, "USD Token", "USD", uint8(18), big.NewInt(100), erc20Suite.HexAddress()) + erc20Suite.TransferOwnership(s.Ctx, newSigner.Address()) } func (s *KeeperTestSuite) TestCodeCheck() { for _, c := range []contract.Contract{contract.GetFIP20(), contract.GetWFX()} { - addr, err := s.App.EvmKeeper.DeployContract(s.Ctx, s.HexAddr(), c.ABI, c.Bin) + contractOwner := s.AddTestSigner() + addr, err := s.App.EvmKeeper.DeployContract(s.Ctx, contractOwner.Address(), c.ABI, c.Bin) s.NoError(err) account := s.App.EvmKeeper.GetAccount(s.Ctx, addr) @@ -99,39 +100,39 @@ func (s *KeeperTestSuite) TestKeeper_UpdateContractCode_WFX() { err := s.App.EvmKeeper.CreateContractWithCode(s.Ctx, wfx.Address, v3TestWFXCode) s.Require().NoError(err) - erc20Suite := s.NewERC20Suite() + erc20Suite := s.NewERC20TokenSuite() initializeArgs := []interface{}{"Wrapped Function X", "WFX", uint8(18), common.BytesToAddress(s.App.AccountKeeper.GetModuleAddress(evmtypes.ModuleName))} - wfxAddress, err := s.App.EvmKeeper.DeployUpgradableContract(s.Ctx, erc20Suite.HexAddr(), wfx.Address, nil, &wfx.ABI, initializeArgs...) + wfxAddress, err := s.App.EvmKeeper.DeployUpgradableContract(s.Ctx, erc20Suite.HexAddress(), wfx.Address, nil, &wfx.ABI, initializeArgs...) s.Require().NoError(err) - erc20Suite.WithContractAddr(wfxAddress) + erc20Suite.WithContract(wfxAddress) - erc20Suite.OnTest("Wrapped Function X", "WFX", uint8(18), big.NewInt(0), erc20Suite.HexAddr()) + erc20Suite.OnTest(s.Ctx, "Wrapped Function X", "WFX", uint8(18), big.NewInt(0), erc20Suite.HexAddress()) - erc20Suite.Deposit(big.NewInt(100), true) + erc20Suite.Deposit(s.Ctx, big.NewInt(100)) err = s.App.EvmKeeper.UpdateContractCode(s.Ctx, wfx.Address, v4TestWFXCode) s.Require().NoError(err) - s.Require().True(erc20Suite.BalanceOf(erc20Suite.HexAddr()).Cmp(big.NewInt(100)) == 0) + s.Require().True(erc20Suite.BalanceOf(s.Ctx, erc20Suite.HexAddress()).Cmp(big.NewInt(100)) == 0) newSigner := helpers.NewSigner(helpers.NewEthPrivKey()) s.MintToken(newSigner.AccAddress(), helpers.NewStakingCoin(100, 18)) - erc20Suite.Transfer(newSigner.Address(), big.NewInt(100), true) + erc20Suite.Transfer(s.Ctx, newSigner.Address(), big.NewInt(100)) - erc20Suite.Approve(newSigner.Address(), big.NewInt(100), true) + erc20Suite.Approve(s.Ctx, newSigner.Address(), big.NewInt(100)) - erc20Suite.Deposit(big.NewInt(100), true) - erc20Suite.Transfer(newSigner.Address(), big.NewInt(100), true) - erc20Suite.OnTest("Wrapped Function X", "WFX", uint8(18), big.NewInt(200), erc20Suite.HexAddr()) - s.Require().True(erc20Suite.BalanceOf(newSigner.Address()).Cmp(big.NewInt(200)) == 0) + erc20Suite.Deposit(s.Ctx, big.NewInt(100)) + erc20Suite.Transfer(s.Ctx, newSigner.Address(), big.NewInt(100)) + erc20Suite.OnTest(s.Ctx, "Wrapped Function X", "WFX", uint8(18), big.NewInt(200), erc20Suite.HexAddress()) + s.Require().True(erc20Suite.BalanceOf(s.Ctx, newSigner.Address()).Cmp(big.NewInt(200)) == 0) err = s.App.EvmKeeper.UpdateContractCode(s.Ctx, wfx.Address, wfx.Code) s.Require().NoError(err) - erc20Suite.Burn(newSigner.Address(), big.NewInt(100), true) - erc20Suite.Deposit(big.NewInt(100), true) - erc20Suite.WithdrawSelf(big.NewInt(50), true) - erc20Suite.Withdraw(newSigner.Address(), big.NewInt(50), true) + erc20Suite.Burn(s.Ctx, newSigner.Address(), big.NewInt(100)) + erc20Suite.Deposit(s.Ctx, big.NewInt(100)) + erc20Suite.WithdrawSelf(s.Ctx, big.NewInt(50)) + erc20Suite.Withdraw(s.Ctx, newSigner.Address(), big.NewInt(50)) - erc20Suite.OnTest("Wrapped Function X", "WFX", uint8(18), big.NewInt(100), erc20Suite.HexAddr()) + erc20Suite.OnTest(s.Ctx, "Wrapped Function X", "WFX", uint8(18), big.NewInt(100), erc20Suite.HexAddress()) } diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index 5b4d4ca35..e5c0c974a 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - "math/big" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -13,26 +12,18 @@ import ( "github.com/functionx/fx-core/v8/testutil/helpers" fxtypes "github.com/functionx/fx-core/v8/types" - "github.com/functionx/fx-core/v8/x/evm/testutil" ) type KeeperTestSuite struct { helpers.BaseSuite - testutil.EVMSuite } func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } -func (s *KeeperTestSuite) SetupTest() { - s.BaseSuite.SetupTest() - s.EVMSuite.Init(s.Require(), s.Ctx, s.App.EvmKeeper, s.BaseSuite.AddTestSigner()) - s.EVMSuite.WithGasPrice(big.NewInt(500 * 1e9)) -} - -func (s *KeeperTestSuite) NewERC20Suite() testutil.ERC20Suite { - return testutil.NewERC20Suite(s.EVMSuite) +func (s *KeeperTestSuite) NewERC20TokenSuite() helpers.ERC20TokenSuite { + return helpers.NewERC20Suite(s.Require(), s.AddTestSigner(), s.App.EvmKeeper) } func (s *KeeperTestSuite) MintFeeCollector(coins sdk.Coins) { @@ -55,10 +46,10 @@ func (s *KeeperTestSuite) BurnEvmRefundFee(addr sdk.AccAddress, coins sdk.Coins) s.Require().NoError(err) } -func (s *KeeperTestSuite) AssertContractAddr(singer, newContractAddr common.Address) { - nonce, err := s.App.AccountKeeper.GetSequence(s.Ctx, singer.Bytes()) - s.NoError(err) +func (s *KeeperTestSuite) AssertContractAddr(sender, newContractAddr common.Address) { + nonce, err := s.App.AccountKeeper.GetSequence(s.Ctx, sender.Bytes()) + s.Require().NoError(err) - contractAddr := crypto.CreateAddress(singer, nonce-1) + contractAddr := crypto.CreateAddress(sender, nonce-1) s.Equal(contractAddr, newContractAddr) } diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index 884e9f7d3..3784af15c 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -6,18 +6,49 @@ import ( sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/evmos/ethermint/x/evm/types" "github.com/functionx/fx-core/v8/testutil/helpers" fxtypes "github.com/functionx/fx-core/v8/types" + fxevmtypes "github.com/functionx/fx-core/v8/x/evm/types" ) +func (s *KeeperTestSuite) ethereumTx(signer *helpers.Signer, to *common.Address, data []byte, value *big.Int, gasLimit uint64) (*types.MsgEthereumTxResponse, error) { + chanId := s.App.EvmKeeper.ChainID() + s.Equal(fxtypes.EIP155ChainID(s.Ctx.ChainID()), chanId) + if value == nil { + value = big.NewInt(0) + } + + nonce := s.App.EvmKeeper.GetNonce(s.Ctx, signer.Address()) + tx := types.NewTx( + chanId, + nonce, + to, + value, + gasLimit, + big.NewInt(500*1e9), + nil, + nil, + data, + nil, + ) + tx.From = signer.Address().Bytes() + s.NoError(tx.Sign(ethtypes.LatestSignerForChainID(chanId), signer)) + + return s.App.EvmKeeper.EthereumTx(s.Ctx, tx) +} + func (s *KeeperTestSuite) TestKeeper_EthereumTx_Data() { - erc20Suite := s.NewERC20Suite() - contractAddr := erc20Suite.Deploy("TEST") + signer := s.NewSigner() + erc20Suite := s.NewERC20TokenSuite() + erc20Suite.WithSigner(signer) - erc20Suite.Mint(erc20Suite.HexAddr(), big.NewInt(100), true) + contractAddr := erc20Suite.DeployERC20Token(s.Ctx, "TEST") + erc20Suite.Mint(s.Ctx, erc20Suite.HexAddress(), big.NewInt(100)) gasLimit := uint64(71000) @@ -29,10 +60,10 @@ func (s *KeeperTestSuite) TestKeeper_EthereumTx_Data() { recipient := helpers.GenHexAddress() amount := big.NewInt(10) - data, err := erc20Suite.PackTransfer(recipient, amount) + data, err := erc20Suite.ERC20TokenKeeper.PackMint(recipient, amount) s.Require().NoError(err) - res, err := s.EVMSuite.EthereumTx(&contractAddr, data, nil, gasLimit) + res, err := s.ethereumTx(signer, &contractAddr, data, nil, gasLimit) s.Require().NoError(err) s.Require().False(res.Failed(), res) @@ -40,12 +71,12 @@ func (s *KeeperTestSuite) TestKeeper_EthereumTx_Data() { s.Commit() refundAmount := gasPrice * int64(gasLimit-res.GasUsed) - s.BurnEvmRefundFee(erc20Suite.AccAddr(), helpers.NewStakingCoins(refundAmount, 0)) + s.BurnEvmRefundFee(erc20Suite.AccAddress(), helpers.NewStakingCoins(refundAmount, 0)) totalSupplyAfter := s.App.BankKeeper.GetSupply(s.Ctx, fxtypes.DefaultDenom) s.Require().Equal(totalSupplyBefore.String(), totalSupplyAfter.String()) - s.Require().Equal(amount, erc20Suite.BalanceOf(recipient)) + s.Require().Equal(amount, erc20Suite.BalanceOf(s.Ctx, recipient)) } func (s *KeeperTestSuite) TestKeeper_EthereumTx_Value() { @@ -54,12 +85,13 @@ func (s *KeeperTestSuite) TestKeeper_EthereumTx_Value() { gasLimit := uint64(71000) + signer := s.AddTestSigner() totalSupplyBefore := s.App.BankKeeper.GetSupply(s.Ctx, fxtypes.DefaultDenom) // Mint the max gas to the FeeCollector to ensure balance in case of refund mintAmount := sdkmath.NewInt(s.App.FeeMarketKeeper.GetBaseFee(s.Ctx).Int64() * int64(gasLimit)) s.MintFeeCollector(sdk.NewCoins(sdk.NewCoin(fxtypes.DefaultDenom, mintAmount))) - res, err := s.EVMSuite.EthereumTx(&recipient, nil, amount, gasLimit) + res, err := s.ethereumTx(signer, &recipient, nil, amount, gasLimit) s.Require().NoError(err) s.Require().False(res.Failed(), res) @@ -67,7 +99,7 @@ func (s *KeeperTestSuite) TestKeeper_EthereumTx_Value() { s.Commit() refundAmount := sdkmath.NewInt(s.App.FeeMarketKeeper.GetBaseFee(s.Ctx).Int64() * int64(gasLimit-res.GasUsed)) - s.BurnEvmRefundFee(s.EVMSuite.AccAddr(), sdk.NewCoins(sdk.NewCoin(fxtypes.DefaultDenom, refundAmount))) + s.BurnEvmRefundFee(signer.AccAddress(), sdk.NewCoins(sdk.NewCoin(fxtypes.DefaultDenom, refundAmount))) totalSupplyAfter := s.App.BankKeeper.GetSupply(s.Ctx, fxtypes.DefaultDenom) s.Require().Equal(totalSupplyBefore.String(), totalSupplyAfter.String()) @@ -80,29 +112,33 @@ func (s *KeeperTestSuite) TestKeeper_EthereumTx_Value() { } func (s *KeeperTestSuite) TestKeeper_CallContract() { - s.EVMSuite.DeployUpgradableERC20Logic("USD") - - erc20Suite := s.NewERC20Suite() + erc20Suite := s.NewERC20TokenSuite() + contract := erc20Suite.DeployERC20Token(s.Ctx, "USD") amount := big.NewInt(100) - recipient := erc20Suite.HexAddr() - data, err := erc20Suite.PackMint(recipient, amount) + recipient := erc20Suite.HexAddress() + data, err := erc20Suite.ERC20TokenKeeper.PackMint(recipient, amount) s.Require().NoError(err) - account := s.App.AccountKeeper.GetAccount(s.Ctx, authtypes.NewModuleAddress(types.ModuleName)) - s.Require().NotNil(account) - // failed: not authorized - err = s.EVMSuite.CallContract(data) + _, err = s.App.EvmKeeper.CallContract(s.Ctx, &fxevmtypes.MsgCallContract{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ContractAddress: contract.String(), + Data: common.Bytes2Hex(data), + }) s.Require().EqualError(err, "Ownable: caller is not the owner: evm transaction execution failed") // transfer erc20 token owner to evm module evmModuleAddr := common.BytesToAddress(authtypes.NewModuleAddress(types.ModuleName)) - erc20Suite.TransferOwnership(evmModuleAddr, true) + erc20Suite.TransferOwnership(s.Ctx, evmModuleAddr) // success - err = s.EVMSuite.CallContract(data) + _, err = s.App.EvmKeeper.CallContract(s.Ctx, &fxevmtypes.MsgCallContract{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ContractAddress: contract.String(), + Data: common.Bytes2Hex(data), + }) s.Require().NoError(err) - s.Equal(amount, erc20Suite.BalanceOf(recipient)) + s.Equal(amount, erc20Suite.BalanceOf(s.Ctx, recipient)) } diff --git a/x/evm/testutil/erc20.go b/x/evm/testutil/erc20.go deleted file mode 100644 index e7437749f..000000000 --- a/x/evm/testutil/erc20.go +++ /dev/null @@ -1,252 +0,0 @@ -package testutil - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/crypto" - evmtypes "github.com/evmos/ethermint/x/evm/types" - - "github.com/functionx/fx-core/v8/contract" - "github.com/functionx/fx-core/v8/testutil/helpers" -) - -type ERC20Suite struct { - contract.ERC20ABI - EVMSuite - abi abi.ABI -} - -func NewERC20Suite(evmSuite EVMSuite) ERC20Suite { - return ERC20Suite{ - ERC20ABI: contract.NewERC20ABI(), - EVMSuite: evmSuite, - abi: contract.GetWFX().ABI, - } -} - -func (s *ERC20Suite) Call(method string, res interface{}, args ...interface{}) { - s.EVMSuite.Call(s.abi, method, res, args...) -} - -func (s *ERC20Suite) Send(method string, args ...interface{}) *evmtypes.MsgEthereumTxResponse { - return s.EVMSuite.Send(s.abi, method, args...) -} - -func (s *ERC20Suite) Deploy(symbol string) common.Address { - data := contract.GetFIP20().Bin - nonce := s.evmKeeper.GetNonce(s.ctx, s.signer.Address()) - msg := &core.Message{ - To: nil, - From: s.signer.Address(), - Nonce: nonce, - Value: big.NewInt(0), - GasLimit: 1_700_000, - GasPrice: big.NewInt(500 * 1e9), - GasFeeCap: nil, - GasTipCap: nil, - Data: data, - AccessList: nil, - SkipAccountChecks: false, - } - rsp, err := s.evmKeeper.ApplyMessage(s.ctx, msg, nil, true) - s.NoError(err) - s.False(rsp.Failed(), rsp.VmError) - s.Equal(uint64(1_407_757), rsp.GasUsed) - addr := crypto.CreateAddress(s.signer.Address(), nonce) - s.contractAddr = addr - s.Initialize(symbol, true) - return addr -} - -func (s *ERC20Suite) Initialize(symbol string, result bool) { - response := s.Send("initialize", symbol+" Token", symbol, uint8(18), helpers.GenHexAddress()) - s.Equal(response.Failed(), !result) -} - -func (s *ERC20Suite) Owner() common.Address { - var ownerRes struct { - Value common.Address - } - s.Call("owner", &ownerRes) - return ownerRes.Value -} - -func (s *ERC20Suite) Name() string { - var nameRes struct { - Value string - } - s.Call("name", &nameRes) - return nameRes.Value -} - -func (s *ERC20Suite) Symbol() string { - var symbolRes struct { - Value string - } - s.Call("symbol", &symbolRes) - return symbolRes.Value -} - -func (s *ERC20Suite) Decimals() uint8 { - var decimalsRes struct { - Value uint8 - } - s.Call("decimals", &decimalsRes) - return decimalsRes.Value -} - -func (s *ERC20Suite) TotalSupply() *big.Int { - var totalSupplyRes struct { - Value *big.Int - } - s.Call("totalSupply", &totalSupplyRes) - return totalSupplyRes.Value -} - -func (s *ERC20Suite) BalanceOf(account common.Address) *big.Int { - var balanceRes struct { - Value *big.Int - } - s.Call("balanceOf", &balanceRes, account) - return balanceRes.Value -} - -func (s *ERC20Suite) Allowance(owner, spender common.Address) *big.Int { - var allowanceRes struct { - Value *big.Int - } - s.Call("allowance", &allowanceRes, owner, spender) - return allowanceRes.Value -} - -func (s *ERC20Suite) Approve(spender common.Address, amount *big.Int, result bool) { - before := s.Allowance(s.signer.Address(), spender) - response := s.Send("approve", spender, amount) - after := s.Allowance(s.signer.Address(), spender) - s.Equal(response.Failed(), !result) - if result { - s.Equal(after, new(big.Int).Add(before, amount)) - } -} - -func (s *ERC20Suite) Transfer(recipient common.Address, amount *big.Int, result bool) *evmtypes.MsgEthereumTxResponse { - before := s.BalanceOf(s.signer.Address()) - response := s.Send("transfer", recipient, amount) - after := s.BalanceOf(s.signer.Address()) - s.Equal(response.Failed(), !result) - if result { - s.Equal(after, new(big.Int).Sub(before, amount)) - } - return response -} - -func (s *ERC20Suite) TransferFrom(sender, recipient common.Address, amount *big.Int, result bool) { - before := s.BalanceOf(recipient) - response := s.Send("transferFrom", sender, recipient, amount) - after := s.BalanceOf(recipient) - s.Equal(response.Failed(), !result) - if result { - s.Equal(after, new(big.Int).Add(before, amount)) - } -} - -func (s *ERC20Suite) Mint(to common.Address, amount *big.Int, result bool) *evmtypes.MsgEthereumTxResponse { - before := s.TotalSupply() - response := s.Send("mint", to, amount) - after := s.TotalSupply() - s.Equal(response.Failed(), !result) - if result { - s.Equal(after, new(big.Int).Add(before, amount)) - } - return response -} - -func (s *ERC20Suite) Burn(from common.Address, amount *big.Int, result bool) { - before := s.BalanceOf(from) - response := s.Send("burn", from, amount) - after := s.BalanceOf(from) - s.Equal(response.Failed(), !result) - if result { - s.Equal(after, new(big.Int).Sub(before, amount)) - } -} - -func (s *ERC20Suite) TransferOwnership(newOwner common.Address, result bool) { - before := s.Owner() - response := s.Send("transferOwnership", newOwner) - after := s.Owner() - s.Equal(response.Failed(), !result) - if result { - s.NotEqual(before, after) - } -} - -func (s *ERC20Suite) WithdrawSelf(amount *big.Int, result bool) { - before := s.BalanceOf(s.signer.Address()) - response := s.Send("withdraw", amount) - after := s.BalanceOf(s.signer.Address()) - s.Equal(response.Failed(), !result) - if result { - s.Equal(after, new(big.Int).Sub(before, amount)) - } -} - -func (s *ERC20Suite) Withdraw(to common.Address, amount *big.Int, result bool) { - before := s.BalanceOf(to) - response := s.Send("withdraw0", to, amount) - after := s.BalanceOf(to) - s.Equal(response.Failed(), !result) - if result { - s.Equal(after, before) - } -} - -func (s *ERC20Suite) Deposit(value *big.Int, result bool) { - data, err := s.abi.Pack("deposit") - s.NoError(err) - - msg := &core.Message{ - To: &s.contractAddr, - From: s.signer.Address(), - Nonce: s.evmKeeper.GetNonce(s.ctx, s.signer.Address()), - Value: value, - GasLimit: 80000, - GasPrice: big.NewInt(500 * 1e9), - GasFeeCap: nil, - GasTipCap: nil, - Data: data, - AccessList: nil, - SkipAccountChecks: false, - } - - before := s.BalanceOf(s.signer.Address()) - rsp, err := s.evmKeeper.ApplyMessage(s.ctx, msg, evmtypes.NewNoOpTracer(), true) - after := s.BalanceOf(s.signer.Address()) - s.NoError(err) - s.Equal(rsp.Failed(), !result) - if result { - s.Equal(after, new(big.Int).Add(before, value)) - } -} - -func (s *ERC20Suite) OnTest(name, symbol string, decimals uint8, totalSupply *big.Int, owner common.Address) { - s.Equal(name, s.Name()) - s.Equal(symbol, s.Symbol()) - s.Equal(decimals, s.Decimals()) - s.Equal(totalSupply.String(), s.TotalSupply().String()) - s.Equal(owner.String(), s.Owner().String()) - - s.Equal("0", s.Allowance(s.HexAddr(), s.HexAddr()).String()) - s.Approve(s.HexAddr(), big.NewInt(100), true) - s.Equal("100", s.Allowance(s.HexAddr(), s.HexAddr()).String()) - - newSigner := helpers.NewSigner(helpers.NewEthPrivKey()) - - s.Mint(s.signer.Address(), big.NewInt(200), true) - s.Transfer(newSigner.Address(), big.NewInt(100), true) - s.TransferFrom(s.signer.Address(), newSigner.Address(), big.NewInt(100), true) - s.Burn(newSigner.Address(), big.NewInt(200), true) -} diff --git a/x/evm/testutil/evm.go b/x/evm/testutil/evm.go deleted file mode 100644 index f98258ff3..000000000 --- a/x/evm/testutil/evm.go +++ /dev/null @@ -1,139 +0,0 @@ -package testutil - -import ( - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - ethtypes "github.com/ethereum/go-ethereum/core/types" - evmtypes "github.com/evmos/ethermint/x/evm/types" - "github.com/stretchr/testify/require" - - "github.com/functionx/fx-core/v8/contract" - "github.com/functionx/fx-core/v8/testutil/helpers" - fxtypes "github.com/functionx/fx-core/v8/types" - erc20types "github.com/functionx/fx-core/v8/x/erc20/types" - fxevmkeeper "github.com/functionx/fx-core/v8/x/evm/keeper" - fxevmtypes "github.com/functionx/fx-core/v8/x/evm/types" -) - -type EVMSuite struct { - *require.Assertions - ctx sdk.Context - evmKeeper *fxevmkeeper.Keeper - from common.Address - contractAddr common.Address - signer *helpers.Signer - gasPrice *big.Int -} - -func (s *EVMSuite) Init(ass *require.Assertions, ctx sdk.Context, evmKeeper *fxevmkeeper.Keeper, signer *helpers.Signer) *EVMSuite { - s.Assertions = ass - s.ctx = ctx - s.evmKeeper = evmKeeper - s.signer = signer - return s -} - -func (s *EVMSuite) GetContractAddr() *common.Address { - return &s.contractAddr -} - -func (s *EVMSuite) WithContractAddr(addr common.Address) { - s.contractAddr = addr -} - -func (s *EVMSuite) WithGasPrice(gasPrice *big.Int) { - s.gasPrice = gasPrice -} - -func (s *EVMSuite) WithSigner(signer *helpers.Signer) { - s.signer = signer -} - -func (s *EVMSuite) WithFrom(from common.Address) { - s.from = from -} - -func (s *EVMSuite) GetFrom() common.Address { - from := s.from - if contract.IsZeroEthAddress(from) && s.signer != nil { - from = s.signer.Address() - } - return from -} - -func (s *EVMSuite) HexAddr() common.Address { - return s.signer.Address() -} - -func (s *EVMSuite) AccAddr() sdk.AccAddress { - return s.signer.AccAddress() -} - -func (s *EVMSuite) Call(abi abi.ABI, method string, res interface{}, args ...interface{}) { - err := s.evmKeeper.QueryContract(s.ctx, s.GetFrom(), s.contractAddr, abi, method, res, args...) - s.NoError(err) -} - -func (s *EVMSuite) CallEVM(data []byte, gasLimit uint64) *evmtypes.MsgEthereumTxResponse { - tx, err := s.evmKeeper.ExecuteEVM(s.ctx, s.GetFrom(), &s.contractAddr, nil, gasLimit, data) - s.NoError(err) - return tx -} - -func (s *EVMSuite) Send(abi abi.ABI, method string, args ...interface{}) *evmtypes.MsgEthereumTxResponse { - response, err := s.evmKeeper.ApplyContract(s.ctx, s.signer.Address(), s.contractAddr, nil, abi, method, args...) - s.NoError(err) - return response -} - -func (s *EVMSuite) EthereumTx(to *common.Address, data []byte, value *big.Int, gasLimit uint64) (*evmtypes.MsgEthereumTxResponse, error) { - chanId := s.evmKeeper.ChainID() - s.Equal(fxtypes.EIP155ChainID(s.ctx.ChainID()), chanId) - if value == nil { - value = big.NewInt(0) - } - - nonce := s.evmKeeper.GetNonce(s.ctx, s.signer.Address()) - tx := evmtypes.NewTx( - chanId, - nonce, - to, - value, - gasLimit, - s.gasPrice, - nil, - nil, - data, - nil, - ) - tx.From = s.signer.Address().Bytes() - s.NoError(tx.Sign(ethtypes.LatestSignerForChainID(chanId), s.signer)) - - return s.evmKeeper.EthereumTx(s.ctx, tx) -} - -func (s *EVMSuite) DeployUpgradableERC20Logic(symbol string) common.Address { - erc20Contract := contract.GetFIP20() - erc20ModuleAddress := common.BytesToAddress(authtypes.NewModuleAddress(erc20types.ModuleName).Bytes()) - initializeArgs := []interface{}{symbol + " Token", symbol, uint8(18), erc20ModuleAddress} - newContractAddr, err := s.evmKeeper.DeployUpgradableContract(s.ctx, - s.signer.Address(), erc20Contract.Address, nil, &erc20Contract.ABI, initializeArgs...) - s.NoError(err) - s.contractAddr = newContractAddr - return newContractAddr -} - -func (s *EVMSuite) CallContract(data []byte) error { - msg := &fxevmtypes.MsgCallContract{ - Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), - ContractAddress: s.contractAddr.String(), - Data: common.Bytes2Hex(data), - } - _, err := s.evmKeeper.CallContract(s.ctx, msg) - return err -} diff --git a/x/staking/testutil/staking_precompile.go b/x/staking/testutil/staking_precompile.go index 50b07df01..90e019c39 100644 --- a/x/staking/testutil/staking_precompile.go +++ b/x/staking/testutil/staking_precompile.go @@ -6,32 +6,18 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/stretchr/testify/require" - fxcontract "github.com/functionx/fx-core/v8/contract" - "github.com/functionx/fx-core/v8/x/evm/testutil" "github.com/functionx/fx-core/v8/x/staking/precompile" fxstakingtypes "github.com/functionx/fx-core/v8/x/staking/types" ) type StakingPrecompileSuite struct { - testutil.EVMSuite + *require.Assertions } func (s *StakingPrecompileSuite) EthereumTx(data []byte, value *big.Int, gasLimit uint64, success bool) *evmtypes.MsgEthereumTxResponse { - toAddr := s.EVMSuite.GetContractAddr() - if gasLimit == 0 { - gasLimit = fxcontract.DefaultGasCap - } - if gasLimit < 10_000 { - gasLimit += 21_000 + gasLimit - } - tx, err := s.EVMSuite.EthereumTx(toAddr, data, value, gasLimit) - if success { - s.NoError(err) - } else { - s.Error(err) - } - return tx + return nil } func (s *StakingPrecompileSuite) Allowance(validator sdk.ValAddress, owner, spender common.Address) *big.Int { @@ -42,7 +28,7 @@ func (s *StakingPrecompileSuite) Allowance(validator sdk.ValAddress, owner, spen Spender: spender, }) s.NoError(err) - tx := s.CallEVM(data, method.RequiredGas()) + tx := s.EthereumTx(data, nil, method.RequiredGas(), true) output, err := method.UnpackOutput(tx.Ret) s.NoError(err) return output @@ -55,7 +41,7 @@ func (s *StakingPrecompileSuite) Delegation(validator sdk.ValAddress, delegator Delegator: delegator, }) s.NoError(err) - tx := s.CallEVM(data, method.RequiredGas()) + tx := s.EthereumTx(data, nil, method.RequiredGas(), true) shares, amount, err := method.UnpackOutput(tx.Ret) s.NoError(err) return shares, amount @@ -68,7 +54,7 @@ func (s *StakingPrecompileSuite) DelegationRewards(validator sdk.ValAddress, del Delegator: delegator, }) s.NoError(err) - tx := s.CallEVM(data, method.RequiredGas()) + tx := s.EthereumTx(data, nil, method.RequiredGas(), true) rewards, err := method.UnpackOutput(tx.Ret) s.NoError(err) return rewards