diff --git a/Cargo.toml b/Cargo.toml index 388e1cb..ad065a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,8 @@ members = [ "examples/call-neovm", "examples/invoke-native-test", "examples/notify-test", - "examples/call_native" + "examples/call_native", + "examples/oracle" ] [profile.release] diff --git a/examples/oracle/Cargo.toml b/examples/oracle/Cargo.toml new file mode 100644 index 0000000..4bbdeb4 --- /dev/null +++ b/examples/oracle/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "oracle" +version = "0.1.0" +authors = ["qiluge "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +ontio-std = {git = "https://github.com/ontio/ontology-wasm-cdt-rust"} + + +[lib] +crate-type = ["cdylib", "rlib"] #Compile as a dynamic link library + + +[features] +mock = ["ontio-std/mock"] \ No newline at end of file diff --git a/examples/oracle/src/lib.rs b/examples/oracle/src/lib.rs new file mode 100644 index 0000000..1b96530 --- /dev/null +++ b/examples/oracle/src/lib.rs @@ -0,0 +1,59 @@ +#![cfg_attr(not(feature = "mock"), no_std)] +#![feature(proc_macro_hygiene)] +extern crate ontio_std as ostd; + +use ostd::abi::{Sink, Source}; +use ostd::prelude::*; +use ostd::runtime::{check_witness, input, ret}; + +use method::*; +use storage::*; + +pub mod method; +pub mod storage; + +#[no_mangle] +pub fn invoke() { + let input = input(); + let mut source = Source::new(&input); + let action: &[u8] = source.read().unwrap(); + let mut sink = Sink::new(12); + match action { + b"init" => { + let admin = source.read().unwrap(); + sink.write(initialize(admin)); + } + b"isPriceOracle" => { + sink.write(true); + } + b"putUnderlyingPrice" => { + let (key_list, price_list) = source.read().unwrap(); + sink.write(put_underlying_price(key_list, price_list)); + } + b"getUnderlyingPrice" => { + let key = source.read().unwrap(); + sink.write(get_price(key)); + } + b"setDecimal" => { + let decimal = source.read().unwrap(); + assert!(check_witness(&get_admin()), "check witness failed"); + sink.write(put_decimal(decimal)); + } + b"getDecimal" => { + sink.write(get_decimal()); + } + _ => { + let method = str::from_utf8(action).ok().unwrap(); + panic!("not support method:{}", method) + } + } + ret(sink.bytes()); +} + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/examples/oracle/src/method.rs b/examples/oracle/src/method.rs new file mode 100644 index 0000000..de4c7d1 --- /dev/null +++ b/examples/oracle/src/method.rs @@ -0,0 +1,30 @@ +use ostd::abi::EventBuilder; +use ostd::prelude::*; +use ostd::runtime::check_witness; +use ostd::types::U128; + +use crate::storage::*; + +/** + * @notice Initialize the money market + * @param admin The address of the Oracle + */ +pub fn initialize(admin: &Address) { + assert!(check_witness(&admin), "check witness failed"); + assert!(!is_init(), "already init"); + put_admin(admin); + init(); +} + +pub fn put_underlying_price(key_list: Vec<&str>, price_list: Vec) { + assert!(check_witness(&get_admin()), "check witness failed"); + assert_eq!(key_list.len(), price_list.len(), "invalid param"); + let mut event_builder = EventBuilder::new(); + event_builder = event_builder.string("PutUnderlyingPrice"); + for (key, price) in key_list.into_iter().zip(price_list.into_iter()) { + put_price(key, price); + event_builder = event_builder.string(key); + event_builder = event_builder.number(price); + } + event_builder.notify() +} diff --git a/examples/oracle/src/storage.rs b/examples/oracle/src/storage.rs new file mode 100644 index 0000000..ead0b8e --- /dev/null +++ b/examples/oracle/src/storage.rs @@ -0,0 +1,52 @@ +use ostd::database; +use ostd::prelude::*; +use ostd::types::U128; + +/** + * @notice Administrator for this contract + */ +const ADMIN_KEY: &str = "admin"; + +pub fn put_admin(admin: &Address) { + database::put(ADMIN_KEY, admin); +} + +pub fn get_admin() -> Address { + database::get(ADMIN_KEY).unwrap() +} + +const INIT: &str = "init"; + +pub fn init() { + database::put(INIT, true); +} + +pub fn is_init() -> bool { + database::get(INIT).unwrap_or(false) +} + +/** + * @notice Price data for this contract + */ +const PRICE: &str = "price"; + +pub fn put_price(key: &str, price: U128) { + database::put(PRICE.to_string() + key, price); +} + +pub fn get_price(key: &str) -> U128 { + database::get(PRICE.to_string() + key).unwrap() +} + +/** + * @notice Decimal for this contract + */ +const DECIMAL: &str = "decimal"; + +pub fn put_decimal(decimal: u8) { + database::put(DECIMAL, decimal); +} + +pub fn get_decimal() -> u8 { + database::get(DECIMAL).unwrap() +} diff --git a/examples/oracle/tests/tests.rs b/examples/oracle/tests/tests.rs new file mode 100644 index 0000000..f328724 --- /dev/null +++ b/examples/oracle/tests/tests.rs @@ -0,0 +1,43 @@ +extern crate ontio_std as ostd; +extern crate oracle; + +use ostd::types::U128; +use ostd::{mock::build_runtime, prelude::*}; + +use oracle::method; +use oracle::storage; + +#[test] +fn test_oracle() { + let runtime = &build_runtime(); + let admin = Address::repeat_byte(1); + runtime.witness(&[admin.clone()]); + method::initialize(&admin); + storage::put_decimal(9); + assert_eq!(9, storage::get_decimal()); + method::put_underlying_price(vec!["ONT", "BTC", "ETH", "DAI"], vec![100, 10000, 400, 1]); + assert_eq!(100, storage::get_price("ONT")); + assert_eq!(10000, storage::get_price("BTC")); + assert_eq!(400, storage::get_price("ETH")); + assert_eq!(1, storage::get_price("DAI")); +} + +#[test] +#[should_panic] +fn test_init_twice() { + let runtime = &build_runtime(); + let admin = Address::repeat_byte(1); + runtime.witness(&[admin.clone()]); + method::initialize(&admin); + method::initialize(&admin); +} + +#[test] +fn test_set_decimal_twice() { + let runtime = &build_runtime(); + let admin = Address::repeat_byte(1); + runtime.witness(&[admin.clone()]); + method::initialize(&admin); + storage::put_decimal(9); + storage::put_decimal(7); +} diff --git a/ontio-std/src/abi/event_builder.rs b/ontio-std/src/abi/event_builder.rs index d61400b..a602422 100644 --- a/ontio-std/src/abi/event_builder.rs +++ b/ontio-std/src/abi/event_builder.rs @@ -171,7 +171,7 @@ impl VmValueBuilderCommon { // compile-fails /// ```compile_fail -/// #[deny(unused_must_use)] +/// #![deny(unused_must_use)] /// { /// EventBuilder::new().bool(true); /// }