diff --git a/.github/workflows/e2e-test-workflow-call.yml b/.github/workflows/e2e-test-workflow-call.yml index eebf80c2..06cdad55 100644 --- a/.github/workflows/e2e-test-workflow-call.yml +++ b/.github/workflows/e2e-test-workflow-call.yml @@ -6,26 +6,71 @@ on: required: false type: string default: "latest" - rollapp_ci: - description: "CI run on Rollapp Repo" + rollapp_evm_ci: + description: "CI run on Rollapp-EVM Repo" + required: false + type: string + default: "latest" + rollapp_wasm_ci: + description: "CI run on Rollapp-Wasm Repo" required: false type: string default: "latest" jobs: # e2e-tests-by runs the actual go test command to trigger the test. - e2e-tests: + rollapp-evm: + strategy: + matrix: + tests: + - "e2e-test-ibc-success-evm" + - "e2e-test-ibc-timeout-evm" + - "e2e-test-ibc-grace-period-evm" + - "e2e-test-eibc-fulfillment-evm" + - "e2e-test-transfer-multi-hop-evm" + - "e2e-test-pfm-with-grace-period-evm" + - "e2e-test-batch-finalization-evm" + - "e2e-test-rollapp-freeze-evm" + fail-fast: false + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + repository: dymensionxyz/e2e-tests + - name: Set up Go 1.21 + uses: actions/setup-go@v4 + with: + go-version: "1.21.4" + + - name: Download Tarball Artifact + uses: actions/download-artifact@v3 + with: + name: e2e + path: /tmp + + - name: Load Docker Image + run: | + docker image load -i /tmp/e2e.tar + docker image ls -a + + - name: Rollapp-EVM E2E Tests + run: make ${{ matrix.tests }} + env: + DYMENSION_CI: ${{ inputs.dymension_ci }} + ROLLAPP_EVM_CI: ${{ inputs.rollapp_evm_ci }} + ROLLAPP_WASM_CI: ${{ inputs.rollapp_wasm_ci }} + rollapp-wasm: strategy: matrix: tests: - - "e2e-test-ibc-success" - - "e2e-test-ibc-timeout" - - "e2e-test-ibc-grace-period" - - "e2e-test-eibc-fulfillment" - - "e2e-test-transfer-multi-hop" - - "e2e-test-pfm-with-grace-period" - - "e2e-test-batch-finalization" - - "e2e-test-rollapp-freeze" + - "e2e-test-ibc-success-wasm" + - "e2e-test-ibc-timeout-wasm" + - "e2e-test-ibc-grace-period-wasm" + - "e2e-test-eibc-fulfillment-wasm" + - "e2e-test-transfer-multi-hop-wasm" + - "e2e-test-pfm-with-grace-period-wasm" + - "e2e-test-batch-finalization-wasm" + - "e2e-test-rollapp-freeze-wasm" fail-fast: false runs-on: ubuntu-latest steps: @@ -48,8 +93,9 @@ jobs: docker image load -i /tmp/e2e.tar docker image ls -a - - name: E2E Tests + - name: Rollapp-Wasm E2E Tests run: make ${{ matrix.tests }} env: DYMENSION_CI: ${{ inputs.dymension_ci }} - ROLLAPP_CI: ${{ inputs.rollapp_ci }} + ROLLAPP_EVM_CI: ${{ inputs.rollapp_evm_ci }} + ROLLAPP_WASM_CI: ${{ inputs.rollapp_wasm_ci }} diff --git a/.github/workflows/e2e_test.yml b/.github/workflows/e2e_test.yml index 31a6fe3a..a4e729c5 100644 --- a/.github/workflows/e2e_test.yml +++ b/.github/workflows/e2e_test.yml @@ -21,18 +21,18 @@ permissions: jobs: # e2e-tests-by runs the actual go test command to trigger the test. - e2e-tests: + rollapp-evm: strategy: matrix: tests: - - "e2e-test-ibc-success" - - "e2e-test-ibc-timeout" - - "e2e-test-ibc-grace-period" - - "e2e-test-eibc-fulfillment" - - "e2e-test-transfer-multi-hop" - - "e2e-test-pfm-with-grace-period" - - "e2e-test-batch-finalization" - - "e2e-test-rollapp-freeze" + - "e2e-test-ibc-success-evm" + - "e2e-test-ibc-timeout-evm" + - "e2e-test-ibc-grace-period-evm" + - "e2e-test-eibc-fulfillment-evm" + - "e2e-test-transfer-multi-hop-evm" + - "e2e-test-pfm-with-grace-period-evm" + - "e2e-test-batch-finalization-evm" + - "e2e-test-rollapp-freeze-evm" fail-fast: false runs-on: ubuntu-latest steps: @@ -44,6 +44,31 @@ jobs: with: go-version: "1.21.4" - - name: E2E Tests + - name: Rollapp-EVM E2E Tests run: | make ${{ matrix.tests }} + rollapp-wasm: + strategy: + matrix: + tests: + - "e2e-test-ibc-success-wasm" + - "e2e-test-ibc-timeout-wasm" + - "e2e-test-ibc-grace-period-wasm" + - "e2e-test-eibc-fulfillment-wasm" + - "e2e-test-transfer-multi-hop-wasm" + - "e2e-test-pfm-with-grace-period-wasm" + - "e2e-test-batch-finalization-wasm" + - "e2e-test-rollapp-freeze-wasm" + fail-fast: false + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + repository: dymensionxyz/e2e-tests + - name: Set up Go 1.21 + uses: actions/setup-go@v4 + with: + go-version: "1.21.4" + + - name: Rollapp-Wasm E2E Tests + run: make ${{ matrix.tests }} diff --git a/Makefile b/Makefile index 80d647e2..2048a822 100644 --- a/Makefile +++ b/Makefile @@ -7,51 +7,94 @@ clean-e2e: sh clean.sh # Executes IBC tests via rollup-e2e-testing -e2e-test-ibc-success: clean-e2e - cd tests && go test -timeout=25m -race -v -run TestIBCTransferSuccess . +e2e-test-ibc-success-evm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestIBCTransferSuccess_EVM . # Executes IBC tests via rollup-e2e-testing -e2e-test-ibc-timeout: clean-e2e - cd tests && go test -timeout=25m -race -v -run TestIBCTransferTimeout . +e2e-test-ibc-timeout-evm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestIBCTransferTimeout_EVM . # Executes IBC tests via rollup-e2e-testing -e2e-test-eibc-fulfillment: clean-e2e - cd tests && go test -timeout=25m -race -v -run TestEIBCFulfillment . +e2e-test-eibc-fulfillment-evm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestEIBCFulfillment_EVM . # Executes IBC tests via rollup-e2e-testing -e2e-test-ibc-grace-period: clean-e2e - cd tests && go test -timeout=25m -race -v -run TestIBCGracePeriodCompliance . +e2e-test-ibc-grace-period-evm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestIBCGracePeriodCompliance_EVM . -e2e-test-transfer-multi-hop: clean-e2e - cd tests && go test -timeout=25m -race -v -run TestIBCTransferMultiHop . +e2e-test-transfer-multi-hop-evm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestIBCTransferMultiHop_EVM . -e2e-test-pfm-with-grace-period: clean-e2e - cd tests && go test -timeout=25m -race -v -run TestIBCPFMWithGracePeriod . -e2e-test-batch-finalization: - cd tests && go test -timeout=25m -race -v -run TestBatchFinalization . +e2e-test-pfm-with-grace-period-evm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestIBCPFMWithGracePeriod_EVM . -e2e-test-rollapp-freeze: clean-e2e - cd tests && go test -timeout=25m -race -v -run TestRollAppFreeze . +e2e-test-batch-finalization-evm: + cd tests && go test -timeout=25m -race -v -run TestBatchFinalization_EVM . + +e2e-test-rollapp-freeze-evm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestRollAppFreeze_EVM . + +# Executes IBC tests via rollup-e2e-testing +e2e-test-ibc-success-wasm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestIBCTransferSuccess_Wasm . + +# Executes IBC tests via rollup-e2e-testing +e2e-test-ibc-timeout-wasm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestIBCTransferTimeout_Wasm . + +# Executes IBC tests via rollup-e2e-testing +e2e-test-eibc-fulfillment-wasm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestEIBCFulfillment_Wasm . + +# Executes IBC tests via rollup-e2e-testing +e2e-test-ibc-grace-period-wasm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestIBCGracePeriodCompliance_Wasm . + +e2e-test-transfer-multi-hop-wasm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestIBCTransferMultiHop_Wasm . + +e2e-test-pfm-with-grace-period-wasm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestIBCPFMWithGracePeriod_Wasm . + +e2e-test-batch-finalization-wasm: + cd tests && go test -timeout=25m -race -v -run TestBatchFinalization_Wasm . + +e2e-test-rollapp-freeze-wasm: clean-e2e + cd tests && go test -timeout=25m -race -v -run TestRollAppFreeze_Wasm . # Executes all tests via rollup-e2e-testing -e2e-test-all: e2e-test-ibc-success \ - e2e-test-ibc-timeout \ - e2e-test-ibc-grace-period \ - e2e-test-transfer-multi-hop \ - e2e-test-eibc-fulfillment \ - e2e-test-transfer-multi-hop \ - e2e-test-pfm-with-grace-period \ - e2e-test-batch-finalization \ - e2e-test-rollapp-freeze +e2e-test-all: e2e-test-ibc-success-evm \ + e2e-test-ibc-timeout-evm \ + e2e-test-ibc-grace-period-evm \ + e2e-test-transfer-multi-hop-evm \ + e2e-test-eibc-fulfillment-evm \ + e2e-test-pfm-with-grace-period-evm \ + e2e-test-batch-finalization-evm \ + e2e-test-rollapp-freeze-evm \ + e2e-test-ibc-success-wasm \ + e2e-test-ibc-timeout-wasm \ + e2e-test-ibc-grace-period-wasm \ + e2e-test-transfer-multi-hop-wasm \ + e2e-test-eibc-fulfillment-wasm \ + e2e-test-pfm-with-grace-period-wasm \ + e2e-test-batch-finalization-wasm \ + e2e-test-rollapp-freeze-wasm .PHONY: clean-e2e \ e2e-test-all \ - e2e-test-ibc-success \ - e2e-test-ibc-timeout \ - e2e-test-ibc-grace-period \ - e2e-test-transfer-multi-hop \ - e2e-test-eibc-fulfillment \ - e2e-test-transfer-multi-hop \ - e2e-test-pfm-with-grace-period \ - e2e-test-batch-finalization \ - e2e-test-rollapp-freeze + e2e-test-ibc-success-evm \ + e2e-test-ibc-timeout-evm \ + e2e-test-ibc-grace-period-evm \ + e2e-test-eibc-fulfillment-evm \ + e2e-test-transfer-multi-hop-evm \ + e2e-test-pfm-with-grace-period-evm \ + e2e-test-batch-finalization-evm \ + e2e-test-rollapp-freeze-evm \ + e2e-test-ibc-success-wasm \ + e2e-test-ibc-timeout-wasm \ + e2e-test-ibc-grace-period-wasm \ + e2e-test-eibc-fulfillment-wasm \ + e2e-test-transfer-multi-hop-wasm \ + e2e-test-pfm-with-grace-period-wasm \ + e2e-test-batch-finalization-wasm \ + e2e-test-rollapp-freeze-wasm diff --git a/tests/eibc_fulfillment_test.go b/tests/eibc_fulfillment_test.go index aac947b6..d1ea1c43 100644 --- a/tests/eibc_fulfillment_test.go +++ b/tests/eibc_fulfillment_test.go @@ -25,7 +25,7 @@ import ( // This test case verifies the system's behavior when an eIBC packet sent from the rollapp to the hub // that is fulfilled by the market maker -func TestEIBCFulfillment(t *testing.T) { +func TestEIBCFulfillment_EVM(t *testing.T) { if testing.Short() { t.Skip() } @@ -35,7 +35,7 @@ func TestEIBCFulfillment(t *testing.T) { configFileOverrides := make(map[string]any) dymintTomlOverrides := make(testutil.Toml) dymintTomlOverrides["settlement_layer"] = "dymension" - dymintTomlOverrides["node_address"] = "http://dymension_100-1-val-0-TestEIBCFulfillment:26657" + dymintTomlOverrides["node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) dymintTomlOverrides["rollapp_id"] = "rollappevm_1234-1" dymintTomlOverrides["gas_prices"] = "0adym" @@ -61,7 +61,7 @@ func TestEIBCFulfillment(t *testing.T) { Type: "rollapp-dym", Name: "rollapp-temp", ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappImage}, + Images: []ibc.DockerImage{rollappEVMImage}, Bin: "rollappd", Bech32Prefix: "ethm", Denom: "urax", @@ -268,6 +268,249 @@ func TestEIBCFulfillment(t *testing.T) { ) } +func TestEIBCFulfillment_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["node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides["rollapp_id"] = "rollappwasm_1234-1" + dymintTomlOverrides["gas_prices"] = "0adym" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + const BLOCK_FINALITY_PERIOD = 80 + modifyGenesisKV := append( + dymensionGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollapp.params.dispute_period_in_blocks", + Value: fmt.Sprint(BLOCK_FINALITY_PERIOD), + }, + ) + + // 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: nil, + 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(modifyGenesisKV), + 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("ghcr.io/decentrio/relayer", "e2e-amd", "100:1000"), + ).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: 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(), + }) + require.NoError(t, err) + + walletAmount := math.NewInt(1_000_000_000_000) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, dymension, rollapp1) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // 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) + + transferAmount := math.NewInt(1_000_000) + multiplier := math.NewInt(10) + + eibcFee := transferAmount.Quo(multiplier) // transferAmount * 0.1 + transferAmountWithoutFee := transferAmount.Sub(eibcFee) + + 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) + + transferData := ibc.WalletData{ + Address: marketMakerAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + // 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() + + var options ibc.TransferOptions + //market maker needs to have funds on the hub first to be able to fulfill upcoming demand order + _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, transferData, options) + 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) + + expMmBalanceRollappDenom := transferData.Amount + 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)) + // end of preconditions + + 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) + rollappHeight, err = rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + zeroBalance := math.NewInt(0) + balance, err = dymension.GetBalance(ctx, dymensionUserAddr, rollappIBCDenom) + require.NoError(t, err) + fmt.Println("Balance of dymensionUserAddr right after sending eIBC transfer:", 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, 30, false) + require.NoError(t, err) + fmt.Println("Event:", eibcEvents[0]) + + // fulfill demand order + txhash, err := dymension.FullfillDemandOrder(ctx, eibcEvents[0].ID, marketMakerAddr) + require.NoError(t, err) + fmt.Println(txhash) + 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), fmt.Sprintf("Value mismatch. Expected %s, actual %s", transferAmountWithoutFee, balance)) + // verify funds were deducted from market maker's wallet address + balance, err = dymension.GetBalance(ctx, marketMakerAddr, rollappIBCDenom) + require.NoError(t, err) + fmt.Println("Balance of marketMakerAddr after fulfilling the order:", balance) + expMmBalanceRollappDenom = expMmBalanceRollappDenom.Sub((transferAmountWithoutFee)) + require.True(t, balance.Equal(expMmBalanceRollappDenom), fmt.Sprintf("Value mismatch. Expected %s, actual %s", expMmBalanceRollappDenom, balance)) + // wait until packet finalization and verify funds + fee were added to market maker's wallet address + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + balance, err = dymension.GetBalance(ctx, marketMakerAddr, rollappIBCDenom) + require.NoError(t, err) + fmt.Println("Balance of marketMakerAddr after packet finalization:", balance) + expMmBalanceRollappDenom = expMmBalanceRollappDenom.Add(transferData.Amount) + require.True(t, balance.Equal(expMmBalanceRollappDenom), fmt.Sprintf("Value mismatch. Expected %s, actual %s", expMmBalanceRollappDenom, balance)) + + t.Cleanup( + func() { + err := r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) +} + func getEibcEventFromTx(t *testing.T, dymension *dym_hub.DymHub, txhash string) *dymensiontesting.EibcEvent { txResp, err := dymension.GetTransaction(txhash) if err != nil { diff --git a/tests/frozen_test.go b/tests/frozen_test.go index c9e6fac6..85b0fc81 100644 --- a/tests/frozen_test.go +++ b/tests/frozen_test.go @@ -23,7 +23,7 @@ import ( ) // TestRollAppFreeze ensure upon freeze gov proposal passed, no updates can be made to the rollapp and not IBC txs are passing. -func TestRollAppFreeze(t *testing.T) { +func TestRollAppFreeze_EVM(t *testing.T) { if testing.Short() { t.Skip() } @@ -50,7 +50,7 @@ func TestRollAppFreeze(t *testing.T) { Type: "rollapp-dym", Name: "rollapp-temp", ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappImage}, + Images: []ibc.DockerImage{rollappEVMImage}, Bin: "rollappd", Bech32Prefix: "ethm", Denom: "urax", @@ -250,3 +250,232 @@ func TestRollAppFreeze(t *testing.T) { eRep, ibc.TransferOptions{}) require.Error(t, err) } + +// TestRollAppFreeze ensure upon freeze gov proposal passed, no updates can be made to the rollapp and not IBC txs are passing. +func TestRollAppFreeze_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["node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides["rollapp_id"] = "rollappwasm_1234-1" + dymintTomlOverrides["gas_prices"] = "0adym" + + 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: nil, + 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("ghcr.io/decentrio/relayer", "e2e-amd", "100:1000"), + ).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: 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(), + }) + require.NoError(t, err) + + walletAmount := math.NewInt(1_000_000_000_000) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.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) + + rollappOrigBal, err := rollapp1.GetBalance(ctx, rollappUserAddr, rollapp1.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, rollappOrigBal) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 3, dymension, rollapp1) + require.NoError(t, err) + + keyDir := rollapp1.GetSequencerKeyDir() + + err = testutil.WaitForBlocks(ctx, 1, dymension, rollapp1) + require.NoError(t, err) + + oldLatestIndex, err := dymension.GetNode().QueryLatestStateIndex(ctx, "rollappevm_1234-1") + require.NoError(t, err) + + // Access the index value + index := oldLatestIndex.StateIndex.Index + uintIndex, err := strconv.ParseUint(index, 10, 64) + require.NoError(t, err) + + targetIndex := uintIndex + 1 + + // Convert the uint to string + myUintStr := fmt.Sprintf("%d", 50) + + // Create a JSON string with the uint value quoted + jsonData := fmt.Sprintf(`"%s"`, myUintStr) + + disputeblock := json.RawMessage(jsonData) + propTx, err := dymension.ParamChangeProposal(ctx, dymensionUser.KeyName(), &utils.ParamChangeProposalJSON{ + Title: "Add new deployer_whitelist", + Description: "Add current dymensionUserAddr to the deployer_whitelist", + Changes: utils.ParamChangesJSON{ + utils.NewParamChangeJSON("rollapp", "DisputePeriodInBlocks", disputeblock), + }, + Deposit: "500000000000" + dymension.Config().Denom, // greater than min deposit + }) + require.NoError(t, err) + + err = dymension.VoteOnProposalAllValidators(ctx, propTx.ProposalID, 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, propTx.ProposalID, cosmos.ProposalStatusPassed) + require.NoError(t, err, "proposal status did not change to passed") + + new_params, err := dymension.QueryParam(ctx, "rollapp", "DisputePeriodInBlocks") + require.NoError(t, err) + require.Equal(t, new_params.Value, string(disputeblock)) + + // Loop until the latest index updates + for { + oldLatestIndex, err := dymension.GetNode().QueryLatestStateIndex(ctx, "rollappevm_1234-1") + require.NoError(t, err) + + index := oldLatestIndex.StateIndex.Index + uintIndex, err := strconv.ParseUint(index, 10, 64) + + require.NoError(t, err) + if uintIndex >= targetIndex { + break + } + } + sequencerAddr, err := dymension.AccountKeyBech32WithKeyDir(ctx, "sequencer", keyDir) + require.NoError(t, err) + + submitFraudStr := "fraud" + deposit := "500000000000" + dymension.Config().Denom + + t.Log("deposit:", deposit) + + rollappHeight, err := rollapp1.Height(ctx) + require.NoError(t, err) + + fraudHeight := fmt.Sprint(rollappHeight - 2) + + err = dymension.SubmitFraudProposal(ctx, dymensionUser.KeyName(), "rollappevm_1234-1", fraudHeight, sequencerAddr, "07-tendermint-0", submitFraudStr, submitFraudStr, deposit) + require.NoError(t, err) + + err = dymension.VoteOnProposalAllValidators(ctx, "2", cosmos.ProposalVoteYes) + require.NoError(t, err, "failed to submit votes") + + // Wait a few blocks for the gov to pass and to verify if the state index increment + err = testutil.WaitForBlocks(ctx, 50, dymension, rollapp1) + require.NoError(t, err) + + // Check if rollapp has frozen or not + rollappParams, err := dymension.QueryRollappParams(ctx, "rollappevm_1234-1") + require.NoError(t, err) + require.Equal(t, rollappParams.Rollapp.Frozen, true, "rollapp does not frozen") + + // Check rollapp state index not increment + latestIndex, err := dymension.GetNode().QueryLatestStateIndex(ctx, "rollappevm_1234-1") + require.NoError(t, err) + require.Equal(t, latestIndex.StateIndex.Index, "2", "rollapp state index still increment") + + // IBC Transfer not working + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + var transferAmount = math.NewInt(1_000_000) + + err = dymension.IBCTransfer(ctx, + dymension, rollapp1, transferAmount, dymensionUserAddr, + rollappUserAddr, r, ibcPath, channel, + eRep, ibc.TransferOptions{}) + require.Error(t, err) + require.Equal(t, strings.Contains(err.Error(), "status Frozen"), true) + + err = rollapp1.IBCTransfer(ctx, + rollapp1, dymension, transferAmount, rollappUserAddr, + dymensionUserAddr, r, ibcPath, channel, + eRep, ibc.TransferOptions{}) + require.Error(t, err) +} diff --git a/tests/ibc_grace_period_test.go b/tests/ibc_grace_period_test.go index 12df7788..e3cb7fc0 100644 --- a/tests/ibc_grace_period_test.go +++ b/tests/ibc_grace_period_test.go @@ -20,7 +20,7 @@ import ( ) // TestIBCGracePeriodCompliance ensures that the grace period for transaction finalization is correctly enforced on hub and rollapp. -func TestIBCGracePeriodCompliance(t *testing.T) { +func TestIBCGracePeriodCompliance_EVM(t *testing.T) { if testing.Short() { t.Skip() } @@ -55,7 +55,7 @@ func TestIBCGracePeriodCompliance(t *testing.T) { Type: "rollapp-dym", Name: "rollapp-temp", ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappImage}, + Images: []ibc.DockerImage{rollappEVMImage}, Bin: "rollappd", Bech32Prefix: "ethm", Denom: "urax", @@ -227,3 +227,212 @@ func TestIBCGracePeriodCompliance(t *testing.T) { }, ) } + +// TestIBCGracePeriodCompliance ensures that the grace period for transaction finalization is correctly enforced on hub and rollapp. +func TestIBCGracePeriodCompliance_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["node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides["rollapp_id"] = "rollappwasm_1234-1" + dymintTomlOverrides["gas_prices"] = "0adym" + + modifyGenesisKV := append( + dymensionGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollapp.params.dispute_period_in_blocks", + Value: "20", + }, + ) + + 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: nil, + 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(modifyGenesisKV), + 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("ghcr.io/decentrio/relayer", "e2e-amd", "100:1000"), + ).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: 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(), + }) + require.NoError(t, err) + + walletAmount := math.NewInt(1_000_000_000_000) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // 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) + + // Compose an IBC transfer and send from rollapp -> dymension + var transferAmount = math.NewInt(1_000_000) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, rollapp1.Config().ChainID, dymension.Config().ChainID) + require.NoError(t, err) + + transferData := ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + // 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)) + // 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() + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, math.NewInt(0)) + + err = testutil.WaitForBlocks(ctx, 10, rollapp1) + require.NoError(t, err) + + // Assert balance was updated on the Rollapp + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, transferData.Amount) + + channel, err = ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + 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) + + // Assert balance was updated on the rollapp because transfer amount was deducted from wallet balance + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + + // 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() + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + // Assert funds are waiting + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, math.NewInt(0)) + + // Wait a 40 blocks + err = testutil.WaitForBlocks(ctx, 40, 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)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferData.Amount) + + t.Cleanup( + func() { + err := r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) +} diff --git a/tests/ibc_pfm_test.go b/tests/ibc_pfm_test.go index b9778d54..2a9d3c3a 100644 --- a/tests/ibc_pfm_test.go +++ b/tests/ibc_pfm_test.go @@ -21,7 +21,7 @@ import ( "go.uber.org/zap/zaptest" ) -func TestIBCTransferMultiHop(t *testing.T) { +func TestIBCTransferMultiHop_EVM(t *testing.T) { if testing.Short() { t.Skip() } @@ -50,7 +50,7 @@ func TestIBCTransferMultiHop(t *testing.T) { Type: "rollapp-dym", Name: "rollapp-test", ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappImage}, + Images: []ibc.DockerImage{rollappEVMImage}, Bin: "rollappd", Bech32Prefix: "ethm", Denom: "urax", @@ -257,3 +257,240 @@ func TestIBCTransferMultiHop(t *testing.T) { testutil.AssertBalance(t, ctx, osmosis, osmosisUserAddr, secondHopIBCDenom, transferAmount) }) } + +func TestIBCTransferMultiHop_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["node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides["rollapp_id"] = "rollappwasm_1234-1" + dymintTomlOverrides["gas_prices"] = "0adym" + + 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: nil, + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + }, + { + Name: "osmosis", + Version: "v17.0.0", + ChainConfig: osmosisConfig, + 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) + osmosis := chains[2].(*cosmos.CosmosChain) + + // Relayer Factory + client, network := test.DockerSetup(t) + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage("ghcr.io/decentrio/relayer", "e2e-amd", "100:1000"), + ).Build(t, client, "relayer", network) + + r2 := test.NewBuiltinRelayerFactory( + ibc.CosmosRly, + zaptest.NewLogger(t), + relayer.CustomDockerImage(IBCRelayerImage, IBCRelayerVersion, "100:1000"), + ).Build(t, client, "relayer2", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddChain(osmosis). + AddRelayer(r, "relayer"). + AddRelayer(r2, "relayer2"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: pathHubToRollApp, + }). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: osmosis, + Relayer: r2, + Path: pathDymToOsmos, + }) + + 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(), + }) + require.NoError(t, err) + + t.Cleanup(func() { + _ = ic.Close() + }) + + channsDym, err := r.GetChannels(ctx, eRep, dymension.GetChainID()) + require.NoError(t, err) + require.Len(t, channsDym, 2) + + channsRollApp, err := r.GetChannels(ctx, eRep, rollapp1.GetChainID()) + require.NoError(t, err) + require.Len(t, channsRollApp, 1) + + channDymRollApp := channsRollApp[0].Counterparty + require.NotEmpty(t, channDymRollApp.ChannelID) + + channsRollAppDym := channsRollApp[0] + require.NotEmpty(t, channsRollAppDym.ChannelID) + + channsDym, err = r2.GetChannels(ctx, eRep, dymension.GetChainID()) + require.NoError(t, err) + + channsOsmosis, err := r2.GetChannels(ctx, eRep, osmosis.GetChainID()) + require.NoError(t, err) + + require.Len(t, channsDym, 2) + require.Len(t, channsOsmosis, 1) + + channDymOsmos := channsOsmosis[0].Counterparty + require.NotEmpty(t, channDymOsmos.ChannelID) + + channOsmosDym := channsOsmosis[0] + require.NotEmpty(t, channOsmosDym.ChannelID) + + // Start the relayer and set the cleanup function. + err = r.StartRelayer(ctx, eRep, pathHubToRollApp) + require.NoError(t, err) + + err = r2.StartRelayer(ctx, eRep, pathDymToOsmos) + 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) + } + }, + ) + + walletAmount := math.NewInt(1_000_000_000_000) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1, osmosis) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser, osmosisUser := users[0], users[1], users[2] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + osmosisUserAddr := osmosisUser.FormattedAddress() + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, dymensionOrigBal) + + rollappOrigBal, err := rollapp1.GetBalance(ctx, rollappUserAddr, rollapp1.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, rollappOrigBal) + + osmosisOrigBal, err := osmosis.GetBalance(ctx, osmosisUserAddr, osmosis.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, osmosisOrigBal) + + t.Run("multihop rollapp->dym->osmosis", func(t *testing.T) { + firstHopDenom := transfertypes.GetPrefixedDenom(channDymRollApp.PortID, channDymRollApp.ChannelID, rollapp1.Config().Denom) + secondHopDenom := transfertypes.GetPrefixedDenom(channOsmosDym.PortID, channOsmosDym.ChannelID, firstHopDenom) + + firstHopDenomTrace := transfertypes.ParseDenomTrace(firstHopDenom) + secondHopDenomTrace := transfertypes.ParseDenomTrace(secondHopDenom) + + firstHopIBCDenom := firstHopDenomTrace.IBCDenom() + secondHopIBCDenom := secondHopDenomTrace.IBCDenom() + + zeroBal := math.ZeroInt() + transferAmount := math.NewInt(100_000) + + // Send packet from rollapp1 -> dym -> osmosis + transfer := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + firstHopMetadata := &PacketMetadata{ + Forward: &ForwardMetadata{ + Receiver: osmosisUserAddr, + Channel: channDymOsmos.ChannelID, + Port: channDymOsmos.PortID, + Timeout: 5 * time.Minute, + }, + } + + memo, err := json.Marshal(firstHopMetadata) + require.NoError(t, err) + + transferTx, err := rollapp1.SendIBCTransfer(ctx, channsRollAppDym.ChannelID, rollappUser.KeyName(), transfer, ibc.TransferOptions{Memo: string(memo)}) + require.NoError(t, err) + err = transferTx.Validate() + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 40, rollapp1, osmosis) + require.NoError(t, err) + + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferAmount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, firstHopIBCDenom, zeroBal) + testutil.AssertBalance(t, ctx, osmosis, osmosisUserAddr, secondHopIBCDenom, transferAmount) + }) +} diff --git a/tests/ibc_pfm_with_grace_period_test.go b/tests/ibc_pfm_with_grace_period_test.go index 3be0cf5c..f0e0c303 100644 --- a/tests/ibc_pfm_with_grace_period_test.go +++ b/tests/ibc_pfm_with_grace_period_test.go @@ -21,7 +21,7 @@ import ( "go.uber.org/zap/zaptest" ) -func TestIBCPFMWithGracePeriod(t *testing.T) { +func TestIBCPFMWithGracePeriod_EVM(t *testing.T) { if testing.Short() { t.Skip() } @@ -56,7 +56,7 @@ func TestIBCPFMWithGracePeriod(t *testing.T) { Type: "rollapp-dym", Name: "rollapp-test", ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappImage}, + Images: []ibc.DockerImage{rollappEVMImage}, Bin: "rollappd", Bech32Prefix: "ethm", Denom: "urax", @@ -298,3 +298,281 @@ func TestIBCPFMWithGracePeriod(t *testing.T) { require.True(t, osmosisBalance.Equal(transferAmount)) }) } + +func TestIBCPFMWithGracePeriod_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["node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides["rollapp_id"] = "rollappwasm_1234-1" + dymintTomlOverrides["gas_prices"] = "0adym" + + modifyGenesisKV := append(dymensionGenesisKV, cosmos.GenesisKV{ + Key: "app_state.rollapp.params.dispute_period_in_blocks", + Value: "100", + }) + + 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: nil, + 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(modifyGenesisKV), + ConfigFileOverrides: nil, + }, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + }, + { + Name: "osmosis", + Version: "v17.0.0", + ChainConfig: osmosisConfig, + 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) + osmosis := chains[2].(*cosmos.CosmosChain) + + // Relayer Factory + client, network := test.DockerSetup(t) + + r := test.NewBuiltinRelayerFactory( + ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage("ghcr.io/decentrio/relayer", "e2e-amd", "100:1000"), + ).Build(t, client, "relayer", network) + + r2 := test.NewBuiltinRelayerFactory( + ibc.CosmosRly, + zaptest.NewLogger(t), + relayer.CustomDockerImage(IBCRelayerImage, IBCRelayerVersion, "100:1000"), + ).Build(t, client, "relayer2", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + AddChain(osmosis). + AddRelayer(r, "relayer"). + AddRelayer(r2, "relayer2"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: pathHubToRollApp, + }). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: osmosis, + Relayer: r2, + Path: pathDymToOsmos, + }) + + 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(), + }) + require.NoError(t, err) + + t.Cleanup(func() { + _ = ic.Close() + }) + + channsDym, err := r.GetChannels(ctx, eRep, dymension.GetChainID()) + require.NoError(t, err) + require.Len(t, channsDym, 2) + + channsRollApp, err := r.GetChannels(ctx, eRep, rollapp1.GetChainID()) + require.NoError(t, err) + require.Len(t, channsRollApp, 1) + + channDymRollApp := channsRollApp[0].Counterparty + require.NotEmpty(t, channDymRollApp.ChannelID) + + channsRollAppDym := channsRollApp[0] + require.NotEmpty(t, channsRollAppDym.ChannelID) + + channsDym, err = r2.GetChannels(ctx, eRep, dymension.GetChainID()) + require.NoError(t, err) + + channsOsmosis, err := r2.GetChannels(ctx, eRep, osmosis.GetChainID()) + require.NoError(t, err) + + require.Len(t, channsDym, 2) + require.Len(t, channsOsmosis, 1) + + channDymOsmos := channsOsmosis[0].Counterparty + require.NotEmpty(t, channDymOsmos.ChannelID) + + channOsmosDym := channsOsmosis[0] + require.NotEmpty(t, channOsmosDym.ChannelID) + + // Start the relayer and set the cleanup function. + err = r.StartRelayer(ctx, eRep, pathHubToRollApp) + require.NoError(t, err) + + err = r2.StartRelayer(ctx, eRep, pathDymToOsmos) + 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) + } + }, + ) + + walletAmount := math.NewInt(1_000_000_000_000) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1, osmosis) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser, osmosisUser := users[0], users[1], users[2] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + osmosisUserAddr := osmosisUser.FormattedAddress() + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, dymensionOrigBal) + + rollappOrigBal, err := rollapp1.GetBalance(ctx, rollappUserAddr, rollapp1.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, rollappOrigBal) + + osmosisOrigBal, err := osmosis.GetBalance(ctx, osmosisUserAddr, osmosis.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, osmosisOrigBal) + + t.Run("multihop rollapp->dym->osmosis, funds received on osmosis after grace period", func(t *testing.T) { + firstHopDenom := transfertypes.GetPrefixedDenom(channDymRollApp.PortID, channDymRollApp.ChannelID, rollapp1.Config().Denom) + secondHopDenom := transfertypes.GetPrefixedDenom(channOsmosDym.PortID, channOsmosDym.ChannelID, firstHopDenom) + + firstHopDenomTrace := transfertypes.ParseDenomTrace(firstHopDenom) + secondHopDenomTrace := transfertypes.ParseDenomTrace(secondHopDenom) + + firstHopIBCDenom := firstHopDenomTrace.IBCDenom() + secondHopIBCDenom := secondHopDenomTrace.IBCDenom() + + zeroBal := math.ZeroInt() + transferAmount := math.NewInt(100_000) + + // Send packet from rollapp1 -> dym -> osmosis + transfer := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + firstHopMetadata := &PacketMetadata{ + Forward: &ForwardMetadata{ + Receiver: osmosisUserAddr, + Channel: channDymOsmos.ChannelID, + Port: channDymOsmos.PortID, + Timeout: 5 * time.Minute, + }, + } + + memo, err := json.Marshal(firstHopMetadata) + require.NoError(t, err) + + transferTx, err := rollapp1.SendIBCTransfer(ctx, channsRollAppDym.ChannelID, rollappUser.KeyName(), transfer, ibc.TransferOptions{Memo: string(memo)}) + require.NoError(t, err) + err = transferTx.Validate() + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 50, rollapp1) + require.NoError(t, err) + + rollAppBalance, err := rollapp1.GetBalance(ctx, rollappUserAddr, rollapp1.Config().Denom) + require.NoError(t, err) + + dymBalance, err := dymension.GetBalance(ctx, dymensionUserAddr, firstHopIBCDenom) + require.NoError(t, err) + + osmosisBalance, err := osmosis.GetBalance(ctx, osmosisUserAddr, secondHopIBCDenom) + require.NoError(t, err) + + // Make sure that the transfer is not successful yet due to the grace period + require.True(t, rollAppBalance.Equal(walletAmount.Sub(transferAmount))) + require.True(t, dymBalance.Equal(zeroBal)) + require.True(t, osmosisBalance.Equal(zeroBal)) + + err = testutil.WaitForBlocks(ctx, 100, rollapp1) + require.NoError(t, err) + + osmosisBalance, err = osmosis.GetBalance(ctx, osmosisUserAddr, secondHopIBCDenom) + require.NoError(t, err) + require.True(t, osmosisBalance.Equal(transferAmount)) + }) +} diff --git a/tests/ibc_timeout_test.go b/tests/ibc_timeout_test.go index 2ecb2108..5c8f792a 100644 --- a/tests/ibc_timeout_test.go +++ b/tests/ibc_timeout_test.go @@ -21,7 +21,7 @@ import ( ) // This test case verifies the system's behavior when an IBC packet sent from the rollapp to the hub times out. -func TestIBCTransferTimeout(t *testing.T) { +func TestIBCTransferTimeout_EVM(t *testing.T) { if testing.Short() { t.Skip() } @@ -56,7 +56,7 @@ func TestIBCTransferTimeout(t *testing.T) { Type: "rollapp-dym", Name: "rollapp-test", ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappImage}, + Images: []ibc.DockerImage{rollappEVMImage}, Bin: "rollappd", Bech32Prefix: "ethm", Denom: "urax", @@ -236,3 +236,220 @@ func TestIBCTransferTimeout(t *testing.T) { }, ) } + +// This test case verifies the system's behavior when an IBC packet sent from the rollapp to the hub times out. +func TestIBCTransferTimeout_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["node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides["rollapp_id"] = "rollappwasm_1234-1" + dymintTomlOverrides["gas_prices"] = "0adym" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + const BLOCK_FINALITY_PERIOD = 10 + modifyGenesisKV := append( + dymensionGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollapp.params.dispute_period_in_blocks", + Value: fmt.Sprint(BLOCK_FINALITY_PERIOD), + }, + ) + // 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-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: nil, + 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(modifyGenesisKV), + 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("ghcr.io/decentrio/relayer", "e2e-amd", "100:1000"), + ).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: 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(), + }) + require.NoError(t, err) + + walletAmount := math.NewInt(1_000_000_000_000) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // 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) + + // Compose an IBC transfer and send from rollapp -> dymension + var transferAmount = math.NewInt(1_000_000) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + transferData := ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + // 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 + }, + } + + // Compose an IBC transfer and send from Rollapp -> Hub + _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, transferData, options) + require.NoError(t, err) + // Assert balance was updated on the rollapp + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + // Stop relayer after relaying + err = r.StopRelayer(ctx, eRep) + require.NoError(t, err, "an error occurred while stopping the relayer") + + // 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() + + // Assert funds were returned to the sender after the timeout has occured + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, math.NewInt(0)) + + channel, err = ibc.GetTransferChannel(ctx, r, eRep, rollapp1.Config().ChainID, dymension.Config().ChainID) + require.NoError(t, err) + + 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, options) + require.NoError(t, err) + // Assert balance was updated on the rollapp + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferData.Amount)) + // 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() + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, math.NewInt(0)) + + // 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, 5, rollapp1) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 40, dymension, rollapp1) + require.NoError(t, err) + + // Assert funds were returned to the sender after the timeout has occured + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, math.NewInt(0)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount) + + t.Cleanup( + func() { + err := r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) +} diff --git a/tests/ibc_transfer_test.go b/tests/ibc_transfer_test.go index 4c5ae505..e4efaf33 100644 --- a/tests/ibc_transfer_test.go +++ b/tests/ibc_transfer_test.go @@ -21,7 +21,7 @@ import ( const ibcPath = "dymension-demo" // TestIBCTransferSuccess ensure that the transfer between Hub and Rollapp is accurate. -func TestIBCTransferSuccess(t *testing.T) { +func TestIBCTransferSuccess_EVM(t *testing.T) { if testing.Short() { t.Skip() } @@ -49,7 +49,7 @@ func TestIBCTransferSuccess(t *testing.T) { Type: "rollapp-dym", Name: "rollapp-temp", ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappImage}, + Images: []ibc.DockerImage{rollappEVMImage}, Bin: "rollappd", Bech32Prefix: "ethm", Denom: "urax", @@ -198,3 +198,182 @@ func TestIBCTransferSuccess(t *testing.T) { testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount) } + +// TestIBCTransferSuccess ensure that the transfer between Hub and Rollapp is accurate. +func TestIBCTransferSuccess_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["node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides["rollapp_id"] = "rollappwasm_1234-1" + dymintTomlOverrides["gas_prices"] = "0adym" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + // Create chain factory with dymension + numHubVals := 2 + 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: nil, + 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("ghcr.io/decentrio/relayer", "e2e-amd", "100:1000"), + ).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: 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(), + }) + require.NoError(t, err) + + walletAmount := math.NewInt(1_000_000_000_000) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.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) + + rollappOrigBal, err := rollapp1.GetBalance(ctx, rollappUserAddr, rollapp1.Config().Denom) + require.NoError(t, err) + require.Equal(t, walletAmount, rollappOrigBal) + + 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) + t.Cleanup( + func() { + err := r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) + + // Compose an IBC transfer and send from dymension -> rollapp + var transferAmount = math.NewInt(1_000_000) + + 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, walletAmount.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, walletAmount.Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, transferAmount) + + 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) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 30, 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() + + // Assert funds were returned to the sender after the timeout has occured + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount) +} diff --git a/tests/setup.go b/tests/setup.go index 876436d6..1e51e594 100644 --- a/tests/setup.go +++ b/tests/setup.go @@ -34,12 +34,14 @@ type ForwardMetadata struct { var ( DymensionMainRepo = "ghcr.io/dymensionxyz/dymension" - RollappMainRepo = "ghcr.io/dymensionxyz/rollapp-evm" + RollappEVMMainRepo = "ghcr.io/dymensionxyz/rollapp-evm" + + RollappWasmMainRepo = "ghcr.io/dymensionxyz/rollapp-wasm" IBCRelayerImage = "ghcr.io/decentrio/relayer" IBCRelayerVersion = "main" - dymensionVersion, rollappVersion = GetDockerImageVersion() + dymensionVersion, rollappEVMVersion, rollappWasmVersion = GetDockerImageVersion() dymensionImage = ibc.DockerImage{ Repository: DymensionMainRepo, @@ -47,9 +49,15 @@ var ( UidGid: "1025:1025", } - rollappImage = ibc.DockerImage{ - Repository: RollappMainRepo, - Version: rollappVersion, + rollappEVMImage = ibc.DockerImage{ + Repository: RollappEVMMainRepo, + Version: rollappEVMVersion, + UidGid: "1025:1025", + } + + rollappWasmImage = ibc.DockerImage{ + Repository: RollappWasmMainRepo, + Version: rollappWasmVersion, UidGid: "1025:1025", } @@ -72,7 +80,7 @@ var ( } // Setup for Osmosis - osmosisImageRepo = "ghcr.io/strangelove-ventures/heighliner/osmosis" // + osmosisImageRepo = "ghcr.io/strangelove-ventures/heighliner/osmosis" osmosisImage = ibc.DockerImage{ Repository: osmosisImageRepo, @@ -251,17 +259,22 @@ var ( } ) -func GetDockerImageVersion() (dymensionVersion, rollappVersion string) { +func GetDockerImageVersion() (dymensionVersion, rollappEVMVersion, rollappWasmVersion string) { dymensionVersion, found := os.LookupEnv("DYMENSION_CI") if !found { dymensionVersion = "latest" } - rollappVersion, found = os.LookupEnv("ROLLAPP_CI") + rollappEVMVersion, found = os.LookupEnv("ROLLAPP_EVM_CI") + if !found { + rollappEVMVersion = "latest" + } + + rollappWasmVersion, found = os.LookupEnv("ROLLAPP_WASM_CI") if !found { - rollappVersion = "latest" + rollappWasmVersion = "latest" } - return dymensionVersion, rollappVersion + return dymensionVersion, rollappEVMVersion, rollappWasmVersion } func encodingConfig() *simappparams.EncodingConfig { diff --git a/tests/tx_batch_finalization_test.go b/tests/tx_batch_finalization_test.go index cd78d856..984e1dcc 100644 --- a/tests/tx_batch_finalization_test.go +++ b/tests/tx_batch_finalization_test.go @@ -28,7 +28,7 @@ type ExtractedInfo struct { // This test verifies the system's behavior for batch finalization with different dispute periods // Dispute period is updated with a gov proposal during the test -func TestBatchFinalization(t *testing.T) { +func TestBatchFinalization_EVM(t *testing.T) { if testing.Short() { t.Skip() } @@ -64,7 +64,7 @@ func TestBatchFinalization(t *testing.T) { Type: "rollapp-dym", Name: "rollapp-temp", ChainID: "rollappevm_1234-1", - Images: []ibc.DockerImage{rollappImage}, + Images: []ibc.DockerImage{rollappEVMImage}, Bin: "rollappd", Bech32Prefix: "ethm", Denom: "urax", @@ -170,6 +170,148 @@ func TestBatchFinalization(t *testing.T) { currentFinalizedRollappDymHeight, BLOCK_FINALITY_PERIOD, lastFinalizedRollappHeight, rollappHeight)) } +func TestBatchFinalization_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["node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides["rollapp_id"] = "rollappwasm_1234-1" + dymintTomlOverrides["gas_prices"] = "0adym" + + const BLOCK_FINALITY_PERIOD = 50 + modifyGenesisKV := append( + dymensionGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollapp.params.dispute_period_in_blocks", + Value: fmt.Sprint(BLOCK_FINALITY_PERIOD), + }, + ) + + 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: nil, + 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(modifyGenesisKV), + 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) + + 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: 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(), + }) + require.NoError(t, err) + + walletAmount := math.NewInt(1_000_000_000_000) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // 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) + + // rollapp height should be finalized in a batch processed > 50 hub blocks (dispute period) + rollappHeight, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + IsAnyRollappStateFinalized(ctx, dymension, rollapp1.GetChainID(), 300) + require.NoError(t, err) + + lastFinalizedRollappHeight, err := dymension.FinalizedRollappStateHeight(ctx, rollapp1.GetChainID()) + require.NoError(t, err) + + currentFinalizedRollappDymHeight, err := dymension.FinalizedRollappDymHeight(ctx, rollapp1.GetChainID()) + require.NoError(t, err) + + // verify that the last creation height for finalized states on the hub is greater than dispute period + // also, last finalized rollapp state height needs to be greater than the rollapp height verified + require.True(t, (currentFinalizedRollappDymHeight > BLOCK_FINALITY_PERIOD) && (lastFinalizedRollappHeight > rollappHeight), + fmt.Sprintf("Mismatch in batch finalization check. Current finalization hub height: %d. Dispute period: %d. Last finalized rollapp height: %d. Rollapp height asserted: %d", + currentFinalizedRollappDymHeight, BLOCK_FINALITY_PERIOD, lastFinalizedRollappHeight, rollappHeight)) +} + func IsAnyRollappStateFinalized(ctx context.Context, dymension *dym_hub.DymHub, rollappChainID string, timeoutSecs int) (bool, error) { var err error startTime := time.Now()