diff --git a/sdk/vaa/payloads.go b/sdk/vaa/payloads.go index eab83a6d5b..e3c4c277ee 100644 --- a/sdk/vaa/payloads.go +++ b/sdk/vaa/payloads.go @@ -52,9 +52,10 @@ var ( ActionCoreRecoverChainId GovernanceAction = 5 // Wormchain cosmwasm governance actions - ActionStoreCode GovernanceAction = 1 - ActionInstantiateContract GovernanceAction = 2 - ActionMigrateContract GovernanceAction = 3 + ActionStoreCode GovernanceAction = 1 + ActionInstantiateContract GovernanceAction = 2 + ActionMigrateContract GovernanceAction = 3 + ActionAllowlistInstantiateContract GovernanceAction = 4 // Accountant goverance actions ActionModifyBalance GovernanceAction = 1 @@ -131,6 +132,12 @@ type ( MigrationParamsHash [32]byte } + // BodyWormchainAllowlistInstantiateContract is a governance message to allowlist a specific contract address to instantiate a specific wasm code id. + BodyWormchainAllowlistInstantiateContract struct { + ContractAddr [32]byte + CodeId uint64 + } + // BodyCircleIntegrationUpdateWormholeFinality is a governance message to update the wormhole finality for Circle Integration. BodyCircleIntegrationUpdateWormholeFinality struct { TargetChainID ChainID @@ -250,6 +257,27 @@ func (r BodyWormchainMigrateContract) Serialize() []byte { return serializeBridgeGovernanceVaa(WasmdModuleStr, ActionMigrateContract, ChainIDWormchain, r.MigrationParamsHash[:]) } +func (r BodyWormchainAllowlistInstantiateContract) Serialize() []byte { + payload := &bytes.Buffer{} + payload.Write(r.ContractAddr[:]) + MustWrite(payload, binary.BigEndian, r.CodeId) + return serializeBridgeGovernanceVaa(WasmdModuleStr, ActionAllowlistInstantiateContract, ChainIDWormchain, payload.Bytes()) +} + +func (r *BodyWormchainAllowlistInstantiateContract) Deserialize(bz []byte) { + if len(bz) != 40 { + panic("incorrect payload length") + } + + var contractAddr [32]byte + copy(contractAddr[:], bz[0:32]) + + codeId := binary.BigEndian.Uint64(bz[32:40]) + + r.ContractAddr = contractAddr + r.CodeId = codeId +} + func (r BodyCircleIntegrationUpdateWormholeFinality) Serialize() []byte { return serializeBridgeGovernanceVaa(CircleIntegrationModuleStr, CircleIntegrationActionUpdateWormholeFinality, r.TargetChainID, []byte{r.Finality}) } diff --git a/wormchain/interchaintest/contracts/ibc_translator.wasm b/wormchain/interchaintest/contracts/ibc_translator.wasm index f897db198f..6446cac679 100644 Binary files a/wormchain/interchaintest/contracts/ibc_translator.wasm and b/wormchain/interchaintest/contracts/ibc_translator.wasm differ diff --git a/wormchain/interchaintest/cosmos_to_cosmos_test.go b/wormchain/interchaintest/cosmos_to_cosmos_test.go new file mode 100644 index 0000000000..a5fb91eb27 --- /dev/null +++ b/wormchain/interchaintest/cosmos_to_cosmos_test.go @@ -0,0 +1,217 @@ +package ictest + +import ( + "fmt" + "testing" + + "github.com/btcsuite/btcd/btcutil/base58" + "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" + "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" + + sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" +) + +// TestWormchain runs through a simple test case for each deliverable +func TestCosmosToCosmos(t *testing.T) { + t.Parallel() + + // Base setup + guardians := guardians.CreateValSet(t, numVals) + chains := CreateChains(t, *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) + wormToOsmoChannel := osmoToWormChannel.Counterparty + gaiaToWormChannel, err := ibc.GetTransferChannel(ctx, r, eRep, gaia.Config().ChainID, wormchain.Config().ChainID) + wormToGaiaChannel := gaiaToWormChannel.Counterparty + + users := interchaintest.GetAndFundTestUsers(t, ctx, "default", int64(10_000_000_000), wormchain, gaia, osmosis, osmosis) + _ = users[0] // Wormchain user + gaiaUser := users[1] + osmoUser1 := users[2] + osmoUser2 := users[3] + + 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) + + // 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, 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) + + // Register a new external chain + tbRegisterChainMsg := helpers.TbRegisterChainMsg(t, ExternalChainId, ExternalChainEmitterAddr, guardians) + _, err = wormchain.ExecuteContract(ctx, "faucet", tbContractAddr, string(tbRegisterChainMsg)) + require.NoError(t, err) + + // Register a new foreign asset (Asset1) originating on externalChain + 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) + + // Allowlist worm/osmo chain id / channel + wormOsmoAllowlistMsg := helpers.SubmitUpdateChainToChannelMapMsg(t, OsmoChainID, wormToOsmoChannel.ChannelID, guardians) + _, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, wormOsmoAllowlistMsg) + + // Allowlist worm/gaia chain id / channel + wormGaiaAllowlistMsg := helpers.SubmitUpdateChainToChannelMapMsg(t, GaiaChainID, wormToGaiaChannel.ChannelID, guardians) + _, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, wormGaiaAllowlistMsg) + + // This query was added in a newer version of ibc-translator, so a migration should have taken place for this to succeed + var queryChannelRsp helpers.IbcTranslatorQueryRspMsg + queryChannelMsg := helpers.IbcTranslatorQueryMsg{IbcChannel: helpers.QueryIbcChannel{ChainID: OsmoChainID}} + wormchain.QueryContract(ctx, ibcTranslatorContractAddr, queryChannelMsg, &queryChannelRsp) + fmt.Println("Osmo channel: ", queryChannelRsp.Data.Channel) + + queryChannelMsg = helpers.IbcTranslatorQueryMsg{IbcChannel: helpers.QueryIbcChannel{ChainID: GaiaChainID}} + wormchain.QueryContract(ctx, ibcTranslatorContractAddr, queryChannelMsg, &queryChannelRsp) + fmt.Println("Gaia channel: ", queryChannelRsp.Data.Channel) + + // Create and process a simple ibc payload3: Transfers 1.231245 of asset1 from external chain through wormchain to gaia user + // Add relayer fee + simplePayload := helpers.CreateGatewayIbcTokenBridgePayloadSimple(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(), 30123, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, simplePayload) + completeTransferAndConvertMsg := helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians) + _, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg) + + var tbQueryRsp helpers.TbQueryRsp + tbQueryReq := helpers.CreateCW20Query(t, Asset1ChainID, Asset1ContractAddr) + wormchain.QueryContract(ctx, tbContractAddr, tbQueryReq, &tbQueryRsp) + cw20Address := tbQueryRsp.Data.Address + fmt.Println("Asset1 cw20 addr: ", cw20Address) + + // Transfer some asset1 tokens back to faucet + cw20AddressBz := helpers.MustAccAddressFromBech32(cw20Address, wormchain.Config().Bech32Prefix) + subdenom := base58.Encode(cw20AddressBz) + tokenFactoryDenom := fmt.Sprint("factory/", ibcTranslatorContractAddr, "/", subdenom) + gaiaAsset1Denom := transfertypes.GetPrefixedDenom("transfer", gaiaToWormChannel.ChannelID, tokenFactoryDenom) + gaiaIbcAsset1Denom := transfertypes.ParseDenomTrace(gaiaAsset1Denom).IBCDenom() + + + // ************** PFM + Simple payload **************** + simplePfmMsg := helpers.CreatePfmSimpleMsg(t, osmoUser1.Bech32Address(osmosis.Config().Bech32Prefix), wormToOsmoChannel.ChannelID) + transfer := ibc.WalletAmount{ + Address: wormchainFaucetAddr, + Denom: gaiaIbcAsset1Denom, + Amount: 10012, + } + gaiaHeight, err := gaia.Height(ctx) + require.NoError(t, err) + gaiaIbcTx, err := gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{Memo: simplePfmMsg}) + require.NoError(t, err) + + // wait for transfer to ack + _, err = testutil.PollForAck(ctx, gaia, gaiaHeight, gaiaHeight+30, gaiaIbcTx.Packet) + require.NoError(t, err) + err = testutil.WaitForBlocks(ctx, 1, wormchain, gaia) + require.NoError(t, err) + + // ********* PFM + Contract controlled payload ********** + ccPfmMsg := helpers.CreatePfmContractControlledMsg(t, ibcHooksContractAddr, wormToOsmoChannel.ChannelID, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix)) + transfer = ibc.WalletAmount{ + Address: ibcTranslatorContractAddr, + Denom: gaiaIbcAsset1Denom, + Amount: 10013, + } + gaiaHeight, err = gaia.Height(ctx) + require.NoError(t, err) + gaiaIbcTx, err = gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{Memo: ccPfmMsg}) + require.NoError(t, err) + + // wait for transfer to ack + _, err = testutil.PollForAck(ctx, gaia, gaiaHeight, gaiaHeight+30, gaiaIbcTx.Packet) + require.NoError(t, err) + err = testutil.WaitForBlocks(ctx, 1, wormchain, gaia) + require.NoError(t, err) + + // wait for transfer + err = testutil.WaitForBlocks(ctx, 3, wormchain) + require.NoError(t, err) + + coins, err := wormchain.AllBalances(ctx, ibcTranslatorContractAddr) + require.NoError(t, err) + fmt.Println("Ibc Translator contract coins: ", coins) + + coins, err = wormchain.AllBalances(ctx, wormchainFaucetAddr) + require.NoError(t, err) + fmt.Println("Wormchain faucet coins: ", coins) + + coins, err = gaia.AllBalances(ctx, gaiaUser.Bech32Address(gaia.Config().Bech32Prefix)) + require.NoError(t, err) + fmt.Println("Gaia user coins: ", coins) + + coins, err = osmosis.AllBalances(ctx, osmoUser1.Bech32Address(osmosis.Config().Bech32Prefix)) + require.NoError(t, err) + fmt.Println("Osmo user1 coins: ", coins) + + coins, err = osmosis.AllBalances(ctx, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix)) + require.NoError(t, err) + fmt.Println("Osmo user2 coins: ", coins) + + coins, err = osmosis.AllBalances(ctx, ibcHooksContractAddr) + require.NoError(t, err) + fmt.Println("Ibc Hooks contract coins: ", coins) + + // IBC hooks required: + // Send a bridged token from foreign cosmos chain, over ibc to wormchain and out of wormchain (stretch, nice-to-have) + + // PFM required: + // Send a bridged token from a foreign cosmos chain, through wormchain, to a second foreign cosmos chain (deposited to addr) + // Send a bridged token from a foreign cosmos chain, through wormchain, to a second foreign cosmos chain's contract + + // Out of scope: + // Send a cosmos chain native asset to wormchain for external chain consumption + + err = testutil.WaitForBlocks(ctx, 2, wormchain) + require.NoError(t, err) +} diff --git a/wormchain/interchaintest/cosmos_to_external_test.go b/wormchain/interchaintest/cosmos_to_external_test.go index 10e8ba5a41..ec39f09b38 100644 --- a/wormchain/interchaintest/cosmos_to_external_test.go +++ b/wormchain/interchaintest/cosmos_to_external_test.go @@ -1,7 +1,6 @@ package ictest import ( - "encoding/hex" "fmt" "testing" @@ -95,7 +94,7 @@ func TestCosmosToExternal(t *testing.T) { fmt.Println("ibc_translator code id: ", ibcTranslatorCodeId) // Instantiate ibc translator contract - ibcTranslatorInstantiateMsg := helpers.IbcTranslatorContractInstantiateMsg(t, tbContractAddr, coreContractAddr) + ibcTranslatorInstantiateMsg := helpers.IbcTranslatorContractInstantiateMsg(t, tbContractAddr) ibcTranslatorContractAddr := helpers.InstantiateContract(t, ctx, wormchain, "faucet", ibcTranslatorCodeId, "ibc_translator", ibcTranslatorInstantiateMsg, guardians) fmt.Println("Ibc translator contract address: ", ibcTranslatorContractAddr) @@ -121,7 +120,7 @@ func TestCosmosToExternal(t *testing.T) { // Add relayer fee simplePayload := helpers.CreateGatewayIbcTokenBridgePayloadSimple(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(), 1231245, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, simplePayload) + payload3 := helpers.CreatePayload3(wormchain.Config(), 30000, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, simplePayload) completeTransferAndConvertMsg := helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians) _, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg) @@ -137,14 +136,20 @@ func TestCosmosToExternal(t *testing.T) { tokenFactoryDenom := fmt.Sprint("factory/", ibcTranslatorContractAddr, "/", subdenom) gaiaAsset1Denom := transfertypes.GetPrefixedDenom("transfer", gaiaToWormChannel.ChannelID, tokenFactoryDenom) gaiaIbcAsset1Denom := transfertypes.ParseDenomTrace(gaiaAsset1Denom).IBCDenom() + + + // ************* Ibc hooks + Simple payload **************** + // Call SimpleConvertAndTransfer and ContractControlledConvertAndTransfer + // Using "externalSender" as recipient because it is 32 bytes + simpleIbcHooksMsg := helpers.CreateIbcTranslatorIbcHooksSimpleMsg(t, ibcTranslatorContractAddr, Asset1ChainID, string(externalSender), 0, 1) transfer := ibc.WalletAmount{ - Address: wormchainFaucetAddr, + Address: ibcTranslatorContractAddr, Denom: gaiaIbcAsset1Denom, - Amount: 10000, + Amount: 10001, } gaiaHeight, err := gaia.Height(ctx) require.NoError(t, err) - gaiaIbcTx, err := gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{}) + gaiaIbcTx, err := gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{Memo: simpleIbcHooksMsg}) require.NoError(t, err) // wait for transfer to ack @@ -152,43 +157,24 @@ func TestCosmosToExternal(t *testing.T) { require.NoError(t, err) err = testutil.WaitForBlocks(ctx, 1, wormchain, gaia) require.NoError(t, err) - - // Call SimpleConvertAndTransfer and ContractControlledConvertAndTransfer - // Using "externalSender" as recipient because it is 32 bytes - simpleContractMsg := helpers.CreateIbcTranslatorExecuteSimple(t, Asset1ChainID, string(externalSender), 0, 1) - simpleTxHash, err := wormchain.ExecuteContractWithAmount(ctx, "faucet", ibcTranslatorContractAddr, simpleContractMsg, sdk.NewCoins(sdk.NewCoin(tokenFactoryDenom, sdk.NewInt(4000)))) - require.NoError(t, err) - expectedSequence := 0 - foundEvent := helpers.FindEventAttribute(t, wormchain, simpleTxHash, "wasm", "message.sequence", fmt.Sprint(expectedSequence)) - require.True(t, foundEvent) - - contractControlledContractMsg := helpers.CreateIbcTranslatorExecuteContractControlled(t, Asset1ChainID, string(externalSender), []byte("{ContractPayload}"), 2) - ccTxHash, err := wormchain.ExecuteContractWithAmount(ctx, "faucet", ibcTranslatorContractAddr, contractControlledContractMsg, sdk.NewCoins(sdk.NewCoin(tokenFactoryDenom, sdk.NewInt(5000)))) + // ********* Ibc hooks + Contract controlled payload ********** + ccIbcHooksMsg := helpers.CreateIbcTranslatorIbcHooksContractControlledMsg(t, ibcTranslatorContractAddr, Asset1ChainID, string(externalSender), []byte("ExternalContractPayload"), 1) + transfer = ibc.WalletAmount{ + Address: ibcTranslatorContractAddr, + Denom: gaiaIbcAsset1Denom, + Amount: 10002, + } + gaiaHeight, err = gaia.Height(ctx) require.NoError(t, err) - - expectedSequence++ - foundEvent = helpers.FindEventAttribute(t, wormchain, ccTxHash, "wasm", "message.sequence", fmt.Sprint(expectedSequence)) - require.True(t, foundEvent) - - // Simple payload with a relayer fee - relayerFee := uint64(100) - amount := int64(500) - simpleContractMsg2 := helpers.CreateIbcTranslatorExecuteSimple(t, Asset1ChainID, string(externalSender), relayerFee, 1) - simpleTxHash2, err := wormchain.ExecuteContractWithAmount(ctx, "faucet", ibcTranslatorContractAddr, simpleContractMsg2, sdk.NewCoins(sdk.NewCoin(tokenFactoryDenom, sdk.NewInt(amount)))) + gaiaIbcTx, err = gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{Memo: ccIbcHooksMsg}) + require.NoError(t, err) + + // wait for transfer to ack + _, err = testutil.PollForAck(ctx, gaia, gaiaHeight, gaiaHeight+30, gaiaIbcTx.Packet) + require.NoError(t, err) + err = testutil.WaitForBlocks(ctx, 1, wormchain, gaia) require.NoError(t, err) - - expectedSequence++ - foundEvent = helpers.FindEventAttribute(t, wormchain, simpleTxHash2, "wasm", "message.sequence", fmt.Sprint(expectedSequence)) - require.True(t, foundEvent) - payload1 := helpers.CreatePayload1(uint64(amount), Asset1ContractAddr, Asset1ChainID, externalSender, Asset1ChainID, relayerFee) - payload1Hex := hex.EncodeToString(payload1) - foundEvent = helpers.FindEventAttribute(t, wormchain, simpleTxHash2, "wasm", "message.message", payload1Hex) - require.True(t, foundEvent) - /*var cw20BalanceQueryRsp helpers.Cw20WrappedBalanceQueryRsp - cw20BalanceQueryReq := helpers.Cw20WrappedBalanceQueryMsg{Balance: helpers.Cw20BalanceQuery{Address: wormchainFaucetAddr}} - wormchain.QueryContract(ctx, cw20Address, cw20BalanceQueryReq, &cw20BalanceQueryRsp) - fmt.Println("Faucet Asset1 balance: ", cw20BalanceQueryRsp.Data.Balance)*/ // wait for transfer err = testutil.WaitForBlocks(ctx, 3, wormchain) diff --git a/wormchain/interchaintest/go.mod b/wormchain/interchaintest/go.mod index a34397f362..329c09029c 100644 --- a/wormchain/interchaintest/go.mod +++ b/wormchain/interchaintest/go.mod @@ -220,5 +220,5 @@ replace ( github.com/tendermint/tendermint => github.com/informalsystems/tendermint v0.34.23 github.com/vedhavyas/go-subkey => github.com/strangelove-ventures/go-subkey v1.0.7 github.com/wormhole-foundation/wormchain => ../ - github.com/wormhole-foundation/wormchain/sdk => ../sdk + github.com/wormhole-foundation/wormhole/sdk => ../../sdk ) diff --git a/wormchain/interchaintest/go.sum b/wormchain/interchaintest/go.sum index 770167998f..26072309dd 100644 --- a/wormchain/interchaintest/go.sum +++ b/wormchain/interchaintest/go.sum @@ -677,10 +677,6 @@ github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= github.com/strangelove-ventures/go-subkey v1.0.7 h1:cOP/Lajg3uxV/tvspu0m6+0Cu+DJgygkEAbx/s+f35I= github.com/strangelove-ventures/go-subkey v1.0.7/go.mod h1:E34izOIEm+sZ1YmYawYRquqBQWeZBjVB4pF7bMuhc1c= -github.com/strangelove-ventures/interchaintest/v4 v4.0.0-20230622205228-443173428ad0 h1:E3eEfZWhrRCIJ0+8S5AHK9mNfM46cCN9J1Kbg/JAbBk= -github.com/strangelove-ventures/interchaintest/v4 v4.0.0-20230622205228-443173428ad0/go.mod h1:pZEZL7eKFk6gauxedsFP1UpkNug4TKX4HxkHY1ITfeo= -github.com/strangelove-ventures/interchaintest/v4 v4.0.0-20230701003343-48cb1d77f787 h1:vZr9jw23iL192EH4oDnuI4wkLvZh1dDH7vP+h0MHbPw= -github.com/strangelove-ventures/interchaintest/v4 v4.0.0-20230701003343-48cb1d77f787/go.mod h1:pZEZL7eKFk6gauxedsFP1UpkNug4TKX4HxkHY1ITfeo= github.com/strangelove-ventures/interchaintest/v4 v4.0.0-20230701004017-701263d86262 h1:apc+d7WYXPhzozhkEDNsUCRQD1jt6PANls40Z46gC44= github.com/strangelove-ventures/interchaintest/v4 v4.0.0-20230701004017-701263d86262/go.mod h1:pZEZL7eKFk6gauxedsFP1UpkNug4TKX4HxkHY1ITfeo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -722,8 +718,6 @@ github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBn github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230614161948-7f6213019abf h1:qpJDPMpvdVUnDbqgW5gMriuS4gTOhkrVxY+p16ksgQk= -github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230614161948-7f6213019abf/go.mod h1:DFYzEkE0jR/JclRFzenut188VUsp4r1NvaegOWx8pcE= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/wormchain/interchaintest/helpers/ibc_translator.go b/wormchain/interchaintest/helpers/ibc_translator.go index ac4e41ef7a..07faa2c3e8 100644 --- a/wormchain/interchaintest/helpers/ibc_translator.go +++ b/wormchain/interchaintest/helpers/ibc_translator.go @@ -2,26 +2,59 @@ package helpers import ( "bytes" + "context" "encoding/binary" + "encoding/hex" "encoding/json" "fmt" + "strconv" "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" "github.com/wormhole-foundation/wormhole/sdk/vaa" ) +func SubmitAllowlistInstantiateContract( + t *testing.T, + ctx context.Context, + chain *cosmos.CosmosChain, + keyName string, + cfg ibc.ChainConfig, + contractBech32Addr string, + codeIdStr string, + guardians *guardians.ValSet, +) { + node := chain.GetFullNode() + codeId, err := strconv.ParseUint(codeIdStr, 10, 64) + require.NoError(t, err) + + contractAddr := [32]byte{} + copy(contractAddr[:], MustAccAddressFromBech32(contractBech32Addr, cfg.Bech32Prefix).Bytes()) + payload := vaa.BodyWormchainAllowlistInstantiateContract{ + ContractAddr: contractAddr, + CodeId: codeId, + } + payloadBz := payload.Serialize() + v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz) + vBz, err := v.Marshal() + require.NoError(t, err) + vHex := hex.EncodeToString(vBz) + +// create-instantiate-allowed-contract [bech32 contract addr] [codeId] [vaa-hex] + _, err = node.ExecTx(ctx, keyName, "wormhole", "create-instantiate-allowed-contract", contractBech32Addr, codeIdStr, vHex, "--gas", "auto") + require.NoError(t, err) +} + type IbcTranslatorInstantiateMsg struct { TokenBridgeContract string `json:"token_bridge_contract"` - CoreContract string `json:"wormhole_contract"` } -func IbcTranslatorContractInstantiateMsg(t *testing.T, tbContract string, coreContract string) string { +func IbcTranslatorContractInstantiateMsg(t *testing.T, tbContract string) string { msg := IbcTranslatorInstantiateMsg{ TokenBridgeContract: tbContract, - CoreContract: coreContract, } msgBz, err := json.Marshal(msg) require.NoError(t, err) @@ -243,4 +276,65 @@ type IbcTranslatorQueryRspMsg struct { type IbcTranslatorQueryRspObj struct { Channel string `json:"channel,omitempty"` +} + +// Code below is temporary for testing cosmos->external using ibc-hooks, but without our custom middleware +type IbcTranslatorIbcHooksSimple struct { + Payload IbcTranslatorIbcHooksPayloadSimple `json:"wasm"` +} + +type IbcTranslatorIbcHooksPayloadSimple struct { + Contract string `json:"contract"` + Msg IbcTranslatorExecuteSimple `json:"msg"` +} + +func CreateIbcTranslatorIbcHooksSimpleMsg(t *testing.T, contract string, chainID uint16, recipient string, fee uint64, nonce uint32) string { + msg := IbcTranslatorIbcHooksSimple { + Payload: IbcTranslatorIbcHooksPayloadSimple{ + Contract: contract, + Msg: IbcTranslatorExecuteSimple { + Msg: Simple{ + Chain: chainID, + Recipient: []byte(recipient), + Fee: fmt.Sprint(fee), + Nonce: nonce, + }, + }, + }, + } + + msgBz, err := json.Marshal(msg) + require.NoError(t, err) + + return string(msgBz) +} + +type IbcTranslatorIbcHooksContractControlled struct { + Payload IbcTranslatorIbcHooksPayloadContractControlled `json:"wasm"` +} + +type IbcTranslatorIbcHooksPayloadContractControlled struct { + Contract string `json:"contract"` + Msg IbcTranslatorExecuteContractControlled `json:"msg"` +} + +func CreateIbcTranslatorIbcHooksContractControlledMsg(t *testing.T, contract string, chainID uint16, externalContract string, payload []byte, nonce uint32) string { + msg := IbcTranslatorIbcHooksContractControlled { + Payload: IbcTranslatorIbcHooksPayloadContractControlled{ + Contract: contract, + Msg: IbcTranslatorExecuteContractControlled{ + Msg: ContractControlled{ + Chain: chainID, + Contract: []byte(externalContract), + Payload: payload, + Nonce: nonce, + }, + }, + }, + } + + msgBz, err := json.Marshal(msg) + require.NoError(t, err) + + return string(msgBz) } \ No newline at end of file diff --git a/wormchain/interchaintest/helpers/migrate_contract.go b/wormchain/interchaintest/helpers/migrate_contract.go index 94136a595f..83c31c014c 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, - ) { +) { node := chain.GetFullNode() diff --git a/wormchain/interchaintest/helpers/pfm.go b/wormchain/interchaintest/helpers/pfm.go new file mode 100644 index 0000000000..fc90c31e36 --- /dev/null +++ b/wormchain/interchaintest/helpers/pfm.go @@ -0,0 +1,77 @@ +package helpers + +import ( + "encoding/json" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + + +type PacketMetadata struct { + Forward *ForwardMetadata `json:"forward"` +} + +type ForwardMetadata struct { + Receiver string `json:"receiver"` + Port string `json:"port"` + Channel string `json:"channel"` + Timeout time.Duration `json:"timeout"` + Retries *uint8 `json:"retries,omitempty"` + Next *string `json:"next,omitempty"` + RefundSequence *uint64 `json:"refund_sequence,omitempty"` +} + +func CreatePfmSimpleMsg(t *testing.T, recipient string, channel string) string { + retries := uint8(0) + msg := &PacketMetadata{ + Forward: &ForwardMetadata{ + Receiver: recipient, + Port: "transfer", + Channel: channel, + Timeout: time.Minute*10, + Retries: &retries, + }, + } + + msgBz, err := json.Marshal(msg) + require.NoError(t, err) + + return string(msgBz) +} + +func CreatePfmContractControlledMsg(t *testing.T, contract string, channel string, recipient string) string { + ibchooks := &IbcHooks{ + Payload: IbcHooksPayload{ + Contract: contract, + Msg: IbcHooksExecute{ + Forward: IbcHooksForward{ + Recipient: recipient, + }, + }, + }, + } + + nextBz, err := json.Marshal(ibchooks) + require.NoError(t, err) + + next := string(nextBz) + + retries := uint8(0) + msg := &PacketMetadata{ + Forward: &ForwardMetadata{ + Receiver: contract, + Port: "transfer", + Channel: channel, + Timeout: 1 * time.Minute, + Retries: &retries, + Next: &next, + }, + } + + msgBz, err := json.Marshal(msg) + require.NoError(t, err) + + return string(msgBz) +} \ No newline at end of file diff --git a/wormchain/interchaintest/helpers/token_bridge.go b/wormchain/interchaintest/helpers/token_bridge.go index 0beeaefe51..b8f3b3065e 100644 --- a/wormchain/interchaintest/helpers/token_bridge.go +++ b/wormchain/interchaintest/helpers/token_bridge.go @@ -50,7 +50,6 @@ type TbSubmitVaaMsg struct { SubmitVaa SubmitVaa `json:"submit_vaa,omitempty"` } - type SubmitVaa struct { Data []byte `json:"data,omitempty"` } diff --git a/wormchain/interchaintest/malformed_payload_test.go b/wormchain/interchaintest/malformed_payload_test.go index f9595b0623..a105b8146f 100644 --- a/wormchain/interchaintest/malformed_payload_test.go +++ b/wormchain/interchaintest/malformed_payload_test.go @@ -88,7 +88,7 @@ func TestMalformedPayload(t *testing.T) { fmt.Println("ibc_translator code id: ", ibcTranslatorCodeId) // Instantiate ibc translator contract - ibcTranslatorInstantiateMsg := helpers.IbcTranslatorContractInstantiateMsg(t, tbContractAddr, coreContractAddr) + ibcTranslatorInstantiateMsg := helpers.IbcTranslatorContractInstantiateMsg(t, tbContractAddr) ibcTranslatorContractAddr := helpers.InstantiateContract(t, ctx, wormchain, "faucet", ibcTranslatorCodeId, "ibc_translator", ibcTranslatorInstantiateMsg, guardians) fmt.Println("Ibc translator contract address: ", ibcTranslatorContractAddr) diff --git a/wormchain/interchaintest/setup.go b/wormchain/interchaintest/setup.go index 288d510c87..10204ab35f 100644 --- a/wormchain/interchaintest/setup.go +++ b/wormchain/interchaintest/setup.go @@ -37,6 +37,7 @@ var ( Images: []ibc.DockerImage{ { Repository: "wormchain", + //Version: "gateway-integration", Version: "local", UidGid: "1025:1025", }, diff --git a/wormchain/interchaintest/wormchain_test.go b/wormchain/interchaintest/wormchain_test.go index b84b134349..20b1024277 100644 --- a/wormchain/interchaintest/wormchain_test.go +++ b/wormchain/interchaintest/wormchain_test.go @@ -96,6 +96,8 @@ func TestWormchain(t *testing.T) { 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) + // Register a new external chain tbRegisterChainMsg := helpers.TbRegisterChainMsg(t, ExternalChainId, ExternalChainEmitterAddr, guardians) _, err = wormchain.ExecuteContract(ctx, "faucet", tbContractAddr, string(tbRegisterChainMsg)) @@ -111,7 +113,7 @@ func TestWormchain(t *testing.T) { fmt.Println("Ibc translator code id: ", ibcTranslatorCodeId) // Instantiate ibc translator contract - ibcTranslatorInstantiateMsg := helpers.IbcTranslatorContractInstantiateMsg(t, tbContractAddr, coreContractAddr) + ibcTranslatorInstantiateMsg := helpers.IbcTranslatorContractInstantiateMsg(t, tbContractAddr) ibcTranslatorContractAddr := helpers.InstantiateContract(t, ctx, wormchain, "faucet", ibcTranslatorCodeId, "ibc_translator", ibcTranslatorInstantiateMsg, guardians) fmt.Println("Ibc translator contract address: ", ibcTranslatorContractAddr)