diff --git a/Makefile b/Makefile index c04991ac..fd63277a 100644 --- a/Makefile +++ b/Makefile @@ -350,6 +350,9 @@ e2e-test-eibc-client-lower-fee-evm: clean-e2e e2e-test-eibc-client-fulfill-order-got-polled-evm: clean-e2e cd tests && go test -timeout=30m -race -v -run Test_EIBC_Client_Got_Polled_EVM . +e2e-test-eibc-client-both-ra-evm: clean-e2e + cd tests && go test -timeout=30m -race -v -run Test_EIBC_Client_BothRA_EVM . + # Executes IBC tests via rollup-e2e-testing e2e-test-ibc-success-wasm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestIBCTransferSuccess_Wasm . diff --git a/tests/eibc_client_test.go b/tests/eibc_client_test.go index 338b9df0..120ac5c9 100644 --- a/tests/eibc_client_test.go +++ b/tests/eibc_client_test.go @@ -1044,3 +1044,402 @@ func Test_EIBC_Client_Lower_Fee_EVM(t *testing.T) { // Run invariant check CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } + +func Test_EIBC_Client_BothRA_EVM(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + configFileOverrides := make(map[string]any) + dymintTomlOverrides := make(testutil.Toml) + dymintTomlOverrides["settlement_layer"] = "dymension" + dymintTomlOverrides["settlement_node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides["rollapp_id"] = "rollappevm_1234-1" + dymintTomlOverrides["settlement_gas_prices"] = "0adym" + dymintTomlOverrides["max_idle_time"] = "3s" + dymintTomlOverrides["max_proof_time"] = "500ms" + dymintTomlOverrides["batch_submit_time"] = "50s" + dymintTomlOverrides["p2p_blocksync_enabled"] = "false" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + // setup config for rollapp 2 + configFileOverrides2 := make(map[string]any) + dymintTomlOverrides2 := make(testutil.Toml) + dymintTomlOverrides2["settlement_layer"] = "dymension" + dymintTomlOverrides2["settlement_node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides2["rollapp_id"] = "decentrio_12345-1" + dymintTomlOverrides2["settlement_gas_prices"] = "0adym" + dymintTomlOverrides2["max_idle_time"] = "3s" + dymintTomlOverrides2["max_proof_time"] = "500ms" + dymintTomlOverrides2["batch_submit_time"] = "50s" + dymintTomlOverrides2["p2p_blocksync_enabled"] = "false" + + configFileOverrides2["config/dymint.toml"] = dymintTomlOverrides2 + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 0 + numRollAppVals := 1 + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappevm_1234-1", + Images: []ibc.DockerImage{rollappEVMImage}, + Bin: "rollappd", + Bech32Prefix: "ethm", + Denom: "urax", + CoinType: "60", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappEVMGenesis(rollappEVMGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "rollapp2", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "decentrio_12345-1", + Images: []ibc.DockerImage{rollappEVMImage}, + Bin: "rollappd", + Bech32Prefix: "ethm", + Denom: "urax", + CoinType: "60", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappEVMGenesis(rollappEVMGenesisKV), + ConfigFileOverrides: configFileOverrides2, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: ibc.ChainConfig{ + Type: "hub-dym", + Name: "dymension", + ChainID: "dymension_100-1", + Images: []ibc.DockerImage{dymensionImage}, + Bin: "dymd", + Bech32Prefix: "dym", + Denom: "adym", + CoinType: "60", + GasPrices: "0.0adym", + EncodingConfig: encodingConfig(), + GasAdjustment: 1.1, + TrustingPeriod: "112h", + NoHostMount: false, + ModifyGenesis: modifyDymensionGenesis(dymensionGenesisKV), + ConfigFileOverrides: nil, + SidecarConfigs: []ibc.SidecarConfig{ + { + ProcessName: "eibc-client", + Image: eibcClientImage, + HomeDir: "/root", + Ports: nil, + StartCmd: []string{"eibc-client", "start", "--config", "/root/.eibc-client/config.yaml"}, + PreStart: true, + ValidatorProcess: false, + }, + }, + }, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + rollapp1 := chains[0].(*dym_rollapp.DymRollApp) + rollapp2 := chains[1].(*dym_rollapp.DymRollApp) + dymension := chains[2].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + r2 := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer2", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1, rollapp2). + AddRelayer(r, "relayer"). + AddRelayer(r2, "relayer2"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp2, + Relayer: r2, + Path: anotherIbcPath, + }) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + + // This can be used to write to the block database which will index all block data e.g. txs, msgs, events, etc. + // BlockDatabaseFile: test.DefaultBlockDatabaseFilepath(), + }, nil, "", nil, false, 780) + require.NoError(t, err) + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + CreateChannel(ctx, t, r2, eRep, dymension.CosmosChain, rollapp2.CosmosChain, anotherIbcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, rollapp1, rollapp2) + + // Get our Bech32 encoded user addresses + dymensionUser, dymensionUser2, rollappUser, rollappUser2 := users[0], users[1], users[2], users[3] + + dymensionUserAddr := dymensionUser.FormattedAddress() + dymensionUserAddr2 := dymensionUser2.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + rollappUserAddr2 := rollappUser2.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + channel2, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp2.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = r2.StartRelayer(ctx, eRep, anotherIbcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Send a normal ibc tx from RA -> Hub + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: bigTransferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.Counterparty.ChannelID, rollappUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + rollappHeight, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + + // wait until the packet is finalized + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + txhash, err := dymension.GetNode().FinalizePacketsUntilHeight(ctx, dymensionUserAddr, rollapp1.GetChainID(), fmt.Sprint(rollappHeight)) + require.NoError(t, err) + + fmt.Println(txhash) + + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp2.Config().Denom, + Amount: bigTransferAmount, + } + + _, err = rollapp2.SendIBCTransfer(ctx, channel2.Counterparty.ChannelID, rollappUserAddr2, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + rollappHeight, err = rollapp2.GetNode().Height(ctx) + require.NoError(t, err) + + // wait until the packet is finalized + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp2.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + txhash, err = dymension.GetNode().FinalizePacketsUntilHeight(ctx, dymensionUserAddr, rollapp2.GetChainID(), fmt.Sprint(rollappHeight)) + require.NoError(t, err) + + fmt.Println(txhash) + + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom for urax on Hub + rollappTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, rollapp1.Config().Denom) + rollappIBCDenom := transfertypes.ParseDenomTrace(rollappTokenDenom).IBCDenom() + + rollappTokenDenom2 := transfertypes.GetPrefixedDenom(channel2.Counterparty.PortID, channel2.Counterparty.ChannelID, rollapp2.Config().Denom) + rollappIBCDenom2 := transfertypes.ParseDenomTrace(rollappTokenDenom2).IBCDenom() + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom2, transferData.Amount.Sub(bigBridgingFee)) + + StartDB(ctx, t, client, network) + + configFile := "data/config.yaml" + content, err := os.ReadFile(configFile) + require.NoError(t, err) + + // Unmarshal the YAML content into the Config struct + var config Config + err = yaml.Unmarshal(content, &config) + require.NoError(t, err) + + dymensionHomeDir := strings.Split(dymension.HomeDir(), "/") + dymensionFolderName := dymensionHomeDir[len(dymensionHomeDir)-1] + + // Modify a field + config.NodeAddress = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + config.DBPath = "mongodb://mongodb-container:27017" + config.Gas.MinimumGasBalance = "100adym" + config.Gas.Fees = "100adym" + config.LogLevel = "debug" + config.HomeDir = "/root/.eibc-client" + config.OrderPolling.Interval = 30 * time.Second + config.OrderPolling.Enabled = false + config.Bots.KeyringBackend = "test" + config.Bots.KeyringDir = "/root/.eibc-client" + config.Bots.NumberOfBots = 3 + config.Bots.MaxOrdersPerTx = 10 + config.Bots.TopUpFactor = 5 + config.Whale.AccountName = dymensionUser.KeyName() + config.Whale.AllowedBalanceThresholds = map[string]string{"adym": "1000", "ibc/278D6FE92E9722572773C899D688907EB9276DEBB40552278B96C17C41C59A11": "1000"} + config.Whale.KeyringBackend = "test" + config.Whale.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.FulfillCriteria.MinFeePercentage.Asset = map[string]float32{"adym": 0.1, rollappIBCDenom: 0.1, rollappIBCDenom2: 0.1} + config.FulfillCriteria.MinFeePercentage.Chain = map[string]float32{rollapp1.Config().ChainID: 0.1, rollapp2.Config().ChainID: 0.1} + config.SkipRefund = true + + // Marshal the updated struct back to YAML + modifiedContent, err := yaml.Marshal(&config) + require.NoError(t, err) + + err = os.Chmod(configFile, 0777) + require.NoError(t, err) + + // Write the updated content back to the file + err = os.WriteFile(configFile, modifiedContent, 0777) + require.NoError(t, err) + + err = os.Mkdir("/tmp/.eibc-client", 0755) + require.NoError(t, err) + + err = copyFile("data/config.yaml", "/tmp/.eibc-client/config.yaml") + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + err = dymension.Sidecars[0].CreateContainer(ctx) + require.NoError(t, err) + + err = dymension.Sidecars[0].StartContainer(ctx) + require.NoError(t, err) + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Send a ibc tx from RA -> Hub + transferData = ibc.WalletData{ + Address: dymensionUserAddr2, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + multiplier := math.NewInt(10) + + eibcFee := transferAmount.Quo(multiplier) + + // set eIBC specific memo + var options ibc.TransferOptions + options.Memo = BuildEIbcMemo(eibcFee) + + _, err = rollapp1.SendIBCTransfer(ctx, channel.Counterparty.ChannelID, rollappUserAddr, transferData, options) + require.NoError(t, err) + + transferData = ibc.WalletData{ + Address: dymensionUserAddr2, + Denom: rollapp2.Config().Denom, + Amount: transferAmount, + } + + _, err = rollapp2.SendIBCTransfer(ctx, channel2.Counterparty.ChannelID, rollappUserAddr2, transferData, options) + require.NoError(t, err) + + // get eIbc event + eibcEvents, err := getEIbcEventsWithinBlockRange(ctx, dymension, 10, false) + require.NoError(t, err) + for i, eibcEvent := range eibcEvents { + fmt.Println(i, "EIBC Event:", eibcEvent) + } + + rollappHeight, err = rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount).Sub(bigTransferAmount)) + + // wait until the packet is finalized + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + _, err = dymension.GetNode().FinalizePacketsUntilHeight(ctx, dymensionUserAddr2, rollapp1.GetChainID(), fmt.Sprint(rollappHeight)) + require.NoError(t, err) + + rollappHeight, err = rollapp2.GetNode().Height(ctx) + require.NoError(t, err) + + // wait until the packet is finalized + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp2.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + _, err = dymension.GetNode().FinalizePacketsUntilHeight(ctx, dymensionUserAddr2, rollapp2.GetChainID(), fmt.Sprint(rollappHeight)) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr2, rollappIBCDenom, transferData.Amount.Sub(bridgingFee).Sub(eibcFee)) + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr2, rollappIBCDenom, transferData.Amount.Sub(bridgingFee).Sub(eibcFee)) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +}