diff --git a/Makefile b/Makefile index a0e66564..11333272 100644 --- a/Makefile +++ b/Makefile @@ -14,15 +14,24 @@ e2e-test: clean-e2e e2e-test-ibc-success-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestIBCTransferSuccess_EVM . -e2e-test-light-client-same-chain-id: clean-e2e +e2e-test-light-client-same-chain-id-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestIBCTransferRA_3rdSameChainID_EVM . -e2e-test-light-client-hub-3rd: clean-e2e +e2e-test-light-client-same-chain-id-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestIBCTransferRA_3rdSameChainID_Wasm . + +e2e-test-light-client-hub-3rd-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestIBCTransferBetweenHub3rd_EVM . +e2e-test-light-client-hub-3rd-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestIBCTransferBetweenHub3rd_Wasm . + e2e-test-light-client-same-chain-id-no-light-client: clean-e2e cd tests && go test -timeout=45m -race -v -run TestIBCTransfer_NoLightClient_EVM . +e2e-test-light-client-same-chain-id-no-light-client-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestIBCTransfer_NoLightClient_Wasm . + e2e-test-spinup: clean-e2e cd tests && go test -timeout=45m -race -v -run TestSpinUp . @@ -47,6 +56,9 @@ e2e-hub-to-RA-migrate-dym-evm: clean-e2e e2e-test-bridge-fee-param-change-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestChangeBridgeFeeParam_EVM . +e2e-test-bridge-fee-param-change-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestChangeBridgeFeeParam_Wasm . + e2e-test-ibc-transfer-reserved-word-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestGenesisIBCTransferReservedMemo_EVM . @@ -56,9 +68,12 @@ e2e-test-ibc-timeout-evm: clean-e2e e2e-test-eibc-fulfillment-only-one-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestEIBCFulfillOnOneRollApp_EVM . -e2e-test-eibc-fulfillment-evm-2-RAs: clean-e2e +e2e-test-eibc-fulfillment-evm-2-RAs-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestEIBCFulfillment_two_rollapps_EVM . +e2e-test-eibc-fulfillment-evm-2-RAs-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestEIBCFulfillment_two_rollapps_Wasm . + e2e-test-ibc-grace-period-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestIBCGracePeriodCompliance_EVM . @@ -86,15 +101,27 @@ e2e-test-eibc-pfm-evm: clean-e2e e2e-test-eibc-fulfill-no-balance-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestEIBCNoBalanceToFulfillOrder_EVM . +e2e-test-eibc-fulfill-no-balance-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestEIBCNoBalanceToFulfillOrder_Wasm . + e2e-test-eibc-corrupted-memo-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestEIBCCorruptedMemoNegative_EVM . +e2e-test-eibc-corrupted-memo-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestEIBCCorruptedMemoNegative_Wasm . + e2e-test-eibc-excessive-fee-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestEIBCFeeTooHigh_EVM . +e2e-test-eibc-excessive-fee-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestEIBCFeeTooHigh_Wasm . + e2e-test-eibc-timeout-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestEIBCTimeoutDymToRollapp_EVM . +e2e-test-eibc-timeout-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestEIBCTimeoutDymToRollapp_Wasm . + e2e-test-eibc-timeout_and_fulfill-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestEIBCTimeoutFulFillDymToRollapp_EVM . @@ -212,9 +239,15 @@ e2e-test-rollapp-hardfork-recover-ibc-client-evm: clean-e2e e2e-test-rollapp-hardforkduetodrs-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestHardForkDueToDrs_EVM . +# e2e-test-rollapp-hardforkduetodrs-wasm: clean-e2e +# cd tests && go test -timeout=45m -race -v -run TestHardForkDueToDrs_Wasm . + e2e-test-rollapp-hardforkduetofraud-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestHardForkDueToFraud_EVM . +e2e-test-rollapp-hardforkduetofraud-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestHardForkDueToFraud_Wasm . + e2e-test-rollapp-genesis-transfer-bridge-blocking-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestGenesisTransferBridgeBlocking_EVM . @@ -227,9 +260,15 @@ e2e-test-genesis-bridge-invalid-evm: clean-e2e e2e-test-genesis-bridge-before-channel-set-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestGenesisBridgeBeforeChannelSet_EVM . +e2e-test-genesis-bridge-before-channel-set-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestGenesisBridgeBeforeChannelSet_Wasm . + e2e-test-non-rollapp-unaffected-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_Non_Rollappchain_Unaffected_EVM . +e2e-test-non-rollapp-unaffected-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run Test_Non_Rollappchain_Unaffected_Wasm . + e2e-test-admc-originates-hub-to-rollapp-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestADMC_Originates_HubtoRA_EVM . @@ -251,15 +290,27 @@ e2e-test-update-do-timeout-unallowed-evm: clean-e2e e2e-test-sequencer-celestia-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestSequencerCelestia_EVM . +e2e-test-sequencer-celestia-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestSequencerCelestia_Wasm . + e2e-test-sequencer-hub-disconnection-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestSequencerHubDisconnection_EVM . +e2e-test-sequencer-hub-disconnection-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestSequencerHubDisconnection_Wasm . + e2e-test-fullnode-sync-block-sync-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestSync_BlockSync_EVM . +e2e-test-fullnode-sync-block-sync-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestSync_BlockSync_Wasm . + e2e-test-fullnode-disconnect-block-sync-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestSync_BlockSync_fn_disconnect_EVM . +e2e-test-fullnode-disconnect-block-sync-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestSync_BlockSync_fn_disconnect_Wasm . + e2e-test-sequencer-rotation-oneseq-da-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_SeqRotation_OneSeq_DA_EVM . @@ -353,42 +404,75 @@ e2e-test-sequencer-rotation-history-sync-old-sequencer-unbonded-p2p-wasm: clean- e2e-test-sequencer-rotation-forced-da-evm: clean-e2e cd tests && go test -timeout=30m -race -v -run Test_SeqRotation_Forced_DA_EVM . +e2e-test-sequencer-rotation-forced-da-wasm: clean-e2e + cd tests && go test -timeout=30m -race -v -run Test_SeqRotation_Forced_DA_Wasm . + e2e-test-sequencer-rewardsaddress-update-evm: clean-e2e cd tests && go test -timeout=30m -race -v -run Test_SeqRewardsAddress_Update_EVM . +e2e-test-sequencer-rewardsaddress-update-wasm: clean-e2e + cd tests && go test -timeout=30m -race -v -run Test_SeqRewardsAddress_Update_Wasm . + e2e-test-sequencer-rewardsaddress-register-evm: clean-e2e cd tests && go test -timeout=30m -race -v -run Test_SeqRewardsAddress_Register_EVM . + +e2e-test-sequencer-rewardsaddress-register-wasm: clean-e2e + cd tests && go test -timeout=30m -race -v -run Test_SeqRewardsAddress_Register_Wasm . e2e-test-eibc-client-success-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_EIBC_Client_Success_EVM . +e2e-test-eibc-client-success-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run Test_EIBC_Client_Success_Wasm . + e2e-test-eibc-client-nofulfillrollapp-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_EIBC_Client_NoFulfillRollapp_EVM . +e2e-test-eibc-client-nofulfillrollapp-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run Test_EIBC_Client_NoFulfillRollapp_Wasm . + e2e-test-genesis-bridge-no-relay-ack-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestGenesisBridgeNoRelayAck_EVM . e2e-test-timebaseupgrade-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_TimeBaseUpgrade_EVM . +e2e-test-timebaseupgrade-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run Test_TimeBaseUpgrade_Wasm . + e2e-test-sequencer-rotation-roatate-request-no-da-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_SeqRot_RotReq_No_DA_EVM . e2e-test-fraud-detection-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestFraudDetection_EVM . +e2e-test-fraud-detection-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestFraudDetection_Wasm . + e2e-test-timebaseupgradeinpast-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_TimeBaseUpgradeInPast_EVM . +e2e-test-timebaseupgradeinpast-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run Test_TimeBaseUpgradeInPast_Wasm . + e2e-test-zero-fee-rotated-sequencer-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestZeroFee_RotatedSequencer_EVM . + +e2e-test-zero-fee-rotated-sequencer-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestZeroFee_RotatedSequencer_Wasm . e2e-test-zero-fee-relay-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestZeroFee_RelaySuccess_EVM . +e2e-test-zero-fee-relay-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestZeroFee_RelaySuccess_Wasm . + e2e-test-hardfork-kick-proposer-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_HardFork_KickProposer_EVM . +e2e-test-hardfork-kick-proposer-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run Test_HardFork_KickProposer_Wasm . + e2e-test-rollapp-state-update-success-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_RollAppStateUpdateSuccess_EVM . @@ -413,24 +497,39 @@ e2e-test-erc20-rollapp-to-hub-new-evm: clean-e2e e2e-test-update-min-gas-prices-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestUpdateMinGasPrice_EVM . +e2e-test-update-min-gas-prices-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestUpdateMinGasPrice_Wasm . + e2e-test-tokenless-create-erc20-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestTokenlessCreateERC20_EVM . e2e-test-tokenless-transfer-success-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestTokenlessTransferSuccess_EVM . +e2e-test-tokenless-transfer-success-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestTokenlessTransferSuccess_Wasm . + e2e-test-tokenless-transfer-diff-gas-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestTokenlessTransferDiffGas_EVM . e2e-test-eibc-client-timeout-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_EIBC_Client_Timeout_EVM . +e2e-test-eibc-client-timeout-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run Test_EIBC_Client_Timeout_Wasm . + e2e-test-eibc-client-ackerr-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_EIBC_Client_AckErr_EVM . +e2e-test-eibc-client-ackerr-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run Test_EIBC_Client_AckErr_Wasm . + e2e-test-eibc-client-update-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_EIBC_Client_Update_Order_EVM . +e2e-test-eibc-client-update-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run Test_EIBC_Client_Update_Order_Wasm . + e2e-test-full-node-sync-mul-forks-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_FulNodeSync_MulForks_EVM . @@ -628,12 +727,12 @@ e2e-test-genesis-bridge-no-relay-ack-wasm: clean-e2e e2e-test-sequencer-rotation-roatate-request-no-da-wasm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_SeqRot_RotReq_No_DA_Wasm . -e2e-test-zero-fee-relay-wasm: clean-e2e - cd tests && go test -timeout=45m -race -v -run TestZeroFee_RelaySuccess_Wasm . - e2e-test-without-genesis-account-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestGenesisBridgeWithoutGenesisAcc_EVM . +e2e-test-without-genesis-account-wasm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestGenesisBridgeWithoutGenesisAcc_Wasm . + e2e-test-rollapp-state-update-success-wasm: clean-e2e cd tests && go test -timeout=45m -race -v -run Test_RollAppStateUpdateSuccess_Wasm . diff --git a/go.mod b/go.mod index 2d68921e..184a611e 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ replace ( require ( github.com/decentrio/e2e-testing-live v0.0.0-20240718080249-ee255229c869 - github.com/decentrio/rollup-e2e-testing v0.0.0-20241230041213-ab3dc8baaa9c + github.com/decentrio/rollup-e2e-testing v0.0.0-20250103025120-a09b381ced46 github.com/dymensionxyz/dymension/v3 v3.1.0-rc03.0.20241224113003-12bfcad722ac ) diff --git a/go.sum b/go.sum index 1293f264..dec721d7 100644 --- a/go.sum +++ b/go.sum @@ -742,8 +742,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decentrio/e2e-testing-live v0.0.0-20240718080249-ee255229c869 h1:qWpUYGOsrSC+1Vmd2TjhbsSpntvvx9PsX3AoeMunFxc= github.com/decentrio/e2e-testing-live v0.0.0-20240718080249-ee255229c869/go.mod h1:HZNYnPwmSxkwTPjSD5yolauc1Vx1ZzKL4FFMxTq4H5Y= -github.com/decentrio/rollup-e2e-testing v0.0.0-20241230041213-ab3dc8baaa9c h1:VWuH2yNzKJOKke68P1v6E4oiu4fIq9uISAvKBeTStmI= -github.com/decentrio/rollup-e2e-testing v0.0.0-20241230041213-ab3dc8baaa9c/go.mod h1:QmBrZgZplhtgHRWC0Z7LC7TDsKuC8sDyQvZyXXaqw/c= +github.com/decentrio/rollup-e2e-testing v0.0.0-20250103025120-a09b381ced46 h1:/jhpech7oRzkiPUnMNr4wKlI3j3o87WZekcgKtTgvIA= +github.com/decentrio/rollup-e2e-testing v0.0.0-20250103025120-a09b381ced46/go.mod h1:QmBrZgZplhtgHRWC0Z7LC7TDsKuC8sDyQvZyXXaqw/c= github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= diff --git a/tests/bridging_fee_test.go b/tests/bridging_fee_test.go index 511cb384..d6875e28 100644 --- a/tests/bridging_fee_test.go +++ b/tests/bridging_fee_test.go @@ -162,6 +162,146 @@ func Test_Non_Rollappchain_Unaffected_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } +func Test_Non_Rollappchain_Unaffected_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "gaia-1", + Version: "v14.2.0", + ChainConfig: gaiaConfig, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + gaia1 := chains[0].(*cosmos.CosmosChain) + dymension := chains[1].(*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) + + ic := test.NewSetup(). + AddChain(dymension). + AddChain(gaia1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: gaia1, + Relayer: r, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, gaia1, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, gaia1) + + // Get our Bech32 encoded user addresses + dymensionUser, gaiaUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + gaiaUserAddr := gaiaUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, gaia1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 5, dymension, gaia1) + require.NoError(t, err) + + // Send a normal ibc tx from RA -> Hub + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: gaia1.Config().Denom, + Amount: transferAmount, + } + _, err = gaia1.SendIBCTransfer(ctx, channel.ChannelID, gaiaUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, gaia1) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, gaia1, gaiaUserAddr, gaia1.Config().Denom, walletAmount.Sub(transferData.Amount)) + + // Get the IBC denom for urax on Hub + gaiaTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, gaia1.Config().Denom) + gaiaIBCDenom := transfertypes.ParseDenomTrace(gaiaTokenDenom).IBCDenom() + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, gaiaIBCDenom, transferAmount) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> gaia + transferData = ibc.WalletData{ + Address: gaiaUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> gaia + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, gaia1) + require.NoError(t, err) + + // Get the IBC denom + dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, gaia1, gaiaUserAddr, dymensionIBCDenom, transferAmount) + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + + // TestChangeBridgeFeeParam_EVM create a prop to change bridge fee and after prop passed, transfer from rollapp to hub should have the new bridge fee. func TestChangeBridgeFeeParam_EVM(t *testing.T) { if testing.Short() { @@ -483,3 +623,324 @@ func TestChangeBridgeFeeParam_EVM(t *testing.T) { // Run invariant check CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } + +func TestChangeBridgeFeeParam_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp 1 + settlement_layer_rollapp1 := "dymension" + settlement_node_address := fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + rollapp1_id := "rollappwasm_1234-1" + gas_price_rollapp1 := "0adym" + maxIdleTime1 := "10s" + maxProofTime := "500ms" + configFileOverrides1 := overridesDymintToml(settlement_layer_rollapp1, settlement_node_address, rollapp1_id, gas_price_rollapp1, maxIdleTime1, maxProofTime, "50s") + + extraFlags := map[string]interface{}{"genesis-accounts-path": true} + + // setup config for rollapp 2 + settlement_layer_rollapp2 := "dymension" + rollapp2_id := "decentrio_12345-1" + gas_price_rollapp2 := "0adym" + maxIdleTime2 := "1s" + configFileOverrides2 := overridesDymintToml(settlement_layer_rollapp2, settlement_node_address, rollapp2_id, gas_price_rollapp2, maxIdleTime2, maxProofTime, "50s") + + // 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: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + ConfigFileOverrides: configFileOverrides1, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "rollapp2", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "decentrio_12345-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + 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, + }, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + ExtraFlags: extraFlags, + }, + }) + + // 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) + r1 := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer1", 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(r1, "relayer1"). + AddRelayer(r2, "relayer2"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r1, + 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, 1179360, true) + require.NoError(t, err) + + wallet1, found := r1.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + wallet2, found := r2.GetWallet(rollapp2.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + keyDir2 := dymension.GetRollApps()[1].GetSequencerKeyDir() + require.NoError(t, err) + keyPath2 := keyDir2 + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet1.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet1.FormattedAddress()}) + require.NoError(t, err) + } + + err = testutil.WaitForBlocks(ctx, 2, dymension) + require.NoError(t, err) + + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath2, []string{wallet2.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath2, []string{wallet2.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r1, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + CreateChannel(ctx, t, r2, eRep, dymension.CosmosChain, rollapp2.CosmosChain, anotherIbcPath) + + // Start both relayers + err = r1.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = r2.StartRelayer(ctx, eRep, anotherIbcPath) + require.NoError(t, err) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r1, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get ibc denom of rollapp on hub + rollappTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, rollapp1.Config().Denom) + rollappIBCDenom := transfertypes.ParseDenomTrace(rollappTokenDenom).IBCDenom() + + fmt.Println("rollappIBCDenom", rollappIBCDenom) + + // Send a normal ibc tx from RA -> Hub + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, 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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + + // Change the bridge fee param using gov + // + newBridgeFeeParam := json.RawMessage(`"0"`) + _, err = dymension.GetNode().ParamChangeProposal(ctx, dymensionUser.KeyName(), + &utils.ParamChangeProposalJSON{ + Title: "Change bridge fee params", + Description: "Change bridge fee params", + Changes: utils.ParamChangesJSON{ + utils.NewParamChangeJSON("delayedack", "BridgeFee", newBridgeFeeParam), + }, + Deposit: "500000000000" + dymension.Config().Denom, // greater than min deposit + }) + require.NoError(t, err) + + err = dymension.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) + require.NoError(t, err, "failed to submit votes") + + height, err := dymension.Height(ctx) + require.NoError(t, err, "error fetching height") + _, err = cosmos.PollForProposalStatus(ctx, dymension.CosmosChain, height, height+30, "1", cosmos.ProposalStatusPassed) + require.NoError(t, err, "proposal status did not change to passed") + // + + // send from rollapp to hub again and make sure new bridge fee is applied + _, 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).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) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee).Add(transferAmount)) + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} \ No newline at end of file diff --git a/tests/canonical_light_client_test.go b/tests/canonical_light_client_test.go index 0a5acea8..dfd05b21 100644 --- a/tests/canonical_light_client_test.go +++ b/tests/canonical_light_client_test.go @@ -225,6 +225,212 @@ func TestIBCTransferBetweenHub3rd_EVM(t *testing.T) { }) } +func TestIBCTransferBetweenHub3rd_Wasm(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"] = "rollappwasm_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 + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 0 + numRollAppVals := 1 + numVals := 1 + numFullNodes := 0 + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-test", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + }, + { + Name: "gaia-1", + Version: "v14.2.0", + ChainConfig: gaiaConfig, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + }) + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + rollapp1 := chains[0].(*dym_rollapp.DymRollApp) + dymension := chains[1].(*dym_hub.DymHub) + gaia := chains[2].(*cosmos.CosmosChain) + + // Relayer Factory + client, network := test.DockerSetup(t) + + 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). + AddChain(gaia). + AddRelayer(r2, "relayer2"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: gaia, + 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, 1179360, true) + require.NoError(t, err) + + t.Cleanup(func() { + _ = ic.Close() + }) + + // create ibc path between dymension and gaia + CreateChannel(ctx, t, r2, eRep, dymension.CosmosChain, gaia, anotherIbcPath) + + gaiaChan, err := r2.GetChannels(ctx, eRep, gaia.GetChainID()) + require.NoError(t, err) + require.Len(t, gaiaChan, 1) + + dymGaiaChan := gaiaChan[0].Counterparty + require.NotEmpty(t, dymGaiaChan.ChannelID) + + gaiaDymChan := gaiaChan[0] + require.NotEmpty(t, gaiaDymChan.ChannelID) + + // Start the relayer and set the cleanup function. + err = r2.StartRelayer(ctx, eRep, anotherIbcPath) + require.NoError(t, err) + + t.Cleanup( + func() { + err = r2.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer2: %s", err) + } + }, + ) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, gaia) + + // Get our Bech32 encoded user addresses + dymensionUser, gaiaUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + gaiaUserAddr := gaiaUser.FormattedAddress() + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, dymensionOrigBal) + + gaiaOrigBal, err := gaia.GetBalance(ctx, gaiaUserAddr, gaia.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, gaiaOrigBal) + + t.Run("canonial client gaia<->dym", func(t *testing.T) { + + firstHopDenom := transfertypes.GetPrefixedDenom(dymGaiaChan.PortID, dymGaiaChan.ChannelID, gaia.Config().Denom) + secondHopDenom := transfertypes.GetPrefixedDenom(gaiaDymChan.PortID, gaiaDymChan.ChannelID, dymension.Config().Denom) + + firstHopDenomTrace := transfertypes.ParseDenomTrace(firstHopDenom) + secondHopDenomTrace := transfertypes.ParseDenomTrace(secondHopDenom) + + firstHopIBCDenom := firstHopDenomTrace.IBCDenom() + secondHopIBCDenom := secondHopDenomTrace.IBCDenom() + + // Send packet from gaia -> dym + transfer := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: gaia.Config().Denom, + Amount: transferAmount, + } + + transferTx, err := gaia.SendIBCTransfer(ctx, gaiaDymChan.ChannelID, gaiaUser.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + err = transferTx.Validate() + require.NoError(t, err) + + // wait until dymension receive transferAmount + err = testutil.WaitForBlocks(ctx, 10, dymension, gaia) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, gaia, gaiaUserAddr, gaia.Config().Denom, walletAmount.Sub(transferAmount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, firstHopIBCDenom, transferAmount) + + // Send back packet from dym -> gaia + transfer = ibc.WalletData{ + Address: gaiaUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + transferTx, err = dymension.SendIBCTransfer(ctx, dymGaiaChan.ChannelID, dymensionUser.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + err = transferTx.Validate() + require.NoError(t, err) + + // wait until gaia receive transferAmount + err = testutil.WaitForBlocks(ctx, 10, gaia, dymension) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, gaia, gaiaUserAddr, secondHopIBCDenom, transferAmount) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferAmount)) + + }) +} + + // TestIBCTransferRA3rdSameChainID_EVM create vanilla cosmos chain with the same chain-id as an existing rollapp and test IBC transfer between them func TestIBCTransferRA_3rdSameChainID_EVM(t *testing.T) { if testing.Short() { @@ -237,7 +443,340 @@ func TestIBCTransferRA_3rdSameChainID_EVM(t *testing.T) { 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["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 + + // add modify gaia config so that it has the same chain-id as rollapp1 + gaiaConfig := gaiaConfig.Clone() + gaiaConfig.ChainID = "rollappevm_1234-1" + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 0 + numRollAppVals := 1 + numVals := 1 + numFullNodes := 0 + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-test", + 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: "dymension-hub", + ChainConfig: dymensionConfig, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + }, + { + Name: "gaia-1", + Version: "v14.2.0", + ChainConfig: gaiaConfig, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + }) + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + rollapp1 := chains[0].(*dym_rollapp.DymRollApp) + dymension := chains[1].(*dym_hub.DymHub) + gaia := chains[2].(*cosmos.CosmosChain) + + // 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). + AddChain(gaia). + AddRelayer(r, "relayer"). + AddRelayer(r2, "relayer2"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: gaia, + 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, 1179360, true) + require.NoError(t, err) + + t.Cleanup(func() { + _ = ic.Close() + }) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + // create ibc path between dymension and gaia, and between dymension and rollapp1 + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + CreateChannel(ctx, t, r2, eRep, dymension.CosmosChain, gaia, anotherIbcPath) + + // get rollapp -> dym channel + rollappChan, err := r.GetChannels(ctx, eRep, rollapp1.GetChainID()) + require.NoError(t, err) + require.Len(t, rollappChan, 1) + + rollappDymChan := rollappChan[0] + require.NotEmpty(t, rollappDymChan.ChannelID) + + dymRollappChan := rollappChan[0].Counterparty + require.NotEmpty(t, dymRollappChan.ChannelID) + + // Get gaia -> dym channel + gaiaChan, err := r2.GetChannels(ctx, eRep, gaia.GetChainID()) + require.NoError(t, err) + require.Len(t, gaiaChan, 1) + + dymGaiaChan := gaiaChan[0].Counterparty + require.NotEmpty(t, dymGaiaChan.ChannelID) + + gaiaDymChan := gaiaChan[0] + require.NotEmpty(t, gaiaDymChan.ChannelID) + + // Start the relayer and set the cleanup function. + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + err = r2.StartRelayer(ctx, eRep, anotherIbcPath) + require.NoError(t, err) + + t.Cleanup( + func() { + err = r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + err = r2.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer2: %s", err) + } + }, + ) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, gaia, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, gaiaUser, rollappUser := users[0], users[1], users[2] + + dymensionUserAddr := dymensionUser.FormattedAddress() + gaiaUserAddr := gaiaUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, dymensionOrigBal) + + gaiaOrigBal, err := gaia.GetBalance(ctx, gaiaUserAddr, gaia.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, gaiaOrigBal) + + rollappOrigBal, err := rollapp1.GetBalance(ctx, rollappUserAddr, rollapp1.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, rollappOrigBal) + + t.Run("canonial client test gaia<->dym and rollapp<->dym", func(t *testing.T) { + + // sending between gaia and dymension + firstHopDenom := transfertypes.GetPrefixedDenom(dymGaiaChan.PortID, dymGaiaChan.ChannelID, gaia.Config().Denom) + secondHopDenom := transfertypes.GetPrefixedDenom(gaiaDymChan.PortID, gaiaDymChan.ChannelID, dymension.Config().Denom) + + firstHopDenomTrace := transfertypes.ParseDenomTrace(firstHopDenom) + secondHopDenomTrace := transfertypes.ParseDenomTrace(secondHopDenom) + + firstHopIBCDenom := firstHopDenomTrace.IBCDenom() + secondHopIBCDenom := secondHopDenomTrace.IBCDenom() + + // Send packet from gaia -> dym + transfer := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: gaia.Config().Denom, + Amount: transferAmount, + } + + transferTx, err := gaia.SendIBCTransfer(ctx, gaiaDymChan.ChannelID, gaiaUser.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + err = transferTx.Validate() + require.NoError(t, err) + + // wait until dymension receive transferAmount + err = testutil.WaitForBlocks(ctx, 10, dymension, gaia) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, gaia, gaiaUserAddr, gaia.Config().Denom, walletAmount.Sub(transferAmount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, firstHopIBCDenom, transferAmount) + + // Send back packet from dym -> gaia + transfer = ibc.WalletData{ + Address: gaiaUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + transferTx, err = dymension.SendIBCTransfer(ctx, dymGaiaChan.ChannelID, dymensionUser.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + err = transferTx.Validate() + require.NoError(t, err) + + // wait until gaia receive transferAmount + err = testutil.WaitForBlocks(ctx, 10, gaia, dymension) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferAmount)) + testutil.AssertBalance(t, ctx, gaia, gaiaUserAddr, secondHopIBCDenom, transferAmount) + + // sending between rollapp and dymension + firstHopDenom = transfertypes.GetPrefixedDenom(dymRollappChan.PortID, dymRollappChan.ChannelID, rollapp1.Config().Denom) + secondHopDenom = transfertypes.GetPrefixedDenom(rollappDymChan.PortID, rollappDymChan.ChannelID, dymension.Config().Denom) + + firstHopDenomTrace = transfertypes.ParseDenomTrace(firstHopDenom) + secondHopDenomTrace = transfertypes.ParseDenomTrace(secondHopDenom) + + firstHopIBCDenom = firstHopDenomTrace.IBCDenom() + secondHopIBCDenom = secondHopDenomTrace.IBCDenom() + + // Send packet from rollapp -> dym + transfer = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + _, err = rollapp1.SendIBCTransfer(ctx, rollappDymChan.ChannelID, rollappUser.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension) + require.NoError(t, err) + + // wait until dymension receive transferAmount when rollapp finalized + rollappHeight, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetNode().Chain.GetChainID(), rollappHeight, 600) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferAmount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, firstHopIBCDenom, transferAmount.Sub(bridgingFee)) + + // Send back packet from dym -> rollapp + transfer = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + _, err = dymension.SendIBCTransfer(ctx, dymRollappChan.ChannelID, dymensionUser.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + + // wait until rollapp receive transferAmount + err = testutil.WaitForBlocks(ctx, 10, rollapp1, dymension) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferAmount).Sub(transferAmount)) + erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + require.NoError(t, err) + erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, secondHopIBCDenom, transferAmount) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) + }) +} + +func TestIBCTransferRA_3rdSameChainID_Wasm(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"] = "rollappwasm_1234-1" dymintTomlOverrides["settlement_gas_prices"] = "0adym" dymintTomlOverrides["max_idle_time"] = "3s" dymintTomlOverrides["max_proof_time"] = "500ms" @@ -248,7 +787,7 @@ func TestIBCTransferRA_3rdSameChainID_EVM(t *testing.T) { // add modify gaia config so that it has the same chain-id as rollapp1 gaiaConfig := gaiaConfig.Clone() - gaiaConfig.ChainID = "rollappevm_1234-1" + gaiaConfig.ChainID = "rollappwasm_1234-1" // Create chain factory with dymension numHubVals := 1 @@ -263,18 +802,18 @@ func TestIBCTransferRA_3rdSameChainID_EVM(t *testing.T) { ChainConfig: ibc.ChainConfig{ Type: "rollapp-dym", Name: "rollapp-test", - ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappEVMImage}, + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, Bin: "rollappd", - Bech32Prefix: "ethm", + Bech32Prefix: "rol", Denom: "urax", - CoinType: "60", + CoinType: "118", GasPrices: "0.0urax", GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, - ModifyGenesis: modifyRollappEVMGenesis(rollappEVMGenesisKV), + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), ConfigFileOverrides: configFileOverrides, }, NumValidators: &numRollAppVals, @@ -549,10 +1088,6 @@ func TestIBCTransferRA_3rdSameChainID_EVM(t *testing.T) { require.NoError(t, err) testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferAmount).Sub(transferAmount)) - erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") - require.NoError(t, err) - erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address - testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, secondHopIBCDenom, transferAmount) // Run invariant check CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) @@ -764,3 +1299,210 @@ func TestIBCTransfer_NoLightClient_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) }) } + +func TestIBCTransfer_NoLightClient_Wasm(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"] = "rollappwasm_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 + + // add modify gaia config so that it has the same chain-id as rollapp1 + gaiaConfig := gaiaConfig.Clone() + gaiaConfig.ChainID = "rollappwasm_1234-1" + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 0 + numRollAppVals := 1 + numVals := 1 + numFullNodes := 0 + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-test", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + }, + { + Name: "gaia-1", + Version: "v14.2.0", + ChainConfig: gaiaConfig, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + }) + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + rollapp1 := chains[0].(*dym_rollapp.DymRollApp) + dymension := chains[1].(*dym_hub.DymHub) + gaia := chains[2].(*cosmos.CosmosChain) + + // 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) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddChain(gaia). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: gaia, + Relayer: r, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + t.Cleanup(func() { + _ = ic.Close() + }) + + // create ibc path between dymension and gaia, and between dymension and rollapp1 + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, gaia, ibcPath) + + // Get gaia -> dym channel + gaiaChan, err := r.GetChannels(ctx, eRep, gaia.GetChainID()) + require.NoError(t, err) + require.Len(t, gaiaChan, 1) + + dymGaiaChan := gaiaChan[0].Counterparty + require.NotEmpty(t, dymGaiaChan.ChannelID) + + gaiaDymChan := gaiaChan[0] + + // Start the relayer and set the cleanup function. + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, gaia, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, gaiaUser, rollappUser := users[0], users[1], users[2] + + dymensionUserAddr := dymensionUser.FormattedAddress() + gaiaUserAddr := gaiaUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, dymensionOrigBal) + + gaiaOrigBal, err := gaia.GetBalance(ctx, gaiaUserAddr, gaia.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, gaiaOrigBal) + + rollappOrigBal, err := rollapp1.GetBalance(ctx, rollappUserAddr, rollapp1.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, rollappOrigBal) + + t.Run("canonial client test gaia<->dym", func(t *testing.T) { + + // sending between gaia and dymension + firstHopDenom := transfertypes.GetPrefixedDenom(dymGaiaChan.PortID, dymGaiaChan.ChannelID, gaia.Config().Denom) + secondHopDenom := transfertypes.GetPrefixedDenom(gaiaDymChan.PortID, gaiaDymChan.ChannelID, dymension.Config().Denom) + + firstHopDenomTrace := transfertypes.ParseDenomTrace(firstHopDenom) + secondHopDenomTrace := transfertypes.ParseDenomTrace(secondHopDenom) + + firstHopIBCDenom := firstHopDenomTrace.IBCDenom() + secondHopIBCDenom := secondHopDenomTrace.IBCDenom() + + // Send packet from gaia -> dym + transfer := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: gaia.Config().Denom, + Amount: transferAmount, + } + + transferTx, err := gaia.SendIBCTransfer(ctx, gaiaDymChan.ChannelID, gaiaUser.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + err = transferTx.Validate() + require.NoError(t, err) + + // wait until dymension receive transferAmount + err = testutil.WaitForBlocks(ctx, 10, dymension, gaia) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, gaia, gaiaUserAddr, gaia.Config().Denom, walletAmount.Sub(transferAmount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, firstHopIBCDenom, transferAmount) + + // Send back packet from dym -> gaia + transfer = ibc.WalletData{ + Address: gaiaUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + transferTx, err = dymension.SendIBCTransfer(ctx, dymGaiaChan.ChannelID, dymensionUser.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + err = transferTx.Validate() + require.NoError(t, err) + + // wait until gaia receive transferAmount + err = testutil.WaitForBlocks(ctx, 10, gaia, dymension) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferAmount)) + testutil.AssertBalance(t, ctx, gaia, gaiaUserAddr, secondHopIBCDenom, transferAmount) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) + }) +} + diff --git a/tests/data/config.yaml b/tests/data/config.yaml index 93a87f8d..5d615554 100755 --- a/tests/data/config.yaml +++ b/tests/data/config.yaml @@ -1,4 +1,4 @@ -node_address: http://dymension_100-1-val-0-Test_EIBC_Client_AckErr_EVM:26657 +node_address: http://dymension_100-1-val-0-Test_EIBC_Client_Timeout_Wasm:26657 gas: prices: "" fees: 100adym @@ -7,14 +7,14 @@ order_polling: interval: 30s enabled: false rollapps: - rollappevm_1234-1: + rollappwasm_1234-1: full_nodes: - - http://ra-rollappevm_1234-1-fn-0-Test_EIBC_Client_AckErr_EVM:26657 + - http://ra-rollappwasm_1234-1-fn-0-Test_EIBC_Client_Timeout_Wasm:26657 min_confirmations: 1 operator: account_name: operator keyring_backend: test - keyring_dir: /root/dymension-hub-2a77906c26d4eb0ca26b4d0e01736105c3f8382c0dbf48901b9955659325751d0 + keyring_dir: /root/dymension-hub-228118cbdfee2d16bb4fb02b184b14a72d0e8ba52f8d3410b575deea85f680cc3 group_id: 1 min_fee_share: "0.0001" fulfillers: @@ -22,7 +22,7 @@ fulfillers: operator_address: "" policy_address: dym1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzs8ag8zm keyring_backend: test - keyring_dir: /root/dymension-hub-2a77906c26d4eb0ca26b4d0e01736105c3f8382c0dbf48901b9955659325751d0 + keyring_dir: /root/dymension-hub-228118cbdfee2d16bb4fb02b184b14a72d0e8ba52f8d3410b575deea85f680cc3 batch_size: 0 max_orders_per_tx: 5 validation: diff --git a/tests/eibc_client_test.go b/tests/eibc_client_test.go index 342a520f..0d339f22 100644 --- a/tests/eibc_client_test.go +++ b/tests/eibc_client_test.go @@ -771,7 +771,7 @@ func Test_EIBC_Client_Success_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } -func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { +func Test_EIBC_Client_Success_Wasm(t *testing.T) { if testing.Short() { t.Skip() } @@ -781,7 +781,7 @@ func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { 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["rollapp_id"] = "rollappwasm_1234-1" dymintTomlOverrides["settlement_gas_prices"] = "0adym" dymintTomlOverrides["max_idle_time"] = "3s" dymintTomlOverrides["max_proof_time"] = "500ms" @@ -793,8 +793,8 @@ func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { configFileOverrides["config/dymint.toml"] = dymintTomlOverrides // Create chain factory with dymension - modifyEVMGenesisKV := append( - rollappEVMGenesisKV, + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, cosmos.GenesisKV{ Key: "app_state.rollappparams.params.da", Value: "grpc", @@ -812,18 +812,18 @@ func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { ChainConfig: ibc.ChainConfig{ Type: "rollapp-dym", Name: "rollapp-temp", - ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappEVMImage}, + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, Bin: "rollappd", - Bech32Prefix: "ethm", + Bech32Prefix: "rol", Denom: "urax", - CoinType: "60", + CoinType: "118", GasPrices: "0.0urax", GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, - ModifyGenesis: modifyRollappEVMGenesis(modifyEVMGenesisKV), + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), ConfigFileOverrides: configFileOverrides, }, NumValidators: &numRollAppVals, @@ -903,7 +903,7 @@ func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { }, nil, "", nil, true, 1179360, true) require.NoError(t, err) - containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) // Get the container details containerJSON, err := client.ContainerInspect(context.Background(), containerID) @@ -1160,22 +1160,2546 @@ func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { // rollappErc20MaccBalance, err := rollapp1.GetBalance(ctx, erc20MAccAddr, dymensionIBCDenom) // require.NoError(t, err) - // require.True(t, rollappErc20MaccBalance.Equal(transferData.Amount)) - // require.NoError(t, err) + // require.True(t, rollappErc20MaccBalance.Equal(transferData.Amount)) + // require.NoError(t, err) + + // tokenPair, err := rollapp1.GetNode().QueryErc20TokenPair(ctx, dymensionIBCDenom) + // require.NoError(t, err) + // require.NotNil(t, tokenPair) + + // // convert erc20 + // _, err = rollapp1.GetNode().ConvertErc20(ctx, rollappUser.KeyName(), tokenPair.Erc20Address, transferData.Amount.String(), rollappUserAddr, rollappUserAddr, rollapp1.Config().ChainID) + // require.NoError(t, err, "can not convert erc20 to cosmos coin") + + // err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + // require.NoError(t, err) + // testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, transferData.Amount) + + // StartDB(ctx, t, client, network) + + dymHomeDir := strings.Split(dymension.Validators[0].HomeDir(), "/") + dymFolderName := dymHomeDir[len(dymHomeDir)-1] + + membersData, err := os.ReadFile(fmt.Sprintf("/tmp/%s/members.json", dymFolderName)) + require.NoError(t, err) + + var members MembersJSON + err = json.Unmarshal(membersData, &members) + require.NoError(t, err) + + newAddress := dymensionUserAddr + for i := range members.Members { + members.Members[i].Address = newAddress + } + + updatedJSON, err := json.MarshalIndent(members, "", " ") + require.NoError(t, err) + + err = os.WriteFile(fmt.Sprintf("/tmp/%s/members.json", dymFolderName), updatedJSON, 0755) + require.NoError(t, err) + + cmd = []string{"group", "create-group", "operator", "==A", dymension.GetNode().HomeDir() + "/members.json", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + txHash, err := dymension.GetNode().ExecTx(ctx, "operator", cmd...) + fmt.Println(txHash) + require.NoError(t, err) + + cmd = []string{"group", "create-group-policy", "operator", "1", "==A", dymension.GetNode().HomeDir() + "/policy.json", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + txHash, err = dymension.GetNode().ExecTx(ctx, "operator", cmd...) + + fmt.Println(txHash) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 5, dymension) + + policiesGroup, err := dymension.GetNode().QueryGroupPoliciesByAdmin(ctx, operatorAddr) + require.NoError(t, err) + policyAddr := policiesGroup.GroupPolicies[0].Address + + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+rollappIBCDenom, "rollappwasm_1234-1", rollappIBCDenom, "0.1", "1000000"+rollappIBCDenom, "0.1", true) + fmt.Println(txHash) + require.NoError(t, err) + + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp2.KeyName(), policyAddr, "10000"+rollappIBCDenom, "rollappwasm_1234-1", rollappIBCDenom, "0.1", "10000"+rollappIBCDenom, "0.1", true) + fmt.Println(txHash) + require.NoError(t, err) + + 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.Gas.Fees = "100adym" + config.LogLevel = "debug" + config.OrderPolling.Interval = 30 * time.Second + config.OrderPolling.Enabled = false + config.Fulfillers.KeyringBackend = "test" + config.Fulfillers.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.Fulfillers.Scale = 10 + config.Fulfillers.MaxOrdersPerTx = 5 + config.Fulfillers.PolicyAddress = policyAddr + config.Validation.FallbackLevel = "p2p" + config.Validation.WaitTime = 5 * time.Minute + config.Validation.Interval = 10 * time.Second + config.Operator.AccountName = "operator" + config.Operator.GroupID = 1 + config.Operator.KeyringBackend = "test" + config.Operator.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.Operator.MinFeeShare = "0.1" + config.Rollapps = map[string]RollappConfig{ + "rollappwasm_1234-1": { + FullNodes: []string{fmt.Sprintf("http://ra-rollappwasm_1234-1-fn-0-%s:26657", t.Name())}, + MinConfirmations: 1, + }, + } + config.Slack.Enabled = false + config.Slack.AppToken = "" + config.Slack.ChannelID = "" + + // 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: dymensionUserAddr, + 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.ChannelID, rollappUserAddr, 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) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + 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, dymensionUserAddr, rollappIBCDenom, transferData.Amount.Sub(bridgingFee).Sub(eibcFee)) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + +func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + 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" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides := make(map[string]any) + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + // Create chain factory with dymension + modifyEVMGenesisKV := append( + rollappEVMGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 1 + 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(modifyEVMGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + StartDA(ctx, t, client, network) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 2, dymension) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, lp1, lp2, rollappUser := users[0], users[1], users[2], users[3] + + dymensionUserAddr := dymensionUser.FormattedAddress() + lp1Addr := lp1.FormattedAddress() + // lp2Addr := lp2.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // create operator + cmd := []string{"keys", "add", "operator", + "--coin-type", dymension.GetNode().Chain.Config().CoinType, + "--keyring-backend", "test", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + + _, _, err = dymension.GetNode().ExecBin(ctx, cmd...) + require.NoError(t, err) + + cmd = []string{dymension.GetNode().Chain.Config().Bin, "keys", "show", "--address", "operator", + "--home", dymension.GetNode().HomeDir(), + "--keyring-backend", "test", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + stdout, _, err := dymension.GetNode().Exec(ctx, cmd, nil) + require.NoError(t, err) + + operatorAddr := string(bytes.TrimSuffix(stdout, []byte("\n"))) + println("Done for set up operator: ", operatorAddr) + + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: operatorAddr, + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + 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: lp1Addr, + Denom: rollapp1.Config().Denom, + Amount: bigTransferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, lp1Addr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, lp1Addr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + 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() + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, lp1Addr, rollappIBCDenom, transferData.Amount.Sub(bigBridgingFee)) + + // Get the IBC denom + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + // // register ibc denom on rollapp1 + // metadata := banktypes.Metadata{ + // Description: "IBC token from Dymension", + // DenomUnits: []*banktypes.DenomUnit{ + // { + // Denom: dymensionIBCDenom, + // Exponent: 0, + // Aliases: []string{"udym"}, + // }, + // { + // Denom: "udym", + // Exponent: 6, + // }, + // }, + // // Setting base as IBC hash denom since bank keepers's SetDenomMetadata uses + // // Base as key path and the IBC hash is what gives this token uniqueness + // // on the executing chain + // Base: dymensionIBCDenom, + // Display: "udym", + // Name: "udym", + // Symbol: "udym", + // } + + // data := map[string][]banktypes.Metadata{ + // "metadata": {metadata}, + // } + + // contentFile, err := json.Marshal(data) + // require.NoError(t, err) + // rollapp1.GetNode().WriteFile(ctx, contentFile, "./ibcmetadata.json") + // deposit := "500000000000" + rollapp1.Config().Denom + // rollapp1.GetNode().HostName() + // _, err = rollapp1.GetNode().RegisterIBCTokenDenomProposal(ctx, rollappUser.KeyName(), deposit, rollapp1.GetNode().HomeDir()+"/ibcmetadata.json") + // require.NoError(t, err) + + // err = rollapp1.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) + // require.NoError(t, err, "failed to submit votes") + + // height, err := rollapp1.Height(ctx) + // require.NoError(t, err, "error fetching height") + // _, err = cosmos.PollForProposalStatus(ctx, rollapp1.CosmosChain, height, height+30, "1", cosmos.ProposalStatusPassed) + // require.NoError(t, err, "proposal status did not change to passed") + + // // Compose an IBC transfer and send from dymension -> rollapp + // transferData = ibc.WalletData{ + // Address: rollappUserAddr, + // Denom: dymension.Config().Denom, + // Amount: transferAmount.Mul(math.NewInt(5)), + // } + + // // Compose an IBC transfer and send from Hub -> rollapp + // _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + // require.NoError(t, err) + + // // Assert balance was updated on the hub + // testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferData.Amount)) + + // err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + // require.NoError(t, err) + + // // Check fund was set to erc20 module account on rollapp + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // rollappErc20MaccBalance, err := rollapp1.GetBalance(ctx, erc20MAccAddr, dymensionIBCDenom) + // require.NoError(t, err) + + // require.True(t, rollappErc20MaccBalance.Equal(transferData.Amount)) + // require.NoError(t, err) + + // tokenPair, err := rollapp1.GetNode().QueryErc20TokenPair(ctx, dymensionIBCDenom) + // require.NoError(t, err) + // require.NotNil(t, tokenPair) + + // // convert erc20 + // _, err = rollapp1.GetNode().ConvertErc20(ctx, rollappUser.KeyName(), tokenPair.Erc20Address, transferData.Amount.String(), rollappUserAddr, rollappUserAddr, rollapp1.Config().ChainID) + // require.NoError(t, err, "can not convert erc20 to cosmos coin") + + // err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + // require.NoError(t, err) + // testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, transferData.Amount) + + // StartDB(ctx, t, client, network) + + dymHomeDir := strings.Split(dymension.Validators[0].HomeDir(), "/") + dymFolderName := dymHomeDir[len(dymHomeDir)-1] + + membersData, err := os.ReadFile(fmt.Sprintf("/tmp/%s/members.json", dymFolderName)) + require.NoError(t, err) + + var members MembersJSON + err = json.Unmarshal(membersData, &members) + require.NoError(t, err) + + newAddress := dymensionUserAddr + for i := range members.Members { + members.Members[i].Address = newAddress + } + + updatedJSON, err := json.MarshalIndent(members, "", " ") + require.NoError(t, err) + + err = os.WriteFile(fmt.Sprintf("/tmp/%s/members.json", dymFolderName), updatedJSON, 0755) + require.NoError(t, err) + + cmd = []string{"group", "create-group", "operator", "==A", dymension.GetNode().HomeDir() + "/members.json", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + txHash, err := dymension.GetNode().ExecTx(ctx, "operator", cmd...) + fmt.Println(txHash) + require.NoError(t, err) + + cmd = []string{"group", "create-group-policy", "operator", "1", "==A", dymension.GetNode().HomeDir() + "/policy.json", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + txHash, err = dymension.GetNode().ExecTx(ctx, "operator", cmd...) + + fmt.Println(txHash) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 5, dymension) + + policiesGroup, err := dymension.GetNode().QueryGroupPoliciesByAdmin(ctx, operatorAddr) + require.NoError(t, err) + policyAddr := policiesGroup.GroupPolicies[0].Address + + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+"adym", "rollappevm_1234-1", "adym", "0.1", "1000000"+"adym", "0.1", true) + fmt.Println(txHash) + require.NoError(t, err) + + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp2.KeyName(), policyAddr, "10000"+rollappIBCDenom, "rollappevm_1234-1", rollappIBCDenom, "0.1", "10000"+rollappIBCDenom, "0.1", true) + fmt.Println(txHash) + require.NoError(t, err) + + 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.Gas.Fees = "100adym" + config.LogLevel = "debug" + config.OrderPolling.Interval = 30 * time.Second + config.OrderPolling.Enabled = false + config.Fulfillers.KeyringBackend = "test" + config.Fulfillers.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.Fulfillers.Scale = 10 + config.Fulfillers.MaxOrdersPerTx = 5 + config.Fulfillers.PolicyAddress = policyAddr + config.Validation.FallbackLevel = "p2p" + config.Validation.WaitTime = 5 * time.Minute + config.Validation.Interval = 10 * time.Second + config.Operator.AccountName = "operator" + config.Operator.GroupID = 1 + config.Operator.KeyringBackend = "test" + config.Operator.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.Operator.MinFeeShare = "0.1" + config.Rollapps = map[string]RollappConfig{ + "rollappevm_1234-1": { + FullNodes: []string{fmt.Sprintf("http://ra-rollappevm_1234-1-fn-0-%s:26657", t.Name())}, + MinConfirmations: 1, + }, + } + config.Slack.Enabled = false + config.Slack.AppToken = "" + config.Slack.ChannelID = "" + + // 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: dymensionUserAddr, + 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.ChannelID, rollappUserAddr, 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) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + 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, dymensionUserAddr, rollappIBCDenom, transferData.Amount.Sub(bridgingFee)) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + +func Test_EIBC_Client_NoFulfillRollapp_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + 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"] = "rollappwasm_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" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides := make(map[string]any) + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + // Create chain factory with dymension + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 1 + numRollAppVals := 1 + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + StartDA(ctx, t, client, network) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 2, dymension) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, lp1, lp2, rollappUser := users[0], users[1], users[2], users[3] + + dymensionUserAddr := dymensionUser.FormattedAddress() + lp1Addr := lp1.FormattedAddress() + // lp2Addr := lp2.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // create operator + cmd := []string{"keys", "add", "operator", + "--coin-type", dymension.GetNode().Chain.Config().CoinType, + "--keyring-backend", "test", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + + _, _, err = dymension.GetNode().ExecBin(ctx, cmd...) + require.NoError(t, err) + + cmd = []string{dymension.GetNode().Chain.Config().Bin, "keys", "show", "--address", "operator", + "--home", dymension.GetNode().HomeDir(), + "--keyring-backend", "test", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + stdout, _, err := dymension.GetNode().Exec(ctx, cmd, nil) + require.NoError(t, err) + + operatorAddr := string(bytes.TrimSuffix(stdout, []byte("\n"))) + println("Done for set up operator: ", operatorAddr) + + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: operatorAddr, + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + 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: lp1Addr, + Denom: rollapp1.Config().Denom, + Amount: bigTransferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, lp1Addr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, lp1Addr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + 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() + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, lp1Addr, rollappIBCDenom, transferData.Amount.Sub(bigBridgingFee)) + + // Get the IBC denom + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + // // register ibc denom on rollapp1 + // metadata := banktypes.Metadata{ + // Description: "IBC token from Dymension", + // DenomUnits: []*banktypes.DenomUnit{ + // { + // Denom: dymensionIBCDenom, + // Exponent: 0, + // Aliases: []string{"udym"}, + // }, + // { + // Denom: "udym", + // Exponent: 6, + // }, + // }, + // // Setting base as IBC hash denom since bank keepers's SetDenomMetadata uses + // // Base as key path and the IBC hash is what gives this token uniqueness + // // on the executing chain + // Base: dymensionIBCDenom, + // Display: "udym", + // Name: "udym", + // Symbol: "udym", + // } + + // data := map[string][]banktypes.Metadata{ + // "metadata": {metadata}, + // } + + // contentFile, err := json.Marshal(data) + // require.NoError(t, err) + // rollapp1.GetNode().WriteFile(ctx, contentFile, "./ibcmetadata.json") + // deposit := "500000000000" + rollapp1.Config().Denom + // rollapp1.GetNode().HostName() + // _, err = rollapp1.GetNode().RegisterIBCTokenDenomProposal(ctx, rollappUser.KeyName(), deposit, rollapp1.GetNode().HomeDir()+"/ibcmetadata.json") + // require.NoError(t, err) + + // err = rollapp1.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) + // require.NoError(t, err, "failed to submit votes") + + // height, err := rollapp1.Height(ctx) + // require.NoError(t, err, "error fetching height") + // _, err = cosmos.PollForProposalStatus(ctx, rollapp1.CosmosChain, height, height+30, "1", cosmos.ProposalStatusPassed) + // require.NoError(t, err, "proposal status did not change to passed") + + // // Compose an IBC transfer and send from dymension -> rollapp + // transferData = ibc.WalletData{ + // Address: rollappUserAddr, + // Denom: dymension.Config().Denom, + // Amount: transferAmount.Mul(math.NewInt(5)), + // } + + // // Compose an IBC transfer and send from Hub -> rollapp + // _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + // require.NoError(t, err) + + // // Assert balance was updated on the hub + // testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferData.Amount)) + + // err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + // require.NoError(t, err) + + // // Check fund was set to erc20 module account on rollapp + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // rollappErc20MaccBalance, err := rollapp1.GetBalance(ctx, erc20MAccAddr, dymensionIBCDenom) + // require.NoError(t, err) + + // require.True(t, rollappErc20MaccBalance.Equal(transferData.Amount)) + // require.NoError(t, err) + + // tokenPair, err := rollapp1.GetNode().QueryErc20TokenPair(ctx, dymensionIBCDenom) + // require.NoError(t, err) + // require.NotNil(t, tokenPair) + + // // convert erc20 + // _, err = rollapp1.GetNode().ConvertErc20(ctx, rollappUser.KeyName(), tokenPair.Erc20Address, transferData.Amount.String(), rollappUserAddr, rollappUserAddr, rollapp1.Config().ChainID) + // require.NoError(t, err, "can not convert erc20 to cosmos coin") + + // err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + // require.NoError(t, err) + // testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, transferData.Amount) + + // StartDB(ctx, t, client, network) + + dymHomeDir := strings.Split(dymension.Validators[0].HomeDir(), "/") + dymFolderName := dymHomeDir[len(dymHomeDir)-1] + + membersData, err := os.ReadFile(fmt.Sprintf("/tmp/%s/members.json", dymFolderName)) + require.NoError(t, err) + + var members MembersJSON + err = json.Unmarshal(membersData, &members) + require.NoError(t, err) + + newAddress := dymensionUserAddr + for i := range members.Members { + members.Members[i].Address = newAddress + } + + updatedJSON, err := json.MarshalIndent(members, "", " ") + require.NoError(t, err) + + err = os.WriteFile(fmt.Sprintf("/tmp/%s/members.json", dymFolderName), updatedJSON, 0755) + require.NoError(t, err) + + cmd = []string{"group", "create-group", "operator", "==A", dymension.GetNode().HomeDir() + "/members.json", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + txHash, err := dymension.GetNode().ExecTx(ctx, "operator", cmd...) + fmt.Println(txHash) + require.NoError(t, err) + + cmd = []string{"group", "create-group-policy", "operator", "1", "==A", dymension.GetNode().HomeDir() + "/policy.json", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + txHash, err = dymension.GetNode().ExecTx(ctx, "operator", cmd...) + + fmt.Println(txHash) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 5, dymension) + + policiesGroup, err := dymension.GetNode().QueryGroupPoliciesByAdmin(ctx, operatorAddr) + require.NoError(t, err) + policyAddr := policiesGroup.GroupPolicies[0].Address + + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+"adym", "rollappwasm_1234-1", "adym", "0.1", "1000000"+"adym", "0.1", true) + fmt.Println(txHash) + require.NoError(t, err) + + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp2.KeyName(), policyAddr, "10000"+rollappIBCDenom, "rollappwasm_1234-1", rollappIBCDenom, "0.1", "10000"+rollappIBCDenom, "0.1", true) + fmt.Println(txHash) + require.NoError(t, err) + + 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.Gas.Fees = "100adym" + config.LogLevel = "debug" + config.OrderPolling.Interval = 30 * time.Second + config.OrderPolling.Enabled = false + config.Fulfillers.KeyringBackend = "test" + config.Fulfillers.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.Fulfillers.Scale = 10 + config.Fulfillers.MaxOrdersPerTx = 5 + config.Fulfillers.PolicyAddress = policyAddr + config.Validation.FallbackLevel = "p2p" + config.Validation.WaitTime = 5 * time.Minute + config.Validation.Interval = 10 * time.Second + config.Operator.AccountName = "operator" + config.Operator.GroupID = 1 + config.Operator.KeyringBackend = "test" + config.Operator.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.Operator.MinFeeShare = "0.1" + config.Rollapps = map[string]RollappConfig{ + "rollappwasm_1234-1": { + FullNodes: []string{fmt.Sprintf("http://ra-rollappwasm_1234-1-fn-0-%s:26657", t.Name())}, + MinConfirmations: 1, + }, + } + config.Slack.Enabled = false + config.Slack.AppToken = "" + config.Slack.ChannelID = "" + + // 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: dymensionUserAddr, + 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.ChannelID, rollappUserAddr, 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) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + 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, dymensionUserAddr, rollappIBCDenom, transferData.Amount.Sub(bridgingFee)) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + +func Test_EIBC_Client_Timeout_EVM(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + 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" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides := make(map[string]any) + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + // Create chain factory with dymension + modifyEVMGenesisKV := append( + rollappEVMGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + cosmos.GenesisKV{ + Key: "app_state.erc20.params.enable_erc20", + Value: false, + }, + ) + + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 1 + 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(modifyEVMGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + StartDA(ctx, t, client, network) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 2, dymension) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, lp1, rollappUser := users[0], users[1], users[2] + + dymensionUserAddr := dymensionUser.FormattedAddress() + lp1Addr := lp1.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // create operator + cmd := []string{"keys", "add", "operator", + "--coin-type", dymension.GetNode().Chain.Config().CoinType, + "--keyring-backend", "test", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + + _, _, err = dymension.GetNode().ExecBin(ctx, cmd...) + require.NoError(t, err) + + cmd = []string{dymension.GetNode().Chain.Config().Bin, "keys", "show", "--address", "operator", + "--home", dymension.GetNode().HomeDir(), + "--keyring-backend", "test", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + stdout, _, err := dymension.GetNode().Exec(ctx, cmd, nil) + require.NoError(t, err) + + operatorAddr := string(bytes.TrimSuffix(stdout, []byte("\n"))) + println("Done for set up operator: ", operatorAddr) + + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: operatorAddr, + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + dymHomeDir := strings.Split(dymension.Validators[0].HomeDir(), "/") + dymFolderName := dymHomeDir[len(dymHomeDir)-1] + + membersData, err := os.ReadFile(fmt.Sprintf("/tmp/%s/members.json", dymFolderName)) + require.NoError(t, err) + + var members MembersJSON + err = json.Unmarshal(membersData, &members) + require.NoError(t, err) + + newAddress := dymensionUserAddr + for i := range members.Members { + members.Members[i].Address = newAddress + } + + updatedJSON, err := json.MarshalIndent(members, "", " ") + require.NoError(t, err) + + err = os.WriteFile(fmt.Sprintf("/tmp/%s/members.json", dymFolderName), updatedJSON, 0755) + require.NoError(t, err) + + cmd = []string{"group", "create-group", "operator", "==A", dymension.GetNode().HomeDir() + "/members.json", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + txHash, err := dymension.GetNode().ExecTx(ctx, "operator", cmd...) + fmt.Println(txHash) + require.NoError(t, err) + + cmd = []string{"group", "create-group-policy", "operator", "1", "==A", dymension.GetNode().HomeDir() + "/policy.json", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + txHash, err = dymension.GetNode().ExecTx(ctx, "operator", cmd...) + + fmt.Println(txHash) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 5, dymension) + + policiesGroup, err := dymension.GetNode().QueryGroupPoliciesByAdmin(ctx, operatorAddr) + require.NoError(t, err) + policyAddr := policiesGroup.GroupPolicies[0].Address + + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+dymension.Config().Denom, "rollappevm_1234-1", dymension.Config().Denom, "0.0001", "1000000"+dymension.Config().Denom, "0.0001", false) + fmt.Println(txHash) + require.NoError(t, err) + + 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.Gas.Fees = "100adym" + config.LogLevel = "debug" + config.OrderPolling.Interval = 30 * time.Second + config.OrderPolling.Enabled = false + config.Fulfillers.KeyringBackend = "test" + config.Fulfillers.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.Fulfillers.Scale = 10 + config.Fulfillers.MaxOrdersPerTx = 5 + config.Fulfillers.PolicyAddress = policyAddr + config.Validation.FallbackLevel = "p2p" + config.Validation.WaitTime = 5 * time.Minute + config.Validation.Interval = 10 * time.Second + config.Operator.AccountName = "operator" + config.Operator.GroupID = 1 + config.Operator.KeyringBackend = "test" + config.Operator.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.Operator.MinFeeShare = "0.0001" + config.Rollapps = map[string]RollappConfig{ + "rollappevm_1234-1": { + FullNodes: []string{fmt.Sprintf("http://ra-rollappevm_1234-1-fn-0-%s:26657", t.Name())}, + MinConfirmations: 1, + }, + } + config.Slack.Enabled = false + config.Slack.AppToken = "" + config.Slack.ChannelID = "" + + // 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 Hub -> RA + transferData := ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // set eIBC specific memo + var options ibc.TransferOptions + + // Set a short timeout for IBC transfer + options = ibc.TransferOptions{ + Timeout: &ibc.IBCTimeout{ + NanoSeconds: 1000000, // 1 ms - this will cause the transfer to timeout before it is picked by a relayer + }, + } + + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, 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) + + // wait until the packet is finalized + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + 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, dymensionUserAddr, dymension.Config().Denom, walletAmount.SubRaw(1500)) + // upon timeout error eibc should be created, and eibc should fulfill it + // lp should get his funds after claiming the finalized tx + testutil.AssertBalance(t, ctx, dymension, lp1Addr, dymension.Config().Denom, walletAmount.Sub(transferAmount).AddRaw(1500)) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + +func Test_EIBC_Client_Timeout_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + 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"] = "rollappwasm_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" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides := make(map[string]any) + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + // Create chain factory with dymension + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 1 + numRollAppVals := 1 + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + StartDA(ctx, t, client, network) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 2, dymension) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, lp1, rollappUser := users[0], users[1], users[2] + + dymensionUserAddr := dymensionUser.FormattedAddress() + lp1Addr := lp1.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // create operator + cmd := []string{"keys", "add", "operator", + "--coin-type", dymension.GetNode().Chain.Config().CoinType, + "--keyring-backend", "test", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + + _, _, err = dymension.GetNode().ExecBin(ctx, cmd...) + require.NoError(t, err) + + cmd = []string{dymension.GetNode().Chain.Config().Bin, "keys", "show", "--address", "operator", + "--home", dymension.GetNode().HomeDir(), + "--keyring-backend", "test", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + stdout, _, err := dymension.GetNode().Exec(ctx, cmd, nil) + require.NoError(t, err) + + operatorAddr := string(bytes.TrimSuffix(stdout, []byte("\n"))) + println("Done for set up operator: ", operatorAddr) + + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: operatorAddr, + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + dymHomeDir := strings.Split(dymension.Validators[0].HomeDir(), "/") + dymFolderName := dymHomeDir[len(dymHomeDir)-1] + + membersData, err := os.ReadFile(fmt.Sprintf("/tmp/%s/members.json", dymFolderName)) + require.NoError(t, err) + + var members MembersJSON + err = json.Unmarshal(membersData, &members) + require.NoError(t, err) + + newAddress := dymensionUserAddr + for i := range members.Members { + members.Members[i].Address = newAddress + } + + updatedJSON, err := json.MarshalIndent(members, "", " ") + require.NoError(t, err) + + err = os.WriteFile(fmt.Sprintf("/tmp/%s/members.json", dymFolderName), updatedJSON, 0755) + require.NoError(t, err) + + cmd = []string{"group", "create-group", "operator", "==A", dymension.GetNode().HomeDir() + "/members.json", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + txHash, err := dymension.GetNode().ExecTx(ctx, "operator", cmd...) + fmt.Println(txHash) + require.NoError(t, err) + + cmd = []string{"group", "create-group-policy", "operator", "1", "==A", dymension.GetNode().HomeDir() + "/policy.json", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + txHash, err = dymension.GetNode().ExecTx(ctx, "operator", cmd...) + + fmt.Println(txHash) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 5, dymension) + + policiesGroup, err := dymension.GetNode().QueryGroupPoliciesByAdmin(ctx, operatorAddr) + require.NoError(t, err) + policyAddr := policiesGroup.GroupPolicies[0].Address + + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+dymension.Config().Denom, "rollappwasm_1234-1", dymension.Config().Denom, "0.0001", "1000000"+dymension.Config().Denom, "0.0001", false) + fmt.Println(txHash) + require.NoError(t, err) + + 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.Gas.Fees = "100adym" + config.LogLevel = "debug" + config.OrderPolling.Interval = 30 * time.Second + config.OrderPolling.Enabled = false + config.Fulfillers.KeyringBackend = "test" + config.Fulfillers.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.Fulfillers.Scale = 10 + config.Fulfillers.MaxOrdersPerTx = 5 + config.Fulfillers.PolicyAddress = policyAddr + config.Validation.FallbackLevel = "p2p" + config.Validation.WaitTime = 5 * time.Minute + config.Validation.Interval = 10 * time.Second + config.Operator.AccountName = "operator" + config.Operator.GroupID = 1 + config.Operator.KeyringBackend = "test" + config.Operator.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) + config.Operator.MinFeeShare = "0.0001" + config.Rollapps = map[string]RollappConfig{ + "rollappwasm_1234-1": { + FullNodes: []string{fmt.Sprintf("http://ra-rollappwasm_1234-1-fn-0-%s:26657", t.Name())}, + MinConfirmations: 1, + }, + } + config.Slack.Enabled = false + config.Slack.AppToken = "" + config.Slack.ChannelID = "" + + // 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 Hub -> RA + transferData := ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // set eIBC specific memo + var options ibc.TransferOptions + + // Set a short timeout for IBC transfer + options = ibc.TransferOptions{ + Timeout: &ibc.IBCTimeout{ + NanoSeconds: 1000000, // 1 ms - this will cause the transfer to timeout before it is picked by a relayer + }, + } + + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, 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) + + // wait until the packet is finalized + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + 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, dymensionUserAddr, dymension.Config().Denom, walletAmount.SubRaw(1500)) + // upon timeout error eibc should be created, and eibc should fulfill it + // lp should get his funds after claiming the finalized tx + testutil.AssertBalance(t, ctx, dymension, lp1Addr, dymension.Config().Denom, walletAmount.Sub(transferAmount).AddRaw(1500)) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + +func Test_EIBC_Client_AckErr_EVM(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + 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" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides := make(map[string]any) + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + // Create chain factory with dymension + modifyEVMGenesisKV := append( + rollappEVMGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + cosmos.GenesisKV{ + Key: "app_state.erc20.params.enable_erc20", + Value: false, + }, + ) + + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 1 + 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(modifyEVMGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + StartDA(ctx, t, client, network) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 2, dymension) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, lp1, _ := users[0], users[1], users[2] + + dymensionUserAddr := dymensionUser.FormattedAddress() + lp1Addr := lp1.FormattedAddress() + + // create operator + cmd := []string{"keys", "add", "operator", + "--coin-type", dymension.GetNode().Chain.Config().CoinType, + "--keyring-backend", "test", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + + _, _, err = dymension.GetNode().ExecBin(ctx, cmd...) + require.NoError(t, err) + + cmd = []string{dymension.GetNode().Chain.Config().Bin, "keys", "show", "--address", "operator", + "--home", dymension.GetNode().HomeDir(), + "--keyring-backend", "test", + "--keyring-dir", dymension.GetNode().HomeDir(), + } + stdout, _, err := dymension.GetNode().Exec(ctx, cmd, nil) + require.NoError(t, err) + + operatorAddr := string(bytes.TrimSuffix(stdout, []byte("\n"))) + println("Done for set up operator: ", operatorAddr) - // tokenPair, err := rollapp1.GetNode().QueryErc20TokenPair(ctx, dymensionIBCDenom) - // require.NoError(t, err) - // require.NotNil(t, tokenPair) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: operatorAddr, + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) - // // convert erc20 - // _, err = rollapp1.GetNode().ConvertErc20(ctx, rollappUser.KeyName(), tokenPair.Erc20Address, transferData.Amount.String(), rollappUserAddr, rollappUserAddr, rollapp1.Config().ChainID) - // require.NoError(t, err, "can not convert erc20 to cosmos coin") + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) - // err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) - // require.NoError(t, err) - // testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, transferData.Amount) + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) - // StartDB(ctx, t, client, network) + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) dymHomeDir := strings.Split(dymension.Validators[0].HomeDir(), "/") dymFolderName := dymHomeDir[len(dymHomeDir)-1] @@ -1219,11 +3743,7 @@ func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { require.NoError(t, err) policyAddr := policiesGroup.GroupPolicies[0].Address - txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+"adym", "rollappevm_1234-1", "adym", "0.1", "1000000"+"adym", "0.1", true) - fmt.Println(txHash) - require.NoError(t, err) - - txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp2.KeyName(), policyAddr, "10000"+rollappIBCDenom, "rollappevm_1234-1", rollappIBCDenom, "0.1", "10000"+rollappIBCDenom, "0.1", true) + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+dymension.Config().Denom, "rollappevm_1234-1", dymension.Config().Denom, "0.0001", "1000000"+dymension.Config().Denom, "0.0001", false) fmt.Println(txHash) require.NoError(t, err) @@ -1257,7 +3777,7 @@ func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { config.Operator.GroupID = 1 config.Operator.KeyringBackend = "test" config.Operator.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) - config.Operator.MinFeeShare = "0.1" + config.Operator.MinFeeShare = "0.0001" config.Rollapps = map[string]RollappConfig{ "rollappevm_1234-1": { FullNodes: []string{fmt.Sprintf("http://ra-rollappevm_1234-1-fn-0-%s:26657", t.Name())}, @@ -1296,22 +3816,17 @@ func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) require.NoError(t, err) - // Send a ibc tx from RA -> Hub - transferData = ibc.WalletData{ - Address: dymensionUserAddr, - Denom: rollapp1.Config().Denom, + // Send a ibc tx from Hub -> RA + transferData := ibc.WalletData{ + Address: "rollappUserAddr", + Denom: dymension.Config().Denom, Amount: transferAmount, } - multiplier := math.NewInt(10) - - eibcFee := transferAmount.Quo(multiplier) - - // set eIBC specific memo - var options ibc.TransferOptions - options.Memo = BuildEIbcMemo(eibcFee) + dymHeight, err := dymension.GetNode().Height(ctx) + require.NoError(t, err) - _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, transferData, options) + ibcTx, err := dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) require.NoError(t, err) // get eIbc event @@ -1321,18 +3836,23 @@ func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { fmt.Println(i, "EIBC Event:", eibcEvent) } - rollappHeight, err = rollapp1.GetNode().Height(ctx) + ack, err := testutil.PollForAck(ctx, dymension, dymHeight, dymHeight+30, ibcTx.Packet) 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)) + fmt.Println("ack:", ack.Acknowledgement) + + // Make sure that the ack contains error + require.True(t, bytes.Contains(ack.Acknowledgement, []byte("error"))) + + rollappHeight, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err) // wait until the packet is finalized - isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) require.NoError(t, err) require.True(t, isFinalized) - res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) fmt.Println(res) require.NoError(t, err) @@ -1348,17 +3868,17 @@ func Test_EIBC_Client_NoFulfillRollapp_EVM(t *testing.T) { fmt.Println(txhash) } - 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, dymensionUserAddr, rollappIBCDenom, transferData.Amount.Sub(bridgingFee)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.SubRaw(1500)) + // upon timeout error eibc should be created, and eibc should fulfill it + // lp should get his funds after claiming the finalized tx + testutil.AssertBalance(t, ctx, dymension, lp1Addr, dymension.Config().Denom, walletAmount.Sub(transferAmount).AddRaw(1500)) // Run invariant check CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } -func Test_EIBC_Client_Timeout_EVM(t *testing.T) { +func Test_EIBC_Client_AckErr_Wasm(t *testing.T) { if testing.Short() { t.Skip() } @@ -1368,7 +3888,7 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { 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["rollapp_id"] = "rollappwasm_1234-1" dymintTomlOverrides["settlement_gas_prices"] = "0adym" dymintTomlOverrides["max_idle_time"] = "3s" dymintTomlOverrides["max_proof_time"] = "500ms" @@ -1380,16 +3900,12 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { configFileOverrides["config/dymint.toml"] = dymintTomlOverrides // Create chain factory with dymension - modifyEVMGenesisKV := append( - rollappEVMGenesisKV, + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, cosmos.GenesisKV{ Key: "app_state.rollappparams.params.da", Value: "grpc", }, - cosmos.GenesisKV{ - Key: "app_state.erc20.params.enable_erc20", - Value: false, - }, ) numHubVals := 1 @@ -1403,18 +3919,18 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { ChainConfig: ibc.ChainConfig{ Type: "rollapp-dym", Name: "rollapp-temp", - ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappEVMImage}, + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, Bin: "rollappd", - Bech32Prefix: "ethm", + Bech32Prefix: "rol", Denom: "urax", - CoinType: "60", + CoinType: "118", GasPrices: "0.0urax", GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, - ModifyGenesis: modifyRollappEVMGenesis(modifyEVMGenesisKV), + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), ConfigFileOverrides: configFileOverrides, }, NumValidators: &numRollAppVals, @@ -1494,7 +4010,7 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { }, nil, "", nil, true, 1179360, true) require.NoError(t, err) - containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) // Get the container details containerJSON, err := client.ContainerInspect(context.Background(), containerID) @@ -1587,11 +4103,10 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, rollapp1) // Get our Bech32 encoded user addresses - dymensionUser, lp1, rollappUser := users[0], users[1], users[2] + dymensionUser, lp1, _ := users[0], users[1], users[2] dymensionUserAddr := dymensionUser.FormattedAddress() lp1Addr := lp1.FormattedAddress() - rollappUserAddr := rollappUser.FormattedAddress() // create operator cmd := []string{"keys", "add", "operator", @@ -1672,7 +4187,7 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { require.NoError(t, err) policyAddr := policiesGroup.GroupPolicies[0].Address - txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+dymension.Config().Denom, "rollappevm_1234-1", dymension.Config().Denom, "0.0001", "1000000"+dymension.Config().Denom, "0.0001", false) + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+dymension.Config().Denom, "rollappwasm_1234-1", dymension.Config().Denom, "0.0001", "1000000"+dymension.Config().Denom, "0.0001", false) fmt.Println(txHash) require.NoError(t, err) @@ -1708,8 +4223,8 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { config.Operator.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) config.Operator.MinFeeShare = "0.0001" config.Rollapps = map[string]RollappConfig{ - "rollappevm_1234-1": { - FullNodes: []string{fmt.Sprintf("http://ra-rollappevm_1234-1-fn-0-%s:26657", t.Name())}, + "rollappwasm_1234-1": { + FullNodes: []string{fmt.Sprintf("http://ra-rollappwasm_1234-1-fn-0-%s:26657", t.Name())}, MinConfirmations: 1, }, } @@ -1747,22 +4262,15 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { // Send a ibc tx from Hub -> RA transferData := ibc.WalletData{ - Address: rollappUserAddr, + Address: "rollappUserAddr", Denom: dymension.Config().Denom, Amount: transferAmount, } - // set eIBC specific memo - var options ibc.TransferOptions - - // Set a short timeout for IBC transfer - options = ibc.TransferOptions{ - Timeout: &ibc.IBCTimeout{ - NanoSeconds: 1000000, // 1 ms - this will cause the transfer to timeout before it is picked by a relayer - }, - } + dymHeight, err := dymension.GetNode().Height(ctx) + require.NoError(t, err) - _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, options) + ibcTx, err := dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) require.NoError(t, err) // get eIbc event @@ -1772,6 +4280,14 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { fmt.Println(i, "EIBC Event:", eibcEvent) } + ack, err := testutil.PollForAck(ctx, dymension, dymHeight, dymHeight+30, ibcTx.Packet) + require.NoError(t, err) + + fmt.Println("ack:", ack.Acknowledgement) + + // Make sure that the ack contains error + require.True(t, bytes.Contains(ack.Acknowledgement, []byte("error"))) + rollappHeight, err := rollapp1.GetNode().Height(ctx) require.NoError(t, err) @@ -1796,9 +4312,6 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { fmt.Println(txhash) } - 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, dymensionUserAddr, dymension.Config().Denom, walletAmount.SubRaw(1500)) // upon timeout error eibc should be created, and eibc should fulfill it @@ -1809,7 +4322,7 @@ func Test_EIBC_Client_Timeout_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } -func Test_EIBC_Client_AckErr_EVM(t *testing.T) { +func Test_EIBC_Client_Update_Order_EVM(t *testing.T) { if testing.Short() { t.Skip() } @@ -1837,10 +4350,6 @@ func Test_EIBC_Client_AckErr_EVM(t *testing.T) { Key: "app_state.rollappparams.params.da", Value: "grpc", }, - cosmos.GenesisKV{ - Key: "app_state.erc20.params.enable_erc20", - Value: false, - }, ) numHubVals := 1 @@ -2038,10 +4547,11 @@ func Test_EIBC_Client_AckErr_EVM(t *testing.T) { users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, rollapp1) // Get our Bech32 encoded user addresses - dymensionUser, lp1, _ := users[0], users[1], users[2] + dymensionUser, lp1, rollappUser := users[0], users[1], users[2] dymensionUserAddr := dymensionUser.FormattedAddress() lp1Addr := lp1.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() // create operator cmd := []string{"keys", "add", "operator", @@ -2080,6 +4590,55 @@ func Test_EIBC_Client_AckErr_EVM(t *testing.T) { err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) require.NoError(t, err) + // Send a normal ibc tx from RA -> Hub + transferData := ibc.WalletData{ + Address: lp1Addr, + Denom: rollapp1.Config().Denom, + Amount: bigTransferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, lp1Addr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, lp1Addr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + 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() + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, lp1Addr, rollappIBCDenom, transferData.Amount.Sub(bigBridgingFee)) + dymHomeDir := strings.Split(dymension.Validators[0].HomeDir(), "/") dymFolderName := dymHomeDir[len(dymHomeDir)-1] @@ -2122,7 +4681,7 @@ func Test_EIBC_Client_AckErr_EVM(t *testing.T) { require.NoError(t, err) policyAddr := policiesGroup.GroupPolicies[0].Address - txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+dymension.Config().Denom, "rollappevm_1234-1", dymension.Config().Denom, "0.0001", "1000000"+dymension.Config().Denom, "0.0001", false) + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+rollappIBCDenom, "rollappevm_1234-1", rollappIBCDenom, "0.1", "1000000"+rollappIBCDenom, "0.1", false) fmt.Println(txHash) require.NoError(t, err) @@ -2156,7 +4715,7 @@ func Test_EIBC_Client_AckErr_EVM(t *testing.T) { config.Operator.GroupID = 1 config.Operator.KeyringBackend = "test" config.Operator.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) - config.Operator.MinFeeShare = "0.0001" + config.Operator.MinFeeShare = "0.1" config.Rollapps = map[string]RollappConfig{ "rollappevm_1234-1": { FullNodes: []string{fmt.Sprintf("http://ra-rollappevm_1234-1-fn-0-%s:26657", t.Name())}, @@ -2195,43 +4754,51 @@ func Test_EIBC_Client_AckErr_EVM(t *testing.T) { err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) require.NoError(t, err) - // Send a ibc tx from Hub -> RA - transferData := ibc.WalletData{ - Address: "rollappUserAddr", - Denom: dymension.Config().Denom, + // Send a ibc tx from RA -> Hub + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, Amount: transferAmount, } - dymHeight, err := dymension.GetNode().Height(ctx) - require.NoError(t, err) + multiplier := math.NewInt(1000) - ibcTx, err := dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + eibcFee := transferAmount.Quo(multiplier) + + // set eIBC specific memo + var options ibc.TransferOptions + options.Memo = BuildEIbcMemo(eibcFee) + + _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, 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) - } + fmt.Println("Event:", eibcEvents[0]) - ack, err := testutil.PollForAck(ctx, dymension, dymHeight, dymHeight+30, ibcTx.Packet) - require.NoError(t, err) + multiplier = math.NewInt(10) - fmt.Println("ack:", ack.Acknowledgement) + newEibcFee := transferAmount.Quo(multiplier) - // Make sure that the ack contains error - require.True(t, bytes.Contains(ack.Acknowledgement, []byte("error"))) + _, err = dymension.UpdateDemandOrder(ctx, eibcEvents[0].OrderId, dymensionUserAddr, newEibcFee) + require.NoError(t, err) - rollappHeight, err := rollapp1.GetNode().Height(ctx) + err = testutil.WaitForBlocks(ctx, 5, dymension) + 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).Sub(bigTransferAmount)) + // wait until the packet is finalized - isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) require.NoError(t, err) require.True(t, isFinalized) - res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) fmt.Println(res) require.NoError(t, err) @@ -2247,17 +4814,17 @@ func Test_EIBC_Client_AckErr_EVM(t *testing.T) { fmt.Println(txhash) } + 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, dymensionUserAddr, dymension.Config().Denom, walletAmount.SubRaw(1500)) - // upon timeout error eibc should be created, and eibc should fulfill it - // lp should get his funds after claiming the finalized tx - testutil.AssertBalance(t, ctx, dymension, lp1Addr, dymension.Config().Denom, walletAmount.Sub(transferAmount).AddRaw(1500)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferData.Amount.Sub(bridgingFee).Sub(newEibcFee)) // Run invariant check CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } -func Test_EIBC_Client_Update_Order_EVM(t *testing.T) { +func Test_EIBC_Client_Update_Order_Wasm(t *testing.T) { if testing.Short() { t.Skip() } @@ -2267,7 +4834,7 @@ func Test_EIBC_Client_Update_Order_EVM(t *testing.T) { 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["rollapp_id"] = "rollappwasm_1234-1" dymintTomlOverrides["settlement_gas_prices"] = "0adym" dymintTomlOverrides["max_idle_time"] = "3s" dymintTomlOverrides["max_proof_time"] = "500ms" @@ -2279,8 +4846,8 @@ func Test_EIBC_Client_Update_Order_EVM(t *testing.T) { configFileOverrides["config/dymint.toml"] = dymintTomlOverrides // Create chain factory with dymension - modifyEVMGenesisKV := append( - rollappEVMGenesisKV, + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, cosmos.GenesisKV{ Key: "app_state.rollappparams.params.da", Value: "grpc", @@ -2298,18 +4865,18 @@ func Test_EIBC_Client_Update_Order_EVM(t *testing.T) { ChainConfig: ibc.ChainConfig{ Type: "rollapp-dym", Name: "rollapp-temp", - ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappEVMImage}, + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, Bin: "rollappd", - Bech32Prefix: "ethm", + Bech32Prefix: "rol", Denom: "urax", - CoinType: "60", + CoinType: "118", GasPrices: "0.0urax", GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, - ModifyGenesis: modifyRollappEVMGenesis(modifyEVMGenesisKV), + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), ConfigFileOverrides: configFileOverrides, }, NumValidators: &numRollAppVals, @@ -2389,7 +4956,7 @@ func Test_EIBC_Client_Update_Order_EVM(t *testing.T) { }, nil, "", nil, true, 1179360, true) require.NoError(t, err) - containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) // Get the container details containerJSON, err := client.ContainerInspect(context.Background(), containerID) @@ -2616,7 +5183,7 @@ func Test_EIBC_Client_Update_Order_EVM(t *testing.T) { require.NoError(t, err) policyAddr := policiesGroup.GroupPolicies[0].Address - txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+rollappIBCDenom, "rollappevm_1234-1", rollappIBCDenom, "0.1", "1000000"+rollappIBCDenom, "0.1", false) + txHash, err = dymension.GetNode().GrantAuthorization(ctx, lp1.KeyName(), policyAddr, "1000000"+rollappIBCDenom, "rollappwasm_1234-1", rollappIBCDenom, "0.1", "1000000"+rollappIBCDenom, "0.1", false) fmt.Println(txHash) require.NoError(t, err) @@ -2652,8 +5219,8 @@ func Test_EIBC_Client_Update_Order_EVM(t *testing.T) { config.Operator.KeyringDir = fmt.Sprintf("/root/%s", dymensionFolderName) config.Operator.MinFeeShare = "0.1" config.Rollapps = map[string]RollappConfig{ - "rollappevm_1234-1": { - FullNodes: []string{fmt.Sprintf("http://ra-rollappevm_1234-1-fn-0-%s:26657", t.Name())}, + "rollappwasm_1234-1": { + FullNodes: []string{fmt.Sprintf("http://ra-rollappwasm_1234-1-fn-0-%s:26657", t.Name())}, MinConfirmations: 1, }, } diff --git a/tests/eibc_corrupted_memo_test.go b/tests/eibc_corrupted_memo_test.go index b2c3fe11..6370945d 100644 --- a/tests/eibc_corrupted_memo_test.go +++ b/tests/eibc_corrupted_memo_test.go @@ -301,7 +301,291 @@ func TestEIBCCorruptedMemoNegative_EVM(t *testing.T) { }, ) + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + +func TestEIBCCorruptedMemoNegative_Wasm(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"] = "rollappwasm_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 + + // 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: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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, + }, + 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) + dymension := chains[1].(*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) + const ibcPath = "ibc-path" + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, dymensionUser2, dymensionUser3, rollappUser := users[0], users[1], users[2], users[3] + + dymensionUserAddr := dymensionUser.FormattedAddress() + dymensionUserAddr2 := dymensionUser2.FormattedAddress() + dymensionUserAddr3 := dymensionUser3.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // Assert the accounts were funded + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr2, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr3, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + 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: transferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 10, 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() + // end of preconditions + + var options ibc.TransferOptions + // set eIBC specific memo + + multiplier := math.NewInt(10) + eibcFee := transferAmount.Quo(multiplier) // transferAmount * 0.1 + + options.Memo = BuildEIbcMemo(eibcFee) + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, transferData, options) + require.NoError(t, err) + + invalidMemo2 := `{"eibc": {"feebaba": "200"}}` + options.Memo = invalidMemo2 + transferData = ibc.WalletData{ + Address: dymensionUserAddr2, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, transferData, options) + require.NoError(t, err) + + invalidMemo3 := `{"eibc": {"fee": "this-should-be-number"}}` + options.Memo = invalidMemo3 + transferData = ibc.WalletData{ + Address: dymensionUserAddr3, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, transferData, options) + require.NoError(t, err) + + // get eIbc events + eibcEvents, _ := getEIbcEventsWithinBlockRange(ctx, dymension, 45, false) + fmt.Println(eibcEvents) + require.True(t, len(eibcEvents) == 1) // verify 1 EIBC event was registered on the hub + + rollappHeight, err = rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee).MulRaw(2)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr2, rollappIBCDenom, zeroBal) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr3, rollappIBCDenom, zeroBal) + + t.Cleanup( + func() { + err := r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) + // Run invariant check CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } + diff --git a/tests/eibc_fee_test.go b/tests/eibc_fee_test.go index 75c18180..c5aec90a 100644 --- a/tests/eibc_fee_test.go +++ b/tests/eibc_fee_test.go @@ -282,3 +282,264 @@ func TestEIBCFeeTooHigh_EVM(t *testing.T) { // Run invariant check CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } + +func TestEIBCFeeTooHigh_Wasm(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"] = "rollappwasm_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 + + // 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: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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: "118", + GasPrices: "0.0adym", + EncodingConfig: encodingConfig(), + GasAdjustment: 1.1, + TrustingPeriod: "112h", + NoHostMount: false, + ModifyGenesis: modifyDymensionGenesis(dymensionGenesisKV), + ConfigFileOverrides: nil, + }, + 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) + dymension := chains[1].(*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, "relayer1", network) + const ibcPath = "ibc-path" + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer1"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // Assert the accounts were funded + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount) + + eibcFee := math.NewInt(2_000_000) // set fee to be more than a transfer amount + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + 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: transferAmount, + } + _, 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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 10, 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() + // end of preconditions + + var options ibc.TransferOptions + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + // set eIBC specific memo + options.Memo = BuildEIbcMemo(eibcFee) + + _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, transferData, options) + require.NoError(t, err) + + // balance right after sending IBC transfer + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount).Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferData.Amount.Sub(bridgingFee)) + + // get eIbc event + eibcEvents, _ := getEIbcEventsWithinBlockRange(ctx, dymension, 30, false) + fmt.Println(eibcEvents) + require.True(t, len(eibcEvents) == 0) // verify there were no eibc events registered on the hub + + rollappHeight, err = rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferData.Amount.Sub(bridgingFee)) + + t.Cleanup( + func() { + err := r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} diff --git a/tests/eibc_fulfillment_test.go b/tests/eibc_fulfillment_test.go index 5cbf8d59..dbba89ba 100644 --- a/tests/eibc_fulfillment_test.go +++ b/tests/eibc_fulfillment_test.go @@ -2156,6 +2156,433 @@ func TestEIBCFulfillment_two_rollapps_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } +func TestEIBCFulfillment_two_rollapps_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp 1 + settlement_layer_rollapp1 := "dymension" + settlement_node_address := fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + rollapp1_id := "rollappwasm_1234-1" + gas_price_rollapp1 := "0adym" + maxIdleTime1 := "10s" + maxProofTime := "500ms" + configFileOverrides1 := overridesDymintToml(settlement_layer_rollapp1, settlement_node_address, rollapp1_id, gas_price_rollapp1, maxIdleTime1, maxProofTime, "50s") + + // setup config for rollapp 2 + settlement_layer_rollapp2 := "dymension" + rollapp2_id := "decentrio_12345-1" + gas_price_rollapp2 := "0adym" + maxIdleTime2 := "1s" + configFileOverrides2 := overridesDymintToml(settlement_layer_rollapp2, settlement_node_address, rollapp2_id, gas_price_rollapp2, maxIdleTime2, maxProofTime, "50s") + + // 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: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + ConfigFileOverrides: configFileOverrides1, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "rollapp2", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp2", + ChainID: "decentrio_12345-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + 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, + }, + 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) + + // relayer for rollapp 1 + r1 := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer1", network) + + // relayer for rollapp 2 + 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(r1, "relayer1"). + AddRelayer(r2, "relayer2"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r1, + 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, 1179360, true) + require.NoError(t, err) + + wallet1, found := r1.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + wallet2, found := r2.GetWallet(rollapp2.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + keyDir2 := dymension.GetRollApps()[1].GetSequencerKeyDir() + require.NoError(t, err) + keyPath2 := keyDir2 + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet1.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet1.FormattedAddress()}) + require.NoError(t, err) + } + + err = testutil.WaitForBlocks(ctx, 2, dymension) + require.NoError(t, err) + + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath2, []string{wallet2.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath2, []string{wallet2.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r1, 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) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1, rollapp2) + require.NoError(t, err) + + // Get our Bech32 encoded user addresses + dymensionUser, marketMaker, rollappUser, rollapp2User := users[0], users[1], users[2], users[3] + + dymensionUserAddr := dymensionUser.FormattedAddress() + marketMakerAddr := marketMaker.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + rollapp2UserAddr := rollapp2User.FormattedAddress() + + // Assert the accounts were funded + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, dymension, marketMakerAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, rollapp2, rollapp2UserAddr, rollapp2.Config().Denom, walletAmount) + + multiplier := math.NewInt(10) + + eibcFee := transferAmount.Quo(multiplier) // transferAmount * 0.1 + transferAmountWithoutFee := transferAmount.Sub(eibcFee) + + dymChannel_ra1, err := r1.GetChannels(ctx, eRep, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, 1, len(dymChannel_ra1)) + channDymRollApp1 := dymChannel_ra1[0].Counterparty + require.NotEmpty(t, channDymRollApp1.ChannelID) + + dymChannel_ra2, err := r2.GetChannels(ctx, eRep, rollapp2.Config().ChainID) + require.NoError(t, err) + require.Equal(t, 1, len(dymChannel_ra2)) + channDymRollApp2 := dymChannel_ra2[0].Counterparty + require.NotEmpty(t, channDymRollApp2.ChannelID) + + // Start relayer + err = r1.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: marketMakerAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, dymChannel_ra1[0].ChannelID, rollappUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + transferData = ibc.WalletData{ + Address: marketMakerAddr, + Denom: rollapp2.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp2.SendIBCTransfer(ctx, dymChannel_ra2[0].ChannelID, rollapp2UserAddr, 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) + + // wait until the packet is finalized + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + rollapp2Height, err := rollapp2.GetNode().Height(ctx) + require.NoError(t, err) + + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp2.GetChainID(), rollapp2Height, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, marketMakerAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + txhash, err := dymension.GetNode().FinalizePacket(ctx, marketMakerAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom for urax on Hub + rollappTokenDenom := transfertypes.GetPrefixedDenom(dymChannel_ra1[0].Counterparty.PortID, dymChannel_ra1[0].Counterparty.ChannelID, rollapp1.Config().Denom) + rollappIBCDenom := transfertypes.ParseDenomTrace(rollappTokenDenom).IBCDenom() + + // Get the IBC denom for Rollapp 2's token on Hub + rollapp2TokenDenom := transfertypes.GetPrefixedDenom(dymChannel_ra2[0].Counterparty.PortID, dymChannel_ra2[0].Counterparty.ChannelID, rollapp2.Config().Denom) + rollapp2IBCDenom := transfertypes.ParseDenomTrace(rollapp2TokenDenom).IBCDenom() + + var options ibc.TransferOptions + // market maker needs to have funds on the hub first to be able to fulfill incoming demand order + // Minus 0.1% of transfer amount for bridge fee + expMmBalanceRollappDenom := transferAmount.Sub(transferAmount.Quo(math.NewInt(1000))) + balance, err := dymension.GetBalance(ctx, marketMakerAddr, rollappIBCDenom) + require.NoError(t, err) + fmt.Println("Balance of marketMakerAddr after preconditions:", balance) + require.True(t, balance.Equal(expMmBalanceRollappDenom), fmt.Sprintf("Value mismatch. Expected %s, actual %s", expMmBalanceRollappDenom, balance)) + + // Precondition funds check on Hub for Rollapp 2 + balanceRollapp2, err := dymension.GetBalance(ctx, marketMakerAddr, rollapp2IBCDenom) + require.NoError(t, err) + fmt.Println("Balance of marketMakerAddr after preconditions for", rollapp2IBCDenom, ":", balance) + require.True(t, balanceRollapp2.Equal(expMmBalanceRollappDenom), fmt.Sprintf("Value mismatch. Expected %s, actual %s", expMmBalanceRollappDenom, balanceRollapp2)) + // end of preconditions + + transferDataRollapp1 := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + // Send funds from Rollapp 2 to Hub and set eIBC specific memo + transferDataRollapp2 := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp2.Config().Denom, + Amount: transferAmount, + } + + // set eIBC specific memo + options.Memo = BuildEIbcMemo(eibcFee) + + _, err = rollapp2.SendIBCTransfer(ctx, dymChannel_ra2[0].ChannelID, rollapp2UserAddr, transferDataRollapp2, options) + require.NoError(t, err) + // rollapp2Height, err = rollapp2.GetNode().Height(ctx) + // require.NoError(t, err) + zeroBalance := math.NewInt(0) + balance, err = dymension.GetBalance(ctx, dymensionUserAddr, rollapp2IBCDenom) + require.NoError(t, err) + fmt.Println("Balance of dymensionUserAddr right after sending eIBC transfer from rollapp 2 to dym hub:", balance) + require.True(t, balance.Equal(zeroBalance), fmt.Sprintf("Value mismatch. Expected %s, actual %s", zeroBalance, balance)) + + _, err = rollapp1.SendIBCTransfer(ctx, dymChannel_ra1[0].ChannelID, rollappUserAddr, transferDataRollapp1, options) + require.NoError(t, err) + + balance, err = dymension.GetBalance(ctx, dymensionUserAddr, rollappIBCDenom) + require.NoError(t, err) + fmt.Println("Balance of dymensionUserAddr right after sending eIBC transfer from rollapp 1 to dym hub:", balance) + require.True(t, balance.Equal(zeroBalance), fmt.Sprintf("Value mismatch. Expected %s, actual %s", zeroBalance, balance)) + + // get eIbc event + eibcEvents, err := getEIbcEventsWithinBlockRange(ctx, dymension, 10, false) + fmt.Println(eibcEvents) + require.NoError(t, err) + require.Equal(t, "PENDING", eibcEvents[0].PacketStatus) + require.Equal(t, "PENDING", eibcEvents[1].PacketStatus) + + // fulfill demand order 2 + _, err = dymension.FullfillDemandOrder(ctx, eibcEvents[1].OrderId, marketMakerAddr, eibcFee) + require.NoError(t, err) + txhash, err := dymension.FullfillDemandOrder(ctx, eibcEvents[0].OrderId, marketMakerAddr, eibcFee) + require.NoError(t, err) + + eibcEvent := getEibcEventFromTx(t, dymension, txhash) + if eibcEvent != nil { + fmt.Println("After order fulfillment:", eibcEvent) + } + + // wait a few blocks and verify sender received funds on the hub + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + // verify funds minus fee were added to receiver's address + balance, err = dymension.GetBalance(ctx, dymensionUserAddr, rollappIBCDenom) + require.NoError(t, err) + fmt.Println("Balance of dymensionUserAddr after fulfilling the order:", balance) + require.True(t, balance.Equal(transferAmountWithoutFee.Sub(bridgingFee)), fmt.Sprintf("Value mismatch. Expected %s, actual %s", transferAmountWithoutFee.Sub(bridgingFee), balance)) + + balance, err = dymension.GetBalance(ctx, dymensionUserAddr, rollapp2IBCDenom) + require.NoError(t, err) + fmt.Println("Balance for ibc denom from rollapp 2 of dymensionUserAddr after fulfilling the order:", balance) + require.True(t, balance.Equal(transferAmountWithoutFee.Sub(bridgingFee)), fmt.Sprintf("Value mismatch. Expected %s, actual %s", transferAmountWithoutFee.Sub(bridgingFee), balance)) + + // verify funds were deducted from market maker's wallet address + rollappHeight, err = rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + // wait until the packet is finalized + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + rollapp2Height, err = rollapp2.GetNode().Height(ctx) + require.NoError(t, err) + + // wait until the packet is finalized + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp2.GetChainID(), rollapp2Height, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, marketMakerAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + txhash, err := dymension.GetNode().FinalizePacket(ctx, marketMakerAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + balance, err = dymension.GetBalance(ctx, marketMakerAddr, rollappIBCDenom) + require.NoError(t, err) + fmt.Println("Balance of marketMakerAddr after fulfilling the order:", balance) + expMmBalanceRollappDenom = expMmBalanceRollappDenom.Add(eibcFee) + require.True(t, balance.Equal(expMmBalanceRollappDenom), fmt.Sprintf("Value mismatch. Expected %s, actual %s", expMmBalanceRollappDenom, balance)) + + balance, err = dymension.GetBalance(ctx, marketMakerAddr, rollapp2IBCDenom) + require.NoError(t, err) + fmt.Println("Balance of marketMakerAddr after fulfilling the order:", balance) + require.True(t, balance.Equal(expMmBalanceRollappDenom), fmt.Sprintf("Value mismatch. Expected %s, actual %s", expMmBalanceRollappDenom, balance)) + + t.Cleanup( + func() { + err := r1.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + err = r2.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + // This test case verifies the system's behavior when an eIBC packet sent from the rollapp to the hub // with third party ibc token that is fulfilled by the market maker func TestEIBCFulfillment_ThirdParty_EVM(t *testing.T) { diff --git a/tests/eibc_nobalance_test.go b/tests/eibc_nobalance_test.go index 5f713d51..fe9f4017 100644 --- a/tests/eibc_nobalance_test.go +++ b/tests/eibc_nobalance_test.go @@ -249,3 +249,231 @@ func TestEIBCNoBalanceToFulfillOrder_EVM(t *testing.T) { // Run invariant check CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } + +func TestEIBCNoBalanceToFulfillOrder_Wasm(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"] = "rollappwasm_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 + + // 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: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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, + }, + 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) + dymension := chains[1].(*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) + const ibcPath = "ibc-path" + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, marketMaker, rollappUser := users[0], users[1], users[2] + + dymensionUserAddr := dymensionUser.FormattedAddress() + marketMakerAddr := marketMaker.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // Assert the accounts were funded + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, dymension, marketMakerAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount) + + multiplier := math.NewInt(10) + + eibcFee := transferAmount.Quo(multiplier) // transferAmount * 0.1 + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, 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() + // end of preconditions + + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + var options ibc.TransferOptions + // set eIBC specific memo + options.Memo = BuildEIbcMemo(eibcFee) + + _, err = rollapp1.SendIBCTransfer(ctx, channel.Counterparty.ChannelID, rollappUserAddr, transferData, options) + require.NoError(t, err) + + // verify funds balance right after sending the IBC transfer + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, zeroBal) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + + // get eIbc event + eibcEvents, err := getEIbcEventsWithinBlockRange(ctx, dymension, 10, false) + require.NoError(t, err) + fmt.Println("Event:", eibcEvents[0]) + + // attempt to fulfill demand order without having required denom balance + _, err = dymension.FullfillDemandOrder(ctx, eibcEvents[0].OrderId, marketMakerAddr, eibcFee) + require.Error(t, err) + + rollappHeight, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + // wait until packet finalization + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + // verify funds were transferred to dymensionUserAddr + testutil.AssertBalance(t, ctx, dymension, marketMakerAddr, rollappIBCDenom, zeroBal) + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + + t.Cleanup( + func() { + err := r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + diff --git a/tests/eibc_timeout_test.go b/tests/eibc_timeout_test.go index ed541bfd..0f384053 100644 --- a/tests/eibc_timeout_test.go +++ b/tests/eibc_timeout_test.go @@ -330,6 +330,314 @@ func TestEIBCTimeoutDymToRollapp_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } +func TestEIBCTimeoutDymToRollapp_Wasm(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"] = "rollappwasm_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 + + // 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: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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, + }, + 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) + dymension := chains[1].(*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) + const ibcPath = "ibc-path" + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, marketMakerUser, rollappUser := users[0], users[1], users[2] + + dymensionUserAddr := dymensionUser.FormattedAddress() + marketMakerAddr := marketMakerUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // Assert the accounts were funded + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, dymension, marketMakerAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // Send a normal ibc tx from RA -> Hub + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 50, dymension, rollapp1) + require.NoError(t, err) + + // Compose an IBC transfer and send from hub to rollapp + // global eibc fee in case of auto created orders is 0.0015 + numerator := math.NewInt(15) + denominator := math.NewInt(10000) + globalEIbcFee := transferAmount.Mul(numerator).Quo(denominator) + transferAmountWithoutFee := transferAmount.Sub(globalEIbcFee) + + // Set a short timeout for IBC transfer + options := ibc.TransferOptions{ + Timeout: &ibc.IBCTimeout{ + NanoSeconds: 1000000, // 1 ms - this will cause the transfer to timeout before it is picked by a relayer + }, + } + + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from dym -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, options) + require.NoError(t, err) + + // Get the IBC denom for dymension on roll app + dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, zeroBal) + + // According to delayedack module, we need the rollapp to have finalizedHeight > ibcClientLatestHeight + // in order to trigger ibc timeout or else it will trigger callback + err = testutil.WaitForBlocks(ctx, 1, dymension, rollapp1) + require.NoError(t, err) + + // get eibc event + eibcEvents, err := getEIbcEventsWithinBlockRange(ctx, dymension, 10, false) + require.NoError(t, err) + fmt.Println("Event:", eibcEvents[0]) + require.Equal(t, eibcEvents[0].Price, fmt.Sprintf("%s%s", transferAmountWithoutFee, dymension.Config().Denom)) + require.Equal(t, eibcEvents[0].Fee, fmt.Sprintf("%s%s", globalEIbcFee, dymension.Config().Denom)) + + // fulfill demand order + txhash, err := dymension.FullfillDemandOrder(ctx, eibcEvents[0].OrderId, marketMakerAddr, globalEIbcFee) + require.NoError(t, err) + fmt.Println(txhash) + // eibcEvent := getEibcEventFromTx(t, dymension, txhash) + // if eibcEvent != nil { + // fmt.Println("After order fulfillment:", eibcEvent) + // } + // require.True(t, eibcEvent.IsFulfilled) + + // wait a few blocks and verify sender received funds on the dymension + err = testutil.WaitForBlocks(ctx, 1, dymension) + require.NoError(t, err) + + // verify funds minus fee were added to receiver's address + balance, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + fmt.Println("Balance of dymensionUserAddr after fulfilling the order:", balance) + expBalance := walletAmount.Sub(transferData.Amount).Add(transferAmountWithoutFee) + require.True(t, balance.Equal(expBalance), fmt.Sprintf("Value mismatch. Expected %s, actual %s", expBalance, balance)) + + // wait until packet finalization and verify funds (incl. fee) were added to market maker's wallet address + err = testutil.WaitForBlocks(ctx, 10, dymension) + require.NoError(t, err) + + rollappHeight, err = rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, marketMakerAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, marketMakerAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 10, dymension) + require.NoError(t, err) + + balance, err = dymension.GetBalance(ctx, marketMakerAddr, dymension.Config().Denom) + require.NoError(t, err) + fmt.Println("Balance of marketMakerAddr after packet finalization:", balance) + expBalanceMarketMaker := walletAmount.Add(globalEIbcFee) + require.True(t, balance.Equal(expBalanceMarketMaker), fmt.Sprintf("Value mismatch. Expected %s, actual %s", expBalanceMarketMaker, balance)) + + t.Cleanup( + func() { + err := r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + + // TestEIBCTimeoutFulFillDymToRollapp test send 3rd party IBC denom from dymension to rollapp with timeout // and full filled func TestEIBCTimeoutFulFillDymToRollapp_EVM(t *testing.T) { diff --git a/tests/fraud_detection_test.go b/tests/fraud_detection_test.go index 6ec2f813..53bbf406 100644 --- a/tests/fraud_detection_test.go +++ b/tests/fraud_detection_test.go @@ -184,6 +184,157 @@ func TestFraudDetection_EVM(t *testing.T) { require.Equal(t, "2", resp.Result.Result) } +func TestFraudDetection_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp 1 + settlement_layer_rollapp1 := "dymension" + settlement_node_address := fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + rollapp1_id := "rollappwasm_1234-1" + gas_price_rollapp1 := "0adym" + maxIdleTime1 := "5s" + maxProofTime := "500ms" + configFileOverrides := overridesDymintToml(settlement_layer_rollapp1, settlement_node_address, rollapp1_id, gas_price_rollapp1, maxIdleTime1, maxProofTime, "50s", true) + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppVals := 1 + numRollAppFn := 1 + + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: customEpochConfig("5s"), + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + StartDA(ctx, t, client, network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1) + + 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, true, 1179360, true) + require.NoError(t, err) + + // Wait for rollapp finalized + rollapp1Height, err := rollapp1.Validators[0].Height(ctx) + require.NoError(t, err) + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollapp1Height, 300) + require.True(t, isFinalized) + require.NoError(t, err) + + // Stop the full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + // Wait for a few blocks before start the node again and sync + err = testutil.WaitForBlocks(ctx, 30, dymension) + require.NoError(t, err) + + // Start full node again + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + valHeight, err := rollapp1.Validators[0].Height(ctx) + require.NoError(t, err) + + cmd := []string{"curl", "-X", "GET", fmt.Sprintf("http://%s:26657/block_validated?height=%v", rollapp1.FullNodes[0].Name(), valHeight)} + sdtout, _, err := rollapp1.FullNodes[0].Exec(ctx, cmd, nil) + require.NoError(t, err) + + var resp BlockValidatedResponse + err = json.Unmarshal([]byte(sdtout), &resp) + require.NoError(t, err) + require.Equal(t, "0", resp.Result.Result) + + // Poll until full node is sync + err = testutil.WaitForCondition( + time.Minute*50, + time.Second*5, // each epoch is 5 seconds + func() (bool, error) { + fullnodeHeight, err := rollapp1.FullNodes[0].Height(ctx) + require.NoError(t, err) + + fmt.Println("valHeight", valHeight, " || fullnodeHeight", fullnodeHeight) + if valHeight > fullnodeHeight { + return false, nil + } + + return true, nil + }, + ) + + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + + valHeight, err = rollapp1.Validators[0].Height(ctx) + require.NoError(t, err) + cmd = []string{"curl", "-X", "GET", fmt.Sprintf("http://%s:26657/block_validated?height=%v", rollapp1.FullNodes[0].Name(), valHeight)} + sdtout, _, err = rollapp1.FullNodes[0].Exec(ctx, cmd, nil) + require.NoError(t, err) + err = json.Unmarshal([]byte(sdtout), &resp) + require.NoError(t, err) + require.Equal(t, "2", resp.Result.Result) +} + func TestFraudDetectionDA_P2P_EVM(t *testing.T) { if testing.Short() { t.Skip() diff --git a/tests/fullnode_sync_block_sync_test.go b/tests/fullnode_sync_block_sync_test.go index ddd43b27..a93f3386 100644 --- a/tests/fullnode_sync_block_sync_test.go +++ b/tests/fullnode_sync_block_sync_test.go @@ -371,6 +371,351 @@ func TestSync_BlockSync_EVM(t *testing.T) { require.NoError(t, err) } +func TestSync_BlockSync_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp 1 + 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"] = "rollappwasm_1234-1" + dymintTomlOverrides["settlement_gas_prices"] = "0adym" + dymintTomlOverrides["max_idle_time"] = "3s" + dymintTomlOverrides["max_proof_time"] = "500ms" + dymintTomlOverrides["batch_submit_time"] = "3600s" + dymintTomlOverrides["block_time"] = "200ms" + dymintTomlOverrides["p2p_gossip_cache_size"] = "1" + dymintTomlOverrides["p2p_blocksync_enabled"] = "true" + dymintTomlOverrides["p2p_blocksync_block_request_interval"] = 10 + + configFileOverrides1 := make(map[string]any) + configTomlOverrides1 := make(testutil.Toml) + configTomlOverrides1["timeout_commit"] = "2s" + configTomlOverrides1["timeout_propose"] = "2s" + configTomlOverrides1["index_all_keys"] = "true" + configTomlOverrides1["mode"] = "validator" + + configFileOverrides1["config/config.toml"] = configTomlOverrides1 + + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "celestia", + }, + ) + + numHubVals := 1 + numHubFullNodes := 1 + numCelestiaFn := 0 + numRollAppFn := 1 + numRollAppVals := 1 + nodeStore := "/home/celestia/light" + p2pNetwork := "mocha-4" + coreIp := "mocha-4-consensus.mesa.newmetric.xyz" + + url := "https://api-mocha.celenium.io/v1/block/count" + headerKey := "User-Agent" + headerValue := "Apidog/1.0.0 (https://apidog.com)" + rpcEndpoint := "http://rpc-mocha.pops.one:26657" + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "celes-hub", + ChainConfig: ibc.ChainConfig{ + Name: "celestia", + Denom: "utia", + Type: "hub-celes", + GasPrices: "0.002utia", + TrustingPeriod: "112h", + ChainID: "test", + Bin: "celestia-appd", + Images: []ibc.DockerImage{ + { + Repository: "ghcr.io/decentrio/light", + Version: "latest", + UidGid: "1025:1025", + }, + }, + Bech32Prefix: "celestia", + CoinType: "118", + GasAdjustment: 1.5, + ConfigFileOverrides: configFileOverrides1, + }, + NumValidators: &numHubVals, + NumFullNodes: &numCelestiaFn, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + celestia := chains[0].(*celes_hub.CelesHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + ic := test.NewSetup(). + AddChain(celestia) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + }, nil, "", nil, true, 1179360, true) + require.NoError(t, err) + + validator, err := celestia.Validators[0].AccountKeyBech32(ctx, "validator") + require.NoError(t, err) + + // Get fund for submit blob + GetFaucet("http://18.184.170.181:3000/api/get-tia", validator) + err = testutil.WaitForBlocks(ctx, 2, celestia) + require.NoError(t, err) + + err = celestia.GetNode().InitCelestiaDaLightNode(ctx, nodeStore, p2pNetwork, nil) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 3, celestia) + require.NoError(t, err) + + file, err := os.Open("/tmp/celestia/light/config.toml") + require.NoError(t, err) + defer file.Close() + + lastestBlockHeight, err := GetLatestBlockHeight(url, headerKey, headerValue) + require.NoError(t, err) + lastestBlockHeight = strings.TrimRight(lastestBlockHeight, "\n") + heightOfBlock, err := strconv.ParseInt(lastestBlockHeight, 10, 64) // base 10, bit size 64 + require.NoError(t, err) + + hash, err := celestia.GetNode().GetHashOfBlockHeightWithCustomizeRpcEndpoint(ctx, fmt.Sprintf("%d", heightOfBlock-2), rpcEndpoint) + require.NoError(t, err) + + hash = strings.TrimRight(hash, "\n") + var lines []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, " TrustedHash =") { + lines[i] = fmt.Sprintf(" TrustedHash = \"%s\"", hash) + } else if strings.HasPrefix(line, " SampleFrom =") { + lines[i] = fmt.Sprintf(" SampleFrom = %d", heightOfBlock-2) + } else if strings.HasPrefix(line, " Address =") { + lines[i] = fmt.Sprintf(" Address = \"0.0.0.0\"") + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create("/tmp/celestia/light/config.toml") + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + containerID := fmt.Sprintf("test-val-0-%s", t.Name()) + + // Create an exec instance + execConfig := types.ExecConfig{ + Cmd: strslice.StrSlice([]string{"celestia", "light", "start", "--node.store", nodeStore, "--gateway", "--core.ip", coreIp, "--p2p.network", p2pNetwork, "--keyring.keyname", "validator"}), // Replace with your command and arguments + } + + execIDResp, err := client.ContainerExecCreate(ctx, containerID, execConfig) + if err != nil { + fmt.Println("Err:", err) + } + + execID := execIDResp.ID + + // Start the exec instance + execStartCheck := types.ExecStartCheck{ + Tty: false, + } + + if err := client.ContainerExecStart(ctx, execID, execStartCheck); err != nil { + fmt.Println("Err:", err) + } + + err = testutil.WaitForBlocks(ctx, 10, celestia) + require.NoError(t, err) + + celestia_token, err := celestia.GetNode().GetAuthTokenCelestiaDaLight(ctx, p2pNetwork, nodeStore) + require.NoError(t, err) + println("check token: ", celestia_token) + celestia_namespace_id, err := RandomHex(10) + require.NoError(t, err) + println("check namespace: ", celestia_namespace_id) + da_config := fmt.Sprintf("{\"base_url\": \"http://test-val-0-%s:26658\", \"timeout\": 60000000000, \"gas_prices\":1.0, \"gas_adjustment\": 1.3, \"namespace_id\": \"%s\", \"auth_token\":\"%s\"}", t.Name(), celestia_namespace_id, celestia_token) + + configFileOverrides := make(map[string]any) + dymintTomlOverrides["namespace_id"] = celestia_namespace_id + dymintTomlOverrides["da_config"] = da_config + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + cf = test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + ic = test.NewSetup(). + AddRollUp(dymension, rollapp1) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + }, nil, "", nil, true, 1179360, true) + require.NoError(t, err) + // require.Error(t, err) + + containerID = fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err = os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines = []string{} + scanner = bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output = strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + file, err = os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines = []string{} + scanner = bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "namespace_id =") { + lines[i] = fmt.Sprintf("namespace_id = \"%s\"", celestia_namespace_id) + } else if strings.HasPrefix(line, "da_config =") { + lines[i] = fmt.Sprintf("da_config = \"{\\\"base_url\\\": \\\"http://test-val-0-%s:26658\\\", \\\"timeout\\\": 60000000000, \\\"gas_prices\\\":1.0, \\\"gas_adjustment\\\": 1.3, \\\"namespace_id\\\": \\\"%s\\\", \\\"auth_token\\\":\\\"%s\\\"}\"", t.Name(), celestia_namespace_id, celestia_token) + } + } + + output = strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + valHeight, err := rollapp1.Validators[0].Height(ctx) + require.NoError(t, err) + + //Poll until full node is sync + err = testutil.WaitForCondition( + time.Minute*50, + time.Second*5, // each epoch is 5 seconds + func() (bool, error) { + fullnodeHeight, err := rollapp1.FullNodes[0].Height(ctx) + require.NoError(t, err) + + fmt.Println("valHeight", valHeight, " || fullnodeHeight", fullnodeHeight) + if valHeight > fullnodeHeight { + return false, nil + } + + return true, nil + }, + ) + require.NoError(t, err) +} + func TestSync_BlockSync_fn_disconnect_EVM(t *testing.T) { if testing.Short() { t.Skip() @@ -382,7 +727,385 @@ func TestSync_BlockSync_fn_disconnect_EVM(t *testing.T) { 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["rollapp_id"] = "rollappevm_1234-1" + dymintTomlOverrides["settlement_gas_prices"] = "0adym" + dymintTomlOverrides["max_idle_time"] = "3s" + dymintTomlOverrides["max_proof_time"] = "500ms" + dymintTomlOverrides["batch_submit_time"] = "3600s" + dymintTomlOverrides["block_time"] = "200ms" + dymintTomlOverrides["p2p_gossip_cache_size"] = "1" + dymintTomlOverrides["p2p_blocksync_enabled"] = "true" + dymintTomlOverrides["p2p_blocksync_block_request_interval"] = 10 + + configFileOverrides1 := make(map[string]any) + configTomlOverrides1 := make(testutil.Toml) + configTomlOverrides1["timeout_commit"] = "2s" + configTomlOverrides1["timeout_propose"] = "2s" + configTomlOverrides1["index_all_keys"] = "true" + configTomlOverrides1["mode"] = "validator" + + configFileOverrides1["config/config.toml"] = configTomlOverrides1 + + modifyEVMGenesisKV := append( + rollappEVMGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "celestia", + }, + ) + + numHubVals := 1 + numHubFullNodes := 1 + numCelestiaFn := 0 + numRollAppFn := 1 + numRollAppVals := 1 + nodeStore := "/home/celestia/light" + p2pNetwork := "mocha-4" + coreIp := "mocha-4-consensus.mesa.newmetric.xyz" + + url := "https://api-mocha.celenium.io/v1/block/count" + headerKey := "User-Agent" + headerValue := "Apidog/1.0.0 (https://apidog.com)" + rpcEndpoint := "http://rpc-mocha.pops.one:26657" + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "celes-hub", + ChainConfig: ibc.ChainConfig{ + Name: "celestia", + Denom: "utia", + Type: "hub-celes", + GasPrices: "0.002utia", + TrustingPeriod: "112h", + ChainID: "test", + Bin: "celestia-appd", + Images: []ibc.DockerImage{ + { + Repository: "ghcr.io/decentrio/light", + Version: "latest", + UidGid: "1025:1025", + }, + }, + Bech32Prefix: "celestia", + CoinType: "118", + GasAdjustment: 1.5, + ConfigFileOverrides: configFileOverrides1, + }, + NumValidators: &numHubVals, + NumFullNodes: &numCelestiaFn, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + celestia := chains[0].(*celes_hub.CelesHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + ic := test.NewSetup(). + AddChain(celestia) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + }, nil, "", nil, true, 1179360, true) + require.NoError(t, err) + + validator, err := celestia.Validators[0].AccountKeyBech32(ctx, "validator") + require.NoError(t, err) + + // Get fund for submit blob + GetFaucet("http://18.184.170.181:3000/api/get-tia", validator) + err = testutil.WaitForBlocks(ctx, 2, celestia) + require.NoError(t, err) + + err = celestia.GetNode().InitCelestiaDaLightNode(ctx, nodeStore, p2pNetwork, nil) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 3, celestia) + require.NoError(t, err) + + file, err := os.Open("/tmp/celestia/light/config.toml") + require.NoError(t, err) + defer file.Close() + + lastestBlockHeight, err := GetLatestBlockHeight(url, headerKey, headerValue) + require.NoError(t, err) + lastestBlockHeight = strings.TrimRight(lastestBlockHeight, "\n") + heightOfBlock, err := strconv.ParseInt(lastestBlockHeight, 10, 64) // base 10, bit size 64 + require.NoError(t, err) + + hash, err := celestia.GetNode().GetHashOfBlockHeightWithCustomizeRpcEndpoint(ctx, fmt.Sprintf("%d", heightOfBlock-2), rpcEndpoint) + require.NoError(t, err) + + hash = strings.TrimRight(hash, "\n") + var lines []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, " TrustedHash =") { + lines[i] = fmt.Sprintf(" TrustedHash = \"%s\"", hash) + } else if strings.HasPrefix(line, " SampleFrom =") { + lines[i] = fmt.Sprintf(" SampleFrom = %d", heightOfBlock-2) + } else if strings.HasPrefix(line, " Address =") { + lines[i] = fmt.Sprintf(" Address = \"0.0.0.0\"") + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create("/tmp/celestia/light/config.toml") + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + containerID := fmt.Sprintf("test-val-0-%s", t.Name()) + + // Create an exec instance + execConfig := types.ExecConfig{ + Cmd: strslice.StrSlice([]string{"celestia", "light", "start", "--node.store", nodeStore, "--gateway", "--core.ip", coreIp, "--p2p.network", p2pNetwork, "--keyring.keyname", "validator"}), + } + + execIDResp, err := client.ContainerExecCreate(ctx, containerID, execConfig) + if err != nil { + fmt.Println("Err:", err) + } + + execID := execIDResp.ID + + // Start the exec instance + execStartCheck := types.ExecStartCheck{ + Tty: false, + } + + if err := client.ContainerExecStart(ctx, execID, execStartCheck); err != nil { + fmt.Println("Err:", err) + } + + err = testutil.WaitForBlocks(ctx, 10, celestia) + require.NoError(t, err) + + celestia_token, err := celestia.GetNode().GetAuthTokenCelestiaDaLight(ctx, p2pNetwork, nodeStore) + require.NoError(t, err) + println("check token: ", celestia_token) + celestia_namespace_id, err := RandomHex(10) + require.NoError(t, err) + println("check namespace: ", celestia_namespace_id) + da_config := fmt.Sprintf("{\"base_url\": \"http://test-val-0-%s:26658\", \"timeout\": 60000000000, \"gas_prices\":1.0, \"gas_adjustment\": 1.3, \"namespace_id\": \"%s\", \"auth_token\":\"%s\"}", t.Name(), celestia_namespace_id, celestia_token) + + configFileOverrides := make(map[string]any) + dymintTomlOverrides["namespace_id"] = celestia_namespace_id + dymintTomlOverrides["da_config"] = da_config + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + 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(modifyEVMGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + ic = test.NewSetup(). + AddRollUp(dymension, rollapp1) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + }, nil, "", nil, true, 1179360, true) + require.NoError(t, err) + + containerID = fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err = os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines = []string{} + scanner = bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output = strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // // update dymint.toml for full node to connect with Celestia DA + // fnHomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + // fnFolderName := fnHomeDir[len(fnHomeDir)-1] + + // file, err = os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", fnFolderName)) + // require.NoError(t, err) + // defer file.Close() + + // lines = []string{} + // scanner = bufio.NewScanner(file) + // for scanner.Scan() { + // lines = append(lines, scanner.Text()) + // } + + // for i, line := range lines { + // if strings.HasPrefix(line, "namespace_id =") { + // lines[i] = fmt.Sprintf("namespace_id = \"%s\"", celestia_namespace_id) + // } else if strings.HasPrefix(line, "da_config =") { + // lines[i] = fmt.Sprintf("da_config = \"{\\\"base_url\\\": \\\"http://test-val-0-%s:26658\\\", \\\"timeout\\\": 60000000000, \\\"gas_prices\\\":1.0, \\\"gas_adjustment\\\": 1.3, \\\"namespace_id\\\": \\\"%s\\\", \\\"auth_token\\\":\\\"%s\\\"}\"", t.Name(), celestia_namespace_id, celestia_token) + // } + // } + + // output = strings.Join(lines, "\n") + // file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", fnFolderName)) + // require.NoError(t, err) + // defer file.Close() + + // _, err = file.Write([]byte(output)) + // require.NoError(t, err) + + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + valHeight, err := rollapp1.Validators[0].Height(ctx) + require.NoError(t, err) + + //Poll until full node is sync + err = testutil.WaitForCondition( + time.Minute*50, + time.Second*5, // each epoch is 5 seconds + func() (bool, error) { + fullnodeHeight, err := rollapp1.FullNodes[0].Height(ctx) + require.NoError(t, err) + + fmt.Println("valHeight", valHeight, " || fullnodeHeight", fullnodeHeight) + if valHeight > fullnodeHeight { + return false, nil + } + + return true, nil + }, + ) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + // Wait for few blocks before starting the full node + err = testutil.WaitForBlocks(ctx, 30, dymension) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + valHeight, err = rollapp1.Validators[0].Height(ctx) + require.NoError(t, err) + + //Poll until full node is sync + err = testutil.WaitForCondition( + time.Minute*50, + time.Second*5, // each epoch is 5 seconds + func() (bool, error) { + fullnodeHeight, err := rollapp1.FullNodes[0].Height(ctx) + require.NoError(t, err) + + fmt.Println("valHeight", valHeight, " || fullnodeHeight", fullnodeHeight) + if valHeight > fullnodeHeight { + return false, nil + } + + return true, nil + }, + ) + require.NoError(t, err) +} + +func TestSync_BlockSync_fn_disconnect_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp 1 + 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"] = "rollappwasm_1234-1" dymintTomlOverrides["settlement_gas_prices"] = "0adym" dymintTomlOverrides["max_idle_time"] = "3s" dymintTomlOverrides["max_proof_time"] = "500ms" @@ -401,8 +1124,8 @@ func TestSync_BlockSync_fn_disconnect_EVM(t *testing.T) { configFileOverrides1["config/config.toml"] = configTomlOverrides1 - modifyEVMGenesisKV := append( - rollappEVMGenesisKV, + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, cosmos.GenesisKV{ Key: "app_state.rollappparams.params.da", Value: "celestia", @@ -571,18 +1294,18 @@ func TestSync_BlockSync_fn_disconnect_EVM(t *testing.T) { ChainConfig: ibc.ChainConfig{ Type: "rollapp-dym", Name: "rollapp-temp", - ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappEVMImage}, + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, Bin: "rollappd", - Bech32Prefix: "ethm", + Bech32Prefix: "rol", Denom: "urax", - CoinType: "60", + CoinType: "118", GasPrices: "0.0urax", GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, - ModifyGenesis: modifyRollappEVMGenesis(modifyEVMGenesisKV), + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), ConfigFileOverrides: configFileOverrides, }, NumValidators: &numRollAppVals, @@ -614,7 +1337,7 @@ func TestSync_BlockSync_fn_disconnect_EVM(t *testing.T) { }, nil, "", nil, true, 1179360, true) require.NoError(t, err) - containerID = fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + containerID = fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) // Get the container details containerJSON, err := client.ContainerInspect(context.Background(), containerID) @@ -748,3 +1471,4 @@ func TestSync_BlockSync_fn_disconnect_EVM(t *testing.T) { ) require.NoError(t, err) } + diff --git a/tests/genesis_bridge_test.go b/tests/genesis_bridge_test.go index 56423a50..d0a4f83c 100644 --- a/tests/genesis_bridge_test.go +++ b/tests/genesis_bridge_test.go @@ -1529,6 +1529,222 @@ func TestGenesisBridgeBeforeChannelSet_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } +func TestGenesisBridgeBeforeChannelSet_Wasm(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"] = "rollappwasm_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 + // 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: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + 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) + dymension := chains[1].(*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) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // Send a normal ibc tx from RA -> Hub + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: bigTransferAmount, + } + + _, err = rollapp1.SendIBCTransfer(ctx, "", rollappUserAddr, transferData, ibc.TransferOptions{}) + require.Error(t, err, "IBC transfer should fail because the channel is not created yet") + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + 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: transferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + 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() + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + func TestGenesisBridgeWithoutGenesisAcc_EVM(t *testing.T) { if testing.Short() { t.Skip() @@ -1694,6 +1910,171 @@ func TestGenesisBridgeWithoutGenesisAcc_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } +func TestGenesisBridgeWithoutGenesisAcc_Wasm(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"] = "rollappwasm_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 + // 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: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(rollappWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + 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) + dymension := chains[1].(*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) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, 1179360, false) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData := ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + func TestGenesisTransferBridgeUnBond_EVM(t *testing.T) { if testing.Short() { t.Skip() diff --git a/tests/hardfork_test.go b/tests/hardfork_test.go index 69cfca69..ea1fe393 100644 --- a/tests/hardfork_test.go +++ b/tests/hardfork_test.go @@ -470,6 +470,448 @@ func TestHardForkDueToFraud_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } +func TestHardForkDueToFraud_Wasm(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"] = "rollappwasm_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"] = "true" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 1 + numRollAppVals := 1 + + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + StartDA(ctx, t, client, network) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + // Check IBC Transfer before switch + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Create sequencer + cmd := append([]string{rollapp1.FullNodes[0].Chain.Config().Bin}, "dymint", "show-sequencer", "--home", rollapp1.FullNodes[0].HomeDir()) + pub1, _, err := rollapp1.FullNodes[0].Exec(ctx, cmd, nil) + require.NoError(t, err) + + err = dymension.FullNodes[0].CreateKeyWithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + sequencer, err := dymension.AccountKeyBech32WithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + fund := ibc.WalletData{ + Address: sequencer, + Denom: dymension.Config().Denom, + Amount: math.NewInt(10_000_000_000_000).MulRaw(100_000_000), + } + err = dymension.SendFunds(ctx, "faucet", fund) + require.NoError(t, err) + + resp0, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp0.Sequencers), 1, "should have 1 sequences") + + //Bond + command := []string{"sequencer", "create-sequencer", string(pub1), rollapp1.Config().ChainID, "100000000000000000000adym", rollapp1.GetSequencerKeyDir() + "/metadata_sequencer1.json", + "--broadcast-mode", "async", "--keyring-dir", rollapp1.FullNodes[0].HomeDir() + "/sequencer_keys"} + + _, err = dymension.FullNodes[0].ExecTx(ctx, "sequencer", command...) + require.NoError(t, err) + + resp, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp.Sequencers), 2, "should have 2 sequences") + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + options := ibc.TransferOptions{ + Timeout: &ibc.IBCTimeout{ + NanoSeconds: 1000000, // 1 ms - this will cause the transfer to timeout before it is picked by a relayer + }, + } + + transferData := ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + fraud_height, err := rollapp1.Height(ctx) + require.NoError(t, err, "error fetching height") + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, options) + require.NoError(t, err) + + // Create fraud proposal message + msg := map[string]interface{}{ + "@type": "/dymensionxyz.dymension.rollapp.MsgRollappFraudProposal", + "authority": "dym10d07y265gmmuvt4z0w9aw880jnsr700jgllrna", + "rollapp_id": "rollappwasm_1234-1", + "fraud_revision": "0", + "fraud_height": fmt.Sprint(fraud_height), + "punish_sequencer_address": "", + } + + rawMsg, err := json.Marshal(msg) + if err != nil { + fmt.Println("Err:", err) + } + + proposal := cosmos.TxFraudProposal{ + Deposit: "500000000000" + dymension.Config().Denom, + Title: "rollapp Upgrade 1", + Summary: "test", + Messages: []json.RawMessage{rawMsg}, + Metadata: "ipfs://CID", + } + + // Submit fraud proposal + _, _ = dymension.SubmitFraudProposal(ctx, dymensionUser.KeyName(), proposal) + + err = dymension.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) + require.NoError(t, err, "failed to submit votes") + + height, err := dymension.Height(ctx) + require.NoError(t, err, "error fetching height") + haltHeight := height + haltHeightDelta + + _, err = cosmos.PollForProposalStatus(ctx, dymension.CosmosChain, height, haltHeight, "1", cosmos.ProposalStatusPassed) + require.NoError(t, err, "proposal status did not change to passed") + + command = []string{"sequencer", "opt-in", "true", "--keyring-dir", rollapp1.FullNodes[0].HomeDir() + "/sequencer_keys"} + + _, err = dymension.FullNodes[0].ExecTx(ctx, "sequencer", command...) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 50, dymension) + require.NoError(t, err) + + rollapp1ValHomeDir := strings.Split(rollapp1.Validators[0].HomeDir(), "/") + rollapp1ValFolderName := rollapp1ValHomeDir[len(rollapp1ValHomeDir)-1] + + err = os.RemoveAll(fmt.Sprintf("/tmp/%s/data", rollapp1FolderName)) + require.NoError(t, err) + + err = os.RemoveAll(fmt.Sprintf("/tmp/%s/data", rollapp1ValFolderName)) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.Validators[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + err = rollapp1.Validators[0].StartContainer(ctx) + + if err != nil { + err = rollapp1.Validators[0].StopContainer(ctx) + require.NoError(t, err) + err = rollapp1.Validators[0].StartContainer(ctx) + } + + wallet, found = r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()+"/sequencer_keys", []string{wallet.FormattedAddress()}) + require.NoError(t, err) + + err = r.StopRelayer(ctx, eRep) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 60, dymension) + require.NoError(t, err) + + // Send a normal ibc tx from RA -> Hub + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransferAfterHardFork(ctx, channel.ChannelID, rollappUserAddr, transferData, ibc.TransferOptions{}) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Check IBC after switch + 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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 10, 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() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, (transferAmount.Sub(bridgingFee))) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, dymensionOrigBal) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + func Test_HardFork_KickProposer_EVM(t *testing.T) { if testing.Short() { t.Skip() @@ -480,7 +922,449 @@ func Test_HardFork_KickProposer_EVM(t *testing.T) { // setup config for rollapp 1 settlement_layer_rollapp1 := "dymension" settlement_node_address := fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) - rollapp1_id := "rollappevm_1234-1" + rollapp1_id := "rollappevm_1234-1" + gas_price_rollapp1 := "0adym" + maxIdleTime1 := "3s" + maxProofTime := "500ms" + configFileOverrides := overridesDymintToml(settlement_layer_rollapp1, settlement_node_address, rollapp1_id, gas_price_rollapp1, maxIdleTime1, maxProofTime, "20s", true) + + modifyHubGenesisKV := append( + dymensionGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.sequencer.params.dishonor_kick_threshold", + Value: "1", + }, + cosmos.GenesisKV{ + Key: "app_state.rollapp.params.liveness_slash_blocks", + Value: "1", + }, + cosmos.GenesisKV{ + Key: "app_state.rollapp.params.liveness_slash_interval", + Value: "1", + }, + ) + + modifyRAGenesisKV := append( + rollappEVMGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppVals := 1 + numRollAppFn := 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(modifyRAGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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(modifyHubGenesisKV), + ConfigFileOverrides: nil, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + StartDA(ctx, t, client, network) + + // relayer for rollapp 1 + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + }, nil, "", nil, false, 1179360, true) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + // Check IBC Transfer before switch + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + 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: transferAmount, + } + + // Compose an IBC transfer and send from rollapp -> Hub + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + // 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() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom + dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + require.NoError(t, err) + erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + + cmd := append([]string{rollapp1.FullNodes[0].Chain.Config().Bin}, "dymint", "show-sequencer", "--home", rollapp1.FullNodes[0].HomeDir()) + pub1, _, err := rollapp1.FullNodes[0].Exec(ctx, cmd, nil) + require.NoError(t, err) + + err = dymension.FullNodes[0].CreateKeyWithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + sequencer, err := dymension.AccountKeyBech32WithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + fund := ibc.WalletData{ + Address: sequencer, + Denom: dymension.Config().Denom, + Amount: math.NewInt(10_000_000_000_000).MulRaw(100_000_000), + } + err = dymension.SendFunds(ctx, "faucet", fund) + require.NoError(t, err) + + resp0, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp0.Sequencers), 1, "should have 1 sequences") + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + command := []string{"sequencer", "create-sequencer", string(pub1), rollapp1.Config().ChainID, "100000000000000000000adym", rollapp1.GetSequencerKeyDir() + "/metadata_sequencer1.json", + "--broadcast-mode", "async", "--keyring-dir", rollapp1.FullNodes[0].HomeDir() + "/sequencer_keys"} + + _, err = dymension.FullNodes[0].ExecTx(ctx, "sequencer", command...) + require.NoError(t, err) + + resp, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp.Sequencers), 2, "should have 2 sequences") + + nextProposer, err := dymension.GetNode().GetNextProposerByRollapp(ctx, rollapp1.Config().ChainID, dymensionUserAddr) + require.NoError(t, err) + require.Equal(t, "sentinel", nextProposer.NextProposerAddr) + + currentProposer, err := dymension.GetNode().GetProposerByRollapp(ctx, rollapp1.Config().ChainID, dymensionUserAddr) + require.NoError(t, err) + require.Equal(t, resp0.Sequencers[0].Address, currentProposer.ProposerAddr) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + // stop proposer => slashing then + err = rollapp1.Validators[0].StopContainer(ctx) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 2, dymension) + + err = rollapp1.Validators[0].StartContainer(ctx) + require.NoError(t, err) + + // kick current proposer + err = dymension.FullNodes[0].KickProposer(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + // check client was frozen after kicked + clientStatus, err := dymension.GetNode().QueryClientStatus(ctx, "07-tendermint-0") + require.NoError(t, err) + require.Equal(t, "Frozen", clientStatus.Status) + + rollapp1ValHomeDir := strings.Split(rollapp1.Validators[0].HomeDir(), "/") + rollapp1ValFolderName := rollapp1ValHomeDir[len(rollapp1ValHomeDir)-1] + + err = os.RemoveAll(fmt.Sprintf("/tmp/%s/data", rollapp1FolderName)) + require.NoError(t, err) + + err = os.RemoveAll(fmt.Sprintf("/tmp/%s/data", rollapp1ValFolderName)) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.Validators[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + err = rollapp1.Validators[0].StartContainer(ctx) + + if err != nil { + err = rollapp1.Validators[0].StopContainer(ctx) + require.NoError(t, err) + err = rollapp1.Validators[0].StartContainer(ctx) + } + + // check client was frozen after kicked + clientStatus, err = dymension.GetNode().QueryClientStatus(ctx, "07-tendermint-0") + require.NoError(t, err) + require.Equal(t, "Active", clientStatus.Status) + + // // preparing to kick current proposer + // err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + // require.Error(t, err) + + // queryGetSequencerResponse, err = dymension.QueryShowSequencer(ctx, seqAddr) + // require.NoError(t, err) + // require.Equal(t, "OPERATING_STATUS_UNBONDED", queryGetSequencerResponse.Sequencer.Status) + + // err = rollapp1.StopAllNodes(ctx) + // require.NoError(t, err) + + // _ = rollapp1.StartAllNodes(ctx) + + err = r.StopRelayer(ctx, eRep) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + time.Sleep(45 * time.Second) + + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + _, err = rollapp1.SendIBCTransferAfterHardFork(ctx, channel.ChannelID, rollappUserAddr, transferData, ibc.TransferOptions{}) + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Check IBC after switch + 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(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) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + 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() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, (transferAmount.Sub(bridgingFee)).MulRaw(2)) + + // Get original account balances + dymensionOrigBal, err = dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + rollappOrigBal, err := rollapp1.GetBalance(ctx, rollappUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom + dymensionTokenDenom = transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + dymensionIBCDenom = transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + erc20MAcc, err = rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + require.NoError(t, err) + erc20MAccAddr = erc20MAcc.Account.BaseAccount.Address + testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, rollappOrigBal.Add(transferData.Amount)) +} + +func Test_HardFork_KickProposer_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp 1 + settlement_layer_rollapp1 := "dymension" + settlement_node_address := fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + rollapp1_id := "rollappwasm_1234-1" gas_price_rollapp1 := "0adym" maxIdleTime1 := "3s" maxProofTime := "500ms" @@ -503,7 +1387,7 @@ func Test_HardFork_KickProposer_EVM(t *testing.T) { ) modifyRAGenesisKV := append( - rollappEVMGenesisKV, + rollappWasmGenesisKV, cosmos.GenesisKV{ Key: "app_state.rollappparams.params.da", Value: "grpc", @@ -522,18 +1406,18 @@ func Test_HardFork_KickProposer_EVM(t *testing.T) { ChainConfig: ibc.ChainConfig{ Type: "rollapp-dym", Name: "rollapp-temp", - ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappEVMImage}, + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, Bin: "rollappd", - Bech32Prefix: "ethm", + Bech32Prefix: "rol", Denom: "urax", - CoinType: "60", + CoinType: "118", GasPrices: "0.0urax", GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, - ModifyGenesis: modifyRollappEVMGenesis(modifyRAGenesisKV), + ModifyGenesis: modifyRollappWasmGenesis(modifyRAGenesisKV), ConfigFileOverrides: configFileOverrides, }, NumValidators: &numRollAppVals, @@ -705,14 +1589,14 @@ func Test_HardFork_KickProposer_EVM(t *testing.T) { require.NoError(t, err) // Get the IBC denom - dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) - dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) - erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") - require.NoError(t, err) - erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address - testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) cmd := append([]string{rollapp1.FullNodes[0].Chain.Config().Bin}, "dymint", "show-sequencer", "--home", rollapp1.FullNodes[0].HomeDir()) pub1, _, err := rollapp1.FullNodes[0].Exec(ctx, cmd, nil) @@ -881,7 +1765,7 @@ func Test_HardFork_KickProposer_EVM(t *testing.T) { // Get original account balances dymensionOrigBal, err = dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) require.NoError(t, err) - rollappOrigBal, err := rollapp1.GetBalance(ctx, rollappUserAddr, dymension.Config().Denom) + // rollappOrigBal, err := rollapp1.GetBalance(ctx, rollappUserAddr, dymension.Config().Denom) require.NoError(t, err) // Compose an IBC transfer and send from dymension -> rollapp @@ -902,14 +1786,14 @@ func Test_HardFork_KickProposer_EVM(t *testing.T) { require.NoError(t, err) // Get the IBC denom - dymensionTokenDenom = transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) - dymensionIBCDenom = transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + // dymensionTokenDenom = transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom = transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) - erc20MAcc, err = rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") - require.NoError(t, err) - erc20MAccAddr = erc20MAcc.Account.BaseAccount.Address - testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, rollappOrigBal.Add(transferData.Amount)) + // erc20MAcc, err = rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr = erc20MAcc.Account.BaseAccount.Address + // testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, rollappOrigBal.Add(transferData.Amount)) } func TestHardForkDueToDrs_EVM(t *testing.T) { @@ -1314,12 +2198,425 @@ func TestHardForkDueToDrs_EVM(t *testing.T) { require.NoError(t, err) // Get the IBC denom - dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) - dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) - erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") - require.NoError(t, err) - erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address - testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) } + +// func TestHardForkDueToDrs_Wasm(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"] = "rollappwasm_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"] = "true" +// dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + +// configFileOverrides["config/dymint.toml"] = dymintTomlOverrides +// // Create chain factory with dymension +// numHubVals := 1 +// numHubFullNodes := 1 +// numRollAppFn := 1 +// numRollAppVals := 1 + +// modifyWasmGenesisKV := append( +// rollappWasmGenesisKV, +// cosmos.GenesisKV{ +// Key: "app_state.rollappparams.params.da", +// Value: "grpc", +// }, +// ) + +// cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ +// { +// Name: "rollapp1", +// ChainConfig: ibc.ChainConfig{ +// Type: "rollapp-dym", +// Name: "rollapp-temp", +// ChainID: "rollappwasm_1234-1", +// Images: []ibc.DockerImage{rollappWasmImage}, +// Bin: "rollappd", +// Bech32Prefix: "rol", +// Denom: "urax", +// CoinType: "118", +// GasPrices: "0.0urax", +// GasAdjustment: 1.1, +// TrustingPeriod: "112h", +// EncodingConfig: encodingConfig(), +// NoHostMount: false, +// ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), +// ConfigFileOverrides: configFileOverrides, +// }, +// NumValidators: &numRollAppVals, +// NumFullNodes: &numRollAppFn, +// }, +// { +// Name: "dymension-hub", +// ChainConfig: dymensionConfig, +// 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) +// dymension := chains[1].(*dym_hub.DymHub) + +// // Relayer Factory +// client, network := test.DockerSetup(t) + +// StartDA(ctx, t, client, network) + +// r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), +// relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), +// ).Build(t, client, "relayer", network) + +// ic := test.NewSetup(). +// AddRollUp(dymension, rollapp1). +// AddRelayer(r, "relayer"). +// AddLink(test.InterchainLink{ +// Chain1: dymension, +// Chain2: rollapp1, +// Relayer: r, +// Path: ibcPath, +// }) + +// 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, true, 1179360, true) +// require.NoError(t, err) + +// containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) + +// // Get the container details +// containerJSON, err := client.ContainerInspect(context.Background(), containerID) +// require.NoError(t, err) + +// // Extract the IP address from the network settings +// // If the container is using a custom network, the IP might be under a specific network name +// var ipAddress string +// for _, network := range containerJSON.NetworkSettings.Networks { +// ipAddress = network.IPAddress +// break // Assuming we only need the IP from the first network +// } + +// nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) +// require.NoError(t, err) +// nodeId = strings.TrimRight(nodeId, "\n") +// p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + +// rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") +// rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + +// file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) +// require.NoError(t, err) +// defer file.Close() + +// lines := []string{} +// scanner := bufio.NewScanner(file) +// for scanner.Scan() { +// lines = append(lines, scanner.Text()) +// } + +// for i, line := range lines { +// if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { +// lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) +// } +// } + +// output := strings.Join(lines, "\n") +// file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) +// require.NoError(t, err) +// defer file.Close() + +// _, err = file.Write([]byte(output)) +// require.NoError(t, err) + +// // Start full node +// err = rollapp1.FullNodes[0].StopContainer(ctx) +// require.NoError(t, err) + +// err = rollapp1.FullNodes[0].StartContainer(ctx) +// require.NoError(t, err) + +// addrDym, _ := r.GetWallet(dymension.GetChainID()) +// err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ +// Address: addrDym.FormattedAddress(), +// Amount: math.NewInt(10_000_000_000_000), +// Denom: dymension.Config().Denom, +// }) +// require.NoError(t, err) + +// addrRA, _ := r.GetWallet(rollapp1.GetChainID()) +// err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ +// Address: addrRA.FormattedAddress(), +// Amount: math.NewInt(10_000_000_000_000), +// Denom: rollapp1.Config().Denom, +// }) +// require.NoError(t, err) + +// wallet, found := r.GetWallet(rollapp1.Config().ChainID) +// require.True(t, found) + +// keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() +// keyPath := keyDir + "/sequencer_keys" + +// err = testutil.WaitForBlocks(ctx, 5, dymension) +// require.NoError(t, err) + +// //Update white listed relayers +// _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) +// if err != nil { +// _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) +// require.NoError(t, err) +// } + +// // Check IBC Transfer before switch +// CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + +// // Create some user accounts on both chains +// users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + +// // Get our Bech32 encoded user addresses +// dymensionUser, rollappUser := users[0], users[1] + +// dymensionUserAddr := dymensionUser.FormattedAddress() +// rollappUserAddr := rollappUser.FormattedAddress() + +// channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) +// require.NoError(t, err) + +// err = r.StartRelayer(ctx, eRep, ibcPath) +// require.NoError(t, err) + +// err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) +// require.NoError(t, err) + +// res, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) +// require.NoError(t, err) +// require.Equal(t, len(res.Sequencers), 1, "should have 1 sequences") + +// // Wait a few blocks for relayer to start and for user accounts to be created +// err = testutil.WaitForBlocks(ctx, 5, dymension) +// require.NoError(t, err) + +// // Create DRS deprecation proposal message +// msg := map[string]interface{}{ +// "@type": "/dymensionxyz.dymension.rollapp.MsgMarkObsoleteRollapps", +// "authority": "dym10d07y265gmmuvt4z0w9aw880jnsr700jgllrna", +// "drs_versions": []int{1}, +// } + +// rawMsg, err := json.Marshal(msg) +// if err != nil { +// panic(err) +// } + +// proposal := cosmos.TxDRSDeprecationProposal{ +// Deposit: "500000000000" + dymension.Config().Denom, +// Title: "drs", +// Summary: "SubmitDRSDeprecationProposal", +// Messages: []json.RawMessage{rawMsg}, +// Metadata: "ipfs://CID", +// } + +// // Submit DRS deprecation proposal +// _, _ = dymension.SubmitDRSDeprecationProposal(ctx, dymensionUser.KeyName(), proposal) + +// err = dymension.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) +// require.NoError(t, err, "failed to submit votes") + +// height, err := dymension.Height(ctx) +// require.NoError(t, err, "error fetching height") +// haltHeight := height + haltHeightDelta + +// // Assert that the chain is halted +// // require.Equal(t, initialHeight, height, "chain is not halted as expected") + +// _, err = cosmos.PollForProposalStatus(ctx, dymension.CosmosChain, height, haltHeight, "1", cosmos.ProposalStatusPassed) +// require.NoError(t, err, "proposal status did not change to passed") + +// command := []string{"sequencer", "opt-in", "true", "--keyring-dir", rollapp1.Validators[0].HomeDir() + "/sequencer_keys"} + +// _, err = dymension.Validators[0].ExecTx(ctx, "sequencer", command...) +// require.NoError(t, err) + +// err = testutil.WaitForBlocks(ctx, 10, dymension) +// require.NoError(t, err) + +// err = rollapp1.StopAllNodes(ctx) +// require.NoError(t, err) + +// rollapp1ValHomeDir := strings.Split(rollapp1.Validators[0].HomeDir(), "/") +// rollapp1ValFolderName := rollapp1ValHomeDir[len(rollapp1ValHomeDir)-1] + +// err = os.RemoveAll(fmt.Sprintf("/tmp/%s/data", rollapp1FolderName)) +// require.NoError(t, err) + +// err = os.RemoveAll(fmt.Sprintf("/tmp/%s/data", rollapp1ValFolderName)) +// require.NoError(t, err) + +// err = rollapp1.StartAllNodes(ctx) + +// err = testutil.WaitForBlocks(ctx, 50, dymension) +// require.NoError(t, err) + +// err = rollapp1.StopAllNodes(ctx) + +// // rollapp1.UpgradeVersion(ctx, client, "ghcr.io/decentrio/rollapp-wasm", "drs-2") + +// for _, n := range rollapp1.Validators { +// n.Image.Version = "drs-2" +// n.Image.Repository = "ghcr.io/decentrio/rollapp-wasm" +// } + +// for _, image := range rollapp1.Config().Images { +// rc, err := client.ImagePull( +// ctx, +// image.Repository+":"+image.Version, +// dockertypes.ImagePullOptions{}, +// ) +// if err != nil { +// fmt.Println(err) +// } else { +// _, _ = io.Copy(io.Discard, rc) +// _ = rc.Close() +// } +// } + +// err = rollapp1.StartAllNodes(ctx) + +// err = testutil.WaitForBlocks(ctx, 10, dymension) +// require.NoError(t, err) + +// for _, n := range rollapp1.FullNodes { +// n.Image.Version = "drs-2" +// n.Image.Repository = "ghcr.io/decentrio/rollapp-wasm" +// } + +// for _, image := range rollapp1.Config().Images { +// rc, err := client.ImagePull( +// ctx, +// image.Repository+":"+image.Version, +// dockertypes.ImagePullOptions{}, +// ) +// if err != nil { +// fmt.Println(err) +// } else { +// _, _ = io.Copy(io.Discard, rc) +// _ = rc.Close() +// } +// } + +// err = rollapp1.StopAllNodes(ctx) + +// err = rollapp1.StartAllNodes(ctx) +// require.NoError(t, err) + +// transferData := ibc.WalletData{ +// Address: dymensionUserAddr, +// Denom: rollapp1.Config().Denom, +// Amount: transferAmount, +// } +// _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + +// resp, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) +// fmt.Println(res) +// require.NoError(t, err) + +// for _, packet := range resp.RollappPackets { + +// proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) +// isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) +// require.NoError(t, err) +// require.True(t, isFinalized) +// txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) +// 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() + +// // Minus 0.1% of transfer amount for bridge fee +// testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + +// // Get original account balances +// dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) +// require.NoError(t, err) + +// // Compose an IBC transfer and send from dymension -> rollapp +// transferData = ibc.WalletData{ +// Address: rollappUserAddr, +// Denom: dymension.Config().Denom, +// Amount: transferAmount, +// } + +// // Compose an IBC transfer and send from Hub -> rollapp +// _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) +// require.NoError(t, err) + +// // Assert balance was updated on the hub +// testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + +// err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) +// require.NoError(t, err) + +// // Get the IBC denom +// dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) +// dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + +// testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) +// erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") +// require.NoError(t, err) +// erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address +// testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) +// } + diff --git a/tests/sequencer_reward_address_test.go b/tests/sequencer_reward_address_test.go index 8b3adc16..ccf9d46a 100644 --- a/tests/sequencer_reward_address_test.go +++ b/tests/sequencer_reward_address_test.go @@ -450,6 +450,431 @@ func Test_SeqRewardsAddress_Register_EVM(t *testing.T) { testutil.AssertBalance(t, ctx, rollapp1, rewardAddrStr, rollapp1.Config().Denom, expectedAmountInt) } +func Test_SeqRewardsAddress_Register_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp 1 + 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"] = "rollappwasm_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"] = "true" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + modifyRAGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + cosmos.GenesisKV{ + Key: "app_state.distribution.params.base_proposer_reward", + Value: "0.9", + }, + cosmos.GenesisKV{ + Key: "app_state.distribution.params.bonus_proposer_reward", + Value: "1", + }, + ) + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppVals := 1 + numRollAppFn := 1 + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyRAGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + StartDA(ctx, t, client, network) + + // relayer for rollapp 1 + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + }, nil, "", nil, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + // Check IBC Transfer before switch + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + 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: transferAmount, + } + + // Compose an IBC transfer and send from rollapp -> Hub + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + // 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() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + + err = dymension.FullNodes[0].CreateKeyWithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + sequencer, err := dymension.AccountKeyBech32WithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + fund := ibc.WalletData{ + Address: sequencer, + Denom: dymension.Config().Denom, + Amount: math.NewInt(10_000_000_000_000).MulRaw(100_000_000), + } + err = dymension.SendFunds(ctx, "faucet", fund) + require.NoError(t, err) + + resp0, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp0.Sequencers), 1, "should have 1 sequences") + + operatorAddress, err := rollapp1.GetNode().QueryOperatorAddress(ctx) + require.NoError(t, err) + operatorAddr := operatorAddress.Sequencers[0].OperatorAddress + + rewardAddress, err := rollapp1.GetNode().QuerySequencersRewardAddressResponse(ctx, operatorAddr) + require.NoError(t, err) + rewardAddrStr := rewardAddress.RewardAddr + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + currentProposer, err := dymension.GetNode().GetProposerByRollapp(ctx, rollapp1.Config().ChainID, dymensionUserAddr) + require.NoError(t, err) + require.Equal(t, resp0.Sequencers[0].Address, currentProposer.ProposerAddr) + fmt.Printf("CurrentProposer: %+v\n", currentProposer) + + // Get original account balances + // 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() + + rollappOrigBal2, err := rollapp1.GetBalance(ctx, rollappUserAddr, rollapp1.Config().Denom) + require.NoError(t, err) + dymensionOrigBal2, err := dymension.GetBalance(ctx, dymensionUserAddr, rollappIBCDenom) + require.NoError(t, err) + + // Send a normal ibc tx from RA -> Hub + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransferAfterHardFork(ctx, channel.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, rollappOrigBal2.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) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + 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, dymensionUserAddr, rollappIBCDenom, dymensionOrigBal2.Add(transferData.Amount).Sub(bridgingFee)) + + err = testutil.WaitForBlocks(ctx, 10, rollapp1) + require.NoError(t, err) + + //Query reward address + balance, err := rollapp1.GetBalance(ctx, rewardAddrStr, rollapp1.Config().Denom) + require.NoError(t, err) + require.True(t, balance.Sign() > 0, fmt.Sprintf("Balance is not greater than 0. Actual balance: %s", balance.String())) + + var baseProposerReward float64 + for _, kv := range modifyRAGenesisKV { + if kv.Key == "app_state.distribution.params.base_proposer_reward" { + valueStr, ok := kv.Value.(string) + require.True(t, ok, "kv.Value should be a string") + value, err := strconv.ParseFloat(valueStr, 64) + require.NoError(t, err) + baseProposerReward = value + break + } + } + + feesCollected := float64(4000000000000000) + expectedAmount := int64(feesCollected * baseProposerReward) + expectedAmountInt := math.NewInt(expectedAmount) + + testutil.AssertBalance(t, ctx, rollapp1, rewardAddrStr, rollapp1.Config().Denom, expectedAmountInt) +} + func Test_SeqRewardsAddress_Update_EVM(t *testing.T) { if testing.Short() { t.Skip() @@ -462,7 +887,560 @@ func Test_SeqRewardsAddress_Update_EVM(t *testing.T) { 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["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"] = "true" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + modifyRAGenesisKV := append( + rollappEVMGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + cosmos.GenesisKV{ + Key: "app_state.distribution.params.base_proposer_reward", + Value: "0.9", + }, + cosmos.GenesisKV{ + Key: "app_state.distribution.params.bonus_proposer_reward", + Value: "1", + }, + ) + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppVals := 1 + numRollAppFn := 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(modifyRAGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + StartDA(ctx, t, client, network) + + // relayer for rollapp 1 + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + }, nil, "", nil, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + // Check IBC Transfer before switch + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Create sequencer + cmd := append([]string{rollapp1.FullNodes[0].Chain.Config().Bin}, "dymint", "show-sequencer", "--home", rollapp1.FullNodes[0].HomeDir()) + pub1, _, err := rollapp1.FullNodes[0].Exec(ctx, cmd, nil) + require.NoError(t, err) + + err = dymension.FullNodes[0].CreateKeyWithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + sequencer, err := dymension.AccountKeyBech32WithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + fund := ibc.WalletData{ + Address: sequencer, + Denom: dymension.Config().Denom, + Amount: math.NewInt(10_000_000_000_000).MulRaw(100_000_000), + } + err = dymension.SendFunds(ctx, "faucet", fund) + require.NoError(t, err) + + resp0, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp0.Sequencers), 1, "should have 1 sequences") + fmt.Printf("Sequencercheck1: %v\n", resp0.Sequencers) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + command := []string{"sequencer", "create-sequencer", string(pub1), rollapp1.Config().ChainID, "100000000000000000000adym", rollapp1.GetSequencerKeyDir() + "/metadata_sequencer1.json", + "--broadcast-mode", "async", "--keyring-dir", rollapp1.FullNodes[0].HomeDir() + "/sequencer_keys"} + + _, err = dymension.FullNodes[0].ExecTx(ctx, "sequencer", command...) + require.NoError(t, err) + + resp, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp.Sequencers), 2, "should have 2 sequences") + fmt.Printf("Sequencercheck2: %v\n", resp.Sequencers) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 30, dymension, rollapp1) + require.NoError(t, err) + + // Send a normal ibc tx from RA -> Hub + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from rollapp -> Hub + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + fmt.Println(txhash) + } + + // 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() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom + dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + require.NoError(t, err) + erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + + nextProposer, err := dymension.GetNode().GetNextProposerByRollapp(ctx, rollapp1.Config().ChainID, dymensionUserAddr) + require.NoError(t, err) + require.Equal(t, "sentinel", nextProposer.NextProposerAddr) + + currentProposer, err := dymension.GetNode().GetProposerByRollapp(ctx, rollapp1.Config().ChainID, dymensionUserAddr) + require.NoError(t, err) + require.Equal(t, resp0.Sequencers[0].Address, currentProposer.ProposerAddr) + + // Unbond sequencer1 + err = dymension.Unbond(ctx, "sequencer", rollapp1.GetSequencerKeyDir()) + require.NoError(t, err) + + seqAddr, err := dymension.AccountKeyBech32WithKeyDir(ctx, "sequencer", rollapp1.GetSequencerKeyDir()) + require.NoError(t, err) + + queryGetSequencerResponse, err := dymension.QueryShowSequencer(ctx, seqAddr) + require.NoError(t, err) + require.Equal(t, "OPERATING_STATUS_BONDED", queryGetSequencerResponse.Sequencer.Status) + + // err = testutil.WaitForBlocks(ctx, 30, dymension, rollapp1) + // require.NoError(t, err) + + lastBlock, err := rollapp1.Height(ctx) + require.NoError(t, err) + + time.Sleep(200 * time.Second) + + err = rollapp1.StopAllNodes(ctx) + require.NoError(t, err) + + _ = rollapp1.StartAllNodes(ctx) + + containerID = fmt.Sprintf("ra-rollappevm_1234-1-fn-0-%s", t.Name()) + + currentProposer, err = dymension.GetNode().GetProposerByRollapp(ctx, rollapp1.Config().ChainID, dymensionUserAddr) + require.NoError(t, err) + require.NotEqual(t, resp0.Sequencers[0].Address, currentProposer.ProposerAddr) + + operatorAddress, err := rollapp1.GetNode().QueryOperatorAddress(ctx) + require.NoError(t, err) + fmt.Printf("OperatorAddress: %s\n", operatorAddress.Sequencers[1].OperatorAddress) + operatorAddr := operatorAddress.Sequencers[1].OperatorAddress + + rewardAddress, err := rollapp1.GetNode().QuerySequencersRewardAddressResponse(ctx, operatorAddr) + require.NoError(t, err) + rewardAddrStr := rewardAddress.RewardAddr + fmt.Printf("RewardAddress1: %s\n", rewardAddrStr) + + // Get the container details + containerJSON, err = client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err = rollapp1.FullNodes[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node = fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir = strings.Split(rollapp1.Validators[0].HomeDir(), "/") + rollapp1FolderName = rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err = os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines = []string{} + scanner = bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output = strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.Validators[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.Validators[0].StartContainer(ctx) + require.NoError(t, err) + + time.Sleep(120 * time.Second) + + wallet, found = r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()+"/sequencer_keys", []string{wallet.FormattedAddress()}) + require.NoError(t, err) + + afterBlock, err := rollapp1.Height(ctx) + require.NoError(t, err) + require.True(t, afterBlock > lastBlock) + + channel, err = ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + // err = r.StartRelayer(ctx, eRep, ibcPath) + // require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get original account balances + // 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() + + rollappOrigBal2, err := rollapp1.GetBalance(ctx, rollappUserAddr, rollapp1.Config().Denom) + require.NoError(t, err) + dymensionOrigBal2, err := dymension.GetBalance(ctx, dymensionUserAddr, rollappIBCDenom) + require.NoError(t, err) + + // Send a normal ibc tx from RA -> Hub + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransferAfterHardFork(ctx, channel.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, rollappOrigBal2.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) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + 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, dymensionUserAddr, rollappIBCDenom, dymensionOrigBal2.Add(transferData.Amount).Sub(bridgingFee)) + + err = testutil.WaitForBlocks(ctx, 10, rollapp1) + require.NoError(t, err) + + //Query reward address + balance, err := rollapp1.GetBalance(ctx, rewardAddrStr, rollapp1.Config().Denom) + require.NoError(t, err) + require.True(t, balance.Sign() > 0, fmt.Sprintf("Balance is not greater than 0. Actual balance: %s", balance.String())) + + var baseProposerReward float64 + for _, kv := range modifyRAGenesisKV { + if kv.Key == "app_state.distribution.params.base_proposer_reward" { + valueStr, ok := kv.Value.(string) + require.True(t, ok, "kv.Value should be a string") + value, err := strconv.ParseFloat(valueStr, 64) + require.NoError(t, err) + baseProposerReward = value + break + } + } + feesCollected := float64(4000000000000000) + expectedAmount := int64(feesCollected * baseProposerReward) + expectedAmountInt := math.NewInt(expectedAmount) + + testutil.AssertBalance(t, ctx, rollapp1, rewardAddrStr, rollapp1.Config().Denom, expectedAmountInt) +} + +func Test_SeqRewardsAddress_Update_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp 1 + 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"] = "rollappwasm_1234-1" dymintTomlOverrides["settlement_gas_prices"] = "0adym" dymintTomlOverrides["max_idle_time"] = "3s" dymintTomlOverrides["max_proof_time"] = "500ms" @@ -473,7 +1451,7 @@ func Test_SeqRewardsAddress_Update_EVM(t *testing.T) { configFileOverrides["config/dymint.toml"] = dymintTomlOverrides modifyRAGenesisKV := append( - rollappEVMGenesisKV, + rollappWasmGenesisKV, cosmos.GenesisKV{ Key: "app_state.rollappparams.params.da", Value: "grpc", @@ -500,18 +1478,18 @@ func Test_SeqRewardsAddress_Update_EVM(t *testing.T) { ChainConfig: ibc.ChainConfig{ Type: "rollapp-dym", Name: "rollapp-temp", - ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappEVMImage}, + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, Bin: "rollappd", - Bech32Prefix: "ethm", + Bech32Prefix: "rol", Denom: "urax", - CoinType: "60", + CoinType: "118", GasPrices: "0.0urax", GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, - ModifyGenesis: modifyRollappEVMGenesis(modifyRAGenesisKV), + ModifyGenesis: modifyRollappWasmGenesis(modifyRAGenesisKV), ConfigFileOverrides: configFileOverrides, }, NumValidators: &numRollAppVals, @@ -579,7 +1557,7 @@ func Test_SeqRewardsAddress_Update_EVM(t *testing.T) { }, nil, "", nil, true, 1179360, true) require.NoError(t, err) - containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) // Get the container details containerJSON, err := client.ContainerInspect(context.Background(), containerID) @@ -792,14 +1770,14 @@ func Test_SeqRewardsAddress_Update_EVM(t *testing.T) { require.NoError(t, err) // Get the IBC denom - dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) - dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) - erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") - require.NoError(t, err) - erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address - testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) nextProposer, err := dymension.GetNode().GetNextProposerByRollapp(ctx, rollapp1.Config().ChainID, dymensionUserAddr) require.NoError(t, err) @@ -833,7 +1811,7 @@ func Test_SeqRewardsAddress_Update_EVM(t *testing.T) { _ = rollapp1.StartAllNodes(ctx) - containerID = fmt.Sprintf("ra-rollappevm_1234-1-fn-0-%s", t.Name()) + containerID = fmt.Sprintf("ra-rollappwasm_1234-1-fn-0-%s", t.Name()) currentProposer, err = dymension.GetNode().GetProposerByRollapp(ctx, rollapp1.Config().ChainID, dymensionUserAddr) require.NoError(t, err) diff --git a/tests/sequencer_rotation_test.go b/tests/sequencer_rotation_test.go index 3220b9b3..ee3ed702 100644 --- a/tests/sequencer_rotation_test.go +++ b/tests/sequencer_rotation_test.go @@ -7338,3 +7338,519 @@ func Test_SeqRotation_Forced_DA_EVM(t *testing.T) { // Minus 0.1% of transfer amount for bridge fee testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, dymensionOrigBal2.Add(transferData.Amount).Sub(bridgingFee)) } + +func Test_SeqRotation_Forced_DA_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp 1 + 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"] = "rollappwasm_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"] = "true" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides := make(map[string]any) + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppVals := 1 + numRollAppFn := 3 + + modifyHubGenesisKV := append( + dymensionGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.sequencer.params.dishonor_kick_threshold", + Value: "1", + }, + cosmos.GenesisKV{ + Key: "app_state.rollapp.params.liveness_slash_blocks", + Value: "1", + }, + cosmos.GenesisKV{ + Key: "app_state.rollapp.params.liveness_slash_interval", + Value: "1", + }, + ) + + modifyRAGenesisKV := append( + rollappWasmGenesisKV, + + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyRAGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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(modifyHubGenesisKV), + ConfigFileOverrides: nil, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + StartDA(ctx, t, client, network) + // relayer for rollapp 1 + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + }, nil, "", nil, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + for i := 0; i <= 2; i++ { + rollappHomeDir := strings.Split(rollapp1.FullNodes[i].HomeDir(), "/") + rollappFolderName := rollappHomeDir[len(rollappHomeDir)-1] + + filePath := fmt.Sprintf("/tmp/%s/config/dymint.toml", rollappFolderName) + file, err := os.Open(filePath) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for j, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[j] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(filePath) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + err = rollapp1.FullNodes[i].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[i].StartContainer(ctx) + require.NoError(t, err) + } + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 2, dymension, rollapp1) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + // Check IBC Transfer before switch + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + 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: transferAmount, + } + + // Compose an IBC transfer and send from rollapp -> Hub + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + // 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() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + + cmd := append([]string{rollapp1.FullNodes[0].Chain.Config().Bin}, "dymint", "show-sequencer", "--home", rollapp1.FullNodes[0].HomeDir()) + pub1, _, err := rollapp1.FullNodes[0].Exec(ctx, cmd, nil) + require.NoError(t, err) + + err = dymension.FullNodes[0].CreateKeyWithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + sequencer, err := dymension.AccountKeyBech32WithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + fund := ibc.WalletData{ + Address: sequencer, + Denom: dymension.Config().Denom, + Amount: math.NewInt(10_000_000_000_000).MulRaw(100_000_000), + } + err = dymension.SendFunds(ctx, "faucet", fund) + require.NoError(t, err) + + resp0, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp0.Sequencers), 1, "should have 1 sequences") + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + // stop proposer => slashing then + err = rollapp1.Validators[0].StopContainer(ctx) + require.NoError(t, err) + + testutil.WaitForBlocks(ctx, 2, dymension) + + err = rollapp1.Validators[0].StartContainer(ctx) + require.NoError(t, err) + + // full node B bond + command := []string{"sequencer", "create-sequencer", string(pub1), rollapp1.Config().ChainID, "100000000000000000000adym", rollapp1.GetSequencerKeyDir() + "/metadata_sequencer1.json", + "--broadcast-mode", "async", "--keyring-dir", rollapp1.FullNodes[0].HomeDir() + "/sequencer_keys"} + + _, err = dymension.FullNodes[0].ExecTx(ctx, "sequencer", command...) + require.NoError(t, err) + + cmd = append([]string{rollapp1.FullNodes[1].Chain.Config().Bin}, "dymint", "show-sequencer", "--home", rollapp1.FullNodes[1].HomeDir()) + pub1, _, err = rollapp1.FullNodes[1].Exec(ctx, cmd, nil) + require.NoError(t, err) + + err = dymension.FullNodes[0].CreateKeyWithKeyDir(ctx, "sequencer", rollapp1.FullNodes[1].HomeDir()) + require.NoError(t, err) + + sequencerAddr, err := dymension.AccountKeyBech32WithKeyDir(ctx, "sequencer", rollapp1.FullNodes[1].HomeDir()) + require.NoError(t, err) + + remainingBond, err := dymension.GetBalance(ctx, sequencerAddr, dymension.Config().Denom) + require.NoError(t, err) + fmt.Printf("Remaining bond: %s\n", remainingBond.String()) + + resp, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp.Sequencers), 2, "should have 2 sequences") + + nextProposer, err := dymension.GetNode().GetNextProposerByRollapp(ctx, rollapp1.Config().ChainID, dymensionUserAddr) + require.NoError(t, err) + require.Equal(t, "sentinel", nextProposer.NextProposerAddr) + fmt.Printf("NextProposer: %+v\n", nextProposer) + + currentProposer, err := dymension.GetNode().GetProposerByRollapp(ctx, rollapp1.Config().ChainID, dymensionUserAddr) + require.NoError(t, err) + require.Equal(t, resp0.Sequencers[0].Address, currentProposer.ProposerAddr) + fmt.Printf("CurrentProposer: %+v\n", currentProposer) + + // kick current proposer + err = dymension.FullNodes[0].KickProposer(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + // check client was frozen after kicked + clientStatus, err := dymension.GetNode().QueryClientStatus(ctx, "07-tendermint-0") + require.NoError(t, err) + require.Equal(t, "Frozen", clientStatus.Status) + + rollapp1ValHomeDir := strings.Split(rollapp1.Validators[0].HomeDir(), "/") + rollapp1ValFolderName := rollapp1ValHomeDir[len(rollapp1ValHomeDir)-1] + + err = os.RemoveAll(fmt.Sprintf("/tmp/%s/data", rollapp1FolderName)) + require.NoError(t, err) + + err = os.RemoveAll(fmt.Sprintf("/tmp/%s/data", rollapp1ValFolderName)) + require.NoError(t, err) + + for i, fullNode := range rollapp1.FullNodes { + fmt.Printf("Stopping Full Node %d: %s\n", i, fullNode.Name()) + err := fullNode.StopContainer(ctx) + require.NoError(t, err) + } + + err = rollapp1.Validators[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + fmt.Printf("Start Full Node 0: \n") + require.NoError(t, err) + + err = rollapp1.FullNodes[1].StartContainer(ctx) + fmt.Printf("Start Full Node 1: \n") + require.NoError(t, err) + + err = rollapp1.FullNodes[2].StartContainer(ctx) + fmt.Printf("Start Full Node 2: \n") + require.NoError(t, err) + + err = rollapp1.Validators[0].StartContainer(ctx) + + if err != nil { + err = rollapp1.Validators[0].StopContainer(ctx) + require.NoError(t, err) + err = rollapp1.Validators[0].StartContainer(ctx) + } + + // check client was frozen after kicked + clientStatus, err = dymension.GetNode().QueryClientStatus(ctx, "07-tendermint-0") + require.NoError(t, err) + require.Equal(t, "Active", clientStatus.Status) + + wallet, found = r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + err = testutil.WaitForBlocks(ctx, 10, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()+"/sequencer_keys", []string{wallet.FormattedAddress()}) + require.NoError(t, err) + + err = r.StopRelayer(ctx, eRep) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get original account balances + // 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() + + rollappOrigBal2, err := rollapp1.GetBalance(ctx, rollappUserAddr, rollapp1.Config().Denom) + require.NoError(t, err) + dymensionOrigBal2, err := dymension.GetBalance(ctx, dymensionUserAddr, rollappIBCDenom) + require.NoError(t, err) + + // Send a normal ibc tx from RA -> Hub + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransferAfterHardFork(ctx, channel.ChannelID, rollappUserAddr, transferData, ibc.TransferOptions{}) + + 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, rollappOrigBal2.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) + + res, err = dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + 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, dymensionUserAddr, rollappIBCDenom, dymensionOrigBal2.Add(transferData.Amount).Sub(bridgingFee)) +} + diff --git a/tests/sequencer_test.go b/tests/sequencer_test.go index 59273507..de08034d 100644 --- a/tests/sequencer_test.go +++ b/tests/sequencer_test.go @@ -314,6 +314,293 @@ func TestSequencerCelestia_EVM(t *testing.T) { require.True(t, isFinalized) } +func TestSequencerCelestia_Wasm(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"] = "rollappwasm_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" + + configFileOverrides1 := make(map[string]any) + configTomlOverrides1 := make(testutil.Toml) + configTomlOverrides1["timeout_commit"] = "2s" + configTomlOverrides1["timeout_propose"] = "2s" + configTomlOverrides1["index_all_keys"] = "true" + configTomlOverrides1["mode"] = "validator" + + configFileOverrides1["config/config.toml"] = configTomlOverrides1 + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 0 + numRollAppVals := 1 + nodeStore := "/home/celestia/light" + p2pNetwork := "mocha-4" + coreIp := "mocha-4-consensus.mesa.newmetric.xyz" + // trustedHash := "\"017428B113893E854767E626BC9CF860BDF49C2AC2DF56F3C1B6582B2597AC6E\"" + // sampleFrom := 2423882 + + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "celestia", + }, + ) + + url := "https://api-mocha.celenium.io/v1/block/count" + headerKey := "User-Agent" + headerValue := "Apidog/1.0.0 (https://apidog.com)" + rpcEndpoint := "http://rpc-mocha.pops.one:26657" + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "celes-hub", + ChainConfig: ibc.ChainConfig{ + Name: "celestia", + Denom: "utia", + Type: "hub-celes", + GasPrices: "0.002utia", + TrustingPeriod: "112h", + ChainID: "test", + Bin: "celestia-appd", + Images: []ibc.DockerImage{ + { + Repository: "ghcr.io/decentrio/light", + Version: "latest", + UidGid: "1025:1025", + }, + }, + Bech32Prefix: "celestia", + CoinType: "118", + GasAdjustment: 1.5, + ConfigFileOverrides: configFileOverrides1, + }, + NumValidators: &numHubVals, + NumFullNodes: &numRollAppFn, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + celestia := chains[0].(*celes_hub.CelesHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + ic := test.NewSetup(). + AddChain(celestia) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: false, + + // 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, 1179360, true) + require.NoError(t, err) + + validator, err := celestia.GetNode().AccountKeyBech32(ctx, "validator") + require.NoError(t, err) + // Get fund for submit blob + GetFaucet("http://18.184.170.181:3000/api/get-tia", validator) + + err = testutil.WaitForBlocks(ctx, 8, celestia) + require.NoError(t, err) + + err = celestia.GetNode().InitCelestiaDaLightNode(ctx, nodeStore, p2pNetwork, nil) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 3, celestia) + require.NoError(t, err) + + file, err := os.Open("/tmp/celestia/light/config.toml") + require.NoError(t, err) + defer file.Close() + + lastestBlockHeight, err := GetLatestBlockHeight(url, headerKey, headerValue) + require.NoError(t, err) + lastestBlockHeight = strings.TrimRight(lastestBlockHeight, "\n") + heightOfBlock, err := strconv.ParseInt(lastestBlockHeight, 10, 64) // base 10, bit size 64 + require.NoError(t, err) + + hash, err := celestia.GetNode().GetHashOfBlockHeightWithCustomizeRpcEndpoint(ctx, fmt.Sprintf("%d", heightOfBlock-2), rpcEndpoint) + require.NoError(t, err) + + fmt.Println(hash) + + hash = strings.TrimRight(hash, "\n") + var lines []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, " TrustedHash =") { + lines[i] = fmt.Sprintf(" TrustedHash = \"%s\"", hash) + } else if strings.HasPrefix(line, " SampleFrom =") { + lines[i] = fmt.Sprintf(" SampleFrom = %d", heightOfBlock-2) + } else if strings.HasPrefix(line, " Address =") { + lines[i] = fmt.Sprintf(" Address = \"0.0.0.0\"") + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create("/tmp/celestia/light/config.toml") + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + containerID := fmt.Sprintf("test-val-0-%s", t.Name()) + + // Create an exec instance + execConfig := types.ExecConfig{ + Cmd: strslice.StrSlice([]string{"celestia", "light", "start", "--node.store", nodeStore, "--gateway", "--core.ip", coreIp, "--p2p.network", p2pNetwork, "--keyring.keyname", "validator"}), // Replace with your command and arguments + } + + execIDResp, err := client.ContainerExecCreate(ctx, containerID, execConfig) + if err != nil { + fmt.Println("Err:", err) + } + + execID := execIDResp.ID + + // Start the exec instance + execStartCheck := types.ExecStartCheck{ + Tty: false, + } + + if err := client.ContainerExecStart(ctx, execID, execStartCheck); err != nil { + fmt.Println("Err:", err) + } + + // _ = celestia.GetNode().StartCelestiaDaLightNode(ctx, nodeStore, coreIp, p2pNetwork, nil) + // require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, celestia) + require.NoError(t, err) + + celestia_token, err := celestia.GetNode().GetAuthTokenCelestiaDaLight(ctx, p2pNetwork, nodeStore) + require.NoError(t, err) + println("check token: ", celestia_token) + celestia_namespace_id, err := RandomHex(10) + require.NoError(t, err) + println("check namespace: ", celestia_namespace_id) + da_config := fmt.Sprintf("{\"base_url\": \"http://test-val-0-%s:26658\", \"timeout\": 60000000000, \"gas_prices\":1.0, \"gas_adjustment\": 1.3, \"namespace_id\": \"%s\", \"auth_token\":\"%s\"}", t.Name(), celestia_namespace_id, celestia_token) + + configFileOverrides := make(map[string]any) + dymintTomlOverrides["namespace_id"] = celestia_namespace_id + dymintTomlOverrides["da_config"] = da_config + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + cf = test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + ic = test.NewSetup(). + AddRollUp(dymension, rollapp1) + + 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, 1179360, true) + require.NoError(t, err) + + celestia.StopAllNodes(ctx) + + rollappHeight, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + // wait until the packet is finalized + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 180) + require.Error(t, err) + require.False(t, isFinalized) + + celestia.StartAllNodes(ctx) + + execIDResp, err = client.ContainerExecCreate(ctx, containerID, execConfig) + if err != nil { + fmt.Println("Err:", err) + } + + execID = execIDResp.ID + + // Start the exec instance + execStartCheck = types.ExecStartCheck{ + Tty: false, + } + + if err := client.ContainerExecStart(ctx, execID, execStartCheck); err != nil { + fmt.Println("Err:", err) + } + + // wait until the packet is finalized + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) +} + func TestSequencerHubDisconnection_EVM(t *testing.T) { if testing.Short() { t.Skip() @@ -325,7 +612,304 @@ func TestSequencerHubDisconnection_EVM(t *testing.T) { dymintTomlOverrides := make(testutil.Toml) dymintTomlOverrides["settlement_layer"] = "dymension" dymintTomlOverrides["settlement_node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) // Hub RPC not available - dymintTomlOverrides["rollapp_id"] = "rollappevm_1234-1" + 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"] = "100s" + dymintTomlOverrides["p2p_blocksync_enabled"] = "false" + + configFileOverrides1 := make(map[string]any) + configTomlOverrides1 := make(testutil.Toml) + configTomlOverrides1["timeout_commit"] = "2s" + configTomlOverrides1["timeout_propose"] = "2s" + configTomlOverrides1["index_all_keys"] = "true" + configTomlOverrides1["mode"] = "validator" + + configFileOverrides1["config/config.toml"] = configTomlOverrides1 + + modifyEVMGenesisKV := append( + rollappEVMGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "celestia", + }, + ) + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 0 + numRollAppVals := 1 + nodeStore := "/home/celestia/light" + p2pNetwork := "mocha-4" + coreIp := "mocha-4-consensus.mesa.newmetric.xyz" + // trustedHash := "\"017428B113893E854767E626BC9CF860BDF49C2AC2DF56F3C1B6582B2597AC6E\"" + // sampleFrom := 2423882 + + url := "https://api-mocha.celenium.io/v1/block/count" + headerKey := "User-Agent" + headerValue := "Apidog/1.0.0 (https://apidog.com)" + rpcEndpoint := "http://rpc-mocha.pops.one:26657" + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "celes-hub", + ChainConfig: ibc.ChainConfig{ + Name: "celestia", + Denom: "utia", + Type: "hub-celes", + GasPrices: "0.002utia", + TrustingPeriod: "112h", + ChainID: "test", + Bin: "celestia-appd", + Images: []ibc.DockerImage{ + { + Repository: "ghcr.io/decentrio/light", + Version: "latest", + UidGid: "1025:1025", + }, + }, + Bech32Prefix: "celestia", + CoinType: "118", + GasAdjustment: 1.5, + ConfigFileOverrides: configFileOverrides1, + }, + NumValidators: &numHubVals, + NumFullNodes: &numRollAppFn, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + celestia := chains[0].(*celes_hub.CelesHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + ic := test.NewSetup(). + AddChain(celestia) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: false, + + // 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, 1179360, true) + require.NoError(t, err) + + validator, err := celestia.GetNode().AccountKeyBech32(ctx, "validator") + require.NoError(t, err) + // Get fund for submit blob + GetFaucet("http://18.184.170.181:3000/api/get-tia", validator) + err = testutil.WaitForBlocks(ctx, 8, celestia) + require.NoError(t, err) + + GetFaucet("http://18.184.170.181:3000/api/get-tia", validator) + err = testutil.WaitForBlocks(ctx, 8, celestia) + require.NoError(t, err) + + GetFaucet("http://18.184.170.181:3000/api/get-tia", validator) + err = testutil.WaitForBlocks(ctx, 8, celestia) + require.NoError(t, err) + + err = celestia.GetNode().InitCelestiaDaLightNode(ctx, nodeStore, p2pNetwork, nil) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 3, celestia) + require.NoError(t, err) + + file, err := os.Open("/tmp/celestia/light/config.toml") + require.NoError(t, err) + defer file.Close() + + lastestBlockHeight, err := GetLatestBlockHeight(url, headerKey, headerValue) + require.NoError(t, err) + lastestBlockHeight = strings.TrimRight(lastestBlockHeight, "\n") + heightOfBlock, err := strconv.ParseInt(lastestBlockHeight, 10, 64) // base 10, bit size 64 + require.NoError(t, err) + + hash, err := celestia.GetNode().GetHashOfBlockHeightWithCustomizeRpcEndpoint(ctx, fmt.Sprintf("%d", heightOfBlock-2), rpcEndpoint) + require.NoError(t, err) + + fmt.Println(hash) + + hash = strings.TrimRight(hash, "\n") + var lines []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, " TrustedHash =") { + lines[i] = fmt.Sprintf(" TrustedHash = \"%s\"", hash) + } else if strings.HasPrefix(line, " SampleFrom =") { + lines[i] = fmt.Sprintf(" SampleFrom = %d", heightOfBlock-2) + } else if strings.HasPrefix(line, " Address =") { + lines[i] = fmt.Sprintf(" Address = \"0.0.0.0\"") + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create("/tmp/celestia/light/config.toml") + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + containerID := fmt.Sprintf("test-val-0-%s", t.Name()) + + // Create an exec instance + execConfig := types.ExecConfig{ + Cmd: strslice.StrSlice([]string{"celestia", "light", "start", "--node.store", nodeStore, "--gateway", "--core.ip", coreIp, "--p2p.network", p2pNetwork, "--keyring.keyname", "validator"}), // Replace with your command and arguments + } + + execIDResp, err := client.ContainerExecCreate(ctx, containerID, execConfig) + if err != nil { + fmt.Println("Err:", err) + } + + execID := execIDResp.ID + + // Start the exec instance + execStartCheck := types.ExecStartCheck{ + Tty: false, + } + + if err := client.ContainerExecStart(ctx, execID, execStartCheck); err != nil { + fmt.Println("Err:", err) + } + + // _ = celestia.GetNode().StartCelestiaDaLightNode(ctx, nodeStore, coreIp, p2pNetwork, nil) + // require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, celestia) + require.NoError(t, err) + + celestia_token, err := celestia.GetNode().GetAuthTokenCelestiaDaLight(ctx, p2pNetwork, nodeStore) + require.NoError(t, err) + println("check token: ", celestia_token) + celestia_namespace_id, err := RandomHex(10) + require.NoError(t, err) + println("check namespace: ", celestia_namespace_id) + da_config := fmt.Sprintf("{\"base_url\": \"http://test-val-0-%s:26658\", \"timeout\": 60000000000, \"gas_prices\":1.0, \"gas_adjustment\": 1.3, \"namespace_id\": \"%s\", \"auth_token\":\"%s\"}", t.Name(), celestia_namespace_id, celestia_token) + + configFileOverrides := make(map[string]any) + dymintTomlOverrides["namespace_id"] = celestia_namespace_id + dymintTomlOverrides["da_config"] = da_config + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + 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(modifyEVMGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic = test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + rollappHeight, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + // wait until the packet is finalized + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + dymension.StopAllNodes(ctx) + + rollappHeight, err = rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + // wait until the packet is finalized + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 60) + require.Error(t, err) + require.False(t, isFinalized) + + dymension.StartAllNodes(ctx) + + // wait until the packet is finalized + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 600) + require.NoError(t, err) + require.True(t, isFinalized) +} + +func TestSequencerHubDisconnection_Wasm(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()) // Hub RPC not available + dymintTomlOverrides["rollapp_id"] = "rollappwasm_1234-1" dymintTomlOverrides["settlement_gas_prices"] = "0adym" dymintTomlOverrides["max_idle_time"] = "3s" dymintTomlOverrides["max_proof_time"] = "500ms" @@ -341,8 +925,8 @@ func TestSequencerHubDisconnection_EVM(t *testing.T) { configFileOverrides1["config/config.toml"] = configTomlOverrides1 - modifyEVMGenesisKV := append( - rollappEVMGenesisKV, + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, cosmos.GenesisKV{ Key: "app_state.rollappparams.params.da", Value: "celestia", @@ -528,18 +1112,18 @@ func TestSequencerHubDisconnection_EVM(t *testing.T) { ChainConfig: ibc.ChainConfig{ Type: "rollapp-dym", Name: "rollapp-temp", - ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappEVMImage}, + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, Bin: "rollappd", - Bech32Prefix: "ethm", + Bech32Prefix: "rol", Denom: "urax", - CoinType: "60", + CoinType: "118", GasPrices: "0.0urax", GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, - ModifyGenesis: modifyRollappEVMGenesis(modifyEVMGenesisKV), + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), ConfigFileOverrides: configFileOverrides, }, NumValidators: &numRollAppVals, @@ -609,4 +1193,4 @@ func TestSequencerHubDisconnection_EVM(t *testing.T) { isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 600) require.NoError(t, err) require.True(t, isFinalized) -} +} \ No newline at end of file diff --git a/tests/setup.go b/tests/setup.go index 8d830c17..470f9a25 100644 --- a/tests/setup.go +++ b/tests/setup.go @@ -272,7 +272,7 @@ var ( rollappWasmGenesisKV = []cosmos.GenesisKV{ { Key: "app_state.rollappparams.params.drs_version", - Value: 5, + Value: 7, }, { Key: "app_state.gov.voting_params.voting_period", diff --git a/tests/time_upgrade_test.go b/tests/time_upgrade_test.go index 28d82c20..f865efb1 100644 --- a/tests/time_upgrade_test.go +++ b/tests/time_upgrade_test.go @@ -260,7 +260,7 @@ func Test_TimeBaseUpgrade_EVM(t *testing.T) { msg := map[string]interface{}{ "@type": "/rollapp.timeupgrade.types.MsgSoftwareUpgrade", "authority": "ethm10d07y265gmmuvt4z0w9aw880jnsr700jpva843", - "drs": 4, + "drs": 5, "upgrade_time": upgradeTime, } @@ -271,9 +271,9 @@ func Test_TimeBaseUpgrade_EVM(t *testing.T) { proposal := cosmos.TxProposalV1{ Deposit: "500000000000" + rollapp1.Config().Denom, - Title: "Update Dymension to DRS-2", - Summary: "This proposal aims to upgrade the Dymension rollapp to DRS 2, implementing new features and improvements, with a scheduled upgrade time.", - Description: "Upgrade Dymension to DRS-2 version with scheduled upgrade time", + Title: "Update Dymension to DRS-5", + Summary: "This proposal aims to upgrade the Dymension rollapp to DRS 5, implementing new features and improvements, with a scheduled upgrade time.", + Description: "Upgrade Dymension to DRS-5 version with scheduled upgrade time", Messages: []json.RawMessage{rawMsg}, Expedited: true, } @@ -358,6 +358,340 @@ func Test_TimeBaseUpgrade_EVM(t *testing.T) { testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) } +func Test_TimeBaseUpgrade_Wasm(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"] = "rollappwasm_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"] = "true" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 1 + numRollAppVals := 1 + + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + StartDA(ctx, t, client, network) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + res, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(res.Sequencers), 1, "should have 1 sequences") + + // Assuming block height is located in status["SyncInfo"]["latest_block_height"] + rollappHeightBeforeUpgrade, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err, "Failed to query Rollapp1 height before upgrade") + fmt.Printf("Rollapp1 current block height before upgrade version: %d\n", rollappHeightBeforeUpgrade) + + height, err := rollapp1.Height(ctx) + require.NoError(t, err, "error fetching height before submit upgrade proposal") + + haltHeight := height + haltHeightDelta + check, _ := rollapp1.GetNode().CliContext().GetNode() + blockInfo, _ := check.Block(ctx, &height) + blockTime := blockInfo.Block.Header.Time + fmt.Println("blockTime:", blockTime.Format(time.RFC3339)) + if err != nil { + panic(fmt.Errorf("failed to get latest block time: %w", err)) + } + + upgradeTime := blockTime.Add(90 * time.Second).Format(time.RFC3339) + fmt.Println("Upgrade Time:", upgradeTime) + msg := map[string]interface{}{ + "@type": "/rollapp.timeupgrade.types.MsgSoftwareUpgrade", + "authority": "rol10d07y265gmmuvt4z0w9aw880jnsr700juke5cz", + "drs": 7, + "upgrade_time": upgradeTime, + } + + rawMsg, err := json.Marshal(msg) + if err != nil { + fmt.Println("Err:", err) + } + + proposal := cosmos.TxProposalV1{ + Deposit: "500000000000" + rollapp1.Config().Denom, + Title: "Update Dymension to DRS-5", + Summary: "This proposal aims to upgrade the Dymension rollapp to DRS 5, implementing new features and improvements, with a scheduled upgrade time.", + Description: "Upgrade Dymension to DRS-5 version with scheduled upgrade time", + Messages: []json.RawMessage{rawMsg}, + Expedited: true, + } + + _, err = rollapp1.GetNode().SubmitProposal(ctx, rollappUser.KeyName(), proposal) + require.NoError(t, err, "error submitting software upgrade proposal tx") + + txProposal, err := rollapp1.GovDeposit(ctx, rollappUser.KeyName(), "1", "500000000000urax") + fmt.Printf("Successfully deposited for proposal: %v\n", txProposal) + + err = rollapp1.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) + require.NoError(t, err, "failed to submit votes") + + _, err = cosmos.PollForProposalStatus(ctx, rollapp1.CosmosChain, height, haltHeight, "1", cosmos.ProposalStatusPassed) + require.NoError(t, err) + + prop, err := rollapp1.QueryProposal(ctx, "1") + require.NoError(t, err) + + fmt.Println("prop: ", prop) + + require.Equal(t, cosmos.ProposalStatusPassed, prop.Status) + require.NoError(t, err, "proposal status did not change to passed in expected number of blocks") + + timeoutCtx, timeoutCtxCancel := context.WithTimeout(ctx, time.Second*90) + defer timeoutCtxCancel() + + height, err = rollapp1.Height(ctx) + require.NoError(t, err, "error fetching height before upgrade") + + // bring down nodes to prepare for upgrade + check2, _ := rollapp1.GetNode().CliContext().GetNode() + blockInfo2, _ := check2.Block(ctx, &height) + blockTime2 := blockInfo2.Block.Header.Time + fmt.Println("blockTime2:", blockTime2.Format(time.RFC3339)) + parsedUpgradeTime, err := time.Parse(time.RFC3339, upgradeTime) + fmt.Println("parsedUpgradeTime:", parsedUpgradeTime) + if err != nil { + panic(fmt.Errorf("failed to parse upgrade time: %w", err)) + } + + if blockTime2.After(parsedUpgradeTime) { + err = rollapp1.StopAllNodes(ctx) + } else { + // fmt.Println("blockTime2 is before upgradeTime") + err = testutil.WaitForTime(timeoutCtx, blockTime2, parsedUpgradeTime) + if err != nil { + fmt.Errorf("failed to wait for upgrade time: %w", err) + } + err = rollapp1.StopAllNodes(ctx) + } + require.NoError(t, err, "error stopping node(s)") + + // upgrade version on all nodes + rollapp1.UpgradeVersion(ctx, client, RollappWasmMainRepo, rollappWasmVersion) + + // start all nodes back up. + // validators reach consensus on first block after upgrade height + // and chain block production resumes. + + err = rollapp1.StartAllNodes(ctx) + require.NoError(t, err, "error starting upgraded node(s)") + + rollappHeightAfterUpgrade, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err, "Failed to query Rollapp1 height after upgrade") + fmt.Printf("Rollapp1 current block height after upgrade version: %d\n", rollappHeightAfterUpgrade) + require.Greater(t, rollappHeightAfterUpgrade, rollappHeightBeforeUpgrade, "Block height after upgrade should be greater than before upgrade") + + // Send a normal ibc tx from RA -> Hub + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) +} + func Test_TimeBaseUpgradeInPast_EVM(t *testing.T) { if testing.Short() { t.Skip() @@ -369,7 +703,291 @@ func Test_TimeBaseUpgradeInPast_EVM(t *testing.T) { 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["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"] = "true" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 1 + numRollAppVals := 1 + + modifyEVMGenesisKV := append( + rollappEVMGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + 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(modifyEVMGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + StartDA(ctx, t, client, network) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + res, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(res.Sequencers), 1, "should have 1 sequences") + + // Assuming block height is located in status["SyncInfo"]["latest_block_height"] + rollappHeightBeforeUpgrade, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err, "Failed to query Rollapp1 height before upgrade") + fmt.Printf("Rollapp1 current block height before upgrade version: %d\n", rollappHeightBeforeUpgrade) + + height, err := rollapp1.Height(ctx) + require.NoError(t, err, "error fetching height before submit upgrade proposal") + + haltHeight := height + haltHeightDelta + check, _ := rollapp1.GetNode().CliContext().GetNode() + blockInfo, _ := check.Block(ctx, &height) + // println("check data blocktime: ",blockInfo.Block.String()) + // blockTime, err := rollapp1.GetLatestBlockTime(ctx) + blockTime := blockInfo.Block.Header.Time + fmt.Println("blockTime:", blockTime.Format(time.RFC3339)) + if err != nil { + panic(fmt.Errorf("failed to get latest block time: %w", err)) + } + + upgradeTime := "2024-09-06T18:10:00Z" // upgrade time in the past + fmt.Println("Upgrade Time:", upgradeTime) + msg := map[string]interface{}{ + "@type": "/rollapp.timeupgrade.types.MsgSoftwareUpgrade", + "authority": "ethm10d07y265gmmuvt4z0w9aw880jnsr700jpva843", + "drs": 5, + "upgrade_time": upgradeTime, + } + + rawMsg, err := json.Marshal(msg) + if err != nil { + fmt.Println("Err:", err) + } + + proposal := cosmos.TxProposalV1{ + Deposit: "500000000000" + rollapp1.Config().Denom, + Title: "Update Dymension to DRS-5", + Summary: "This proposal aims to upgrade the Dymension rollapp to DRS 5, implementing new features and improvements, with a scheduled upgrade time.", + Description: "Upgrade Dymension to DRS-5 version with scheduled upgrade time", + Messages: []json.RawMessage{rawMsg}, + Expedited: true, + } + + _, err = rollapp1.GetNode().SubmitProposal(ctx, rollappUser.KeyName(), proposal) + require.NoError(t, err, "failed to submit proposal") + + txProposal, err := rollapp1.GovDeposit(ctx, rollappUser.KeyName(), "1", "500000000000urax") + fmt.Printf("Successfully deposited for proposal: %v\n", txProposal) + + err = rollapp1.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) + require.NoError(t, err, "failed to submit votes") + + _, err = cosmos.PollForProposalStatus(ctx, rollapp1.CosmosChain, height, haltHeight, "1", cosmos.ProposalStatusPassed) + require.Error(t, err) // this should error out as upgrade time is in the past + + // Send a normal ibc tx from RA -> Hub + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) +} + +func Test_TimeBaseUpgradeInPast_Wasm(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"] = "rollappwasm_1234-1" dymintTomlOverrides["settlement_gas_prices"] = "0adym" dymintTomlOverrides["max_idle_time"] = "3s" dymintTomlOverrides["max_proof_time"] = "500ms" @@ -384,8 +1002,8 @@ func Test_TimeBaseUpgradeInPast_EVM(t *testing.T) { numRollAppFn := 1 numRollAppVals := 1 - modifyEVMGenesisKV := append( - rollappEVMGenesisKV, + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, cosmos.GenesisKV{ Key: "app_state.rollappparams.params.da", Value: "grpc", @@ -398,18 +1016,18 @@ func Test_TimeBaseUpgradeInPast_EVM(t *testing.T) { ChainConfig: ibc.ChainConfig{ Type: "rollapp-dym", Name: "rollapp-temp", - ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappEVMImage}, + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, Bin: "rollappd", - Bech32Prefix: "ethm", + Bech32Prefix: "rol", Denom: "urax", - CoinType: "60", + CoinType: "118", GasPrices: "0.0urax", GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, - ModifyGenesis: modifyRollappEVMGenesis(modifyEVMGenesisKV), + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), ConfigFileOverrides: configFileOverrides, }, NumValidators: &numRollAppVals, @@ -463,7 +1081,7 @@ func Test_TimeBaseUpgradeInPast_EVM(t *testing.T) { }, nil, "", nil, true, 1179360, true) require.NoError(t, err) - containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) // Get the container details containerJSON, err := client.ContainerInspect(context.Background(), containerID) @@ -595,8 +1213,8 @@ func Test_TimeBaseUpgradeInPast_EVM(t *testing.T) { fmt.Println("Upgrade Time:", upgradeTime) msg := map[string]interface{}{ "@type": "/rollapp.timeupgrade.types.MsgSoftwareUpgrade", - "authority": "ethm10d07y265gmmuvt4z0w9aw880jnsr700jpva843", - "drs": 2, + "authority": "rol10d07y265gmmuvt4z0w9aw880jnsr700juke5cz", + "drs": 5, "upgrade_time": upgradeTime, } @@ -607,9 +1225,9 @@ func Test_TimeBaseUpgradeInPast_EVM(t *testing.T) { proposal := cosmos.TxProposalV1{ Deposit: "500000000000" + rollapp1.Config().Denom, - Title: "Update Dymension to DRS-2", - Summary: "This proposal aims to upgrade the Dymension rollapp to DRS 2, implementing new features and improvements, with a scheduled upgrade time.", - Description: "Upgrade Dymension to DRS-2 version with scheduled upgrade time", + Title: "Update Dymension to DRS-5", + Summary: "This proposal aims to upgrade the Dymension rollapp to DRS 5, implementing new features and improvements, with a scheduled upgrade time.", + Description: "Upgrade Dymension to DRS-5 version with scheduled upgrade time", Messages: []json.RawMessage{rawMsg}, Expedited: true, } diff --git a/tests/tokenless_test.go b/tests/tokenless_test.go index 502364ae..a8ad01d6 100644 --- a/tests/tokenless_test.go +++ b/tests/tokenless_test.go @@ -524,6 +524,264 @@ func TestTokenlessTransferSuccess_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } +func TestTokenlessTransferSuccess_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp + 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"] = "rollappwasm_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 + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 0 + numRollAppVals := 1 + + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.bank.denom_metadata", + Value: []interface{}{ + map[string]interface{}{ + "base": "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + "denom_units": []interface{}{ + map[string]interface{}{ + "aliases": []interface{}{}, + "denom": "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + "exponent": "0", + }, + map[string]interface{}{ + "aliases": []interface{}{}, + "denom": "DYM", + "exponent": "18", + }, + }, + "description": "Denom metadata for Rollapp wasm", + "display": "DYM", + "name": "DYM", + "symbol": "DYM", + }, + }, + }, + cosmos.GenesisKV{ + Key: "app_state.mint.params.mint_denom", + Value: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + }, + cosmos.GenesisKV{ + Key: "app_state.staking.params.bond_denom", + Value: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + }, + ) + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + CoinType: "118", + GasPrices: "0.0ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + // relayer for rollapp + r1 := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer1", network) + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r1, "relayer1"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r1, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + wallet, found := r1.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r1, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // Assert the accounts were funded + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount) + + channel, err := ibc.GetTransferChannel(ctx, r1, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + // require.NoError(t, err) + + err = r1.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + transferData := ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: bigTransferAmount, + } + + // Get the IBC denom + dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, walletAmount.Add(bigTransferAmount)) + + // Send a ibc tx from RA -> Hub + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from rollapp -> Hub + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + // wait until the packet is finalized + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(bigTransferAmount).Add(transferAmount.Sub(bridgingFee))) + + t.Cleanup( + func() { + err := r1.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + func TestTokenlessTransferDiffGas_EVM(t *testing.T) { if testing.Short() { t.Skip() @@ -593,19 +851,288 @@ func TestTokenlessTransferDiffGas_EVM(t *testing.T) { Key: "app_state.evm.params.gas_denom", Value: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", }, - cosmos.GenesisKV{ - Key: "app_state.rollappparams.params.min_gas_prices", - Value: []interface{}{ - map[string]interface{}{ - "amount": "1", - "denom": "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", - }, - }, - }, - cosmos.GenesisKV{ - Key: "app_state.feemarket.params.min_gas_price", - Value: "1.0", - }, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.min_gas_prices", + Value: []interface{}{ + map[string]interface{}{ + "amount": "1", + "denom": "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + }, + }, + }, + cosmos.GenesisKV{ + Key: "app_state.feemarket.params.min_gas_price", + Value: "1.0", + }, + ) + + 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: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + CoinType: "60", + GasPrices: "10.0ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + GasAdjustment: 1.3, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappEVMGenesis(modifyEVMGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + // relayer for rollapp + r1 := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer1", network) + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r1, "relayer1"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r1, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + wallet, found := r1.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 20, dymension, rollapp1) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r1, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // Assert the accounts were funded + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount) + + channel, err := ibc.GetTransferChannel(ctx, r1, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + // require.NoError(t, err) + + err = r1.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + transferData := ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: bigTransferAmount, + } + + // Get the IBC denom + dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, walletAmount.Add(bigTransferAmount)) + + // Send a ibc tx from RA -> Hub + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + command := []string{"rollappd", "tx", "ibc-transfer", "transfer", "transfer", "channel-0", transferData.Address, fmt.Sprintf("%s%s", transferData.Amount.String(), transferData.Denom), "--gas", "auto", "--gas-prices", "10.0urax", "--gas-adjustment", "1.1", "--from", rollappUserAddr, "--keyring-backend", "test", "--output", "json", "-y", "--home", rollapp1.HomeDir(), "--node", fmt.Sprintf("tcp://%s:26657", rollapp1.Validators[0].HostName()), "--chain-id", "rollappevm_1234-1"} + + stdout, _, err := rollapp1.Validators[0].Exec(ctx, command, nil) + require.NoError(t, err) + + fmt.Println(stdout) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + rollappHeight, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + // wait until the packet is finalized + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(bigTransferAmount)) + + t.Cleanup( + func() { + err := r1.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + +func TestUpdateMinGasPrice_EVM(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp + 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 + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 0 + numRollAppVals := 1 + + modifyEVMGenesisKV := append( + rollappEVMGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.bank.denom_metadata", + Value: []interface{}{ + map[string]interface{}{ + "base": "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + "denom_units": []interface{}{ + map[string]interface{}{ + "aliases": []interface{}{}, + "denom": "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + "exponent": "0", + }, + map[string]interface{}{ + "aliases": []interface{}{}, + "denom": "DYM", + "exponent": "18", + }, + }, + "description": "Denom metadata for Rollapp EVM", + "display": "DYM", + "name": "DYM", + "symbol": "DYM", + }, + }, + }, + cosmos.GenesisKV{ + Key: "app_state.mint.params.mint_denom", + Value: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + }, + cosmos.GenesisKV{ + Key: "app_state.staking.params.bond_denom", + Value: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + }, + cosmos.GenesisKV{ + Key: "app_state.evm.params.evm_denom", + Value: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + }, + cosmos.GenesisKV{ + Key: "app_state.evm.params.gas_denom", + Value: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + }, ) cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ @@ -620,8 +1147,8 @@ func TestTokenlessTransferDiffGas_EVM(t *testing.T) { Bech32Prefix: "ethm", Denom: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", CoinType: "60", - GasPrices: "10.0ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", - GasAdjustment: 1.3, + GasPrices: "0.0ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, @@ -664,17 +1191,18 @@ func TestTokenlessTransferDiffGas_EVM(t *testing.T) { // Relayer Factory client, network := test.DockerSetup(t) - // relayer for rollapp - r1 := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), - ).Build(t, client, "relayer1", network) + ).Build(t, client, "relayer", network) + ic := test.NewSetup(). AddRollUp(dymension, rollapp1). - AddRelayer(r1, "relayer1"). + AddRelayer(r, "relayer"). AddLink(test.InterchainLink{ Chain1: dymension, Chain2: rollapp1, - Relayer: r1, + Relayer: r, Path: ibcPath, }) @@ -692,13 +1220,13 @@ func TestTokenlessTransferDiffGas_EVM(t *testing.T) { }, nil, "", nil, false, 1179360, true) require.NoError(t, err) - wallet, found := r1.GetWallet(rollapp1.Config().ChainID) + wallet, found := r.GetWallet(rollapp1.Config().ChainID) require.True(t, found) keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() keyPath := keyDir + "/sequencer_keys" - err = testutil.WaitForBlocks(ctx, 20, dymension, rollapp1) + err = testutil.WaitForBlocks(ctx, 5, dymension) require.NoError(t, err) //Update white listed relayers @@ -708,9 +1236,10 @@ func TestTokenlessTransferDiffGas_EVM(t *testing.T) { require.NoError(t, err) } - CreateChannel(ctx, t, r1, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + // Create some user accounts on both chains - users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1, rollapp1) + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) // Get our Bech32 encoded user addresses dymensionUser, rollappUser := users[0], users[1] @@ -718,19 +1247,64 @@ func TestTokenlessTransferDiffGas_EVM(t *testing.T) { dymensionUserAddr := dymensionUser.FormattedAddress() rollappUserAddr := rollappUser.FormattedAddress() - // Assert the accounts were funded - testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount) - testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount) - - channel, err := ibc.GetTransferChannel(ctx, r1, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) - // require.NoError(t, err) + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) - err = r1.StartRelayer(ctx, eRep, ibcPath) + err = r.StartRelayer(ctx, eRep, ibcPath) 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: transferAmount, + // } + // _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + // res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + // fmt.Println(res) + // require.NoError(t, err) + + // for _, packet := range res.RollappPackets { + + // proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + // isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + // require.NoError(t, err) + // require.True(t, isFinalized) + // txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + // 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() + + // // Minus 0.1% of transfer amount for bridge fee + // testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + transferData := ibc.WalletData{ Address: rollappUserAddr, Denom: dymension.Config().Denom, @@ -755,6 +1329,39 @@ func TestTokenlessTransferDiffGas_EVM(t *testing.T) { require.NoError(t, err) testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, walletAmount.Add(bigTransferAmount)) + // Change the min gas price rollapp param using gov + newMinGasPriceParam := json.RawMessage(`[ + { + "denom": "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", + "amount": "1" + } + ]`) + _, err = rollapp1.GetNode().ParamChangeProposal(ctx, rollappUser.KeyName(), + &utils.ParamChangeProposalJSON{ + Title: "Change min gas price param", + Description: "Change min gas price param", + Changes: utils.ParamChangesJSON{ + utils.NewParamChangeJSON("rollappparams", "minGasPrices", newMinGasPriceParam), + }, + Deposit: "500000000000" + rollapp1.Config().Denom, // greater than min deposit + }) + require.NoError(t, err) + + err = rollapp1.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) + require.NoError(t, err, "failed to submit votes") + + height, err := rollapp1.Height(ctx) + require.NoError(t, err, "error fetching height") + _, err = cosmos.PollForProposalStatus(ctx, rollapp1.CosmosChain, height, height+30, "1", cosmos.ProposalStatusPassed) + require.NoError(t, err, "proposal status did not change to passed") + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + paramsChange, err := rollapp1.GetNode().QueryParam(ctx, "rollappparams", "minGasPrices") + require.NoError(t, err) + require.Equal(t, `[{"denom":"ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D","amount":"1.000000000000000000"}]`, paramsChange.Value) + // Send a ibc tx from RA -> Hub transferData = ibc.WalletData{ Address: dymensionUserAddr, @@ -762,7 +1369,7 @@ func TestTokenlessTransferDiffGas_EVM(t *testing.T) { Amount: transferAmount, } - command := []string{"rollappd", "tx", "ibc-transfer", "transfer", "transfer", "channel-0", transferData.Address, fmt.Sprintf("%s%s", transferData.Amount.String(), transferData.Denom), "--gas", "auto", "--gas-prices", "10.0urax", "--gas-adjustment", "1.1", "--from", rollappUserAddr, "--keyring-backend", "test", "--output", "json", "-y", "--home", rollapp1.HomeDir(), "--node", fmt.Sprintf("tcp://%s:26657", rollapp1.Validators[0].HostName()), "--chain-id", "rollappevm_1234-1"} + command := []string{"rollappd", "tx", "ibc-transfer", "transfer", "transfer", "channel-0", transferData.Address, fmt.Sprintf("%s%s", transferData.Amount.String(), transferData.Denom), "--gas", "auto", "--gas-prices", "1.0ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", "--gas-adjustment", "1.1", "--from", rollappUserAddr, "--keyring-backend", "test", "--output", "json", "-y", "--home", rollapp1.HomeDir(), "--node", fmt.Sprintf("tcp://%s:26657", rollapp1.Validators[0].HostName()), "--chain-id", "rollappevm_1234-1"} stdout, _, err := rollapp1.Validators[0].Exec(ctx, command, nil) require.NoError(t, err) @@ -795,7 +1402,7 @@ func TestTokenlessTransferDiffGas_EVM(t *testing.T) { t.Cleanup( func() { - err := r1.StopRelayer(ctx, eRep) + err := r.StopRelayer(ctx, eRep) if err != nil { t.Logf("an error occurred while stopping the relayer: %s", err) } @@ -806,7 +1413,7 @@ func TestTokenlessTransferDiffGas_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } -func TestUpdateMinGasPrice_EVM(t *testing.T) { +func TestUpdateMinGasPrice_Wasm(t *testing.T) { if testing.Short() { t.Skip() } @@ -818,7 +1425,7 @@ func TestUpdateMinGasPrice_EVM(t *testing.T) { 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["rollapp_id"] = "rollappwasm_1234-1" dymintTomlOverrides["settlement_gas_prices"] = "0adym" dymintTomlOverrides["max_idle_time"] = "3s" dymintTomlOverrides["max_proof_time"] = "500ms" @@ -833,8 +1440,8 @@ func TestUpdateMinGasPrice_EVM(t *testing.T) { numRollAppFn := 0 numRollAppVals := 1 - modifyEVMGenesisKV := append( - rollappEVMGenesisKV, + modifyWasmGenesisKV := append( + rollappWasmGenesisKV, cosmos.GenesisKV{ Key: "app_state.bank.denom_metadata", Value: []interface{}{ @@ -852,7 +1459,7 @@ func TestUpdateMinGasPrice_EVM(t *testing.T) { "exponent": "18", }, }, - "description": "Denom metadata for Rollapp EVM", + "description": "Denom metadata for Rollapp wasm", "display": "DYM", "name": "DYM", "symbol": "DYM", @@ -867,14 +1474,6 @@ func TestUpdateMinGasPrice_EVM(t *testing.T) { Key: "app_state.staking.params.bond_denom", Value: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", }, - cosmos.GenesisKV{ - Key: "app_state.evm.params.evm_denom", - Value: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", - }, - cosmos.GenesisKV{ - Key: "app_state.evm.params.gas_denom", - Value: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", - }, ) cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ @@ -883,18 +1482,18 @@ func TestUpdateMinGasPrice_EVM(t *testing.T) { ChainConfig: ibc.ChainConfig{ Type: "rollapp-dym", Name: "rollapp-temp", - ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappEVMImage}, + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, Bin: "rollappd", - Bech32Prefix: "ethm", + Bech32Prefix: "rol", Denom: "ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", - CoinType: "60", + CoinType: "118", GasPrices: "0.0ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", GasAdjustment: 1.1, TrustingPeriod: "112h", EncodingConfig: encodingConfig(), NoHostMount: false, - ModifyGenesis: modifyRollappEVMGenesis(modifyEVMGenesisKV), + ModifyGenesis: modifyRollappWasmGenesis(modifyWasmGenesisKV), ConfigFileOverrides: configFileOverrides, }, NumValidators: &numRollAppVals, @@ -1111,7 +1710,7 @@ func TestUpdateMinGasPrice_EVM(t *testing.T) { Amount: transferAmount, } - command := []string{"rollappd", "tx", "ibc-transfer", "transfer", "transfer", "channel-0", transferData.Address, fmt.Sprintf("%s%s", transferData.Amount.String(), transferData.Denom), "--gas", "auto", "--gas-prices", "1.0ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", "--gas-adjustment", "1.1", "--from", rollappUserAddr, "--keyring-backend", "test", "--output", "json", "-y", "--home", rollapp1.HomeDir(), "--node", fmt.Sprintf("tcp://%s:26657", rollapp1.Validators[0].HostName()), "--chain-id", "rollappevm_1234-1"} + command := []string{"rollappd", "tx", "ibc-transfer", "transfer", "transfer", "channel-0", transferData.Address, fmt.Sprintf("%s%s", transferData.Amount.String(), transferData.Denom), "--gas", "auto", "--gas-prices", "1.0ibc/FECACB927EB3102CCCB240FFB3B6FCCEEB8D944C6FEA8DFF079650FEFF59781D", "--gas-adjustment", "1.1", "--from", rollappUserAddr, "--keyring-backend", "test", "--output", "json", "-y", "--home", rollapp1.HomeDir(), "--node", fmt.Sprintf("tcp://%s:26657", rollapp1.Validators[0].HostName()), "--chain-id", "rollappwasm_1234-1"} stdout, _, err := rollapp1.Validators[0].Exec(ctx, command, nil) require.NoError(t, err) @@ -1201,7 +1800,7 @@ func TestTokenlessTransferDiffGas_Wasm(t *testing.T) { "exponent": "18", }, }, - "description": "Denom metadata for Rollapp EVM", + "description": "Denom metadata for Rollapp wasm", "display": "DYM", "name": "DYM", "symbol": "DYM", @@ -1381,7 +1980,7 @@ func TestTokenlessTransferDiffGas_Wasm(t *testing.T) { Amount: transferAmount, } - command := []string{"rollappd", "tx", "ibc-transfer", "transfer", "transfer", "channel-0", transferData.Address, fmt.Sprintf("%s%s", transferData.Amount.String(), transferData.Denom), "--gas", "auto", "--gas-prices", "10.0urax", "--gas-adjustment", "1.1", "--from", rollappUserAddr, "--keyring-backend", "test", "--output", "json", "-y", "--home", rollapp1.HomeDir(), "--node", fmt.Sprintf("tcp://%s:26657", rollapp1.Validators[0].HostName()), "--chain-id", "rollappevm_1234-1"} + command := []string{"rollappd", "tx", "ibc-transfer", "transfer", "transfer", "channel-0", transferData.Address, fmt.Sprintf("%s%s", transferData.Amount.String(), transferData.Denom), "--gas", "auto", "--gas-prices", "10.0urax", "--gas-adjustment", "1.1", "--from", rollappUserAddr, "--keyring-backend", "test", "--output", "json", "-y", "--home", rollapp1.HomeDir(), "--node", fmt.Sprintf("tcp://%s:26657", rollapp1.Validators[0].HostName()), "--chain-id", "rollappwasm_1234-1"} stdout, _, err := rollapp1.Validators[0].Exec(ctx, command, nil) require.NoError(t, err) diff --git a/tests/zero_fee_relay_test.go b/tests/zero_fee_relay_test.go index 7e1eb3b2..71f6022e 100644 --- a/tests/zero_fee_relay_test.go +++ b/tests/zero_fee_relay_test.go @@ -283,6 +283,264 @@ func TestZeroFee_RelaySuccess_EVM(t *testing.T) { CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } +func TestZeroFee_RelaySuccess_Wasm(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"] = "rollappwasm_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" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 1 + numRollAppVals := 1 + + modifyRAGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyRAGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + StartDA(ctx, t, client, network) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + 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, 1179360, true) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + cmd := append([]string{rollapp1.FullNodes[0].Chain.Config().Bin}, "dymint", "show-sequencer", "--home", rollapp1.FullNodes[0].HomeDir()) + pub1, _, err := rollapp1.FullNodes[0].Exec(ctx, cmd, nil) + require.NoError(t, err) + + err = dymension.FullNodes[0].CreateKeyWithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + sequencer, err := dymension.AccountKeyBech32WithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + fund := ibc.WalletData{ + Address: sequencer, + Denom: dymension.Config().Denom, + Amount: math.NewInt(10_000_000_000_000).MulRaw(100_000_000), + } + err = dymension.SendFunds(ctx, "faucet", fund) + require.NoError(t, err) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + command := []string{"sequencer", "create-sequencer", string(pub1), rollapp1.Config().ChainID, "100000000000000000000adym", rollapp1.GetSequencerKeyDir() + "/metadata_sequencer1.json", + "--broadcast-mode", "async", "--keyring-dir", rollapp1.FullNodes[0].HomeDir() + "/sequencer_keys", "--whitelisted-relayers", sequencer} + + _, err = dymension.FullNodes[0].ExecTx(ctx, "sequencer", command...) + require.NoError(t, err) + + resp, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp.Sequencers), 2, "should have 2 sequences") + fmt.Printf("Sequencer check: %v\n", resp.Sequencers) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + 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: transferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + 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() + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +} + func TestZeroFee_RotatedSequencer_EVM(t *testing.T) { if testing.Short() { t.Skip() @@ -707,3 +965,428 @@ func TestZeroFee_RotatedSequencer_EVM(t *testing.T) { // Run invariant check CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) } + +func TestZeroFee_RotatedSequencer_Wasm(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + // setup config for rollapp 1 + 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"] = "rollappwasm_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"] = "true" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + + modifyRAGenesisKV := append( + rollappWasmGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppVals := 1 + numRollAppFn := 1 + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappwasm_1234-1", + Images: []ibc.DockerImage{rollappWasmImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappWasmGenesis(modifyRAGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + 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, + }, + 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) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + StartDA(ctx, t, client, network) + + // relayer for rollapp 1 + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + }, nil, "", nil, true, 1179360, true) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappwasm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + wallet, found := r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + keyDir := dymension.GetRollApps()[0].GetSequencerKeyDir() + keyPath := keyDir + "/sequencer_keys" + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + if err != nil { + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", keyPath, []string{wallet.FormattedAddress()}) + require.NoError(t, err) + } + + // Check IBC Transfer before switch + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + cmd := append([]string{rollapp1.FullNodes[0].Chain.Config().Bin}, "dymint", "show-sequencer", "--home", rollapp1.FullNodes[0].HomeDir()) + pub1, _, err := rollapp1.FullNodes[0].Exec(ctx, cmd, nil) + require.NoError(t, err) + + err = dymension.FullNodes[0].CreateKeyWithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + sequencer, err := dymension.AccountKeyBech32WithKeyDir(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()) + require.NoError(t, err) + + fund := ibc.WalletData{ + Address: sequencer, + Denom: dymension.Config().Denom, + Amount: math.NewInt(10_000_000_000_000).MulRaw(100_000_000), + } + err = dymension.SendFunds(ctx, "faucet", fund) + require.NoError(t, err) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + command := []string{"sequencer", "create-sequencer", string(pub1), rollapp1.Config().ChainID, "100000000000000000000adym", rollapp1.GetSequencerKeyDir() + "/metadata_sequencer1.json", + "--broadcast-mode", "async", "--keyring-dir", rollapp1.FullNodes[0].HomeDir() + "/sequencer_keys", "--whitelisted-relayers", sequencer} + + _, err = dymension.FullNodes[0].ExecTx(ctx, "sequencer", command...) + require.NoError(t, err) + + resp, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(resp.Sequencers), 2, "should have 2 sequences") + fmt.Printf("Sequencer check: %v\n", resp.Sequencers) + + err = dymension.Unbond(ctx, "sequencer", rollapp1.GetSequencerKeyDir()) + require.NoError(t, err) + + lastBlock, err := rollapp1.Height(ctx) + require.NoError(t, err) + + time.Sleep(200 * time.Second) + + err = rollapp1.StopAllNodes(ctx) + require.NoError(t, err) + + _ = rollapp1.StartAllNodes(ctx) + + containerID = fmt.Sprintf("ra-rollappwasm_1234-1-fn-0-%s", t.Name()) + + // Get the container details + containerJSON, err = client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err = rollapp1.FullNodes[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node = fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir = strings.Split(rollapp1.Validators[0].HomeDir(), "/") + rollapp1FolderName = rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err = os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines = []string{} + scanner = bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output = strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.Validators[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.Validators[0].StartContainer(ctx) + require.NoError(t, err) + + time.Sleep(120 * time.Second) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + time.Sleep(60 * time.Second) + + wallet, found = r.GetWallet(rollapp1.Config().ChainID) + require.True(t, found) + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + //Update white listed relayers + _, err = dymension.GetNode().UpdateWhitelistedRelayers(ctx, "sequencer", rollapp1.FullNodes[0].HomeDir()+"/sequencer_keys", []string{wallet.FormattedAddress()}) + require.NoError(t, err) + + afterBlock, err := rollapp1.Height(ctx) + require.NoError(t, err) + require.True(t, afterBlock > lastBlock) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + // Send a normal ibc tx from RA -> Hub + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + _, err = rollapp1.SendIBCTransfer(ctx, channel.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) + + res, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range res.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + 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() + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom + // dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + // dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + // erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + // require.NoError(t, err) + // erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + // testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) + + // Run invariant check + CheckInvariant(t, ctx, dymension, dymensionUser.KeyName()) +}