1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#![feature(
    bind_by_move_pattern_guards,
    linkage,
    non_exhaustive,
    proc_macro_hygiene,
    specialization,
    trait_alias,
    // the following are used by `collections::*`
    drain_filter,
    shrink_to,
    try_reserve,
)]
#![cfg_attr(target_os = "wasi", feature(wasi_ext))]

extern crate oasis_macros;

pub mod backend;
pub mod collections;
pub mod exe;

pub mod abi {
    pub extern crate oasis_borsh;
    pub use oasis_borsh::{BorshDeserialize as Deserialize, BorshSerialize as Serialize};

    /// Encodes arguments into the format expected by Oasis services.
    ///
    /// ## Example
    ///
    /// ```no_run
    /// use oasis_std::{abi::*, Address, AddressExt as _, Context};
    /// let method_id = 4;
    /// let payload =
    ///     oasis_std::abi_encode!(method_id, "some data", &["some", "more", "args"], 42,).unwrap();
    /// let callee = Address::default();
    /// let output = callee.call(&Context::default(), &payload).unwrap();
    /// ```
    #[macro_export]
    macro_rules! abi_encode {
        ($( $arg:expr ),* $(,)?) => {
            $crate::abi_encode!($($arg),* => Vec::new())
        };
        ($( $arg:expr ),* $(,)? => $buf:expr) => {
            Ok($buf)
                $(
                    .and_then(|mut buf| {
                        #[allow(unused)] {
                            use $crate::abi::Serialize as _;
                            $arg.serialize(&mut buf)?;
                        }
                        Ok(buf)
                    })
                )*
                .map_err(|_: std::io::Error| $crate::RpcError::InvalidInput)
        };
    }
}

#[cfg(not(target_os = "wasi"))]
#[doc(hidden)]
pub mod reexports {
    pub extern crate oasis_client; // used by generated clients
    pub extern crate oasis_test; // links the dylib containing the `backend::ext` externs
}

pub use oasis_macros::{default, Event, Service};
pub use oasis_types::{Address, Balance, RpcError};

pub use crate::exe::*;

/// This macro is used to define the "main" service.
///
/// ## Example

/// ```norun
/// fn main() {
///    oasis_std::service!(TheMainService);
/// }
/// ```
#[macro_export]
macro_rules! service {
    ($svc:path) => {};
}

pub trait AddressExt {
    fn call(&self, ctx: &Context, payload: &[u8]) -> Result<Vec<u8>, RpcError>;

    fn transfer<B: Into<Balance>>(&self, value: B) -> Result<(), RpcError>;

    fn balance(&self) -> Balance;

    fn code(&self) -> Vec<u8>;
}

impl AddressExt for Address {
    fn call(&self, ctx: &Context, payload: &[u8]) -> Result<Vec<u8>, RpcError> {
        crate::backend::transact(self, ctx.value(), payload)
    }

    fn transfer<B: Into<Balance>>(&self, value: B) -> Result<(), RpcError> {
        crate::backend::transact(self, value.into(), &[]).map(|_| ())
    }

    fn balance(&self) -> Balance {
        crate::backend::balance(self).unwrap()
    }

    fn code(&self) -> Vec<u8> {
        crate::backend::code(self).unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use abi::*;

    extern crate oasis_test;

    #[test]
    fn test_invoke() {
        type T = (Address, String, Vec<u8>);
        let things = (Address::default(), "an arg", (1..100).collect::<Vec<_>>());
        let encoded = abi_encode!(&things).unwrap();
        let decoded = T::try_from_slice(&encoded).unwrap();
        assert_eq!(decoded.0, things.0);
        assert_eq!(decoded.1, things.1);
        assert_eq!(decoded.2, things.2);
    }
}