diff --git a/Cargo.lock b/Cargo.lock
index d3649db5e9dfaa6067bb36cf15b282a12ec7defc..a8457e91de9191e76723d799a14dc355d3670e46 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1132,8 +1132,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "jsonrpc-core"
-version = "9.0.0"
-source = "git+https://github.com/paritytech/jsonrpc.git#789c74ddc0e4ecdcb1355012e09435f8ff94ce7f"
+version = "10.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1142,47 +1142,48 @@ dependencies = [
  "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "jsonrpc-derive"
+version = "10.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "jsonrpc-http-server"
-version = "9.0.0"
-source = "git+https://github.com/paritytech/jsonrpc.git#789c74ddc0e4ecdcb1355012e09435f8ff94ce7f"
+version = "10.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "hyper 0.12.23 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
- "jsonrpc-server-utils 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
+ "jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-server-utils 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "jsonrpc-macros"
-version = "9.0.0"
-source = "git+https://github.com/paritytech/jsonrpc.git#789c74ddc0e4ecdcb1355012e09435f8ff94ce7f"
-dependencies = [
- "jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
- "jsonrpc-pubsub 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
- "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "jsonrpc-pubsub"
-version = "9.0.0"
-source = "git+https://github.com/paritytech/jsonrpc.git#789c74ddc0e4ecdcb1355012e09435f8ff94ce7f"
+version = "10.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
+ "jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "jsonrpc-server-utils"
-version = "9.0.0"
-source = "git+https://github.com/paritytech/jsonrpc.git#789c74ddc0e4ecdcb1355012e09435f8ff94ce7f"
+version = "10.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
+ "jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1193,16 +1194,16 @@ dependencies = [
 
 [[package]]
 name = "jsonrpc-ws-server"
-version = "9.0.0"
-source = "git+https://github.com/paritytech/jsonrpc.git#789c74ddc0e4ecdcb1355012e09435f8ff94ce7f"
+version = "10.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
- "jsonrpc-server-utils 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
+ "jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-server-utils 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parity-ws 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "ws 0.7.9 (git+https://github.com/tomusdrw/ws-rs)",
 ]
 
 [[package]]
@@ -2125,6 +2126,23 @@ dependencies = [
  "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "parity-ws"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "parking_lot"
 version = "0.5.5"
@@ -3810,9 +3828,9 @@ dependencies = [
  "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
- "jsonrpc-macros 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
- "jsonrpc-pubsub 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
+ "jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-derive 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-pubsub 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3836,9 +3854,9 @@ dependencies = [
 name = "substrate-rpc-servers"
 version = "0.1.0"
 dependencies = [
- "jsonrpc-http-server 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
- "jsonrpc-pubsub 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
- "jsonrpc-ws-server 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
+ "jsonrpc-http-server 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-pubsub 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-ws-server 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
  "sr-primitives 0.1.0",
@@ -4713,23 +4731,6 @@ dependencies = [
  "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "ws"
-version = "0.7.9"
-source = "git+https://github.com/tomusdrw/ws-rs#4baef2dc1abc8e216559af51cfc120bbcc777e21"
-dependencies = [
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "ws"
 version = "0.7.9"
@@ -4915,12 +4916,12 @@ dependencies = [
 "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
 "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
 "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
-"checksum jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "<none>"
-"checksum jsonrpc-http-server 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "<none>"
-"checksum jsonrpc-macros 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "<none>"
-"checksum jsonrpc-pubsub 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "<none>"
-"checksum jsonrpc-server-utils 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "<none>"
-"checksum jsonrpc-ws-server 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "<none>"
+"checksum jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a5152c3fda235dfd68341b3edf4121bc4428642c93acbd6de88c26bf95fc5d7"
+"checksum jsonrpc-derive 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8de4e89cf0938dec51a14255556172b1f5208e4d8999d613813eceeae1405d37"
+"checksum jsonrpc-http-server 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "99e1ce36c7cc9dcab398024d76849ab2cb917ee812653bce6f74fc9eb7c82d16"
+"checksum jsonrpc-pubsub 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56608ed54b1b2a69f4357cb8bdfbcbd99fe1179383c03a09bb428931bd35f592"
+"checksum jsonrpc-server-utils 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5521613b31ea22d36d9f95ad642058dccec846a94ed8690957652d479f620707"
+"checksum jsonrpc-ws-server 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20b8333a5a6e6ccbcf5c90f90919de557cba4929efa164e9bd0e8e497eb20e46"
 "checksum keccak-hasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c75270466c10e5204b2121f9eddb1f7a0fa9d3d753aba51dcd027c00084fb778"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "<none>"
@@ -4996,6 +4997,7 @@ dependencies = [
 "checksum parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a8e5d637787fe097ec1bfca2aa3eb687396518003df991c6c7216d86682d5ff"
 "checksum parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e8eab0287ccde7821e337a124dc5a4f1d6e4c25d10cc91e3f9361615dd95076"
 "checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc"
+"checksum parity-ws 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2fec5048fba72a2e01baeb0d08089db79aead4b57e2443df172fb1840075a233"
 "checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac"
 "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
 "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
@@ -5164,7 +5166,6 @@ dependencies = [
 "checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
-"checksum ws 0.7.9 (git+https://github.com/tomusdrw/ws-rs)" = "<none>"
 "checksum ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "329d3e6dd450a9c5c73024e1047f0be7e24121a68484eb0b5368977bee3cf8c3"
 "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
 "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
diff --git a/core/rpc-servers/Cargo.toml b/core/rpc-servers/Cargo.toml
index f3c0ae9906c3784027c0dc910b5cf4fc49788642..ff71e5ce1d7449083d632db6c12030f3fe479148 100644
--- a/core/rpc-servers/Cargo.toml
+++ b/core/rpc-servers/Cargo.toml
@@ -4,9 +4,9 @@ version = "0.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
 
 [dependencies]
-jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git" }
-jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc.git" }
-jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc.git" }
+jsonrpc-http-server = "10.0.1"
+jsonrpc-pubsub = "10.0.1"
+jsonrpc-ws-server = "10.0.1"
 log = "0.4"
 serde = "1.0"
 substrate-rpc = { path = "../rpc", version = "0.1" }
diff --git a/core/rpc/Cargo.toml b/core/rpc/Cargo.toml
index 7433a7f3452914539a9df8e5426955e4f699984f..0c87e0b2af5114ecdbef4b7e1cf6427ea3b9a174 100644
--- a/core/rpc/Cargo.toml
+++ b/core/rpc/Cargo.toml
@@ -5,9 +5,9 @@ authors = ["Parity Technologies <admin@parity.io>"]
 
 [dependencies]
 error-chain = "0.12"
-jsonrpc-core = { git="https://github.com/paritytech/jsonrpc.git" }
-jsonrpc-macros = { git="https://github.com/paritytech/jsonrpc.git" }
-jsonrpc-pubsub = { git="https://github.com/paritytech/jsonrpc.git" }
+jsonrpc-core = "10.0.1"
+jsonrpc-pubsub = "10.0.1"
+jsonrpc-derive = "10.0.1"
 log = "0.4"
 parking_lot = "0.7.1"
 parity-codec = "3.0"
diff --git a/core/rpc/src/author/mod.rs b/core/rpc/src/author/mod.rs
index be8648750994fb15f6f402ccd44c4817d19f2e9a..88233b0f5c85f9016838967ac77e3bc93668a705 100644
--- a/core/rpc/src/author/mod.rs
+++ b/core/rpc/src/author/mod.rs
@@ -30,8 +30,8 @@ use transaction_pool::{
 		watcher::Status,
 	},
 };
-use jsonrpc_macros::pubsub;
-use jsonrpc_pubsub::SubscriptionId;
+use jsonrpc_derive::rpc;
+use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
 use primitives::{Bytes, Blake2Hasher, H256};
 use rpc::futures::{Sink, Stream, Future};
 use runtime_primitives::{generic, traits};
@@ -44,30 +44,27 @@ mod tests;
 
 use self::error::Result;
 
-build_rpc_trait! {
-	/// Substrate authoring RPC API
-	pub trait AuthorApi<Hash, BlockHash> {
-		type Metadata;
+/// Substrate authoring RPC API
+#[rpc]
+pub trait AuthorApi<Hash, BlockHash> {
+	/// RPC metadata
+	type Metadata;
 
-		/// Submit hex-encoded extrinsic for inclusion in block.
-		#[rpc(name = "author_submitExtrinsic")]
-		fn submit_extrinsic(&self, Bytes) -> Result<Hash>;
+	/// Submit hex-encoded extrinsic for inclusion in block.
+	#[rpc(name = "author_submitExtrinsic")]
+	fn submit_extrinsic(&self, Bytes) -> Result<Hash>;
 
-		/// Returns all pending extrinsics, potentially grouped by sender.
-		#[rpc(name = "author_pendingExtrinsics")]
-		fn pending_extrinsics(&self) -> Result<Vec<Bytes>>;
+	/// Returns all pending extrinsics, potentially grouped by sender.
+	#[rpc(name = "author_pendingExtrinsics")]
+	fn pending_extrinsics(&self) -> Result<Vec<Bytes>>;
 
-		#[pubsub(name = "author_extrinsicUpdate")] {
-			/// Submit an extrinsic to watch.
-			#[rpc(name = "author_submitAndWatchExtrinsic")]
-			fn watch_extrinsic(&self, Self::Metadata, pubsub::Subscriber<Status<Hash, BlockHash>>, Bytes);
+	/// Submit an extrinsic to watch.
+	#[pubsub(subscription = "author_extrinsicUpdate", subscribe, name = "author_submitAndWatchExtrinsic")]
+	fn watch_extrinsic(&self, Self::Metadata, Subscriber<Status<Hash, BlockHash>>, Bytes);
 
-			/// Unsubscribe from extrinsic watching.
-			#[rpc(name = "author_unwatchExtrinsic")]
-			fn unwatch_extrinsic(&self, Option<Self::Metadata>, SubscriptionId) -> Result<bool>;
-		}
-
-	}
+	/// Unsubscribe from extrinsic watching.
+	#[pubsub(subscription = "author_extrinsicUpdate", unsubscribe, name = "author_unwatchExtrinsic")]
+	fn unwatch_extrinsic(&self, Option<Self::Metadata>, SubscriptionId) -> Result<bool>;
 }
 
 /// Authoring API
@@ -120,7 +117,7 @@ impl<B, E, P, RA> AuthorApi<ExHash<P>, BlockHash<P>> for Author<B, E, P, RA> whe
 		Ok(self.pool.ready().map(|tx| tx.data.encode().into()).collect())
 	}
 
-	fn watch_extrinsic(&self, _metadata: Self::Metadata, subscriber: pubsub::Subscriber<Status<ExHash<P>, BlockHash<P>>>, xt: Bytes) {
+	fn watch_extrinsic(&self, _metadata: Self::Metadata, subscriber: Subscriber<Status<ExHash<P>, BlockHash<P>>>, xt: Bytes) {
 		let submit = || -> Result<_> {
 			let best_block_hash = self.client.info()?.chain.best_hash;
 			let dxt = <<P as PoolChainApi>::Block as traits::Block>::Extrinsic::decode(&mut &xt[..]).ok_or(error::Error::from(error::ErrorKind::BadFormat))?;
diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs
index d84fa72225d17dc4851be66b79b242b89c22f317..a93697e6c337d1e92dcde261fc8c7f1eab723860 100644
--- a/core/rpc/src/author/tests.rs
+++ b/core/rpc/src/author/tests.rs
@@ -90,7 +90,7 @@ fn should_watch_extrinsic() {
 		pool: pool.clone(),
 		subscriptions: Subscriptions::new(runtime.executor()),
 	};
-	let (subscriber, id_rx, data) = ::jsonrpc_macros::pubsub::Subscriber::new_test("test");
+	let (subscriber, id_rx, data) = ::jsonrpc_pubsub::typed::Subscriber::new_test("test");
 
 	// when
 	p.watch_extrinsic(Default::default(), subscriber, uxt(Keyring::Alice, 0).encode().into());
diff --git a/core/rpc/src/chain/mod.rs b/core/rpc/src/chain/mod.rs
index ab6f0d710d1b89533a564394f235e851a0683f31..8c7cf7b74aeedd2e2236d139c3044ab62ff19930 100644
--- a/core/rpc/src/chain/mod.rs
+++ b/core/rpc/src/chain/mod.rs
@@ -19,14 +19,13 @@
 use std::sync::Arc;
 
 use client::{self, Client, BlockchainEvents};
-use jsonrpc_macros::{pubsub, Trailing};
-use jsonrpc_pubsub::SubscriptionId;
+use jsonrpc_derive::rpc;
+use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
 use primitives::{H256, Blake2Hasher};
 use rpc::Result as RpcResult;
 use rpc::futures::{stream, Future, Sink, Stream};
 use runtime_primitives::generic::{BlockId, SignedBlock};
 use runtime_primitives::traits::{Block as BlockT, Header, NumberFor};
-use serde::Serialize;
 
 use subscriptions::Subscriptions;
 
@@ -37,52 +36,63 @@ mod number;
 
 use self::error::Result;
 
-build_rpc_trait! {
-	/// Substrate blockchain API
-	pub trait ChainApi<Number, Hash> where
-		Header: Serialize,
-		SignedBlock: Serialize,
-	{
-		type Metadata;
-
-		/// Get header of a relay chain block.
-		#[rpc(name = "chain_getHeader")]
-		fn header(&self, Trailing<Hash>) -> Result<Option<Header>>;
-
-		/// Get header and body of a relay chain block.
-		#[rpc(name = "chain_getBlock")]
-		fn block(&self, Trailing<Hash>) -> Result<Option<SignedBlock>>;
-
-		/// Get hash of the n-th block in the canon chain.
-		///
-		/// By default returns latest block hash.
-		#[rpc(name = "chain_getBlockHash", alias = ["chain_getHead", ])]
-		fn block_hash(&self, Trailing<number::NumberOrHex<Number>>) -> Result<Option<Hash>>;
-
-		/// Get hash of the last finalised block in the canon chain.
-		#[rpc(name = "chain_getFinalisedHead")]
-		fn finalised_head(&self) -> Result<Hash>;
-
-		#[pubsub(name = "chain_newHead")] {
-			/// New head subscription
-			#[rpc(name = "chain_subscribeNewHead", alias = ["subscribe_newHead", ])]
-			fn subscribe_new_head(&self, Self::Metadata, pubsub::Subscriber<Header>);
-
-			/// Unsubscribe from new head subscription.
-			#[rpc(name = "chain_unsubscribeNewHead", alias = ["unsubscribe_newHead", ])]
-			fn unsubscribe_new_head(&self, Option<Self::Metadata>, SubscriptionId) -> RpcResult<bool>;
-		}
-
-		#[pubsub(name = "chain_finalisedHead")] {
-			/// New head subscription
-			#[rpc(name = "chain_subscribeFinalisedHeads")]
-			fn subscribe_finalised_heads(&self, Self::Metadata, pubsub::Subscriber<Header>);
-
-			/// Unsubscribe from new head subscription.
-			#[rpc(name = "chain_unsubscribeFinalisedHeads")]
-			fn unsubscribe_finalised_heads(&self, Option<Self::Metadata>, SubscriptionId) -> RpcResult<bool>;
-		}
-	}
+/// Substrate blockchain API
+#[rpc]
+pub trait ChainApi<Number, Hash, Header, SignedBlock> {
+	/// RPC metadata
+	type Metadata;
+
+	/// Get header of a relay chain block.
+	#[rpc(name = "chain_getHeader")]
+	fn header(&self, Option<Hash>) -> Result<Option<Header>>;
+
+	/// Get header and body of a relay chain block.
+	#[rpc(name = "chain_getBlock")]
+	fn block(&self, Option<Hash>) -> Result<Option<SignedBlock>>;
+
+	/// Get hash of the n-th block in the canon chain.
+	///
+	/// By default returns latest block hash.
+	#[rpc(name = "chain_getBlockHash", alias("chain_getHead"))]
+	fn block_hash(&self, Option<number::NumberOrHex<Number>>) -> Result<Option<Hash>>;
+
+	/// Get hash of the last finalised block in the canon chain.
+	#[rpc(name = "chain_getFinalisedHead")]
+	fn finalised_head(&self) -> Result<Hash>;
+
+	/// New head subscription
+	#[pubsub(
+		subscription = "chain_newHead",
+		subscribe,
+		name = "chain_subscribeNewHead",
+		alias("subscribe_newHead")
+	)]
+	fn subscribe_new_head(&self, Self::Metadata, Subscriber<Header>);
+
+	/// Unsubscribe from new head subscription.
+	#[pubsub(
+		subscription = "chain_newHead",
+		unsubscribe,
+		name = "chain_unsubscribeNewHead",
+		alias("unsubscribe_newHead")
+	)]
+	fn unsubscribe_new_head(&self, Option<Self::Metadata>, SubscriptionId) -> RpcResult<bool>;
+
+	/// New head subscription
+	#[pubsub(
+		subscription = "chain_finalisedHead",
+		subscribe,
+		name = "chain_subscribeFinalisedHeads"
+	)]
+	fn subscribe_finalised_heads(&self, Self::Metadata, Subscriber<Header>);
+
+	/// Unsubscribe from new head subscription.
+	#[pubsub(
+		subscription = "chain_finalisedHead",
+		unsubscribe,
+		name = "chain_unsubscribeFinalisedHeads"
+	)]
+	fn unsubscribe_finalised_heads(&self, Option<Self::Metadata>, SubscriptionId) -> RpcResult<bool>;
 }
 
 /// Chain API with subscriptions support.
@@ -109,7 +119,7 @@ impl<B, E, Block, RA> Chain<B, E, Block, RA> where
 	E: client::CallExecutor<Block, Blake2Hasher> + Send + Sync + 'static,
 	RA: Send + Sync + 'static
 {
-	fn unwrap_or_best(&self, hash: Trailing<Block::Hash>) -> Result<Block::Hash> {
+	fn unwrap_or_best(&self, hash: Option<Block::Hash>) -> Result<Block::Hash> {
 		Ok(match hash.into() {
 			None => self.client.info()?.chain.best_hash,
 			Some(hash) => hash,
@@ -118,7 +128,7 @@ impl<B, E, Block, RA> Chain<B, E, Block, RA> where
 
 	fn subscribe_headers<F, G, S, ERR>(
 		&self,
-		subscriber: pubsub::Subscriber<Block::Header>,
+		subscriber: Subscriber<Block::Header>,
 		best_block_hash: G,
 		stream: F,
 	) where
@@ -161,19 +171,19 @@ impl<B, E, Block, RA> ChainApi<NumberFor<Block>, Block::Hash, Block::Header, Sig
 {
 	type Metadata = ::metadata::Metadata;
 
-	fn header(&self, hash: Trailing<Block::Hash>) -> Result<Option<Block::Header>> {
+	fn header(&self, hash: Option<Block::Hash>) -> Result<Option<Block::Header>> {
 		let hash = self.unwrap_or_best(hash)?;
 		Ok(self.client.header(&BlockId::Hash(hash))?)
 	}
 
-	fn block(&self, hash: Trailing<Block::Hash>)
+	fn block(&self, hash: Option<Block::Hash>)
 		-> Result<Option<SignedBlock<Block>>>
 	{
 		let hash = self.unwrap_or_best(hash)?;
 		Ok(self.client.block(&BlockId::Hash(hash))?)
 	}
 
-	fn block_hash(&self, number: Trailing<number::NumberOrHex<NumberFor<Block>>>) -> Result<Option<Block::Hash>> {
+	fn block_hash(&self, number: Option<number::NumberOrHex<NumberFor<Block>>>) -> Result<Option<Block::Hash>> {
 		let number: Option<number::NumberOrHex<NumberFor<Block>>> = number.into();
 		Ok(match number {
 			None => Some(self.client.info()?.chain.best_hash),
@@ -185,7 +195,7 @@ impl<B, E, Block, RA> ChainApi<NumberFor<Block>, Block::Hash, Block::Header, Sig
 		Ok(self.client.info()?.chain.finalized_hash)
 	}
 
-	fn subscribe_new_head(&self, _metadata: Self::Metadata, subscriber: pubsub::Subscriber<Block::Header>) {
+	fn subscribe_new_head(&self, _metadata: Self::Metadata, subscriber: Subscriber<Block::Header>) {
 		self.subscribe_headers(
 			subscriber,
 			|| self.block_hash(None.into()),
@@ -199,7 +209,7 @@ impl<B, E, Block, RA> ChainApi<NumberFor<Block>, Block::Hash, Block::Header, Sig
 		Ok(self.subscriptions.cancel(id))
 	}
 
-	fn subscribe_finalised_heads(&self, _meta: Self::Metadata, subscriber: pubsub::Subscriber<Block::Header>) {
+	fn subscribe_finalised_heads(&self, _meta: Self::Metadata, subscriber: Subscriber<Block::Header>) {
 		self.subscribe_headers(
 			subscriber,
 			|| Ok(Some(self.client.info()?.chain.finalized_hash)),
diff --git a/core/rpc/src/chain/tests.rs b/core/rpc/src/chain/tests.rs
index f6c8aa4b793b229b7a6f60a4fbedff136c62c200..f9d11f902ecc04b4387a5aac2555499a97b149d6 100644
--- a/core/rpc/src/chain/tests.rs
+++ b/core/rpc/src/chain/tests.rs
@@ -15,7 +15,6 @@
 // along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
 
 use super::*;
-use jsonrpc_macros::pubsub;
 use test_client::{self, TestClient};
 use test_client::runtime::{H256, Block, Header};
 use consensus::BlockOrigin;
@@ -192,7 +191,7 @@ fn should_return_finalised_hash() {
 fn should_notify_about_latest_block() {
 	let mut core = ::tokio::runtime::Runtime::new().unwrap();
 	let remote = core.executor();
-	let (subscriber, id, transport) = pubsub::Subscriber::new_test("test");
+	let (subscriber, id, transport) = Subscriber::new_test("test");
 
 	{
 		let api = Chain {
@@ -223,7 +222,7 @@ fn should_notify_about_latest_block() {
 fn should_notify_about_finalised_block() {
 	let mut core = ::tokio::runtime::Runtime::new().unwrap();
 	let remote = core.executor();
-	let (subscriber, id, transport) = pubsub::Subscriber::new_test("test");
+	let (subscriber, id, transport) = Subscriber::new_test("test");
 
 	{
 		let api = Chain {
diff --git a/core/rpc/src/helpers.rs b/core/rpc/src/helpers.rs
index dca1a45db563ddf0103b81e4ff230ab728824f8a..b9c665191d92833c71e42c7c160a13e964510e30 100644
--- a/core/rpc/src/helpers.rs
+++ b/core/rpc/src/helpers.rs
@@ -15,7 +15,7 @@
 // along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
 
 /// Unwraps the trailing parameter or falls back with the closure result.
-pub fn unwrap_or_else<F, H, E>(or_else: F, optional: ::jsonrpc_macros::Trailing<H>) -> Result<H, E> where
+pub fn unwrap_or_else<F, H, E>(or_else: F, optional: Option<H>) -> Result<H, E> where
 	F: FnOnce() -> Result<H, E>,
 {
 	match optional.into() {
diff --git a/core/rpc/src/lib.rs b/core/rpc/src/lib.rs
index 91eef709a4e82fae10ab276494ef455986941502..b91c06d5a4867b19b1c812d16bc261f0c9c58236 100644
--- a/core/rpc/src/lib.rs
+++ b/core/rpc/src/lib.rs
@@ -20,6 +20,7 @@
 
 extern crate jsonrpc_core as rpc;
 extern crate jsonrpc_pubsub;
+extern crate jsonrpc_derive;
 extern crate parity_codec as codec;
 extern crate parking_lot;
 extern crate serde;
@@ -35,8 +36,6 @@ extern crate tokio;
 #[macro_use]
 extern crate error_chain;
 #[macro_use]
-extern crate jsonrpc_macros;
-#[macro_use]
 extern crate log;
 #[macro_use]
 extern crate serde_derive;
diff --git a/core/rpc/src/state/mod.rs b/core/rpc/src/state/mod.rs
index 50849996799364d1d8c04a07f6b52b2aafe027f3..67e5b3386ed8272e84eb10c2f879f1738b9687df 100644
--- a/core/rpc/src/state/mod.rs
+++ b/core/rpc/src/state/mod.rs
@@ -23,9 +23,8 @@ use std::{
 };
 
 use client::{self, Client, CallExecutor, BlockchainEvents, runtime_api::Metadata};
-use jsonrpc_macros::Trailing;
-use jsonrpc_macros::pubsub;
-use jsonrpc_pubsub::SubscriptionId;
+use jsonrpc_derive::rpc;
+use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
 use primitives::{H256, Blake2Hasher, Bytes};
 use primitives::hexdisplay::HexDisplay;
 use primitives::storage::{self, StorageKey, StorageData, StorageChangeSet};
@@ -43,66 +42,72 @@ mod tests;
 
 use self::error::Result;
 
-build_rpc_trait! {
-	/// Substrate state API
-	pub trait StateApi<Hash> {
-		type Metadata;
-
-		/// Call a contract at a block's state.
-		#[rpc(name = "state_call", alias = ["state_callAt", ])]
-		fn call(&self, String, Bytes, Trailing<Hash>) -> Result<Bytes>;
-
-		/// Returns the keys with prefix, leave empty to get all the keys
-		#[rpc(name = "state_getKeys")]
-		fn storage_keys(&self, StorageKey, Trailing<Hash>) -> Result<Vec<StorageKey>>;
-
-		/// Returns a storage entry at a specific block's state.
-		#[rpc(name = "state_getStorage", alias = ["state_getStorageAt", ])]
-		fn storage(&self, StorageKey, Trailing<Hash>) -> Result<Option<StorageData>>;
-
-		/// Returns the hash of a storage entry at a block's state.
-		#[rpc(name = "state_getStorageHash", alias = ["state_getStorageHashAt", ])]
-		fn storage_hash(&self, StorageKey, Trailing<Hash>) -> Result<Option<Hash>>;
-
-		/// Returns the size of a storage entry at a block's state.
-		#[rpc(name = "state_getStorageSize", alias = ["state_getStorageSizeAt", ])]
-		fn storage_size(&self, StorageKey, Trailing<Hash>) -> Result<Option<u64>>;
-
-		/// Returns the runtime metadata as an opaque blob.
-		#[rpc(name = "state_getMetadata")]
-		fn metadata(&self, Trailing<Hash>) -> Result<Bytes>;
-
-		/// Get the runtime version.
-		#[rpc(name = "state_getRuntimeVersion", alias = ["chain_getRuntimeVersion", ])]
-		fn runtime_version(&self, Trailing<Hash>) -> Result<RuntimeVersion>;
-
-		/// Query historical storage entries (by key) starting from a block given as the second parameter.
-		///
-		/// NOTE This first returned result contains the initial state of storage for all keys.
-		/// Subsequent values in the vector represent changes to the previous state (diffs).
-		#[rpc(name = "state_queryStorage")]
-		fn query_storage(&self, Vec<StorageKey>, Hash, Trailing<Hash>) -> Result<Vec<StorageChangeSet<Hash>>>;
-
-		#[pubsub(name = "state_runtimeVersion")] {
-			/// New runtime version subscription
-			#[rpc(name = "state_subscribeRuntimeVersion", alias = ["chain_subscribeRuntimeVersion", ])]
-			fn subscribe_runtime_version(&self, Self::Metadata, pubsub::Subscriber<RuntimeVersion>);
-
-			/// Unsubscribe from runtime version subscription
-			#[rpc(name = "state_unsubscribeRuntimeVersion", alias = ["chain_unsubscribeRuntimeVersion", ])]
-			fn unsubscribe_runtime_version(&self, Option<Self::Metadata>, SubscriptionId) -> RpcResult<bool>;
-		}
-
-		#[pubsub(name = "state_storage")] {
-			/// New storage subscription
-			#[rpc(name = "state_subscribeStorage")]
-			fn subscribe_storage(&self, Self::Metadata, pubsub::Subscriber<StorageChangeSet<Hash>>, Trailing<Vec<StorageKey>>);
-
-			/// Unsubscribe from storage subscription
-			#[rpc(name = "state_unsubscribeStorage")]
-			fn unsubscribe_storage(&self, Option<Self::Metadata>, SubscriptionId) -> RpcResult<bool>;
-		}
-	}
+/// Substrate state API
+#[rpc]
+pub trait StateApi<Hash> {
+	/// RPC Metadata
+	type Metadata;
+
+	/// Call a contract at a block's state.
+	#[rpc(name = "state_call", alias("state_callAt"))]
+	fn call(&self, String, Bytes, Option<Hash>) -> Result<Bytes>;
+
+	/// Returns the keys with prefix, leave empty to get all the keys
+	#[rpc(name = "state_getKeys")]
+	fn storage_keys(&self, StorageKey, Option<Hash>) -> Result<Vec<StorageKey>>;
+
+	/// Returns a storage entry at a specific block's state.
+	#[rpc(name = "state_getStorage", alias("state_getStorageAt"))]
+	fn storage(&self, StorageKey, Option<Hash>) -> Result<Option<StorageData>>;
+
+	/// Returns the hash of a storage entry at a block's state.
+	#[rpc(name = "state_getStorageHash", alias("state_getStorageHashAt"))]
+	fn storage_hash(&self, StorageKey, Option<Hash>) -> Result<Option<Hash>>;
+
+	/// Returns the size of a storage entry at a block's state.
+	#[rpc(name = "state_getStorageSize", alias("state_getStorageSizeAt"))]
+	fn storage_size(&self, StorageKey, Option<Hash>) -> Result<Option<u64>>;
+
+	/// Returns the runtime metadata as an opaque blob.
+	#[rpc(name = "state_getMetadata")]
+	fn metadata(&self, Option<Hash>) -> Result<Bytes>;
+
+	/// Get the runtime version.
+	#[rpc(name = "state_getRuntimeVersion", alias("chain_getRuntimeVersion"))]
+	fn runtime_version(&self, Option<Hash>) -> Result<RuntimeVersion>;
+
+	/// Query historical storage entries (by key) starting from a block given as the second parameter.
+	///
+	/// NOTE This first returned result contains the initial state of storage for all keys.
+	/// Subsequent values in the vector represent changes to the previous state (diffs).
+	#[rpc(name = "state_queryStorage")]
+	fn query_storage(&self, Vec<StorageKey>, Hash, Option<Hash>) -> Result<Vec<StorageChangeSet<Hash>>>;
+
+	/// New runtime version subscription
+	#[pubsub(
+		subscription = "state_runtimeVersion",
+		subscribe,
+		name = "state_subscribeRuntimeVersion",
+		alias("chain_subscribeRuntimeVersion")
+	)]
+	fn subscribe_runtime_version(&self, Self::Metadata, Subscriber<RuntimeVersion>);
+
+	/// Unsubscribe from runtime version subscription
+	#[pubsub(
+		subscription = "state_runtimeVersion",
+		unsubscribe,
+		name = "state_unsubscribeRuntimeVersion",
+		alias("chain_unsubscribeRuntimeVersion")
+	)]
+	fn unsubscribe_runtime_version(&self, Option<Self::Metadata>, SubscriptionId) -> RpcResult<bool>;
+
+	/// New storage subscription
+	#[pubsub(subscription = "state_storage", subscribe, name = "state_subscribeStorage")]
+	fn subscribe_storage(&self, Self::Metadata, Subscriber<StorageChangeSet<Hash>>, Option<Vec<StorageKey>>);
+
+	/// Unsubscribe from storage subscription
+	#[pubsub(subscription = "state_storage", unsubscribe, name = "state_unsubscribeStorage")]
+	fn unsubscribe_storage(&self, Option<Self::Metadata>, SubscriptionId) -> RpcResult<bool>;
 }
 
 /// State API with subscriptions support.
@@ -146,7 +151,7 @@ impl<B, E, Block: BlockT, RA> State<B, E, Block, RA> where
 	fn split_query_storage_range(
 		&self,
 		from: Block::Hash,
-		to: Trailing<Block::Hash>
+		to: Option<Block::Hash>
 	) -> Result<QueryStorageRange<Block>> {
 		let to = self.unwrap_or_best(to)?;
 		let from_hdr = self.client.header(&BlockId::hash(from))?;
@@ -268,7 +273,7 @@ impl<B, E, Block, RA> State<B, E, Block, RA> where
 	B: client::backend::Backend<Block, Blake2Hasher>,
 	E: CallExecutor<Block, Blake2Hasher>,
 {
-	fn unwrap_or_best(&self, hash: Trailing<Block::Hash>) -> Result<Block::Hash> {
+	fn unwrap_or_best(&self, hash: Option<Block::Hash>) -> Result<Block::Hash> {
 		::helpers::unwrap_or_else(|| Ok(self.client.info()?.chain.best_hash), hash)
 	}
 }
@@ -283,7 +288,7 @@ impl<B, E, Block, RA> StateApi<Block::Hash> for State<B, E, Block, RA> where
 {
 	type Metadata = ::metadata::Metadata;
 
-	fn call(&self, method: String, data: Bytes, block: Trailing<Block::Hash>) -> Result<Bytes> {
+	fn call(&self, method: String, data: Bytes, block: Option<Block::Hash>) -> Result<Bytes> {
 		let block = self.unwrap_or_best(block)?;
 		trace!(target: "rpc", "Calling runtime at {:?} for method {} ({})", block, method, HexDisplay::from(&data.0));
 		let return_data = self.client
@@ -295,28 +300,28 @@ impl<B, E, Block, RA> StateApi<Block::Hash> for State<B, E, Block, RA> where
 		Ok(Bytes(return_data))
 	}
 
-	fn storage_keys(&self, key_prefix: StorageKey, block: Trailing<Block::Hash>) -> Result<Vec<StorageKey>> {
+	fn storage_keys(&self, key_prefix: StorageKey, block: Option<Block::Hash>) -> Result<Vec<StorageKey>> {
 		let block = self.unwrap_or_best(block)?;
 		trace!(target: "rpc", "Querying storage keys at {:?}", block);
 		Ok(self.client.storage_keys(&BlockId::Hash(block), &key_prefix)?)
 	}
 
-	fn storage(&self, key: StorageKey, block: Trailing<Block::Hash>) -> Result<Option<StorageData>> {
+	fn storage(&self, key: StorageKey, block: Option<Block::Hash>) -> Result<Option<StorageData>> {
 		let block = self.unwrap_or_best(block)?;
 		trace!(target: "rpc", "Querying storage at {:?} for key {}", block, HexDisplay::from(&key.0));
 		Ok(self.client.storage(&BlockId::Hash(block), &key)?)
 	}
 
-	fn storage_hash(&self, key: StorageKey, block: Trailing<Block::Hash>) -> Result<Option<Block::Hash>> {
+	fn storage_hash(&self, key: StorageKey, block: Option<Block::Hash>) -> Result<Option<Block::Hash>> {
 		use runtime_primitives::traits::{Hash, Header as HeaderT};
 		Ok(self.storage(key, block)?.map(|x| <Block::Header as HeaderT>::Hashing::hash(&x.0)))
 	}
 
-	fn storage_size(&self, key: StorageKey, block: Trailing<Block::Hash>) -> Result<Option<u64>> {
+	fn storage_size(&self, key: StorageKey, block: Option<Block::Hash>) -> Result<Option<u64>> {
 		Ok(self.storage(key, block)?.map(|x| x.0.len() as u64))
 	}
 
-	fn metadata(&self, block: Trailing<Block::Hash>) -> Result<Bytes> {
+	fn metadata(&self, block: Option<Block::Hash>) -> Result<Bytes> {
 		let block = self.unwrap_or_best(block)?;
 		self.client.runtime_api().metadata(&BlockId::Hash(block)).map(Into::into).map_err(Into::into)
 	}
@@ -325,7 +330,7 @@ impl<B, E, Block, RA> StateApi<Block::Hash> for State<B, E, Block, RA> where
 		&self,
 		keys: Vec<StorageKey>,
 		from: Block::Hash,
-		to: Trailing<Block::Hash>
+		to: Option<Block::Hash>
 	) -> Result<Vec<StorageChangeSet<Block::Hash>>> {
 		let range = self.split_query_storage_range(from, to)?;
 		let mut changes = Vec::new();
@@ -337,8 +342,8 @@ impl<B, E, Block, RA> StateApi<Block::Hash> for State<B, E, Block, RA> where
 	fn subscribe_storage(
 		&self,
 		_meta: Self::Metadata,
-		subscriber: pubsub::Subscriber<StorageChangeSet<Block::Hash>>,
-		keys: Trailing<Vec<StorageKey>>
+		subscriber: Subscriber<StorageChangeSet<Block::Hash>>,
+		keys: Option<Vec<StorageKey>>
 	) {
 		let keys = Into::<Option<Vec<_>>>::into(keys);
 		let stream = match self.client.storage_changes_notification_stream(keys.as_ref().map(|x| &**x)) {
@@ -383,12 +388,12 @@ impl<B, E, Block, RA> StateApi<Block::Hash> for State<B, E, Block, RA> where
 		Ok(self.subscriptions.cancel(id))
 	}
 
-	fn runtime_version(&self, at: Trailing<Block::Hash>) -> Result<RuntimeVersion> {
+	fn runtime_version(&self, at: Option<Block::Hash>) -> Result<RuntimeVersion> {
 		let at = self.unwrap_or_best(at)?;
 		Ok(self.client.runtime_version_at(&BlockId::Hash(at))?)
 	}
 
-	fn subscribe_runtime_version(&self, _meta: Self::Metadata, subscriber: pubsub::Subscriber<RuntimeVersion>) {
+	fn subscribe_runtime_version(&self, _meta: Self::Metadata, subscriber: Subscriber<RuntimeVersion>) {
 		let stream = match self.client.storage_changes_notification_stream(Some(&[StorageKey(storage::well_known_keys::CODE.to_vec())])) {
 			Ok(stream) => stream,
 			Err(err) => {
diff --git a/core/rpc/src/state/tests.rs b/core/rpc/src/state/tests.rs
index 9c860adef7f729c7063ac51328df0a4a46e938e0..87b3dfcc9f4e47324cf0e56f3573c5bad3fb1971 100644
--- a/core/rpc/src/state/tests.rs
+++ b/core/rpc/src/state/tests.rs
@@ -18,7 +18,6 @@ use super::*;
 use self::error::{Error, ErrorKind};
 
 use consensus::BlockOrigin;
-use jsonrpc_macros::pubsub;
 use rustc_hex::FromHex;
 use test_client::{self, runtime, keyring::Keyring, TestClient, BlockBuilderExt};
 
@@ -52,7 +51,7 @@ fn should_call_contract() {
 fn should_notify_about_storage_changes() {
 	let mut core = ::tokio::runtime::Runtime::new().unwrap();
 	let remote = core.executor();
-	let (subscriber, id, transport) = pubsub::Subscriber::new_test("test");
+	let (subscriber, id, transport) = Subscriber::new_test("test");
 
 	{
 		let api = State::new(Arc::new(test_client::new()), Subscriptions::new(remote));
@@ -83,7 +82,7 @@ fn should_notify_about_storage_changes() {
 fn should_send_initial_storage_changes_and_notifications() {
 	let mut core = ::tokio::runtime::Runtime::new().unwrap();
 	let remote = core.executor();
-	let (subscriber, id, transport) = pubsub::Subscriber::new_test("test");
+	let (subscriber, id, transport) = Subscriber::new_test("test");
 
 	{
 		let api = State::new(Arc::new(test_client::new()), Subscriptions::new(remote));
@@ -230,7 +229,7 @@ fn should_return_runtime_version() {
 #[test]
 fn should_notify_on_runtime_version_initially() {
 	let mut core = ::tokio::runtime::Runtime::new().unwrap();
-	let (subscriber, id, transport) = pubsub::Subscriber::new_test("test");
+	let (subscriber, id, transport) = Subscriber::new_test("test");
 
 	{
 		let client = Arc::new(test_client::new());
diff --git a/core/rpc/src/subscriptions.rs b/core/rpc/src/subscriptions.rs
index 17ca51b3504b598575963a41e36b613927e48f3c..16687b0d11c34b2719a58ed72845d00784d5f9dc 100644
--- a/core/rpc/src/subscriptions.rs
+++ b/core/rpc/src/subscriptions.rs
@@ -17,8 +17,7 @@
 use std::collections::HashMap;
 use std::sync::{Arc, atomic::{self, AtomicUsize}};
 
-use jsonrpc_macros::pubsub;
-use jsonrpc_pubsub::SubscriptionId;
+use jsonrpc_pubsub::{SubscriptionId, typed::{Sink, Subscriber}};
 use parking_lot::Mutex;
 use rpc::futures::sync::oneshot;
 use rpc::futures::{Future, future};
@@ -72,8 +71,8 @@ impl Subscriptions {
 	/// Second parameter is a function that converts Subscriber sink into a future.
 	/// This future will be driven to completion bu underlying event loop
 	/// or will be cancelled in case #cancel is invoked.
-	pub fn add<T, E, G, R, F>(&self, subscriber: pubsub::Subscriber<T, E>, into_future: G) where
-		G: FnOnce(pubsub::Sink<T, E>) -> R,
+	pub fn add<T, E, G, R, F>(&self, subscriber: Subscriber<T, E>, into_future: G) where
+		G: FnOnce(Sink<T, E>) -> R,
 		R: future::IntoFuture<Future=F, Item=(), Error=()>,
 		F: future::Future<Item=(), Error=()> + Send + 'static,
 	{
diff --git a/core/rpc/src/system/mod.rs b/core/rpc/src/system/mod.rs
index a06aaaad2384bde355b5edf36619758650536fa6..e3856fac9fd98fde3bcd0618204b653e0928df0e 100644
--- a/core/rpc/src/system/mod.rs
+++ b/core/rpc/src/system/mod.rs
@@ -23,43 +23,43 @@ mod helpers;
 mod tests;
 
 use std::sync::Arc;
+use jsonrpc_derive::rpc;
 use network;
 use runtime_primitives::traits::{self, Header as HeaderT};
 
 use self::error::Result;
 pub use self::helpers::{Properties, SystemInfo, Health, PeerInfo};
 
-build_rpc_trait! {
-	/// Substrate system RPC API
-	pub trait SystemApi<Hash, Number> {
-		/// Get the node's implementation name. Plain old string.
-		#[rpc(name = "system_name")]
-		fn system_name(&self) -> Result<String>;
-
-		/// Get the node implementation's version. Should be a semver string.
-		#[rpc(name = "system_version")]
-		fn system_version(&self) -> Result<String>;
-
-		/// Get the chain's type. Given as a string identifier.
-		#[rpc(name = "system_chain")]
-		fn system_chain(&self) -> Result<String>;
-
-		/// Get a custom set of properties as a JSON object, defined in the chain spec.
-		#[rpc(name = "system_properties")]
-		fn system_properties(&self) -> Result<Properties>;
-
-		/// Return health status of the node.
-		///
-		/// Node is considered healthy if it is:
-		/// - connected to some peers (unless running in dev mode)
-		/// - not performing a major sync
-		#[rpc(name = "system_health")]
-		fn system_health(&self) -> Result<Health>;
-
-		/// Returns currently connected peers
-		#[rpc(name = "system_peers")]
-		fn system_peers(&self) -> Result<Vec<PeerInfo<Hash, Number>>>;
-	}
+/// Substrate system RPC API
+#[rpc]
+pub trait SystemApi<Hash, Number> {
+	/// Get the node's implementation name. Plain old string.
+	#[rpc(name = "system_name")]
+	fn system_name(&self) -> Result<String>;
+
+	/// Get the node implementation's version. Should be a semver string.
+	#[rpc(name = "system_version")]
+	fn system_version(&self) -> Result<String>;
+
+	/// Get the chain's type. Given as a string identifier.
+	#[rpc(name = "system_chain")]
+	fn system_chain(&self) -> Result<String>;
+
+	/// Get a custom set of properties as a JSON object, defined in the chain spec.
+	#[rpc(name = "system_properties")]
+	fn system_properties(&self) -> Result<Properties>;
+
+	/// Return health status of the node.
+	///
+	/// Node is considered healthy if it is:
+	/// - connected to some peers (unless running in dev mode)
+	/// - not performing a major sync
+	#[rpc(name = "system_health")]
+	fn system_health(&self) -> Result<Health>;
+
+	/// Returns currently connected peers
+	#[rpc(name = "system_peers")]
+	fn system_peers(&self) -> Result<Vec<PeerInfo<Hash, Number>>>;
 }
 
 /// System API implementation