This commit is contained in:
Steve 2024-04-20 16:56:50 +02:00 committed by GitHub
commit 89696b5200
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 4918 additions and 0 deletions

View File

@ -0,0 +1,59 @@
package ictest
import (
"context"
"fmt"
"testing"
"time"
"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"
)
// TestCancelUpgrade will start on wormchain v2.18.1.1, schedule an upgrade to v2.23.0, cancel the upgrade,
// and verify that block production does not stop at the cancelled scheduled upgrade height.
func TestCancelUpgrade(t *testing.T) {
// Base setup
numVals := 2
guardians := guardians.CreateValSet(t, numVals)
chains := CreateChains(t, "v2.18.1.1", *guardians)
ctx, _, _, _ := BuildInterchain(t, chains)
// Chains
wormchain := chains[0].(*cosmos.CosmosChain)
// Set up upgrade
blocksAfterUpgrade := uint64(10)
height, err := wormchain.Height(ctx)
require.NoError(t, err, "error fetching height before upgrade")
fmt.Println("Height at sending schedule upgrade: ", height)
haltHeight := height + blocksAfterUpgrade
fmt.Println("Height for scheduled upgrade: ", haltHeight)
// Schedule upgrade
helpers.ScheduleUpgrade(t, ctx, wormchain, "faucet", "v2.23.0", haltHeight, guardians)
// Cancel upgrade
testutil.WaitForBlocks(ctx, 2, wormchain)
helpers.CancelUpgrade(t, ctx, wormchain, "faucet", guardians)
timeoutCtx3, timeoutCtxCancel3 := context.WithTimeout(ctx, time.Second*45)
defer timeoutCtxCancel3()
// Wait for chain to reach/exceed originally scheduled upgrade height
// If it times-out, the cancel upgrade did not work and the chain will have halted at the scheduled upgrade height
// If it does not timeout, it will be one block after the originally scheduled upgrade height
testutil.WaitForBlocks(timeoutCtx3, int(blocksAfterUpgrade), wormchain)
height, err = wormchain.Height(ctx)
require.NoError(t, err, "error fetching height after chain should have halted")
// Ensure that the chain continued making blocks passed the upgrade height
require.NotEqual(t, haltHeight, height, "height is equal to halt height, it shouldn't be")
fmt.Println("***** Cancel upgrade test passed ******")
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
[alias]
wasm = "build --release --target wasm32-unknown-unknown"
wasm-debug = "build --target wasm32-unknown-unknown"
unit-test = "test --lib --features backtraces"
integration-test = "test --test integration"

View File

@ -0,0 +1,690 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]]
name = "anyhow"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
name = "base16ct"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "const-oid"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913"
[[package]]
name = "cosmwasm-crypto"
version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb64554a91d6a9231127f4355d351130a0b94e663d5d9dc8b3a54ca17d83de49"
dependencies = [
"digest 0.10.7",
"ed25519-zebra",
"k256",
"rand_core 0.6.4",
"thiserror",
]
[[package]]
name = "cosmwasm-derive"
version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0fb2ce09f41a3dae1a234d56a9988f9aff4c76441cd50ef1ee9a4f20415b028"
dependencies = [
"syn 1.0.109",
]
[[package]]
name = "cosmwasm-schema"
version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "230e5d1cefae5331db8934763c81b9c871db6a2cd899056a5694fa71d292c815"
dependencies = [
"cosmwasm-schema-derive",
"schemars",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "cosmwasm-schema-derive"
version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43dadf7c23406cb28079d69e6cb922c9c29b9157b0fe887e3b79c783b7d4bcb8"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "cosmwasm-std"
version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4337eef8dfaf8572fe6b6b415d6ec25f9308c7bb09f2da63789209fb131363be"
dependencies = [
"base64",
"cosmwasm-crypto",
"cosmwasm-derive",
"derivative",
"forward_ref",
"hex",
"schemars",
"serde",
"serde-json-wasm",
"sha2 0.10.7",
"thiserror",
"uint",
]
[[package]]
name = "cpufeatures"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c"
dependencies = [
"libc",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-bigint"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
dependencies = [
"generic-array",
"rand_core 0.6.4",
"subtle",
"zeroize",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "curve25519-dalek"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
dependencies = [
"byteorder",
"digest 0.9.0",
"rand_core 0.5.1",
"subtle",
"zeroize",
]
[[package]]
name = "der"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
dependencies = [
"const-oid",
"zeroize",
]
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer 0.10.4",
"crypto-common",
"subtle",
]
[[package]]
name = "dyn-clone"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
[[package]]
name = "ecdsa"
version = "0.14.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"
dependencies = [
"der",
"elliptic-curve",
"rfc6979",
"signature",
]
[[package]]
name = "ed25519-zebra"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6"
dependencies = [
"curve25519-dalek",
"hashbrown",
"hex",
"rand_core 0.6.4",
"serde",
"sha2 0.9.9",
"zeroize",
]
[[package]]
name = "elliptic-curve"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
dependencies = [
"base16ct",
"crypto-bigint",
"der",
"digest 0.10.7",
"ff",
"generic-array",
"group",
"pkcs8",
"rand_core 0.6.4",
"sec1",
"subtle",
"zeroize",
]
[[package]]
name = "ff"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
dependencies = [
"rand_core 0.6.4",
"subtle",
]
[[package]]
name = "forward_ref"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "group"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
dependencies = [
"ff",
"rand_core 0.6.4",
"subtle",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest 0.10.7",
]
[[package]]
name = "ibc-hooks"
version = "0.1.0"
dependencies = [
"anyhow",
"cosmwasm-schema",
"cosmwasm-std",
]
[[package]]
name = "itoa"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "k256"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b"
dependencies = [
"cfg-if",
"ecdsa",
"elliptic-curve",
"sha2 0.10.7",
]
[[package]]
name = "libc"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "pkcs8"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
dependencies = [
"der",
"spki",
]
[[package]]
name = "proc-macro2"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rfc6979"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb"
dependencies = [
"crypto-bigint",
"hmac",
"zeroize",
]
[[package]]
name = "ryu"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
name = "schemars"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f"
dependencies = [
"dyn-clone",
"schemars_derive",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 1.0.109",
]
[[package]]
name = "sec1"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
dependencies = [
"base16ct",
"der",
"generic-array",
"pkcs8",
"subtle",
"zeroize",
]
[[package]]
name = "serde"
version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde-json-wasm"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137"
dependencies = [
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.22",
]
[[package]]
name = "serde_derive_internals"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "serde_json"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
"block-buffer 0.9.0",
"cfg-if",
"cpufeatures",
"digest 0.9.0",
"opaque-debug",
]
[[package]]
name = "sha2"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.10.7",
]
[[package]]
name = "signature"
version = "1.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
dependencies = [
"digest 0.10.7",
"rand_core 0.6.4",
]
[[package]]
name = "spki"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
dependencies = [
"base64ct",
"der",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.22",
]
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "uint"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52"
dependencies = [
"byteorder",
"crunchy",
"hex",
"static_assertions",
]
[[package]]
name = "unicode-ident"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "zeroize"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"

View File

@ -0,0 +1,37 @@
[package]
name = "ibc-hooks"
version = "0.1.0"
authors = ["Wormhole Project Contributors"]
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[profile.release]
opt-level = 0
debug = true
rpath = false
lto = false
debug-assertions = false
codegen-units = 1
panic = 'abort'
incremental = false
overflow-checks = true
[features]
# for more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]
# use library feature to disable all instantiate/execute/query/reply exports
library = []
[package.metadata.scripts]
optimize = """docker run --rm -v "$(pwd)":/code \
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
cosmwasm/rust-optimizer:0.12.6
"""
[dependencies]
cosmwasm-std = {version="1.2.7", features = ["ibc3"] }
cosmwasm-schema = "1.2.7"
anyhow = "1"

View File

@ -0,0 +1,54 @@
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use anyhow::{Context, ensure};
use cosmwasm_std::{
BankMsg, CosmosMsg, DepsMut, Empty, Env, MessageInfo, Response,
};
use crate::{
msg::{ExecuteMsg, InstantiateMsg},
};
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_msg: InstantiateMsg,
) -> Result<Response, anyhow::Error> {
Ok(Response::new())
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: Empty) -> Result<Response, anyhow::Error> {
Ok(Response::default())
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
_deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, anyhow::Error> {
match msg {
ExecuteMsg::ForwardTokens { recipient } => {
// bank tokens sent to the contract will be in info.funds
ensure!(
info.funds.len() == 1,
"info.funds should contain only 1 coin"
);
// batch calls together
let mut response: Response = Response::new();
response = response.add_message(BankMsg::Send {
to_address: recipient,
amount: info.funds,
//amount: vec![amount],
});
Ok(response)
},
}
}

View File

@ -0,0 +1,2 @@
pub mod contract;
pub mod msg;

View File

@ -0,0 +1,11 @@
use cosmwasm_schema::cw_serde;
#[cw_serde]
pub struct InstantiateMsg {}
#[cw_serde]
pub enum ExecuteMsg {
ForwardTokens {
recipient: String,
},
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,225 @@
module github.com/wormhole-foundation/wormchain/interchaintest
go 1.19
require (
github.com/cosmos/cosmos-sdk v0.45.14
github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845
github.com/stretchr/testify v1.8.4
github.com/wormhole-foundation/wormchain v0.0.0-00010101000000-000000000000
go.uber.org/zap v1.24.0
)
require (
github.com/btcsuite/btcd/btcutil v1.1.3
github.com/cosmos/ibc-go/v4 v4.3.0
github.com/docker/docker v20.10.19+incompatible
github.com/ethereum/go-ethereum v1.11.6
github.com/strangelove-ventures/interchaintest/v4 v4.0.0-20230815125617-67bc301715ea
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230614161948-7f6213019abf
)
require (
cosmossdk.io/api v0.2.6 // indirect
cosmossdk.io/core v0.5.1 // indirect
cosmossdk.io/depinject v1.0.0-alpha.3 // indirect
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.1 // indirect
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect
github.com/ChainSafe/go-schnorrkel/1 v0.0.0-00010101000000-000000000000 // indirect
github.com/CosmWasm/wasmd v0.31.0 // indirect
github.com/CosmWasm/wasmvm v1.2.1 // indirect
github.com/DataDog/zstd v1.5.2 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/StirlingMarketingGroup/go-namecase v1.0.0 // indirect
github.com/armon/go-metrics v0.4.0 // indirect
github.com/avast/retry-go/v4 v4.0.4 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
github.com/btcsuite/btcd v0.23.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.4 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cockroachdb/errors v1.9.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect
github.com/cockroachdb/redact v1.1.3 // indirect
github.com/confio/ics23/go v0.9.0 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogoproto v1.4.6 // indirect
github.com/cosmos/gorocksdb v1.2.0 // indirect
github.com/cosmos/iavl v0.19.5 // indirect
github.com/cosmos/interchain-security v1.0.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.12.2 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/base58 v1.0.3 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.0 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/getsentry/sentry-go v0.18.0 // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/gateway v1.1.0 // indirect
github.com/gogo/protobuf v1.3.3 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/ipfs/go-cid v0.0.7 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.15.15 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-libp2p-core v0.15.1 // indirect
github.com/libp2p/go-openssl v0.0.7 // indirect
github.com/linxGnu/grocksdb v1.7.10 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multiaddr v0.4.1 // indirect
github.com/multiformats/go-multibase v0.0.3 // indirect
github.com/multiformats/go-multicodec v0.4.1 // indirect
github.com/multiformats/go-multihash v0.1.0 // indirect
github.com/multiformats/go-varint v0.0.6 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pierrec/xxHash v0.1.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.39.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/rakyll/statik v0.1.7 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/regen-network/cosmos-proto v0.3.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/rs/cors v1.8.2 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.14.0 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tendermint/tendermint v0.34.26 // indirect
github.com/tendermint/tm-db v0.6.7 // indirect
github.com/tidwall/btree v1.5.0 // indirect
github.com/vedhavyas/go-subkey v1.0.3 // indirect
github.com/zondax/hid v0.9.1 // indirect
github.com/zondax/ledger-go v0.14.1 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/term v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/tools v0.7.0 // indirect
google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa // indirect
google.golang.org/grpc v1.53.0 // indirect
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.6 // indirect
lukechampine.com/uint128 v1.1.1 // indirect
modernc.org/cc/v3 v3.36.0 // indirect
modernc.org/ccgo/v3 v3.16.6 // indirect
modernc.org/libc v1.16.7 // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.1.1 // indirect
modernc.org/opt v0.1.1 // indirect
modernc.org/sqlite v1.17.3 // indirect
modernc.org/strutil v1.1.1 // indirect
modernc.org/token v1.0.0 // indirect
)
replace (
github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
github.com/ChainSafe/go-schnorrkel => github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d
github.com/ChainSafe/go-schnorrkel/1 => github.com/ChainSafe/go-schnorrkel v1.0.0
// specify the version of btcd used so we don't get the btcec issue
github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.2
// use cosmos-sdk with ics support
github.com/cosmos/cosmos-sdk => github.com/cosmos/cosmos-sdk v0.45.14-ics
//github.com/cosmos/cosmos-sdk => github.com/wormhole-foundation/cosmos-sdk v0.45.9-wormhole-2
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
//github.com/strangelove-ventures/interchaintest/v4 => ../../../../../strangelove-ventures/interchaintest_v4
// pin version! 126854af5e6d has issues with the store so that queries fail
github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
// use informal tendermint
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/wormhole/sdk => ../../sdk
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,56 @@
package guardians
import (
"crypto/ecdsa"
"testing"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
)
type ValSet struct {
Vals []Val
Total int
}
type Val struct {
Addr []byte
Priv *ecdsa.PrivateKey
}
func CreateVal(t *testing.T) *Val {
priv, err := crypto.GenerateKey()
require.NoError(t, err)
signer := crypto.PubkeyToAddress(priv.PublicKey).Bytes()
return &Val{
Addr: signer,
Priv: priv,
}
}
func CreateValSet(t *testing.T, total int) *ValSet {
// If total == 1, mirror the guardian keys in scripts/devnet-consts.json
if total == 1 {
privHex := "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0"
priv, err := crypto.HexToECDSA(privHex)
require.NoError(t, err)
signer := crypto.PubkeyToAddress(priv.PublicKey).Bytes()
return &ValSet{
Vals: []Val{
{signer, priv},
},
Total: 1,
}
}
var valSet ValSet
for i := 0; i < total; i++ {
valSet.Vals = append(valSet.Vals, *CreateVal(t))
}
valSet.Total = total
return &valSet
}

View File

@ -0,0 +1,33 @@
package helpers
import (
"context"
"encoding/json"
"fmt"
"testing"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/strangelove-ventures/interchaintest/v4/chain/cosmos"
"github.com/stretchr/testify/require"
)
func GetDenomsMetadata(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain) QueryDenomsMetadataResponse {
node := chain.GetFullNode()
stdoutBz, _, err := node.ExecQuery(ctx, "bank", "denom-metadata")
require.NoError(t, err)
fmt.Println("Stdout: ", string(stdoutBz))
res := QueryDenomsMetadataResponse{}
err = json.Unmarshal(stdoutBz, &res)
require.NoError(t, err)
return res
}
// QueryDenomsMetadataResponse is the response type for the Query/DenomsMetadata RPC
// method.
type QueryDenomsMetadataResponse struct {
// metadata provides the client information for all the registered tokens.
Metadatas []banktypes.Metadata `json:"metadatas"`
}

View File

@ -0,0 +1,114 @@
package helpers
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
type Cw20InstantiateMsg struct {
Name string `json:"name"`
Symbol string `json:"symbol"`
AssetChain uint16 `json:"asset_chain"`
AssetAddr []byte `json:"asset_address"`
Decimals uint8 `json:"decimals"`
InitHook InitHook `json:"init_hook"`
}
type InitHook struct {
Msg []byte `json:"msg"`
ContractAddr string `json:"contract_addr"`
}
type TbRegisterAssetHookMsg struct {
RegisterAssetHook RegisterAssetHook `json:"register_asset_hook,omitempty"`
}
type RegisterAssetHook struct {
Chain uint16 `json:"chain,omitempty"`
TokenAddr ExternalTokenId `json:"token_address,omitempty"`
}
type ExternalTokenId struct {
Bytes [32]byte `json:"bytes,omitempty"`
}
func Cw20ContractInstantiateMsg(
t *testing.T,
name string,
symbol string,
chainID uint16,
assetAddr string,
decimals uint8,
tbContractAddr string,
) string {
index := 32
assetAddr32 := [32]byte{}
for i := len(assetAddr); i > 0; i-- {
assetAddr32[index-1] = assetAddr[i-1]
index--
}
tbMsg := TbRegisterAssetHookMsg{
RegisterAssetHook: RegisterAssetHook{
Chain: chainID,
TokenAddr: ExternalTokenId{
Bytes: assetAddr32,
},
},
}
tbMsgBz, err := json.Marshal(tbMsg)
require.NoError(t, err)
msg := Cw20InstantiateMsg{
Name: name,
Symbol: symbol,
AssetChain: chainID,
AssetAddr: assetAddr32[:],
Decimals: decimals,
InitHook: InitHook{
Msg: tbMsgBz,
ContractAddr: tbContractAddr,
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return string(msgBz)
}
type Cw20WrappedQueryMsg struct {
TokenInfo Cw20TokenInfo `json:"token_info"`
}
type Cw20TokenInfo struct{}
type Cw20WrappedBalanceQueryMsg struct {
Balance Cw20BalanceQuery `json:"balance"`
}
type Cw20BalanceQuery struct {
Address string `json:"address"`
}
type Cw20WrappedQueryRsp struct {
Data *Cw20WrappedQueryRspObj `json:"data,omitempty"`
}
type Cw20WrappedQueryRspObj struct {
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals uint8 `json:"decimals"`
TotalSupply string `json:"total_supply"`
}
type Cw20WrappedBalanceQueryRsp struct {
Data *Cw20WrappedBalanceQueryRspObj `json:"data,omitempty"`
}
type Cw20WrappedBalanceQueryRspObj struct {
Balance string `json:"balance"`
}

View File

@ -0,0 +1,94 @@
package helpers
import (
"context"
"encoding/hex"
"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 GetMiddlewareContract(
t *testing.T,
ctx context.Context,
chain *cosmos.CosmosChain,
) string {
node := chain.GetFullNode()
stdout, _, err := node.ExecQuery(ctx, "wormhole", "show-ibc-composability-mw-contract")
require.NoError(t, err)
return string(stdout)
}
func SetMiddlewareContract(
t *testing.T,
ctx context.Context,
chain *cosmos.CosmosChain,
keyName string,
cfg ibc.ChainConfig,
contractBech32Addr string,
guardians *guardians.ValSet,
) {
node := chain.GetFullNode()
contractAddr := [32]byte{}
copy(contractAddr[:], MustAccAddressFromBech32(contractBech32Addr, cfg.Bech32Prefix).Bytes())
payload := vaa.BodyGatewayIbcComposabilityMwContract{
ContractAddr: contractAddr,
}
payloadBz := payload.Serialize()
v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz)
vBz, err := v.Marshal()
require.NoError(t, err)
vHex := hex.EncodeToString(vBz)
_, err = node.ExecTx(ctx, keyName, "wormhole", "execute-gateway-governance-vaa", vHex, "--gas", "auto")
require.NoError(t, err)
}
func ScheduleUpgrade(
t *testing.T,
ctx context.Context,
chain *cosmos.CosmosChain,
keyName string,
name string,
height uint64,
guardians *guardians.ValSet,
) {
node := chain.GetFullNode()
payload := vaa.BodyGatewayScheduleUpgrade{
Name: name,
Height: height,
}
payloadBz := payload.Serialize()
v := generateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payloadBz)
vBz, err := v.Marshal()
require.NoError(t, err)
vHex := hex.EncodeToString(vBz)
_, err = node.ExecTx(ctx, keyName, "wormhole", "execute-gateway-governance-vaa", vHex, "--gas", "auto")
require.NoError(t, err)
}
func CancelUpgrade(
t *testing.T,
ctx context.Context,
chain *cosmos.CosmosChain,
keyName string,
guardians *guardians.ValSet,
) {
node := chain.GetFullNode()
payloadBz := vaa.EmptyPayloadVaa(vaa.GatewayModuleStr, vaa.ActionCancelUpgrade, vaa.ChainIDWormchain)
v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz)
vBz, err := v.Marshal()
require.NoError(t, err)
vHex := hex.EncodeToString(vBz)
_, err = node.ExecTx(ctx, keyName, "wormhole", "execute-gateway-governance-vaa", vHex, "--gas", "auto")
require.NoError(t, err)
}

View File

@ -0,0 +1,43 @@
package helpers
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
type IbcHooks struct {
Payload IbcHooksPayload `json:"wasm"`
}
type IbcHooksPayload struct {
Contract string `json:"contract"`
Msg IbcHooksExecute `json:"msg"`
}
type IbcHooksExecute struct {
Forward IbcHooksForward `json:"forward_tokens"`
}
type IbcHooksForward struct {
Recipient string `json:"recipient"`
}
func CreateIbcHooksMsg(t *testing.T, contract string, recipient string) []byte {
msg := IbcHooks{
Payload: IbcHooksPayload{
Contract: contract,
Msg: IbcHooksExecute{
Forward: IbcHooksForward{
Recipient: recipient,
},
},
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return msgBz
}

View File

@ -0,0 +1,282 @@
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.BodyWormchainWasmAllowlistInstantiate{
ContractAddr: contractAddr,
CodeId: codeId,
}
payloadBz := payload.Serialize(vaa.ActionAddWasmInstantiateAllowlist)
v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz)
vBz, err := v.Marshal()
require.NoError(t, err)
vHex := hex.EncodeToString(vBz)
// add-wasm-instantiate-allowlist [bech32 contract addr] [codeId] [vaa-hex]
_, err = node.ExecTx(ctx, keyName, "wormhole", "add-wasm-instantiate-allowlist", contractBech32Addr, codeIdStr, vHex, "--gas", "auto")
require.NoError(t, err)
}
type IbcTranslatorInstantiateMsg struct {
TokenBridgeContract string `json:"token_bridge_contract"`
}
func IbcTranslatorContractInstantiateMsg(t *testing.T, tbContract string) string {
msg := IbcTranslatorInstantiateMsg{
TokenBridgeContract: tbContract,
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return string(msgBz)
}
type IbcTranslatorSubmitUpdateChainToChannelMap struct {
SubmitUpdateChainToChannelMap SubmitUpdateChainToChannelMap `json:"submit_update_chain_to_channel_map"`
}
type SubmitUpdateChainToChannelMap struct {
Vaa []byte `json:"vaa"`
}
func SubmitUpdateChainToChannelMapMsg(t *testing.T, allowlistChainID uint16, allowlistChannel string, guardians *guardians.ValSet) string {
payload := new(bytes.Buffer)
module := vaa.LeftPadBytes("IbcTranslator", 32)
payload.Write(module.Bytes())
vaa.MustWrite(payload, binary.BigEndian, uint8(1))
vaa.MustWrite(payload, binary.BigEndian, uint16(0))
channelPadded := vaa.LeftPadBytes(allowlistChannel, 64)
payload.Write(channelPadded.Bytes())
vaa.MustWrite(payload, binary.BigEndian, allowlistChainID)
v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payload.Bytes())
vBz, err := v.Marshal()
require.NoError(t, err)
msg := IbcTranslatorSubmitUpdateChainToChannelMap{
SubmitUpdateChainToChannelMap: SubmitUpdateChainToChannelMap{
Vaa: vBz,
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return string(msgBz)
}
type IbcTranslatorCompleteTransferAndConvert struct {
CompleteTransferAndConvert CompleteTransferAndConvert `json:"complete_transfer_and_convert"`
}
type CompleteTransferAndConvert struct {
Vaa []byte `json:"vaa"`
}
// TODO: replace amount's uint64 with big int or equivalent
func CreatePayload1(amount uint64, tokenAddr string, tokenChain uint16, recipient []byte, recipientChain uint16, fee uint64) []byte {
payload := new(bytes.Buffer)
vaa.MustWrite(payload, binary.BigEndian, uint8(1)) // Payload 1: Transfer
payload.Write(make([]byte, 24))
vaa.MustWrite(payload, binary.BigEndian, amount)
tokenAddrPadded := vaa.LeftPadBytes(tokenAddr, 32)
payload.Write(tokenAddrPadded.Bytes())
vaa.MustWrite(payload, binary.BigEndian, tokenChain)
payload.Write(recipient)
vaa.MustWrite(payload, binary.BigEndian, recipientChain)
payload.Write(make([]byte, 24))
vaa.MustWrite(payload, binary.BigEndian, fee)
return payload.Bytes()
}
// TODO: replace amount's uint64 with big int or equivalent
func CreatePayload3(cfg ibc.ChainConfig, amount uint64, tokenAddr string, tokenChain uint16, recipient string, recipientChain uint16, from []byte, contractPayload []byte) []byte {
payload := new(bytes.Buffer)
vaa.MustWrite(payload, binary.BigEndian, uint8(3)) // Payload 3: TransferWithPayload
payload.Write(make([]byte, 24))
vaa.MustWrite(payload, binary.BigEndian, amount)
tokenAddrPadded := vaa.LeftPadBytes(tokenAddr, 32)
payload.Write(tokenAddrPadded.Bytes())
vaa.MustWrite(payload, binary.BigEndian, tokenChain)
recipientAddr := MustAccAddressFromBech32(recipient, cfg.Bech32Prefix)
payload.Write(recipientAddr.Bytes())
vaa.MustWrite(payload, binary.BigEndian, recipientChain)
payload.Write(from)
payload.Write(contractPayload)
return payload.Bytes()
}
func IbcTranslatorCompleteTransferAndConvertMsg(t *testing.T, emitterChainID uint16, emitterAddr string, payload []byte, guardians *guardians.ValSet) string {
emitterBz := [32]byte{}
eIndex := 32
for i := len(emitterAddr); i > 0; i-- {
emitterBz[eIndex-1] = emitterAddr[i-1]
eIndex--
}
v := generateVaa(0, guardians, vaa.ChainID(emitterChainID), vaa.Address(emitterBz), payload)
vBz, err := v.Marshal()
require.NoError(t, err)
msg := IbcTranslatorCompleteTransferAndConvert{
CompleteTransferAndConvert: CompleteTransferAndConvert{
Vaa: vBz,
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return string(msgBz)
}
type GatewayIbcTokenBridgePayloadTransfer struct {
GatewayTransfer GatewayTransfer `json:"gateway_transfer"`
}
type GatewayTransfer struct {
Chain uint16 `json:"chain"`
Recipient []byte `json:"recipient"`
Fee string `json:"fee"`
Nonce uint32 `json:"nonce"`
}
func CreateGatewayIbcTokenBridgePayloadTransfer(t *testing.T, chainID uint16, recipient string, fee uint64, nonce uint32) []byte {
msg := GatewayIbcTokenBridgePayloadTransfer{
GatewayTransfer: GatewayTransfer{
Chain: chainID,
Recipient: []byte(recipient),
Fee: fmt.Sprint(fee),
Nonce: nonce,
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return msgBz
}
type GatewayIbcTokenBridgePayloadTransferWithPayload struct {
GatewayTransferWithPayload GatewayTransferWithPayload `json:"gateway_transfer_with_payload"`
}
type GatewayTransferWithPayload struct {
Chain uint16 `json:"chain"`
Contract []byte `json:"contract"`
Payload []byte `json:"payload"`
Nonce uint32 `json:"nonce"`
}
func CreateGatewayIbcTokenBridgePayloadTransferWithPayload(t *testing.T, chainID uint16, contract string, payload []byte, nonce uint32) []byte {
msg := GatewayIbcTokenBridgePayloadTransferWithPayload{
GatewayTransferWithPayload: GatewayTransferWithPayload{
Chain: chainID,
Contract: []byte(contract),
Payload: payload,
Nonce: nonce,
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return msgBz
}
type IbcTranslatorQueryMsg struct {
IbcChannel QueryIbcChannel `json:"ibc_channel"`
}
type QueryIbcChannel struct {
ChainID uint16 `json:"chain_id"`
}
type IbcTranslatorQueryRspMsg struct {
Data *IbcTranslatorQueryRspObj `json:"data"`
}
type IbcTranslatorQueryRspObj struct {
Channel string `json:"channel,omitempty"`
}
type IbcComposabilityMwMemoGatewayTransfer struct {
GatewayIbcTokenBridgePayloadTransfer GatewayIbcTokenBridgePayloadTransfer `json:"gateway_ibc_token_bridge_payload"`
}
func CreateIbcComposabilityMwMemoGatewayTransfer(t *testing.T, chainID uint16, recipient []byte, fee uint64, nonce uint32) string {
msg := IbcComposabilityMwMemoGatewayTransfer{
GatewayIbcTokenBridgePayloadTransfer{
GatewayTransfer: GatewayTransfer{
Chain: chainID,
Recipient: recipient,
Fee: fmt.Sprint(fee),
Nonce: nonce,
},
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return string(msgBz)
}
type IbcComposabilityMwMemoGatewayTransferWithPayload struct {
GatewayIbcTokenBridgePayloadTransferWithPayload GatewayIbcTokenBridgePayloadTransferWithPayload `json:"gateway_ibc_token_bridge_payload"`
}
func CreateIbcComposabilityMwMemoGatewayTransferWithPayload(t *testing.T, chainID uint16, externalContract []byte, payload []byte, nonce uint32) string {
msg := IbcComposabilityMwMemoGatewayTransferWithPayload{
GatewayIbcTokenBridgePayloadTransferWithPayload{
GatewayTransferWithPayload: GatewayTransferWithPayload{
Chain: chainID,
Contract: externalContract,
Payload: payload,
Nonce: nonce,
},
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return string(msgBz)
}

View File

@ -0,0 +1,71 @@
package helpers
import (
"bytes"
"context"
"encoding/binary"
"encoding/hex"
"encoding/json"
"strconv"
"testing"
"github.com/strangelove-ventures/interchaintest/v4/chain/cosmos"
"github.com/stretchr/testify/require"
"github.com/wormhole-foundation/wormchain/interchaintest/guardians"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
)
func createWasmInstantiatePayload(code_id uint64, label string, json_msg string) []byte {
// governance message with sha3 of arguments to instantiate
// - code_id (big endian)
// - label
// - json_msg
expected_hash := vaa.CreateInstatiateCosmwasmContractHash(code_id, label, []byte(json_msg))
var payload bytes.Buffer
payload.Write(vaa.WasmdModule[:])
payload.Write([]byte{byte(vaa.ActionInstantiateContract)})
binary.Write(&payload, binary.BigEndian, uint16(vaa.ChainIDWormchain))
// custom payload
payload.Write(expected_hash[:])
return payload.Bytes()
}
func InstantiateContract(
t *testing.T,
ctx context.Context,
chain *cosmos.CosmosChain,
keyName string,
codeId string,
label string,
message string,
guardians *guardians.ValSet,
) (contract string) {
node := chain.GetFullNode()
code_id, err := strconv.ParseUint(codeId, 10, 64)
require.NoError(t, err)
payload := createWasmInstantiatePayload(code_id, label, message)
v := generateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload)
vBz, err := v.Marshal()
require.NoError(t, err)
vHex := hex.EncodeToString(vBz)
_, err = node.ExecTx(ctx, keyName, "wormhole", "instantiate", label, codeId, message, vHex, "--gas", "auto")
require.NoError(t, err)
stdout, _, err := node.ExecQuery(ctx, "wasm", "list-contract-by-code", codeId)
require.NoError(t, err)
contactsRes := QueryContractResponse{}
err = json.Unmarshal([]byte(stdout), &contactsRes)
require.NoError(t, err)
contractAddr := contactsRes.Contracts[len(contactsRes.Contracts)-1]
return contractAddr
}
type QueryContractResponse struct {
Contracts []string `json:"contracts"`
}

View File

@ -0,0 +1,52 @@
package helpers
import (
"bytes"
"context"
"encoding/binary"
"encoding/hex"
"strconv"
"testing"
"github.com/strangelove-ventures/interchaintest/v4/chain/cosmos"
"github.com/stretchr/testify/require"
"github.com/wormhole-foundation/wormchain/interchaintest/guardians"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
)
func createWasmMigrationPayload(code_id uint64, contractAddr string, json_msg string) []byte {
expected_hash := vaa.CreateMigrateCosmwasmContractHash(code_id, contractAddr, []byte(json_msg))
var payload bytes.Buffer
payload.Write(vaa.WasmdModule[:])
payload.Write([]byte{byte(vaa.ActionMigrateContract)})
binary.Write(&payload, binary.BigEndian, uint16(vaa.ChainIDWormchain))
// custom payload
payload.Write(expected_hash[:])
return payload.Bytes()
}
func MigrateContract(
t *testing.T,
ctx context.Context,
chain *cosmos.CosmosChain,
keyName string,
contractAddr string,
codeId string,
message string,
guardians *guardians.ValSet,
) {
node := chain.GetFullNode()
code_id, err := strconv.ParseUint(codeId, 10, 64)
require.NoError(t, err)
payload := createWasmMigrationPayload(code_id, contractAddr, message)
v := generateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload)
vBz, err := v.Marshal()
require.NoError(t, err)
vHex := hex.EncodeToString(vBz)
_, err = node.ExecTx(ctx, keyName, "wormhole", "migrate", contractAddr, codeId, message, vHex, "--gas", "auto")
require.NoError(t, err)
}

View File

@ -0,0 +1,76 @@
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)
}

View File

@ -0,0 +1,104 @@
package helpers
import (
"bytes"
"compress/gzip"
"context"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"testing"
"github.com/strangelove-ventures/interchaintest/v4/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v4/testutil"
"github.com/stretchr/testify/require"
"github.com/tendermint/crypto/sha3"
"github.com/wormhole-foundation/wormchain/interchaintest/guardians"
"github.com/wormhole-foundation/wormchain/x/wormhole/types"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
)
func createWasmStoreCodePayload(wasmBytes []byte) []byte {
// governance message with sha3 of wasmBytes as the payload
var hashWasm [32]byte
keccak := sha3.NewLegacyKeccak256()
keccak.Write(wasmBytes)
keccak.Sum(hashWasm[:0])
gov_msg := types.NewGovernanceMessage(vaa.WasmdModule, byte(vaa.ActionStoreCode), uint16(vaa.ChainIDWormchain), hashWasm[:])
return gov_msg.MarshalBinary()
}
// wormchaind tx wormhole store [wasm file] [vaa-hex] [flags]
func StoreContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, keyName string, fileLoc string, guardians *guardians.ValSet) (codeId string) {
node := chain.GetFullNode()
_, file := filepath.Split(fileLoc)
err := node.CopyFile(ctx, fileLoc, file)
require.NoError(t, err, fmt.Errorf("writing contract file to docker volume: %w", err))
content, err := os.ReadFile(fileLoc)
require.NoError(t, err)
// gzip the wasm file
if IsWasm(content) {
content, err = GzipIt(content)
require.NoError(t, err)
}
payload := createWasmStoreCodePayload(content)
v := generateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload)
vBz, err := v.Marshal()
require.NoError(t, err)
vHex := hex.EncodeToString(vBz)
_, err = node.ExecTx(ctx, keyName, "wormhole", "store", path.Join(node.HomeDir(), file), vHex, "--gas", "auto")
require.NoError(t, err)
err = testutil.WaitForBlocks(ctx, 2, node.Chain)
require.NoError(t, err)
stdoutBz, _, err := node.ExecQuery(ctx, "wasm", "list-code", "--reverse")
require.NoError(t, err)
res := CodeInfosResponse{}
err = json.Unmarshal(stdoutBz, &res)
require.NoError(t, err)
return res.CodeInfos[0].CodeID
}
// IsWasm checks if the file contents are of wasm binary
func IsWasm(input []byte) bool {
wasmIdent := []byte("\x00\x61\x73\x6D")
return bytes.Equal(input[:4], wasmIdent)
}
// GzipIt compresses the input ([]byte)
func GzipIt(input []byte) ([]byte, error) {
// Create gzip writer.
var b bytes.Buffer
w := gzip.NewWriter(&b)
_, err := w.Write(input)
if err != nil {
return nil, err
}
err = w.Close() // You must close this first to flush the bytes to the buffer.
if err != nil {
return nil, err
}
return b.Bytes(), nil
}
type CodeInfo struct {
CodeID string `json:"code_id"`
}
type CodeInfosResponse struct {
CodeInfos []CodeInfo `json:"code_infos"`
}

View File

@ -0,0 +1,149 @@
package helpers
import (
"bytes"
"encoding/binary"
"encoding/json"
"strconv"
"testing"
"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"
)
type TbInstantiateMsg struct {
GovChain uint16 `json:"gov_chain"`
GovAddress []byte `json:"gov_address"`
WormholeContract string `json:"wormhole_contract"`
WrappedAssetCodeId uint64 `json:"wrapped_asset_code_id"`
ChainId uint16 `json:"chain_id"`
NativeDenom string `json:"native_denom"`
NativeSymbol string `json:"native_symbol"`
NativeDecimals uint8 `json:"native_decimals"`
}
func TbContractInstantiateMsg(t *testing.T, cfg ibc.ChainConfig, whContract string, wrappedAssetCodeId string) string {
codeId, err := strconv.ParseUint(wrappedAssetCodeId, 10, 64)
require.NoError(t, err)
msg := TbInstantiateMsg{
GovChain: uint16(vaa.GovernanceChain),
GovAddress: vaa.GovernanceEmitter[:],
WormholeContract: whContract,
WrappedAssetCodeId: codeId,
ChainId: uint16(vaa.ChainIDWormchain),
NativeDenom: cfg.Denom,
NativeSymbol: "WORM",
NativeDecimals: 6,
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return string(msgBz)
}
type TbSubmitVaaMsg struct {
SubmitVaa SubmitVaa `json:"submit_vaa,omitempty"`
}
type SubmitVaa struct {
Data []byte `json:"data,omitempty"`
}
func TbRegisterChainMsg(t *testing.T, chainID uint16, emitterAddr string, guardians *guardians.ValSet) []byte {
emitterBz := [32]byte{}
eIndex := 32
for i := len(emitterAddr); i > 0; i-- {
emitterBz[eIndex-1] = emitterAddr[i-1]
eIndex--
}
bodyTbRegisterChain := vaa.BodyTokenBridgeRegisterChain{
Module: "TokenBridge",
ChainID: vaa.ChainID(chainID),
EmitterAddress: vaa.Address(emitterBz),
}
payload := bodyTbRegisterChain.Serialize()
v := generateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload)
vBz, err := v.Marshal()
require.NoError(t, err)
msg := TbSubmitVaaMsg{
SubmitVaa: SubmitVaa{
Data: vBz,
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return msgBz
}
func TbRegisterForeignAsset(t *testing.T, tokenAddr string, chainID uint16, emitterAddr string, decimals uint8, symbol string, name string, guardians *guardians.ValSet) []byte {
payload := new(bytes.Buffer)
vaa.MustWrite(payload, binary.BigEndian, uint8(2))
tokenAddrPadded := vaa.LeftPadBytes(tokenAddr, 32)
payload.Write(tokenAddrPadded.Bytes())
vaa.MustWrite(payload, binary.BigEndian, chainID)
vaa.MustWrite(payload, binary.BigEndian, decimals)
symbolPad := make([]byte, 32)
copy(symbolPad, []byte(symbol))
payload.Write(symbolPad)
namePad := make([]byte, 32)
copy(namePad, []byte(name))
payload.Write(namePad)
emitterBz := [32]byte{}
eIndex := 32
for i := len(emitterAddr); i > 0; i-- {
emitterBz[eIndex-1] = emitterAddr[i-1]
eIndex--
}
v := generateVaa(0, guardians, vaa.ChainID(chainID), vaa.Address(emitterBz), payload.Bytes())
vBz, err := v.Marshal()
require.NoError(t, err)
msg := TbSubmitVaaMsg{
SubmitVaa: SubmitVaa{
Data: vBz,
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return msgBz
}
type TbQueryMsg struct {
WrappedRegistry WrappedRegistry `json:"wrapped_registry"`
}
type WrappedRegistry struct {
Chain uint16 `json:"chain"`
Address []byte `json:"address"`
}
func CreateCW20Query(t *testing.T, chainID uint16, address string) TbQueryMsg {
addressBz := vaa.LeftPadBytes(address, 32)
msg := TbQueryMsg{
WrappedRegistry: WrappedRegistry{
Chain: chainID,
Address: addressBz.Bytes(),
},
}
return msg
}
type TbQueryRsp struct {
Data *TbQueryRspObj `json:"data,omitempty"`
}
type TbQueryRspObj struct {
Address string `json:"address"`
}

View File

@ -0,0 +1,47 @@
package helpers
import (
"fmt"
"strings"
"testing"
"github.com/strangelove-ventures/interchaintest/v4/chain/cosmos"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
func MustAccAddressFromBech32(address string, bech32Prefix string) sdk.AccAddress {
if len(strings.TrimSpace(address)) == 0 {
panic("empty address string is not allowed")
}
bz, err := sdk.GetFromBech32(address, bech32Prefix)
if err != nil {
panic(err)
}
err = sdk.VerifyAddressFormat(bz)
if err != nil {
panic(err)
}
return sdk.AccAddress(bz)
}
func FindEventAttribute(t *testing.T, chain *cosmos.CosmosChain, txHash string, eventType string, attributeKey string, attributeValue string) bool {
tx, err := chain.GetTransaction(txHash)
require.NoError(t, err)
for _, event := range tx.Events {
if event.Type == eventType {
for _, attribute := range event.Attributes {
if string(attribute.Key) == attributeKey && string(attribute.Value) == attributeValue {
fmt.Println("Found: ", eventType, " ", attributeKey, " ", attributeValue)
return true
}
}
}
}
fmt.Println("Not found: ", eventType, " ", attributeKey, " ", attributeValue, "!")
return false
}

View File

@ -0,0 +1,35 @@
package helpers
import (
"time"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
"github.com/wormhole-foundation/wormchain/interchaintest/guardians"
)
var latestSequence = 1
func signVaa(vaaToSign vaa.VAA, signers *guardians.ValSet) vaa.VAA {
for i, key := range signers.Vals {
vaaToSign.AddSignature(key.Priv, uint8(i))
}
return vaaToSign
}
func generateVaa(index uint32, signers *guardians.ValSet, emitterChain vaa.ChainID, emitterAddr vaa.Address, payload []byte) vaa.VAA {
v := vaa.VAA{
Version: uint8(1),
GuardianSetIndex: index,
Signatures: nil,
Timestamp: time.Unix(0, 0),
Nonce: uint32(1),
Sequence: uint64(latestSequence),
ConsistencyLevel: uint8(32),
EmitterChain: emitterChain,
EmitterAddress: emitterAddr,
Payload: payload,
}
latestSequence = latestSequence + 1
return signVaa(v, signers)
}

View File

@ -0,0 +1,54 @@
package helpers
import (
"encoding/json"
"testing"
"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"
)
type CoreInstantiateMsg struct {
GovChain uint16 `json:"gov_chain"`
GovAddress []byte `json:"gov_address"`
InitialGuardianSet GuardianSetInfo `json:"initial_guardian_set"`
GuardianSetExpirity uint64 `json:"guardian_set_expirity"`
ChainId uint16 `json:"chain_id"`
FeeDenom string `json:"fee_denom"`
}
type GuardianSetInfo struct {
Addresses []GuardianAddress `json:"addresses"`
ExpirationTime uint64 `json:"expiration_time"`
}
type GuardianAddress struct {
Bytes []byte `json:"bytes"`
}
func CoreContractInstantiateMsg(t *testing.T, cfg ibc.ChainConfig, guardians *guardians.ValSet) string {
guardianAddresses := []GuardianAddress{}
for i := 0; i < guardians.Total; i++ {
guardianAddresses = append(guardianAddresses, GuardianAddress{
Bytes: guardians.Vals[i].Addr,
})
}
msg := CoreInstantiateMsg{
GovChain: uint16(vaa.GovernanceChain),
GovAddress: vaa.GovernanceEmitter[:],
InitialGuardianSet: GuardianSetInfo{
Addresses: guardianAddresses,
ExpirationTime: 0,
},
GuardianSetExpirity: 86400,
ChainId: uint16(vaa.ChainIDWormchain),
FeeDenom: cfg.Denom,
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return string(msgBz)
}

View File

@ -0,0 +1,331 @@
package ictest
import (
"encoding/json"
"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"
)
// TestMalformedPayload tests the state of wormhole/osmosis chains when a GatewayIbcTokenBridge payload is malformed
// and what tokens are created
func TestMalformedPayload(t *testing.T) {
// Base setup
numVals := 1
guardians := guardians.CreateValSet(t, numVals)
chains := CreateChains(t, "v2.23.0", *guardians)
ctx, r, eRep, _ := BuildInterchain(t, chains)
// Chains
wormchain := chains[0].(*cosmos.CosmosChain)
gaia := chains[1].(*cosmos.CosmosChain)
osmosis := chains[2].(*cosmos.CosmosChain)
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)
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)
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))
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)
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)
// Allowlist worm/gaia chain id / channel
wormGaiaAllowlistMsg := helpers.SubmitUpdateChainToChannelMapMsg(t, GaiaChainID, wormToGaiaChannel.ChannelID, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, wormGaiaAllowlistMsg)
// Get Asset 1 CW20 contract address
var tbQueryRsp helpers.TbQueryRsp
tbQueryReq := helpers.CreateCW20Query(t, Asset1ChainID, Asset1ContractAddr)
wormchain.QueryContract(ctx, tbContractAddr, tbQueryReq, &tbQueryRsp)
cw20Address := tbQueryRsp.Data.Address
// Set up cw20 req/resp
var cw20QueryRsp helpers.Cw20WrappedQueryRsp
cw20QueryReq := helpers.Cw20WrappedQueryMsg{TokenInfo: helpers.Cw20TokenInfo{}}
// Get the Osmo/IBC denom of asset1
cw20AddressBz := helpers.MustAccAddressFromBech32(cw20Address, wormchain.Config().Bech32Prefix)
subdenom := base58.Encode(cw20AddressBz)
asset1TokenFactoryDenom := fmt.Sprint("factory/", ibcTranslatorContractAddr, "/", subdenom)
osmoAsset1Denom := transfertypes.GetPrefixedDenom("transfer", osmoToWormChannel.ChannelID, asset1TokenFactoryDenom)
osmoIbcAsset1Denom := transfertypes.ParseDenomTrace(osmoAsset1Denom).IBCDenom()
// ***************** Start of interesting test cases ***************************************************************************************
// # Test | Result |
// | Cw20 minted | TB minted | Final location |
// -----------------------------------------------------------------------------------------------------------------------------------------
// 1. GW Transfer: chain id isn't allowlisted | X (0) X (0) X (0) |
// 2. GW Transfer: recipient has invalid bech32 addr | + (100) + (100) wormchain (100) |
// 3. GW TransferWithPayload: recipient is valid, but not a contract | + (200) + (200) wormchain (200) |
// 4. GW TransferWithPayload: Memo malformed: ibc hooks: invalid "wasm" root keyword | + (300) + (300) osmosis (100) |
// 5. GW TransferWithPayload: Memo malformed: ibc hooks: invalid recipient (bech32 invalid) | + (400) + (400) wormchain (300) |
// 6. GW TransferWithPayload: Memo malformed: ibc hooks: invalid recipient (not a contract) | + (500) + (500) wormchain (400) |
// 7. GW TransferWithPayload: Memo malformed: ibc hooks: msg: invalid execute method | + (600) + (600) wormchain (500) |
// 8. GW TransferWithPayload: Memo malformed: ibc hooks: msg: invalid "forward to" recipient | + (700) + (700) wormchain (600) |
// -----------------------------------------------------------------------------------------------------------------------------------------
// Test 1 (GW Tranfer has 100 added to osmo chain id to make it denied / no chain id -> channel mapping)
simplePayload := helpers.CreateGatewayIbcTokenBridgePayloadTransfer(t, OsmoChainID+100, osmoUser1.Bech32Address(osmosis.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(), 100, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, simplePayload)
completeTransferAndConvertMsg := helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg)
err = testutil.WaitForBlocks(ctx, 1, wormchain, osmosis)
// Check the asset 1 CW20 total supply
wormchain.QueryContract(ctx, cw20Address, cw20QueryReq, &cw20QueryRsp)
require.Equal(t, "0", cw20QueryRsp.Data.TotalSupply, "Asset 1 CW20 total supply should be 0")
// Check ibc-translator asset 1 denom balance
asset1DenomBalance, err := wormchain.GetBalance(ctx, ibcTranslatorContractAddr, asset1TokenFactoryDenom)
require.NoError(t, err)
require.Equal(t, int64(0), asset1DenomBalance, "Ibc translator asset 1 denom balance should be 0")
// Test 2 (GW Transfer has a cosmos/gaia prefix for recipient address)
simplePayload = helpers.CreateGatewayIbcTokenBridgePayloadTransfer(t, OsmoChainID, osmoUser1.Bech32Address(gaia.Config().Bech32Prefix), 0, 1)
payload3 = helpers.CreatePayload3(wormchain.Config(), 100, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, simplePayload)
completeTransferAndConvertMsg = helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg)
err = testutil.WaitForBlocks(ctx, 20, wormchain, osmosis)
// Check the asset 1 CW20 total supply
wormchain.QueryContract(ctx, cw20Address, cw20QueryReq, &cw20QueryRsp)
require.Equal(t, "100", cw20QueryRsp.Data.TotalSupply, "Asset 1 CW20 total supply should be 100")
// Check ibc-translator asset 1 denom balance
asset1DenomBalance, err = wormchain.GetBalance(ctx, ibcTranslatorContractAddr, asset1TokenFactoryDenom)
require.NoError(t, err)
require.Equal(t, int64(100), asset1DenomBalance, "Ibc translator asset 1 denom balance should be 100")
// Test 3 (GW TransferWithPayload has osmo user1 as recipient and not a contract)
ibcHooksPayload := helpers.CreateIbcHooksMsg(t, ibcHooksContractAddr, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix))
contractControlledPayload := helpers.CreateGatewayIbcTokenBridgePayloadTransferWithPayload(t, OsmoChainID, osmoUser1.Bech32Address(osmosis.Config().Bech32Prefix), ibcHooksPayload, 1)
payload3 = helpers.CreatePayload3(wormchain.Config(), 100, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, contractControlledPayload)
completeTransferAndConvertMsg = helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg)
err = testutil.WaitForBlocks(ctx, 20, wormchain, osmosis)
// Check the asset 1 CW20 total supply
wormchain.QueryContract(ctx, cw20Address, cw20QueryReq, &cw20QueryRsp)
require.Equal(t, "200", cw20QueryRsp.Data.TotalSupply, "Asset 1 CW20 total supply should be 200")
// Check ibc-translator asset 1 denom balance
asset1DenomBalance, err = wormchain.GetBalance(ctx, ibcTranslatorContractAddr, asset1TokenFactoryDenom)
require.NoError(t, err)
require.Equal(t, int64(200), asset1DenomBalance, "Ibc translator asset 1 denom balance should be 200")
// Test 4 (GW TransferWithPayload - change wasm root in memo)
ibcHooksPayload = CreateInvalidIbcHooksMsgWasm(t, ibcHooksContractAddr, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix))
contractControlledPayload = helpers.CreateGatewayIbcTokenBridgePayloadTransferWithPayload(t, OsmoChainID, ibcHooksContractAddr, ibcHooksPayload, 1)
payload3 = helpers.CreatePayload3(wormchain.Config(), 100, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, contractControlledPayload)
completeTransferAndConvertMsg = helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg)
err = testutil.WaitForBlocks(ctx, 20, wormchain, osmosis)
// Check the asset 1 CW20 total supply
wormchain.QueryContract(ctx, cw20Address, cw20QueryReq, &cw20QueryRsp)
require.Equal(t, "300", cw20QueryRsp.Data.TotalSupply, "Asset 1 CW20 total supply should be 300")
// Check ibc-translator asset 1 denom balance
asset1DenomBalance, err = osmosis.GetBalance(ctx, ibcHooksContractAddr, osmoIbcAsset1Denom)
require.NoError(t, err)
require.Equal(t, int64(100), asset1DenomBalance, "Ibchooks asset 1 denom balance should be 100")
// Test 5 (GW TransferWithPayload's ibc hook payload has osmo user1 as recipient and not a contract)
cosmosIbcHooksContractAddr := swapBech32Prefix(ibcHooksContractAddr, osmosis.Config().Bech32Prefix, gaia.Config().Bech32Prefix)
ibcHooksPayload = helpers.CreateIbcHooksMsg(t, cosmosIbcHooksContractAddr, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix))
contractControlledPayload = helpers.CreateGatewayIbcTokenBridgePayloadTransferWithPayload(t, OsmoChainID, ibcHooksContractAddr, ibcHooksPayload, 1)
payload3 = helpers.CreatePayload3(wormchain.Config(), 100, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, contractControlledPayload)
completeTransferAndConvertMsg = helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg)
err = testutil.WaitForBlocks(ctx, 20, wormchain, osmosis)
// Check the asset 1 CW20 total supply
wormchain.QueryContract(ctx, cw20Address, cw20QueryReq, &cw20QueryRsp)
require.Equal(t, "400", cw20QueryRsp.Data.TotalSupply, "Asset 1 CW20 total supply should be 400")
// Check ibc-translator asset 1 denom balance
asset1DenomBalance, err = wormchain.GetBalance(ctx, ibcTranslatorContractAddr, asset1TokenFactoryDenom)
require.NoError(t, err)
require.Equal(t, int64(300), asset1DenomBalance, "Ibc translator asset 1 denom balance should be 300")
// Test 6 (GW TransferWithPayload's ibc hook payload has osmo user1 as recipient and not a contract)
ibcHooksPayload = helpers.CreateIbcHooksMsg(t, osmoUser1.Bech32Address(osmosis.Config().Bech32Prefix), osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix))
contractControlledPayload = helpers.CreateGatewayIbcTokenBridgePayloadTransferWithPayload(t, OsmoChainID, ibcHooksContractAddr, ibcHooksPayload, 1)
payload3 = helpers.CreatePayload3(wormchain.Config(), 100, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, contractControlledPayload)
completeTransferAndConvertMsg = helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg)
err = testutil.WaitForBlocks(ctx, 20, wormchain, osmosis)
// Check the asset 1 CW20 total supply
wormchain.QueryContract(ctx, cw20Address, cw20QueryReq, &cw20QueryRsp)
require.Equal(t, "500", cw20QueryRsp.Data.TotalSupply, "Asset 1 CW20 total supply should be 500")
// Check ibc-translator asset 1 denom balance
asset1DenomBalance, err = wormchain.GetBalance(ctx, ibcTranslatorContractAddr, asset1TokenFactoryDenom)
require.NoError(t, err)
require.Equal(t, int64(400), asset1DenomBalance, "Ibc translator asset 1 denom balance should be 400")
// Test 7 (GW TransferWithPayload has invalid execute method for ibc hooks contract)
ibcHooksPayload = CreateInvalidIbcHooksMsgExecute(t, ibcHooksContractAddr, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix))
contractControlledPayload = helpers.CreateGatewayIbcTokenBridgePayloadTransferWithPayload(t, OsmoChainID, ibcHooksContractAddr, ibcHooksPayload, 1)
payload3 = helpers.CreatePayload3(wormchain.Config(), 100, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, contractControlledPayload)
completeTransferAndConvertMsg = helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg)
err = testutil.WaitForBlocks(ctx, 20, wormchain, osmosis)
// Check the asset 1 CW20 total supply
wormchain.QueryContract(ctx, cw20Address, cw20QueryReq, &cw20QueryRsp)
require.Equal(t, "600", cw20QueryRsp.Data.TotalSupply, "Asset 1 CW20 total supply should be 600")
// Check ibc-translator asset 1 denom balance
asset1DenomBalance, err = wormchain.GetBalance(ctx, ibcTranslatorContractAddr, asset1TokenFactoryDenom)
require.NoError(t, err)
require.Equal(t, int64(500), asset1DenomBalance, "Ibc translator asset 1 denom balance should be 500")
// Test 8 (GW TransferWithPayload's ibc hook payload has recipient with cosmos/gaia bech32 prefix)
ibcHooksPayload = helpers.CreateIbcHooksMsg(t, ibcHooksContractAddr, osmoUser2.Bech32Address(gaia.Config().Bech32Prefix))
contractControlledPayload = helpers.CreateGatewayIbcTokenBridgePayloadTransferWithPayload(t, OsmoChainID, ibcHooksContractAddr, ibcHooksPayload, 1)
payload3 = helpers.CreatePayload3(wormchain.Config(), 100, Asset1ContractAddr, Asset1ChainID, ibcTranslatorContractAddr, uint16(vaa.ChainIDWormchain), externalSender, contractControlledPayload)
completeTransferAndConvertMsg = helpers.IbcTranslatorCompleteTransferAndConvertMsg(t, ExternalChainId, ExternalChainEmitterAddr, payload3, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, completeTransferAndConvertMsg)
err = testutil.WaitForBlocks(ctx, 20, wormchain, osmosis)
// Check the asset 1 CW20 total supply
wormchain.QueryContract(ctx, cw20Address, cw20QueryReq, &cw20QueryRsp)
require.Equal(t, "700", cw20QueryRsp.Data.TotalSupply, "Asset 1 CW20 total supply should be 700")
// Check ibc-translator asset 1 denom balance
asset1DenomBalance, err = wormchain.GetBalance(ctx, ibcTranslatorContractAddr, asset1TokenFactoryDenom)
require.NoError(t, err)
require.Equal(t, int64(600), asset1DenomBalance, "Ibc translator asset 1 denom balance should be 600")
}
type IbcHooksWasm struct {
Payload helpers.IbcHooksPayload `json:"was"` // invalid keyword
}
func CreateInvalidIbcHooksMsgWasm(t *testing.T, contract string, recipient string) []byte {
msg := IbcHooksWasm{
Payload: helpers.IbcHooksPayload{
Contract: contract,
Msg: helpers.IbcHooksExecute{
Forward: helpers.IbcHooksForward{
Recipient: recipient,
},
},
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return msgBz
}
type IbcHooks struct {
Payload IbcHooksPayload `json:"wasm"`
}
type IbcHooksPayload struct {
Contract string `json:"contract"`
Msg IbcHooksExecute `json:"msg"`
}
type IbcHooksExecute struct {
Forward helpers.IbcHooksForward `json:"forward_tokens1"` // invalid method
}
func CreateInvalidIbcHooksMsgExecute(t *testing.T, contract string, recipient string) []byte {
msg := IbcHooks{
Payload: IbcHooksPayload{
Contract: contract,
Msg: IbcHooksExecute{
Forward: helpers.IbcHooksForward{
Recipient: recipient,
},
},
},
}
msgBz, err := json.Marshal(msg)
require.NoError(t, err)
return msgBz
}
func swapBech32Prefix(address string, currentBech32Prefix string, newBech32Prefix string) string {
accAddr := helpers.MustAccAddressFromBech32(address, currentBech32Prefix)
return sdk.MustBech32ifyAddressBytes(newBech32Prefix, accAddr)
}

View File

@ -0,0 +1,279 @@
package ictest
import (
"context"
"encoding/json"
"fmt"
"testing"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/icza/dyno"
interchaintest "github.com/strangelove-ventures/interchaintest/v4"
"github.com/strangelove-ventures/interchaintest/v4/chain/cosmos/wasm"
"github.com/strangelove-ventures/interchaintest/v4/ibc"
"github.com/strangelove-ventures/interchaintest/v4/testreporter"
"github.com/wormhole-foundation/wormchain/interchaintest/guardians"
"github.com/wormhole-foundation/wormchain/interchaintest/helpers"
wormholetypes "github.com/wormhole-foundation/wormchain/x/wormhole/types"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
"github.com/docker/docker/client"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
)
var (
pathWormchainGaia = "wormchain-gaia" // Replace with 2nd cosmos chain supporting wormchain
genesisWalletAmount = int64(10_000_000)
votingPeriod = "10s"
maxDepositPeriod = "10s"
coinType = "118"
wormchainConfig = ibc.ChainConfig{
Type: "cosmos",
Name: "wormchain",
ChainID: "wormchain-1",
Images: []ibc.DockerImage{
{
Repository: "ghcr.io/strangelove-ventures/heighliner/wormchain",
UidGid: "1025:1025",
},
},
Bin: "wormchaind",
Bech32Prefix: "wormhole",
Denom: "uworm",
CoinType: coinType,
GasPrices: "0.00uworm",
GasAdjustment: 1.8,
TrustingPeriod: "112h",
NoHostMount: false,
EncodingConfig: wormchainEncoding(),
}
numFullNodes = 1
)
// wormchainEncoding registers the Wormchain specific module codecs so that the associated types and msgs
// will be supported when writing to the blocksdb sqlite database.
func wormchainEncoding() *simappparams.EncodingConfig {
cfg := wasm.WasmEncoding()
// register custom types
wormholetypes.RegisterInterfaces(cfg.InterfaceRegistry)
return cfg
}
func CreateChains(t *testing.T, wormchainVersion string, guardians guardians.ValSet) []ibc.Chain {
numWormchainVals := len(guardians.Vals)
wormchainConfig.Images[0].Version = wormchainVersion
// Create chain factory with wormchain
wormchainConfig.ModifyGenesis = ModifyGenesis(votingPeriod, maxDepositPeriod, guardians)
cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{
{
ChainName: "wormchain",
ChainConfig: wormchainConfig,
NumValidators: &numWormchainVals,
NumFullNodes: &numFullNodes,
},
{Name: "gaia", Version: "v10.0.1", ChainConfig: ibc.ChainConfig{
GasPrices: "0.0uatom",
}},
{
Name: "osmosis",
Version: "v15.1.2",
ChainConfig: ibc.ChainConfig{
ChainID: "osmosis-1002", // hardcoded handling in osmosis binary for osmosis-1, so need to override to something different.
GasPrices: "1.0uosmo",
EncodingConfig: wasm.WasmEncoding(),
},
},
})
// Get chains from the chain factory
chains, err := cf.Chains(t.Name())
require.NoError(t, err)
return chains
}
func BuildInterchain(t *testing.T, chains []ibc.Chain) (context.Context, ibc.Relayer, *testreporter.RelayerExecReporter, *client.Client) {
// Create a new Interchain object which describes the chains, relayers, and IBC connections we want to use
ic := interchaintest.NewInterchain()
for _, chain := range chains {
ic.AddChain(chain)
}
rep := testreporter.NewNopReporter()
eRep := rep.RelayerExecReporter(t)
wormGaiaPath := "wormgaia"
wormOsmoPath := "wormosmo"
ctx := context.Background()
client, network := interchaintest.DockerSetup(t)
r := interchaintest.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t)).Build(
t, client, network)
ic.AddRelayer(r, "relayer")
ic.AddLink(interchaintest.InterchainLink{
Chain1: chains[0], // Wormchain
Chain2: chains[1], // Gaia
Relayer: r,
Path: wormGaiaPath,
})
ic.AddLink(interchaintest.InterchainLink{
Chain1: chains[0], // Wormchain
Chain2: chains[2], // Osmosis
Relayer: r,
Path: wormOsmoPath,
})
err := ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{
TestName: t.Name(),
Client: client,
NetworkID: network,
SkipPathCreation: false,
BlockDatabaseFile: interchaintest.DefaultBlockDatabaseFilepath(),
})
require.NoError(t, err)
t.Cleanup(func() {
_ = ic.Close()
})
// Start the relayer
err = r.StartRelayer(ctx, eRep, wormGaiaPath, wormOsmoPath)
require.NoError(t, err)
t.Cleanup(
func() {
err := r.StopRelayer(ctx, eRep)
if err != nil {
t.Logf("an error occured while stopping the relayer: %s", err)
}
},
)
return ctx, r, eRep, client
}
// Modify the genesis file:
// * Goverance - i.e. voting period
// * Get generated val set
// * Get faucet address
// * 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) {
return func(chainConfig ibc.ChainConfig, genbz []byte) ([]byte, error) {
numVals := len(guardians.Vals)
g := make(map[string]interface{})
if err := json.Unmarshal(genbz, &g); err != nil {
return nil, fmt.Errorf("failed to unmarshal genesis file: %w", err)
}
// Modify gov
if err := dyno.Set(g, votingPeriod, "app_state", "gov", "voting_params", "voting_period"); err != nil {
return nil, fmt.Errorf("failed to set voting period in genesis json: %w", err)
}
if err := dyno.Set(g, maxDepositPeriod, "app_state", "gov", "deposit_params", "max_deposit_period"); err != nil {
return nil, fmt.Errorf("failed to set max deposit period in genesis json: %w", err)
}
if err := dyno.Set(g, chainConfig.Denom, "app_state", "gov", "deposit_params", "min_deposit", 0, "denom"); err != nil {
return nil, fmt.Errorf("failed to set min deposit in genesis json: %w", err)
}
// Get validators
var validators [][]byte
for i := 0; i < numVals; i++ {
validatorBech32, err := dyno.Get(g, "app_state", "genutil", "gen_txs", i, "body", "messages", 0, "delegator_address")
if err != nil {
return nil, fmt.Errorf("failed to get validator pub key: %w", err)
}
validatorAccAddr := helpers.MustAccAddressFromBech32(validatorBech32.(string), chainConfig.Bech32Prefix).Bytes()
validators = append(validators, validatorAccAddr)
}
// Get faucet address
faucetAddress, err := dyno.Get(g, "app_state", "auth", "accounts", numVals, "address")
// Get relayer address
relayerAddress, err := dyno.Get(g, "app_state", "auth", "accounts", numVals+1, "address")
// Set guardian set list and validators
guardianSetList := []GuardianSet{}
guardianSet := GuardianSet{
Index: 0,
Keys: [][]byte{},
}
guardianValidators := []GuardianValidator{}
for i := 0; i < numVals; i++ {
guardianSet.Keys = append(guardianSet.Keys, guardians.Vals[i].Addr)
guardianValidators = append(guardianValidators, GuardianValidator{
GuardianKey: guardians.Vals[i].Addr,
ValidatorAddr: validators[i],
})
}
guardianSetList = append(guardianSetList, guardianSet)
if err := dyno.Set(g, guardianSetList, "app_state", "wormhole", "guardianSetList"); err != nil {
return nil, fmt.Errorf("failed to set guardian set list: %w", err)
}
if err := dyno.Set(g, guardianValidators, "app_state", "wormhole", "guardianValidatorList"); err != nil {
return nil, fmt.Errorf("failed to set guardian validator list: %w", err)
}
allowedAddresses := []ValidatorAllowedAddress{}
allowedAddresses = append(allowedAddresses, ValidatorAllowedAddress{
ValidatorAddress: sdk.MustBech32ifyAddressBytes(chainConfig.Bech32Prefix, validators[0]),
AllowedAddress: faucetAddress.(string),
Name: "Faucet",
})
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)
}
config := wormholetypes.Config{
GuardianSetExpiration: 86400,
GovernanceEmitter: vaa.GovernanceEmitter[:],
GovernanceChain: uint32(vaa.GovernanceChain),
ChainId: uint32(vaa.ChainIDWormchain),
}
if err := dyno.Set(g, config, "app_state", "wormhole", "config"); err != nil {
return nil, fmt.Errorf("failed to set guardian validator list: %w", err)
}
out, err := json.Marshal(g)
if err != nil {
return nil, fmt.Errorf("failed to marshal genesis bytes to json: %w", err)
}
fmt.Println("Genesis: ", string(out))
return out, nil
}
}
// Replace these with reference to x/wormchain/types
type GuardianSet struct {
Index uint32 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"`
Keys [][]byte `protobuf:"bytes,2,rep,name=keys,proto3" json:"keys,omitempty"`
ExpirationTime uint64 `protobuf:"varint,3,opt,name=expirationTime,proto3" json:"expirationTime,omitempty"`
}
type ValidatorAllowedAddress struct {
// the validator/guardian that controls this entry
ValidatorAddress string `protobuf:"bytes,1,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"`
// the allowlisted account
AllowedAddress string `protobuf:"bytes,2,opt,name=allowed_address,json=allowedAddress,proto3" json:"allowed_address,omitempty"`
// human readable name
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
}
type GuardianValidator struct {
GuardianKey []byte `protobuf:"bytes,1,opt,name=guardianKey,proto3" json:"guardianKey,omitempty"`
ValidatorAddr []byte `protobuf:"bytes,2,opt,name=validatorAddr,proto3" json:"validatorAddr,omitempty"`
}

View File

@ -0,0 +1,75 @@
package ictest
import (
"context"
"fmt"
"testing"
"time"
"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"
)
// TestUpgradeFailure starts wormchain on v2.18.1, then attempts to upgrade 1 validator at a time to v2.23.0
func TestUpgradeFailure(t *testing.T) {
// Base setup
numVals := 5
guardians := guardians.CreateValSet(t, numVals)
chains := CreateChains(t, "v2.18.1", *guardians)
ctx, _, _, client := BuildInterchain(t, chains)
// Chains
wormchain := chains[0].(*cosmos.CosmosChain)
blocksAfterUpgrade := uint64(5)
// upgrade version on all nodes
wormchain.UpgradeVersion(ctx, client, "v2.23.0")
for i := 0; i < numVals; i++ {
haltHeight, err := wormchain.Height(ctx)
require.NoError(t, err)
fmt.Println("Halt height:", i, " : ", haltHeight)
// bring down node to prepare for upgrade
err = wormchain.StopANode(ctx, i)
require.NoError(t, err, "error stopping node(s)")
// start node back up with new binary
err = wormchain.StartANode(ctx, i)
require.NoError(t, err, "error starting upgraded node(s)")
// Restart the fullnode with the last validator
if i+1 == numVals {
err = wormchain.StopANode(ctx, i+1)
require.NoError(t, err, "error stopping node(s)")
err = wormchain.StartANode(ctx, i+1)
require.NoError(t, err, "error starting upgraded node(s)")
}
timeoutCtx, timeoutCtxCancel := context.WithTimeout(ctx, time.Second*20)
defer timeoutCtxCancel()
// Wait for 5 blocks (2sec/block) or 20 seconds
testutil.WaitForBlocks(timeoutCtx, int(blocksAfterUpgrade), wormchain)
}
// Get current height
height1, err := wormchain.Height(ctx)
require.NoError(t, err)
timeoutCtx, timeoutCtxCancel := context.WithTimeout(ctx, time.Second*20)
defer timeoutCtxCancel()
// Wait for 5 blocks (2sec/block) or 20 seconds
testutil.WaitForBlocks(timeoutCtx, int(blocksAfterUpgrade), wormchain)
height2, err := wormchain.Height(ctx)
require.NoError(t, err, "error fetching height after upgrade")
fmt.Println("Checked height: ", height2)
// height1 and height2 should be equal since we don't produce blocks with this upgrade path
require.Equal(t, height1, height2, "height incremented after upgrade, so upgrade succeeded and test failed")
}

View File

@ -0,0 +1,392 @@
package ictest
import (
"context"
"fmt"
"strconv"
"testing"
"time"
"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"
)
// TestUpgradeTest upgrades from v2.18.1 -> v2.18.1.1 -> V2.23.0 and:
// - Setup wormchain, gaia, and osmosis including contracts/allowlists/etc
// - External->Cosmos: Send 10.000_018 to gaia user 1 (simple)
// - External->Cosmos: Send 1.000_001 to osmo user 1 (simple)
// - External->Cosmos: Send 1.000_002 to osmo user 2 (contract controlled via osmo ibc-hooks contract)
// - Cosmos->External: Send 1.000_003 to external address (simple) from gaia user 1
// -- gaia user 1 now has 9.000_015 of asset 1
// - Cosmos->External: Send 1.000_004 to external address (contract controlled) from gaia user 1
// -- gaia user 1 now has 8.000_011 of asset 1
// - Cosmos->Cosmos: Send 1.000_005 to osmo user 1 (simple) from gaia user 1
// -- gaia user 1 now has 7.000_006 of asset 1
// -- osmo user 1 now has 2.000_006 of asset 1
// - Cosmos->Cosmos: Send 1.000_006 to osmo user 2 (contract controlled via osmo ibc-hooks contract) from gaia user 1
// -- gaia user 1 now has 6.000_000 of asset 1
// -- osmo user 2 now has 2.000_008 of asset 1
// - Verify asset 1 balance of gaia user 1, osmo user 1, osmo user 2, and cw20 contract total supply
func TestUpgrade(t *testing.T) {
// Base setup
numVals := 5
guardians := guardians.CreateValSet(t, numVals)
chains := CreateChains(t, "v2.18.1", *guardians)
ctx, r, eRep, client := 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]
// *************************************************************
// ********* Upgrade to new version of wormchain ***************
// *************************************************************
blocksAfterUpgrade := uint64(5)
// upgrade version on all nodes
wormchain.UpgradeVersion(ctx, client, "v2.18.1.1")
for i := 0; i < numVals; i++ {
haltHeight, err := wormchain.Height(ctx)
require.NoError(t, err)
fmt.Println("Halt height:", i, " : ", haltHeight)
// bring down nodes to prepare for upgrade
err = wormchain.StopANode(ctx, i)
require.NoError(t, err, "error stopping node(s)")
// start all nodes back up.
// validators reach consensus on first block after upgrade height
// and chain block production resumes.
err = wormchain.StartANode(ctx, i)
require.NoError(t, err, "error starting upgraded node(s)")
// Restart the fullnode with the last validator
if i+1 == numVals {
err = wormchain.StopANode(ctx, i+1)
require.NoError(t, err, "error stopping node(s)")
err = wormchain.StartANode(ctx, i+1)
require.NoError(t, err, "error starting upgraded node(s)")
}
timeoutCtx, timeoutCtxCancel := context.WithTimeout(ctx, time.Second*45)
defer timeoutCtxCancel()
err = testutil.WaitForBlocks(timeoutCtx, int(blocksAfterUpgrade), wormchain)
require.NoError(t, err, "chain did not produce blocks after upgrade1")
height, err := wormchain.Height(ctx)
require.NoError(t, err, "error fetching height after upgrade")
fmt.Println("Checked height: ", height)
require.GreaterOrEqual(t, height, haltHeight+blocksAfterUpgrade, "height did not increment enough after upgrade")
}
fmt.Println("***** PASS upgrade #1 **********")
// --------------------------------------------------------------------------------------
// upgrade version on all nodes
blocksAfterUpgrade = uint64(10)
height, err := wormchain.Height(ctx)
require.NoError(t, err, "error fetching height before upgrade")
fmt.Println("Height at sending schedule upgrade: ", height)
haltHeight := height + blocksAfterUpgrade
fmt.Println("Height for scheduled upgrade: ", haltHeight)
helpers.ScheduleUpgrade(t, ctx, wormchain, "faucet", "v2.23.0", haltHeight, guardians)
timeoutCtx3, timeoutCtxCancel3 := context.WithTimeout(ctx, time.Second*45)
defer timeoutCtxCancel3()
// this should timeout due to chain halt at upgrade height.
testutil.WaitForBlocks(timeoutCtx3, int(blocksAfterUpgrade)+2, wormchain)
height, err = wormchain.Height(ctx)
require.NoError(t, err, "error fetching height after chain should have halted")
fmt.Println("Height when chains should have halted: ", height)
require.Equal(t, haltHeight, height, "height is not equal to halt height")
// bring down nodes to prepare for upgrade
err = wormchain.StopAllNodes(ctx)
require.NoError(t, err, "error stopping node(s)")
// upgrade version on all nodes
wormchain.UpgradeVersion(ctx, client, "v2.23.0")
// start all nodes back up.
// validators reach consensus on first block after upgrade height
// and chain block production resumes.
err = wormchain.StartAllNodes(ctx)
require.NoError(t, err, "error starting upgraded node(s)")
timeoutCtx4, timeoutCtxCancel4 := context.WithTimeout(ctx, time.Second*45)
defer timeoutCtxCancel4()
err = testutil.WaitForBlocks(timeoutCtx4, int(blocksAfterUpgrade)+1, wormchain)
require.NoError(t, err, "chain did not produce blocks after upgrade")
height, err = wormchain.Height(ctx)
require.NoError(t, err, "error fetching height after upgrade")
fmt.Println("Height after upgrade >10 blocks after scheduled halt: ", height)
require.GreaterOrEqual(t, height, haltHeight+blocksAfterUpgrade, "height did not increment enough after upgrade")
fmt.Println("***** PASS 2nd upgrade **********")
// *************************************************************
// ******************* Continue with test **********************
// *************************************************************
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)
err = testutil.WaitForBlocks(ctx, 2, wormchain)
require.NoError(t, err, "error waiting for 2 blocks")
// 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)
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))
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)
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)
// Allowlist worm/gaia chain id / channel
wormGaiaAllowlistMsg := helpers.SubmitUpdateChainToChannelMapMsg(t, GaiaChainID, wormToGaiaChannel.ChannelID, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, wormGaiaAllowlistMsg)
// 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)
// 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)
// 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)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 10, wormchain, gaia)
require.NoError(t, err)
// Query the CW20 address of asset1
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)
// Get the Gaia/IBC denom of asset1
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()
// Get the Osmo/IBC denom of asset1
osmoAsset1Denom := transfertypes.GetPrefixedDenom("transfer", osmoToWormChannel.ChannelID, tokenFactoryDenom)
osmoIbcAsset1Denom := transfertypes.ParseDenomTrace(osmoAsset1Denom).IBCDenom()
// Verify Gaia user 1 has expected asset 1 balance
gaiaUser1Asset1BalanceTemp, err := gaia.GetBalance(ctx, gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), gaiaIbcAsset1Denom)
require.NoError(t, err)
fmt.Println("Gaia user asset1 coins: ", gaiaUser1Asset1BalanceTemp)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 2, wormchain, gaia)
require.NoError(t, err)
// Verify Gaia user 1 has expected asset 1 balance
gaiaUser1Asset1BalanceTemp, err = gaia.GetBalance(ctx, gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), gaiaIbcAsset1Denom)
require.NoError(t, err)
fmt.Println("Gaia user asset1 coins: ", gaiaUser1Asset1BalanceTemp)
// ************* Cosmos->External: Simple payload (wormhole-mw + ibc-hooks) ****************
// Send 1.000_003 asset 1 from gaia user 1 to external
simpleMemo := helpers.CreateIbcComposabilityMwMemoGatewayTransfer(t, Asset1ChainID, externalSender, 0, 1)
transfer := ibc.WalletAmount{
Address: ibcTranslatorContractAddr,
Denom: gaiaIbcAsset1Denom,
Amount: int64(AmountGaiaUser1ToExternalSimple),
}
_, err = gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{Memo: simpleMemo})
require.NoError(t, err)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 2, wormchain, gaia)
require.NoError(t, err)
// ************* Cosmos->External: Contract controlled payload (wormhole-mw + ibc-hooks) ****************
// Send 1.000_004 asset 1 from gaia user 1 to external
ccIbcHooksMsg := helpers.CreateIbcComposabilityMwMemoGatewayTransferWithPayload(t, Asset1ChainID, externalSender, []byte("ExternalContractPayload"), 1)
transfer = ibc.WalletAmount{
Address: ibcTranslatorContractAddr,
Denom: gaiaIbcAsset1Denom,
Amount: int64(AmountGaiaUser1ToExternalCC),
}
_, err = gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{Memo: ccIbcHooksMsg})
require.NoError(t, err)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 2, wormchain, gaia)
require.NoError(t, err)
// ************** Cosmos->Cosmos: Simple payload (wormhole-mw + PFM) ****************
// Send 1.000_005 asset 1 from gaia user 1 to osmo user 1
simplePfmMsg := helpers.CreateIbcComposabilityMwMemoGatewayTransfer(t, OsmoChainID, []byte(osmoUser1.Bech32Address(osmosis.Config().Bech32Prefix)), 0, 1)
transfer = ibc.WalletAmount{
Address: wormchainFaucetAddr,
Denom: gaiaIbcAsset1Denom,
Amount: int64(AmountGaiaUser1ToOsmoUser1),
}
_, err = gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{
Timeout: &ibc.IBCTimeout{
NanoSeconds: 30_000_000_000,
},
Memo: simplePfmMsg,
})
require.NoError(t, err)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 2, wormchain, gaia)
require.NoError(t, err)
// ************** Cosmos->Cosmos: Contract controlled payload (wormhole-mw + PFM) ****************
// Send 1.000_006 asset 1 from gaia user 1 to osmo user 2
ccPayload := helpers.CreateIbcHooksMsg(t, ibcHooksContractAddr, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix))
ccPfmMsg := helpers.CreateIbcComposabilityMwMemoGatewayTransferWithPayload(t, OsmoChainID, []byte(ibcHooksContractAddr), ccPayload, 1)
transfer = ibc.WalletAmount{
Address: ibcTranslatorContractAddr,
Denom: gaiaIbcAsset1Denom,
Amount: int64(AmountGaiaUser1ToOsmoUser2),
}
_, err = gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{
Timeout: &ibc.IBCTimeout{
NanoSeconds: 30_000_000_000,
},
Memo: ccPfmMsg,
})
require.NoError(t, err)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 15, wormchain, gaia)
require.NoError(t, err)
// Verify Gaia user 1 has expected asset 1 balance
gaiaUser1Asset1Balance, err := gaia.GetBalance(ctx, gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), gaiaIbcAsset1Denom)
require.NoError(t, err)
expectedGaiaUser1Amount := AmountExternalToGaiaUser1 - AmountGaiaUser1ToExternalCC - AmountGaiaUser1ToExternalSimple - AmountGaiaUser1ToOsmoUser1 - AmountGaiaUser1ToOsmoUser2
require.Equal(t, int64(expectedGaiaUser1Amount), gaiaUser1Asset1Balance)
fmt.Println("Gaia user asset1 coins: ", gaiaUser1Asset1Balance)
// Verify osmo user 1 has expected asset 1 balance
osmoUser1Asset1Balance, err := osmosis.GetBalance(ctx, osmoUser1.Bech32Address(osmosis.Config().Bech32Prefix), osmoIbcAsset1Denom)
require.NoError(t, err)
require.Equal(t, int64(AmountExternalToOsmoUser1+AmountGaiaUser1ToOsmoUser1), osmoUser1Asset1Balance)
fmt.Println("Osmo user1 asset1 coins: ", osmoUser1Asset1Balance)
// Verify osmo user 2 has expected asset 1 balance
osmoUser2Asset1Balance, err := osmosis.GetBalance(ctx, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix), osmoIbcAsset1Denom)
require.NoError(t, err)
require.Equal(t, int64(AmountExternalToOsmoUser2+AmountGaiaUser1ToOsmoUser2), osmoUser2Asset1Balance)
fmt.Println("Osmo user2 asset1 coins: ", osmoUser2Asset1Balance)
// Verify asset 1 cw20 contract has expected final total supply
var cw20QueryRsp helpers.Cw20WrappedQueryRsp
cw20QueryReq := helpers.Cw20WrappedQueryMsg{TokenInfo: helpers.Cw20TokenInfo{}}
wormchain.QueryContract(ctx, cw20Address, cw20QueryReq, &cw20QueryRsp)
fmt.Println("Asset1 supply: ", cw20QueryRsp.Data.TotalSupply)
totalSupply, err := strconv.ParseUint(cw20QueryRsp.Data.TotalSupply, 10, 64)
require.NoError(t, err)
expectedTotalSupply := AmountExternalToGaiaUser1 + AmountExternalToOsmoUser1 + AmountExternalToOsmoUser2 - AmountGaiaUser1ToExternalSimple - AmountGaiaUser1ToExternalCC
require.Equal(t, uint64(expectedTotalSupply), totalSupply)
}

View File

@ -0,0 +1,326 @@
package ictest
import (
"fmt"
"strconv"
"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"
)
var (
GaiaChainID = uint16(11)
OsmoChainID = uint16(12)
ExternalChainId = uint16(123)
ExternalChainEmitterAddr = "0x123EmitterAddress"
Asset1Name = "Wrapped BTC"
Asset1Symbol = "XBTC"
Asset1ContractAddr = "0xXBTC"
Asset1ChainID = ExternalChainId
Asset1Decimals = uint8(6)
AmountExternalToGaiaUser1 = 10_000_018
AmountExternalToOsmoUser1 = 1_000_001
AmountExternalToOsmoUser2 = 1_000_002
AmountGaiaUser1ToExternalSimple = 1_000_003
AmountGaiaUser1ToExternalCC = 1_000_004
AmountGaiaUser1ToOsmoUser1 = 1_000_005
AmountGaiaUser1ToOsmoUser2 = 1_000_006
)
// TestWormchain runs through a simple test case for each deliverable
// - Setup wormchain, gaia, and osmosis including contracts/allowlists/etc
// - External->Cosmos: Send 10.000_018 to gaia user 1 (simple)
// - External->Cosmos: Send 1.000_001 to osmo user 1 (simple)
// - External->Cosmos: Send 1.000_002 to osmo user 2 (contract controlled via osmo ibc-hooks contract)
// - Cosmos->External: Send 1.000_003 to external address (simple) from gaia user 1
// -- gaia user 1 now has 9.000_015 of asset 1
// - Cosmos->External: Send 1.000_004 to external address (contract controlled) from gaia user 1
// -- gaia user 1 now has 8.000_011 of asset 1
// - Cosmos->Cosmos: Send 1.000_005 to osmo user 1 (simple) from gaia user 1
// -- gaia user 1 now has 7.000_006 of asset 1
// -- osmo user 1 now has 2.000_006 of asset 1
// - Cosmos->Cosmos: Send 1.000_006 to osmo user 2 (contract controlled via osmo ibc-hooks contract) from gaia user 1
// -- gaia user 1 now has 6.000_000 of asset 1
// -- osmo user 2 now has 2.000_008 of asset 1
// - Verify asset 1 balance of gaia user 1, osmo user 1, osmo user 2, and cw20 contract total supply
func TestWormchain(t *testing.T) {
// Base setup
numVals := 2
guardians := guardians.CreateValSet(t, numVals)
chains := CreateChains(t, "v2.23.0", *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)
err = testutil.WaitForBlocks(ctx, 2, wormchain)
require.NoError(t, err, "error waiting for 2 blocks")
// 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)
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))
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)
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)
// Allowlist worm/gaia chain id / channel
wormGaiaAllowlistMsg := helpers.SubmitUpdateChainToChannelMapMsg(t, GaiaChainID, wormToGaiaChannel.ChannelID, guardians)
_, err = wormchain.ExecuteContract(ctx, "faucet", ibcTranslatorContractAddr, wormGaiaAllowlistMsg)
// 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)
// 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)
// 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)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 10, wormchain, gaia)
require.NoError(t, err)
// Query the CW20 address of asset1
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)
// Get the Gaia/IBC denom of asset1
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()
// Get the Osmo/IBC denom of asset1
osmoAsset1Denom := transfertypes.GetPrefixedDenom("transfer", osmoToWormChannel.ChannelID, tokenFactoryDenom)
osmoIbcAsset1Denom := transfertypes.ParseDenomTrace(osmoAsset1Denom).IBCDenom()
// Verify Gaia user 1 has expected asset 1 balance
gaiaUser1Asset1BalanceTemp, err := gaia.GetBalance(ctx, gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), gaiaIbcAsset1Denom)
require.NoError(t, err)
fmt.Println("Gaia user asset1 coins: ", gaiaUser1Asset1BalanceTemp)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 2, wormchain, gaia)
require.NoError(t, err)
// Verify Gaia user 1 has expected asset 1 balance
gaiaUser1Asset1BalanceTemp, err = gaia.GetBalance(ctx, gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), gaiaIbcAsset1Denom)
require.NoError(t, err)
fmt.Println("Gaia user asset1 coins: ", gaiaUser1Asset1BalanceTemp)
// ************* Cosmos->External: Simple payload (wormhole-mw + ibc-hooks) ****************
// Send 1.000_003 asset 1 from gaia user 1 to external
simpleMemo := helpers.CreateIbcComposabilityMwMemoGatewayTransfer(t, Asset1ChainID, externalSender, 0, 1)
transfer := ibc.WalletAmount{
Address: ibcTranslatorContractAddr,
Denom: gaiaIbcAsset1Denom,
Amount: int64(AmountGaiaUser1ToExternalSimple),
}
_, err = gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{Memo: simpleMemo})
require.NoError(t, err)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 2, wormchain, gaia)
require.NoError(t, err)
// ************* Cosmos->External: Contract controlled payload (wormhole-mw + ibc-hooks) ****************
// Send 1.000_004 asset 1 from gaia user 1 to external
ccIbcHooksMsg := helpers.CreateIbcComposabilityMwMemoGatewayTransferWithPayload(t, Asset1ChainID, externalSender, []byte("ExternalContractPayload"), 1)
transfer = ibc.WalletAmount{
Address: ibcTranslatorContractAddr,
Denom: gaiaIbcAsset1Denom,
Amount: int64(AmountGaiaUser1ToExternalCC),
}
_, err = gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{Memo: ccIbcHooksMsg})
require.NoError(t, err)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 2, wormchain, gaia)
require.NoError(t, err)
// ************** Cosmos->Cosmos: Simple payload (wormhole-mw + PFM) ****************
// Send 1.000_005 asset 1 from gaia user 1 to osmo user 1
simplePfmMsg := helpers.CreateIbcComposabilityMwMemoGatewayTransfer(t, OsmoChainID, []byte(osmoUser1.Bech32Address(osmosis.Config().Bech32Prefix)), 0, 1)
transfer = ibc.WalletAmount{
Address: wormchainFaucetAddr,
Denom: gaiaIbcAsset1Denom,
Amount: int64(AmountGaiaUser1ToOsmoUser1),
}
_, err = gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{
Timeout: &ibc.IBCTimeout{
NanoSeconds: 30_000_000_000,
},
Memo: simplePfmMsg,
})
require.NoError(t, err)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 2, wormchain, gaia)
require.NoError(t, err)
// ************** Cosmos->Cosmos: Contract controlled payload (wormhole-mw + PFM) ****************
// Send 1.000_006 asset 1 from gaia user 1 to osmo user 2
ccPayload := helpers.CreateIbcHooksMsg(t, ibcHooksContractAddr, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix))
ccPfmMsg := helpers.CreateIbcComposabilityMwMemoGatewayTransferWithPayload(t, OsmoChainID, []byte(ibcHooksContractAddr), ccPayload, 1)
transfer = ibc.WalletAmount{
Address: ibcTranslatorContractAddr,
Denom: gaiaIbcAsset1Denom,
Amount: int64(AmountGaiaUser1ToOsmoUser2),
}
_, err = gaia.SendIBCTransfer(ctx, gaiaToWormChannel.ChannelID, gaiaUser.KeyName, transfer, ibc.TransferOptions{
Timeout: &ibc.IBCTimeout{
NanoSeconds: 30_000_000_000,
},
Memo: ccPfmMsg,
})
require.NoError(t, err)
// wait for transfer to ack
err = testutil.WaitForBlocks(ctx, 15, wormchain, gaia)
require.NoError(t, err)
// Verify Gaia user 1 has expected asset 1 balance
gaiaUser1Asset1Balance, err := gaia.GetBalance(ctx, gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), gaiaIbcAsset1Denom)
require.NoError(t, err)
expectedGaiaUser1Amount := AmountExternalToGaiaUser1 - AmountGaiaUser1ToExternalCC - AmountGaiaUser1ToExternalSimple - AmountGaiaUser1ToOsmoUser1 - AmountGaiaUser1ToOsmoUser2
require.Equal(t, int64(expectedGaiaUser1Amount), gaiaUser1Asset1Balance)
fmt.Println("Gaia user asset1 coins: ", gaiaUser1Asset1Balance)
// Verify osmo user 1 has expected asset 1 balance
osmoUser1Asset1Balance, err := osmosis.GetBalance(ctx, osmoUser1.Bech32Address(osmosis.Config().Bech32Prefix), osmoIbcAsset1Denom)
require.NoError(t, err)
require.Equal(t, int64(AmountExternalToOsmoUser1+AmountGaiaUser1ToOsmoUser1), osmoUser1Asset1Balance)
fmt.Println("Osmo user1 asset1 coins: ", osmoUser1Asset1Balance)
// Verify osmo user 2 has expected asset 1 balance
osmoUser2Asset1Balance, err := osmosis.GetBalance(ctx, osmoUser2.Bech32Address(osmosis.Config().Bech32Prefix), osmoIbcAsset1Denom)
require.NoError(t, err)
require.Equal(t, int64(AmountExternalToOsmoUser2+AmountGaiaUser1ToOsmoUser2), osmoUser2Asset1Balance)
fmt.Println("Osmo user2 asset1 coins: ", osmoUser2Asset1Balance)
// Verify asset 1 cw20 contract has expected final total supply
var cw20QueryRsp helpers.Cw20WrappedQueryRsp
cw20QueryReq := helpers.Cw20WrappedQueryMsg{TokenInfo: helpers.Cw20TokenInfo{}}
wormchain.QueryContract(ctx, cw20Address, cw20QueryReq, &cw20QueryRsp)
fmt.Println("Asset1 supply: ", cw20QueryRsp.Data.TotalSupply)
totalSupply, err := strconv.ParseUint(cw20QueryRsp.Data.TotalSupply, 10, 64)
require.NoError(t, err)
expectedTotalSupply := AmountExternalToGaiaUser1 + AmountExternalToOsmoUser1 + AmountExternalToOsmoUser2 - AmountGaiaUser1ToExternalSimple - AmountGaiaUser1ToExternalCC
require.Equal(t, uint64(expectedTotalSupply), totalSupply)
denomsMetadata := helpers.GetDenomsMetadata(t, ctx, wormchain)
fmt.Println("Denoms metadata: ", denomsMetadata)
}
type QueryMsg struct {
GuardianSetInfo *struct{} `json:"guardian_set_info,omitempty"`
}
type QueryRsp struct {
Data *QueryRspObj `json:"data,omitempty"`
}
type QueryRspObj struct {
GuardianSetIndex uint32 `json:"guardian_set_index"`
Addresses []helpers.GuardianAddress `json:"addresses"`
}