Skip to content

Commit

Permalink
OdraType and OdraError derive macros (#284)
Browse files Browse the repository at this point in the history
* OdraType derive macro
* add derive macro supporting structs
* support basic enums
* autogenerate Clone
* OdraError derive macro
* update examples
* update justfile
  • Loading branch information
kpob authored Dec 12, 2023
1 parent ac3bdc8 commit 0c96bc7
Show file tree
Hide file tree
Showing 27 changed files with 1,177 additions and 146 deletions.
2 changes: 1 addition & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub use unwrap_or_revert::UnwrapOrRevert;
pub use utils::serialize;

pub use casper_types;
pub use casper_types::bytesrepr::{Bytes, FromBytes, ToBytes};
pub use casper_types::bytesrepr::{Bytes, Error as BytesReprError, FromBytes, ToBytes};
pub use casper_types::CLValue;
pub use casper_types::{runtime_args, RuntimeArgs};
pub use casper_types::{CLType, CLTyped, PublicKey, SecretKey, U128, U256, U512};
16 changes: 8 additions & 8 deletions core/src/variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@ impl<T> Variable<T> {
}
}

impl<T: FromBytes + Default> Variable<T> {
pub fn get_or_default(&self) -> T {
let env = self.env();
env.get_value(&env.current_key()).unwrap_or_default()
}

impl<T: FromBytes> Variable<T> {
pub fn get(&self) -> Option<T> {
let env = self.env();
env.get_value(&env.current_key())
}

pub fn get_or_revert_with<E: Into<OdraError>>(&self, error: E) -> T {
let env = self.env();
env.get_value(&env.current_key())
.unwrap_or_revert_with(&env, error)
self.get().unwrap_or_revert_with(&env, error)
}
}

impl<T: FromBytes + Default> Variable<T> {
pub fn get_or_default(&self) -> T {
self.get().unwrap_or_default()
}
}

Expand Down
134 changes: 56 additions & 78 deletions examples2/src/counter.rs
Original file line number Diff line number Diff line change
@@ -1,100 +1,78 @@
use odra::prelude::*;
use odra::{runtime_args, FromBytes, RuntimeArgs};
use odra::{CallDef, ContractEnv, HostEnv, Mapping, Variable};
use odra::{Address, CallDef, ContractEnv, HostEnv, Mapping, Module, OdraType, Variable};

pub struct Counter {
env: Rc<ContractEnv>,
count0: Variable<u32>,
count1: Variable<u32>,
count2: Variable<u32>,
count3: Variable<u32>,
count4: Variable<u32>,
count5: Variable<u32>,
count6: Variable<u32>,
count7: Variable<u32>,
count8: Variable<u32>,
count9: Variable<u32>,
counts: Mapping<u8, u32>
#[derive(OdraType)]
struct MyCounter {
value: u32,
creator: Address
}

impl odra::contract_def::HasEvents for Counter {
fn events() -> Vec<odra::contract_def::Event> {
vec![]
}
#[derive(OdraType)]
enum MyEnum {
VariantA,
VariantB,
Unknown
}

#[odra::module]
pub struct Counter {
count0: Variable<MyCounter>,
count1: Variable<MyCounter>,
count2: Variable<MyCounter>,
count3: Variable<MyCounter>,
count4: Variable<MyCounter>,
count5: Variable<MyCounter>,
count6: Variable<MyCounter>,
count7: Variable<MyCounter>,
count8: Variable<MyCounter>,
count9: Variable<MyCounter>,
counts: Mapping<u8, MyCounter>
}

impl Counter {
pub fn get_count(&self, index: u8) -> u32 {
match index {
0 => self.count0.get_or_default(),
1 => self.count1.get_or_default(),
2 => self.count2.get_or_default(),
3 => self.count3.get_or_default(),
4 => self.count4.get_or_default(),
5 => self.count5.get_or_default(),
6 => self.count6.get_or_default(),
7 => self.count7.get_or_default(),
8 => self.count8.get_or_default(),
9 => self.count9.get_or_default(),
0 => self.count0.get().map(|c| c.value).unwrap_or_default(),
1 => self.count1.get().map(|c| c.value).unwrap_or_default(),
2 => self.count2.get().map(|c| c.value).unwrap_or_default(),
3 => self.count3.get().map(|c| c.value).unwrap_or_default(),
4 => self.count4.get().map(|c| c.value).unwrap_or_default(),
5 => self.count5.get().map(|c| c.value).unwrap_or_default(),
6 => self.count6.get().map(|c| c.value).unwrap_or_default(),
7 => self.count7.get().map(|c| c.value).unwrap_or_default(),
8 => self.count8.get().map(|c| c.value).unwrap_or_default(),
9 => self.count9.get().map(|c| c.value).unwrap_or_default(),
_ => unreachable!()
}
}

pub fn increment(&mut self, index: u8) {
match index {
0 => increment(&mut self.count0),
1 => increment(&mut self.count1),
2 => increment(&mut self.count2),
3 => increment(&mut self.count3),
4 => increment(&mut self.count4),
5 => increment(&mut self.count5),
6 => increment(&mut self.count6),
7 => increment(&mut self.count7),
8 => increment(&mut self.count8),
9 => increment(&mut self.count9),
0 => increment(&self.env(), &mut self.count0),
1 => increment(&self.env(), &mut self.count1),
2 => increment(&self.env(), &mut self.count2),
3 => increment(&self.env(), &mut self.count3),
4 => increment(&self.env(), &mut self.count4),
5 => increment(&self.env(), &mut self.count5),
6 => increment(&self.env(), &mut self.count6),
7 => increment(&self.env(), &mut self.count7),
8 => increment(&self.env(), &mut self.count8),
9 => increment(&self.env(), &mut self.count9),
_ => unreachable!()
};
}
}

fn increment(count: &mut Variable<u32>) {
let a = count.get_or_default();
count.set(a + 1);
}

mod __counter_pack_module {
use super::*;
impl odra::module::Module for Counter {
fn new(env: Rc<ContractEnv>) -> Self {
let count0 = Variable::new(Rc::clone(&env), 0);
let count1 = Variable::new(Rc::clone(&env), 1);
let count2 = Variable::new(Rc::clone(&env), 2);
let count3 = Variable::new(Rc::clone(&env), 3);
let count4 = Variable::new(Rc::clone(&env), 4);
let count5 = Variable::new(Rc::clone(&env), 5);
let count6 = Variable::new(Rc::clone(&env), 6);
let count7 = Variable::new(Rc::clone(&env), 7);
let count8 = Variable::new(Rc::clone(&env), 8);
let count9 = Variable::new(Rc::clone(&env), 9);
let counts = Mapping::new(Rc::clone(&env), 10);
Self {
env,
count0,
count1,
count2,
count3,
count4,
count5,
count6,
count7,
count8,
count9,
counts
}
}

fn env(&self) -> Rc<ContractEnv> {
self.env.clone()
}
fn increment(env: &ContractEnv, count: &mut Variable<MyCounter>) {
if let Some(counter) = count.get() {
count.set(MyCounter {
value: counter.value + 1,
creator: counter.creator
});
} else {
count.set(MyCounter {
value: 1,
creator: env.caller()
});
}
}
10 changes: 2 additions & 8 deletions examples2/src/erc20.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use casper_event_standard::Event;
use odra::{casper_event_standard, Bytes, Module, OdraError, PublicKey};
use odra::{prelude::*, CallDef, ModuleWrapper};
use odra::{Address, ContractEnv, Mapping, Variable, U256, U512};
use odra::{Address, Mapping, Variable, U256, U512};

#[derive(Event, Eq, PartialEq, Debug)]
pub struct OnTransfer {
Expand All @@ -25,18 +25,12 @@ pub struct OnApprove {
pub value: U256
}

#[repr(u16)]
#[derive(OdraError)]
pub enum Erc20Error {
InsufficientBalance = 1,
InsufficientAllowance = 2
}

impl From<Erc20Error> for OdraError {
fn from(error: Erc20Error) -> Self {
OdraError::user(error as u16)
}
}

#[odra::module(events = [OnTransfer, OnCrossTransfer, OnApprove])]
pub struct Erc20 {
total_supply: Variable<U256>,
Expand Down
7 changes: 3 additions & 4 deletions examples2/src/reentrancy_guard.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use odra::{prelude::*, ContractEnv, Variable};
use odra::{prelude::*, Module, Variable};

#[odra::module]
pub struct ReentrancyMock {
env: Rc<ContractEnv>,
counter: Variable<u32>
}

Expand All @@ -21,8 +20,8 @@ impl ReentrancyMock {
if n > 0 {
self.count();
let other_erc20 = ReentrancyMockContractRef {
address: self.env.self_address(),
env: self.env.clone()
address: self.env().self_address(),
env: self.env().clone()
}
.count_ref_recursive(n - 1);
}
Expand Down
12 changes: 6 additions & 6 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,20 @@ clean:
cd modules && rm -f Cargo.lock

build-erc20:
cd examples2 && ODRA_MODULE=Erc20 cargo build --release --target wasm32-unknown-unknown --bin contract
wasm-strip examples2/target/wasm32-unknown-unknown/release/contract.wasm
cd examples2 && ODRA_MODULE=Erc20 cargo build --release --target wasm32-unknown-unknown --bin build_contract
wasm-strip examples2/target/wasm32-unknown-unknown/release/build_contract.wasm
rm -rf examples2/wasm/Erc20.wasm
mkdir -p examples2/wasm
mv examples2/target/wasm32-unknown-unknown/release/contract.wasm examples2/wasm/Erc20.wasm
mv examples2/target/wasm32-unknown-unknown/release/build_contract.wasm examples2/wasm/Erc20.wasm

test-erc20: build-erc20
cd examples2 && cargo test --lib erc20 -- --nocapture
cd examples2 && ODRA_BACKEND=casper cargo test --lib erc20 -- --nocapture

build-counter-pack:
cd examples2 && ODRA_MODULE=CounterPack cargo build --release --target wasm32-unknown-unknown --bin contract
wasm-strip examples2/target/wasm32-unknown-unknown/release/contract.wasm
cp examples2/target/wasm32-unknown-unknown/release/contract.wasm examples2/wasm/CounterPack.wasm
cd examples2 && ODRA_MODULE=CounterPack cargo build --release --target wasm32-unknown-unknown --bin build_contract
wasm-strip examples2/target/wasm32-unknown-unknown/release/build_contract.wasm
cp examples2/target/wasm32-unknown-unknown/release/build_contract.wasm examples2/wasm/CounterPack.wasm

test-counter-pack: build-counter-pack
cd examples2 && ODRA_BACKEND=casper cargo test --lib counter_pack -- --nocapture
Expand Down
25 changes: 11 additions & 14 deletions modules/src/erc20.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use odra::prelude::*;
use odra::{Address, ContractEnv, Mapping, U256, Variable};
use crate::erc20::errors::Error::{DecimalsNotSet, NameNotSet, SymbolNotSet};
use crate::erc20::events::*;
use odra::prelude::*;
use odra::{Address, ContractEnv, Mapping, Variable, U256};

#[odra::module(events = [Approval, Transfer])]
pub struct Erc20 {
Expand Down Expand Up @@ -33,8 +33,7 @@ impl Erc20 {
self.balances.set(&caller, initial_supply);

if !initial_supply.is_zero() {
self.env.emit_event(
Transfer {
self.env.emit_event(Transfer {
from: None,
to: Some(caller),
amount: initial_supply
Expand Down Expand Up @@ -76,9 +75,7 @@ impl Erc20 {
}

pub fn decimals(&self) -> u8 {
self.decimals
.get()
.unwrap_or_revert_with(DecimalsNotSet)
self.decimals.get().unwrap_or_revert_with(DecimalsNotSet)
}

pub fn total_supply(&self) -> U256 {
Expand Down Expand Up @@ -156,8 +153,8 @@ impl Erc20 {
}

pub mod events {
use odra::{Address, U256};
use casper_event_standard::Event;
use odra::{Address, U256};

#[derive(Event, Eq, PartialEq, Debug)]
pub struct Transfer {
Expand All @@ -178,12 +175,12 @@ pub mod errors {
use odra::OdraError;

pub enum Error {
InsufficientBalance = 30_000,
InsufficientAllowance = 30_001,
NameNotSet = 30_002,
SymbolNotSet = 30_003,
DecimalsNotSet = 30_004,
}
InsufficientBalance = 30_000,
InsufficientAllowance = 30_001,
NameNotSet = 30_002,
SymbolNotSet = 30_003,
DecimalsNotSet = 30_004
}

impl From<Error> for OdraError {
fn from(error: Error) -> Self {
Expand Down
Loading

0 comments on commit 0c96bc7

Please sign in to comment.