Skip to content

Commit

Permalink
Merge pull request #24 from make-software/feature/docs
Browse files Browse the repository at this point in the history
Reputation Token and utils documentation.
  • Loading branch information
zie1ony authored Mar 15, 2022
2 parents 30a3c3d + 136ee01 commit 4e8e668
Show file tree
Hide file tree
Showing 19 changed files with 240 additions and 62 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ lint: clippy
clean:
cargo clean
rm -rf tests/wasm/*.wasm

docs:
cargo doc --features test-support --no-deps --open
61 changes: 23 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,29 @@
# contracts
# MVPR DAO for Casper

Voting contract
data:
- voting_address - Address
Reusable smart contracts for building DAOs on top of Casper.

Reputation contract
data:
- reputation_address - Address
- owner - Address
- whitelist - Vec<Address>
Repository contains following modules:
- `contract` provides smart contracts implementation,
- `utils` and `macros` makes writing code easier,
- `tests` contain integration tests,
- `client` implements a JavaScript client for smart contracts interactions.

methods:
only_onwer:
- change_onwership(new_owner: Address)
- add_to_whitelist(addr: Address)
- remove_from_whitelist(addr: Address)
whitelist_only:
- mint
- burn
- transfer_from
- stake
## Build contracts
Build `WASM` files.

Variable Repository
data:
...

methods:
only_onwer:
- change_onwership(new_owner: Address)
- add_to_whitelist(addr: Address)
- remove_from_whitelist(addr: Address)

whitelist_only:
- set_string(name: String, value: String)
- set_u256(name: String, value: U256)
```bash
$ make build-contracts
```

all:
- get_string(name: String) -> String
- get_u256(name: String) -> U256
## Test
Run integration tests.

Master Voting Contract:
- vote for whitelist changes.
```bash
$ make test
```

## Docs
Generate `rustdoc`. Opens a new browser window.
```bash
$ make docs
```
1 change: 1 addition & 0 deletions contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ path = "bin/reputation_contract.rs"
bench = false
doctest = false
test = false
doc = false

[profile.release]
codegen-units = 1
Expand Down
92 changes: 92 additions & 0 deletions contracts/src/reputation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,108 @@ use casper_types::{
EntryPointType, EntryPoints, Group, RuntimeArgs, URef, U256,
};

/// Interface of the Reputation Contract.
///
/// It should be implemented by [`ReputationContract`], [`ReputationContractCaller`]
/// and [`ReputationContractTest`].
pub trait ReputationContractInterface {
/// Constructor method.
///
/// It initializes contract elements:
/// * Events dictionary.
/// * Named keys of [`TokenWithStaking`], [`Owner`] and [`Whitelist`].
/// * Set [`caller`] as the owner of the contract.
/// * Add [`caller`] to the whitelist.
///
/// It emits [`OwnerChanged`](casper_dao_utils::owner::events::OwnerChanged),
/// [`AddedToWhitelist`](casper_dao_utils::whitelist::events::AddedToWhitelist) events.
fn init(&mut self);

/// Mint new tokens. Add `amount` of new tokens to the balance of the `recipient` and
/// increment the total supply. Only whitelisted addresses are permited to call this method.
///
/// It throws [`NotWhitelisted`](casper_dao_utils::Error::NotWhitelisted) if caller
/// is not whitelisted.
///
/// It emits [`Mint`](casper_dao_utils::token::events::Mint) event.
fn mint(&mut self, recipient: Address, amount: U256);

/// Burn existing tokens. Remove `amount` of existing tokens from the balance of the `owner`
/// and decrement the total supply. Only whitelisted addresses are permited to call this
/// method.
///
/// It throws [`NotWhitelisted`](casper_dao_utils::Error::NotWhitelisted) if caller
/// is not whitelisted.
///
/// It emits [`Burn`](casper_dao_utils::token::events::Burn) event.
fn burn(&mut self, owner: Address, amount: U256);

/// Transfer `amount` of tokens from `owner` to `recipient`. Only whitelisted addresses are
/// permited to call this method.
///
/// It throws [`NotWhitelisted`](casper_dao_utils::Error::NotWhitelisted) if caller
/// is not whitelisted.
///
/// It throws [`InsufficientBalance`](casper_dao_utils::Error::InsufficientBalance)
/// if `recipient`'s balance is less then `amount`.
///
/// It emits [`Transfer`](casper_dao_utils::token::events::Transfer) event.
fn transfer_from(&mut self, owner: Address, recipient: Address, amount: U256);

/// Change ownership of the contract. Transfer the ownership to the `owner`. Only current owner
/// is permited to call this method.
///
/// It throws [`NotAnOwner`](casper_dao_utils::Error::NotAnOwner) if caller
/// is not the current owner.
///
/// It emits [`OwnerChanged`](casper_dao_utils::owner::events::OwnerChanged),
/// [`AddedToWhitelist`](casper_dao_utils::whitelist::events::AddedToWhitelist) events.
fn change_ownership(&mut self, owner: Address);

/// Add new address to the whitelist.
///
/// It throws [`NotAnOwner`](casper_dao_utils::Error::NotAnOwner) if caller
/// is not the current owner.
///
/// It emits [`AddedToWhitelist`](casper_dao_utils::whitelist::events::AddedToWhitelist) event.
fn add_to_whitelist(&mut self, address: Address);

/// Remove address from the whitelist.
///
/// It throws [`NotAnOwner`](casper_dao_utils::Error::NotAnOwner) if caller
/// is not the current owner.
///
/// It emits [`RemovedFromWhitelist`](casper_dao_utils::whitelist::events::RemovedFromWhitelist)
/// event.
fn remove_from_whitelist(&mut self, address: Address);

/// Stake `amount` of tokens for the `address`. It decrements `address`'s balance by `amount`.
///
/// It throws [`NotAnOwner`](casper_dao_utils::Error::NotAnOwner) if caller
/// is not the current owner.
///
/// It throws [`InsufficientBalance`](casper_dao_utils::Error::InsufficientBalance)
/// if `address`'s balance is less then `amount`.
///
/// It emits [`TokensStaked`](casper_dao_utils::staking::events::TokensStaked)
/// event.
fn stake(&mut self, address: Address, amount: U256);

/// Unstake `amount` of tokens for the `address`. It increments `address`'s balance by
/// `amount`.
///
/// It throws [`NotAnOwner`](casper_dao_utils::Error::NotAnOwner) if caller
/// is not the current owner.
///
/// It throws [`InsufficientBalance`](casper_dao_utils::Error::InsufficientBalance)
/// if `address`'s staked amount is less then `amount`.
///
/// It emits [`TokensUnstaked`](casper_dao_utils::staking::events::TokensUnstaked)
/// event.
fn unstake(&mut self, address: Address, amount: U256);
}

/// Implementation of the Reputation Contract. See [`ReputationContractInterface`].
#[derive(Default)]
pub struct ReputationContract {
pub token: TokenWithStaking,
Expand Down Expand Up @@ -148,6 +238,7 @@ impl ReputationContract {
}
}

/// Implementation of the Reputation Contract Caller. See [`ReputationContractInterface`].
pub struct ReputationContractCaller {
contract_package_hash: ContractPackageHash,
}
Expand Down Expand Up @@ -275,6 +366,7 @@ mod tests {

use crate::{ReputationContract, ReputationContractInterface};

/// Implementation of the Reputation Contract Test. See [`ReputationContractInterface`].
pub struct ReputationContractTest {
env: TestEnv,
package_hash: ContractPackageHash,
Expand Down
1 change: 1 addition & 0 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, TokenStreamExt};
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields};

/// Derive events on top of any struct.
#[proc_macro_derive(Event)]
pub fn derive_events(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
Expand Down
2 changes: 1 addition & 1 deletion tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ name = "reputation-tests"
path = "src/reputation_tests.rs"
bench = false
doctest = false

doc = false
13 changes: 10 additions & 3 deletions utils/src/casper_env.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Interact with the CasperVM inside the contract.
use std::convert::TryInto;

use casper_contract::{
Expand All @@ -10,8 +12,9 @@ use casper_types::{
CLTyped,
};

use crate::{modules::events::Events, Address};
use crate::{Address, Events};

/// Read value from the storage.
pub fn get_key<T: FromBytes + CLTyped>(name: &str) -> Option<T> {
match runtime::get_key(name) {
None => None,
Expand All @@ -23,6 +26,7 @@ pub fn get_key<T: FromBytes + CLTyped>(name: &str) -> Option<T> {
}
}

/// Save value to the storage.
pub fn set_key<T: ToBytes + CLTyped>(name: &str, value: T) {
match runtime::get_key(name) {
Some(key) => {
Expand All @@ -44,8 +48,8 @@ fn call_stack_element_to_address(call_stack_element: CallStackElement) -> Addres
match call_stack_element {
CallStackElement::Session { account_hash } => Address::from(account_hash),
CallStackElement::StoredSession { account_hash, .. } => {
// Stored session code acts in account's context, so if stored session wants to interact
// with an ERC20 token caller's address will be used.
// Stored session code acts in account's context, so if stored session
// wants to interact, caller's address will be used.
Address::from(account_hash)
}
CallStackElement::StoredContract {
Expand All @@ -71,14 +75,17 @@ pub fn caller() -> Address {
call_stack_element_to_address(second_elem)
}

/// Initialize events dictionary.
pub fn init_events() {
Events::default().init();
}

/// Record event to the contract's storage.
pub fn emit<T: ToBytes>(event: T) {
Events::default().emit(event);
}

/// Convert any key to base64.
pub fn to_dictionary_key<T: ToBytes>(key: &T) -> String {
let preimage = key.to_bytes().unwrap_or_revert();
base64::encode(&preimage)
Expand Down
1 change: 1 addition & 0 deletions utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub use modules::owner;
pub use modules::staking;
pub use modules::token;
pub use modules::whitelist;
use modules::Events;

#[cfg(feature = "test-support")]
mod test_env;
Expand Down
4 changes: 3 additions & 1 deletion utils/src/modules/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub mod events;
mod events;
pub mod owner;
pub mod staking;
pub mod token;
pub mod whitelist;

pub(crate) use events::Events;
13 changes: 11 additions & 2 deletions utils/src/modules/owner.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Single-owner-based access control system.
use casper_contract::contract_api::runtime;

use crate::{
Expand All @@ -7,6 +9,7 @@ use crate::{

use self::events::OwnerChanged;

/// The Owner module.
pub struct Owner {
pub owner: Variable<Option<Address>>,
}
Expand All @@ -20,15 +23,18 @@ impl Default for Owner {
}

impl Owner {
/// Initialize the module.
pub fn init(&mut self, owner: Address) {
self.change_ownership(owner);
}

/// Set the owner to the new address.
pub fn change_ownership(&mut self, owner: Address) {
self.owner.set(Some(owner));
emit(OwnerChanged { new_owner: owner });
}

/// Verify if the contract caller is the owner. Revert otherwise.
pub fn ensure_owner(&self) {
if let Some(owner) = self.owner.get() {
if owner != caller() {
Expand All @@ -41,10 +47,11 @@ impl Owner {
}

pub mod entry_points {
use casper_types::{CLTyped, EntryPoint, EntryPointAccess, EntryPointType, Parameter};

//! Entry points definitions.
use crate::{consts, Address};
use casper_types::{CLTyped, EntryPoint, EntryPointAccess, EntryPointType, Parameter};

/// Public `change_ownership` entry point. Corresponds to [`change_ownership`](super::Owner::change_ownership).
pub fn change_ownership() -> EntryPoint {
EntryPoint::new(
consts::EP_CHANGE_OWNERSHIP,
Expand All @@ -57,9 +64,11 @@ pub mod entry_points {
}

pub mod events {
//! Events definitions.
use crate::Address;
use casper_dao_macros::Event;

/// Informs the owner change.
#[derive(Debug, PartialEq, Event)]
pub struct OwnerChanged {
pub new_owner: Address,
Expand Down
Loading

0 comments on commit 4e8e668

Please sign in to comment.