github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/erc20/keeper/keeper_test.go (about)

     1  package keeper_test
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math/big"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/ethereum/go-ethereum/accounts/abi"
    11  	"github.com/ethereum/go-ethereum/common"
    12  	"github.com/stretchr/testify/suite"
    13  
    14  	"github.com/fibonacci-chain/fbc/app"
    15  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    16  	minttypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/mint"
    17  	transfertypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/apps/transfer/types"
    18  	clienttypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/02-client/types"
    19  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    20  	tmbytes "github.com/fibonacci-chain/fbc/libs/tendermint/libs/bytes"
    21  	"github.com/fibonacci-chain/fbc/x/erc20/keeper"
    22  	"github.com/fibonacci-chain/fbc/x/erc20/types"
    23  	evmtypes "github.com/fibonacci-chain/fbc/x/evm/types"
    24  )
    25  
    26  var (
    27  	Uint256, _ = abi.NewType("uint256", "", nil)
    28  )
    29  
    30  func TestKeeperTestSuite(t *testing.T) {
    31  	suite.Run(t, new(KeeperTestSuite))
    32  }
    33  
    34  type KeeperTestSuite struct {
    35  	suite.Suite
    36  
    37  	ctx sdk.Context
    38  	app *app.FBChainApp
    39  
    40  	querier sdk.Querier
    41  }
    42  
    43  func (suite *KeeperTestSuite) SetupTest() {
    44  	checkTx := false
    45  
    46  	suite.app = app.Setup(checkTx)
    47  	suite.ctx = suite.app.NewContext(checkTx, abci.Header{
    48  		Height:  1,
    49  		ChainID: "ethermint-3",
    50  		Time:    time.Now().UTC(),
    51  	})
    52  	suite.querier = keeper.NewQuerier(suite.app.Erc20Keeper)
    53  	suite.app.Erc20Keeper.SetParams(suite.ctx, types.DefaultParams())
    54  }
    55  
    56  func (suite *KeeperTestSuite) MintCoins(address sdk.AccAddress, coins sdk.Coins) error {
    57  	err := suite.app.SupplyKeeper.MintCoins(suite.ctx, minttypes.ModuleName, coins)
    58  	if err != nil {
    59  		return err
    60  	}
    61  	err = suite.app.SupplyKeeper.SendCoinsFromModuleToAccount(suite.ctx, minttypes.ModuleName, address, coins)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	return nil
    66  }
    67  
    68  func (suite *KeeperTestSuite) GetBalance(address sdk.AccAddress, denom string) sdk.Coin {
    69  	acc := suite.app.AccountKeeper.GetAccount(suite.ctx, address)
    70  	return sdk.Coin{denom, acc.GetCoins().AmountOf(denom)}
    71  }
    72  
    73  type IbcKeeperMock struct{}
    74  
    75  func (i IbcKeeperMock) SendTransfer(ctx sdk.Context, sourcePort, sourceChannel string, token sdk.CoinAdapter,
    76  	sender sdk.AccAddress, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64) error {
    77  	return nil
    78  }
    79  
    80  func (i IbcKeeperMock) DenomPathFromHash(ctx sdk.Context, denom string) (string, error) { //nolint
    81  	if denom == "ibc/ddcd907790b8aa2bf9b2b3b614718fa66bfc7540e832ce3e3696ea717dceff49" {
    82  		return "transfer/channel-0", nil
    83  	}
    84  	if denom == "ibc/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" {
    85  		return "transfer/channel-0", nil
    86  	}
    87  	return "", errors.New("not fount")
    88  }
    89  
    90  func (i IbcKeeperMock) GetDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) (transfertypes.DenomTrace, bool) {
    91  	return transfertypes.DenomTrace{}, false
    92  }
    93  
    94  func (suite *KeeperTestSuite) TestDenomContractMap() {
    95  	denom1 := "testdenom1"
    96  	denom2 := "testdenom2"
    97  
    98  	autoContract := common.BigToAddress(big.NewInt(1))
    99  	externalContract := common.BigToAddress(big.NewInt(2))
   100  
   101  	testCases := []struct {
   102  		name     string
   103  		malleate func()
   104  	}{
   105  		{
   106  			"success, happy path",
   107  			func() {
   108  				keeper := suite.app.Erc20Keeper
   109  
   110  				contract, found := keeper.GetContractByDenom(suite.ctx, denom1)
   111  				suite.Require().False(found)
   112  
   113  				keeper.SetContractForDenom(suite.ctx, denom1, autoContract)
   114  
   115  				contract, found = keeper.GetContractByDenom(suite.ctx, denom1)
   116  				suite.Require().True(found)
   117  				suite.Require().Equal(autoContract, contract)
   118  
   119  				denom, found := keeper.GetDenomByContract(suite.ctx, contract)
   120  				suite.Require().True(found)
   121  				suite.Require().Equal(denom1, denom)
   122  
   123  				keeper.SetContractForDenom(suite.ctx, denom1, externalContract)
   124  
   125  				contract, found = keeper.GetContractByDenom(suite.ctx, denom1)
   126  				suite.Require().True(found)
   127  				suite.Require().Equal(externalContract, contract)
   128  			},
   129  		},
   130  		{
   131  			"failure, multiple denoms map to same contract",
   132  			func() {
   133  				keeper := suite.app.Erc20Keeper
   134  				keeper.SetContractForDenom(suite.ctx, denom1, autoContract)
   135  				err := keeper.SetContractForDenom(suite.ctx, denom2, autoContract)
   136  				suite.Require().Error(err)
   137  			},
   138  		},
   139  		{
   140  			"failure, multiple denoms map to same external contract",
   141  			func() {
   142  				keeper := suite.app.Erc20Keeper
   143  				err := keeper.SetContractForDenom(suite.ctx, denom1, externalContract)
   144  				suite.Require().NoError(err)
   145  				err = keeper.SetContractForDenom(suite.ctx, denom2, externalContract)
   146  				suite.Require().Error(err)
   147  			},
   148  		},
   149  		{
   150  			"success, delete contract",
   151  			func() {
   152  				keeper := suite.app.Erc20Keeper
   153  				r := keeper.DeleteContractForDenom(suite.ctx, denom1)
   154  				suite.Require().Equal(r, false)
   155  				err := keeper.SetContractForDenom(suite.ctx, denom1, externalContract)
   156  				suite.Require().NoError(err)
   157  				r = keeper.DeleteContractForDenom(suite.ctx, denom1)
   158  				suite.Require().Equal(r, true)
   159  			},
   160  		},
   161  		{
   162  			"success, multiple denoms map to different contracts",
   163  			func() {
   164  				keeper := suite.app.Erc20Keeper
   165  				err := keeper.SetContractForDenom(suite.ctx, denom1, autoContract)
   166  				suite.Require().NoError(err)
   167  				err = keeper.SetContractForDenom(suite.ctx, denom2, externalContract)
   168  				suite.Require().NoError(err)
   169  				out := keeper.GetContracts(suite.ctx)
   170  				suite.Require().Equal(out[0].Contract, autoContract.String())
   171  				suite.Require().Equal(out[1].Contract, externalContract.String())
   172  			},
   173  		},
   174  	}
   175  
   176  	for _, tc := range testCases {
   177  		suite.Run(tc.name, func() {
   178  			suite.SetupTest()
   179  			tc.malleate()
   180  		})
   181  	}
   182  }
   183  
   184  func (suite *KeeperTestSuite) TestProxyContractRedirect() {
   185  	denom := "testdenom1"
   186  	addr1 := common.BigToAddress(big.NewInt(2))
   187  
   188  	testCases := []struct {
   189  		name     string
   190  		malleate func()
   191  	}{
   192  		{
   193  			"success, proxy contract redirect owner",
   194  			func() {
   195  				suite.app.Erc20Keeper.InitInternalTemplateContract(suite.ctx)
   196  				evmParams := evmtypes.DefaultParams()
   197  				evmParams.EnableCreate = true
   198  				evmParams.EnableCall = true
   199  				suite.app.EvmKeeper.SetParams(suite.ctx, evmParams)
   200  				suite.app.Erc20Keeper.SetContractForDenom(suite.ctx, denom, addr1)
   201  				err := suite.app.Erc20Keeper.ProxyContractRedirect(suite.ctx, denom, types.RedirectOwner, addr1)
   202  				suite.Require().NoError(err)
   203  			},
   204  		},
   205  		{
   206  			"success, proxy contract redirect contract",
   207  			func() {
   208  				suite.app.Erc20Keeper.InitInternalTemplateContract(suite.ctx)
   209  				evmParams := evmtypes.DefaultParams()
   210  				evmParams.EnableCreate = true
   211  				evmParams.EnableCall = true
   212  				suite.app.EvmKeeper.SetParams(suite.ctx, evmParams)
   213  				suite.app.Erc20Keeper.SetContractForDenom(suite.ctx, denom, addr1)
   214  				err := suite.app.Erc20Keeper.ProxyContractRedirect(suite.ctx, denom, types.RedirectImplementation, addr1)
   215  				suite.Require().NoError(err)
   216  			},
   217  		},
   218  	}
   219  
   220  	for _, tc := range testCases {
   221  		suite.Run(tc.name, func() {
   222  			suite.SetupTest()
   223  			tc.malleate()
   224  		})
   225  	}
   226  }
   227  
   228  func (suite *KeeperTestSuite) TestSetGetTemplateContract() {
   229  	f := func(bin string) string {
   230  		json := `[{	"inputs": [{"internalType": "uint256","name": "a","type": "uint256"	},{	"internalType": "uint256","name": "b","type": "uint256"}],"stateMutability": "nonpayable","type": "constructor"}]`
   231  		str := fmt.Sprintf(`{"abi":%s,"bin":"%s"}`, json, bin)
   232  		return str
   233  	}
   234  
   235  	testCases := []struct {
   236  		name     string
   237  		malleate func()
   238  	}{
   239  		{
   240  			"success, there is no data ",
   241  			func() {
   242  				_, found := suite.app.Erc20Keeper.GetImplementTemplateContract(suite.ctx)
   243  				suite.Require().Equal(found, false)
   244  			},
   245  		},
   246  		{
   247  			"success,set contract first",
   248  			func() {
   249  				c1 := f("c1")
   250  				err := suite.app.Erc20Keeper.SetTemplateContract(suite.ctx, types.ProposalTypeContextTemplateImpl, c1)
   251  				suite.Require().NoError(err)
   252  				c11, found := suite.app.Erc20Keeper.GetImplementTemplateContract(suite.ctx)
   253  				suite.Require().NoError(err)
   254  				suite.Require().Equal(found, true)
   255  				suite.Require().NotEqual(c11, types.ModuleERC20Contract)
   256  				suite.Require().Equal(c11.Bin, "c1")
   257  			},
   258  		},
   259  		{
   260  			"success, set contract twice",
   261  			func() {
   262  				c1 := f("c1")
   263  				c2 := f("c2")
   264  				err := suite.app.Erc20Keeper.SetTemplateContract(suite.ctx, types.ProposalTypeContextTemplateImpl, c1)
   265  				suite.Require().NoError(err)
   266  				err = suite.app.Erc20Keeper.SetTemplateContract(suite.ctx, types.ProposalTypeContextTemplateImpl, c2)
   267  				suite.Require().NoError(err)
   268  				c11, found := suite.app.Erc20Keeper.GetImplementTemplateContract(suite.ctx)
   269  				suite.Require().Equal(found, true)
   270  				suite.Require().NoError(err)
   271  				suite.Require().NotEqual(c11, types.ModuleERC20Contract)
   272  				suite.Require().NotEqual(c11.Bin, "c1")
   273  				suite.Require().Equal(c11.Bin, "c2")
   274  			},
   275  		},
   276  		{
   277  			"success ,no proxy contract",
   278  			func() {
   279  				_, found := suite.app.Erc20Keeper.GetProxyTemplateContract(suite.ctx)
   280  				suite.Require().Equal(false, found)
   281  			},
   282  		},
   283  		{
   284  			"success ,set proxy contract",
   285  			func() {
   286  				_, found := suite.app.Erc20Keeper.GetProxyTemplateContract(suite.ctx)
   287  				suite.Require().Equal(false, found)
   288  				proxy := f("proxy")
   289  				suite.app.Erc20Keeper.SetTemplateContract(suite.ctx, types.ProposalTypeContextTemplateProxy, proxy)
   290  				cc, found := suite.app.Erc20Keeper.GetProxyTemplateContract(suite.ctx)
   291  				suite.Require().Equal(true, found)
   292  				suite.Require().Equal(cc.Bin, "proxy")
   293  			},
   294  		},
   295  	}
   296  
   297  	for _, tc := range testCases {
   298  		suite.Run(tc.name, func() {
   299  			suite.SetupTest()
   300  			tc.malleate()
   301  		})
   302  	}
   303  }