package ictest import ( "encoding/base64" "encoding/json" "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/strangelove-ventures/interchaintest/v4" "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" "github.com/wormhole-foundation/wormchain/interchaintest/helpers" "github.com/wormhole-foundation/wormchain/interchaintest/helpers/cw_wormhole" "github.com/wormhole-foundation/wormhole/sdk/vaa" ) // TestShutdownCoreContract tests the endpoints of a contract in its "shutdown" state func TestShutdownCoreContract(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) // Chains wormchain := chain.(*cosmos.CosmosChain) // Users users := interchaintest.GetAndFundTestUsers(t, ctx, t.Name(), 1, wormchain) user := users[0] // Deploy contract to wormhole coreInstantiateMsg := helpers.CoreContractInstantiateMsg(t, wormchainConfig, vaa.ChainIDWormchain, oldGuardians) contractInfo := helpers.StoreAndInstantiateWormholeContract(t, ctx, wormchain, "faucet", "./contracts/wormhole_core.wasm", "wormhole_core", coreInstantiateMsg, oldGuardians) contractAddr := contractInfo.Address // Store a new version of the contract to upgrade to wormNewCodeId := helpers.StoreContract(t, ctx, wormchain, "faucet", "./contracts/shutdown_wormhole_core.wasm", oldGuardians) // Submit contract upgrade err := cw_wormhole.SubmitContractUpgrade(t, ctx, oldGuardians, wormchain, contractAddr, wormNewCodeId) require.NoError(t, err) // ----------------------------------- // Try to post a message - should fail 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 _, err = wormchain.ExecuteContract(ctx, "faucet", contractAddr, string(executeMsg)) require.Error(t, err) // ----------------------------------- // Try to set fees - should fail _, err = cw_wormhole.SubmitFeeUpdate(t, ctx, oldGuardians, wormchain, contractAddr, "1000000", false) require.Error(t, err) // ----------------------------------- // Try to transfer fees - should fail _, err = cw_wormhole.SubmitTransferFee(t, ctx, oldGuardians, wormchain, contractAddr, []byte(user.Address), "10000000000", false) require.Error(t, err) // ----------------------------------- // Try to submit a guardian set update - should pass initialIndex := int(helpers.QueryConsensusGuardianSetIndex(t, wormchain, ctx)) signingGuardians := guardians.CreateValSet(t, numVals) 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) // ----------------------------------- // Migrate contract back to original contract id err = cw_wormhole.SubmitContractUpgrade(t, ctx, signingGuardians, wormchain, contractAddr, contractInfo.ContractInfo.CodeID) require.NoError(t, err) } // TestShutdownTokenBridge tests the endpoints of a contract in its "shutdown" state // The shutdown contract only allows the following: Upgrading the Contract & Registering a new chain. func TestShutdownTokenBridge(t *testing.T) { // Setup chain and contract numVals := 1 guardians := guardians.CreateValSet(t, numVals) chains := CreateChains(t, "v2.24.2", *guardians) ctx, r, eRep, _ := BuildInterchain(t, chains) // Chains wormchain := chains[0].(*cosmos.CosmosChain) gaia := chains[1].(*cosmos.CosmosChain) osmosis := chains[2].(*cosmos.CosmosChain) wormchainFaucetAddrBz, err := wormchain.GetAddress(ctx, "faucet") require.NoError(t, err) wormchainFaucetAddr := sdk.MustBech32ifyAddressBytes(wormchain.Config().Bech32Prefix, wormchainFaucetAddrBz) fmt.Println("Wormchain faucet addr: ", wormchainFaucetAddr) osmoToWormChannel, err := ibc.GetTransferChannel(ctx, r, eRep, osmosis.Config().ChainID, wormchain.Config().ChainID) require.NoError(t, err) wormToOsmoChannel := osmoToWormChannel.Counterparty gaiaToWormChannel, err := ibc.GetTransferChannel(ctx, r, eRep, gaia.Config().ChainID, wormchain.Config().ChainID) require.NoError(t, err) wormToGaiaChannel := gaiaToWormChannel.Counterparty users := interchaintest.GetAndFundTestUsers(t, ctx, "default", int64(10_000_000_000), gaia, osmosis, osmosis) gaiaUser := users[0] osmoUser1 := users[1] osmoUser2 := users[2] // Store wormhole core contract coreContractCodeId := helpers.StoreContract(t, ctx, wormchain, "faucet", "./contracts/wormhole_core.wasm", guardians) fmt.Println("Core contract code id: ", coreContractCodeId) // Instantiate wormhole core contract 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) // Store cw20_wrapped_2 contract wrappedAssetCodeId := helpers.StoreContract(t, ctx, wormchain, "faucet", "./contracts/cw20_wrapped_2.wasm", guardians) fmt.Println("CW20 wrapped_2 code id: ", wrappedAssetCodeId) // Store token bridge contract tbContractCodeId := helpers.StoreContract(t, ctx, wormchain, "faucet", "./contracts/token_bridge.wasm", guardians) fmt.Println("Token bridge contract code id: ", tbContractCodeId) // Instantiate token bridge contract tbInstantiateMsg := helpers.TbContractInstantiateMsg(t, wormchainConfig, coreContractAddr, wrappedAssetCodeId) tbContractAddr := helpers.InstantiateContract(t, ctx, wormchain, "faucet", tbContractCodeId, "token_bridge", tbInstantiateMsg, guardians) fmt.Println("Token bridge contract address: ", tbContractAddr) helpers.SubmitAllowlistInstantiateContract(t, ctx, wormchain, "faucet", wormchain.Config(), tbContractAddr, wrappedAssetCodeId, guardians) // Store a new version of the token bridge to upgrade to tbNewCodeId := helpers.StoreContract(t, ctx, wormchain, "faucet", "./contracts/shutdown_token_bridge.wasm", guardians) // Submit contract upgrade err = cw_wormhole.SubmitContractUpgrade(t, ctx, guardians, wormchain, tbContractAddr, tbNewCodeId) require.NoError(t, err) // ----------------------------------- // Registering a new chain - should pass tbRegisterChainMsg := helpers.TbRegisterChainMsg(t, ExternalChainId, ExternalChainEmitterAddr, guardians) _, err = wormchain.ExecuteContract(ctx, "faucet", tbContractAddr, string(tbRegisterChainMsg)) require.NoError(t, err) // ----------------------------------- // Registering a new token - should fail tbRegisterForeignAssetMsg := helpers.TbRegisterForeignAsset(t, Asset1ContractAddr, Asset1ChainID, ExternalChainEmitterAddr, Asset1Decimals, Asset1Symbol, Asset1Name, guardians) _, err = wormchain.ExecuteContract(ctx, "faucet", tbContractAddr, string(tbRegisterForeignAssetMsg)) require.Error(t, err) require.ErrorContains(t, err, "InvalidVAAAction") // ----------------------------------- // Upgrade contract back to original contract id - should pass err = cw_wormhole.SubmitContractUpgrade(t, ctx, guardians, wormchain, tbContractAddr, tbContractCodeId) require.NoError(t, err) // ----------------------------------- // Setup chains in "full" mode in preparation for transfer vaas // Now register a new token - should pass on original contract tbRegisterForeignAssetMsg = helpers.TbRegisterForeignAsset(t, Asset1ContractAddr, Asset1ChainID, ExternalChainEmitterAddr, Asset1Decimals, Asset1Symbol, Asset1Name, guardians) _, err = wormchain.ExecuteContract(ctx, "faucet", tbContractAddr, string(tbRegisterForeignAssetMsg)) require.NoError(t, err) // Store ibc translator contract ibcTranslatorCodeId := helpers.StoreContract(t, ctx, wormchain, "faucet", "./contracts/ibc_translator.wasm", guardians) fmt.Println("Ibc translator code id: ", ibcTranslatorCodeId) // Instantiate ibc translator contract ibcTranslatorInstantiateMsg := helpers.IbcTranslatorContractInstantiateMsg(t, tbContractAddr) ibcTranslatorContractAddr := helpers.InstantiateContract(t, ctx, wormchain, "faucet", ibcTranslatorCodeId, "ibc_translator", ibcTranslatorInstantiateMsg, guardians) fmt.Println("Ibc translator contract address: ", ibcTranslatorContractAddr) helpers.SetMiddlewareContract(t, ctx, wormchain, "faucet", wormchain.Config(), ibcTranslatorContractAddr, guardians) // Allowlist worm/osmo chain id / channel wormOsmoAllowlistMsg := helpers.SubmitUpdateChainToChannelMapMsg(t, OsmoChainID, wormToOsmoChannel.ChannelID, guardians) _, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, wormOsmoAllowlistMsg) require.NoError(t, err) // Allowlist worm/gaia chain id / channel wormGaiaAllowlistMsg := helpers.SubmitUpdateChainToChannelMapMsg(t, GaiaChainID, wormToGaiaChannel.ChannelID, guardians) _, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, wormGaiaAllowlistMsg) require.NoError(t, err) ibcHooksCodeId, err := osmosis.StoreContract(ctx, osmoUser1.KeyName, "./contracts/ibc_hooks.wasm") require.NoError(t, err) fmt.Println("IBC hooks code id: ", ibcHooksCodeId) ibcHooksContractAddr, err := osmosis.InstantiateContract(ctx, osmoUser1.KeyName, ibcHooksCodeId, "{}", true) require.NoError(t, err) fmt.Println("IBC hooks contract addr: ", ibcHooksContractAddr) // ----------------------------------- // Upgrade contract to shutdown contract err = cw_wormhole.SubmitContractUpgrade(t, ctx, guardians, wormchain, tbContractAddr, tbNewCodeId) require.NoError(t, err) // ----------------------------------- // Send transfer vaas - all should fail // Create and process a simple ibc payload3: Transfers 10.000_018 of asset1 from external chain through wormchain to gaia user simplePayload := helpers.CreateGatewayIbcTokenBridgePayloadTransfer(t, GaiaChainID, gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), 0, 1) externalSender := []byte{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8} payload3 := helpers.CreatePayload3(wormchain.Config(), uint64(AmountExternalToGaiaUser1), Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, simplePayload) completeTransferAndConvertMsg := helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians) _, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg) require.Error(t, err) require.ErrorContains(t, err, "Invalid during shutdown mode") // Create and process a simple ibc payload3: Transfers 1.000_001 of asset1 from external chain through wormchain to osmo user1 simplePayload = helpers.CreateGatewayIbcTokenBridgePayloadTransfer(t, OsmoChainID, osmoUser1.Bech32Address(osmosis.Config().Bech32Prefix), 0, 1) payload3 = helpers.CreatePayload3(wormchain.Config(), uint64(AmountExternalToOsmoUser1), Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, simplePayload) completeTransferAndConvertMsg = helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians) _, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg) require.Error(t, err) require.ErrorContains(t, err, "Invalid during shutdown mode") // Create and process a contract controlled ibc payload3 // Transfers 1.000_002 of asset1 from external chain through wormchain to ibc hooks contract addr // IBC hooks is used to route the contract controlled payload to a test contract which forwards tokens to osmo user2 ibcHooksPayload := helpers.CreateIbcHooksMsg(t, ibcHooksContractAddr, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix)) contractControlledPayload := helpers.CreateGatewayIbcTokenBridgePayloadTransferWithPayload(t, OsmoChainID, ibcHooksContractAddr, ibcHooksPayload, 1) payload3 = helpers.CreatePayload3(wormchain.Config(), uint64(AmountExternalToOsmoUser2), Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, contractControlledPayload) completeTransferAndConvertMsg = helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians) _, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg) require.Error(t, err) require.ErrorContains(t, err, "Invalid during shutdown mode") }