Repository: DA0-DA0/dao-contracts
Pull request #318 (2022-06-04 00:39:42)

Enable ibcv3 feature for cw-proposal-single contract
When we were trying to create a proposal with a create validator transaction, we found out that we dont currently support the `stargate` field in a [CosmosMsg](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.CosmosMsg.html).

I decided to enable the [ibc3 feature](https://github.com/CosmWasm/cosmwasm/blob/main/packages/std/Cargo.toml#L35), which includes the `stargate` features and the new ibcv3 interchain account stuff. 


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 0a297e01..65caaa6d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -170,13 +170,13 @@ dependencies = [
 
 [[package]]
 name = "cw-controllers"
-version = "0.13.2"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bc6d042b14823b0e9f33f5cdd67a1eb9b16a7d79f7547b1a73c8870b518b97b"
+checksum = "4f0bc6019b4d3d81e11f5c384bcce7173e2210bd654d75c6c9668e12cca05dfa"
 dependencies = [
  "cosmwasm-std",
- "cw-storage-plus",
- "cw-utils",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemars",
  "serde",
  "thiserror",
@@ -191,11 +191,11 @@ dependencies = [
  "cosmwasm-storage",
  "cw-core-interface",
  "cw-core-macros",
- "cw-multi-test",
+ "cw-multi-test 0.13.4 (git+https://github.com/CosmWasm/cw-plus?branch=main)",
  "cw-paginate",
  "cw-proposal-sudo",
- "cw-storage-plus",
- "cw-utils",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw20",
  "cw20-balance-voting",
@@ -233,15 +233,33 @@ dependencies = [
 
 [[package]]
 name = "cw-multi-test"
-version = "0.13.2"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cbea57e5be4a682268a5eca1a57efece57a54ff216bfd87603d5e864aad40e12"
+checksum = "a3f9a8ab7c3c29ec93cb7a39ce4b14a05e053153b4a17ef7cf2246af1b7c087e"
 dependencies = [
  "anyhow",
  "cosmwasm-std",
  "cosmwasm-storage",
- "cw-storage-plus",
- "cw-utils",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derivative",
+ "itertools",
+ "prost",
+ "schemars",
+ "serde",
+ "thiserror",
+]
+
+[[package]]
+name = "cw-multi-test"
+version = "0.13.4"
+source = "git+https://github.com/CosmWasm/cw-plus?branch=main#44852805788d9c76e3b1faa7a039d5a77c49007b"
+dependencies = [
+ "anyhow",
+ "cosmwasm-std",
+ "cosmwasm-storage",
+ "cw-storage-plus 0.13.4 (git+https://github.com/CosmWasm/cw-plus?branch=main)",
+ "cw-utils 0.13.4 (git+https://github.com/CosmWasm/cw-plus?branch=main)",
  "derivative",
  "itertools",
  "prost",
@@ -257,8 +275,8 @@ dependencies = [
  "cosmwasm-schema",
  "cosmwasm-std",
  "cosmwasm-storage",
- "cw-multi-test",
- "cw-storage-plus",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "schemars",
  "serde",
@@ -273,8 +291,8 @@ dependencies = [
  "cosmwasm-schema",
  "cosmwasm-std",
  "cosmwasm-storage",
- "cw-multi-test",
- "cw-storage-plus",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw20",
  "cw20-base",
@@ -289,8 +307,8 @@ version = "0.1.0"
 dependencies = [
  "cosmwasm-std",
  "cosmwasm-storage",
- "cw-multi-test",
- "cw-storage-plus",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde",
 ]
 
@@ -304,9 +322,9 @@ dependencies = [
  "cw-core",
  "cw-core-interface",
  "cw-core-macros",
- "cw-multi-test",
- "cw-storage-plus",
- "cw-utils",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw20",
  "cw20-balance-voting",
@@ -337,8 +355,8 @@ dependencies = [
  "cw-core",
  "cw-core-interface",
  "cw-core-macros",
- "cw-multi-test",
- "cw-storage-plus",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "schemars",
  "serde",
@@ -347,9 +365,19 @@ dependencies = [
 
 [[package]]
 name = "cw-storage-plus"
-version = "0.13.2"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9336ecef1e19d56cf6e3e932475fc6a3dee35eec5a386e07917a1d1ba6bb0e35"
+checksum = "648b1507290bbc03a8d88463d7cd9b04b1fa0155e5eef366c4fa052b9caaac7a"
+dependencies = [
+ "cosmwasm-std",
+ "schemars",
+ "serde",
+]
+
+[[package]]
+name = "cw-storage-plus"
+version = "0.13.4"
+source = "git+https://github.com/CosmWasm/cw-plus?branch=main#44852805788d9c76e3b1faa7a039d5a77c49007b"
 dependencies = [
  "cosmwasm-std",
  "schemars",
@@ -358,9 +386,20 @@ dependencies = [
 
 [[package]]
 name = "cw-utils"
-version = "0.13.2"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "babd2c090f39d07ce5bf2556962305e795daa048ce20a93709eb591476e4a29e"
+checksum = "9dbaecb78c8e8abfd6b4258c7f4fbeb5c49a5e45ee4d910d3240ee8e1d714e1b"
+dependencies = [
+ "cosmwasm-std",
+ "schemars",
+ "serde",
+ "thiserror",
+]
+
+[[package]]
+name = "cw-utils"
+version = "0.13.4"
+source = "git+https://github.com/CosmWasm/cw-plus?branch=main#44852805788d9c76e3b1faa7a039d5a77c49007b"
 dependencies = [
  "cosmwasm-std",
  "schemars",
@@ -370,24 +409,24 @@ dependencies = [
 
 [[package]]
 name = "cw2"
-version = "0.13.2"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "993df11574f29574dd443eb0c189484bb91bc0638b6de3e32ab7f9319c92122d"
+checksum = "04cf4639517490dd36b333bbd6c4fbd92e325fd0acf4683b41753bc5eb63bfc1"
 dependencies = [
  "cosmwasm-std",
- "cw-storage-plus",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemars",
  "serde",
 ]
 
 [[package]]
 name = "cw20"
-version = "0.13.2"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "356d364602c5fe763544ea00d485b825d6ef519a2fc6a3145528d7df3a603f40"
+checksum = "4cb782b8f110819a4eb5dbbcfed25ffba49ec16bbe32b4ad8da50a5ce68fec05"
 dependencies = [
  "cosmwasm-std",
- "cw-utils",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemars",
  "serde",
 ]
@@ -401,9 +440,9 @@ dependencies = [
  "cosmwasm-storage",
  "cw-core-interface",
  "cw-core-macros",
- "cw-multi-test",
- "cw-storage-plus",
- "cw-utils",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw20",
  "cw20-base",
@@ -414,13 +453,13 @@ dependencies = [
 
 [[package]]
 name = "cw20-base"
-version = "0.13.2"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b370e5fb6b35db58cabd7903b8f9bd4c3bcff701c63bf1a7185a84e60bfa502"
+checksum = "0306e606581f4fb45e82bcbb7f0333179ed53dd949c6523f01a99b4bfc1475a0"
 dependencies = [
  "cosmwasm-std",
- "cw-storage-plus",
- "cw-utils",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw20",
  "schemars",
@@ -437,9 +476,9 @@ dependencies = [
  "cosmwasm-storage",
  "cw-core-interface",
  "cw-core-macros",
- "cw-multi-test",
- "cw-storage-plus",
- "cw-utils",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw20",
  "cw20-base",
@@ -451,38 +490,38 @@ dependencies = [
 
 [[package]]
 name = "cw3"
-version = "0.13.2"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f871854338a54c7bb094d16ffe17212b93b146d9659dbce4c9402a9b77e240ef"
+checksum = "fe19462a7f644ba60c19d3443cb90d00c50d9b6b3b0a3a7fca93df8261af979b"
 dependencies = [
  "cosmwasm-std",
- "cw-utils",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemars",
  "serde",
 ]
 
 [[package]]
 name = "cw4"
-version = "0.13.2"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4476d6a7c13c46ed9ff260bd0e1cf648dc37b13f483822e1ff2a431f0f6ee52"
+checksum = "0acc3549d5ce11c6901b3a676f2e2628684722197054d97cd0101ea174ed5cbd"
 dependencies = [
  "cosmwasm-std",
- "cw-storage-plus",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemars",
  "serde",
 ]
 
 [[package]]
 name = "cw4-group"
-version = "0.13.2"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5503e4627160fc3c008cdb433df9392ea204c51259c0c58290c1e795db88c88e"
+checksum = "a6c95c89153e7831c8306c8eba40a3daa76f9c7b8f5179dd0b8628aca168ec7a"
 dependencies = [
  "cosmwasm-std",
  "cw-controllers",
- "cw-storage-plus",
- "cw-utils",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw4",
  "schemars",
@@ -499,9 +538,9 @@ dependencies = [
  "cosmwasm-storage",
  "cw-core-interface",
  "cw-core-macros",
- "cw-multi-test",
- "cw-storage-plus",
- "cw-utils",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw4",
  "cw4-group",
@@ -517,7 +556,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "72b9fd71276795554c35899bb3a378561ed0c288d231113e9915f6ee1f42b7b5"
 dependencies = [
  "cosmwasm-std",
- "cw-utils",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemars",
  "serde",
 ]
@@ -529,8 +568,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b61200af4e027af2d7485dbdc37c2a9c4093b6b2f2b811732329ef456076f97e"
 dependencies = [
  "cosmwasm-std",
- "cw-storage-plus",
- "cw-utils",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw721",
  "schemars",
@@ -704,7 +743,7 @@ name = "indexable-hooks"
 version = "0.1.0"
 dependencies = [
  "cosmwasm-std",
- "cw-storage-plus",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "schemars",
  "serde",
  "thiserror",
@@ -794,10 +833,10 @@ dependencies = [
  "cosmwasm-std",
  "cosmwasm-storage",
  "cw-core",
- "cw-multi-test",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw-proposal-single",
- "cw-storage-plus",
- "cw-utils",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw20",
  "cw20-balance-voting",
@@ -1029,9 +1068,9 @@ dependencies = [
  "cosmwasm-std",
  "cosmwasm-storage",
  "cw-controllers",
- "cw-multi-test",
- "cw-storage-plus",
- "cw-utils",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw20",
  "cw20-base",
@@ -1049,9 +1088,9 @@ dependencies = [
  "cosmwasm-std",
  "cosmwasm-storage",
  "cw-controllers",
- "cw-multi-test",
- "cw-storage-plus",
- "cw-utils",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw20",
  "cw20-base",
@@ -1068,9 +1107,9 @@ dependencies = [
  "cosmwasm-schema",
  "cosmwasm-std",
  "cosmwasm-storage",
- "cw-multi-test",
- "cw-storage-plus",
- "cw-utils",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-storage-plus 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cw-utils 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cw2",
  "cw20",
  "cw20-base",
@@ -1094,9 +1133,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
 
 [[package]]
 name = "syn"
-version = "1.0.95"
+version = "1.0.96"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
+checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1108,7 +1147,7 @@ name = "testing"
 version = "0.1.0"
 dependencies = [
  "cosmwasm-std",
- "cw-multi-test",
+ "cw-multi-test 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand",
  "voting",
 ]
diff --git a/contracts/cw-core/Cargo.toml b/contracts/cw-core/Cargo.toml
index cf59b78b..1639e505 100644
--- a/contracts/cw-core/Cargo.toml
+++ b/contracts/cw-core/Cargo.toml
@@ -29,7 +29,7 @@ optimize = """docker run --rm -v "$(pwd)":/code \
 """
 
 [dependencies]
-cosmwasm-std = { version = "1.0.0" }
+cosmwasm-std = { version = "1.0.0", features = ["ibc3"] }
 cosmwasm-storage = { version = "1.0.0" }
 cw-storage-plus = "0.13"
 cw2 = "0.13"
@@ -45,7 +45,8 @@ cw-paginate = { version = "0.1.0", path = "../../packages/cw-paginate" }
 
 [dev-dependencies]
 cosmwasm-schema = { version = "1.0.0" }
-cw-multi-test = "0.13"
+# TODO: We are using the main branch of cw-multi-test until the next release, because we need recent stargate parsing fixes
+cw-multi-test = { git = "https://github.com/CosmWasm/cw-plus", branch = "main",  features = ["stargate"] }
 cw20-base = "0.13"
 cw721-base = "0.13"
 cw-proposal-sudo = { version = "0.1.0", path = "../../debug/cw-proposal-sudo"}
diff --git a/contracts/cw-core/schema/execute_msg.json b/contracts/cw-core/schema/execute_msg.json
index da747260..7aee7c6e 100644
--- a/contracts/cw-core/schema/execute_msg.json
+++ b/contracts/cw-core/schema/execute_msg.json
@@ -521,6 +521,43 @@
           },
           "additionalProperties": false
         },
+        {
+          "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)",
+          "type": "object",
+          "required": [
+            "stargate"
+          ],
+          "properties": {
+            "stargate": {
+              "type": "object",
+              "required": [
+                "type_url",
+                "value"
+              ],
+              "properties": {
+                "type_url": {
+                  "type": "string"
+                },
+                "value": {
+                  "$ref": "#/definitions/Binary"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "required": [
+            "ibc"
+          ],
+          "properties": {
+            "ibc": {
+              "$ref": "#/definitions/IbcMsg"
+            }
+          },
+          "additionalProperties": false
+        },
         {
           "type": "object",
           "required": [
@@ -532,6 +569,18 @@
             }
           },
           "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "required": [
+            "gov"
+          ],
+          "properties": {
+            "gov": {
+              "$ref": "#/definitions/GovMsg"
+            }
+          },
+          "additionalProperties": false
         }
       ]
     },
@@ -662,6 +711,190 @@
       "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)",
       "type": "object"
     },
+    "GovMsg": {
+      "oneOf": [
+        {
+          "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.",
+          "type": "object",
+          "required": [
+            "vote"
+          ],
+          "properties": {
+            "vote": {
+              "type": "object",
+              "required": [
+                "proposal_id",
+                "vote"
+              ],
+              "properties": {
+                "proposal_id": {
+                  "type": "integer",
+                  "format": "uint64",
+                  "minimum": 0.0
+                },
+                "vote": {
+                  "$ref": "#/definitions/VoteOption"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        }
+      ]
+    },
+    "IbcMsg": {
+      "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)",
+      "oneOf": [
+        {
+          "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.",
+          "type": "object",
+          "required": [
+            "transfer"
+          ],
+          "properties": {
+            "transfer": {
+              "type": "object",
+              "required": [
+                "amount",
+                "channel_id",
+                "timeout",
+                "to_address"
+              ],
+              "properties": {
+                "amount": {
+                  "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/Coin"
+                    }
+                  ]
+                },
+                "channel_id": {
+                  "description": "exisiting channel to send the tokens over",
+                  "type": "string"
+                },
+                "timeout": {
+                  "description": "when packet times out, measured on remote chain",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/IbcTimeout"
+                    }
+                  ]
+                },
+                "to_address": {
+                  "description": "address on the remote chain to receive these tokens",
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.",
+          "type": "object",
+          "required": [
+            "send_packet"
+          ],
+          "properties": {
+            "send_packet": {
+              "type": "object",
+              "required": [
+                "channel_id",
+                "data",
+                "timeout"
+              ],
+              "properties": {
+                "channel_id": {
+                  "type": "string"
+                },
+                "data": {
+                  "$ref": "#/definitions/Binary"
+                },
+                "timeout": {
+                  "description": "when packet times out, measured on remote chain",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/IbcTimeout"
+                    }
+                  ]
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port",
+          "type": "object",
+          "required": [
+            "close_channel"
+          ],
+          "properties": {
+            "close_channel": {
+              "type": "object",
+              "required": [
+                "channel_id"
+              ],
+              "properties": {
+                "channel_id": {
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        }
+      ]
+    },
+    "IbcTimeout": {
+      "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.",
+      "type": "object",
+      "properties": {
+        "block": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/IbcTimeoutBlock"
+            },
+            {
+              "type": "null"
+            }
+          ]
+        },
+        "timestamp": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/Timestamp"
+            },
+            {
+              "type": "null"
+            }
+          ]
+        }
+      }
+    },
+    "IbcTimeoutBlock": {
+      "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)",
+      "type": "object",
+      "required": [
+        "height",
+        "revision"
+      ],
+      "properties": {
+        "height": {
+          "description": "block height after which the packet times out. the height within the given revision",
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        },
+        "revision": {
+          "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)",
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        }
+      }
+    },
     "ModuleInstantiateInfo": {
       "description": "Information needed to instantiate a proposal or voting module.",
       "type": "object",
@@ -784,10 +1017,31 @@
         }
       ]
     },
+    "Timestamp": {
+      "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```",
+      "allOf": [
+        {
+          "$ref": "#/definitions/Uint64"
+        }
+      ]
+    },
     "Uint128": {
       "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
       "type": "string"
     },
+    "Uint64": {
+      "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
+      "type": "string"
+    },
+    "VoteOption": {
+      "type": "string",
+      "enum": [
+        "yes",
+        "no",
+        "abstain",
+        "no_with_veto"
+      ]
+    },
     "WasmMsg": {
       "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto",
       "oneOf": [
diff --git a/contracts/cw-core/schema/migrate_msg.json b/contracts/cw-core/schema/migrate_msg.json
new file mode 100644
index 00000000..87b18ea7
--- /dev/null
+++ b/contracts/cw-core/schema/migrate_msg.json
@@ -0,0 +1,5 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "MigrateMsg",
+  "type": "object"
+}
diff --git a/contracts/cw-proposal-single/Cargo.toml b/contracts/cw-proposal-single/Cargo.toml
index f8fc6321..86f555eb 100644
--- a/contracts/cw-proposal-single/Cargo.toml
+++ b/contracts/cw-proposal-single/Cargo.toml
@@ -29,7 +29,7 @@ optimize = """docker run --rm -v "$(pwd)":/code \
 """
 
 [dependencies]
-cosmwasm-std = { version = "1.0.0" }
+cosmwasm-std = { version = "1.0.0", features = ["ibc3"] }
 cosmwasm-storage = { version = "1.0.0" }
 cw-storage-plus = "0.13"
 cw-utils = "0.13"
diff --git a/contracts/cw-proposal-single/schema/execute_msg.json b/contracts/cw-proposal-single/schema/execute_msg.json
index c21e013c..16b12b46 100644
--- a/contracts/cw-proposal-single/schema/execute_msg.json
+++ b/contracts/cw-proposal-single/schema/execute_msg.json
@@ -387,6 +387,43 @@
           },
           "additionalProperties": false
         },
+        {
+          "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)",
+          "type": "object",
+          "required": [
+            "stargate"
+          ],
+          "properties": {
+            "stargate": {
+              "type": "object",
+              "required": [
+                "type_url",
+                "value"
+              ],
+              "properties": {
+                "type_url": {
+                  "type": "string"
+                },
+                "value": {
+                  "$ref": "#/definitions/Binary"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "required": [
+            "ibc"
+          ],
+          "properties": {
+            "ibc": {
+              "$ref": "#/definitions/IbcMsg"
+            }
+          },
+          "additionalProperties": false
+        },
         {
           "type": "object",
           "required": [
@@ -398,6 +435,18 @@
             }
           },
           "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "required": [
+            "gov"
+          ],
+          "properties": {
+            "gov": {
+              "$ref": "#/definitions/GovMsg"
+            }
+          },
+          "additionalProperties": false
         }
       ]
     },
@@ -562,6 +611,190 @@
       "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)",
       "type": "object"
     },
+    "GovMsg": {
+      "oneOf": [
+        {
+          "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.",
+          "type": "object",
+          "required": [
+            "vote"
+          ],
+          "properties": {
+            "vote": {
+              "type": "object",
+              "required": [
+                "proposal_id",
+                "vote"
+              ],
+              "properties": {
+                "proposal_id": {
+                  "type": "integer",
+                  "format": "uint64",
+                  "minimum": 0.0
+                },
+                "vote": {
+                  "$ref": "#/definitions/VoteOption"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        }
+      ]
+    },
+    "IbcMsg": {
+      "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)",
+      "oneOf": [
+        {
+          "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.",
+          "type": "object",
+          "required": [
+            "transfer"
+          ],
+          "properties": {
+            "transfer": {
+              "type": "object",
+              "required": [
+                "amount",
+                "channel_id",
+                "timeout",
+                "to_address"
+              ],
+              "properties": {
+                "amount": {
+                  "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/Coin"
+                    }
+                  ]
+                },
+                "channel_id": {
+                  "description": "exisiting channel to send the tokens over",
+                  "type": "string"
+                },
+                "timeout": {
+                  "description": "when packet times out, measured on remote chain",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/IbcTimeout"
+                    }
+                  ]
+                },
+                "to_address": {
+                  "description": "address on the remote chain to receive these tokens",
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.",
+          "type": "object",
+          "required": [
+            "send_packet"
+          ],
+          "properties": {
+            "send_packet": {
+              "type": "object",
+              "required": [
+                "channel_id",
+                "data",
+                "timeout"
+              ],
+              "properties": {
+                "channel_id": {
+                  "type": "string"
+                },
+                "data": {
+                  "$ref": "#/definitions/Binary"
+                },
+                "timeout": {
+                  "description": "when packet times out, measured on remote chain",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/IbcTimeout"
+                    }
+                  ]
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port",
+          "type": "object",
+          "required": [
+            "close_channel"
+          ],
+          "properties": {
+            "close_channel": {
+              "type": "object",
+              "required": [
+                "channel_id"
+              ],
+              "properties": {
+                "channel_id": {
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        }
+      ]
+    },
+    "IbcTimeout": {
+      "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.",
+      "type": "object",
+      "properties": {
+        "block": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/IbcTimeoutBlock"
+            },
+            {
+              "type": "null"
+            }
+          ]
+        },
+        "timestamp": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/Timestamp"
+            },
+            {
+              "type": "null"
+            }
+          ]
+        }
+      }
+    },
+    "IbcTimeoutBlock": {
+      "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)",
+      "type": "object",
+      "required": [
+        "height",
+        "revision"
+      ],
+      "properties": {
+        "height": {
+          "description": "block height after which the packet times out. the height within the given revision",
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        },
+        "revision": {
+          "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)",
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        }
+      }
+    },
     "PercentageThreshold": {
       "description": "A percentage of voting power that must vote yes for a proposal to pass. An example of why this is needed:\n\nIf a user specifies a 60% passing threshold, and there are 10 voters they likely expect that proposal to pass when there are 6 yes votes. This implies that the condition for passing should be `yes_votes >= total_votes * threshold`.\n\nWith this in mind, how should a user specify that they would like proposals to pass if the majority of voters choose yes? Selecting a 50% passing threshold with those rules doesn't properly cover that case as 5 voters voting yes out of 10 would pass the proposal. Selecting 50.0001% or or some variation of that also does not work as a very small yes vote which technically makes the majority yes may not reach that threshold.\n\nTo handle these cases we provide both a majority and percent option for all percentages. If majority is selected passing will be determined by `yes > total_votes * 0.5`. If percent is selected passing is determined by `yes >= total_votes * percent`.\n\nIn both of these cases a proposal with only abstain votes must fail. This requires a special case passing logic.",
       "oneOf": [
@@ -749,10 +982,22 @@
         }
       ]
     },
+    "Timestamp": {
+      "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```",
+      "allOf": [
+        {
+          "$ref": "#/definitions/Uint64"
+        }
+      ]
+    },
     "Uint128": {
       "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
       "type": "string"
     },
+    "Uint64": {
+      "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
+      "type": "string"
+    },
     "Vote": {
       "type": "string",
       "enum": [
@@ -761,6 +1006,15 @@
         "abstain"
       ]
     },
+    "VoteOption": {
+      "type": "string",
+      "enum": [
+        "yes",
+        "no",
+        "abstain",
+        "no_with_veto"
+      ]
+    },
     "WasmMsg": {
       "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto",
       "oneOf": [
diff --git a/contracts/cw-proposal-single/schema/list_proposals_response.json b/contracts/cw-proposal-single/schema/list_proposals_response.json
index 909b0005..ade96a90 100644
--- a/contracts/cw-proposal-single/schema/list_proposals_response.json
+++ b/contracts/cw-proposal-single/schema/list_proposals_response.json
@@ -176,6 +176,43 @@
           },
           "additionalProperties": false
         },
+        {
+          "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)",
+          "type": "object",
+          "required": [
+            "stargate"
+          ],
+          "properties": {
+            "stargate": {
+              "type": "object",
+              "required": [
+                "type_url",
+                "value"
+              ],
+              "properties": {
+                "type_url": {
+                  "type": "string"
+                },
+                "value": {
+                  "$ref": "#/definitions/Binary"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "required": [
+            "ibc"
+          ],
+          "properties": {
+            "ibc": {
+              "$ref": "#/definitions/IbcMsg"
+            }
+          },
+          "additionalProperties": false
+        },
         {
           "type": "object",
           "required": [
@@ -187,6 +224,18 @@
             }
           },
           "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "required": [
+            "gov"
+          ],
+          "properties": {
+            "gov": {
+              "$ref": "#/definitions/GovMsg"
+            }
+          },
+          "additionalProperties": false
         }
       ]
     },
@@ -293,6 +342,190 @@
         }
       ]
     },
+    "GovMsg": {
+      "oneOf": [
+        {
+          "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.",
+          "type": "object",
+          "required": [
+            "vote"
+          ],
+          "properties": {
+            "vote": {
+              "type": "object",
+              "required": [
+                "proposal_id",
+                "vote"
+              ],
+              "properties": {
+                "proposal_id": {
+                  "type": "integer",
+                  "format": "uint64",
+                  "minimum": 0.0
+                },
+                "vote": {
+                  "$ref": "#/definitions/VoteOption"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        }
+      ]
+    },
+    "IbcMsg": {
+      "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)",
+      "oneOf": [
+        {
+          "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.",
+          "type": "object",
+          "required": [
+            "transfer"
+          ],
+          "properties": {
+            "transfer": {
+              "type": "object",
+              "required": [
+                "amount",
+                "channel_id",
+                "timeout",
+                "to_address"
+              ],
+              "properties": {
+                "amount": {
+                  "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/Coin"
+                    }
+                  ]
+                },
+                "channel_id": {
+                  "description": "exisiting channel to send the tokens over",
+                  "type": "string"
+                },
+                "timeout": {
+                  "description": "when packet times out, measured on remote chain",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/IbcTimeout"
+                    }
+                  ]
+                },
+                "to_address": {
+                  "description": "address on the remote chain to receive these tokens",
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.",
+          "type": "object",
+          "required": [
+            "send_packet"
+          ],
+          "properties": {
+            "send_packet": {
+              "type": "object",
+              "required": [
+                "channel_id",
+                "data",
+                "timeout"
+              ],
+              "properties": {
+                "channel_id": {
+                  "type": "string"
+                },
+                "data": {
+                  "$ref": "#/definitions/Binary"
+                },
+                "timeout": {
+                  "description": "when packet times out, measured on remote chain",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/IbcTimeout"
+                    }
+                  ]
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port",
+          "type": "object",
+          "required": [
+            "close_channel"
+          ],
+          "properties": {
+            "close_channel": {
+              "type": "object",
+              "required": [
+                "channel_id"
+              ],
+              "properties": {
+                "channel_id": {
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        }
+      ]
+    },
+    "IbcTimeout": {
+      "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.",
+      "type": "object",
+      "properties": {
+        "block": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/IbcTimeoutBlock"
+            },
+            {
+              "type": "null"
+            }
+          ]
+        },
+        "timestamp": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/Timestamp"
+            },
+            {
+              "type": "null"
+            }
+          ]
+        }
+      }
+    },
+    "IbcTimeoutBlock": {
+      "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)",
+      "type": "object",
+      "required": [
+        "height",
+        "revision"
+      ],
+      "properties": {
+        "height": {
+          "description": "block height after which the packet times out. the height within the given revision",
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        },
+        "revision": {
+          "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)",
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        }
+      }
+    },
     "PercentageThreshold": {
       "description": "A percentage of voting power that must vote yes for a proposal to pass. An example of why this is needed:\n\nIf a user specifies a 60% passing threshold, and there are 10 voters they likely expect that proposal to pass when there are 6 yes votes. This implies that the condition for passing should be `yes_votes >= total_votes * threshold`.\n\nWith this in mind, how should a user specify that they would like proposals to pass if the majority of voters choose yes? Selecting a 50% passing threshold with those rules doesn't properly cover that case as 5 voters voting yes out of 10 would pass the proposal. Selecting 50.0001% or or some variation of that also does not work as a very small yes vote which technically makes the majority yes may not reach that threshold.\n\nTo handle these cases we provide both a majority and percent option for all percentages. If majority is selected passing will be determined by `yes > total_votes * 0.5`. If percent is selected passing is determined by `yes >= total_votes * percent`.\n\nIn both of these cases a proposal with only abstain votes must fail. This requires a special case passing logic.",
       "oneOf": [
@@ -591,6 +824,15 @@
       "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
       "type": "string"
     },
+    "VoteOption": {
+      "type": "string",
+      "enum": [
+        "yes",
+        "no",
+        "abstain",
+        "no_with_veto"
+      ]
+    },
     "Votes": {
       "type": "object",
       "required": [
diff --git a/contracts/cw-proposal-single/schema/migrate_msg.json b/contracts/cw-proposal-single/schema/migrate_msg.json
new file mode 100644
index 00000000..87b18ea7
--- /dev/null
+++ b/contracts/cw-proposal-single/schema/migrate_msg.json
@@ -0,0 +1,5 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "MigrateMsg",
+  "type": "object"
+}
diff --git a/contracts/cw-proposal-single/schema/proposal_response.json b/contracts/cw-proposal-single/schema/proposal_response.json
index 5d106697..a0ef8ca5 100644
--- a/contracts/cw-proposal-single/schema/proposal_response.json
+++ b/contracts/cw-proposal-single/schema/proposal_response.json
@@ -179,6 +179,43 @@
           },
           "additionalProperties": false
         },
+        {
+          "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)",
+          "type": "object",
+          "required": [
+            "stargate"
+          ],
+          "properties": {
+            "stargate": {
+              "type": "object",
+              "required": [
+                "type_url",
+                "value"
+              ],
+              "properties": {
+                "type_url": {
+                  "type": "string"
+                },
+                "value": {
+                  "$ref": "#/definitions/Binary"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "required": [
+            "ibc"
+          ],
+          "properties": {
+            "ibc": {
+              "$ref": "#/definitions/IbcMsg"
+            }
+          },
+          "additionalProperties": false
+        },
         {
           "type": "object",
           "required": [
@@ -190,6 +227,18 @@
             }
           },
           "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "required": [
+            "gov"
+          ],
+          "properties": {
+            "gov": {
+              "$ref": "#/definitions/GovMsg"
+            }
+          },
+          "additionalProperties": false
         }
       ]
     },
@@ -296,6 +345,190 @@
         }
       ]
     },
+    "GovMsg": {
+      "oneOf": [
+        {
+          "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.",
+          "type": "object",
+          "required": [
+            "vote"
+          ],
+          "properties": {
+            "vote": {
+              "type": "object",
+              "required": [
+                "proposal_id",
+                "vote"
+              ],
+              "properties": {
+                "proposal_id": {
+                  "type": "integer",
+                  "format": "uint64",
+                  "minimum": 0.0
+                },
+                "vote": {
+                  "$ref": "#/definitions/VoteOption"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        }
+      ]
+    },
+    "IbcMsg": {
+      "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)",
+      "oneOf": [
+        {
+          "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.",
+          "type": "object",
+          "required": [
+            "transfer"
+          ],
+          "properties": {
+            "transfer": {
+              "type": "object",
+              "required": [
+                "amount",
+                "channel_id",
+                "timeout",
+                "to_address"
+              ],
+              "properties": {
+                "amount": {
+                  "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/Coin"
+                    }
+                  ]
+                },
+                "channel_id": {
+                  "description": "exisiting channel to send the tokens over",
+                  "type": "string"
+                },
+                "timeout": {
+                  "description": "when packet times out, measured on remote chain",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/IbcTimeout"
+                    }
+                  ]
+                },
+                "to_address": {
+                  "description": "address on the remote chain to receive these tokens",
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.",
+          "type": "object",
+          "required": [
+            "send_packet"
+          ],
+          "properties": {
+            "send_packet": {
+              "type": "object",
+              "required": [
+                "channel_id",
+                "data",
+                "timeout"
+              ],
+              "properties": {
+                "channel_id": {
+                  "type": "string"
+                },
+                "data": {
+                  "$ref": "#/definitions/Binary"
+                },
+                "timeout": {
+                  "description": "when packet times out, measured on remote chain",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/IbcTimeout"
+                    }
+                  ]
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port",
+          "type": "object",
+          "required": [
+            "close_channel"
+          ],
+          "properties": {
+            "close_channel": {
+              "type": "object",
+              "required": [
+                "channel_id"
+              ],
+              "properties": {
+                "channel_id": {
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        }
+      ]
+    },
+    "IbcTimeout": {
+      "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.",
+      "type": "object",
+      "properties": {
+        "block": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/IbcTimeoutBlock"
+            },
+            {
+              "type": "null"
+            }
+          ]
+        },
+        "timestamp": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/Timestamp"
+            },
+            {
+              "type": "null"
+            }
+          ]
+        }
+      }
+    },
+    "IbcTimeoutBlock": {
+      "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)",
+      "type": "object",
+      "required": [
+        "height",
+        "revision"
+      ],
+      "properties": {
+        "height": {
+          "description": "block height after which the packet times out. the height within the given revision",
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        },
+        "revision": {
+          "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)",
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        }
+      }
+    },
     "PercentageThreshold": {
       "description": "A percentage of voting power that must vote yes for a proposal to pass. An example of why this is needed:\n\nIf a user specifies a 60% passing threshold, and there are 10 voters they likely expect that proposal to pass when there are 6 yes votes. This implies that the condition for passing should be `yes_votes >= total_votes * threshold`.\n\nWith this in mind, how should a user specify that they would like proposals to pass if the majority of voters choose yes? Selecting a 50% passing threshold with those rules doesn't properly cover that case as 5 voters voting yes out of 10 would pass the proposal. Selecting 50.0001% or or some variation of that also does not work as a very small yes vote which technically makes the majority yes may not reach that threshold.\n\nTo handle these cases we provide both a majority and percent option for all percentages. If majority is selected passing will be determined by `yes > total_votes * 0.5`. If percent is selected passing is determined by `yes >= total_votes * percent`.\n\nIn both of these cases a proposal with only abstain votes must fail. This requires a special case passing logic.",
       "oneOf": [
@@ -576,6 +809,15 @@
       "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
       "type": "string"
     },
+    "VoteOption": {
+      "type": "string",
+      "enum": [
+        "yes",
+        "no",
+        "abstain",
+        "no_with_veto"
+      ]
+    },
     "Votes": {
       "type": "object",
       "required": [
diff --git a/contracts/cw-proposal-single/schema/reverse_proposals_response.json b/contracts/cw-proposal-single/schema/reverse_proposals_response.json
index d26586b2..fa543295 100644
--- a/contracts/cw-proposal-single/schema/reverse_proposals_response.json
+++ b/contracts/cw-proposal-single/schema/reverse_proposals_response.json
@@ -176,6 +176,43 @@
           },
           "additionalProperties": false
         },
+        {
+          "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)",
+          "type": "object",
+          "required": [
+            "stargate"
+          ],
+          "properties": {
+            "stargate": {
+              "type": "object",
+              "required": [
+                "type_url",
+                "value"
+              ],
+              "properties": {
+                "type_url": {
+                  "type": "string"
+                },
+                "value": {
+                  "$ref": "#/definitions/Binary"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "required": [
+            "ibc"
+          ],
+          "properties": {
+            "ibc": {
+              "$ref": "#/definitions/IbcMsg"
+            }
+          },
+          "additionalProperties": false
+        },
         {
           "type": "object",
           "required": [
@@ -187,6 +224,18 @@
             }
           },
           "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "required": [
+            "gov"
+          ],
+          "properties": {
+            "gov": {
+              "$ref": "#/definitions/GovMsg"
+            }
+          },
+          "additionalProperties": false
         }
       ]
     },
@@ -293,6 +342,190 @@
         }
       ]
     },
+    "GovMsg": {
+      "oneOf": [
+        {
+          "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.",
+          "type": "object",
+          "required": [
+            "vote"
+          ],
+          "properties": {
+            "vote": {
+              "type": "object",
+              "required": [
+                "proposal_id",
+                "vote"
+              ],
+              "properties": {
+                "proposal_id": {
+                  "type": "integer",
+                  "format": "uint64",
+                  "minimum": 0.0
+                },
+                "vote": {
+                  "$ref": "#/definitions/VoteOption"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        }
+      ]
+    },
+    "IbcMsg": {
+      "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)",
+      "oneOf": [
+        {
+          "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.",
+          "type": "object",
+          "required": [
+            "transfer"
+          ],
+          "properties": {
+            "transfer": {
+              "type": "object",
+              "required": [
+                "amount",
+                "channel_id",
+                "timeout",
+                "to_address"
+              ],
+              "properties": {
+                "amount": {
+                  "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/Coin"
+                    }
+                  ]
+                },
+                "channel_id": {
+                  "description": "exisiting channel to send the tokens over",
+                  "type": "string"
+                },
+                "timeout": {
+                  "description": "when packet times out, measured on remote chain",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/IbcTimeout"
+                    }
+                  ]
+                },
+                "to_address": {
+                  "description": "address on the remote chain to receive these tokens",
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.",
+          "type": "object",
+          "required": [
+            "send_packet"
+          ],
+          "properties": {
+            "send_packet": {
+              "type": "object",
+              "required": [
+                "channel_id",
+                "data",
+                "timeout"
+              ],
+              "properties": {
+                "channel_id": {
+                  "type": "string"
+                },
+                "data": {
+                  "$ref": "#/definitions/Binary"
+                },
+                "timeout": {
+                  "description": "when packet times out, measured on remote chain",
+                  "allOf": [
+                    {
+                      "$ref": "#/definitions/IbcTimeout"
+                    }
+                  ]
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        },
+        {
+          "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port",
+          "type": "object",
+          "required": [
+            "close_channel"
+          ],
+          "properties": {
+            "close_channel": {
+              "type": "object",
+              "required": [
+                "channel_id"
+              ],
+              "properties": {
+                "channel_id": {
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "additionalProperties": false
+        }
+      ]
+    },
+    "IbcTimeout": {
+      "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.",
+      "type": "object",
+      "properties": {
+        "block": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/IbcTimeoutBlock"
+            },
+            {
+              "type": "null"
+            }
+          ]
+        },
+        "timestamp": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/Timestamp"
+            },
+            {
+              "type": "null"
+            }
+          ]
+        }
+      }
+    },
+    "IbcTimeoutBlock": {
+      "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)",
+      "type": "object",
+      "required": [
+        "height",
+        "revision"
+      ],
+      "properties": {
+        "height": {
+          "description": "block height after which the packet times out. the height within the given revision",
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        },
+        "revision": {
+          "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)",
+          "type": "integer",
+          "format": "uint64",
+          "minimum": 0.0
+        }
+      }
+    },
     "PercentageThreshold": {
       "description": "A percentage of voting power that must vote yes for a proposal to pass. An example of why this is needed:\n\nIf a user specifies a 60% passing threshold, and there are 10 voters they likely expect that proposal to pass when there are 6 yes votes. This implies that the condition for passing should be `yes_votes >= total_votes * threshold`.\n\nWith this in mind, how should a user specify that they would like proposals to pass if the majority of voters choose yes? Selecting a 50% passing threshold with those rules doesn't properly cover that case as 5 voters voting yes out of 10 would pass the proposal. Selecting 50.0001% or or some variation of that also does not work as a very small yes vote which technically makes the majority yes may not reach that threshold.\n\nTo handle these cases we provide both a majority and percent option for all percentages. If majority is selected passing will be determined by `yes > total_votes * 0.5`. If percent is selected passing is determined by `yes >= total_votes * percent`.\n\nIn both of these cases a proposal with only abstain votes must fail. This requires a special case passing logic.",
       "oneOf": [
@@ -591,6 +824,15 @@
       "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
       "type": "string"
     },
+    "VoteOption": {
+      "type": "string",
+      "enum": [
+        "yes",
+        "no",
+        "abstain",
+        "no_with_veto"
+      ]
+    },
     "Votes": {
       "type": "object",
       "required": [


Test patch:
diff --git a/contracts/cw-core/src/tests.rs b/contracts/cw-core/src/tests.rs
index 063cc7be..79e00fdd 100644
--- a/contracts/cw-core/src/tests.rs
+++ b/contracts/cw-core/src/tests.rs
@@ -1911,3 +1911,35 @@ fn test_migrate() {
 
     assert_eq!(new_state, state);
 }
+
+#[test]
+fn test_execute_stargate_msg() {
+    let (core_addr, mut app) = do_standard_instantiate(true, None);
+    let proposal_modules: Vec<Addr> = app
+        .wrap()
+        .query_wasm_smart(
+            core_addr.clone(),
+            &QueryMsg::ProposalModules {
+                start_at: None,
+                limit: None,
+            },
+        )
+        .unwrap();
+
+    assert_eq!(proposal_modules.len(), 1);
+    let proposal_module = proposal_modules.into_iter().next().unwrap();
+
+    let res = app.execute_contract(
+        proposal_module,
+        core_addr,
+        &ExecuteMsg::ExecuteProposalHook {
+            msgs: vec![CosmosMsg::Stargate {
+                type_url: "foo_type".to_string(),
+                value: to_binary("foo_bin").unwrap(),
+            }],
+        },
+        &[],
+    );
+    // TODO: Once cw-multi-test supports executing stargate/ibc messages we can change this test assert
+    assert!(res.is_err());
+}
diff --git a/contracts/cw-proposal-single/src/tests.rs b/contracts/cw-proposal-single/src/tests.rs
index 24144f72..e7eb702f 100644
--- a/contracts/cw-proposal-single/src/tests.rs
+++ b/contracts/cw-proposal-single/src/tests.rs
@@ -778,6 +778,82 @@ fn test_propose() {
     assert_eq!(created.id, 1u64);
 }
 
+#[test]
+fn test_propose_supports_stargate_message() {
+    let mut app = App::default();
+    let govmod_id = app.store_code(single_proposal_contract());
+
+    let threshold = Threshold::AbsolutePercentage {
+        percentage: PercentageThreshold::Majority {},
+    };
+    let max_voting_period = cw_utils::Duration::Height(6);
+    let instantiate = InstantiateMsg {
+        threshold: threshold.clone(),
+        max_voting_period,
+        only_members_execute: false,
+        allow_revoting: false,
+        deposit_info: None,
+    };
+
+    let governance_addr =
+        instantiate_with_cw20_balances_governance(&mut app, govmod_id, instantiate, None);
+    let governance_modules: Vec<Addr> = app
+        .wrap()
+        .query_wasm_smart(
+            governance_addr,
+            &cw_core::msg::QueryMsg::ProposalModules {
+                start_at: None,
+                limit: None,
+            },
+        )
+        .unwrap();
+
+    assert_eq!(governance_modules.len(), 1);
+    let govmod_single = governance_modules.into_iter().next().unwrap();
+
+    // Create a new proposal.
+    app.execute_contract(
+        Addr::unchecked(CREATOR_ADDR),
+        govmod_single.clone(),
+        &ExecuteMsg::Propose {
+            title: "A simple text proposal".to_string(),
+            description: "This is a simple text proposal".to_string(),
+            msgs: vec![CosmosMsg::Stargate {
+                type_url: "foo_type".to_string(),
+                value: to_binary("foo_bin").unwrap(),
+            }],
+        },
+        &[],
+    )
+    .unwrap();
+
+    let created: ProposalResponse = app
+        .wrap()
+        .query_wasm_smart(govmod_single, &QueryMsg::Proposal { proposal_id: 1 })
+        .unwrap();
+    let current_block = app.block_info();
+    let expected = Proposal {
+        title: "A simple text proposal".to_string(),
+        description: "This is a simple text proposal".to_string(),
+        proposer: Addr::unchecked(CREATOR_ADDR),
+        start_height: current_block.height,
+        expiration: max_voting_period.after(&current_block),
+        threshold,
+        allow_revoting: false,
+        total_power: Uint128::new(100_000_000),
+        msgs: vec![CosmosMsg::Stargate {
+            type_url: "foo_type".to_string(),
+            value: to_binary("foo_bin").unwrap(),
+        }],
+        status: Status::Open,
+        votes: Votes::zero(),
+        deposit_info: None,
+    };
+
+    assert_eq!(created.proposal, expected);
+    assert_eq!(created.id, 1u64);
+}
+
 #[test]
 fn test_vote_simple() {
     testing::test_simple_votes(do_votes_cw20_balances);