diff --git a/oracle/rpc/Cargo.toml b/oracle/rpc/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..ad2f0efdb963a5aeb84a5fa77bc9fd35a989e295
--- /dev/null
+++ b/oracle/rpc/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "orml-oracle-rpc"
+version = "0.0.1"
+authors = ["Laminar Developers <hello@laminar.one>"]
+edition = "2018"
+
+[dependencies]
+codec = { package = "parity-scale-codec", version = "1.0.0" }
+jsonrpc-core = "14.0.3"
+jsonrpc-core-client = "14.0.3"
+jsonrpc-derive = "14.0.3"
+sp-runtime = { git = "https://github.com/paritytech/substrate.git" }
+sp-api = { git = "https://github.com/paritytech/substrate.git" }
+sp-blockchain = { git = "https://github.com/paritytech/substrate.git" }
+orml-oracle-rpc-runtime-api = { path = "runtime-api" }
diff --git a/oracle/rpc/runtime-api/Cargo.toml b/oracle/rpc/runtime-api/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..6d449385ffe42eaffcb731b9eb3d04620bf0db6b
--- /dev/null
+++ b/oracle/rpc/runtime-api/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "orml-oracle-rpc-runtime-api"
+version = "0.1.0"
+authors = ["Laminar Developers <hello@laminar.one>"]
+edition = "2018"
+
+[dependencies]
+codec = { package = "parity-scale-codec", version = "1.0.6", default-features = false, features = ["derive"] }
+sp-api = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git" }
+
+[features]
+default = ["std"]
+std = [
+	"sp-api/std",
+	"codec/std",
+]
diff --git a/oracle/rpc/runtime-api/src/lib.rs b/oracle/rpc/runtime-api/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..437fa40eb0b39d2c7d8381720013345a08d8aa0a
--- /dev/null
+++ b/oracle/rpc/runtime-api/src/lib.rs
@@ -0,0 +1,14 @@
+//! Runtime API definition for oracle module.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+use codec::Codec;
+
+sp_api::decl_runtime_apis! {
+	pub trait OracleApi<Key, Value> where
+		Key: Codec,
+		Value: Codec,
+	{
+		fn get_no_op(key: Key) -> Option<Value>;
+	}
+}
diff --git a/oracle/rpc/src/lib.rs b/oracle/rpc/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..124dd6dfba0b82954962d79075e254fa61ca072e
--- /dev/null
+++ b/oracle/rpc/src/lib.rs
@@ -0,0 +1,66 @@
+pub use self::gen_client::Client as OracleClient;
+use codec::Codec;
+use jsonrpc_core::{Error as RpcError, ErrorCode, Result};
+use jsonrpc_derive::rpc;
+pub use orml_oracle_rpc_runtime_api::OracleApi as OracleRuntimeApi;
+use sp_api::ProvideRuntimeApi;
+use sp_blockchain::HeaderBackend;
+use sp_runtime::{generic::BlockId, traits::Block as BlockT};
+use std::sync::Arc;
+
+#[rpc]
+pub trait OracleApi<BlockHash, Key, Value> {
+	#[rpc(name = "oracle_getValue")]
+	fn get_value(&self, key: Key, at: Option<BlockHash>) -> Result<Option<Value>>;
+}
+
+/// A struct that implements the [`OracleApi`].
+pub struct Oracle<C, B> {
+	client: Arc<C>,
+	_marker: std::marker::PhantomData<B>,
+}
+
+impl<C, B> Oracle<C, B> {
+	/// Create new `Oracle` with the given reference to the client.
+	pub fn new(client: Arc<C>) -> Self {
+		Oracle {
+			client,
+			_marker: Default::default(),
+		}
+	}
+}
+
+pub enum Error {
+	RuntimeError,
+}
+
+impl From<Error> for i64 {
+	fn from(e: Error) -> i64 {
+		match e {
+			Error::RuntimeError => 1,
+		}
+	}
+}
+
+impl<C, Block, Key, Value> OracleApi<<Block as BlockT>::Hash, Key, Value> for Oracle<C, Block>
+where
+	Block: BlockT,
+	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
+	C::Api: OracleRuntimeApi<Block, Key, Value>,
+	Key: Codec,
+	Value: Codec,
+{
+	fn get_value(&self, key: Key, at: Option<<Block as BlockT>::Hash>) -> Result<Option<Value>> {
+		let api = self.client.runtime_api();
+		let at = BlockId::hash(at.unwrap_or_else(||
+			// If the block hash is not supplied assume the best block.
+			self.client.info().best_hash));
+		api.get_no_op(&at, key)
+			.map_err(|e| RpcError {
+				code: ErrorCode::ServerError(Error::RuntimeError.into()),
+				message: "Unable to get value.".into(),
+				data: Some(format!("{:?}", e).into()),
+			})
+			.into()
+	}
+}
diff --git a/oracle/src/lib.rs b/oracle/src/lib.rs
index ba1f79249cc7ad4840a613c247100a17cdef3928..61823c16fa1d0d0e34ce36d0a7803382da46b1ea 100644
--- a/oracle/src/lib.rs
+++ b/oracle/src/lib.rs
@@ -82,15 +82,33 @@ impl<T: Trait> Module<T> {
 			.collect()
 	}
 
+	/// Returns fresh combined value if has update, or latest combined value.
+	///
+	/// Note this will update values storage if has update.
 	pub fn get(key: &T::OracleKey) -> Option<TimestampedValueOf<T>> {
 		if <HasUpdate<T>>::take(key) {
-			let values = Self::read_raw_values(key);
-			let timestamped = T::CombineData::combine_data(key, values, <Values<T>>::get(key))?;
+			let timestamped = Self::combined(key)?;
 			<Values<T>>::insert(key, timestamped.clone());
 			return Some(timestamped);
 		}
 		<Values<T>>::get(key)
 	}
+
+	/// Returns fresh combined value if has update, or latest combined value.
+	///
+	/// This is a no-op function which would not change storage.
+	pub fn get_no_op(key: &T::OracleKey) -> Option<TimestampedValueOf<T>> {
+		if Self::has_update(key) {
+			Self::combined(key)
+		} else {
+			Self::values(key)
+		}
+	}
+
+	fn combined(key: &T::OracleKey) -> Option<TimestampedValueOf<T>> {
+		let values = Self::read_raw_values(key);
+		T::CombineData::combine_data(key, values, Self::values(key))
+	}
 }
 
 impl<T: Trait> DataProvider<T::OracleKey, T::OracleValue> for Module<T> {
diff --git a/oracle/src/timestamped_value.rs b/oracle/src/timestamped_value.rs
index 0b29aac7b83ad20822a73b7e4b0637caf2fbc388..26b80d7334aa47b67b24ac7b9b6260dd956b19a1 100644
--- a/oracle/src/timestamped_value.rs
+++ b/oracle/src/timestamped_value.rs
@@ -1,7 +1,11 @@
 use codec::{Decode, Encode};
 use sp_runtime::RuntimeDebug;
 
+#[cfg(feature = "std")]
+use serde::{Deserialize, Serialize};
+
 #[derive(Encode, Decode, RuntimeDebug, Eq, PartialEq, Clone, Copy)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 pub struct TimestampedValue<Value, Moment> {
 	pub value: Value,
 	pub timestamp: Moment,
diff --git a/utilities/Cargo.toml b/utilities/Cargo.toml
index 6d065cdd0420cf098fb452a017b2bb654957d9af..05d08a8263b6c5401ab9caf479cdfc5f09f17170 100644
--- a/utilities/Cargo.toml
+++ b/utilities/Cargo.toml
@@ -16,7 +16,7 @@ frame-system = { git = "https://github.com/paritytech/substrate.git", default-fe
 frame-support = { git = "https://github.com/paritytech/substrate.git", default-features = false }
 
 [dev-dependencies]
-
+serde_json = "1.0.41"
 clear_on_drop = { version = "0.2.3", features = ["no_cc"] }	# https://github.com/paritytech/substrate/issues/4179
 
 [features]
diff --git a/utilities/src/fixed128.rs b/utilities/src/fixed128.rs
index f3cd0029263194afef3b02d4738dcba045cdcaae..8b0d314a126ceb17b8bb9a133eeb0ee878236f6c 100644
--- a/utilities/src/fixed128.rs
+++ b/utilities/src/fixed128.rs
@@ -1,18 +1,21 @@
 use codec::{Decode, Encode};
 use primitives::U256;
-use rstd::convert::{Into, TryFrom, TryInto};
+use rstd::{
+	convert::{Into, TryFrom, TryInto},
+	result::Result,
+	vec::Vec,
+};
 use sp_runtime::{
 	traits::{Bounded, Saturating, UniqueSaturatedInto},
 	Perbill, Percent, Permill, Perquintill,
 };
 
 #[cfg(feature = "std")]
-use serde::{Deserialize, Serialize};
+use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
 
 /// An unsigned fixed point number. Can hold any value in the range [0, 340_282_366_920_938_463_464]
 /// with fixed point accuracy of 10 ** 18.
 #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 pub struct FixedU128(u128);
 
 const DIV: u128 = 1_000_000_000_000_000_000;
@@ -211,6 +214,61 @@ impl_perthing_into_fixed_u128!(Permill);
 impl_perthing_into_fixed_u128!(Perbill);
 impl_perthing_into_fixed_u128!(Perquintill);
 
+#[cfg(feature = "std")]
+impl FixedU128 {
+	fn str_with_precision(&self) -> String {
+		format!("{}.{}", &self.0 / DIV, &self.0 % DIV)
+	}
+
+	fn from_str_with_precision(s: &str) -> Result<Self, &'static str> {
+		let err = "invalid string input";
+		let vec_str: Vec<&str> = s.split(".").collect();
+
+		// parsing to decimal and fractional parts
+		let (decimal_str, fractional_str) = match vec_str.as_slice() {
+			&[d] => (d, "0"),
+			&[d, f] => (d, f),
+			_ => return Err(err),
+		};
+
+		let decimal: u128 = decimal_str.parse().map_err(|_| err)?;
+		let decimal_with_precision = decimal.checked_mul(DIV).ok_or(err)?;
+		// width = 18; precision = 18
+		let padded_fractional_string = format!("{:0<18.18}", fractional_str);
+		let fractional_with_precision: u128 = padded_fractional_string.parse().map_err(|_| err)?;
+
+		let parts = decimal_with_precision
+			.checked_add(fractional_with_precision)
+			.ok_or(err)?;
+		Ok(Self::from_parts(parts))
+	}
+}
+
+// Manual impl `Serialize` as serde_json does not support u128.
+// TODO: remove impl if issue https://github.com/serde-rs/json/issues/548 fixed.
+#[cfg(feature = "std")]
+impl Serialize for FixedU128 {
+	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+	where
+		S: Serializer,
+	{
+		serializer.serialize_str(&self.str_with_precision())
+	}
+}
+
+// Manual impl `Serialize` as serde_json does not support u128.
+// TODO: remove impl if issue https://github.com/serde-rs/json/issues/548 fixed.
+#[cfg(feature = "std")]
+impl<'de> Deserialize<'de> for FixedU128 {
+	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+	where
+		D: Deserializer<'de>,
+	{
+		let s = String::deserialize(deserializer)?;
+		FixedU128::from_str_with_precision(&s).map_err(|err_str| de::Error::custom(err_str))
+	}
+}
+
 #[cfg(test)]
 mod tests {
 	use super::*;
@@ -361,4 +419,45 @@ mod tests {
 		let a = FixedU128::from_natural(0);
 		assert_eq!(a.recip(), None);
 	}
+
+	#[test]
+	fn from_str_with_precision_should_work() {
+		assert_eq!(
+			FixedU128::from_str_with_precision("1").unwrap(),
+			FixedU128::from_natural(1)
+		);
+		assert_eq!(
+			FixedU128::from_str_with_precision("1.0").unwrap(),
+			FixedU128::from_natural(1)
+		);
+		assert_eq!(
+			FixedU128::from_str_with_precision("0.1").unwrap(),
+			FixedU128::from_rational(1, 10)
+		);
+		assert_eq!(
+			FixedU128::from_str_with_precision("2.5").unwrap(),
+			FixedU128::from_rational(5, 2)
+		);
+		assert_eq!(
+			FixedU128::from_str_with_precision("0.1000000000000000111").unwrap(),
+			FixedU128::from_rational(100000000000000011u128, 1000000000000000000u128)
+		);
+
+		assert!(FixedU128::from_str_with_precision(".").is_err());
+		assert!(FixedU128::from_str_with_precision("").is_err());
+		assert!(FixedU128::from_str_with_precision("1.1.1").is_err());
+		assert!(FixedU128::from_str_with_precision("a.1").is_err());
+		assert!(FixedU128::from_str_with_precision("1.a").is_err());
+		// 340282366920938463464 == u128::max_value() / DIV + 1; overflows
+		assert!(FixedU128::from_str_with_precision("340282366920938463464").is_err());
+	}
+
+	#[test]
+	fn serialize_deserialize_should_work() {
+		let two_point_five = FixedU128::from_rational(5, 2);
+		let serialized = serde_json::to_string(&two_point_five).unwrap();
+		assert_eq!(serialized, "\"2.500000000000000000\"");
+		let deserialized: FixedU128 = serde_json::from_str(&serialized).unwrap();
+		assert_eq!(deserialized, two_point_five);
+	}
 }
diff --git a/utilities/src/linked_item.rs b/utilities/src/linked_item.rs
index 9e8f3a849b77995e73f7e22222f4aeaa8512c784..690a279deb13fed6aec74a50b1ecc35d22289c64 100644
--- a/utilities/src/linked_item.rs
+++ b/utilities/src/linked_item.rs
@@ -367,7 +367,8 @@ mod tests {
 	#[test]
 	fn linked_list_can_enumerate() {
 		new_test_ext().execute_with(|| {
-			assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), []);
+			let v: Vec<u32> = vec![];
+			assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), v);
 
 			TestLinkedList::append(&0, 1);
 			TestLinkedList::append(&0, 2);
@@ -384,7 +385,8 @@ mod tests {
 	#[test]
 	fn linked_list_can_take_all() {
 		new_test_ext().execute_with(|| {
-			assert_eq!(TestLinkedList::take_all(&0).collect::<Vec<_>>(), []);
+			let v: Vec<u32> = vec![];
+			assert_eq!(TestLinkedList::take_all(&0).collect::<Vec<_>>(), v);
 
 			TestLinkedList::append(&0, 1);
 			TestLinkedList::append(&0, 2);
@@ -395,14 +397,15 @@ mod tests {
 			assert_eq!(TestItem::get(&(0, Some(1))), None);
 			assert_eq!(TestItem::get(&(0, Some(2))), None);
 			assert_eq!(TestItem::get(&(0, Some(3))), None);
-			assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), []);
+			assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), v);
 		});
 	}
 
 	#[test]
 	fn linked_list_take_all_is_safe() {
 		new_test_ext().execute_with(|| {
-			assert_eq!(TestLinkedList::take_all(&0).collect::<Vec<_>>(), []);
+			let v: Vec<u32> = vec![];
+			assert_eq!(TestLinkedList::take_all(&0).collect::<Vec<_>>(), v);
 
 			TestLinkedList::append(&0, 1);
 			TestLinkedList::append(&0, 2);
@@ -413,7 +416,7 @@ mod tests {
 			assert_eq!(TestItem::get(&(0, Some(1))), None);
 			assert_eq!(TestItem::get(&(0, Some(2))), None);
 			assert_eq!(TestItem::get(&(0, Some(3))), None);
-			assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), []);
+			assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), v);
 		});
 	}
 }