diff --git a/.github/workflows/wormchain-icts.yml b/.github/workflows/wormchain-icts.yml index 7c71430a85..d8bb38b526 100644 --- a/.github/workflows/wormchain-icts.yml +++ b/.github/workflows/wormchain-icts.yml @@ -30,6 +30,7 @@ jobs: - "ictest-upgrade" - "ictest-wormchain" - "ictest-ibc-receiver" + - "ictest-cw-wormhole" fail-fast: false steps: diff --git a/wormchain/Makefile b/wormchain/Makefile index 8252663763..ac8819f70e 100644 --- a/wormchain/Makefile +++ b/wormchain/Makefile @@ -105,4 +105,7 @@ ictest-wormchain: rm-testcache ictest-ibc-receiver: rm-testcache cd interchaintest && go test -race -v -run ^TestIbcReceiver ./... -.PHONY: ictest-cancel-upgrade ictest-malformed-payload ictest-upgrade-failure ictest-upgrade ictest-wormchain ictest-ibc-receiver \ No newline at end of file +ictest-cw-wormhole: rm-testcache + cd interchaintest && go test -race -v -run ^TestCWWormhole ./... + +.PHONY: ictest-cancel-upgrade ictest-malformed-payload ictest-upgrade-failure ictest-upgrade ictest-wormchain ictest-ibc-receiver ictest-cw-wormhole \ No newline at end of file diff --git a/wormchain/interchaintest/contracts/cw_wormhole.wasm b/wormchain/interchaintest/contracts/cw_wormhole.wasm new file mode 100644 index 0000000000..b852a957a3 Binary files /dev/null and b/wormchain/interchaintest/contracts/cw_wormhole.wasm differ diff --git a/wormchain/interchaintest/cw_wormhole_test.go b/wormchain/interchaintest/cw_wormhole_test.go new file mode 100644 index 0000000000..9ce1054964 --- /dev/null +++ b/wormchain/interchaintest/cw_wormhole_test.go @@ -0,0 +1,492 @@ +package ictest + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/hex" + "encoding/json" + "testing" + + "github.com/docker/docker/client" + "github.com/strangelove-ventures/interchaintest/v4" + "github.com/strangelove-ventures/interchaintest/v4/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v4/ibc" + "github.com/strangelove-ventures/interchaintest/v4/testutil" + "go.uber.org/zap/zaptest" + + "github.com/stretchr/testify/require" + + "github.com/wormhole-foundation/wormchain/interchaintest/guardians" + "github.com/wormhole-foundation/wormchain/interchaintest/helpers" + "github.com/wormhole-foundation/wormchain/interchaintest/helpers/cw_wormhole" + "github.com/wormhole-foundation/wormhole/sdk/vaa" +) + +func createSingleNodeCluster(t *testing.T, wormchainVersion string, guardians guardians.ValSet) ibc.Chain { + numWormchainVals := len(guardians.Vals) + numFullNodes := 0 + + wormchainConfig.Images[0].Version = wormchainVersion + wormchainConfig.ModifyGenesis = ModifyGenesis(votingPeriod, maxDepositPeriod, guardians, true) + + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + { + ChainName: "wormchain", + ChainConfig: wormchainConfig, + NumValidators: &numWormchainVals, + NumFullNodes: &numFullNodes, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + return chains[0] +} + +func buildSingleNodeInterchain(t *testing.T, chain ibc.Chain) (context.Context, *client.Client) { + ic := interchaintest.NewInterchain() + ic.AddChain(chain) + + ctx := context.Background() + client, network := interchaintest.DockerSetup(t) + + err := ic.Build(ctx, nil, interchaintest.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + }) + require.NoError(t, err) + + t.Cleanup(func() { + _ = ic.Close() + }) + + return ctx, client +} + +// TestCWWormholeQueries tests the query functions of the cw_wormhole contract +func TestCWWormholeQueries(t *testing.T) { + // Base setup + numVals := 1 + guardians := guardians.CreateValSet(t, numVals) + + chain := createSingleNodeCluster(t, "v2.24.2", *guardians) + ctx, _ := buildSingleNodeInterchain(t, chain) + + wormchain := chain.(*cosmos.CosmosChain) + + // Instantiate the cw_wormhole contract + coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, guardians) + wormchainCoreContractInfo := helpers.StoreAndInstantiateWormholeContract(t, ctx, wormchain, "faucet", "./contracts/cw_wormhole.wasm", "wormhole_core", coreInstantiateMsg, guardians) + contractAddr := wormchainCoreContractInfo.Address + + // Query the contract to check that the guardian set is correct + var guardianSetResp cw_wormhole.GuardianSetQueryResponse + err := wormchain.QueryContract(ctx, contractAddr, cw_wormhole.QueryMsg{ + GuardianSetInfo: &cw_wormhole.QueryMsg_GuardianSetInfo{}, + }, &guardianSetResp) + require.NoError(t, err) + require.Equal(t, numVals, len(guardianSetResp.Data.Addresses), "guardian set should have the correct number of guardians") + // Check that all the guardians from the query are the ones in the running valset + for _, val := range guardians.Vals { + found := false + for _, guardian := range guardianSetResp.Data.Addresses { + decoded, err := base64.StdEncoding.DecodeString(string(guardian.Bytes)) + require.NoError(t, err) + guardianDecodedBytes := []byte(decoded) + if bytes.Equal(val.Addr, guardianDecodedBytes) { + found = true + break + } + } + require.True(t, found, "guardian not found in guardian set") + } + + // Check that the core contract fee is set to 0uworm + var stateResp cw_wormhole.GetStateQueryResponse + err = wormchain.QueryContract(ctx, contractAddr, cw_wormhole.QueryMsg{ + GetState: &cw_wormhole.QueryMsg_GetState{}, + }, &stateResp) + require.NoError(t, err) + require.Equal(t, "uworm", stateResp.Data.Fee.Denom, "core contract fee should be in uworm") + require.Equal(t, cw_wormhole.Uint128("0"), stateResp.Data.Fee.Amount, "core contract fee should be 0") + + // Check that hex addresse are able to be queried + var hexAddressResp cw_wormhole.QueryAddressHexQueryResponse + err = wormchain.QueryContract(ctx, contractAddr, cw_wormhole.QueryMsg{ + QueryAddressHex: &cw_wormhole.QueryMsg_QueryAddressHex{ + Address: "wormhole14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srrg465", + }, + }, &hexAddressResp) + require.NoError(t, err) + require.IsType(t, "", hexAddressResp.Data.Hex, "hex address should be a string") + + // Check that the core contract can properly verify a VAA + guardianSetIndex := helpers.QueryConsensusGuardianSetIndex(t, wormchain, ctx) + vaa := helpers.GenerateGovernanceVaa(uint32(guardianSetIndex), guardians, []byte("test")) + vaaBz, err := vaa.Marshal() + require.NoError(t, err) + encodedVaa := base64.StdEncoding.EncodeToString(vaaBz) + vaaBinary := cw_wormhole.Binary(encodedVaa) + + currentWormchainBlock, err := wormchain.Height(ctx) + require.NoError(t, err) + + var parsedVaaResponse cw_wormhole.VerifyVAAQueryResponse + err = wormchain.QueryContract(ctx, contractAddr, cw_wormhole.QueryMsg{ + VerifyVaa: &cw_wormhole.QueryMsg_VerifyVAA{ + BlockTime: int(currentWormchainBlock), + Vaa: vaaBinary, + }, + }, &parsedVaaResponse) + require.NoError(t, err) + require.NotNil(t, parsedVaaResponse.Data, "VAA should be verified") + require.Equal(t, "test", string(parsedVaaResponse.Data.Payload), "VAA payload should be what we passed in") +} + +// TestCWWormholePostMessage tests the PostMessage function of the cw_wormhole contract +func TestCWWormholePostMessage(t *testing.T) { + numVals := 1 + guardians := guardians.CreateValSet(t, numVals) + chain := createSingleNodeCluster(t, "v2.24.2", *guardians) + ctx, _ := buildSingleNodeInterchain(t, chain) + wormchain := chain.(*cosmos.CosmosChain) + + // Instantiate contract + coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, guardians) + contractInfo := helpers.StoreAndInstantiateWormholeContract(t, ctx, wormchain, "faucet", "./contracts/cw_wormhole.wasm", "wormhole_core", coreInstantiateMsg, guardians) + contractAddr := contractInfo.Address + + // Create message and encode to base64 + message := []byte("test message") + messageBase64 := base64.StdEncoding.EncodeToString(message) + nonce := 1 + + executeMsg, err := json.Marshal(cw_wormhole.ExecuteMsg{ + PostMessage: &cw_wormhole.ExecuteMsg_PostMessage{ + Message: cw_wormhole.Binary(messageBase64), + Nonce: nonce, + }, + }) + require.NoError(t, err) + + // Execute contract + txHash, err := wormchain.ExecuteContract(ctx, "faucet", contractAddr, string(executeMsg)) + require.NoError(t, err) + + // Wait 2 blocks + err = testutil.WaitForBlocks(ctx, 2, wormchain) + require.NoError(t, err) + + // Query and parse the response + txResult, _, err := wormchain.Validators[0].ExecQuery(ctx, "tx", txHash) + require.NoError(t, err) + + var txResponse cw_wormhole.TxResponse + err = json.Unmarshal(txResult, &txResponse) + require.NoError(t, err) + + // Verify event attributes + cw_wormhole.VerifyEventAttributes(t, &txResponse, map[string]string{ + "_contract_address": contractAddr, + "message.message": hex.EncodeToString(message), + "message.nonce": "1", + "message.sequence": "0", + }) +} + +// TestCWWormholeUpdateGuardianSet tests the UpdateGuardianSet function of the cw_wormhole contract +func TestCWWormholeUpdateGuardianSet(t *testing.T) { + // Setup chain and contract + numVals := 1 + oldGuardians := guardians.CreateValSet(t, numVals) + chain := createSingleNodeCluster(t, "v2.24.2", *oldGuardians) + ctx, _ := buildSingleNodeInterchain(t, chain) + wormchain := chain.(*cosmos.CosmosChain) + + // Deploy contract + coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, oldGuardians) + contractInfo := helpers.StoreAndInstantiateWormholeContract(t, ctx, wormchain, "faucet", "./contracts/cw_wormhole.wasm", "wormhole_core", coreInstantiateMsg, oldGuardians) + contractAddr := contractInfo.Address + + // Get initial guardian set index + initialIndex := int(helpers.QueryConsensusGuardianSetIndex(t, wormchain, ctx)) + signingGuardians := guardians.CreateValSet(t, numVals+1) + + t.Run("successful update", func(t *testing.T) { + newGuardians := signingGuardians + err := cw_wormhole.SubmitGuardianSetUpdate(t, ctx, wormchain, contractAddr, newGuardians, uint32(initialIndex+1), oldGuardians) + require.NoError(t, err) + cw_wormhole.VerifyGuardianSet(t, ctx, wormchain, contractAddr, newGuardians, initialIndex+1) + }) + + t.Run("invalid guardian set index", func(t *testing.T) { + // Try to update with non-sequential index + newGuardians := guardians.CreateValSet(t, numVals+1) + err := cw_wormhole.SubmitGuardianSetUpdate(t, ctx, wormchain, contractAddr, newGuardians, uint32(initialIndex+3), signingGuardians) + require.Error(t, err) + + // Try to update with same index + err = cw_wormhole.SubmitGuardianSetUpdate(t, ctx, wormchain, contractAddr, newGuardians, uint32(initialIndex), signingGuardians) + require.Error(t, err) + }) + + t.Run("empty guardian set", func(t *testing.T) { + emptyGuardians := guardians.CreateValSet(t, 0) + err := cw_wormhole.SubmitGuardianSetUpdate(t, ctx, wormchain, contractAddr, emptyGuardians, uint32(initialIndex+1), signingGuardians) + require.Error(t, err) + require.Contains(t, err.Error(), "GuardianSignatureError") + }) + + t.Run("duplicate guardians", func(t *testing.T) { + // Create guardian set with duplicate addresses + dupGuardians := guardians.CreateValSet(t, 1) + dupGuardians.Vals = append(dupGuardians.Vals, dupGuardians.Vals[0]) + dupGuardians.Total = 2 + + err := cw_wormhole.SubmitGuardianSetUpdate(t, ctx, wormchain, contractAddr, dupGuardians, uint32(initialIndex+1), signingGuardians) + require.Error(t, err) + require.Contains(t, err.Error(), "GuardianSignatureError") + }) + + t.Run("wrong signing guardian set", func(t *testing.T) { + // Create new guardians and try to use them to sign the update + wrongSigners := guardians.CreateValSet(t, numVals) + newGuardians := guardians.CreateValSet(t, numVals+1) + + err := cw_wormhole.SubmitGuardianSetUpdate(t, ctx, wormchain, contractAddr, newGuardians, uint32(initialIndex+1), wrongSigners) + require.Error(t, err) + require.Contains(t, err.Error(), "governance VAAs must be signed by the current guardian set") + }) + + t.Run("insufficient signatures", func(t *testing.T) { + // Create a guardian set with only one signer (below quorum) + insufficientSigners := guardians.CreateValSet(t, 1) + newGuardians := guardians.CreateValSet(t, numVals+1) + + err := cw_wormhole.SubmitGuardianSetUpdate(t, ctx, wormchain, contractAddr, newGuardians, uint32(initialIndex+1), insufficientSigners) + require.Error(t, err) + require.Contains(t, err.Error(), "governance VAAs must be signed by the current guardian set") + + // too many signatures + insufficientSigners = guardians.CreateValSet(t, numVals+2) + err = cw_wormhole.SubmitGuardianSetUpdate(t, ctx, wormchain, contractAddr, newGuardians, uint32(initialIndex+1), insufficientSigners) + require.Error(t, err) + require.Contains(t, err.Error(), "GuardianSignatureError") + }) + + // Verify signing validators did not change + cw_wormhole.VerifyGuardianSet(t, ctx, wormchain, contractAddr, signingGuardians, initialIndex+1) +} + +// TestCWWormholeContractUpgrade tests the SubmitContractUpgrade function of the cw_wormhole contract +func TestCWWormholeContractUpgrade(t *testing.T) { + // Setup chain and contract + numVals := 1 + guardians := guardians.CreateValSet(t, numVals) + chains := CreateChains(t, "v2.24.2", *guardians) + ctx, _, _, _ := BuildInterchain(t, chains) + + // Chains + wormchain := chains[0].(*cosmos.CosmosChain) + + // Deploy contract to wormhole + coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, guardians) + contractInfo := helpers.StoreAndInstantiateWormholeContract(t, ctx, wormchain, "faucet", "./contracts/cw_wormhole.wasm", "wormhole_core", coreInstantiateMsg, guardians) + wormContractAddr := contractInfo.Address + + // Store a new version of the contract to upgrade to + wormNewCodeId := helpers.StoreContract(t, ctx, wormchain, "faucet", "./contracts/cw_wormhole.wasm", guardians) + + t.Run("successful upgrade", func(t *testing.T) { + err := cw_wormhole.SubmitContractUpgrade(t, ctx, guardians, wormchain, wormContractAddr, wormNewCodeId) + require.NoError(t, err) + + contractInfo = helpers.QueryContractInfo(t, wormchain, ctx, wormContractAddr) + require.NoError(t, err) + require.Equal(t, wormNewCodeId, contractInfo.ContractInfo.CodeID) + }) + + t.Run("invalid code id", func(t *testing.T) { + err := cw_wormhole.SubmitContractUpgrade(t, ctx, guardians, wormchain, wormContractAddr, "999999") + require.Error(t, err) + }) + + // VAA payload to upgrade contract is not allowed on Wormchain, must use the wormhole module + t.Run("upgrade wormhole contract with vaa: fails - use x/wormhole", func(t *testing.T) { + // Submit VAA + err := cw_wormhole.SubmitContractUpgradeWithVaa(t, ctx, guardians, 0, vaa.ChainIDWormchain, wormchain, wormContractAddr, wormNewCodeId, "faucet") + require.Error(t, err) + require.Contains(t, err.Error(), "must use x/wormhole") + }) + + // Test osmo chain + osmo := chains[2].(*cosmos.CosmosChain) + users := interchaintest.GetAndFundTestUsers(t, ctx, t.Name(), 10_000_000_000, osmo) + osmoUser := users[0] + + // Deploy contract to osmo + osmoCodeId, err := osmo.StoreContract(ctx, osmoUser.KeyName, "./contracts/cw_wormhole.wasm") + require.NoError(t, err) + + instantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDOsmosis, guardians) + + osmoContractAddr, err := osmo.InstantiateContract(ctx, osmoUser.KeyName, osmoCodeId, instantiateMsg, false, "--admin", osmoUser.Bech32Address("osmo")) + require.NoError(t, err) + + // Update admin to contract addr + _, err = osmo.GetFullNode().ExecTx(ctx, osmoUser.KeyName, "wasm", "set-contract-admin", osmoContractAddr, osmoContractAddr) + require.NoError(t, err) + err = testutil.WaitForBlocks(ctx, 2, osmo) + require.NoError(t, err) + + // Verify new admin is contract + contractInfo = helpers.QueryContractInfo(t, osmo, ctx, osmoContractAddr) + require.NoError(t, err) + require.Equal(t, osmoContractAddr, contractInfo.ContractInfo.Admin) + + // Store a new version of the contract to upgrade to + osmoNewCodeId, err := osmo.StoreContract(ctx, osmoUser.KeyName, "./contracts/cw_wormhole.wasm") + require.NoError(t, err) + + t.Run("migrate osmosis via payload", func(t *testing.T) { + // Submit VAA + err := cw_wormhole.SubmitContractUpgradeWithVaa(t, ctx, guardians, 0, vaa.ChainIDOsmosis, osmo, osmoContractAddr, osmoNewCodeId, osmoUser.KeyName) + require.NoError(t, err) + + contractInfo := helpers.QueryContractInfo(t, osmo, ctx, osmoContractAddr) + require.NoError(t, err) + require.Equal(t, osmoNewCodeId, contractInfo.ContractInfo.CodeID) + }) + +} + +// TestCWWormholeSetFee tests the SetFee function of the cw_wormhole contract +func TestCWWormholeSetFee(t *testing.T) { + // Setup chain and contract + numVals := 1 + guardians := guardians.CreateValSet(t, numVals) + chain := createSingleNodeCluster(t, "v2.24.2", *guardians) + ctx, _ := buildSingleNodeInterchain(t, chain) + wormchain := chain.(*cosmos.CosmosChain) + + // Deploy contract + coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, guardians) + contractInfo := helpers.StoreAndInstantiateWormholeContract(t, ctx, wormchain, "faucet", "./contracts/cw_wormhole.wasm", "wormhole_core", coreInstantiateMsg, guardians) + contractAddr := contractInfo.Address + + // wrapper around helper function for cleaner test code + submitFeeUpdate := func(amount string, replay bool) (*cw_wormhole.TxResponse, error) { + return cw_wormhole.SubmitFeeUpdate(t, ctx, guardians, wormchain, contractAddr, amount, replay) + } + + t.Run("successful fee update", func(t *testing.T) { + txResponse, err := submitFeeUpdate("1000000", true) // Set fee to 1 WORM (1000000 uworm) + require.NoError(t, err) + cw_wormhole.VerifyEventAttributes(t, txResponse, map[string]string{ + "action": "fee_change", + "new_fee.amount": "1000000", + "new_fee.denom": "uworm", + }) + cw_wormhole.VerifyFee(t, ctx, wormchain, contractAddr, "1000000") + + // post a message with fee under the new fee + err = cw_wormhole.PostMessageWithFee(t, ctx, wormchain, contractAddr, "message1", 999999) + require.Error(t, err) + require.Contains(t, err.Error(), "FeeTooLow") + + // post a message with fee equal to the new fee + err = cw_wormhole.PostMessageWithFee(t, ctx, wormchain, contractAddr, "message2", 1000000) + require.NoError(t, err) + + // post a message with fee above the new fee + err = cw_wormhole.PostMessageWithFee(t, ctx, wormchain, contractAddr, "message3", 1000001) + require.NoError(t, err) + }) + + t.Run("zero fee", func(t *testing.T) { + txResponse, err := submitFeeUpdate("0", false) + require.NoError(t, err) + cw_wormhole.VerifyEventAttributes(t, txResponse, map[string]string{ + "action": "fee_change", + "new_fee.amount": "0", + "new_fee.denom": "uworm", + }) + cw_wormhole.VerifyFee(t, ctx, wormchain, contractAddr, "0") + }) + + t.Run("very large fee", func(t *testing.T) { + txResponse, err := submitFeeUpdate("1000000000000", false) // 1M WORM + require.NoError(t, err) + cw_wormhole.VerifyEventAttributes(t, txResponse, map[string]string{ + "action": "fee_change", + "new_fee.amount": "1000000000000", + "new_fee.denom": "uworm", + }) + cw_wormhole.VerifyFee(t, ctx, wormchain, contractAddr, "1000000000000") + }) +} + +// TestCWWormholeTransferFees tests transferring the accumulated fees to the core contract +func TestCWWormholeTransferFees(t *testing.T) { + // Setup chain and contract + numVals := 1 + guardians := guardians.CreateValSet(t, numVals) + chain := createSingleNodeCluster(t, "v2.24.2", *guardians) + ctx, _ := buildSingleNodeInterchain(t, chain) + wormchain := chain.(*cosmos.CosmosChain) + + // Deploy contract + coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, guardians) + contractInfo := helpers.StoreAndInstantiateWormholeContract(t, ctx, wormchain, "faucet", "./contracts/cw_wormhole.wasm", "wormhole_core", coreInstantiateMsg, guardians) + contractAddr := contractInfo.Address + + users := interchaintest.GetAndFundTestUsers(t, ctx, t.Name(), 1, wormchain) + user := users[0] + userAddr := user.Bech32Address("wormhole") + + t.Run("successful fee transfer", func(t *testing.T) { + // Set fee to 1000000 uworm + _, err := cw_wormhole.SubmitFeeUpdate(t, ctx, guardians, wormchain, contractAddr, "1000000", false) + require.NoError(t, err) + + // Post some messages with fees to build up balance + err = cw_wormhole.PostMessageWithFee(t, ctx, wormchain, contractAddr, "message1", 1000000) + require.NoError(t, err) + err = cw_wormhole.PostMessageWithFee(t, ctx, wormchain, contractAddr, "message2", 1000000) + require.NoError(t, err) + + // Get recipient's initial balance + initialBalance, err := cw_wormhole.GetUwormBalance(t, ctx, wormchain, userAddr) + require.NoError(t, err) + + // Transfer 1500000 uworm + _, err = cw_wormhole.SubmitTransferFee(t, ctx, guardians, wormchain, contractAddr, []byte(user.Address), "1500000", true) + require.NoError(t, err) + + // Verify successful transfer + finalBalance, err := cw_wormhole.GetUwormBalance(t, ctx, wormchain, userAddr) + require.NoError(t, err) + require.Equal(t, initialBalance+1500000, finalBalance) + }) + + t.Run("transfer more than balance", func(t *testing.T) { + _, err := cw_wormhole.SubmitTransferFee(t, ctx, guardians, wormchain, contractAddr, []byte(user.Address), "10000000000", false) + require.Error(t, err) + require.Contains(t, err.Error(), "insufficient funds") + }) + + t.Run("invalid recipient", func(t *testing.T) { + _, err := cw_wormhole.SubmitTransferFee(t, ctx, guardians, wormchain, contractAddr, []byte("invalid"), "1000000", false) + require.Error(t, err) + }) + + t.Run("zero amount - invalid coins", func(t *testing.T) { + _, err := cw_wormhole.SubmitTransferFee(t, ctx, guardians, wormchain, contractAddr, []byte(user.Address), "0", false) + require.Error(t, err) + }) +} diff --git a/wormchain/interchaintest/helpers/cw_wormhole/cw_wormhole.go b/wormchain/interchaintest/helpers/cw_wormhole/cw_wormhole.go new file mode 100644 index 0000000000..b8d7d0b849 --- /dev/null +++ b/wormchain/interchaintest/helpers/cw_wormhole/cw_wormhole.go @@ -0,0 +1,110 @@ +/* Code generated by github.com/srdtrk/go-codegen, DO NOT EDIT. */ +package cw_wormhole + +// The instantiation parameters of the core bridge contract. See [`crate::state::ConfigInfo`] for more details on what these fields mean. +type InstantiateMsg struct { + FeeDenom string `json:"fee_denom"` + GovAddress Binary `json:"gov_address"` + GovChain int `json:"gov_chain"` + GuardianSetExpirity int `json:"guardian_set_expirity"` + // Guardian set to initialise the contract with. + InitialGuardianSet GuardianSetInfo `json:"initial_guardian_set"` + ChainId int `json:"chain_id"` +} + +type ExecuteMsg struct { + SubmitVaa *ExecuteMsg_SubmitVAA `json:"submit_v_a_a,omitempty"` + PostMessage *ExecuteMsg_PostMessage `json:"post_message,omitempty"` +} + +type QueryMsg struct { + GuardianSetInfo *QueryMsg_GuardianSetInfo `json:"guardian_set_info,omitempty"` + VerifyVaa *QueryMsg_VerifyVAA `json:"verify_v_a_a,omitempty"` + GetState *QueryMsg_GetState `json:"get_state,omitempty"` + QueryAddressHex *QueryMsg_QueryAddressHex `json:"query_address_hex,omitempty"` +} + +type ExecuteMsg_PostMessage struct { + Message Binary `json:"message"` + Nonce int `json:"nonce"` +} + +type GuardianSetInfoResponse struct { + Addresses []GuardianAddress `json:"addresses"` + GuardianSetIndex int `json:"guardian_set_index"` +} + +/* +A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq. + +# Examples + +Use `from` to create instances of this and `u128` to get the value out: + +``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123); + +let b = Uint128::from(42u64); assert_eq!(b.u128(), 42); + +let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ``` +*/ +type Uint128 string + +type GetStateResponse struct { + Fee Coin `json:"fee"` +} + +type GuardianAddress struct { + Bytes Binary `json:"bytes"` +} + +type QueryMsg_GetState struct{} + +type QueryMsg_QueryAddressHex struct { + Address string `json:"address"` +} + +/* +Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline. + +This is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also . +*/ +type Binary string + +type ExecuteMsg_SubmitVAA struct { + Vaa Binary `json:"vaa"` +} + +type QueryMsg_VerifyVAA struct { + BlockTime int `json:"block_time"` + Vaa Binary `json:"vaa"` +} + +type ParsedVAA struct { + ConsistencyLevel int `json:"consistency_level"` + EmitterAddress []int `json:"emitter_address"` + Hash []int `json:"hash"` + LenSigners int `json:"len_signers"` + Timestamp int `json:"timestamp"` + Version int `json:"version"` + EmitterChain int `json:"emitter_chain"` + GuardianSetIndex int `json:"guardian_set_index"` + Nonce int `json:"nonce"` + Payload []byte `json:"payload"` + Sequence int `json:"sequence"` +} + +type Coin struct { + Amount Uint128 `json:"amount"` + Denom string `json:"denom"` +} + +type GuardianSetInfo struct { + Addresses []GuardianAddress `json:"addresses"` + ExpirationTime int `json:"expiration_time"` +} + +type GetAddressHexResponse struct { + Hex string `json:"hex"` +} + +type QueryMsg_GuardianSetInfo struct{} diff --git a/wormchain/interchaintest/helpers/cw_wormhole/helpers.go b/wormchain/interchaintest/helpers/cw_wormhole/helpers.go new file mode 100644 index 0000000000..6468094bc2 --- /dev/null +++ b/wormchain/interchaintest/helpers/cw_wormhole/helpers.go @@ -0,0 +1,408 @@ +package cw_wormhole + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/binary" + "encoding/json" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/strangelove-ventures/interchaintest/v4/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v4/testutil" + + "github.com/stretchr/testify/require" + + "github.com/wormhole-foundation/wormchain/interchaintest/guardians" + "github.com/wormhole-foundation/wormchain/interchaintest/helpers" + "github.com/wormhole-foundation/wormhole/sdk/vaa" +) + +type GuardianSetQueryResponse struct { + Data GuardianSetInfoResponse `json:"data"` +} + +type VerifyVAAQueryResponse struct { + Data ParsedVAA `json:"data"` +} + +type GetStateQueryResponse struct { + Data GetStateResponse `json:"data"` +} + +type QueryAddressHexQueryResponse struct { + Data GetAddressHexResponse `json:"data"` +} + +// Custom response type to handle string numbers +type TxResponse struct { + Code uint32 `json:"code"` + Logs sdk.ABCIMessageLogs `json:"logs"` +} + +// SubmitGuardianSetUpdate submits a VAA to update the guardian set +func SubmitGuardianSetUpdate( + t *testing.T, + ctx context.Context, + wormchain *cosmos.CosmosChain, + contractAddr string, + newGuardians *guardians.ValSet, + newIndex uint32, + signingGuardians *guardians.ValSet, +) error { + // Create guardian set update payload + guardianKeys := make([]common.Address, len(newGuardians.Vals)) + for i, g := range newGuardians.Vals { + copy(guardianKeys[i][:], g.Addr) + } + + updateMsg := vaa.BodyGuardianSetUpdate{ + Keys: guardianKeys, + NewIndex: newIndex, + } + + payload, err := updateMsg.Serialize() + require.NoError(t, err) + + // Generate and sign the governance VAA using the signing guardian set + guardianSetIndex := helpers.QueryConsensusGuardianSetIndex(t, wormchain, ctx) + govVaa := helpers.GenerateGovernanceVaa(uint32(guardianSetIndex), signingGuardians, payload) + vaaBz, err := govVaa.Marshal() + require.NoError(t, err) + + encodedVaa := base64.StdEncoding.EncodeToString(vaaBz) + executeVAAPayload, err := json.Marshal(ExecuteMsg{ + SubmitVaa: &ExecuteMsg_SubmitVAA{ + Vaa: Binary(encodedVaa), + }, + }) + require.NoError(t, err) + + // Submit VAA + _, err = wormchain.ExecuteContract(ctx, "faucet", contractAddr, string(executeVAAPayload)) + if err != nil { + return err + } + + // Wait for transaction + return testutil.WaitForBlocks(ctx, 2, wormchain) +} + +// VerifyGuardianSet verifies the guardian set in the contract state +func VerifyGuardianSet( + t *testing.T, + ctx context.Context, + wormchain *cosmos.CosmosChain, + contractAddr string, + expectedGuardians *guardians.ValSet, + expectedIndex int, +) { + var guardianSetResp GuardianSetQueryResponse + err := wormchain.QueryContract(ctx, contractAddr, QueryMsg{ + GuardianSetInfo: &QueryMsg_GuardianSetInfo{}, + }, &guardianSetResp) + require.NoError(t, err) + + require.Equal(t, len(expectedGuardians.Vals), len(guardianSetResp.Data.Addresses), "unexpected number of guardians") + require.Equal(t, expectedIndex, guardianSetResp.Data.GuardianSetIndex, "unexpected guardian set index") + + for i, val := range expectedGuardians.Vals { + found := false + for _, guardian := range guardianSetResp.Data.Addresses { + decoded, err := base64.StdEncoding.DecodeString(string(guardian.Bytes)) + require.NoError(t, err) + guardianDecodedBytes := []byte(decoded) + if bytes.Equal(val.Addr, guardianDecodedBytes) { + found = true + break + } + } + require.True(t, found, "guardian %d not found in guardian set", i) + } +} + +// SubmitContractUpgrade submits a VAA to upgrade the contract code +func SubmitContractUpgrade( + t *testing.T, + ctx context.Context, + guardians *guardians.ValSet, + wormchain *cosmos.CosmosChain, + contractAddr string, + newCodeId string, +) error { + if err := helpers.MigrateContract(t, ctx, wormchain, "faucet", contractAddr, newCodeId, "{}", guardians); err != nil { + return err + } + + // Wait for transaction + return testutil.WaitForBlocks(ctx, 2, wormchain) +} + +func SubmitContractUpgradeWithVaa( + t *testing.T, + ctx context.Context, + guardians *guardians.ValSet, + guardianSetIndex uint64, + vaaChainId vaa.ChainID, + chain *cosmos.CosmosChain, + contractAddr string, + newCodeId string, + keyName string, +) error { + // convert newCodeId to Uint256 + var newCodeIdBz [32]byte + newCodeIdInt := new(big.Int) + newCodeIdInt.SetString(newCodeId, 10) + newCodeIdInt.FillBytes(newCodeIdBz[:]) + + // Create contract upgrade payload + updateMsg := vaa.BodyContractUpgrade{ + ChainID: vaaChainId, + NewContract: vaa.Address(newCodeIdBz), + } + + payload, err := updateMsg.Serialize() + require.NoError(t, err) + + // Generate and sign the governance VAA + govVaa := helpers.GenerateGovernanceVaa(uint32(guardianSetIndex), guardians, payload) + vaaBz, err := govVaa.Marshal() + require.NoError(t, err) + + encodedVaa := base64.StdEncoding.EncodeToString(vaaBz) + executeVAAPayload, err := json.Marshal(ExecuteMsg{ + SubmitVaa: &ExecuteMsg_SubmitVAA{ + Vaa: Binary(encodedVaa), + }, + }) + require.NoError(t, err) + + // Submit VAA + _, err = chain.ExecuteContract(ctx, keyName, contractAddr, string(executeVAAPayload)) + return err +} + +// SubmitFeeUpdate submits a VAA to update the fee amount +func SubmitFeeUpdate( + t *testing.T, + ctx context.Context, + guardians *guardians.ValSet, + wormchain *cosmos.CosmosChain, + contractAddr string, + amount string, + replay bool, +) (*TxResponse, error) { + // Get current guardian set index + guardianSetIndex := helpers.QueryConsensusGuardianSetIndex(t, wormchain, ctx) + + // Create a fixed 32-byte array for the fee amount + var amountBytes [32]byte + amountInt := new(big.Int) + amountInt.SetString(amount, 10) + amountInt.FillBytes(amountBytes[:]) + + // Create governance VAA payload + // [32 bytes] Core Module + // [1 byte] Action (3 for set fee) + // [2 bytes] ChainID (0 for universal) + // [32 bytes] Amount + buf := new(bytes.Buffer) + buf.Write(vaa.CoreModule) + vaa.MustWrite(buf, binary.BigEndian, vaa.ActionCoreSetMessageFee) + vaa.MustWrite(buf, binary.BigEndian, uint16(0)) // ChainID 0 for universal + buf.Write(amountBytes[:]) + + // Generate and sign governance VAA + govVaa := helpers.GenerateGovernanceVaa(uint32(guardianSetIndex), guardians, buf.Bytes()) + vaaBz, err := govVaa.Marshal() + require.NoError(t, err) + + // Rest of the function remains the same... + encodedVaa := base64.StdEncoding.EncodeToString(vaaBz) + executeVAAPayload, err := json.Marshal(ExecuteMsg{ + SubmitVaa: &ExecuteMsg_SubmitVAA{ + Vaa: Binary(encodedVaa), + }, + }) + require.NoError(t, err) + + // Submit VAA + txHash, err := wormchain.ExecuteContract(ctx, "faucet", contractAddr, string(executeVAAPayload)) + if err != nil { + return nil, err + } + + // Wait for transaction + err = testutil.WaitForBlocks(ctx, 2, wormchain) + require.NoError(t, err) + + // Replay the transaction + if replay { + _, err = wormchain.ExecuteContract(ctx, "faucet", contractAddr, string(executeVAAPayload)) + require.Error(t, err) + require.Contains(t, err.Error(), "VaaAlreadyExecuted") + } + + // Query transaction result + txResult, _, err := wormchain.Validators[0].ExecQuery(ctx, "tx", txHash) + require.NoError(t, err) + + // Parse response + var txResponse TxResponse + err = json.Unmarshal(txResult, &txResponse) + require.NoError(t, err) + + return &txResponse, nil +} + +// VerifyFee verifies the fee amount in the contract state +func VerifyFee( + t *testing.T, + ctx context.Context, + wormchain *cosmos.CosmosChain, + contractAddr string, + expectedAmount string, +) { + var stateResp GetStateQueryResponse + err := wormchain.QueryContract(ctx, contractAddr, QueryMsg{ + GetState: &QueryMsg_GetState{}, + }, &stateResp) + require.NoError(t, err) + require.Equal(t, "uworm", stateResp.Data.Fee.Denom) + require.Equal(t, Uint128(expectedAmount), stateResp.Data.Fee.Amount) +} + +// VerifyEventAttributes verifies the attributes in a wasm tx response +func VerifyEventAttributes(t *testing.T, txResponse *TxResponse, expectedAttributes map[string]string) { + require.Equal(t, uint32(0), txResponse.Code, "tx should succeed") + + // Find the wasm event + var wasmEvent *sdk.StringEvent + for _, log := range txResponse.Logs { + for _, event := range log.Events { + if event.Type == "wasm" { + wasmEvent = &event + break + } + } + } + require.NotNil(t, wasmEvent, "wasm event not found") + + // Helper to find attribute value + findAttribute := func(key string) string { + for _, attr := range wasmEvent.Attributes { + if attr.Key == key { + return attr.Value + } + } + return "" + } + + // Verify each expected attribute + for key, expectedValue := range expectedAttributes { + actualValue := findAttribute(key) + require.Equal(t, expectedValue, actualValue, + "unexpected value for attribute %s", key) + } +} + +// PostMessageWithFee posts a message to the contract with a fee +func PostMessageWithFee( + t *testing.T, + ctx context.Context, + wormchain *cosmos.CosmosChain, + contractAddr string, + message string, + fee int64, +) error { + messageBase64 := base64.StdEncoding.EncodeToString([]byte(message)) + executeMsg, err := json.Marshal(ExecuteMsg{ + PostMessage: &ExecuteMsg_PostMessage{ + Message: Binary(messageBase64), + Nonce: 1, + }, + }) + require.NoError(t, err) + + funds := sdk.Coins{sdk.NewInt64Coin("uworm", fee)} + _, err = wormchain.ExecuteContractWithAmount(ctx, "faucet", contractAddr, string(executeMsg), funds) + return err +} + +// SubmitTransferFee submits a VAA to transfer fees to an address +func SubmitTransferFee( + t *testing.T, + ctx context.Context, + guardians *guardians.ValSet, + wormchain *cosmos.CosmosChain, + contractAddr string, + addrBytes []byte, + amount string, + replay bool, +) (*TxResponse, error) { + // Created a fixed 32-byte array for the recipient address + var recipientBytes [32]byte + copy(recipientBytes[32-len(addrBytes):], addrBytes) + + // Create a fixed 32-byte array for the fee amount + var amountBytes [32]byte + amountInt := new(big.Int) + amountInt.SetString(amount, 10) + amountInt.FillBytes(amountBytes[:]) + + buf := new(bytes.Buffer) + buf.Write(vaa.CoreModule) + vaa.MustWrite(buf, binary.BigEndian, vaa.ActionCoreTransferFees) + vaa.MustWrite(buf, binary.BigEndian, uint16(0)) + buf.Write(recipientBytes[:]) + buf.Write(amountBytes[:]) + + guardianSetIndex := helpers.QueryConsensusGuardianSetIndex(t, wormchain, ctx) + govVaa := helpers.GenerateGovernanceVaa(uint32(guardianSetIndex), guardians, buf.Bytes()) + vaaBz, err := govVaa.Marshal() + require.NoError(t, err) + + encodedVaa := base64.StdEncoding.EncodeToString(vaaBz) + executeVAAPayload, err := json.Marshal(ExecuteMsg{ + SubmitVaa: &ExecuteMsg_SubmitVAA{ + Vaa: Binary(encodedVaa), + }, + }) + require.NoError(t, err) + + txHash, err := wormchain.ExecuteContract(ctx, "faucet", contractAddr, string(executeVAAPayload)) + if err != nil { + return nil, err + } + + err = testutil.WaitForBlocks(ctx, 2, wormchain) + require.NoError(t, err) + + if replay { + _, err = wormchain.ExecuteContract(ctx, "faucet", contractAddr, string(executeVAAPayload)) + require.Error(t, err) + require.Contains(t, err.Error(), "VaaAlreadyExecuted") + } + + txResult, _, err := wormchain.Validators[0].ExecQuery(ctx, "tx", txHash) + require.NoError(t, err) + + var txResponse TxResponse + err = json.Unmarshal(txResult, &txResponse) + require.NoError(t, err) + + return &txResponse, nil +} + +// GetUwormBalance returns the balance of uworm tokens for an address +func GetUwormBalance(t *testing.T, ctx context.Context, wormchain *cosmos.CosmosChain, addr string) (int64, error) { + coins, err := wormchain.GetBalance(ctx, addr, "uworm") + if err != nil { + return 0, err + } + + return coins, nil +} diff --git a/wormchain/interchaintest/helpers/migrate_contract.go b/wormchain/interchaintest/helpers/migrate_contract.go index b488f462ee..1f57c6a964 100644 --- a/wormchain/interchaintest/helpers/migrate_contract.go +++ b/wormchain/interchaintest/helpers/migrate_contract.go @@ -35,7 +35,7 @@ func MigrateContract( codeId string, message string, guardians *guardians.ValSet, -) { +) error { node := chain.GetFullNode() @@ -48,5 +48,5 @@ func MigrateContract( vHex := hex.EncodeToString(vBz) _, err = node.ExecTx(ctx, keyName, "wormhole", "migrate", contractAddr, codeId, message, vHex, "--gas", "auto") - require.NoError(t, err) + return err } diff --git a/wormchain/interchaintest/helpers/vaa.go b/wormchain/interchaintest/helpers/vaa.go index 093b84e920..d2dfb84ee7 100644 --- a/wormchain/interchaintest/helpers/vaa.go +++ b/wormchain/interchaintest/helpers/vaa.go @@ -1,8 +1,11 @@ package helpers import ( + "encoding/hex" + "testing" "time" + "github.com/stretchr/testify/require" "github.com/wormhole-foundation/wormhole/sdk/vaa" "github.com/wormhole-foundation/wormchain/interchaintest/guardians" @@ -44,3 +47,23 @@ func GenerateGovernanceVaa(index uint32, latestSequence = latestSequence + 1 return signVaa(*v, signers) } + +func GenerateEmptyVAA( + t *testing.T, + guardians *guardians.ValSet, + moduleStr string, + action vaa.GovernanceAction, + chainID vaa.ChainID, +) string { + + payloadBz, err := vaa.EmptyPayloadVaa(moduleStr, action, chainID) + require.NoError(t, err) + v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz) + + v = signVaa(v, guardians) + vBz, err := v.Marshal() + require.NoError(t, err) + vHex := hex.EncodeToString(vBz) + + return vHex +} diff --git a/wormchain/interchaintest/helpers/wormhole_core.go b/wormchain/interchaintest/helpers/wormhole_core.go index 9615d3ab04..d7b3cd7b3e 100644 --- a/wormchain/interchaintest/helpers/wormhole_core.go +++ b/wormchain/interchaintest/helpers/wormhole_core.go @@ -1,9 +1,11 @@ package helpers import ( + "context" "encoding/json" "testing" + "github.com/strangelove-ventures/interchaintest/v4/chain/cosmos" "github.com/strangelove-ventures/interchaintest/v4/ibc" "github.com/stretchr/testify/require" "github.com/wormhole-foundation/wormchain/interchaintest/guardians" @@ -28,7 +30,7 @@ type GuardianAddress struct { Bytes []byte `json:"bytes"` } -func CoreContractInstantiateMsg(t *testing.T, cfg ibc.ChainConfig, guardians *guardians.ValSet) string { +func CoreContractInstantiateMsg(t *testing.T, cfg ibc.ChainConfig, vaaChainId vaa.ChainID, guardians *guardians.ValSet) string { guardianAddresses := []GuardianAddress{} for i := 0; i < guardians.Total; i++ { guardianAddresses = append(guardianAddresses, GuardianAddress{ @@ -44,7 +46,7 @@ func CoreContractInstantiateMsg(t *testing.T, cfg ibc.ChainConfig, guardians *gu ExpirationTime: 0, }, GuardianSetExpirity: 86400, - ChainId: uint16(vaa.ChainIDWormchain), + ChainId: uint16(vaaChainId), FeeDenom: cfg.Denom, } msgBz, err := json.Marshal(msg) @@ -52,3 +54,23 @@ func CoreContractInstantiateMsg(t *testing.T, cfg ibc.ChainConfig, guardians *gu return string(msgBz) } + +// QueryConsensusGuardianSetIndex queries the index of the consensus guardian set +func QueryConsensusGuardianSetIndex(t *testing.T, wormchain *cosmos.CosmosChain, ctx context.Context) uint64 { + stdout, _, err := wormchain.GetFullNode().ExecQuery(ctx, + "wormhole", "show-consensus-guardian-set-index", + ) + require.NoError(t, err) + + res := new(ConsensusGuardianSetIndexResponse) + err = json.Unmarshal(stdout, res) + require.NoError(t, err) + + return res.ConsensusGuardianSetIndex.Index +} + +type ConsensusGuardianSetIndexResponse struct { + ConsensusGuardianSetIndex struct { + Index uint64 `json:"index"` + } `json:"ConsensusGuardianSetIndex"` +} diff --git a/wormchain/interchaintest/ibc_receiver_test.go b/wormchain/interchaintest/ibc_receiver_test.go index 38ec704d49..cf4380c80b 100644 --- a/wormchain/interchaintest/ibc_receiver_test.go +++ b/wormchain/interchaintest/ibc_receiver_test.go @@ -34,7 +34,7 @@ func createChains(t *testing.T, wormchainVersion string, guardians guardians.Val wormchainConfig.Images[0].Version = wormchainVersion // Create chain factory with wormchain - wormchainConfig.ModifyGenesis = ModifyGenesis(votingPeriod, maxDepositPeriod, guardians) + wormchainConfig.ModifyGenesis = ModifyGenesis(votingPeriod, maxDepositPeriod, guardians, false) cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ { @@ -338,7 +338,7 @@ func instantiateWormholeIbcContracts(t *testing.T, ctx context.Context, guardians *guardians.ValSet) (helpers.ContractInfoResponse, helpers.ContractInfoResponse) { // Instantiate the Wormchain core contract - coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, guardians) + coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, guardians) wormchainCoreContractInfo := helpers.StoreAndInstantiateWormholeContract(t, ctx, wormchain, "faucet", "./contracts/wormhole_core.wasm", "wormhole_core", coreInstantiateMsg, guardians) // Store wormhole-ibc-receiver contract on wormchain @@ -354,7 +354,7 @@ func instantiateWormholeIbcContracts(t *testing.T, ctx context.Context, require.NotEmpty(t, wormchainReceiverContractInfo.ContractInfo.IbcPortID, "wormchain (wormchain-ibc-receiver) contract port id is nil") // Store and instantiate wormhole-ibc contract on osmosis - senderInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, guardians) + senderInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, guardians) senderCodeId, err := remoteChain.StoreContract(ctx, "faucet", "./contracts/wormhole_ibc.wasm") require.NoError(t, err) senderContractAddr, err := remoteChain.InstantiateContract(ctx, "faucet", senderCodeId, senderInstantiateMsg, true) diff --git a/wormchain/interchaintest/malformed_payload_test.go b/wormchain/interchaintest/malformed_payload_test.go index 871c4c312a..dfed0fc998 100644 --- a/wormchain/interchaintest/malformed_payload_test.go +++ b/wormchain/interchaintest/malformed_payload_test.go @@ -58,7 +58,7 @@ func TestMalformedPayload(t *testing.T) { fmt.Println("Core contract code id: ", coreContractCodeId) // Instantiate wormhole core contract - coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, guardians) + coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, guardians) coreContractAddr := helpers.InstantiateContract(t, ctx, wormchain, "faucet", coreContractCodeId, "wormhole_core", coreInstantiateMsg, guardians) fmt.Println("Core contract address: ", coreContractAddr) diff --git a/wormchain/interchaintest/setup.go b/wormchain/interchaintest/setup.go index 6cc5dbc5ed..6b7a6a3124 100644 --- a/wormchain/interchaintest/setup.go +++ b/wormchain/interchaintest/setup.go @@ -70,7 +70,7 @@ func CreateChains(t *testing.T, wormchainVersion string, guardians guardians.Val wormchainConfig.Images[0].Version = wormchainVersion // Create chain factory with wormchain - wormchainConfig.ModifyGenesis = ModifyGenesis(votingPeriod, maxDepositPeriod, guardians) + wormchainConfig.ModifyGenesis = ModifyGenesis(votingPeriod, maxDepositPeriod, guardians, false) cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ { @@ -167,7 +167,7 @@ func BuildInterchain(t *testing.T, chains []ibc.Chain) (context.Context, ibc.Rel // * Set Guardian Set List using new val set // * Set Guardian Validator List using new val set // * Allow list the faucet address -func ModifyGenesis(votingPeriod string, maxDepositPeriod string, guardians guardians.ValSet) func(ibc.ChainConfig, []byte) ([]byte, error) { +func ModifyGenesis(votingPeriod string, maxDepositPeriod string, guardians guardians.ValSet, skipRelayers bool) func(ibc.ChainConfig, []byte) ([]byte, error) { return func(chainConfig ibc.ChainConfig, genbz []byte) ([]byte, error) { numVals := len(guardians.Vals) g := make(map[string]interface{}) @@ -202,10 +202,13 @@ func ModifyGenesis(votingPeriod string, maxDepositPeriod string, guardians guard return nil, fmt.Errorf("failed to get faucet address: %w", err) } - // Get relayer address - relayerAddress, err := dyno.Get(g, "app_state", "auth", "accounts", numVals+1, "address") - if err != nil { - return nil, fmt.Errorf("failed to get relayer address: %w", err) + var relayerAddress interface{} + if !skipRelayers { + // Get relayer address + relayerAddress, err = dyno.Get(g, "app_state", "auth", "accounts", numVals+1, "address") + if err != nil { + return nil, fmt.Errorf("failed to get relayer address: %w", err) + } } // Set guardian set list and validators @@ -236,11 +239,15 @@ func ModifyGenesis(votingPeriod string, maxDepositPeriod string, guardians guard AllowedAddress: faucetAddress.(string), Name: "Faucet", }) - allowedAddresses = append(allowedAddresses, ValidatorAllowedAddress{ - ValidatorAddress: sdk.MustBech32ifyAddressBytes(chainConfig.Bech32Prefix, validators[0]), - AllowedAddress: relayerAddress.(string), - Name: "Relayer", - }) + + if !skipRelayers { + allowedAddresses = append(allowedAddresses, ValidatorAllowedAddress{ + ValidatorAddress: sdk.MustBech32ifyAddressBytes(chainConfig.Bech32Prefix, validators[0]), + AllowedAddress: relayerAddress.(string), + Name: "Relayer", + }) + } + if err := dyno.Set(g, allowedAddresses, "app_state", "wormhole", "allowedAddresses"); err != nil { return nil, fmt.Errorf("failed to set guardian validator list: %w", err) } diff --git a/wormchain/interchaintest/upgrade_test.go b/wormchain/interchaintest/upgrade_test.go index 2ce7440f84..5ad1d3af35 100644 --- a/wormchain/interchaintest/upgrade_test.go +++ b/wormchain/interchaintest/upgrade_test.go @@ -186,7 +186,7 @@ func TestUpgrade(t *testing.T) { fmt.Println("Core contract code id: ", coreContractCodeId) // Instantiate wormhole core contract - coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, guardians) + coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, guardians) coreContractAddr := helpers.InstantiateContract(t, ctx, wormchain, "faucet", coreContractCodeId, "wormhole_core", coreInstantiateMsg, guardians) fmt.Println("Core contract address: ", coreContractAddr) diff --git a/wormchain/interchaintest/wormchain_test.go b/wormchain/interchaintest/wormchain_test.go index cec5d30cac..587aec0487 100644 --- a/wormchain/interchaintest/wormchain_test.go +++ b/wormchain/interchaintest/wormchain_test.go @@ -104,7 +104,7 @@ func TestWormchain(t *testing.T) { fmt.Println("Core contract code id: ", coreContractCodeId) // Instantiate wormhole core contract - coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, guardians) + coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, guardians) coreContractAddr := helpers.InstantiateContract(t, ctx, wormchain, "faucet", coreContractCodeId, "wormhole_core", coreInstantiateMsg, guardians) fmt.Println("Core contract address: ", coreContractAddr)