diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs
new file mode 100644
index 000000000..ef2d8b29e
--- /dev/null
+++ b/rpc/src/v1/types/filter.rs
@@ -0,0 +1,75 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+use serde::{Deserialize, Deserializer, Error};
+use serde_json::value;
+use jsonrpc_core::Value;
+use util::hash::*;
+use v1::types::BlockNumber;
+
+#[derive(Debug, PartialEq)]
+pub enum Topic {
+ Single(H256),
+ Multiple(Vec),
+ Null
+}
+
+impl Deserialize for Topic {
+ fn deserialize(deserializer: &mut D) -> Result
+ where D: Deserializer {
+ let v = try!(Value::deserialize(deserializer));
+
+ if v.is_null() {
+ return Ok(Topic::Null);
+ }
+
+ Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Topic::Single)
+ .or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Topic::Multiple))
+ .map_err(|_| Error::syntax("")) // unreachable, but types must match
+ }
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Filter {
+ #[serde(rename="fromBlock")]
+ pub from_block: BlockNumber,
+ #[serde(rename="toBlock")]
+ pub to_block: BlockNumber,
+ pub address: Address,
+ pub topics: Vec
+}
+
+#[cfg(test)]
+mod tests {
+ use serde_json;
+ use std::str::FromStr;
+ use util::hash::*;
+ use super::*;
+
+ #[test]
+ fn filter_deserialization() {
+ let s = r#"["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"]]"#;
+ let deserialized: Vec = serde_json::from_str(s).unwrap();
+ assert_eq!(deserialized, vec![
+ Topic::Single(H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap()),
+ Topic::Null,
+ Topic::Multiple(vec![
+ H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(),
+ H256::from_str("0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc").unwrap()
+ ])
+ ]);
+ }
+}
diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs
index 9dc57f24f..b35e7ff15 100644
--- a/rpc/src/v1/types/mod.rs
+++ b/rpc/src/v1/types/mod.rs
@@ -17,6 +17,7 @@
mod block;
mod block_number;
mod bytes;
+mod filter;
mod optionals;
mod sync;
mod transaction;
@@ -24,6 +25,7 @@ mod transaction;
pub use self::block::{Block, BlockTransactions};
pub use self::block_number::BlockNumber;
pub use self::bytes::Bytes;
+pub use self::filter::Filter;
pub use self::optionals::OptionalValue;
pub use self::sync::SyncStatus;
pub use self::transaction::Transaction;