diff --git a/command/bridge/deploy/deploy.go b/command/bridge/deploy/deploy.go index 3a21e2dc1d..20803db4e4 100644 --- a/command/bridge/deploy/deploy.go +++ b/command/bridge/deploy/deploy.go @@ -34,7 +34,6 @@ const ( exitHelperName = "ExitHelper" rootERC20PredicateName = "RootERC20Predicate" childERC20MintablePredicateName = "ChildERC20MintablePredicate" - rootERC20Name = "RootERC20" erc20TemplateName = "ERC20Template" rootERC721PredicateName = "RootERC721Predicate" childERC721MintablePredicateName = "ChildERC721MintablePredicate" @@ -78,9 +77,6 @@ var ( rootchainConfig *polybft.RootchainConfig, addr types.Address) { rootchainConfig.ChildMintableERC20PredicateAddress = addr }, - rootERC20Name: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.RootNativeERC20Address = addr - }, erc20TemplateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { rootchainConfig.ChildERC20Address = addr }, @@ -133,7 +129,7 @@ var ( NewChildERC20Predicate: contracts.ChildERC20PredicateContract, NewChildTokenTemplate: contracts.ChildERC20Contract, // map root native token address should be non-zero only if native token is non-mintable on a childchain - NewNativeTokenRoot: config.RootNativeERC20Address, + NewNativeTokenRoot: types.ZeroAddress, } return initContract(fmt, relayer, inputParams, @@ -247,13 +243,6 @@ func GetCommand() *cobra.Command { "the JSON RPC rootchain IP address", ) - cmd.Flags().StringVar( - ¶ms.rootERC20TokenAddr, - erc20AddrFlag, - "", - "existing root chain root native token address", - ) - cmd.Flags().BoolVar( ¶ms.isTestMode, helper.TestModeFlag, @@ -419,21 +408,6 @@ func deployContracts(outputter command.OutputFormatter, client *jsonrpc.Client, StakeManagerAddress: types.StringToAddress(params.stakeManagerAddr), } - tokenContracts := []*contractInfo{} - - // deploy root ERC20 token only if non-mintable native token flavor is used on a child chain - if params.rootERC20TokenAddr != "" { - // use existing root chain ERC20 token - if err := populateExistingTokenAddr(client.Eth(), - params.rootERC20TokenAddr, rootERC20Name, rootchainConfig); err != nil { - return deploymentResultInfo{RootchainCfg: nil, CommandResults: nil}, err - } - } else { - // deploy MockERC20 as a root chain root native token - tokenContracts = append(tokenContracts, - &contractInfo{name: rootERC20Name, artifact: contractsapi.RootERC20}) - } - allContracts := []*contractInfo{ { name: stateSenderName, @@ -515,8 +489,6 @@ func deployContracts(outputter command.OutputFormatter, client *jsonrpc.Client, }, } - allContracts = append(tokenContracts, allContracts...) - g, ctx := errgroup.WithContext(cmdCtx) results := make(map[string]*deployContractResult, len(allContracts)) resultsLock := sync.Mutex{} diff --git a/command/bridge/deploy/deploy_test.go b/command/bridge/deploy/deploy_test.go index 4ebe9cbc60..3c899067af 100644 --- a/command/bridge/deploy/deploy_test.go +++ b/command/bridge/deploy/deploy_test.go @@ -53,10 +53,9 @@ func TestDeployContracts_NoPanics(t *testing.T) { params.proxyContractsAdmin = "0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed" consensusCfg = polybft.PolyBFTConfig{ NativeTokenConfig: &polybft.TokenConfig{ - Name: "Test", - Symbol: "TST", - Decimals: 18, - IsMintable: false, + Name: "Test", + Symbol: "TST", + Decimals: 18, }, } diff --git a/command/bridge/deploy/params.go b/command/bridge/deploy/params.go index 33ab529856..8e71ea0408 100644 --- a/command/bridge/deploy/params.go +++ b/command/bridge/deploy/params.go @@ -12,7 +12,6 @@ import ( const ( deployerKeyFlag = "deployer-key" jsonRPCFlag = "json-rpc" - erc20AddrFlag = "erc20-token" ) type deployParams struct { @@ -20,7 +19,6 @@ type deployParams struct { deployerKey string jsonRPCAddress string stakeTokenAddr string - rootERC20TokenAddr string stakeManagerAddr string proxyContractsAdmin string isTestMode bool @@ -42,11 +40,6 @@ func (ip *deployParams) validateFlags() error { return errors.New("native token configuration is undefined") } - // when using mintable native token, child native token on root chain gets mapped automatically - if consensusCfg.NativeTokenConfig.IsMintable && ip.rootERC20TokenAddr != "" { - return errors.New("if child chain native token is mintable, root native token must not pre-exist on root chain") - } - if params.stakeTokenAddr == "" { return errors.New("stake token address is not provided") } diff --git a/command/genesis/params.go b/command/genesis/params.go index 7444b66bb1..bf38838a2e 100644 --- a/command/genesis/params.go +++ b/command/genesis/params.go @@ -47,9 +47,7 @@ var ( errBaseFeeEMZero = errors.New("base fee elasticity multiplier must be greater than 0") errBaseFeeZero = errors.New("base fee must be greater than 0") errRewardWalletNotDefined = errors.New("reward wallet address must be defined") - errRewardTokenOnNonMintable = errors.New("a custom reward token must be defined when " + - "native ERC20 token is non-mintable") - errRewardWalletZero = errors.New("reward wallet address must not be zero address") + errRewardWalletZero = errors.New("reward wallet address must not be zero address") ) type genesisParams struct { diff --git a/command/genesis/params_test.go b/command/genesis/params_test.go index 9ff5e388fb..de3d7c623d 100644 --- a/command/genesis/params_test.go +++ b/command/genesis/params_test.go @@ -52,11 +52,10 @@ func Test_extractNativeTokenMetadata(t *testing.T) { name: "valid config", rawConfig: "MyToken:MTK:9:0x123456789", expectedCfg: &polybft.TokenConfig{ - Name: "MyToken", - Symbol: "MTK", - Decimals: 9, - IsMintable: true, - Owner: types.StringToAddress("0x123456789"), + Name: "MyToken", + Symbol: "MTK", + Decimals: 9, + Owner: types.StringToAddress("0x123456789"), }, expectErr: false, }, @@ -185,13 +184,6 @@ func Test_validateRewardWallet(t *testing.T) { isNativeERC20Mintable: true, expectValidateErr: nil, }, - { - name: "valid reward wallet: native ERC20 mintable", - rewardWallet: types.StringToAddress("1").String() + ":0", - epochReward: 0, - isNativeERC20Mintable: false, - expectValidateErr: errRewardTokenOnNonMintable, - }, } for _, c := range cases { c := c @@ -201,7 +193,7 @@ func Test_validateRewardWallet(t *testing.T) { p := &genesisParams{ rewardWallet: c.rewardWallet, epochReward: c.epochReward, - nativeTokenConfig: &polybft.TokenConfig{IsMintable: c.isNativeERC20Mintable}, + nativeTokenConfig: &polybft.TokenConfig{}, } err := p.validateRewardWalletAndToken() require.ErrorIs(t, err, c.expectValidateErr) diff --git a/command/genesis/polybft_params.go b/command/genesis/polybft_params.go index bad4a44fe8..58b8922002 100644 --- a/command/genesis/polybft_params.go +++ b/command/genesis/polybft_params.go @@ -58,8 +58,6 @@ const ( var ( errNoGenesisValidators = errors.New("genesis validators aren't provided") - errNoPremineAllowed = errors.New("native token is not mintable, so no premine is allowed " + - "except for zero address and reward wallet if native token is used as reward token") ) type contractInfo struct { @@ -81,16 +79,6 @@ func (p *genesisParams) generateChainConfig(o command.OutputFormatter) error { return fmt.Errorf("invalid reward wallet configuration provided '%s' : %w", p.rewardWallet, err) } - if !p.nativeTokenConfig.IsMintable { - // validate premine map, no premine is allowed if token is not mintable, - // except for the reward wallet (if native token is used as reward token) and zero address - for a := range premineBalances { - if a != types.ZeroAddress && (p.rewardTokenCode != "" || a != walletPremineInfo.Address) { - return errNoPremineAllowed - } - } - } - var ( rewardTokenByteCode []byte rewardTokenAddr = contracts.NativeERC20TokenContract @@ -339,20 +327,10 @@ func (p *genesisParams) deployContracts( artifact: contractsapi.RootERC20, address: contracts.ERC20Contract, }, - } - - if !params.nativeTokenConfig.IsMintable { - genesisContracts = append(genesisContracts, - &contractInfo{ - artifact: contractsapi.NativeERC20, - address: contracts.NativeERC20TokenContractV1, - }) - } else { - genesisContracts = append(genesisContracts, - &contractInfo{ - artifact: contractsapi.NativeERC20, - address: contracts.NativeERC20TokenContractV1, - }) + { + artifact: contractsapi.NativeERC20, + address: contracts.NativeERC20TokenContractV1, + }, } if len(params.bridgeAllowListAdmin) != 0 || len(params.bridgeBlockListAdmin) != 0 { @@ -540,10 +518,6 @@ func (p *genesisParams) validateRewardWalletAndToken() error { return errRewardWalletNotDefined } - if !p.nativeTokenConfig.IsMintable && p.rewardTokenCode == "" { - return errRewardTokenOnNonMintable - } - premineInfo, err := helper.ParsePremineInfo(p.rewardWallet) if err != nil { return err diff --git a/consensus/polybft/contracts_initializer.go b/consensus/polybft/contracts_initializer.go index 1bf92d45df..6f8aae8a3e 100644 --- a/consensus/polybft/contracts_initializer.go +++ b/consensus/polybft/contracts_initializer.go @@ -106,7 +106,7 @@ func getInitERC20PredicateInput(config *BridgeConfig, childChainMintable bool) ( NewStateReceiver: contracts.StateReceiverContract, NewRootERC20Predicate: config.RootERC20PredicateAddr, NewChildTokenTemplate: contracts.ChildERC20Contract, - NewNativeTokenRootAddress: config.RootNativeERC20Addr, + NewNativeTokenRootAddress: types.ZeroAddress, } } @@ -133,7 +133,7 @@ func getInitERC20PredicateACLInput(config *BridgeConfig, owner types.Address, NewStateReceiver: contracts.StateReceiverContract, NewRootERC20Predicate: config.RootERC20PredicateAddr, NewChildTokenTemplate: contracts.ChildERC20Contract, - NewNativeTokenRootAddress: config.RootNativeERC20Addr, + NewNativeTokenRootAddress: types.ZeroAddress, NewUseAllowList: useAllowList, NewUseBlockList: useBlockList, NewOwner: owner, diff --git a/consensus/polybft/helpers_test.go b/consensus/polybft/helpers_test.go index c3b0fcc596..f224eb39a0 100644 --- a/consensus/polybft/helpers_test.go +++ b/consensus/polybft/helpers_test.go @@ -184,7 +184,6 @@ func createTestBridgeConfig() *BridgeConfig { ExitHelperAddr: types.StringToAddress("3"), RootERC20PredicateAddr: types.StringToAddress("4"), ChildMintableERC20PredicateAddr: types.StringToAddress("5"), - RootNativeERC20Addr: types.StringToAddress("6"), RootERC721PredicateAddr: types.StringToAddress("8"), ChildMintableERC721PredicateAddr: types.StringToAddress("9"), RootERC1155PredicateAddr: types.StringToAddress("11"), diff --git a/consensus/polybft/polybft.go b/consensus/polybft/polybft.go index 7ad6adef5c..b4abf9d630 100644 --- a/consensus/polybft/polybft.go +++ b/consensus/polybft/polybft.go @@ -343,47 +343,25 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st } } - if polyBFTConfig.NativeTokenConfig.IsMintable { - // initialize NativeERC20Mintable SC - params := &contractsapi.InitializeNativeERC20Fn{ - Predicate_: contracts.ChildERC20PredicateContract, - Owner_: polyBFTConfig.NativeTokenConfig.Owner, - RootToken_: types.ZeroAddress, // in case native mintable token is used, it is always root token - Name_: polyBFTConfig.NativeTokenConfig.Name, - Symbol_: polyBFTConfig.NativeTokenConfig.Symbol, - Decimals_: polyBFTConfig.NativeTokenConfig.Decimals, - TokenSupply_: initialTotalSupply, - } - - input, err := params.EncodeAbi() - if err != nil { - return err - } - - if err = callContract(contracts.SystemCaller, - contracts.NativeERC20TokenContract, input, "NativeERC20Mintable", transition); err != nil { - return err - } - } else { - // initialize NativeERC20 SC - params := &contractsapi.InitializeNativeERC20Fn{ - Name_: polyBFTConfig.NativeTokenConfig.Name, - Symbol_: polyBFTConfig.NativeTokenConfig.Symbol, - Decimals_: polyBFTConfig.NativeTokenConfig.Decimals, - RootToken_: polyBFTConfig.Bridge.RootNativeERC20Addr, - Predicate_: contracts.ChildERC20PredicateContract, - TokenSupply_: initialTotalSupply, - } + // initialize NativeERC20 SC + params := &contractsapi.InitializeNativeERC20Fn{ + Predicate_: contracts.ChildERC20PredicateContract, + Owner_: polyBFTConfig.NativeTokenConfig.Owner, + RootToken_: types.ZeroAddress, // in case native mintable token is used, it is always root token + Name_: polyBFTConfig.NativeTokenConfig.Name, + Symbol_: polyBFTConfig.NativeTokenConfig.Symbol, + Decimals_: polyBFTConfig.NativeTokenConfig.Decimals, + TokenSupply_: initialTotalSupply, + } - input, err := params.EncodeAbi() - if err != nil { - return err - } + input, err := params.EncodeAbi() + if err != nil { + return err + } - if err = callContract(contracts.SystemCaller, - contracts.NativeERC20TokenContract, input, "NativeERC20", transition); err != nil { - return err - } + if err = callContract(contracts.SystemCaller, + contracts.NativeERC20TokenContract, input, "NativeERC20", transition); err != nil { + return err } } diff --git a/consensus/polybft/polybft_config.go b/consensus/polybft/polybft_config.go index f4c3a8ad95..b869755ceb 100644 --- a/consensus/polybft/polybft_config.go +++ b/consensus/polybft/polybft_config.go @@ -25,15 +25,14 @@ const ( var ( DefaultTokenConfig = &TokenConfig{ - Name: defaultNativeTokenName, - Symbol: defaultNativeTokenSymbol, - Decimals: defaultNativeTokenDecimals, - Owner: types.ZeroAddress, - IsMintable: true, + Name: defaultNativeTokenName, + Symbol: defaultNativeTokenSymbol, + Decimals: defaultNativeTokenDecimals, + Owner: types.ZeroAddress, } errInvalidTokenParams = errors.New("native token params were not submitted in proper format " + - "()") + "()") ) // PolyBFTConfig is the configuration file for the Polybft consensus protocol. @@ -122,7 +121,6 @@ type BridgeConfig struct { ExitHelperAddr types.Address `json:"exitHelperAddress"` RootERC20PredicateAddr types.Address `json:"erc20PredicateAddress"` ChildMintableERC20PredicateAddr types.Address `json:"erc20ChildMintablePredicateAddress"` - RootNativeERC20Addr types.Address `json:"nativeERC20Address"` RootERC721PredicateAddr types.Address `json:"erc721PredicateAddress"` ChildMintableERC721PredicateAddr types.Address `json:"erc721ChildMintablePredicateAddress"` RootERC1155PredicateAddr types.Address `json:"erc1155PredicateAddress"` @@ -156,7 +154,6 @@ type RootchainConfig struct { ExitHelperAddress types.Address RootERC20PredicateAddress types.Address ChildMintableERC20PredicateAddress types.Address - RootNativeERC20Address types.Address ChildERC20Address types.Address RootERC721PredicateAddress types.Address ChildMintableERC721PredicateAddress types.Address @@ -179,7 +176,6 @@ func (r *RootchainConfig) ToBridgeConfig() *BridgeConfig { ExitHelperAddr: r.ExitHelperAddress, RootERC20PredicateAddr: r.RootERC20PredicateAddress, ChildMintableERC20PredicateAddr: r.ChildMintableERC20PredicateAddress, - RootNativeERC20Addr: r.RootNativeERC20Address, RootERC721PredicateAddr: r.RootERC721PredicateAddress, ChildMintableERC721PredicateAddr: r.ChildMintableERC721PredicateAddress, RootERC1155PredicateAddr: r.RootERC1155PredicateAddress, @@ -196,11 +192,10 @@ func (r *RootchainConfig) ToBridgeConfig() *BridgeConfig { // TokenConfig is the configuration of native token used by edge network type TokenConfig struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - Decimals uint8 `json:"decimals"` - IsMintable bool `json:"isMintable"` - Owner types.Address `json:"owner"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals uint8 `json:"decimals"` + Owner types.Address `json:"owner"` } func ParseRawTokenConfig(rawConfig string) (*TokenConfig, error) { @@ -235,11 +230,10 @@ func ParseRawTokenConfig(rawConfig string) (*TokenConfig, error) { owner := types.StringToAddress(strings.TrimSpace(params[3])) return &TokenConfig{ - Name: name, - Symbol: symbol, - Decimals: uint8(decimals), - IsMintable: true, // native token on blade is always mintable - Owner: owner, + Name: name, + Symbol: symbol, + Decimals: uint8(decimals), + Owner: owner, }, nil } diff --git a/consensus/polybft/polybft_test.go b/consensus/polybft/polybft_test.go index 93a7f178e4..d64b4dc72e 100644 --- a/consensus/polybft/polybft_test.go +++ b/consensus/polybft/polybft_test.go @@ -315,7 +315,7 @@ func Test_GenesisPostHookFactory(t *testing.T) { Bridge: bridgeCfg, EpochSize: epochSize, RewardConfig: &RewardsConfig{WalletAmount: ethgo.Ether(1000)}, - NativeTokenConfig: &TokenConfig{Name: "Test Mintable", Symbol: "TEST_MNT", Decimals: 18, IsMintable: true}, + NativeTokenConfig: &TokenConfig{Name: "Test Mintable", Symbol: "TEST_MNT", Decimals: 18}, MaxValidatorSetSize: maxValidators, }, bridgeAllowList: &chain.AddressListConfig{ diff --git a/e2e-polybft/e2e/bridge_test.go b/e2e-polybft/e2e/bridge_test.go index b339a5e23f..ceb097d99c 100644 --- a/e2e-polybft/e2e/bridge_test.go +++ b/e2e-polybft/e2e/bridge_test.go @@ -84,9 +84,14 @@ func TestE2E_Bridge_Transfers(t *testing.T) { // bridge some tokens for first validator to child chain tokensToDeposit := ethgo.Ether(10) + erc20Txn := cluster.Deploy(t, senderAccount.Ecdsa, contractsapi.RootERC20.Bytecode) + require.NoError(t, erc20Txn.Wait()) + require.True(t, erc20Txn.Succeed()) + rootERC20Token := types.Address(erc20Txn.Receipt().ContractAddress) + require.NoError(t, cluster.Bridge.Deposit( common.ERC20, - polybftCfg.Bridge.RootNativeERC20Addr, + rootERC20Token, polybftCfg.Bridge.RootERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, senderAccount.Address().String(), @@ -122,7 +127,7 @@ func TestE2E_Bridge_Transfers(t *testing.T) { // send a few transactions to the bridge require.NoError(t, cluster.Bridge.Deposit( common.ERC20, - polybftCfg.Bridge.RootNativeERC20Addr, + rootERC20Token, polybftCfg.Bridge.RootERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join(receivers[:], ","), @@ -233,7 +238,7 @@ func TestE2E_Bridge_Transfers(t *testing.T) { // assert that receiver's balances on RootERC20 smart contract are expected for _, receiver := range receivers { balance := erc20BalanceOf(t, types.StringToAddress(receiver), - polybftCfg.Bridge.RootNativeERC20Addr, rootchainTxRelayer) + rootERC20Token, rootchainTxRelayer) require.Equal(t, big.NewInt(amount), balance) } }) @@ -268,7 +273,7 @@ func TestE2E_Bridge_Transfers(t *testing.T) { // send two transactions to the bridge so that we have a minimal commitment require.NoError(t, cluster.Bridge.Deposit( common.ERC20, - polybftCfg.Bridge.RootNativeERC20Addr, + rootERC20Token, polybftCfg.Bridge.RootERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join(receivers[:depositsSubset], ","), @@ -295,7 +300,7 @@ func TestE2E_Bridge_Transfers(t *testing.T) { // send some more transactions to the bridge to build another commitment in epoch require.NoError(t, cluster.Bridge.Deposit( common.ERC20, - polybftCfg.Bridge.RootNativeERC20Addr, + rootERC20Token, polybftCfg.Bridge.RootERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join(receivers[depositsSubset:], ","), @@ -1341,6 +1346,7 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { framework.WithNumBlockConfirmations(0), framework.WithEpochSize(epochSize), framework.WithTestRewardToken(), + framework.WithRootTrackerPollInterval(3*time.Second), framework.WithBridgeAllowListAdmin(adminAddr), framework.WithBridgeBlockListAdmin(adminAddr), framework.WithSecretsCallback(func(a []types.Address, tcc *framework.TestClusterConfig) { @@ -1371,11 +1377,16 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { adminBalanceOnChild := ethgo.Ether(5) + erc20Txn := cluster.Deploy(t, admin, contractsapi.RootERC20.Bytecode) + require.NoError(t, erc20Txn.Wait()) + require.True(t, erc20Txn.Succeed()) + rootERC20Token := types.Address(erc20Txn.Receipt().ContractAddress) + // bridge some tokens for admin to child chain require.NoError( t, cluster.Bridge.Deposit( common.ERC20, - polybftCfg.Bridge.RootNativeERC20Addr, + rootERC20Token, polybftCfg.Bridge.RootERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, adminAddr.String(), @@ -1402,14 +1413,14 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { require.NoError(t, err) require.Equal(t, adminBalanceOnChild, balance) - t.Run("bridge native (ERC 20) tokens", func(t *testing.T) { + t.Run("bridge ERC 20 tokens", func(t *testing.T) { // DEPOSIT ERC20 TOKENS // send a few transactions to the bridge require.NoError( t, cluster.Bridge.Deposit( common.ERC20, - polybftCfg.Bridge.RootNativeERC20Addr, + rootERC20Token, polybftCfg.Bridge.RootERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join(receivers[:], ","), @@ -1522,7 +1533,7 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { oldBalances := map[types.Address]*big.Int{} for _, receiver := range receivers { - balance := erc20BalanceOf(t, types.StringToAddress(receiver), polybftCfg.Bridge.RootNativeERC20Addr, rootchainTxRelayer) + balance := erc20BalanceOf(t, types.StringToAddress(receiver), rootERC20Token, rootchainTxRelayer) oldBalances[types.StringToAddress(receiver)] = balance } @@ -1534,299 +1545,9 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { // assert that receiver's balances on RootERC20 smart contract are expected for _, receiver := range receivers { - balance := erc20BalanceOf(t, types.StringToAddress(receiver), polybftCfg.Bridge.RootNativeERC20Addr, rootchainTxRelayer) + balance := erc20BalanceOf(t, types.StringToAddress(receiver), rootERC20Token, rootchainTxRelayer) require.Equal(t, oldBalances[types.StringToAddress(receiver)].Add( oldBalances[types.StringToAddress(receiver)], withdrawAmount), balance) } }) } - -func TestE2E_Bridge_Transfers_WithRootTrackerPollInterval(t *testing.T) { - var ( - numBlockConfirmations = uint64(2) - epochSize = 30 - sprintSize = uint64(5) - rootPollInterval = 5 * time.Second - numberOfAttempts = uint64(4) - stateSyncedLogsCount = 1 - ) - - cluster := framework.NewTestCluster(t, 5, - framework.WithEpochSize(epochSize), - framework.WithNumBlockConfirmations(numBlockConfirmations), - framework.WithRootTrackerPollInterval(rootPollInterval), - framework.WithTestRewardToken(), - ) - defer cluster.Stop() - - cluster.WaitForReady(t) - - polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) - require.NoError(t, err) - - validatorSrv := cluster.Servers[0] - senderAccount, err := validatorHelper.GetAccountFromDir(validatorSrv.DataDir()) - require.NoError(t, err) - - childEthEndpoint := validatorSrv.JSONRPC().Eth() - - // bridge some tokens for first validator to child chain - tokensToDeposit := ethgo.Ether(10) - - require.NoError(t, cluster.Bridge.Deposit( - common.ERC20, - polybftCfg.Bridge.RootNativeERC20Addr, - polybftCfg.Bridge.RootERC20PredicateAddr, - bridgeHelper.TestAccountPrivKey, - senderAccount.Address().String(), - tokensToDeposit.String(), - "", - cluster.Bridge.JSONRPCAddr(), - bridgeHelper.TestAccountPrivKey, - false), - ) - - // wait for a couple of sprints - finalBlockNum := 5 * sprintSize - - // the transaction is processed and there should be a success event - var stateSyncedResult contractsapi.StateSyncResultEvent - - for i := uint64(0); i < numberOfAttempts; i++ { - logs, err := getFilteredLogs(stateSyncedResult.Sig(), 0, finalBlockNum+i*sprintSize, childEthEndpoint) - require.NoError(t, err) - - if len(logs) == stateSyncedLogsCount || i == numberOfAttempts-1 { - // assert that all deposits are executed successfully - checkStateSyncResultLogs(t, logs, stateSyncedLogsCount) - - break - } - - require.NoError(t, cluster.WaitForBlock(finalBlockNum+(i+1)*sprintSize, 2*time.Minute)) - } - - // check validator balance got increased by deposited amount - balance, err := childEthEndpoint.GetBalance(ethgo.Address(senderAccount.Address()), ethgo.Latest) - require.NoError(t, err) - - // because we premined the validators - expectedBalance := new(big.Int).Add(command.DefaultPremineBalance, tokensToDeposit) - require.Equal(t, expectedBalance, balance) -} - -func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) { - var ( - numBlockConfirmations = uint64(2) - epochSize = 10 - sprintSize = uint64(5) - numberOfAttempts = uint64(4) - stateSyncedLogsCount = 2 - exitEventsCount = uint64(2) - tokensToTransfer = ethgo.Gwei(10) - bigZero = big.NewInt(0) - ) - - nonValidatorKey, err := wallet.GenerateKey() - require.NoError(t, err) - - nonValidatorKeyRaw, err := nonValidatorKey.MarshallPrivateKey() - require.NoError(t, err) - - // start cluster with default, non-mintable native erc20 root token - // with london fork enabled - cluster := framework.NewTestCluster(t, 5, - framework.WithEpochSize(epochSize), - framework.WithNumBlockConfirmations(numBlockConfirmations), - framework.WithTestRewardToken(), - framework.WithSecretsCallback(func(_ []types.Address, tcc *framework.TestClusterConfig) { - nonValidatorKeyString := hex.EncodeToString(nonValidatorKeyRaw) - - // do premine to a non validator address - tcc.Premine = append(tcc.Premine, - fmt.Sprintf("%s:%s:%s", - nonValidatorKey.Address(), - command.DefaultPremineBalance.String(), - nonValidatorKeyString)) - }), - ) - - rootchainTxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) - require.NoError(t, err) - - childEthEndpoint := cluster.Servers[0].JSONRPC().Eth() - - defer cluster.Stop() - - cluster.WaitForReady(t) - - polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) - require.NoError(t, err) - - checkBalancesFn := func(address types.Address, rootExpected, childExpected *big.Int) { - t.Log("Checking balance of native ERC20 token on root and child", "Address", address, - "Root expected", rootExpected, "Child Expected", childExpected) - - balance := erc20BalanceOf(t, address, - polybftCfg.Bridge.RootNativeERC20Addr, rootchainTxRelayer) - t.Log("Balance of native ERC20 token on root", balance, "Address", address) - require.Equal(t, rootExpected, balance) - - balance, err = childEthEndpoint.GetBalance(ethgo.Address(address), ethgo.Latest) - require.NoError(t, err) - t.Log("Balance of native ERC20 token on child", balance, "Address", address) - require.True(t, balance.Cmp(childExpected) >= 0) // because of London fork - } - - t.Run("check the balances at the beginning", func(t *testing.T) { - // check the balances on root and child at the beginning to see if they are as expected - checkBalancesFn(types.Address(nonValidatorKey.Address()), bigZero, command.DefaultPremineBalance) - - for _, server := range cluster.Servers { - validatorAccount, err := validatorHelper.GetAccountFromDir(server.DataDir()) - require.NoError(t, err) - - checkBalancesFn(validatorAccount.Address(), bigZero, command.DefaultPremineBalance) - } - }) - - // this test case will check first if they can withdraw some of the premined amount of non-mintable token - t.Run("Do a withdraw for premined validator address and premined non-validator address", func(t *testing.T) { - validatorSrv := cluster.Servers[1] - validatorAcc, err := validatorHelper.GetAccountFromDir(validatorSrv.DataDir()) - require.NoError(t, err) - - validatorRawKey, err := validatorAcc.Ecdsa.MarshallPrivateKey() - require.NoError(t, err) - - err = cluster.Bridge.Withdraw( - common.ERC20, - hex.EncodeToString(validatorRawKey), - validatorAcc.Address().String(), - tokensToTransfer.String(), - "", - validatorSrv.JSONRPCAddr(), - contracts.ChildERC20PredicateContract, - contracts.NativeERC20TokenContract, - false) - require.NoError(t, err) - - validatorBalanceAfterWithdraw, err := childEthEndpoint.GetBalance( - ethgo.Address(validatorAcc.Address()), ethgo.Latest) - require.NoError(t, err) - - err = cluster.Bridge.Withdraw( - common.ERC20, - hex.EncodeToString(nonValidatorKeyRaw), - nonValidatorKey.Address().String(), - tokensToTransfer.String(), - "", - validatorSrv.JSONRPCAddr(), - contracts.ChildERC20PredicateContract, - contracts.NativeERC20TokenContract, - false) - require.NoError(t, err) - - nonValidatorBalanceAfterWithdraw, err := childEthEndpoint.GetBalance( - nonValidatorKey.Address(), ethgo.Latest) - require.NoError(t, err) - - currentBlock, err := childEthEndpoint.GetBlockByNumber(ethgo.Latest, false) - require.NoError(t, err) - - currentExtra, err := polybft.GetIbftExtra(currentBlock.ExtraData) - require.NoError(t, err) - - t.Logf("Latest block number: %d, epoch number: %d\n", currentBlock.Number, currentExtra.Checkpoint.EpochNumber) - - currentEpoch := currentExtra.Checkpoint.EpochNumber - - exitHelper := polybftCfg.Bridge.ExitHelperAddr - childJSONRPC := validatorSrv.JSONRPCAddr() - - successfulExitTransactions := make([]bool, exitEventsCount) - - for i := uint64(0); i < numberOfAttempts; i++ { - t.Log("Number of attempts: ", i+1) - - require.NoError(t, waitForRootchainEpoch(currentEpoch+i, 3*time.Minute, - rootchainTxRelayer, polybftCfg.Bridge.CheckpointManagerAddr)) - - for exitEventID := uint64(1); exitEventID <= exitEventsCount; exitEventID++ { - if successfulExitTransactions[exitEventID-1] { - continue - } - - // send exit transaction to exit helper - if err = cluster.Bridge.SendExitTransaction(exitHelper, exitEventID, childJSONRPC); err == nil { - successfulExitTransactions[exitEventID-1] = true - - continue - } - - if i == numberOfAttempts-1 { - require.NoError(t, err) - } - } - - allExitsSuccessfull := true - for _, isSuccessfull := range successfulExitTransactions { - if !isSuccessfull { - allExitsSuccessfull = false - - break - } - } - - if allExitsSuccessfull { - break - } - } - - // assert that receiver's balances on RootERC20 smart contract are expected - checkBalancesFn(validatorAcc.Address(), tokensToTransfer, validatorBalanceAfterWithdraw) - checkBalancesFn(types.Address(nonValidatorKey.Address()), tokensToTransfer, nonValidatorBalanceAfterWithdraw) - }) - - t.Run("Do a deposit to some validator and non-validator address", func(t *testing.T) { - validatorSrv := cluster.Servers[4] - validatorAcc, err := validatorHelper.GetAccountFromDir(validatorSrv.DataDir()) - require.NoError(t, err) - - require.NoError(t, cluster.Bridge.Deposit( - common.ERC20, - polybftCfg.Bridge.RootNativeERC20Addr, - polybftCfg.Bridge.RootERC20PredicateAddr, - bridgeHelper.TestAccountPrivKey, - strings.Join([]string{validatorAcc.Address().String(), nonValidatorKey.Address().String()}, ","), - strings.Join([]string{tokensToTransfer.String(), tokensToTransfer.String()}, ","), - "", - cluster.Bridge.JSONRPCAddr(), - bridgeHelper.TestAccountPrivKey, - false), - ) - - currentBlock, err := childEthEndpoint.GetBlockByNumber(ethgo.Latest, false) - require.NoError(t, err) - - // wait for a couple of sprints - finalBlockNum := currentBlock.Number + 5*sprintSize - - // the transaction is processed and there should be a success event - var stateSyncedResult contractsapi.StateSyncResultEvent - - for i := uint64(0); i < numberOfAttempts; i++ { - logs, err := getFilteredLogs(stateSyncedResult.Sig(), 0, finalBlockNum+i*sprintSize, childEthEndpoint) - require.NoError(t, err) - - if len(logs) == stateSyncedLogsCount || i == numberOfAttempts-1 { - // assert that all deposits are executed successfully - checkStateSyncResultLogs(t, logs, stateSyncedLogsCount) - - break - } - - require.NoError(t, cluster.WaitForBlock(finalBlockNum+(i+1)*sprintSize, 2*time.Minute)) - } - }) -} diff --git a/e2e-polybft/framework/test-bridge.go b/e2e-polybft/framework/test-bridge.go index 51e6f32117..d2a1f957ea 100644 --- a/e2e-polybft/framework/test-bridge.go +++ b/e2e-polybft/framework/test-bridge.go @@ -352,16 +352,13 @@ func (t *TestBridge) fundAddressesOnRoot(tokenConfig *polybft.TokenConfig, polyb // then fund all other addresses if token is non-mintable // so that they can do premine on SupernetMAnager - if tokenConfig.IsMintable || len(t.clusterConfig.Premine) == 0 { + if len(t.clusterConfig.Premine) == 0 { return nil } // non-validator addresses don't need to mint stake token, // they only need to be funded with root token - args := []string{ - "bridge", - "fund", - } + args := []string{"bridge", "fund"} for _, premineRaw := range t.clusterConfig.Premine { premineInfo, err := cmdHelper.ParsePremineInfo(premineRaw) @@ -521,123 +518,3 @@ func (t *TestBridge) FundValidators(tokenAddress types.Address, secretsPaths []s return nil } - -func (t *TestBridge) mintNativeRootToken(validatorAddresses []types.Address, tokenConfig *polybft.TokenConfig, - polybftConfig polybft.PolyBFTConfig) error { - if tokenConfig.IsMintable { - // if token is mintable, it is premined in genesis command, - // so we just return here - return nil - } - - // if token is non-mintable, then to do premine we first need to mint those tokens - // to validators and other provided addresses - args := []string{ - "bridge", - "mint-erc20", - "--jsonrpc", t.JSONRPCAddr(), - "--erc20-token", polybftConfig.Bridge.RootNativeERC20Addr.String(), - } - - // mint something for every validator - for _, addr := range validatorAddresses { - args = append(args, "--addresses", addr.String()) - args = append(args, "--amounts", command.DefaultPremineBalance.String()) - } - - // mint something to others as well - for _, premineRaw := range t.clusterConfig.Premine { - premineInfo, err := cmdHelper.ParsePremineInfo(premineRaw) - if err != nil { - return err - } - - args = append(args, "--addresses", premineInfo.Address.String()) - args = append(args, "--amounts", premineInfo.Amount.String()) - } - - return t.cmdRun(args...) -} - -func (t *TestBridge) premineNativeRootToken(tokenConfig *polybft.TokenConfig, - polybftConfig polybft.PolyBFTConfig) error { - if tokenConfig.IsMintable { - // if token is mintable, it is premined in genesis command, - // so we just return here - return nil - } - - validatorSecrets, err := genesis.GetValidatorKeyFiles(t.clusterConfig.TmpDir, t.clusterConfig.ValidatorPrefix) - if err != nil { - return fmt.Errorf("could not get validator secrets on premining native root"+ - " token for genesis validators: %w", err) - } - - premineCmdArgs := func(secret, key string, amount *big.Int) error { - args := []string{ - "bridge", - "premine", - "--jsonrpc", t.JSONRPCAddr(), - "--supernet-manager", polybftConfig.Bridge.CustomSupernetManagerAddr.String(), - "--amount", amount.String(), - "--erc20-token", polybftConfig.Bridge.RootNativeERC20Addr.String(), - "--root-erc20-predicate", polybftConfig.Bridge.RootERC20PredicateAddr.String(), - } - - if secret != "" { - args = append(args, "--"+polybftsecrets.AccountDirFlag, path.Join(t.clusterConfig.TmpDir, secret)) - } else { - args = append(args, "--private-key", key) - } - - return t.cmdRun(args...) - } - - g, ctx := errgroup.WithContext(context.Background()) - - // premine validators - for _, secret := range validatorSecrets { - secret := secret - - g.Go(func() error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - if err := premineCmdArgs(secret, "", command.DefaultPremineBalance); err != nil { - return fmt.Errorf("failed to do premine of native root token for genesis validator: %w", - err) - } - - return nil - } - }) - } - - // now premine for other addresses - for _, premineRaw := range t.clusterConfig.Premine { - premineRaw := premineRaw - - g.Go(func() error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - premineInfo, err := cmdHelper.ParsePremineInfo(premineRaw) - if err != nil { - return fmt.Errorf("failed to do premine of native root token for non-validator"+ - " account: %w. premine raw: %s", err, premineRaw) - } - - if err := premineCmdArgs("", premineInfo.Key, premineInfo.Amount); err != nil { - return fmt.Errorf("failed to do premine of native root token for "+ - "non-validator account: %w. premine raw: %s", err, premineRaw) - } - - return nil - } - }) - } - - return g.Wait() -} diff --git a/e2e-polybft/framework/test-cluster.go b/e2e-polybft/framework/test-cluster.go index be447ecc5c..987203a04b 100644 --- a/e2e-polybft/framework/test-cluster.go +++ b/e2e-polybft/framework/test-cluster.go @@ -515,10 +515,7 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T args = append(args, "--native-token-config", cluster.Config.NativeTokenConfigRaw) } - tokenConfig, err := polybft.ParseRawTokenConfig(cluster.Config.NativeTokenConfigRaw) - require.NoError(t, err) - - if len(cluster.Config.Premine) != 0 && tokenConfig.IsMintable { + if len(cluster.Config.Premine) != 0 { // only add premine flags in genesis if token is mintable for _, premine := range cluster.Config.Premine { args = append(args, "--premine", premine)