Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add shutdown contract interchain tests #4230

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/wormchain-icts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
- "ictest-wormchain"
- "ictest-ibc-receiver"
- "ictest-cw-wormhole"
- "ictest-cw-shutdown-contracts"
fail-fast: false

steps:
Expand Down
5 changes: 4 additions & 1 deletion wormchain/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,7 @@ ictest-ibc-receiver: rm-testcache
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
ictest-cw-shutdown-contracts: rm-testcache
cd interchaintest && go test -race -v -run ^TestShutdown ./...

.PHONY: ictest-cancel-upgrade ictest-malformed-payload ictest-upgrade-failure ictest-upgrade ictest-wormchain ictest-ibc-receiver ictest-cw-wormhole ictest-cw-shutdown-contracts
Binary file not shown.
Binary file not shown.
254 changes: 254 additions & 0 deletions wormchain/interchaintest/shutdown_contracts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
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")
}
Loading