Browse Source

Merge pull request #264 from shamil-gadelshin/propovals_v2_iteration7_with_dev_commits

Propovals. Version 2. Iteration7 (pre-merged with development)
Bedeho Mender 4 years ago
parent
commit
6952350dde

+ 125 - 115
Cargo.lock

@@ -131,7 +131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0d0864d84b8e07b145449be9a8537db86bf9de5ce03b913214694643b4743502"
 dependencies = [
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -159,9 +159,9 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
 
 [[package]]
 name = "backtrace"
-version = "0.3.45"
+version = "0.3.46"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8"
+checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
 dependencies = [
  "backtrace-sys",
  "cfg-if",
@@ -171,9 +171,9 @@ dependencies = [
 
 [[package]]
 name = "backtrace-sys"
-version = "0.1.34"
+version = "0.1.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69"
+checksum = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
 dependencies = [
  "cc",
  "libc",
@@ -230,9 +230,13 @@ checksum = "5da9b3d9f6f585199287a473f4f8dfab6566cf827d15c00c219f53c645687ead"
 
 [[package]]
 name = "bitvec"
-version = "0.15.2"
+version = "0.17.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a993f74b4c99c1908d156b8d2e0fb6277736b0ecbd833982fd1241d39b2766a6"
+checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c"
+dependencies = [
+ "either",
+ "radium",
+]
 
 [[package]]
 name = "blake2"
@@ -309,9 +313,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.2.0"
+version = "3.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742"
+checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187"
 
 [[package]]
 name = "byte-slice-cast"
@@ -459,7 +463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a"
 dependencies = [
  "const-random-macro",
- "proc-macro-hack 0.5.12",
+ "proc-macro-hack 0.5.15",
 ]
 
 [[package]]
@@ -469,7 +473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a"
 dependencies = [
  "getrandom",
- "proc-macro-hack 0.5.12",
+ "proc-macro-hack 0.5.15",
 ]
 
 [[package]]
@@ -646,9 +650,9 @@ version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1eae4d76b7cefedd1b4f8cc24378b2fbd1ac1b66e3bbebe8e2192d3be81cb355"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -787,9 +791,9 @@ checksum = "516aa8d7a71cb00a1c4146f0798549b93d083d4f189b3ced8f3de6b8f11ee6c4"
 
 [[package]]
 name = "erased-serde"
-version = "0.3.10"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd7d80305c9bd8cd78e3c753eb9fb110f83621e5211f1a3afffcc812b104daf9"
+checksum = "d88b6d1705e16a4d62e05ea61cc0496c2bd190f4fa8e5c1f11ce747be6bcf3d1"
 dependencies = [
  "serde",
 ]
@@ -820,9 +824,9 @@ version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
  "synstructure",
 ]
 
@@ -1056,10 +1060,10 @@ version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7"
 dependencies = [
- "proc-macro-hack 0.5.12",
- "proc-macro2 1.0.9",
+ "proc-macro-hack 0.5.15",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -1119,7 +1123,7 @@ dependencies = [
  "futures-task",
  "memchr",
  "pin-utils",
- "proc-macro-hack 0.5.12",
+ "proc-macro-hack 0.5.15",
  "proc-macro-nested",
  "slab",
 ]
@@ -1280,9 +1284,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.1.8"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
+checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
 dependencies = [
  "libc",
 ]
@@ -1316,7 +1320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0"
 dependencies = [
  "hex-literal-impl 0.2.1",
- "proc-macro-hack 0.5.12",
+ "proc-macro-hack 0.5.15",
 ]
 
 [[package]]
@@ -1334,7 +1338,7 @@ version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9d4c5c844e2fee0bf673d54c2c177f1713b3d2af2ff6e666b49cb7572e6cf42d"
 dependencies = [
- "proc-macro-hack 0.5.12",
+ "proc-macro-hack 0.5.15",
 ]
 
 [[package]]
@@ -1498,9 +1502,9 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -1669,9 +1673,9 @@ dependencies = [
 
 [[package]]
 name = "js-sys"
-version = "0.3.36"
+version = "0.3.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cb931d43e71f560c81badb0191596562bafad2be06a3f9025b845c847c60df5"
+checksum = "6a27d435371a2fa5b6d2b028a74bbdb1234f308da363226a2854ca3ff8ba7055"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -1734,9 +1738,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8609af8f63b626e8e211f52441fcdb6ec54f1a446606b10d5c89ae9bf8a20058"
 dependencies = [
  "proc-macro-crate",
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -2371,8 +2375,8 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e37c5d4cd9473c5f4c9c111f033f15d4df9bd378fdf615944e360a4f55a05f0b"
 dependencies = [
- "proc-macro2 1.0.9",
- "syn 1.0.16",
+ "proc-macro2 1.0.10",
+ "syn 1.0.17",
  "synstructure",
 ]
 
@@ -2518,9 +2522,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d5a615a1ad92048ad5d9633251edb7492b8abc057d7a679a9898476aef173935"
 dependencies = [
  "cfg-if",
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -2673,9 +2677,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d"
 dependencies = [
  "proc-macro-crate",
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -2791,9 +2795,9 @@ dependencies = [
 
 [[package]]
 name = "parity-scale-codec"
-version = "1.2.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f509c5e67ca0605ee17dcd3f91ef41cadd685c75a298fb6261b781a5acb3f910"
+checksum = "329c8f7f4244ddb5c37c103641027a76c530e65e8e4b8240b29f81ea40508b17"
 dependencies = [
  "arrayvec 0.5.1",
  "bitvec",
@@ -2809,9 +2813,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5a0ec292e92e8ec7c58e576adacc1e3f399c597c8f263c42f18420abe58e7245"
 dependencies = [
  "proc-macro-crate",
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -2962,24 +2966,24 @@ dependencies = [
 
 [[package]]
 name = "paste"
-version = "0.1.7"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63e1afe738d71b1ebab5f1207c055054015427dbfc7bbe9ee1266894156ec046"
+checksum = "ab4fb1930692d1b6a9cfabdde3d06ea0a7d186518e2f4d67660d8970e2fa647a"
 dependencies = [
  "paste-impl",
- "proc-macro-hack 0.5.12",
+ "proc-macro-hack 0.5.15",
 ]
 
 [[package]]
 name = "paste-impl"
-version = "0.1.7"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d4dc4a7f6f743211c5aab239640a65091535d97d43d92a52bca435a640892bb"
+checksum = "a62486e111e571b1e93b710b61e8f493c0013be39629b714cb166bdb06aa5a8a"
 dependencies = [
- "proc-macro-hack 0.5.12",
- "proc-macro2 1.0.9",
+ "proc-macro-hack 0.5.15",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -3099,9 +3103,9 @@ version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -3115,14 +3119,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro-hack"
-version = "0.5.12"
+version = "0.5.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f918f2b601f93baa836c1c2945faef682ba5b6d4828ecb45eeb7cc3c71b811b4"
-dependencies = [
- "proc-macro2 1.0.9",
- "quote 1.0.3",
- "syn 1.0.16",
-]
+checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
 
 [[package]]
 name = "proc-macro-hack-impl"
@@ -3147,9 +3146,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.9"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
+checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
 dependencies = [
  "unicode-xid 0.2.0",
 ]
@@ -3233,9 +3232,15 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
 ]
 
+[[package]]
+name = "radium"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac"
+
 [[package]]
 name = "rand"
 version = "0.3.23"
@@ -3460,9 +3465,9 @@ checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
 
 [[package]]
 name = "regex"
-version = "1.3.5"
+version = "1.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8900ebc1363efa7ea1c399ccc32daed870b4002651e0bed86e72d501ebbe0048"
+checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -3487,9 +3492,9 @@ dependencies = [
 
 [[package]]
 name = "ring"
-version = "0.16.11"
+version = "0.16.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "741ba1704ae21999c00942f9f5944f801e977f54302af346b596287599ad1862"
+checksum = "1ba5a8ec64ee89a76c98c549af81ff14813df09c3e6dc4766c3856da48597a0c"
 dependencies = [
  "cc",
  "lazy_static",
@@ -3642,29 +3647,29 @@ checksum = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4"
 
 [[package]]
 name = "serde"
-version = "1.0.104"
+version = "1.0.106"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
+checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.104"
+version = "1.0.106"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
+checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.48"
+version = "1.0.51"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25"
+checksum = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9"
 dependencies = [
  "itoa",
  "ryu",
@@ -3742,7 +3747,7 @@ dependencies = [
 [[package]]
 name = "slog-async"
 version = "2.3.0"
-source = "git+https://github.com/paritytech/slog-async#107848e7ded5e80dc43f6296c2b96039eb92c0a5"
+source = "git+https://github.com/paritytech/slog-async#0329dc74feb3afe93d0cd2533a472b7ceab44aaf"
 dependencies = [
  "crossbeam-channel",
  "slog",
@@ -3846,9 +3851,9 @@ source = "git+https://github.com/paritytech/substrate.git?rev=c37bb08535c49a1232
 dependencies = [
  "blake2-rfc",
  "proc-macro-crate",
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -4165,9 +4170,9 @@ version = "2.0.0"
 source = "git+https://github.com/paritytech/substrate.git?rev=c37bb08535c49a12320af7facfd555ce05cce2e8#c37bb08535c49a12320af7facfd555ce05cce2e8"
 dependencies = [
  "proc-macro-crate",
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -4210,11 +4215,11 @@ name = "srml-support-procedural"
 version = "2.0.0"
 source = "git+https://github.com/paritytech/substrate.git?rev=c37bb08535c49a12320af7facfd555ce05cce2e8#c37bb08535c49a12320af7facfd555ce05cce2e8"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
  "sr-api-macros",
  "srml-support-procedural-tools",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -4223,10 +4228,10 @@ version = "2.0.0"
 source = "git+https://github.com/paritytech/substrate.git?rev=c37bb08535c49a12320af7facfd555ce05cce2e8#c37bb08535c49a12320af7facfd555ce05cce2e8"
 dependencies = [
  "proc-macro-crate",
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
  "srml-support-procedural-tools-derive",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -4234,9 +4239,9 @@ name = "srml-support-procedural-tools-derive"
 version = "2.0.0"
 source = "git+https://github.com/paritytech/substrate.git?rev=c37bb08535c49a12320af7facfd555ce05cce2e8#c37bb08535c49a12320af7facfd555ce05cce2e8"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -4359,9 +4364,9 @@ checksum = "ea692d40005b3ceba90a9fe7a78fa8d4b82b0ce627eebbffc329aab850f3410e"
 dependencies = [
  "heck",
  "proc-macro-error",
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -4477,9 +4482,9 @@ version = "2.0.0"
 source = "git+https://github.com/paritytech/substrate.git?rev=c37bb08535c49a12320af7facfd555ce05cce2e8#c37bb08535c49a12320af7facfd555ce05cce2e8"
 dependencies = [
  "proc-macro-crate",
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -4714,9 +4719,9 @@ name = "substrate-debug-derive"
 version = "2.0.0"
 source = "git+https://github.com/paritytech/substrate.git?rev=c37bb08535c49a12320af7facfd555ce05cce2e8#c37bb08535c49a12320af7facfd555ce05cce2e8"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
 ]
 
 [[package]]
@@ -5109,13 +5114,18 @@ dependencies = [
  "srml-system",
  "srml-timestamp",
  "substrate-common-module",
+ "substrate-content-working-group-module",
  "substrate-governance-module",
+ "substrate-hiring-module",
  "substrate-membership-module",
  "substrate-primitives",
  "substrate-proposals-discussion-module",
  "substrate-proposals-engine-module",
+ "substrate-recurring-reward-module",
  "substrate-stake-module",
  "substrate-token-mint-module",
+ "substrate-versioned-store",
+ "substrate-versioned-store-permissions-module",
 ]
 
 [[package]]
@@ -5578,11 +5588,11 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.16"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
+checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
  "unicode-xid 0.2.0",
 ]
@@ -5593,9 +5603,9 @@ version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
  "unicode-xid 0.2.0",
 ]
 
@@ -6172,9 +6182,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.59"
+version = "0.2.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3557c397ab5a8e347d434782bcd31fc1483d927a6826804cec05cc792ee2519d"
+checksum = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -6182,16 +6192,16 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.59"
+version = "0.2.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0da9c9a19850d3af6df1cb9574970b566d617ecfaf36eb0b706b6f3ef9bd2f8"
+checksum = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd"
 dependencies = [
  "bumpalo",
  "lazy_static",
  "log",
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
  "wasm-bindgen-shared",
 ]
 
@@ -6210,9 +6220,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.59"
+version = "0.2.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f6fde1d36e75a714b5fe0cffbb78978f222ea6baebb726af13c78869fdb4205"
+checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4"
 dependencies = [
  "quote 1.0.3",
  "wasm-bindgen-macro-support",
@@ -6220,22 +6230,22 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.59"
+version = "0.2.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25bda4168030a6412ea8a047e27238cadf56f0e53516e1e83fec0a8b7c786f6d"
+checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.59"
+version = "0.2.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc9f36ad51f25b0219a3d4d13b90eb44cd075dff8b6280cca015775d7acaddd8"
+checksum = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639"
 
 [[package]]
 name = "wasm-timer"
@@ -6276,9 +6286,9 @@ dependencies = [
 
 [[package]]
 name = "web-sys"
-version = "0.3.36"
+version = "0.3.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "721c6263e2c66fd44501cc5efbfa2b7dfa775d13e4ea38c46299646ed1f9c70a"
+checksum = "2d6f51648d8c56c366144378a33290049eafdd784071077f6fe37dae64c1c4cb"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -6352,9 +6362,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.3"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
+checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e"
 dependencies = [
  "winapi 0.3.8",
 ]
@@ -6454,8 +6464,8 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2"
 dependencies = [
- "proc-macro2 1.0.9",
+ "proc-macro2 1.0.10",
  "quote 1.0.3",
- "syn 1.0.16",
+ "syn 1.0.17",
  "synstructure",
 ]

+ 13 - 0
runtime-modules/governance/src/election.rs

@@ -99,6 +99,19 @@ impl<Elected, Term, X: CouncilElected<Elected, Term>> CouncilElected<Elected, Te
         X::council_elected(new_council, term);
     }
 }
+// Chain of handlers.
+impl<
+        Elected: Clone,
+        Term: Clone,
+        X: CouncilElected<Elected, Term>,
+        Y: CouncilElected<Elected, Term>,
+    > CouncilElected<Elected, Term> for (X, Y)
+{
+    fn council_elected(new_council: Elected, term: Term) {
+        X::council_elected(new_council.clone(), term.clone());
+        Y::council_elected(new_council, term);
+    }
+}
 
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
 #[derive(Clone, Copy, Encode, Decode, Default)]

+ 40 - 8
runtime-modules/proposals/codex/Cargo.toml

@@ -12,7 +12,7 @@ std = [
     'rstd/std',
     'srml-support/std',
     'primitives/std',
-    'runtime-primitives/std',
+    'sr-primitives/std',
     'system/std',
     'timestamp/std',
     'serde',
@@ -21,6 +21,8 @@ std = [
     'stake/std',
     'balances/std',
     'membership/std',
+    'governance/std',
+    'mint/std',
 ]
 
 
@@ -51,7 +53,7 @@ git = 'https://github.com/paritytech/substrate.git'
 package = 'sr-std'
 rev = 'c37bb08535c49a12320af7facfd555ce05cce2e8'
 
-[dependencies.runtime-primitives]
+[dependencies.sr-primitives]
 default_features = false
 git = 'https://github.com/paritytech/substrate.git'
 package = 'sr-primitives'
@@ -91,6 +93,16 @@ default_features = false
 package = 'substrate-membership-module'
 path = '../../membership'
 
+[dependencies.governance]
+default_features = false
+package = 'substrate-governance-module'
+path = '../../governance'
+
+[dependencies.mint]
+default_features = false
+package = 'substrate-token-mint-module'
+path = '../../token-minting'
+
 [dependencies.proposal_engine]
 default_features = false
 package = 'substrate-proposals-engine-module'
@@ -106,18 +118,38 @@ default_features = false
 package = 'substrate-common-module'
 path = '../../common'
 
+[dependencies.content_working_group]
+default_features = false
+package = 'substrate-content-working-group-module'
+path = '../../content-working-group'
+
 [dev-dependencies.runtime-io]
 default_features = false
 git = 'https://github.com/paritytech/substrate.git'
 package = 'sr-io'
 rev = 'c37bb08535c49a12320af7facfd555ce05cce2e8'
 
-[dev-dependencies.governance]
+[dev-dependencies.hiring]
 default_features = false
-package = 'substrate-governance-module'
-path = '../../governance'
+package = 'substrate-hiring-module'
+path = '../../hiring'
 
-[dev-dependencies.token_mint]
+[dev-dependencies.versioned_store]
 default_features = false
-package = 'substrate-token-mint-module'
-path = '../../token-minting'
+package ='substrate-versioned-store'
+path = '../../versioned-store'
+
+[dependencies.versioned_store]
+default_features = false
+package ='substrate-versioned-store'
+path = '../../versioned-store'
+
+[dev-dependencies.versioned_store_permissions]
+default_features = false
+package = 'substrate-versioned-store-permissions-module'
+path = '../../versioned-store-permissions'
+
+[dev-dependencies.recurring_rewards]
+default_features = false
+package = 'substrate-recurring-reward-module'
+path = '../../recurring-reward'

+ 252 - 66
runtime-modules/proposals/codex/src/lib.rs

@@ -1,34 +1,69 @@
-//! Proposals codex module for the Joystream platform. Version 2.
-//! Contains preset proposal types
+//! # Proposals codex module
+//! Proposals `codex` module for the Joystream platform. Version 2.
+//! Component of the proposals system. Contains preset proposal types.
 //!
-//! Supported extrinsics (proposal type):
-//! - create_text_proposal
+//! ## Overview
+//!
+//! The proposals codex module serves as facade and entry point of the proposals system. It uses
+//! proposals `engine` module to maintain a lifecycle of the proposal and to execute proposals.
+//! During the proposal creation `codex` also create a discussion thread using the `discussion`
+//! proposals module. `Codex` uses predefined parameters (eg.:`voting_period`) for each proposal and
+//! encodes extrinsic calls from dependency modules in order to create proposals inside the `engine`
+//! module.
+//!
+//! ### Supported extrinsics (proposal types)
+//! - [create_text_proposal](./struct.Module.html#method.create_text_proposal)
+//! - [create_runtime_upgrade_proposal](./struct.Module.html#method.create_runtime_upgrade_proposal)
+//! - [create_set_election_parameters_proposal](./struct.Module.html#method.create_set_election_parameters_proposal)
+//! - [create_set_council_mint_capacity_proposal](./struct.Module.html#method.create_set_council_mint_capacity_proposal)
+//! - [create_set_content_working_group_mint_capacity_proposal](./struct.Module.html#method.create_set_content_working_group_mint_capacity_proposal)
+//! - [create_spending_proposal](./struct.Module.html#method.create_spending_proposal)
+//! - [create_set_lead_proposal](./struct.Module.html#method.create_set_lead_proposal)
+//!
+//! ### Proposal implementations of this module
+//! - execute_text_proposal - prints the proposal to the log
+//! - execute_runtime_upgrade_proposal - sets the runtime code
+//!
+//! ### Dependencies:
+//! - [proposals engine](../substrate_proposals_engine_module/index.html)
+//! - [proposals discussion](../substrate_proposals_discussion_module/index.html)
+//! - [membership](../substrate_membership_module/index.html)
+//! - [governance](../substrate_governance_module/index.html)
+//! - [content_working_group](../substrate_content_working_group_module/index.html)
 //!
 
 // Ensure we're `no_std` when compiling for Wasm.
 #![cfg_attr(not(feature = "std"), no_std)]
 
 // Do not delete! Cannot be uncommented by default, because of Parity decl_module! issue.
-//#![warn(missing_docs)]
+// #![warn(missing_docs)]
 
 mod proposal_types;
 #[cfg(test)]
 mod tests;
 
 use codec::Encode;
+use common::origin_validator::ActorOriginValidator;
+use governance::election_params::ElectionParameters;
+use proposal_engine::ProposalParameters;
 use rstd::clone::Clone;
 use rstd::prelude::*;
 use rstd::str::from_utf8;
 use rstd::vec::Vec;
+use sr_primitives::traits::Zero;
+use srml_support::dispatch::DispatchResult;
+use srml_support::traits::{Currency, Get};
 use srml_support::{decl_error, decl_module, decl_storage, ensure, print};
 use system::{ensure_root, RawOrigin};
 
-use common::origin_validator::ActorOriginValidator;
-use proposal_engine::ProposalParameters;
-
 /// 'Proposals codex' substrate module Trait
 pub trait Trait:
-    system::Trait + proposal_engine::Trait + membership::members::Trait + proposal_discussion::Trait
+    system::Trait
+    + proposal_engine::Trait
+    + proposal_discussion::Trait
+    + membership::members::Trait
+    + governance::election::Trait
+    + content_working_group::Trait
 {
     /// Defines max allowed text proposal length.
     type TextProposalMaxLength: Get<u32>;
@@ -43,19 +78,29 @@ pub trait Trait:
         Self::AccountId,
     >;
 }
-use srml_support::traits::{Currency, Get};
 
-/// Balance alias
+/// Balance alias for `stake` module
 pub type BalanceOf<T> =
     <<T as stake::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
 
-/// Balance alias for staking
+/// Balance alias for GovernanceCurrency from `common` module. TODO: replace with BalanceOf
+pub type BalanceOfGovernanceCurrency<T> =
+    <<T as common::currency::GovernanceCurrency>::Currency as Currency<
+        <T as system::Trait>::AccountId,
+    >>::Balance;
+
+/// Balance alias for token mint balance from `token mint` module. TODO: replace with BalanceOf
+pub type BalanceOfMint<T> =
+    <<T as mint::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
+
+/// Negative imbalance alias for staking
 pub type NegativeImbalance<T> =
     <<T as stake::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
 
 type MemberId<T> = <T as membership::members::Trait>::MemberId;
 
 decl_error! {
+    /// Codex module predefined errors
     pub enum Error {
         /// The size of the provided text for text proposal exceeded the limit
         TextProposalSizeExceeded,
@@ -69,11 +114,11 @@ decl_error! {
         /// Provided WASM code for the runtime upgrade proposal is empty
         RuntimeProposalIsEmpty,
 
+        /// Invalid balance value for the spending proposal
+        SpendingProposalZeroBalance,
+
         /// Require root origin in extrinsics
         RequireRootOrigin,
-
-        /// Errors from the proposal engine
-        ProposalsEngineError
     }
 }
 
@@ -117,113 +162,214 @@ decl_storage! {
 }
 
 decl_module! {
-    /// 'Proposal codex' substrate module
+    /// Proposal codex substrate module Call
     pub struct Module<T: Trait> for enum Call where origin: T::Origin {
         /// Predefined errors
         type Error = Error;
 
-        /// Create text (signal) proposal type. On approval prints its content.
+        /// Create 'Text (signal)' proposal type.
         pub fn create_text_proposal(
             origin,
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            text: Vec<u8>,
             stake_balance: Option<BalanceOf<T>>,
+            text: Vec<u8>,
         ) {
-            let account_id = T::MembershipOriginValidator::ensure_actor_origin(origin, member_id.clone())?;
-
-            let parameters = proposal_types::parameters::text_proposal::<T>();
-
             ensure!(!text.is_empty(), Error::TextProposalIsEmpty);
             ensure!(text.len() as u32 <=  T::TextProposalMaxLength::get(),
                 Error::TextProposalSizeExceeded);
 
-            <proposal_engine::Module<T>>::ensure_create_proposal_parameters_are_valid(
-                &parameters,
-                &title,
-                &description,
+            let proposal_parameters = proposal_types::parameters::text_proposal::<T>();
+            let proposal_code =
+                <Call<T>>::execute_text_proposal(title.clone(), description.clone(), text);
+
+            Self::create_proposal(
+                origin,
+                member_id,
+                title,
+                description,
                 stake_balance,
+                proposal_code.encode(),
+                proposal_parameters,
             )?;
+        }
 
-            <proposal_discussion::Module<T>>::ensure_can_create_thread(
-                &title,
-                member_id.clone(),
-            )?;
+        /// Create 'Runtime upgrade' proposal type.
+        pub fn create_runtime_upgrade_proposal(
+            origin,
+            member_id: MemberId<T>,
+            title: Vec<u8>,
+            description: Vec<u8>,
+            stake_balance: Option<BalanceOf<T>>,
+            wasm: Vec<u8>,
+        ) {
+            ensure!(!wasm.is_empty(), Error::RuntimeProposalIsEmpty);
+            ensure!(wasm.len() as u32 <= T::RuntimeUpgradeWasmProposalMaxLength::get(),
+                Error::RuntimeProposalSizeExceeded);
 
-            let proposal_code = <Call<T>>::text_proposal(title.clone(), description.clone(), text);
+            let proposal_code =
+                <Call<T>>::execute_runtime_upgrade_proposal(title.clone(), description.clone(), wasm);
 
-            let discussion_thread_id = <proposal_discussion::Module<T>>::create_thread(
-                member_id,
-                title.clone(),
-            )?;
+            let proposal_parameters = proposal_types::parameters::upgrade_runtime::<T>();
 
-            let proposal_id = <proposal_engine::Module<T>>::create_proposal(
-                account_id,
+            Self::create_proposal(
+                origin,
                 member_id,
-                parameters,
                 title,
                 description,
                 stake_balance,
                 proposal_code.encode(),
+                proposal_parameters,
             )?;
-
-             <ThreadIdByProposalId<T>>::insert(proposal_id, discussion_thread_id);
         }
 
-        /// Create runtime upgrade proposal type. On approval prints its content.
-        pub fn create_runtime_upgrade_proposal(
+        /// Create 'Set election parameters' proposal type. This proposal uses `set_election_parameters()`
+        /// extrinsic from the `governance::election module`.
+        pub fn create_set_election_parameters_proposal(
             origin,
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            wasm: Vec<u8>,
             stake_balance: Option<BalanceOf<T>>,
+            election_parameters: ElectionParameters<BalanceOfGovernanceCurrency<T>, T::BlockNumber>,
         ) {
-            let account_id = T::MembershipOriginValidator::ensure_actor_origin(origin, member_id.clone())?;
+            election_parameters.ensure_valid()?;
 
-            let parameters = proposal_types::parameters::upgrade_runtime::<T>();
+            let proposal_code =
+                <governance::election::Call<T>>::set_election_parameters(election_parameters);
 
-            ensure!(!wasm.is_empty(), Error::RuntimeProposalIsEmpty);
-            ensure!(wasm.len() as u32 <= T::RuntimeUpgradeWasmProposalMaxLength::get(),
-                Error::RuntimeProposalSizeExceeded);
+            let proposal_parameters =
+                proposal_types::parameters::set_election_parameters_proposal::<T>();
 
-            <proposal_engine::Module<T>>::ensure_create_proposal_parameters_are_valid(
-                &parameters,
-                &title,
-                &description,
+            Self::create_proposal(
+                origin,
+                member_id,
+                title,
+                description,
                 stake_balance,
+                proposal_code.encode(),
+                proposal_parameters,
             )?;
+        }
+
+
+        /// Create 'Set council mint capacity' proposal type. This proposal uses `set_mint_capacity()`
+        /// extrinsic from the `governance::council` module.
+        pub fn create_set_council_mint_capacity_proposal(
+            origin,
+            member_id: MemberId<T>,
+            title: Vec<u8>,
+            description: Vec<u8>,
+            stake_balance: Option<BalanceOf<T>>,
+            mint_balance: BalanceOfMint<T>,
+        ) {
+            let proposal_code =
+                <governance::council::Call<T>>::set_council_mint_capacity(mint_balance);
+
+            let proposal_parameters =
+                proposal_types::parameters::set_council_mint_capacity_proposal::<T>();
 
-            <proposal_discussion::Module<T>>::ensure_can_create_thread(
-                &title,
-                member_id.clone(),
+            Self::create_proposal(
+                origin,
+                member_id,
+                title,
+                description,
+                stake_balance,
+                proposal_code.encode(),
+                proposal_parameters,
             )?;
+        }
 
-            let proposal_code = <Call<T>>::text_proposal(title.clone(), description.clone(), wasm);
+        /// Create 'Set content working group mint capacity' proposal type.
+        /// This proposal uses `set_mint_capacity()` extrinsic from the `content-working-group`  module.
+        pub fn create_set_content_working_group_mint_capacity_proposal(
+            origin,
+            member_id: MemberId<T>,
+            title: Vec<u8>,
+            description: Vec<u8>,
+            stake_balance: Option<BalanceOf<T>>,
+            mint_balance: BalanceOfMint<T>,
+        ) {
+            let proposal_code =
+                <content_working_group::Call<T>>::set_mint_capacity(mint_balance);
+
+            let proposal_parameters =
+                proposal_types::parameters::set_content_working_group_mint_capacity_proposal::<T>();
 
-            let discussion_thread_id = <proposal_discussion::Module<T>>::create_thread(
+            Self::create_proposal(
+                origin,
                 member_id,
-                title.clone(),
+                title,
+                description,
+                stake_balance,
+                proposal_code.encode(),
+                proposal_parameters,
             )?;
+        }
+
+        /// Create 'Spending' proposal type.
+        /// This proposal uses `spend_from_council_mint()` extrinsic from the `governance::council`  module.
+        pub fn create_spending_proposal(
+            origin,
+            member_id: MemberId<T>,
+            title: Vec<u8>,
+            description: Vec<u8>,
+            stake_balance: Option<BalanceOf<T>>,
+            balance: BalanceOfMint<T>,
+            destination: T::AccountId,
+        ) {
+            ensure!(balance != BalanceOfMint::<T>::zero(), Error::SpendingProposalZeroBalance);
+
+            let proposal_code =
+                <governance::council::Call<T>>::spend_from_council_mint(balance, destination);
 
-            let proposal_id = <proposal_engine::Module<T>>::create_proposal(
-                account_id,
+            let proposal_parameters =
+                proposal_types::parameters::spending_proposal::<T>();
+
+            Self::create_proposal(
+                origin,
                 member_id,
-                parameters,
                 title,
                 description,
                 stake_balance,
                 proposal_code.encode(),
+                proposal_parameters,
             )?;
+        }
+
+
+        /// Create 'Set lead' proposal type.
+        /// This proposal uses `replace_lead()` extrinsic from the `content_working_group`  module.
+        pub fn create_set_lead_proposal(
+            origin,
+            member_id: MemberId<T>,
+            title: Vec<u8>,
+            description: Vec<u8>,
+            stake_balance: Option<BalanceOf<T>>,
+            new_lead: Option<(T::MemberId, T::AccountId)>
+        ) {
+            let proposal_code =
+                <content_working_group::Call<T>>::replace_lead(new_lead);
 
-            <ThreadIdByProposalId<T>>::insert(proposal_id, discussion_thread_id);
+            let proposal_parameters =
+                proposal_types::parameters::set_lead_proposal::<T>();
+
+            Self::create_proposal(
+                origin,
+                member_id,
+                title,
+                description,
+                stake_balance,
+                proposal_code.encode(),
+                proposal_parameters,
+            )?;
         }
 
 // *************** Extrinsic to execute
 
-        /// Text proposal extrinsic. Should be used as callable object to pass to the engine module.
-        fn text_proposal(
+        /// Text proposal extrinsic. Should be used as callable object to pass to the `engine` module.
+        fn execute_text_proposal(
             origin,
             title: Vec<u8>,
             _description: Vec<u8>,
@@ -238,8 +384,8 @@ decl_module! {
         }
 
         /// Runtime upgrade proposal extrinsic.
-        /// Should be used as callable object to pass to the engine module.
-        fn runtime_upgrade_proposal(
+        /// Should be used as callable object to pass to the `engine` module.
+        fn execute_runtime_upgrade_proposal(
             origin,
             title: Vec<u8>,
             _description: Vec<u8>,
@@ -278,4 +424,44 @@ impl<T: Trait> Module<T> {
 
         (cloned_origin1.into(), cloned_origin2.into())
     }
+
+    // Generic template proposal builder
+    fn create_proposal(
+        origin: T::Origin,
+        member_id: MemberId<T>,
+        title: Vec<u8>,
+        description: Vec<u8>,
+        stake_balance: Option<BalanceOf<T>>,
+        proposal_code: Vec<u8>,
+        proposal_parameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>,
+    ) -> DispatchResult<Error> {
+        let account_id =
+            T::MembershipOriginValidator::ensure_actor_origin(origin, member_id.clone())?;
+
+        <proposal_engine::Module<T>>::ensure_create_proposal_parameters_are_valid(
+            &proposal_parameters,
+            &title,
+            &description,
+            stake_balance,
+        )?;
+
+        <proposal_discussion::Module<T>>::ensure_can_create_thread(&title, member_id.clone())?;
+
+        let discussion_thread_id =
+            <proposal_discussion::Module<T>>::create_thread(member_id, title.clone())?;
+
+        let proposal_id = <proposal_engine::Module<T>>::create_proposal(
+            account_id,
+            member_id,
+            proposal_parameters,
+            title,
+            description,
+            stake_balance,
+            proposal_code,
+        )?;
+
+        <ThreadIdByProposalId<T>>::insert(proposal_id, discussion_thread_id);
+
+        Ok(())
+    }
 }

+ 70 - 0
runtime-modules/proposals/codex/src/proposal_types/mod.rs

@@ -24,8 +24,78 @@ pub(crate) mod parameters {
             approval_quorum_percentage: 40,
             approval_threshold_percentage: 51,
             slashing_quorum_percentage: 80,
+            slashing_threshold_percentage: 82,
+            required_stake: Some(<BalanceOf<T>>::from(500u32)),
+        }
+    }
+
+    // Proposal parameters for the 'Set Election Parameters' proposal
+    pub(crate) fn set_election_parameters_proposal<T: crate::Trait>(
+    ) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
+        ProposalParameters {
+            voting_period: T::BlockNumber::from(50000u32),
+            grace_period: T::BlockNumber::from(10000u32),
+            approval_quorum_percentage: 40,
+            approval_threshold_percentage: 51,
+            slashing_quorum_percentage: 81,
             slashing_threshold_percentage: 80,
             required_stake: Some(<BalanceOf<T>>::from(500u32)),
         }
     }
+
+    // Proposal parameters for the 'Set council mint capacity' proposal
+    pub(crate) fn set_council_mint_capacity_proposal<T: crate::Trait>(
+    ) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
+        ProposalParameters {
+            voting_period: T::BlockNumber::from(50000u32),
+            grace_period: T::BlockNumber::from(10000u32),
+            approval_quorum_percentage: 40,
+            approval_threshold_percentage: 51,
+            slashing_quorum_percentage: 81,
+            slashing_threshold_percentage: 84,
+            required_stake: Some(<BalanceOf<T>>::from(500u32)),
+        }
+    }
+
+    // Proposal parameters for the 'Set content working group mint capacity' proposal
+    pub(crate) fn set_content_working_group_mint_capacity_proposal<T: crate::Trait>(
+    ) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
+        ProposalParameters {
+            voting_period: T::BlockNumber::from(50000u32),
+            grace_period: T::BlockNumber::from(10000u32),
+            approval_quorum_percentage: 40,
+            approval_threshold_percentage: 51,
+            slashing_quorum_percentage: 81,
+            slashing_threshold_percentage: 85,
+            required_stake: Some(<BalanceOf<T>>::from(500u32)),
+        }
+    }
+
+    // Proposal parameters for the 'Spending' proposal
+    pub(crate) fn spending_proposal<T: crate::Trait>(
+    ) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
+        ProposalParameters {
+            voting_period: T::BlockNumber::from(50000u32),
+            grace_period: T::BlockNumber::from(10000u32),
+            approval_quorum_percentage: 40,
+            approval_threshold_percentage: 51,
+            slashing_quorum_percentage: 84,
+            slashing_threshold_percentage: 85,
+            required_stake: Some(<BalanceOf<T>>::from(500u32)),
+        }
+    }
+
+    // Proposal parameters for the 'Set lead' proposal
+    pub(crate) fn set_lead_proposal<T: crate::Trait>(
+    ) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
+        ProposalParameters {
+            voting_period: T::BlockNumber::from(50000u32),
+            grace_period: T::BlockNumber::from(10000u32),
+            approval_quorum_percentage: 40,
+            approval_threshold_percentage: 51,
+            slashing_quorum_percentage: 81,
+            slashing_threshold_percentage: 86,
+            required_stake: Some(<BalanceOf<T>>::from(500u32)),
+        }
+    }
 }

+ 38 - 6
runtime-modules/proposals/codex/src/tests/mock.rs

@@ -3,7 +3,7 @@
 pub use system;
 
 pub use primitives::{Blake2Hasher, H256};
-pub use runtime_primitives::{
+pub use sr_primitives::{
     testing::{Digest, DigestItem, Header, UintAuthorityId},
     traits::{BlakeTwo256, Convert, IdentityLookup, OnFinalize},
     weights::Weight,
@@ -109,16 +109,16 @@ impl Default for crate::Call<Test> {
     }
 }
 
+impl mint::Trait for Test {
+    type Currency = Balances;
+    type MintId = u64;
+}
+
 impl governance::council::Trait for Test {
     type Event = ();
     type CouncilTermEnded = ();
 }
 
-impl token_mint::Trait for Test {
-    type Currency = Balances;
-    type MintId = u64;
-}
-
 impl common::origin_validator::ActorOriginValidator<Origin, u64, u64> for () {
     fn ensure_actor_origin(_: Origin, _: u64) -> Result<u64, &'static str> {
         Ok(1)
@@ -155,6 +155,38 @@ parameter_types! {
     pub const RuntimeUpgradeWasmProposalMaxLength: u32 = 20_000;
 }
 
+impl governance::election::Trait for Test {
+    type Event = ();
+    type CouncilElected = ();
+}
+
+impl content_working_group::Trait for Test {
+    type Event = ();
+}
+
+impl recurring_rewards::Trait for Test {
+    type PayoutStatusHandler = ();
+    type RecipientId = u64;
+    type RewardRelationshipId = u64;
+}
+
+impl versioned_store_permissions::Trait for Test {
+    type Credential = u64;
+    type CredentialChecker = ();
+    type CreateClassPermissionsChecker = ();
+}
+
+impl versioned_store::Trait for Test {
+    type Event = ();
+}
+
+impl hiring::Trait for Test {
+    type OpeningId = u64;
+    type ApplicationId = u64;
+    type ApplicationDeactivatedHandler = ();
+    type StakeHandlerProvider = hiring::Module<Self>;
+}
+
 impl crate::Trait for Test {
     type TextProposalMaxLength = TextProposalMaxLength;
     type RuntimeUpgradeWasmProposalMaxLength = RuntimeUpgradeWasmProposalMaxLength;

+ 421 - 108
runtime-modules/proposals/codex/src/tests/mod.rs

@@ -1,68 +1,120 @@
 mod mock;
 
+use governance::election_params::ElectionParameters;
 use srml_support::traits::Currency;
 use srml_support::StorageMap;
 use system::RawOrigin;
 
 use crate::{BalanceOf, Error};
 use mock::*;
+use proposal_engine::ProposalParameters;
+use srml_support::dispatch::DispatchResult;
 
-#[test]
-fn create_text_proposal_codex_call_succeeds() {
-    initial_test_ext().execute_with(|| {
-        let account_id = 1;
-        let proposer_id = 1;
-        let origin = RawOrigin::Signed(account_id).into();
+struct ProposalTestFixture<InsufficientRightsCall, EmptyStakeCall, InvalidStakeCall, SuccessfulCall>
+where
+    InsufficientRightsCall: Fn() -> DispatchResult<crate::Error>,
+    EmptyStakeCall: Fn() -> DispatchResult<crate::Error>,
+    InvalidStakeCall: Fn() -> DispatchResult<crate::Error>,
+    SuccessfulCall: Fn() -> DispatchResult<crate::Error>,
+{
+    insufficient_rights_call: InsufficientRightsCall,
+    empty_stake_call: EmptyStakeCall,
+    invalid_stake_call: InvalidStakeCall,
+    successful_call: SuccessfulCall,
+    proposal_parameters: ProposalParameters<u64, u64>,
+}
 
-        let required_stake = Some(<BalanceOf<Test>>::from(500u32));
-        let _imbalance = <Test as stake::Trait>::Currency::deposit_creating(&account_id, 50000);
+impl<InsufficientRightsCall, EmptyStakeCall, InvalidStakeCall, SuccessfulCall>
+    ProposalTestFixture<InsufficientRightsCall, EmptyStakeCall, InvalidStakeCall, SuccessfulCall>
+where
+    InsufficientRightsCall: Fn() -> DispatchResult<crate::Error>,
+    EmptyStakeCall: Fn() -> DispatchResult<crate::Error>,
+    InvalidStakeCall: Fn() -> DispatchResult<crate::Error>,
+    SuccessfulCall: Fn() -> DispatchResult<crate::Error>,
+{
+    fn check_for_invalid_stakes(&self) {
+        assert_eq!((self.empty_stake_call)(), Err(Error::Other("EmptyStake")));
 
         assert_eq!(
-            ProposalCodex::create_text_proposal(
-                origin,
-                proposer_id,
-                b"title".to_vec(),
-                b"body".to_vec(),
-                b"text".to_vec(),
-                required_stake,
-            ),
-            Ok(())
+            (self.invalid_stake_call)(),
+            Err(Error::Other("StakeDiffersFromRequired"))
         );
+    }
+
+    fn check_call_for_insufficient_rights(&self) {
+        assert!((self.insufficient_rights_call)().is_err());
+    }
+
+    fn check_for_successful_call(&self) {
+        let account_id = 1;
+        let _imbalance = <Test as stake::Trait>::Currency::deposit_creating(&account_id, 50000);
+
+        assert_eq!((self.successful_call)(), Ok(()));
 
         // a discussion was created
         let thread_id = <crate::ThreadIdByProposalId<Test>>::get(1);
         assert_eq!(thread_id, 1);
-    });
+
+        let proposal_id = 1;
+        let proposal = ProposalsEngine::proposals(proposal_id);
+        // check for correct proposal parameters
+        assert_eq!(proposal.parameters, self.proposal_parameters);
+    }
+
+    pub fn check_all(&self) {
+        self.check_call_for_insufficient_rights();
+        self.check_for_invalid_stakes();
+        self.check_for_successful_call();
+    }
 }
 
 #[test]
-fn create_text_proposal_codex_call_fails_with_invalid_stake() {
+fn create_text_proposal_common_checks_succeed() {
     initial_test_ext().execute_with(|| {
-        assert_eq!(
-            ProposalCodex::create_text_proposal(
-                RawOrigin::Signed(1).into(),
-                1,
-                b"title".to_vec(),
-                b"body".to_vec(),
-                b"text".to_vec(),
-                None,
-            ),
-            Err(Error::Other("EmptyStake"))
-        );
-
-        let invalid_stake = Some(<BalanceOf<Test>>::from(5000u32));
-
-        assert_eq!(
-            ProposalCodex::create_text_proposal(
-                RawOrigin::Signed(1).into(),
-                1,
-                b"title".to_vec(),
-                b"body".to_vec(),
-                b"text".to_vec(),
-                invalid_stake,
-            ),
-            Err(Error::Other("StakeDiffersFromRequired"))
-        );
+        let proposal_fixture = ProposalTestFixture {
+            insufficient_rights_call: || {
+                ProposalCodex::create_text_proposal(
+                    RawOrigin::None.into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    b"text".to_vec(),
+                )
+            },
+            empty_stake_call: || {
+                ProposalCodex::create_text_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    b"text".to_vec(),
+                )
+            },
+            invalid_stake_call: || {
+                ProposalCodex::create_text_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(5000u32)),
+                    b"text".to_vec(),
+                )
+            },
+            successful_call: || {
+                ProposalCodex::create_text_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(500u32)),
+                    b"text".to_vec(),
+                )
+            },
+            proposal_parameters: crate::proposal_types::parameters::text_proposal::<Test>(),
+        };
+        proposal_fixture.check_all();
     });
 }
 
@@ -78,8 +130,8 @@ fn create_text_proposal_codex_call_fails_with_incorrect_text_size() {
                 1,
                 b"title".to_vec(),
                 b"body".to_vec(),
-                long_text,
                 None,
+                long_text,
             ),
             Err(Error::TextProposalSizeExceeded)
         );
@@ -90,8 +142,8 @@ fn create_text_proposal_codex_call_fails_with_incorrect_text_size() {
                 1,
                 b"title".to_vec(),
                 b"body".to_vec(),
-                Vec::new(),
                 None,
+                Vec::new(),
             ),
             Err(Error::TextProposalIsEmpty)
         );
@@ -99,19 +151,52 @@ fn create_text_proposal_codex_call_fails_with_incorrect_text_size() {
 }
 
 #[test]
-fn create_text_proposal_codex_call_fails_with_insufficient_rights() {
+fn create_runtime_upgrade_common_checks_succeed() {
     initial_test_ext().execute_with(|| {
-        let origin = RawOrigin::None.into();
-
-        assert!(ProposalCodex::create_text_proposal(
-            origin,
-            1,
-            b"title".to_vec(),
-            b"body".to_vec(),
-            b"text".to_vec(),
-            None,
-        )
-        .is_err());
+        let proposal_fixture = ProposalTestFixture {
+            insufficient_rights_call: || {
+                ProposalCodex::create_runtime_upgrade_proposal(
+                    RawOrigin::None.into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    b"wasm".to_vec(),
+                )
+            },
+            empty_stake_call: || {
+                ProposalCodex::create_runtime_upgrade_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    b"wasm".to_vec(),
+                )
+            },
+            invalid_stake_call: || {
+                ProposalCodex::create_runtime_upgrade_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(500u32)),
+                    b"wasm".to_vec(),
+                )
+            },
+            successful_call: || {
+                ProposalCodex::create_runtime_upgrade_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(50000u32)),
+                    b"wasm".to_vec(),
+                )
+            },
+            proposal_parameters: crate::proposal_types::parameters::upgrade_runtime::<Test>(),
+        };
+        proposal_fixture.check_all();
     });
 }
 
@@ -127,8 +212,8 @@ fn create_upgrade_runtime_proposal_codex_call_fails_with_incorrect_wasm_size() {
                 1,
                 b"title".to_vec(),
                 b"body".to_vec(),
-                long_wasm,
                 None,
+                long_wasm,
             ),
             Err(Error::RuntimeProposalSizeExceeded)
         );
@@ -139,8 +224,8 @@ fn create_upgrade_runtime_proposal_codex_call_fails_with_incorrect_wasm_size() {
                 1,
                 b"title".to_vec(),
                 b"body".to_vec(),
-                Vec::new(),
                 None,
+                Vec::new(),
             ),
             Err(Error::RuntimeProposalIsEmpty)
         );
@@ -148,78 +233,306 @@ fn create_upgrade_runtime_proposal_codex_call_fails_with_incorrect_wasm_size() {
 }
 
 #[test]
-fn create_upgrade_runtime_proposal_codex_call_fails_with_insufficient_rights() {
+fn create_set_election_parameters_proposal_common_checks_succeed() {
     initial_test_ext().execute_with(|| {
-        let origin = RawOrigin::None.into();
-
-        assert!(ProposalCodex::create_runtime_upgrade_proposal(
-            origin,
-            1,
-            b"title".to_vec(),
-            b"body".to_vec(),
-            b"wasm".to_vec(),
-            None,
-        )
-        .is_err());
+        let election_parameters = ElectionParameters {
+            announcing_period: 1,
+            voting_period: 2,
+            revealing_period: 3,
+            council_size: 4,
+            candidacy_limit: 5,
+            min_voting_stake: 6,
+            min_council_stake: 7,
+            new_term_duration: 8,
+        };
+
+        let proposal_fixture = ProposalTestFixture {
+            insufficient_rights_call: || {
+                ProposalCodex::create_set_election_parameters_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(500u32)),
+                    ElectionParameters::default(),
+                )
+            },
+            empty_stake_call: || {
+                ProposalCodex::create_set_election_parameters_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    election_parameters.clone(),
+                )
+            },
+            invalid_stake_call: || {
+                ProposalCodex::create_set_election_parameters_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(50000u32)),
+                    election_parameters.clone(),
+                )
+            },
+            successful_call: || {
+                ProposalCodex::create_set_election_parameters_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(500u32)),
+                    election_parameters.clone(),
+                )
+            },
+            proposal_parameters:
+                crate::proposal_types::parameters::set_election_parameters_proposal::<Test>(),
+        };
+        proposal_fixture.check_all();
     });
 }
-
 #[test]
-fn create_runtime_upgrade_proposal_codex_call_fails_with_invalid_stake() {
+fn create_set_election_parameters_call_fails_with_incorrect_parameters() {
     initial_test_ext().execute_with(|| {
-        let proposer_id = 1;
-        assert_eq!(
-            ProposalCodex::create_runtime_upgrade_proposal(
-                RawOrigin::Signed(1).into(),
-                proposer_id,
-                b"title".to_vec(),
-                b"body".to_vec(),
-                b"wasm".to_vec(),
-                None,
-            ),
-            Err(Error::Other("EmptyStake"))
-        );
-
-        let invalid_stake = Some(<BalanceOf<Test>>::from(500u32));
+        let account_id = 1;
+        let required_stake = Some(<BalanceOf<Test>>::from(500u32));
+        let _imbalance = <Test as stake::Trait>::Currency::deposit_creating(&account_id, 50000);
 
         assert_eq!(
-            ProposalCodex::create_runtime_upgrade_proposal(
+            ProposalCodex::create_set_election_parameters_proposal(
                 RawOrigin::Signed(1).into(),
-                proposer_id,
+                1,
                 b"title".to_vec(),
                 b"body".to_vec(),
-                b"wasm".to_vec(),
-                invalid_stake,
+                required_stake,
+                ElectionParameters::default(),
             ),
-            Err(Error::Other("StakeDiffersFromRequired"))
+            Err(Error::Other("PeriodCannotBeZero"))
         );
     });
 }
 
 #[test]
-fn create_runtime_upgrade_proposal_codex_call_succeeds() {
+fn create_set_council_mint_capacity_proposal_common_checks_succeed() {
     initial_test_ext().execute_with(|| {
-        let account_id = 1;
-        let proposer_id = 1;
-        let origin = RawOrigin::Signed(account_id).into();
+        let proposal_fixture = ProposalTestFixture {
+            insufficient_rights_call: || {
+                ProposalCodex::create_set_council_mint_capacity_proposal(
+                    RawOrigin::None.into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    0,
+                )
+            },
+            empty_stake_call: || {
+                ProposalCodex::create_set_council_mint_capacity_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    0,
+                )
+            },
+            invalid_stake_call: || {
+                ProposalCodex::create_set_council_mint_capacity_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(5000u32)),
+                    0,
+                )
+            },
+            successful_call: || {
+                ProposalCodex::create_set_council_mint_capacity_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(500u32)),
+                    0,
+                )
+            },
+            proposal_parameters:
+                crate::proposal_types::parameters::set_council_mint_capacity_proposal::<Test>(),
+        };
+        proposal_fixture.check_all();
+    });
+}
 
-        let required_stake = Some(<BalanceOf<Test>>::from(50000u32));
-        let _imbalance = <Test as stake::Trait>::Currency::deposit_creating(&account_id, 50000);
+#[test]
+fn create_set_content_working_group_mint_capacity_proposal_common_checks_succeed() {
+    initial_test_ext().execute_with(|| {
+        let proposal_fixture = ProposalTestFixture {
+            insufficient_rights_call: || {
+                ProposalCodex::create_set_content_working_group_mint_capacity_proposal(
+                    RawOrigin::None.into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    0,
+                )
+            },
+            empty_stake_call: || {
+                ProposalCodex::create_set_content_working_group_mint_capacity_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    0,
+                )
+            },
+            invalid_stake_call: || {
+                ProposalCodex::create_set_content_working_group_mint_capacity_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(5000u32)),
+                    0,
+                )
+            },
+            successful_call: || {
+                ProposalCodex::create_set_content_working_group_mint_capacity_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(500u32)),
+                    0,
+                )
+            },
+            proposal_parameters: crate::proposal_types::parameters::set_content_working_group_mint_capacity_proposal::<Test>(),
+        };
+        proposal_fixture.check_all();
+    });
+}
+
+#[test]
+fn create_spending_proposal_common_checks_succeed() {
+    initial_test_ext().execute_with(|| {
+        let proposal_fixture = ProposalTestFixture {
+            insufficient_rights_call: || {
+                ProposalCodex::create_spending_proposal(
+                    RawOrigin::None.into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    20,
+                    10,
+                )
+            },
+            empty_stake_call: || {
+                ProposalCodex::create_spending_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    20,
+                    10,
+                )
+            },
+            invalid_stake_call: || {
+                ProposalCodex::create_spending_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(5000u32)),
+                    20,
+                    10,
+                )
+            },
+            successful_call: || {
+                ProposalCodex::create_spending_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(500u32)),
+                    100,
+                    2,
+                )
+            },
+            proposal_parameters: crate::proposal_types::parameters::spending_proposal::<Test>(),
+        };
+        proposal_fixture.check_all();
+    });
+}
 
+#[test]
+fn create_spending_proposal_call_fails_with_incorrect_balance() {
+    initial_test_ext().execute_with(|| {
         assert_eq!(
-            ProposalCodex::create_runtime_upgrade_proposal(
-                origin,
-                proposer_id,
+            ProposalCodex::create_spending_proposal(
+                RawOrigin::Signed(1).into(),
+                1,
                 b"title".to_vec(),
                 b"body".to_vec(),
-                b"wasm".to_vec(),
-                required_stake,
+                Some(<BalanceOf<Test>>::from(500u32)),
+                0,
+                2,
             ),
-            Ok(())
+            Err(Error::SpendingProposalZeroBalance)
         );
+    });
+}
 
-        // a discussion was created
-        let thread_id = <crate::ThreadIdByProposalId<Test>>::get(1);
-        assert_eq!(thread_id, 1);
+#[test]
+fn create_set_lead_proposal_common_checks_succeed() {
+    initial_test_ext().execute_with(|| {
+        let proposal_fixture = ProposalTestFixture {
+            insufficient_rights_call: || {
+                ProposalCodex::create_set_lead_proposal(
+                    RawOrigin::None.into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    Some((20, 10)),
+                )
+            },
+            empty_stake_call: || {
+                ProposalCodex::create_set_lead_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    Some((20, 10)),
+                )
+            },
+            invalid_stake_call: || {
+                ProposalCodex::create_set_lead_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(5000u32)),
+                    Some((20, 10)),
+                )
+            },
+            successful_call: || {
+                ProposalCodex::create_set_lead_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(500u32)),
+                    Some((20, 10)),
+                )
+            },
+            proposal_parameters: crate::proposal_types::parameters::set_lead_proposal::<Test>(),
+        };
+        proposal_fixture.check_all();
     });
 }

+ 1 - 3
runtime-modules/proposals/discussion/src/lib.rs

@@ -7,6 +7,7 @@
 //!
 //! Public API:
 //! - create_discussion - creates a discussion
+//! - ensure_can_create_thread - ensures safe thread creation
 //!
 
 // Ensure we're `no_std` when compiling for Wasm.
@@ -84,9 +85,6 @@ pub trait Trait: system::Trait + membership::members::Trait {
 
 decl_error! {
     pub enum Error {
-        /// The size of the provided text for text proposal exceeded the limit
-        TextProposalSizeExceeded,
-
         /// Author should match the post creator
         NotAuthor,
 

+ 2 - 0
runtime-modules/proposals/discussion/src/types.rs

@@ -1,3 +1,5 @@
+#![warn(missing_docs)]
+
 use codec::{Decode, Encode};
 #[cfg(feature = "std")]
 use serde::{Deserialize, Serialize};

+ 0 - 14
runtime-modules/proposals/engine/src/errors.rs

@@ -1,14 +0,0 @@
-pub const MSG_EMPTY_TITLE_PROVIDED: &str = "Proposal cannot have an empty title";
-pub const MSG_EMPTY_BODY_PROVIDED: &str = "Proposal cannot have an empty body";
-pub const MSG_TOO_LONG_TITLE: &str = "Title is too long";
-pub const MSG_TOO_LONG_BODY: &str = "Body is too long";
-pub const MSG_PROPOSAL_NOT_FOUND: &str = "This proposal does not exist";
-pub const MSG_PROPOSAL_FINALIZED: &str = "Proposal is finalized already";
-pub const MSG_YOU_ALREADY_VOTED: &str = "You have already voted on this proposal";
-pub const MSG_YOU_DONT_OWN_THIS_PROPOSAL: &str = "You do not own this proposal";
-pub const MSG_MAX_ACTIVE_PROPOSAL_NUMBER_EXCEEDED: &str = "Max active proposals number exceeded";
-pub const MSG_STAKE_IS_EMPTY: &str = "Stake cannot be empty with this proposal";
-pub const MSG_STAKE_SHOULD_BE_EMPTY: &str = "Stake should be empty for this proposal";
-pub const MSG_STAKE_DIFFERS_FROM_REQUIRED: &str = "Stake differs from the proposal requirements";
-pub const MSG_INVALID_PARAMETER_APPROVAL_THRESHOLD: &str = "Approval threshold cannot be zero";
-pub const MSG_INVALID_PARAMETER_SLASHING_THRESHOLD: &str = "Slashing threshold cannot be zero";

+ 35 - 16
runtime-modules/proposals/engine/src/lib.rs

@@ -7,8 +7,11 @@
 //! - cancel_proposal - cancels the proposal (can be canceled only by owner)
 //! - veto_proposal - vetoes the proposal
 //!
-//! Public API (requires root origin):
+//! Public API:
 //! - create_proposal - creates proposal using provided parameters
+//! - ensure_create_proposal_parameters_are_valid - ensures that we can create the proposal
+//! - refund_proposal_stake - a callback for StakingHandlerEvents
+//! - reset_active_proposals - resets voting results for active proposals
 //!
 
 // Ensure we're `no_std` when compiling for Wasm.
@@ -17,12 +20,6 @@
 // Do not delete! Cannot be uncommented by default, because of Parity decl_module! issue.
 //#![warn(missing_docs)]
 
-// TODO: Test module after the https://github.com/Joystream/substrate-runtime-joystream/issues/161
-// issue will be fixed: "Fix stake module and allow slashing and unstaking in the same block."
-// TODO: Test cancellation, rejection fees
-// TODO: Test StakingEventHandler
-// TODO: Test refund_proposal_stake()
-
 use types::FinalizedProposalData;
 use types::ProposalStakeManager;
 pub use types::{
@@ -379,7 +376,7 @@ impl<T: Trait> Module<T> {
 
     /// Performs all checks for the proposal creation:
     /// - title, body lengths
-    /// - mac active proposal
+    /// - max active proposal
     /// - provided parameters: approval_threshold_percentage and slashing_threshold_percentage > 0
     /// - provided stake balance and parameters.required_stake are valid
     pub fn ensure_create_proposal_parameters_are_valid(
@@ -434,12 +431,11 @@ impl<T: Trait> Module<T> {
         Ok(())
     }
 
-    //TODO: candidate for invariant break or error saving to the state
-    /// Callback from StakingEventsHandler. Refunds unstaked imbalance back to the source account
+    /// Callback from StakingEventsHandler. Refunds unstaked imbalance back to the source account.
+    /// There can be a lot of invariant breaks in the scope of this proposal.
+    /// Such situations are handled by adding error messages to the log.
     pub fn refund_proposal_stake(stake_id: T::StakeId, imbalance: NegativeImbalance<T>) {
         if <StakesProposals<T>>::exists(stake_id) {
-            //TODO: handle non existence
-
             let proposal_id = Self::stakes_proposals(stake_id);
 
             if <Proposals<T>>::exists(proposal_id) {
@@ -447,16 +443,35 @@ impl<T: Trait> Module<T> {
 
                 if let ProposalStatus::Active(active_stake_result) = proposal.status {
                     if let Some(active_stake) = active_stake_result {
-                        //TODO: handle the result
-                        let _ = CurrencyOf::<T>::resolve_into_existing(
+                        let refunding_result = CurrencyOf::<T>::resolve_into_existing(
                             &active_stake.source_account_id,
                             imbalance,
                         );
+
+                        if refunding_result.is_err() {
+                            print("Broken invariant: cannot refund");
+                        }
                     }
+                } else {
+                    print("Broken invariant: proposal status is not Active");
                 }
+            } else {
+                print("Broken invariant: proposal doesn't exist");
             }
+        } else {
+            print("Broken invariant: stake doesn't exist");
         }
     }
+
+    /// Resets voting results for active proposals.
+    /// Possible application - after the new council elections.
+    pub fn reset_active_proposals() {
+        <ActiveProposalIds<T>>::enumerate().for_each(|(proposal_id, _)| {
+            <Proposals<T>>::mutate(proposal_id, |proposal| {
+                proposal.reset_proposal();
+            });
+        });
+    }
 }
 
 impl<T: Trait> Module<T> {
@@ -552,8 +567,12 @@ impl<T: Trait> Module<T> {
                 Self::slash_and_unstake(active_stake.clone(), slash_balance);
 
             // create finalized proposal status with error if any
-            let new_proposal_status = //TODO rename without an error
-            ProposalStatus::finalized_with_error(decision_status, slash_and_unstake_result.err(), active_stake, Self::current_block());
+            let new_proposal_status = ProposalStatus::finalized(
+                decision_status,
+                slash_and_unstake_result.err(),
+                active_stake,
+                Self::current_block(),
+            );
 
             proposal.status = new_proposal_status.clone();
             <Proposals<T>>::insert(proposal_id, proposal);

+ 4 - 9
runtime-modules/proposals/engine/src/tests/mock/balance_manager.rs

@@ -23,16 +23,11 @@ impl stake::StakingEventsHandler<Test> for BalanceManagerStakingEventsHandler {
 
     fn slashed(
         _id: &u64,
-        _slash_id: Option<u64>,
-        slashed_amount: stake::BalanceOf<Test>,
+        _slash_id: Option<<Test as stake::Trait>::SlashId>,
+        _slashed_amount: stake::BalanceOf<Test>,
         _remaining_stake: stake::BalanceOf<Test>,
-        _imbalance: stake::NegativeImbalance<Test>,
+        imbalance: stake::NegativeImbalance<Test>,
     ) -> stake::NegativeImbalance<Test> {
-        let default_account_id = 1;
-
-        let (remaining_imbalance, _) =
-            <Test as stake::Trait>::Currency::slash(&default_account_id, slashed_amount);
-
-        remaining_imbalance
+        imbalance
     }
 }

+ 165 - 22
runtime-modules/proposals/engine/src/tests/mod.rs

@@ -464,7 +464,7 @@ fn rejected_voting_results_and_remove_proposal_id_from_active_succeeds() {
 
         assert_eq!(
             proposal.status,
-            ProposalStatus::finalized(ProposalDecisionStatus::Rejected, 1),
+            ProposalStatus::finalized_successfully(ProposalDecisionStatus::Rejected, 1),
         );
         assert!(!<ActiveProposalIds<Test>>::exists(proposal_id));
     });
@@ -566,7 +566,7 @@ fn cancel_proposal_succeeds() {
                 parameters: parameters_fixture.params(),
                 proposer_id: 1,
                 created_at: 1,
-                status: ProposalStatus::finalized(ProposalDecisionStatus::Canceled, 1),
+                status: ProposalStatus::finalized_successfully(ProposalDecisionStatus::Canceled, 1),
                 title: b"title".to_vec(),
                 description: b"description".to_vec(),
                 voting_results: VotingResults::default(),
@@ -634,7 +634,7 @@ fn veto_proposal_succeeds() {
                 parameters: parameters_fixture.params(),
                 proposer_id: 1,
                 created_at: 1,
-                status: ProposalStatus::finalized(ProposalDecisionStatus::Vetoed, 1),
+                status: ProposalStatus::finalized_successfully(ProposalDecisionStatus::Vetoed, 1),
                 title: b"title".to_vec(),
                 description: b"description".to_vec(),
                 voting_results: VotingResults::default(),
@@ -701,7 +701,7 @@ fn veto_proposal_event_emitted() {
             RawEvent::ProposalCreated(1, 1),
             RawEvent::ProposalStatusUpdated(
                 1,
-                ProposalStatus::finalized(ProposalDecisionStatus::Vetoed, 1),
+                ProposalStatus::finalized_successfully(ProposalDecisionStatus::Vetoed, 1),
             ),
         ]);
     });
@@ -765,7 +765,7 @@ fn create_proposal_and_expire_it() {
                 parameters: parameters_fixture.params(),
                 proposer_id: 1,
                 created_at: 1,
-                status: ProposalStatus::finalized(ProposalDecisionStatus::Expired, 4),
+                status: ProposalStatus::finalized_successfully(ProposalDecisionStatus::Expired, 4),
                 title: b"title".to_vec(),
                 description: b"description".to_vec(),
                 voting_results: VotingResults::default(),
@@ -1004,8 +1004,7 @@ fn create_proposal_fais_with_invalid_stake_parameters() {
         dummy_proposal.create_proposal_and_assert(Err(Error::StakeDiffersFromRequired.into()));
     });
 }
-/* TODO: restore after the https://github.com/Joystream/substrate-runtime-joystream/issues/161
-// issue will be fixed: "Fix stake module and allow slashing and unstaking in the same block."
+
 #[test]
 fn finalize_expired_proposal_and_check_stake_removing_with_balance_checks_succeeds() {
     initial_test_ext().execute_with(|| {
@@ -1023,7 +1022,7 @@ fn finalize_expired_proposal_and_check_stake_removing_with_balance_checks_succee
         };
         let dummy_proposal = DummyProposalFixture::default()
             .with_parameters(parameters)
-            .with_origin(RawOrigin::Signed(account_id))
+            .with_account_id(account_id)
             .with_stake(stake_amount);
 
         let account_balance = 500;
@@ -1035,7 +1034,7 @@ fn finalize_expired_proposal_and_check_stake_removing_with_balance_checks_succee
             account_balance
         );
 
-        let proposal_id = dummy_proposal.create_proposal_and_assert(Ok(())).unwrap();
+        let proposal_id = dummy_proposal.create_proposal_and_assert(Ok(1)).unwrap();
         assert_eq!(
             <Test as stake::Trait>::Currency::total_balance(&account_id),
             account_balance - stake_amount
@@ -1044,17 +1043,16 @@ fn finalize_expired_proposal_and_check_stake_removing_with_balance_checks_succee
         let mut proposal = <crate::Proposals<Test>>::get(proposal_id);
 
         let mut expected_proposal = Proposal {
-            proposal_type: 1,
             parameters,
             proposer_id: 1,
             created_at: 1,
-            status: ProposalStatus::Active,
+            status: ProposalStatus::Active(Some(ActiveStake {
+                stake_id: 0,
+                source_account_id: 1,
+            })),
             title: b"title".to_vec(),
-            body: b"body".to_vec(),
-            approved_at: None,
+            description: b"description".to_vec(),
             voting_results: VotingResults::default(),
-            finalized_at: None,
-            stake_id: Some(0), // valid stake_id
         };
 
         assert_eq!(proposal, expected_proposal);
@@ -1063,23 +1061,98 @@ fn finalize_expired_proposal_and_check_stake_removing_with_balance_checks_succee
 
         proposal = <crate::Proposals<Test>>::get(proposal_id);
 
-        expected_proposal.stake_id = None;
-        expected_proposal.finalized_at = Some(4);
-        expected_proposal.status = ProposalStatus::Finalized(FinalizationStatus {
+        expected_proposal.status = ProposalStatus::Finalized(FinalizationData {
             proposal_status: ProposalDecisionStatus::Expired,
-            finalization_error: None,
+            finalized_at: 4,
+            encoded_unstaking_error_due_to_broken_runtime: None,
+            stake_data_after_unstaking_error: None,
         });
 
         assert_eq!(proposal, expected_proposal);
 
-        let rejection_fee = <RejectionFee<Test>>::get();
+        let rejection_fee = RejectionFee::get();
         assert_eq!(
             <Test as stake::Trait>::Currency::total_balance(&account_id),
             account_balance - rejection_fee
         );
     });
 }
-*/
+
+#[test]
+fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
+    initial_test_ext().execute_with(|| {
+        let account_id = 1;
+
+        let stake_amount = 200;
+        let parameters = ProposalParameters {
+            voting_period: 3,
+            approval_quorum_percentage: 50,
+            approval_threshold_percentage: 60,
+            slashing_quorum_percentage: 60,
+            slashing_threshold_percentage: 60,
+            grace_period: 5,
+            required_stake: Some(stake_amount),
+        };
+        let dummy_proposal = DummyProposalFixture::default()
+            .with_parameters(parameters)
+            .with_account_id(account_id.clone())
+            .with_stake(stake_amount);
+
+        let account_balance = 500;
+        let _imbalance =
+            <Test as stake::Trait>::Currency::deposit_creating(&account_id, account_balance);
+
+        assert_eq!(
+            <Test as stake::Trait>::Currency::total_balance(&account_id),
+            account_balance
+        );
+
+        let proposal_id = dummy_proposal.create_proposal_and_assert(Ok(1)).unwrap();
+        assert_eq!(
+            <Test as stake::Trait>::Currency::total_balance(&account_id),
+            account_balance - stake_amount
+        );
+
+        let mut proposal = <crate::Proposals<Test>>::get(proposal_id);
+
+        let mut expected_proposal = Proposal {
+            parameters,
+            proposer_id: 1,
+            created_at: 1,
+            status: ProposalStatus::Active(Some(ActiveStake {
+                stake_id: 0,
+                source_account_id: 1,
+            })),
+            title: b"title".to_vec(),
+            description: b"description".to_vec(),
+            voting_results: VotingResults::default(),
+        };
+
+        assert_eq!(proposal, expected_proposal);
+
+        let cancel_proposal_fixture = CancelProposalFixture::new(proposal_id);
+
+        cancel_proposal_fixture.cancel_and_assert(Ok(()));
+
+        proposal = <crate::Proposals<Test>>::get(proposal_id);
+
+        expected_proposal.status = ProposalStatus::Finalized(FinalizationData {
+            proposal_status: ProposalDecisionStatus::Canceled,
+            finalized_at: 1,
+            encoded_unstaking_error_due_to_broken_runtime: None,
+            stake_data_after_unstaking_error: None,
+        });
+
+        assert_eq!(proposal, expected_proposal);
+
+        let cancellation_fee = CancellationFee::get();
+        assert_eq!(
+            <Test as stake::Trait>::Currency::total_balance(&account_id),
+            account_balance - cancellation_fee
+        );
+    });
+}
+
 #[test]
 fn finalize_proposal_using_stake_mocks_succeeds() {
     handle_mock(|| {
@@ -1209,7 +1282,7 @@ fn finalize_proposal_using_stake_mocks_failed() {
                     parameters: parameters_fixture.params(),
                     proposer_id: 1,
                     created_at: 1,
-                    status: ProposalStatus::finalized_with_error(
+                    status: ProposalStatus::finalized(
                         ProposalDecisionStatus::Expired,
                         Some("Cannot remove stake"),
                         Some(ActiveStake {
@@ -1226,3 +1299,73 @@ fn finalize_proposal_using_stake_mocks_failed() {
         });
     });
 }
+
+#[test]
+fn create_proposal_fails_with_invalid_threshold_parameters() {
+    initial_test_ext().execute_with(|| {
+        let mut parameters = ProposalParameters {
+            voting_period: 3,
+            approval_quorum_percentage: 50,
+            approval_threshold_percentage: 0,
+            slashing_quorum_percentage: 60,
+            slashing_threshold_percentage: 60,
+            grace_period: 5,
+            required_stake: None,
+        };
+
+        let mut dummy_proposal = DummyProposalFixture::default().with_parameters(parameters);
+
+        dummy_proposal
+            .create_proposal_and_assert(Err(Error::InvalidParameterApprovalThreshold.into()));
+
+        parameters.approval_threshold_percentage = 60;
+        parameters.slashing_threshold_percentage = 0;
+        dummy_proposal = DummyProposalFixture::default().with_parameters(parameters);
+
+        dummy_proposal
+            .create_proposal_and_assert(Err(Error::InvalidParameterSlashingThreshold.into()));
+    });
+}
+
+#[test]
+fn proposal_reset_succeeds() {
+    initial_test_ext().execute_with(|| {
+        let dummy_proposal = DummyProposalFixture::default();
+        let proposal_id = dummy_proposal.create_proposal_and_assert(Ok(1)).unwrap();
+
+        let mut vote_generator = VoteGenerator::new(proposal_id);
+        vote_generator.vote_and_assert_ok(VoteKind::Reject);
+        vote_generator.vote_and_assert_ok(VoteKind::Abstain);
+        vote_generator.vote_and_assert_ok(VoteKind::Slash);
+
+        assert!(<ActiveProposalIds<Test>>::exists(proposal_id));
+
+        run_to_block_and_finalize(2);
+
+        let proposal = <Proposals<Test>>::get(proposal_id);
+
+        assert_eq!(
+            proposal.voting_results,
+            VotingResults {
+                abstentions: 1,
+                approvals: 0,
+                rejections: 1,
+                slashes: 1,
+            }
+        );
+
+        ProposalsEngine::reset_active_proposals();
+
+        let updated_proposal = <Proposals<Test>>::get(proposal_id);
+
+        assert_eq!(
+            updated_proposal.voting_results,
+            VotingResults {
+                abstentions: 0,
+                approvals: 0,
+                rejections: 0,
+                slashes: 0,
+            }
+        );
+    });
+}

+ 12 - 2
runtime-modules/proposals/engine/src/types/mod.rs

@@ -1,6 +1,8 @@
 //! Proposals types module for the Joystream platform. Version 2.
 //! Provides types for the proposal engine.
 
+#![warn(missing_docs)]
+
 use codec::{Decode, Encode};
 use rstd::cmp::PartialOrd;
 use rstd::ops::Add;
@@ -210,6 +212,14 @@ where
             None
         }
     }
+
+    /// Reset the proposal in Active status. Proposal with other status won't be changed.
+    /// Reset proposal operation clears voting results.
+    pub fn reset_proposal(&mut self) {
+        if let ProposalStatus::Active(_) = self.status.clone() {
+            self.voting_results = VotingResults::default();
+        }
+    }
 }
 
 /// Provides data for voting.
@@ -389,7 +399,7 @@ mod tests {
         let mut proposal = ProposalObject::default();
 
         proposal.parameters.grace_period = 3;
-        proposal.status = ProposalStatus::finalized(
+        proposal.status = ProposalStatus::finalized_successfully(
             ProposalDecisionStatus::Approved(ApprovedProposalStatus::PendingExecution),
             0,
         );
@@ -402,7 +412,7 @@ mod tests {
         let mut proposal = ProposalObject::default();
 
         proposal.parameters.grace_period = 0;
-        proposal.status = ProposalStatus::finalized(
+        proposal.status = ProposalStatus::finalized_successfully(
             ProposalDecisionStatus::Approved(ApprovedProposalStatus::PendingExecution),
             0,
         );

+ 12 - 4
runtime-modules/proposals/engine/src/types/proposal_statuses.rs

@@ -1,3 +1,5 @@
+#![warn(missing_docs)]
+
 use codec::{Decode, Encode};
 use rstd::prelude::*;
 
@@ -24,26 +26,32 @@ impl<BlockNumber, StakeId, AccountId> Default for ProposalStatus<BlockNumber, St
 
 impl<BlockNumber, StakeId, AccountId> ProposalStatus<BlockNumber, StakeId, AccountId> {
     /// Creates finalized proposal status with provided ProposalDecisionStatus
-    pub fn finalized(
+    pub fn finalized_successfully(
         decision_status: ProposalDecisionStatus,
         now: BlockNumber,
     ) -> ProposalStatus<BlockNumber, StakeId, AccountId> {
-        Self::finalized_with_error(decision_status, None, None, now)
+        Self::finalized(decision_status, None, None, now)
     }
 
     /// Creates finalized proposal status with provided ProposalDecisionStatus and error
-    pub fn finalized_with_error(
+    pub fn finalized(
         decision_status: ProposalDecisionStatus,
         encoded_unstaking_error_due_to_broken_runtime: Option<&str>,
         active_stake: Option<ActiveStake<StakeId, AccountId>>,
         now: BlockNumber,
     ) -> ProposalStatus<BlockNumber, StakeId, AccountId> {
+        // drop the stake information if there were no errors on unstaking
+        let actual_stake = if encoded_unstaking_error_due_to_broken_runtime.is_some() {
+            active_stake
+        } else {
+            None
+        };
         ProposalStatus::Finalized(FinalizationData {
             proposal_status: decision_status,
             encoded_unstaking_error_due_to_broken_runtime:
                 encoded_unstaking_error_due_to_broken_runtime.map(|err| err.as_bytes().to_vec()),
             finalized_at: now,
-            stake_data_after_unstaking_error: active_stake,
+            stake_data_after_unstaking_error: actual_stake,
         })
     }
 

+ 22 - 6
runtime-modules/proposals/engine/src/types/stakes.rs

@@ -1,9 +1,10 @@
+#![warn(missing_docs)]
+
 use super::{BalanceOf, CurrencyOf, NegativeImbalance};
 use crate::Trait;
 use rstd::convert::From;
 use rstd::marker::PhantomData;
 use rstd::rc::Rc;
-use sr_primitives::traits::Zero;
 use srml_support::traits::{Currency, ExistenceRequirement, WithdrawReasons};
 
 // Mocking dependencies for testing
@@ -92,8 +93,7 @@ impl<T: Trait> StakeHandler<T> for DefaultStakeHandler<T> {
 
     /// Execute unstaking
     fn unstake(&self, stake_id: <T as stake::Trait>::StakeId) -> Result<(), &'static str> {
-        stake::Module::<T>::initiate_unstaking(&stake_id, Some(T::BlockNumber::zero()))
-            .map_err(WrappedError)?;
+        stake::Module::<T>::initiate_unstaking(&stake_id, None).map_err(WrappedError)?;
 
         Ok(())
     }
@@ -104,8 +104,8 @@ impl<T: Trait> StakeHandler<T> for DefaultStakeHandler<T> {
         stake_id: <T as stake::Trait>::StakeId,
         slash_balance: BalanceOf<T>,
     ) -> Result<(), &'static str> {
-        let _slash_id =
-            stake::Module::<T>::initiate_slashing(&stake_id, slash_balance, T::BlockNumber::zero())
+        let _ignored_successful_result =
+            stake::Module::<T>::slash_immediate(&stake_id, slash_balance, false)
                 .map_err(WrappedError)?;
 
         Ok(())
@@ -153,7 +153,6 @@ impl<T: Trait> ProposalStakeManager<T> {
     pub fn remove_stake(stake_id: T::StakeId) -> Result<(), &'static str> {
         T::StakeHandlerProvider::stakes().unstake(stake_id)?;
 
-        //TODO: can't remove stake before refunding
         T::StakeHandlerProvider::stakes().remove_stake(stake_id)?;
 
         Ok(())
@@ -229,3 +228,20 @@ impl From<WrappedError<stake::StakeActionError<stake::InitiateSlashingError>>> f
         }
     }
 }
+
+// error conversion for the Wrapped StakeActionError with the inner ImmediateSlashingError
+impl From<WrappedError<stake::StakeActionError<stake::ImmediateSlashingError>>> for &str {
+    fn from(wrapper: WrappedError<stake::StakeActionError<stake::ImmediateSlashingError>>) -> Self {
+        {
+            match wrapper.0 {
+                stake::StakeActionError::StakeNotFound => "StakeNotFound",
+                stake::StakeActionError::Error(err) => match err {
+                    stake::ImmediateSlashingError::NotStaked => "NotStaked",
+                    stake::ImmediateSlashingError::SlashAmountShouldBeGreaterThanZero => {
+                        "SlashAmountShouldBeGreaterThanZero"
+                    }
+                },
+            }
+        }
+    }
+}

+ 14 - 0
runtime/src/integration/proposals/council_elected_handler.rs

@@ -0,0 +1,14 @@
+#![warn(missing_docs)]
+
+use crate::Runtime;
+use governance::election::CouncilElected;
+
+/// 'Council elected' event handler. Should be applied to the 'election' substrate module.
+/// CouncilEvent is handled by resetting active proposals.
+pub struct CouncilElectedHandler;
+
+impl<Elected, Term> CouncilElected<Elected, Term> for CouncilElectedHandler {
+    fn council_elected(_new_council: Elected, _term: Term) {
+        <proposals_engine::Module<Runtime>>::reset_active_proposals();
+    }
+}

+ 2 - 0
runtime/src/integration/proposals/council_origin_validator.rs

@@ -1,3 +1,5 @@
+#![warn(missing_docs)]
+
 use rstd::marker::PhantomData;
 
 use common::origin_validator::ActorOriginValidator;

+ 2 - 0
runtime/src/integration/proposals/membership_origin_validator.rs

@@ -1,3 +1,5 @@
+#![warn(missing_docs)]
+
 use rstd::marker::PhantomData;
 
 use common::origin_validator::ActorOriginValidator;

+ 4 - 0
runtime/src/integration/proposals/mod.rs

@@ -1,7 +1,11 @@
+#![warn(missing_docs)]
+
+mod council_elected_handler;
 mod council_origin_validator;
 mod membership_origin_validator;
 mod staking_events_handler;
 
+pub use council_elected_handler::CouncilElectedHandler;
 pub use council_origin_validator::CouncilManager;
 pub use membership_origin_validator::{MemberId, MembershipOriginValidator};
 pub use staking_events_handler::StakingEventsHandler;

+ 2 - 0
runtime/src/integration/proposals/staking_events_handler.rs

@@ -1,3 +1,5 @@
+#![warn(missing_docs)]
+
 use rstd::marker::PhantomData;
 use srml_support::traits::{Currency, Imbalance};
 use srml_support::StorageMap;

+ 5 - 2
runtime/src/lib.rs

@@ -1,4 +1,4 @@
-//! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.
+//! The Joystream Substrate Node runtime.
 
 #![cfg_attr(not(feature = "std"), no_std)]
 // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
@@ -7,6 +7,9 @@
 // TODO: remove after post-Rome substrate upgrade
 #![allow(array_into_iter)]
 
+// Runtime integration tests
+mod test;
+
 // Make the WASM binary available.
 // This is required only by the node build.
 // A dummy wasm_binary.rs will be built for the IDE.
@@ -670,7 +673,7 @@ impl common::currency::GovernanceCurrency for Runtime {
 
 impl governance::election::Trait for Runtime {
     type Event = Event;
-    type CouncilElected = (Council,);
+    type CouncilElected = (Council, integration::proposals::CouncilElectedHandler);
 }
 
 impl governance::council::Trait for Runtime {

+ 5 - 0
runtime/src/test/mod.rs

@@ -0,0 +1,5 @@
+//! The Joystream Substrate Node runtime integration tests.
+
+#![cfg(test)]
+
+mod proposals_integration;

+ 367 - 0
runtime/src/test/proposals_integration.rs

@@ -0,0 +1,367 @@
+//! Proposals integration tests - with stake, membership, governance modules.
+
+#![cfg(test)]
+
+use crate::{ProposalCancellationFee, Runtime};
+use codec::Encode;
+use governance::election::CouncilElected;
+use membership::members;
+use proposals_engine::{
+    ActiveStake, BalanceOf, Error, FinalizationData, Proposal, ProposalDecisionStatus,
+    ProposalParameters, ProposalStatus, VoteKind, VotersParameters, VotingResults,
+};
+use sr_primitives::traits::DispatchResult;
+use sr_primitives::AccountId32;
+use srml_support::traits::Currency;
+use srml_support::StorageLinkedMap;
+use system::RawOrigin;
+
+use crate::CouncilManager;
+
+fn initial_test_ext() -> runtime_io::TestExternalities {
+    let t = system::GenesisConfig::default()
+        .build_storage::<Runtime>()
+        .unwrap();
+
+    t.into()
+}
+
+type Membership = membership::members::Module<Runtime>;
+type ProposalsEngine = proposals_engine::Module<Runtime>;
+type Council = governance::council::Module<Runtime>;
+
+fn setup_members(count: u8) {
+    let authority_account_id = <Runtime as system::Trait>::AccountId::default();
+    Membership::set_screening_authority(RawOrigin::Root.into(), authority_account_id.clone())
+        .unwrap();
+
+    for i in 0..count {
+        let account_id: [u8; 32] = [i; 32];
+        Membership::add_screened_member(
+            RawOrigin::Signed(authority_account_id.clone().into()).into(),
+            account_id.clone().into(),
+            members::UserInfo {
+                handle: Some(account_id.to_vec()),
+                avatar_uri: None,
+                about: None,
+            },
+        )
+        .unwrap();
+    }
+}
+
+fn setup_council() {
+    let councilor0 = AccountId32::default();
+    let councilor1: [u8; 32] = [1; 32];
+    let councilor2: [u8; 32] = [2; 32];
+    let councilor3: [u8; 32] = [3; 32];
+    let councilor4: [u8; 32] = [4; 32];
+    let councilor5: [u8; 32] = [5; 32];
+    assert!(Council::set_council(
+        system::RawOrigin::Root.into(),
+        vec![
+            councilor0,
+            councilor1.into(),
+            councilor2.into(),
+            councilor3.into(),
+            councilor4.into(),
+            councilor5.into()
+        ]
+    )
+    .is_ok());
+}
+
+struct VoteGenerator {
+    proposal_id: u32,
+    current_account_id: AccountId32,
+    current_account_id_seed: u8,
+    current_voter_id: u64,
+    pub auto_increment_voter_id: bool,
+}
+
+impl VoteGenerator {
+    fn new(proposal_id: u32) -> Self {
+        VoteGenerator {
+            proposal_id,
+            current_voter_id: 0,
+            current_account_id_seed: 0,
+            current_account_id: AccountId32::default(),
+            auto_increment_voter_id: true,
+        }
+    }
+    fn vote_and_assert_ok(&mut self, vote_kind: VoteKind) {
+        self.vote_and_assert(vote_kind, Ok(()));
+    }
+
+    fn vote_and_assert(&mut self, vote_kind: VoteKind, expected_result: DispatchResult<Error>) {
+        assert_eq!(self.vote(vote_kind.clone()), expected_result);
+    }
+
+    fn vote(&mut self, vote_kind: VoteKind) -> DispatchResult<Error> {
+        if self.auto_increment_voter_id {
+            self.current_account_id_seed += 1;
+            self.current_voter_id += 1;
+            let account_id: [u8; 32] = [self.current_account_id_seed; 32];
+            self.current_account_id = account_id.into();
+        }
+
+        ProposalsEngine::vote(
+            system::RawOrigin::Signed(self.current_account_id.clone()).into(),
+            self.current_voter_id,
+            self.proposal_id,
+            vote_kind,
+        )
+    }
+}
+
+#[derive(Clone)]
+struct DummyProposalFixture {
+    parameters: ProposalParameters<u32, u128>,
+    account_id: AccountId32,
+    proposer_id: u64,
+    proposal_code: Vec<u8>,
+    title: Vec<u8>,
+    description: Vec<u8>,
+    stake_balance: Option<BalanceOf<Runtime>>,
+}
+
+impl Default for DummyProposalFixture {
+    fn default() -> Self {
+        let title = b"title".to_vec();
+        let description = b"description".to_vec();
+        let dummy_proposal = proposals_codex::Call::<Runtime>::execute_text_proposal(
+            title.clone(),
+            description.clone(),
+            b"text".to_vec(),
+        );
+
+        DummyProposalFixture {
+            parameters: ProposalParameters {
+                voting_period: 3,
+                approval_quorum_percentage: 60,
+                approval_threshold_percentage: 60,
+                slashing_quorum_percentage: 60,
+                slashing_threshold_percentage: 60,
+                grace_period: 0,
+                required_stake: None,
+            },
+            account_id: <Runtime as system::Trait>::AccountId::default(),
+            proposer_id: 0,
+            proposal_code: dummy_proposal.encode(),
+            title,
+            description,
+            stake_balance: None,
+        }
+    }
+}
+
+impl DummyProposalFixture {
+    fn with_parameters(self, parameters: ProposalParameters<u32, u128>) -> Self {
+        DummyProposalFixture { parameters, ..self }
+    }
+
+    fn with_account_id(self, account_id: AccountId32) -> Self {
+        DummyProposalFixture { account_id, ..self }
+    }
+
+    fn with_stake(self, stake_balance: BalanceOf<Runtime>) -> Self {
+        DummyProposalFixture {
+            stake_balance: Some(stake_balance),
+            ..self
+        }
+    }
+
+    fn with_proposer(self, proposer_id: u64) -> Self {
+        DummyProposalFixture {
+            proposer_id,
+            ..self
+        }
+    }
+
+    fn create_proposal_and_assert(self, result: Result<u32, Error>) -> Option<u32> {
+        let proposal_id_result = ProposalsEngine::create_proposal(
+            self.account_id,
+            self.proposer_id,
+            self.parameters,
+            self.title,
+            self.description,
+            self.stake_balance,
+            self.proposal_code,
+        );
+        assert_eq!(proposal_id_result, result);
+
+        proposal_id_result.ok()
+    }
+}
+
+struct CancelProposalFixture {
+    origin: RawOrigin<AccountId32>,
+    proposal_id: u32,
+    proposer_id: u64,
+}
+
+impl CancelProposalFixture {
+    fn new(proposal_id: u32) -> Self {
+        let account_id = <Runtime as system::Trait>::AccountId::default();
+        CancelProposalFixture {
+            proposal_id,
+            origin: RawOrigin::Signed(account_id),
+            proposer_id: 0,
+        }
+    }
+
+    fn with_proposer(self, proposer_id: u64) -> Self {
+        CancelProposalFixture {
+            proposer_id,
+            ..self
+        }
+    }
+
+    fn cancel_and_assert(self, expected_result: DispatchResult<Error>) {
+        assert_eq!(
+            ProposalsEngine::cancel_proposal(
+                self.origin.into(),
+                self.proposer_id,
+                self.proposal_id
+            ),
+            expected_result
+        );
+    }
+}
+
+/// Main purpose of this integration test: check balance of the member on proposal finalization (cancellation)
+/// It tests StakingEventsHandler integration. Also, membership module is tested during the proposal creation (ActorOriginValidator).
+#[test]
+fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
+    initial_test_ext().execute_with(|| {
+        let account_id = <Runtime as system::Trait>::AccountId::default();
+
+        setup_members(2);
+        let member_id = 0; // newly created member_id
+
+        let stake_amount = 200u128;
+        let parameters = ProposalParameters {
+            voting_period: 3,
+            approval_quorum_percentage: 50,
+            approval_threshold_percentage: 60,
+            slashing_quorum_percentage: 60,
+            slashing_threshold_percentage: 60,
+            grace_period: 5,
+            required_stake: Some(stake_amount),
+        };
+        let dummy_proposal = DummyProposalFixture::default()
+            .with_parameters(parameters)
+            .with_account_id(account_id.clone())
+            .with_stake(stake_amount)
+            .with_proposer(member_id);
+
+        let account_balance = 500;
+        let _imbalance =
+            <Runtime as stake::Trait>::Currency::deposit_creating(&account_id, account_balance);
+
+        assert_eq!(
+            <Runtime as stake::Trait>::Currency::total_balance(&account_id),
+            account_balance
+        );
+
+        let proposal_id = dummy_proposal.create_proposal_and_assert(Ok(1)).unwrap();
+        assert_eq!(
+            <Runtime as stake::Trait>::Currency::total_balance(&account_id),
+            account_balance - stake_amount
+        );
+
+        let mut proposal = ProposalsEngine::proposals(proposal_id);
+
+        let mut expected_proposal = Proposal {
+            parameters,
+            proposer_id: member_id,
+            created_at: 1,
+            status: ProposalStatus::Active(Some(ActiveStake {
+                stake_id: 0,
+                source_account_id: account_id.clone(),
+            })),
+            title: b"title".to_vec(),
+            description: b"description".to_vec(),
+            voting_results: VotingResults::default(),
+        };
+
+        assert_eq!(proposal, expected_proposal);
+
+        let cancel_proposal_fixture =
+            CancelProposalFixture::new(proposal_id).with_proposer(member_id);
+
+        cancel_proposal_fixture.cancel_and_assert(Ok(()));
+
+        proposal = ProposalsEngine::proposals(proposal_id);
+
+        expected_proposal.status = ProposalStatus::Finalized(FinalizationData {
+            proposal_status: ProposalDecisionStatus::Canceled,
+            finalized_at: 1,
+            encoded_unstaking_error_due_to_broken_runtime: None,
+            stake_data_after_unstaking_error: None,
+        });
+
+        assert_eq!(proposal, expected_proposal);
+
+        let cancellation_fee = ProposalCancellationFee::get() as u128;
+        assert_eq!(
+            <Runtime as stake::Trait>::Currency::total_balance(&account_id),
+            account_balance - cancellation_fee
+        );
+    });
+}
+
+#[test]
+fn proposal_reset_succeeds() {
+    initial_test_ext().execute_with(|| {
+        setup_members(4);
+        setup_council();
+        // create proposal
+        let dummy_proposal = DummyProposalFixture::default();
+        let proposal_id = dummy_proposal.create_proposal_and_assert(Ok(1)).unwrap();
+
+        // create some votes
+        let mut vote_generator = VoteGenerator::new(proposal_id);
+        vote_generator.vote_and_assert_ok(VoteKind::Reject);
+        vote_generator.vote_and_assert_ok(VoteKind::Abstain);
+        vote_generator.vote_and_assert_ok(VoteKind::Slash);
+
+        assert!(<proposals_engine::ActiveProposalIds<Runtime>>::exists(
+            proposal_id
+        ));
+
+        // check
+        let proposal = ProposalsEngine::proposals(proposal_id);
+        assert_eq!(
+            proposal.voting_results,
+            VotingResults {
+                abstentions: 1,
+                approvals: 0,
+                rejections: 1,
+                slashes: 1,
+            }
+        );
+
+        // Ensure council was elected
+        assert_eq!(CouncilManager::<Runtime>::total_voters_count(), 6);
+
+        // Check proposals CouncilElected hook
+        // just trigger the election hook, we don't care about the parameters
+        <Runtime as governance::election::Trait>::CouncilElected::council_elected(Vec::new(), 10);
+
+        let updated_proposal = ProposalsEngine::proposals(proposal_id);
+
+        assert_eq!(
+            updated_proposal.voting_results,
+            VotingResults {
+                abstentions: 0,
+                approvals: 0,
+                rejections: 0,
+                slashes: 0,
+            }
+        );
+
+        // Check council CouncilElected hook. It should set current council. And we passed empty council.
+        assert_eq!(CouncilManager::<Runtime>::total_voters_count(), 0);
+    });
+}