diff --git a/integrationTests/relayers/common.go b/integrationTests/relayers/common.go index 5fc45bf2..20745a0b 100644 --- a/integrationTests/relayers/common.go +++ b/integrationTests/relayers/common.go @@ -70,7 +70,7 @@ func CreateBridgeComponentsConfig(index int, workingDir string, gasStationURL st MultisigContractAddress: "3009d97FfeD62E57d444e552A9eDF9Ee6Bc8644c", PrivateKeyFile: fmt.Sprintf("testdata/ethereum%d.sk", index), IntervalToResendTxsInSeconds: 10, - GasLimitBase: 200000, + GasLimitBase: 350000, GasLimitForEach: 30000, GasStation: config.GasStationConfig{ Enabled: len(gasStationURL) > 0, diff --git a/integrationTests/relayers/multiversXToEth_test.go b/integrationTests/relayers/multiversXToEth_test.go index 1372e406..c3cf23ef 100644 --- a/integrationTests/relayers/multiversXToEth_test.go +++ b/integrationTests/relayers/multiversXToEth_test.go @@ -22,6 +22,7 @@ import ( ) var zero = big.NewInt(0) +var relayerEthBalance = big.NewInt(1000000000) func asyncCancelCall(cancelHandler func(), delay time.Duration) { go func() { @@ -55,7 +56,7 @@ func TestRelayersShouldExecuteSimpleTransfersFromMultiversXToEth(t *testing.T) { return expectedStatuses, true } ethereumChainMock.BalanceAtCalled = func(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { - return big.NewInt(260000000), nil + return relayerEthBalance, nil } multiversXChainMock := mock.NewMultiversXChainMock() for i := 0; i < len(deposits); i++ { @@ -152,7 +153,7 @@ func testRelayersShouldExecuteTransfersFromMultiversXToEthIfTransactionsAppearIn return expectedStatuses, true } ethereumChainMock.BalanceAtCalled = func(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { - return big.NewInt(260000000), nil + return relayerEthBalance, nil } multiversXChainMock := mock.NewMultiversXChainMock() for i := 0; i < len(deposits); i++ { diff --git a/integrationTests/relayers/slowTests/common.go b/integrationTests/relayers/slowTests/common.go index 157f3c50..0746134d 100644 --- a/integrationTests/relayers/slowTests/common.go +++ b/integrationTests/relayers/slowTests/common.go @@ -31,8 +31,9 @@ func GenerateTestUSDCToken() framework.TestTokenParams { ValueToMintOnMvx: "10000000000", IsMintBurnOnMvX: true, IsNativeOnMvX: false, - EthTokenName: "ETHTOKEN", - EthTokenSymbol: "ETHT", + HasChainSpecificToken: true, + EthTokenName: "EthUSDC", + EthTokenSymbol: "USDC", ValueToMintOnEth: "10000000000", IsMintBurnOnEth: false, IsNativeOnEth: true, @@ -72,8 +73,9 @@ func GenerateTestMEMEToken() framework.TestTokenParams { ValueToMintOnMvx: "10000000000", IsMintBurnOnMvX: false, IsNativeOnMvX: true, - EthTokenName: "ETHMEME", - EthTokenSymbol: "ETHM", + HasChainSpecificToken: true, + EthTokenName: "EthMEME", + EthTokenSymbol: "MEME", ValueToMintOnEth: "10000000000", IsMintBurnOnEth: true, IsNativeOnEth: false, @@ -98,6 +100,90 @@ func GenerateTestMEMEToken() framework.TestTokenParams { } } +// GenerateTestEUROCToken will generate a test EUROC token +func GenerateTestEUROCToken() framework.TestTokenParams { + //EUROC is ethNative = true, ethMintBurn = true, mvxNative = false, mvxMintBurn = true + return framework.TestTokenParams{ + IssueTokenParams: framework.IssueTokenParams{ + AbstractTokenIdentifier: "EUROC", + NumOfDecimalsUniversal: 6, + NumOfDecimalsChainSpecific: 6, + MvxUniversalTokenTicker: "EUROC", + MvxChainSpecificTokenTicker: "EUROC", + MvxUniversalTokenDisplayName: "TestEUROC", + MvxChainSpecificTokenDisplayName: "TestEUROC", + ValueToMintOnMvx: "10000000000", + IsMintBurnOnMvX: true, + IsNativeOnMvX: false, + HasChainSpecificToken: false, + EthTokenName: "EthEuroC", + EthTokenSymbol: "EUROC", + ValueToMintOnEth: "10000000000", + IsMintBurnOnEth: true, + IsNativeOnEth: true, + }, + TestOperations: []framework.TokenOperations{ + { + ValueToTransferToMvx: big.NewInt(5010), + ValueToSendFromMvX: big.NewInt(2510), + }, + { + ValueToTransferToMvx: big.NewInt(7010), + ValueToSendFromMvX: big.NewInt(310), + }, + { + ValueToTransferToMvx: big.NewInt(1010), + ValueToSendFromMvX: nil, + MvxSCCallData: createScCallData("callPayable", 50000000), + }, + }, + ESDTSafeExtraBalance: big.NewInt(100), // extra is just for the fees for the 2 transfers mvx->eth + EthTestAddrExtraBalance: big.NewInt(-5010 + 2510 - 50 - 7010 + 310 - 50 - 1010), // -(eth->mvx) + (mvx->eth) - fees + } +} + +// GenerateTestMEXToken will generate a test EUROC token +func GenerateTestMEXToken() framework.TestTokenParams { + //MEX is ethNative = false, ethMintBurn = true, mvxNative = true, mvxMintBurn = true + return framework.TestTokenParams{ + IssueTokenParams: framework.IssueTokenParams{ + AbstractTokenIdentifier: "MEX", + NumOfDecimalsUniversal: 2, + NumOfDecimalsChainSpecific: 2, + MvxUniversalTokenTicker: "MEX", + MvxChainSpecificTokenTicker: "MEX", + MvxUniversalTokenDisplayName: "TestMEX", + MvxChainSpecificTokenDisplayName: "TestMEX", + ValueToMintOnMvx: "10000000000", + IsMintBurnOnMvX: true, + IsNativeOnMvX: true, + HasChainSpecificToken: false, + EthTokenName: "EthMex", + EthTokenSymbol: "MEX", + ValueToMintOnEth: "10000000000", + IsMintBurnOnEth: true, + IsNativeOnEth: false, + }, + TestOperations: []framework.TokenOperations{ + { + ValueToTransferToMvx: big.NewInt(2410), + ValueToSendFromMvX: big.NewInt(4010), + }, + { + ValueToTransferToMvx: big.NewInt(210), + ValueToSendFromMvX: big.NewInt(6010), + }, + { + ValueToTransferToMvx: big.NewInt(1010), + ValueToSendFromMvX: big.NewInt(2010), + MvxSCCallData: createScCallData("callPayable", 50000000), + }, + }, + ESDTSafeExtraBalance: big.NewInt(150), // just the fees should be collected in ESDT safe + EthTestAddrExtraBalance: big.NewInt(4010 - 50 + 6010 - 50 + 2010 - 50), + } +} + func createScCallData(function string, gasLimit uint64, args ...string) []byte { codec := testsCommon.TestMultiversXCodec{} callData := parsers.CallData{ diff --git a/integrationTests/relayers/slowTests/ethToMultiversXWithChainSimulator_test.go b/integrationTests/relayers/slowTests/ethToMultiversXWithChainSimulator_test.go index 21d90bf5..6f4a00a1 100644 --- a/integrationTests/relayers/slowTests/ethToMultiversXWithChainSimulator_test.go +++ b/integrationTests/relayers/slowTests/ethToMultiversXWithChainSimulator_test.go @@ -39,6 +39,15 @@ func TestRelayersShouldExecuteTransfers(t *testing.T) { ) } +func TestRelayersShouldExecuteTransfersWithMintBurnTokens(t *testing.T) { + _ = testRelayersWithChainSimulatorAndTokens( + t, + make(chan error), + GenerateTestEUROCToken(), + GenerateTestMEXToken(), + ) +} + func TestRelayersShouldExecuteTransfersWithSCCallsWithArguments(t *testing.T) { dummyAddress := strings.Repeat("2", 32) dummyUint64 := string([]byte{37}) @@ -58,7 +67,39 @@ func TestRelayersShouldExecuteTransfersWithSCCallsWithArguments(t *testing.T) { memeToken, ) - testCallPayableWithParamsWasCalled(testSetup, 37, usdcToken.AbstractTokenIdentifier, memeToken.AbstractTokenIdentifier) + testCallPayableWithParamsWasCalled( + testSetup, + 37, + usdcToken.AbstractTokenIdentifier, + memeToken.AbstractTokenIdentifier, + ) +} + +func TestRelayersShouldExecuteTransfersWithSCCallsWithArgumentsWithMintBurnTokens(t *testing.T) { + dummyAddress := strings.Repeat("2", 32) + dummyUint64 := string([]byte{37}) + + callData := createScCallData("callPayableWithParams", 50000000, dummyUint64, dummyAddress) + + eurocToken := GenerateTestEUROCToken() + eurocToken.TestOperations[2].MvxSCCallData = callData + + mexToken := GenerateTestMEXToken() + mexToken.TestOperations[2].MvxSCCallData = callData + + testSetup := testRelayersWithChainSimulatorAndTokens( + t, + make(chan error), + eurocToken, + mexToken, + ) + + testCallPayableWithParamsWasCalled( + testSetup, + 37, + eurocToken.AbstractTokenIdentifier, + mexToken.AbstractTokenIdentifier, + ) } func TestRelayerShouldExecuteTransfersAndNotCatchErrors(t *testing.T) { @@ -258,6 +299,7 @@ func TestRelayersShouldNotExecuteTransfers(t *testing.T) { badToken.IsMintBurnOnEth = false badToken.IsNativeOnMvX = true badToken.IsMintBurnOnMvX = false + badToken.HasChainSpecificToken = true expectedStringInLogs := "error = invalid setup isNativeOnEthereum = true, isNativeOnMultiversX = true" testRelayersShouldNotExecuteTransfers(t, expectedStringInLogs, badToken) @@ -268,6 +310,7 @@ func TestRelayersShouldNotExecuteTransfers(t *testing.T) { badToken.IsMintBurnOnEth = false badToken.IsNativeOnMvX = true badToken.IsMintBurnOnMvX = true + badToken.HasChainSpecificToken = false expectedStringInLogs := "error = invalid setup isNativeOnEthereum = true, isNativeOnMultiversX = true" testRelayersShouldNotExecuteTransfers(t, expectedStringInLogs, badToken) @@ -278,6 +321,7 @@ func TestRelayersShouldNotExecuteTransfers(t *testing.T) { badToken.IsMintBurnOnEth = true badToken.IsNativeOnMvX = true badToken.IsMintBurnOnMvX = false + badToken.HasChainSpecificToken = true testEthContractsShouldError(t, badToken) }) @@ -287,6 +331,7 @@ func TestRelayersShouldNotExecuteTransfers(t *testing.T) { badToken.IsMintBurnOnEth = true badToken.IsNativeOnMvX = false badToken.IsMintBurnOnMvX = true + badToken.HasChainSpecificToken = true testEthContractsShouldError(t, badToken) }) @@ -394,6 +439,12 @@ func testCallPayableWithParamsWasCalled(testSetup *framework.TestSetup, value ui return } + universalTokens := make([]string, 0, len(tokens)) + for _, identifier := range tokens { + tkData := testSetup.TokensRegistry.GetTokenData(identifier) + universalTokens = append(universalTokens, tkData.MvxUniversalToken) + } + vmRequest := &data.VmValueRequest{ Address: testSetup.MultiversxHandler.TestCallerAddress.Bech32(), FuncName: "getCalledDataParams", @@ -405,11 +456,20 @@ func testCallPayableWithParamsWasCalled(testSetup *framework.TestSetup, value ui returnedData := vmResponse.Data.ReturnData require.Equal(testSetup, len(tokens), len(returnedData)) - for i, token := range tokens { - buff := returnedData[i] + mapUniversalTokens := make(map[string]int) + for _, tokenIdentifier := range universalTokens { + mapUniversalTokens[tokenIdentifier] = 0 + } + + for _, buff := range returnedData { parsedValue, parsedToken := processCalledDataParams(buff) assert.Equal(testSetup, value, parsedValue) - assert.Contains(testSetup, parsedToken, token) + mapUniversalTokens[parsedToken]++ + } + + assert.Equal(testSetup, len(tokens), len(mapUniversalTokens)) + for _, numTokens := range mapUniversalTokens { + assert.Equal(testSetup, 1, numTokens) } } diff --git a/integrationTests/relayers/slowTests/framework/ethereumHandler.go b/integrationTests/relayers/slowTests/framework/ethereumHandler.go index 6db3c50a..81d7b68a 100644 --- a/integrationTests/relayers/slowTests/framework/ethereumHandler.go +++ b/integrationTests/relayers/slowTests/framework/ethereumHandler.go @@ -339,6 +339,13 @@ func (handler *EthereumHandler) deployTestERC20Contract(ctx context.Context, par require.NoError(handler, err) require.Equal(handler, mintAmount.String(), balance.String()) + if params.IsNativeOnEth { + tx, err = ethMintBurnContract.Mint(auth, handler.TestKeys.EthAddress, mintAmount) + require.NoError(handler, err) + handler.SimulatedChain.Commit() + handler.checkEthTxResult(ctx, tx.Hash()) + } + return ethMintBurnAddress, ethMintBurnContract } diff --git a/integrationTests/relayers/slowTests/framework/multiversxHandler.go b/integrationTests/relayers/slowTests/framework/multiversxHandler.go index 93010ed4..225abfe5 100644 --- a/integrationTests/relayers/slowTests/framework/multiversxHandler.go +++ b/integrationTests/relayers/slowTests/framework/multiversxHandler.go @@ -66,8 +66,7 @@ const ( esdtSafeSetMaxBridgedAmountForTokenFunction = "esdtSafeSetMaxBridgedAmountForToken" multiTransferEsdtSetMaxBridgedAmountForTokenFunction = "multiTransferEsdtSetMaxBridgedAmountForToken" submitBatchFunction = "submitBatch" - createTransactionFunction = "createTransaction" - unwrapTokenFunction = "unwrapToken" + unwrapTokenCreateTransactionFunction = "unwrapTokenCreateTransaction" setBridgedTokensWrapperAddressFunction = "setBridgedTokensWrapperAddress" setMultiTransferAddressFunction = "setMultiTransferAddress" withdrawRefundFeesForEthereumFunction = "withdrawRefundFeesForEthereum" @@ -90,13 +89,14 @@ type MultiversxHandler struct { TokensRegistry TokensRegistry ChainSimulator ChainSimulatorWrapper - AggregatorAddress *MvxAddress - WrapperAddress *MvxAddress - SafeAddress *MvxAddress - MultisigAddress *MvxAddress - MultiTransferAddress *MvxAddress - ScProxyAddress *MvxAddress - TestCallerAddress *MvxAddress + AggregatorAddress *MvxAddress + WrapperAddress *MvxAddress + SafeAddress *MvxAddress + MultisigAddress *MvxAddress + MultiTransferAddress *MvxAddress + ScProxyAddress *MvxAddress + TestCallerAddress *MvxAddress + ESDTSystemContractAddress *MvxAddress } // NewMultiversxHandler will create the handler that will adapt all test operations on MultiversX @@ -116,6 +116,8 @@ func NewMultiversxHandler( Quorum: quorum, } + handler.ESDTSystemContractAddress = NewMvxAddressFromBech32(handler, esdtSystemSCAddress) + handler.ChainSimulator.GenerateBlocksUntilEpochReached(ctx, 1) handler.ChainSimulator.FundWallets(ctx, handler.WalletsToFundOnMultiversX()) @@ -550,23 +552,63 @@ func (handler *MultiversxHandler) stakeAddressesOnContract(ctx context.Context, // IssueAndWhitelistToken will issue and whitelist the token on MultiversX func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, params IssueTokenParams) { + if params.HasChainSpecificToken { + handler.issueAndWhitelistTokensWithChainSpecific(ctx, params) + } else { + handler.issueAndWhitelistTokens(ctx, params) + } +} + +func (handler *MultiversxHandler) issueAndWhitelistTokensWithChainSpecific(ctx context.Context, params IssueTokenParams) { + handler.issueUniversalToken(ctx, params) + handler.issueChainSpecificToken(ctx, params) + handler.setLocalRolesForUniversalTokenOnWrapper(ctx, params) + handler.transferChainSpecificTokenToSCs(ctx, params) + handler.addUniversalTokenToWrapper(ctx, params) + handler.whitelistTokenOnWrapper(ctx, params) + handler.setRolesForSpecificTokenOnSafe(ctx, params) + handler.addMappingInMultisig(ctx, params) + handler.whitelistTokenOnMultisig(ctx, params) + handler.setInitialSupply(ctx, params) + handler.setPairDecimalsOnAggregator(ctx, params) + handler.setMaxBridgeAmountOnSafe(ctx, params) + handler.setMaxBridgeAmountOnMultitransfer(ctx, params) +} + +func (handler *MultiversxHandler) issueAndWhitelistTokens(ctx context.Context, params IssueTokenParams) { + handler.issueUniversalToken(ctx, params) + + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) + handler.TokensRegistry.RegisterChainSpecificToken(params.AbstractTokenIdentifier, tkData.MvxUniversalToken) + + handler.setRolesForSpecificTokenOnSafe(ctx, params) + handler.addMappingInMultisig(ctx, params) + handler.whitelistTokenOnMultisig(ctx, params) + handler.setInitialSupply(ctx, params) + handler.setPairDecimalsOnAggregator(ctx, params) + handler.setMaxBridgeAmountOnSafe(ctx, params) + handler.setMaxBridgeAmountOnMultitransfer(ctx, params) +} + +func (handler *MultiversxHandler) issueUniversalToken(ctx context.Context, params IssueTokenParams) { token := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) require.NotNil(handler, token) - esdtAddress := NewMvxAddressFromBech32(handler, esdtSystemSCAddress) + valueToMintInt, ok := big.NewInt(0).SetString(params.ValueToMintOnMvx, 10) + require.True(handler, ok) // issue universal token hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, - esdtAddress, + handler.ESDTSystemContractAddress, esdtIssueCost, issueTokenGasLimit, issueFunction, []string{ hex.EncodeToString([]byte(params.MvxUniversalTokenDisplayName)), hex.EncodeToString([]byte(params.MvxUniversalTokenTicker)), - "00", + hex.EncodeToString(valueToMintInt.Bytes()), fmt.Sprintf("%02x", params.NumOfDecimalsUniversal), hex.EncodeToString([]byte(canAddSpecialRoles)), hex.EncodeToString([]byte(trueStr))}) @@ -574,15 +616,16 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa require.Greater(handler, len(mvxUniversalToken), 0) handler.TokensRegistry.RegisterUniversalToken(params.AbstractTokenIdentifier, mvxUniversalToken) log.Info("issue universal token tx executed", "hash", hash, "status", txResult.Status, "token", mvxUniversalToken, "owner", handler.OwnerKeys.MvxAddress) +} - // issue chain specific token +func (handler *MultiversxHandler) issueChainSpecificToken(ctx context.Context, params IssueTokenParams) { valueToMintInt, ok := big.NewInt(0).SetString(params.ValueToMintOnMvx, 10) require.True(handler, ok) - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, - esdtAddress, + handler.ESDTSystemContractAddress, esdtIssueCost, issueTokenGasLimit, issueFunction, @@ -597,25 +640,36 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa require.Greater(handler, len(mvxChainSpecificToken), 0) handler.TokensRegistry.RegisterChainSpecificToken(params.AbstractTokenIdentifier, mvxChainSpecificToken) log.Info("issue chain specific token tx executed", "hash", hash, "status", txResult.Status, "token", mvxChainSpecificToken, "owner", handler.OwnerKeys.MvxAddress) +} + +func (handler *MultiversxHandler) setLocalRolesForUniversalTokenOnWrapper(ctx context.Context, params IssueTokenParams) { + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) // set local roles bridged tokens wrapper - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, - esdtAddress, + handler.ESDTSystemContractAddress, zeroStringValue, setCallsGasLimit, setSpecialRoleFunction, []string{ - hex.EncodeToString([]byte(mvxUniversalToken)), + hex.EncodeToString([]byte(tkData.MvxUniversalToken)), handler.WrapperAddress.Hex(), hex.EncodeToString([]byte(esdtRoleLocalMint)), hex.EncodeToString([]byte(esdtRoleLocalBurn))}) log.Info("set local roles bridged tokens wrapper tx executed", "hash", hash, "status", txResult.Status) +} + +func (handler *MultiversxHandler) transferChainSpecificTokenToSCs(ctx context.Context, params IssueTokenParams) { + valueToMintInt, ok := big.NewInt(0).SetString(params.ValueToMintOnMvx, 10) + require.True(handler, ok) + + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) // transfer to wrapper sc initialMintValue := valueToMintInt.Div(valueToMintInt, big.NewInt(3)) - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, handler.WrapperAddress, @@ -623,7 +677,7 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa setCallsGasLimit, esdtTransferFunction, []string{ - hex.EncodeToString([]byte(mvxChainSpecificToken)), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken)), hex.EncodeToString(initialMintValue.Bytes()), hex.EncodeToString([]byte(depositLiquidityFunction))}) log.Info("transfer to wrapper sc tx executed", "hash", hash, "status", txResult.Status) @@ -637,12 +691,16 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa setCallsGasLimit, esdtTransferFunction, []string{ - hex.EncodeToString([]byte(mvxChainSpecificToken)), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken)), hex.EncodeToString(initialMintValue.Bytes())}) log.Info("transfer to safe sc tx executed", "hash", hash, "status", txResult.Status) +} + +func (handler *MultiversxHandler) addUniversalTokenToWrapper(ctx context.Context, params IssueTokenParams) { + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) // add wrapped token - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, handler.WrapperAddress, @@ -650,13 +708,17 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa setCallsGasLimit, addWrappedTokenFunction, []string{ - hex.EncodeToString([]byte(mvxUniversalToken)), + hex.EncodeToString([]byte(tkData.MvxUniversalToken)), fmt.Sprintf("%02x", params.NumOfDecimalsUniversal), }) log.Info("add wrapped token tx executed", "hash", hash, "status", txResult.Status) +} + +func (handler *MultiversxHandler) whitelistTokenOnWrapper(ctx context.Context, params IssueTokenParams) { + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) // wrapper whitelist token - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, handler.WrapperAddress, @@ -664,28 +726,36 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa setCallsGasLimit, whitelistTokenFunction, []string{ - hex.EncodeToString([]byte(mvxChainSpecificToken)), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken)), fmt.Sprintf("%02x", params.NumOfDecimalsChainSpecific), - hex.EncodeToString([]byte(mvxUniversalToken))}) + hex.EncodeToString([]byte(tkData.MvxUniversalToken))}) log.Info("wrapper whitelist token tx executed", "hash", hash, "status", txResult.Status) +} + +func (handler *MultiversxHandler) setRolesForSpecificTokenOnSafe(ctx context.Context, params IssueTokenParams) { + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) // set local roles esdt safe - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, - esdtAddress, + handler.ESDTSystemContractAddress, zeroStringValue, setCallsGasLimit, setSpecialRoleFunction, []string{ - hex.EncodeToString([]byte(mvxChainSpecificToken)), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken)), handler.SafeAddress.Hex(), hex.EncodeToString([]byte(esdtRoleLocalMint)), hex.EncodeToString([]byte(esdtRoleLocalBurn))}) log.Info("set local roles esdt safe tx executed", "hash", hash, "status", txResult.Status) +} + +func (handler *MultiversxHandler) addMappingInMultisig(ctx context.Context, params IssueTokenParams) { + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) // add mapping - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, handler.MultisigAddress, @@ -693,12 +763,16 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa setCallsGasLimit, addMappingFunction, []string{ - hex.EncodeToString(token.EthErc20Address.Bytes()), - hex.EncodeToString([]byte(mvxChainSpecificToken))}) + hex.EncodeToString(tkData.EthErc20Address.Bytes()), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken))}) log.Info("add mapping tx executed", "hash", hash, "status", txResult.Status) +} + +func (handler *MultiversxHandler) whitelistTokenOnMultisig(ctx context.Context, params IssueTokenParams) { + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) // whitelist token - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, handler.MultisigAddress, @@ -706,7 +780,7 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa setCallsGasLimit, esdtSafeAddTokenToWhitelistFunction, []string{ - hex.EncodeToString([]byte(mvxChainSpecificToken)), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken)), hex.EncodeToString([]byte(params.MvxChainSpecificTokenTicker)), getHexBool(params.IsMintBurnOnMvX), getHexBool(params.IsNativeOnMvX), @@ -715,6 +789,10 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa hex.EncodeToString(zeroValueBigInt.Bytes()), // burn_balance }) log.Info("whitelist token tx executed", "hash", hash, "status", txResult.Status) +} + +func (handler *MultiversxHandler) setInitialSupply(ctx context.Context, params IssueTokenParams) { + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) // set initial supply if len(params.InitialSupplyValue) > 0 { @@ -722,7 +800,7 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa require.True(handler, okConvert) if params.IsMintBurnOnMvX { - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, handler.MultisigAddress, @@ -730,7 +808,7 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa setCallsGasLimit, initSupplyMintBurnEsdtSafe, []string{ - hex.EncodeToString([]byte(mvxChainSpecificToken)), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken)), hex.EncodeToString(initialSupply.Bytes()), hex.EncodeToString([]byte{0}), }, @@ -738,7 +816,7 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa log.Info("initial supply tx executed", "hash", hash, "status", txResult.Status, "initial mint", params.InitialSupplyValue, "initial burned", "0") } else { - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, handler.MultisigAddress, @@ -746,10 +824,10 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa setCallsGasLimit, esdtTransferFunction, []string{ - hex.EncodeToString([]byte(mvxChainSpecificToken)), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken)), hex.EncodeToString(initialSupply.Bytes()), hex.EncodeToString([]byte(initSupplyEsdtSafe)), - hex.EncodeToString([]byte(mvxChainSpecificToken)), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken)), hex.EncodeToString(initialSupply.Bytes()), }) @@ -757,9 +835,11 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa "initial value", params.InitialSupplyValue) } } +} +func (handler *MultiversxHandler) setPairDecimalsOnAggregator(ctx context.Context, params IssueTokenParams) { // setPairDecimals on aggregator - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, handler.AggregatorAddress, @@ -771,10 +851,14 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa hex.EncodeToString([]byte(params.MvxChainSpecificTokenTicker)), fmt.Sprintf("%02x", params.NumOfDecimalsChainSpecific)}) log.Info("setPairDecimals tx executed", "hash", hash, "status", txResult.Status) +} + +func (handler *MultiversxHandler) setMaxBridgeAmountOnSafe(ctx context.Context, params IssueTokenParams) { + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) // safe set max bridge amount for token maxBridgedAmountForTokenInt, _ := big.NewInt(0).SetString(maxBridgedAmountForToken, 10) - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, handler.MultisigAddress, @@ -782,12 +866,17 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa setCallsGasLimit, esdtSafeSetMaxBridgedAmountForTokenFunction, []string{ - hex.EncodeToString([]byte(mvxChainSpecificToken)), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken)), hex.EncodeToString(maxBridgedAmountForTokenInt.Bytes())}) log.Info("safe set max bridge amount for token tx executed", "hash", hash, "status", txResult.Status) +} + +func (handler *MultiversxHandler) setMaxBridgeAmountOnMultitransfer(ctx context.Context, params IssueTokenParams) { + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) // multi-transfer set max bridge amount for token - hash, txResult = handler.ChainSimulator.ScCall( + maxBridgedAmountForTokenInt, _ := big.NewInt(0).SetString(maxBridgedAmountForToken, 10) + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.OwnerKeys.MvxSk, handler.MultisigAddress, @@ -795,7 +884,7 @@ func (handler *MultiversxHandler) IssueAndWhitelistToken(ctx context.Context, pa setCallsGasLimit, multiTransferEsdtSetMaxBridgedAmountForTokenFunction, []string{ - hex.EncodeToString([]byte(mvxChainSpecificToken)), + hex.EncodeToString([]byte(tkData.MvxChainSpecificToken)), hex.EncodeToString(maxBridgedAmountForTokenInt.Bytes())}) log.Info("multi-transfer set max bridge amount for token tx executed", "hash", hash, "status", txResult.Status) } @@ -852,97 +941,28 @@ func (handler *MultiversxHandler) submitAggregatorBatchForKey(ctx context.Contex return hash } -// CreateDepositsOnMultiversxForToken will send the deposit transactions on MultiversX returning how many tokens should be minted on Ethereum -func (handler *MultiversxHandler) CreateDepositsOnMultiversxForToken( - ctx context.Context, - params TestTokenParams, -) *big.Int { - token := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) - require.NotNil(handler, token) - - valueToMintOnEthereum := big.NewInt(0) - for _, operation := range params.TestOperations { - if operation.ValueToSendFromMvX == nil { - continue - } - - valueToMintOnEthereum.Add(valueToMintOnEthereum, operation.ValueToSendFromMvX) - - // transfer to sender tx - hash, txResult := handler.ChainSimulator.ScCall( - ctx, - handler.OwnerKeys.MvxSk, - handler.TestKeys.MvxAddress, - zeroStringValue, - createDepositGasLimit, - esdtTransferFunction, - []string{ - hex.EncodeToString([]byte(token.MvxChainSpecificToken)), - hex.EncodeToString(operation.ValueToSendFromMvX.Bytes())}) - log.Info("transfer to sender tx executed", "hash", hash, "status", txResult.Status) - - // send tx to safe contract - scCallParams := []string{ - hex.EncodeToString([]byte(token.MvxChainSpecificToken)), - hex.EncodeToString(operation.ValueToSendFromMvX.Bytes()), - hex.EncodeToString([]byte(createTransactionFunction)), - hex.EncodeToString(handler.TestKeys.EthAddress.Bytes()), - } - dataField := strings.Join(scCallParams, "@") - - hash, txResult = handler.ChainSimulator.ScCall( - ctx, - handler.TestKeys.MvxSk, - handler.SafeAddress, - zeroStringValue, - createDepositGasLimit+gasLimitPerDataByte*uint64(len(dataField)), - esdtTransferFunction, - scCallParams) - log.Info("MultiversX->Ethereum transaction sent", "hash", hash, "status", txResult.Status) - } - - return valueToMintOnEthereum -} - // SendDepositTransactionFromMultiversx will send the deposit transaction from MultiversX func (handler *MultiversxHandler) SendDepositTransactionFromMultiversx(ctx context.Context, token *TokenData, value *big.Int) { - // unwrap token - paramsUnwrap := []string{ + // create transaction params + params := []string{ hex.EncodeToString([]byte(token.MvxUniversalToken)), hex.EncodeToString(value.Bytes()), - hex.EncodeToString([]byte(unwrapTokenFunction)), + hex.EncodeToString([]byte(unwrapTokenCreateTransactionFunction)), hex.EncodeToString([]byte(token.MvxChainSpecificToken)), - } - - hash, txResult := handler.ChainSimulator.ScCall( - ctx, - handler.TestKeys.MvxSk, - handler.WrapperAddress, - zeroStringValue, - createDepositGasLimit, - esdtTransferFunction, - paramsUnwrap, - ) - log.Info("unwrap transaction sent", "hash", hash, "token", token.MvxUniversalToken, "status", txResult.Status) - - // send tx to safe contract - params := []string{ - hex.EncodeToString([]byte(token.MvxChainSpecificToken)), - hex.EncodeToString(value.Bytes()), - hex.EncodeToString([]byte(createTransactionFunction)), hex.EncodeToString(handler.TestKeys.EthAddress.Bytes()), } dataField := strings.Join(params, "@") - hash, txResult = handler.ChainSimulator.ScCall( + hash, txResult := handler.ChainSimulator.ScCall( ctx, handler.TestKeys.MvxSk, - handler.SafeAddress, + handler.WrapperAddress, zeroStringValue, createDepositGasLimit+gasLimitPerDataByte*uint64(len(dataField)), esdtTransferFunction, - params) - log.Info("MultiversX->Ethereum transaction sent", "hash", hash, "status", txResult.Status) + params, + ) + log.Info("MultiversX->Ethereum transaction sent", "hash", hash, "token", token.MvxUniversalToken, "status", txResult.Status) } // TestWithdrawFees will try to withdraw the fees for the provided token from the safe contract to the owner @@ -999,6 +1019,30 @@ func (handler *MultiversxHandler) withdrawFees(ctx context.Context, withdrawFunction, initialBalanceStr, finalBalanceStr, expectedDelta.String())) } +// TransferToken is able to create an ESDT transfer +func (handler *MultiversxHandler) TransferToken(ctx context.Context, source KeysHolder, receiver KeysHolder, amount *big.Int, params TestTokenParams) { + tkData := handler.TokensRegistry.GetTokenData(params.AbstractTokenIdentifier) + + // transfer to the test key, so it will have funds to carry on with the deposits + hash, txResult := handler.ChainSimulator.ScCall( + ctx, + source.MvxSk, + receiver.MvxAddress, + zeroStringValue, + createDepositGasLimit, + esdtTransferFunction, + []string{ + hex.EncodeToString([]byte(tkData.MvxUniversalToken)), + hex.EncodeToString(amount.Bytes())}) + + log.Info("transfer to tx executed", + "source address", source.MvxAddress.Bech32(), + "receiver", receiver.MvxAddress.Bech32(), + "token", tkData.MvxUniversalToken, + "amount", amount.String(), + "hash", hash, "status", txResult.Status) +} + func getHexBool(input bool) string { if input { return hexTrue diff --git a/integrationTests/relayers/slowTests/framework/testSetup.go b/integrationTests/relayers/slowTests/framework/testSetup.go index d35232a9..83ec55b0 100644 --- a/integrationTests/relayers/slowTests/framework/testSetup.go +++ b/integrationTests/relayers/slowTests/framework/testSetup.go @@ -304,29 +304,52 @@ func (setup *TestSetup) createBatchOnMultiversXForToken(params TestTokenParams) token := setup.GetTokenData(params.AbstractTokenIdentifier) require.NotNil(setup, token) - valueToMintOnEthereum := setup.MultiversxHandler.CreateDepositsOnMultiversxForToken(setup.Ctx, params) - + setup.transferTokensToTestKey(params) + valueToMintOnEthereum := setup.sendFromMultiversxToEthereumForToken(params) setup.EthereumHandler.Mint(setup.Ctx, params, valueToMintOnEthereum) } +func (setup *TestSetup) transferTokensToTestKey(params TestTokenParams) { + depositValue := big.NewInt(0) + for _, operation := range params.TestOperations { + if operation.ValueToSendFromMvX == nil { + continue + } + + depositValue.Add(depositValue, operation.ValueToSendFromMvX) + } + + setup.MultiversxHandler.TransferToken( + setup.Ctx, + setup.OwnerKeys, + setup.TestKeys, + depositValue, + params, + ) +} + // SendFromMultiversxToEthereum will create the deposits that will be gathered in a batch on MultiversX (without mint on Ethereum) func (setup *TestSetup) SendFromMultiversxToEthereum(tokensParams ...TestTokenParams) { for _, params := range tokensParams { - setup.sendFromMultiversxToEthereumForToken(params) + _ = setup.sendFromMultiversxToEthereumForToken(params) } } -func (setup *TestSetup) sendFromMultiversxToEthereumForToken(params TestTokenParams) { +func (setup *TestSetup) sendFromMultiversxToEthereumForToken(params TestTokenParams) *big.Int { token := setup.GetTokenData(params.AbstractTokenIdentifier) require.NotNil(setup, token) + depositValue := big.NewInt(0) for _, operation := range params.TestOperations { if operation.ValueToSendFromMvX == nil { continue } + depositValue.Add(depositValue, operation.ValueToSendFromMvX) setup.MultiversxHandler.SendDepositTransactionFromMultiversx(setup.Ctx, token, operation.ValueToSendFromMvX) } + + return depositValue } // TestWithdrawTotalFeesOnEthereumForTokens will test the withdrawal functionality for the provided test tokens diff --git a/integrationTests/relayers/slowTests/framework/types.go b/integrationTests/relayers/slowTests/framework/types.go index 9a01cb82..dc165fe4 100644 --- a/integrationTests/relayers/slowTests/framework/types.go +++ b/integrationTests/relayers/slowTests/framework/types.go @@ -21,6 +21,7 @@ type IssueTokenParams struct { ValueToMintOnMvx string IsMintBurnOnMvX bool IsNativeOnMvX bool + HasChainSpecificToken bool // Ethereum EthTokenName string diff --git a/integrationTests/relayers/slowTests/refundWithChainSimulator_test.go b/integrationTests/relayers/slowTests/refundWithChainSimulator_test.go index a90c2ad9..0a5d8b27 100644 --- a/integrationTests/relayers/slowTests/refundWithChainSimulator_test.go +++ b/integrationTests/relayers/slowTests/refundWithChainSimulator_test.go @@ -35,6 +35,18 @@ func TestRelayersShouldExecuteTransfersWithRefund(t *testing.T) { memeToken, ) }) + t.Run("unknown marker and malformed SC call data should refund with MEX", func(t *testing.T) { + callData := []byte{5, 4, 55} + mexToken := GenerateTestMEXToken() + mexToken.TestOperations[2].MvxSCCallData = callData + mexToken.TestOperations[2].MvxFaultySCCall = true + + testRelayersWithChainSimulatorAndTokensAndRefund( + t, + make(chan error), + mexToken, + ) + }) t.Run("malformed SC call data should refund", func(t *testing.T) { callData := []byte{bridgeCore.DataPresentProtocolMarker, 4, 55} usdcToken := GenerateTestUSDCToken() diff --git a/integrationTests/relayers/slowTests/testdata/contracts/mvx/bridge-proxy.wasm b/integrationTests/relayers/slowTests/testdata/contracts/mvx/bridge-proxy.wasm index e39b6e01..c32618c4 100755 Binary files a/integrationTests/relayers/slowTests/testdata/contracts/mvx/bridge-proxy.wasm and b/integrationTests/relayers/slowTests/testdata/contracts/mvx/bridge-proxy.wasm differ diff --git a/integrationTests/relayers/slowTests/testdata/contracts/mvx/bridged-tokens-wrapper.wasm b/integrationTests/relayers/slowTests/testdata/contracts/mvx/bridged-tokens-wrapper.wasm index 16599312..b261b427 100755 Binary files a/integrationTests/relayers/slowTests/testdata/contracts/mvx/bridged-tokens-wrapper.wasm and b/integrationTests/relayers/slowTests/testdata/contracts/mvx/bridged-tokens-wrapper.wasm differ diff --git a/integrationTests/relayers/slowTests/testdata/contracts/mvx/esdt-safe.wasm b/integrationTests/relayers/slowTests/testdata/contracts/mvx/esdt-safe.wasm index dd7f90f3..2217c142 100755 Binary files a/integrationTests/relayers/slowTests/testdata/contracts/mvx/esdt-safe.wasm and b/integrationTests/relayers/slowTests/testdata/contracts/mvx/esdt-safe.wasm differ diff --git a/integrationTests/relayers/slowTests/testdata/contracts/mvx/multi-transfer-esdt.wasm b/integrationTests/relayers/slowTests/testdata/contracts/mvx/multi-transfer-esdt.wasm index 15a73562..d6de789b 100755 Binary files a/integrationTests/relayers/slowTests/testdata/contracts/mvx/multi-transfer-esdt.wasm and b/integrationTests/relayers/slowTests/testdata/contracts/mvx/multi-transfer-esdt.wasm differ diff --git a/integrationTests/relayers/slowTests/testdata/contracts/mvx/multisig.wasm b/integrationTests/relayers/slowTests/testdata/contracts/mvx/multisig.wasm index ddc0cd82..1d41892e 100755 Binary files a/integrationTests/relayers/slowTests/testdata/contracts/mvx/multisig.wasm and b/integrationTests/relayers/slowTests/testdata/contracts/mvx/multisig.wasm differ