diff --git a/Cargo.toml b/Cargo.toml index 03c4c56..a21dd6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "examples/notify-test", "examples/call_native", "examples/oracle", + "examples/gov", "examples/bridge" ] diff --git a/examples/gov/Cargo.toml b/examples/gov/Cargo.toml new file mode 100644 index 0000000..1b3c31f --- /dev/null +++ b/examples/gov/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "gov" +version = "0.1.0" +authors = ["lucas7788 "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib"] +path = "src/lib.rs" + +[dependencies] +ontio-std = {path="../../ontio-std", features=["bump-alloc"]} + +[features] +mock = ["ontio-std/mock"] diff --git a/examples/gov/src/lib.rs b/examples/gov/src/lib.rs new file mode 100644 index 0000000..6a3eca0 --- /dev/null +++ b/examples/gov/src/lib.rs @@ -0,0 +1,67 @@ +#![no_std] +#![feature(proc_macro_hygiene)] +extern crate ontio_std as ostd; +use ostd::abi::{Sink, Source}; +use ostd::contract::governance::un_authorize_for_peer; +use ostd::contract::{governance, ont}; +use ostd::prelude::*; +use ostd::runtime; +use ostd::runtime::address; + +fn authorize_for_peer_transfer_from(user: &Address, amt: U128, peer_pub_key: &str) -> bool { + let this = address(); + ont::transfer(user, &this, amt); + governance::authorize_for_peer_transfer_from(&this, amt, peer_pub_key) +} + +fn authorize_for_peer(user: &Address, amt: U128, peer_pub_key: &str) -> bool { + governance::authorize_for_peer(user, amt, peer_pub_key) +} + +fn withdraw(user: &Address, amt: U128, peer_pub_key: &str) -> bool { + governance::withdraw(user, amt, peer_pub_key) +} + +fn withdraw_ong(user: &Address) -> bool { + governance::withdraw_ong(user) +} + +#[no_mangle] +pub fn invoke() { + let input = runtime::input(); + let mut source = Source::new(&input); + let action = source.read().unwrap(); + let mut sink = Sink::new(12); + match action { + "authorize_for_peer_transfer_from" => { + let (user, amt, peer_pub_key) = source.read().unwrap(); + sink.write(authorize_for_peer_transfer_from(user, amt, peer_pub_key)); + } + "authorize_for_peer" => { + let (user, amt, peer_pub_key) = source.read().unwrap(); + sink.write(authorize_for_peer(user, amt, peer_pub_key)) + } + "un_authorize_for_peer" => { + let (user, amt, peer_pub_key) = source.read().unwrap(); + sink.write(un_authorize_for_peer(user, amt, peer_pub_key)) + } + "withdraw" => { + let (user, amt, peer_pub_key) = source.read().unwrap(); + sink.write(withdraw(user, amt, peer_pub_key)); + } + "withdraw_ong" => { + let user = source.read().unwrap(); + sink.write(withdraw_ong(user)); + } + _ => panic!("unsupported action!"), + } + runtime::ret(sink.bytes()) +} + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/ontio-std/Cargo.toml b/ontio-std/Cargo.toml index 7d2f594..43e0c99 100644 --- a/ontio-std/Cargo.toml +++ b/ontio-std/Cargo.toml @@ -21,6 +21,7 @@ uint = {version = "0.8.5", default-features=false} [dev-dependencies] rand = "0.7.0" +etcommon-hexutil = { version = "0.2.4", default-features = false } [features] std = [] diff --git a/ontio-std/src/contract.rs b/ontio-std/src/contract.rs index a73ae65..dc74abf 100644 --- a/ontio-std/src/contract.rs +++ b/ontio-std/src/contract.rs @@ -1,5 +1,186 @@ use crate::prelude::*; +pub mod governance { + use crate::abi::{Encoder, Sink, Source}; + use crate::macros::base58; + use crate::prelude::*; + use crate::runtime::call_contract; + use crate::types::u128_to_neo_bytes; + + const VERSION: u8 = 0; + pub const GOV_CONTRACT_ADDRESS: Address = base58!("AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK"); + + pub struct AuthorizeForPeerParam<'a> { + addr: &'a Address, + peer_pubkey_list: &'a [&'a str], + pos_list: &'a [u32], + } + + impl<'a> AuthorizeForPeerParam<'a> { + pub fn new(addr: &'a Address, pos_list: &'a [u32], peer_pub_key: &'a [&str]) -> Self { + AuthorizeForPeerParam { addr, peer_pubkey_list: peer_pub_key, pos_list } + } + } + + impl<'a> Encoder for AuthorizeForPeerParam<'a> { + fn encode(&self, sink: &mut Sink) { + sink.write_var_bytes(self.addr.as_bytes()); + sink.write_native_varuint(self.peer_pubkey_list.len() as u64); + for &pk in self.peer_pubkey_list.iter() { + sink.write(pk); + } + sink.write_native_varuint(self.pos_list.len() as u64); + for pos in self.pos_list.iter() { + sink.write(u128_to_neo_bytes(U128::new(*pos as u128))); + } + } + } + + pub fn authorize_for_peer(addr: &Address, amt: U128, peer_pub_key: &str) -> bool { + let mut sink = Sink::new(64); + let pos_list = vec![amt.raw() as u32]; + let peer_pub_key = &[peer_pub_key]; + let a = AuthorizeForPeerParam::new(addr, pos_list.as_slice(), peer_pub_key); + sink.write(a); + + let mut sink_param = Sink::new(64); + sink_param.write(VERSION); + sink_param.write("authorizeForPeer"); + sink_param.write(sink.bytes()); + + let output = call_contract(&GOV_CONTRACT_ADDRESS, sink_param.bytes()); + let mut source = Source::new(output.as_slice()); + source.read_bool().unwrap_or_default() + } + + //Authorize for a node by depositing ONT in this governance contract, used by contracts + pub fn authorize_for_peer_transfer_from(addr: &Address, amt: U128, peer_pub_key: &str) -> bool { + let mut sink = Sink::new(64); + let pos_list = &[amt.raw() as u32]; + let peer_pub_key = &[peer_pub_key]; + let a = AuthorizeForPeerParam::new(addr, pos_list, peer_pub_key); + sink.write(a); + let mut sink_param = Sink::new(64); + sink_param.write(VERSION); + sink_param.write("authorizeForPeerTransferFrom"); + sink_param.write(sink.bytes()); + + let output = call_contract(&GOV_CONTRACT_ADDRESS, sink_param.bytes()); + let mut source = Source::new(output.as_slice()); + source.read_bool().unwrap_or_default() + } + + //UnAuthorize for a node by redeeming ONT from this governance contract + pub fn un_authorize_for_peer(addr: &Address, amt: U128, peer_pub_key: &str) -> bool { + let mut sink = Sink::new(64); + let pos_list = vec![amt.raw() as u32]; + let peer_pub_key = &[peer_pub_key]; + let a = AuthorizeForPeerParam::new(addr, pos_list.as_slice(), peer_pub_key); + sink.write(a); + + let mut sink_param = Sink::new(64); + sink_param.write(VERSION); + sink_param.write("unAuthorizeForPeer"); + sink_param.write(sink.bytes()); + + let output = call_contract(&GOV_CONTRACT_ADDRESS, sink_param.bytes()); + let mut source = Source::new(output.as_slice()); + source.read_bool().unwrap_or_default() + } + + struct WithdrawParam<'a> { + addr: &'a Address, + peer_pubkey_list: &'a [&'a str], + withdraw_list: &'a [u32], + } + impl<'a> Encoder for WithdrawParam<'a> { + fn encode(&self, sink: &mut Sink) { + sink.write_var_bytes(self.addr.as_bytes()); + sink.write_var_bytes( + u128_to_neo_bytes(U128::new(self.peer_pubkey_list.len() as u128)).as_slice(), + ); + self.peer_pubkey_list.iter().for_each(|peer_pubkey| sink.write(peer_pubkey)); + sink.write_var_bytes( + u128_to_neo_bytes(U128::new(self.withdraw_list.len() as u128)).as_slice(), + ); + self.withdraw_list.iter().for_each(|withdraw| { + sink.write_var_bytes(u128_to_neo_bytes(U128::new(*withdraw as u128)).as_slice()) + }); + } + } + + //Withdraw unfreezed ONT deposited in this governance contract. + pub fn withdraw(addr: &Address, amt: U128, peer_pub_key: &str) -> bool { + let mut sink = Sink::new(80); + sink.write(WithdrawParam { + addr, + peer_pubkey_list: &[peer_pub_key], + withdraw_list: &[amt.raw() as u32], + }); + let mut sink_param = Sink::new(64); + sink_param.write(VERSION); + sink_param.write("withdraw"); + sink_param.write(sink.bytes()); + + let output = call_contract(&GOV_CONTRACT_ADDRESS, sink_param.bytes()); + let mut source = Source::new(output.as_slice()); + source.read_bool().unwrap_or_default() + } + + struct WithdrawOngParam<'a> { + addr: &'a Address, + } + impl<'a> Encoder for WithdrawOngParam<'a> { + fn encode(&self, sink: &mut Sink) { + sink.write_var_bytes(self.addr.as_bytes()) + } + } + + //Withdraw unbounded ONG according to deposit ONT in this governance contract + pub fn withdraw_ong(addr: &Address) -> bool { + let mut sink = Sink::new(64); + sink.write(WithdrawOngParam { addr }); + let mut sink_param = Sink::new(64); + sink_param.write(VERSION); + sink_param.write("withdrawOng"); + sink_param.write(sink.bytes()); + + let output = call_contract(&GOV_CONTRACT_ADDRESS, sink_param.bytes()); + let mut source = Source::new(output.as_slice()); + source.read_bool().unwrap_or_default() + } + + #[test] + pub fn test_struct() { + let data = [ + 0x1b, 0x25, 0xfb, 0x79, 0xe6, 0x1d, 0x58, 0x60, 0x97, 0xef, 0xd9, 0xee, 0x89, 0xa5, + 0xab, 0xbf, 0x22, 0x27, 0xa2, 0xba, + ]; + let ap = AuthorizeForPeerParam { + addr: &Address::new(data), + peer_pubkey_list: &[&"test".to_string()], + pos_list: &[128u32], + }; + let mut sink = Sink::new(64); + sink.write(ap); + println!("AuthorizeForPeerParam:{}", hexutil::to_hex(sink.bytes())); + + let wp = WithdrawParam { + addr: &Address::repeat_byte(2), + peer_pubkey_list: &["test"], + withdraw_list: &[128u32], + }; + let mut sink = Sink::new(64); + sink.write(wp); + println!("WithdrawParam:{}", hexutil::to_hex(sink.bytes())); + + let wp = WithdrawOngParam { addr: &Address::repeat_byte(2) }; + let mut sink = Sink::new(64); + sink.write(wp); + println!("WithdrawOngParam:{}", hexutil::to_hex(sink.bytes())); + } +} + pub mod neo { use crate::prelude::*;