#[macro_use]
extern crate cfg_if;
cfg_if! {
if #[cfg(feature = "wee_alloc")] {
extern crate wee_alloc;
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
} else if #[cfg(feature = "qimalloc")] {
extern crate qimalloc;
#[global_allocator]
static ALLOC: qimalloc::QIMalloc = qimalloc::QIMalloc::INIT;
}
}
mod native;
mod utils;
pub mod types;
#[cfg(feature = "debug")]
pub mod debug;
#[cfg(feature = "experimental")]
pub mod bignum;
#[cfg(feature = "eth2")]
pub mod eth2;
#[cfg(not(feature = "std"))]
pub mod convert;
#[cfg(feature = "std")]
use std::vec::Vec;
use types::*;
#[cfg(feature = "std")]
use utils::*;
pub mod prelude {
pub use crate::*;
pub use crate::types::*;
#[cfg(not(feature = "std"))]
pub use crate::convert::*;
#[cfg(feature = "debug")]
pub use crate::debug;
#[cfg(feature = "experimental")]
pub use crate::bignum;
#[cfg(feature = "eth2")]
pub use crate::eth2;
}
#[macro_export]
macro_rules! ewasm_entry_point {
($name:ident) => {
#[cfg(target_arch = "wasm32")]
#[no_mangle]
pub extern "C" fn main() {
$name()
}
};
}
pub enum Error {
OutOfBoundsCopy,
}
pub enum CallResult {
Successful,
Failure,
Revert,
Unknown,
}
pub enum CreateResult {
Successful(Address),
Failure,
Revert,
Unknown,
}
pub fn consume_gas(amount: u64) {
unsafe {
native::ethereum_useGas(amount);
}
}
pub fn gas_left() -> u64 {
unsafe { native::ethereum_getGasLeft() }
}
pub fn current_address() -> Address {
let mut ret = Address::default();
unsafe {
native::ethereum_getAddress(ret.bytes.as_mut_ptr() as *const u32);
}
ret
}
pub fn external_balance(address: &Address) -> EtherValue {
let mut ret = EtherValue::default();
unsafe {
native::ethereum_getExternalBalance(
address.bytes.as_ptr() as *const u32,
ret.bytes.as_mut_ptr() as *const u32,
);
}
ret
}
pub fn block_coinbase() -> Address {
let mut ret = Address::default();
unsafe {
native::ethereum_getBlockCoinbase(ret.bytes.as_mut_ptr() as *const u32);
}
ret
}
pub fn block_difficulty() -> Difficulty {
let mut ret = Difficulty::default();
unsafe {
native::ethereum_getBlockDifficulty(ret.bytes.as_mut_ptr() as *const u32);
}
ret
}
pub fn block_gas_limit() -> u64 {
unsafe { native::ethereum_getBlockGasLimit() }
}
pub fn block_hash(number: u64) -> Hash {
let mut ret = Hash::default();
unsafe {
native::ethereum_getBlockHash(number, ret.bytes.as_mut_ptr() as *const u32);
}
ret
}
pub fn block_number() -> u64 {
unsafe { native::ethereum_getBlockNumber() }
}
pub fn block_timestamp() -> u64 {
unsafe { native::ethereum_getBlockTimestamp() }
}
pub fn tx_gas_price() -> EtherValue {
let mut ret = EtherValue::default();
unsafe {
native::ethereum_getTxGasPrice(ret.bytes.as_mut_ptr() as *const u32);
}
ret
}
pub fn tx_origin() -> Address {
let mut ret = Address::default();
unsafe {
native::ethereum_getTxOrigin(ret.bytes.as_mut_ptr() as *const u32);
}
ret
}
fn log(
data: &[u8],
topic_count: usize,
topic1: *const u8,
topic2: *const u8,
topic3: *const u8,
topic4: *const u8,
) {
unsafe {
native::ethereum_log(
data.as_ptr() as *const u32,
data.len() as u32,
topic_count as u32,
topic1 as *const u32,
topic2 as *const u32,
topic3 as *const u32,
topic4 as *const u32,
);
}
}
pub fn log0(data: &[u8]) {
log(
data,
0,
0 as *const u8,
0 as *const u8,
0 as *const u8,
0 as *const u8,
)
}
pub fn log1(data: &[u8], topic1: &LogTopic) {
log(
data,
1,
topic1.bytes.as_ptr() as *const u8,
0 as *const u8,
0 as *const u8,
0 as *const u8,
)
}
pub fn log2(data: &[u8], topic1: &LogTopic, topic2: &LogTopic) {
log(
data,
2,
topic1.bytes.as_ptr() as *const u8,
topic2.bytes.as_ptr() as *const u8,
0 as *const u8,
0 as *const u8,
)
}
pub fn log3(data: &[u8], topic1: &LogTopic, topic2: &LogTopic, topic3: &LogTopic) {
log(
data,
3,
topic1.bytes.as_ptr() as *const u8,
topic2.bytes.as_ptr() as *const u8,
topic3.bytes.as_ptr() as *const u8,
0 as *const u8,
)
}
pub fn log4(
data: &[u8],
topic1: &LogTopic,
topic2: &LogTopic,
topic3: &LogTopic,
topic4: &LogTopic,
) {
log(
data,
4,
topic1.bytes.as_ptr() as *const u8,
topic2.bytes.as_ptr() as *const u8,
topic3.bytes.as_ptr() as *const u8,
topic4.bytes.as_ptr() as *const u8,
)
}
pub fn call_mutable(
gas_limit: u64,
address: &Address,
value: &EtherValue,
data: &[u8],
) -> CallResult {
let ret = unsafe {
native::ethereum_call(
gas_limit,
address.bytes.as_ptr() as *const u32,
value.bytes.as_ptr() as *const u32,
data.as_ptr() as *const u32,
data.len() as u32,
)
};
match ret {
0 => CallResult::Successful,
1 => CallResult::Failure,
2 => CallResult::Revert,
_ => CallResult::Unknown,
}
}
pub fn call_code(gas_limit: u64, address: &Address, value: &EtherValue, data: &[u8]) -> CallResult {
let ret = unsafe {
native::ethereum_callCode(
gas_limit,
address.bytes.as_ptr() as *const u32,
value.bytes.as_ptr() as *const u32,
data.as_ptr() as *const u32,
data.len() as u32,
)
};
match ret {
0 => CallResult::Successful,
1 => CallResult::Failure,
2 => CallResult::Revert,
_ => CallResult::Unknown,
}
}
pub fn call_delegate(gas_limit: u64, address: &Address, data: &[u8]) -> CallResult {
let ret = unsafe {
native::ethereum_callDelegate(
gas_limit,
address.bytes.as_ptr() as *const u32,
data.as_ptr() as *const u32,
data.len() as u32,
)
};
match ret {
0 => CallResult::Successful,
1 => CallResult::Failure,
2 => CallResult::Revert,
_ => CallResult::Unknown,
}
}
pub fn call_static(gas_limit: u64, address: &Address, data: &[u8]) -> CallResult {
let ret = unsafe {
native::ethereum_callStatic(
gas_limit,
address.bytes.as_ptr() as *const u32,
data.as_ptr() as *const u32,
data.len() as u32,
)
};
match ret {
0 => CallResult::Successful,
1 => CallResult::Failure,
2 => CallResult::Revert,
_ => CallResult::Unknown,
}
}
pub fn create(value: &EtherValue, data: &[u8]) -> CreateResult {
let mut address = Address::default();
let ret = unsafe {
native::ethereum_create(
value.bytes.as_ptr() as *const u32,
data.as_ptr() as *const u32,
data.len() as u32,
address.bytes.as_mut_ptr() as *const u32,
)
};
match ret {
0 => CreateResult::Successful(address),
1 => CreateResult::Failure,
2 => CreateResult::Revert,
_ => CreateResult::Unknown,
}
}
pub fn unsafe_calldata_copy(from: usize, length: usize, ret: &mut [u8]) {
unsafe {
native::ethereum_callDataCopy(ret.as_mut_ptr() as *const u32, from as u32, length as u32);
}
}
#[cfg(feature = "std")]
pub fn calldata_acquire() -> Vec<u8> {
let length = calldata_size();
let mut ret: Vec<u8> = unsafe_alloc_buffer(length);
unsafe_calldata_copy(0, length, &mut ret);
ret
}
pub fn calldata_copy(from: usize, length: usize, ret: &mut [u8]) -> Result<(), Error> {
let size = calldata_size();
if (size < from) || ((size - from) < length) || (ret.len() < length) {
Err(Error::OutOfBoundsCopy)
} else {
unsafe_calldata_copy(from, length, ret);
Ok(())
}
}
pub fn calldata_size() -> usize {
unsafe { native::ethereum_getCallDataSize() as usize }
}
pub fn caller() -> Address {
let mut ret = Address::default();
unsafe {
native::ethereum_getCaller(ret.bytes.as_mut_ptr() as *const u32);
}
ret
}
pub fn callvalue() -> EtherValue {
let mut ret = EtherValue::default();
unsafe {
native::ethereum_getCallValue(ret.bytes.as_mut_ptr() as *const u32);
}
ret
}
pub fn unsafe_code_copy(from: usize, length: usize, ret: &mut [u8]) {
unsafe {
native::ethereum_codeCopy(ret.as_mut_ptr() as *const u32, from as u32, length as u32);
}
}
#[cfg(feature = "std")]
pub fn code_acquire() -> Vec<u8> {
let length = code_size();
let mut ret: Vec<u8> = unsafe_alloc_buffer(length);
unsafe_code_copy(0, length, &mut ret);
ret
}
pub fn code_copy(from: usize, length: usize, ret: &mut [u8]) -> Result<(), Error> {
let size = code_size();
if (size < from) || ((size - from) < length) || (ret.len() < length) {
Err(Error::OutOfBoundsCopy)
} else {
unsafe_code_copy(from, length, ret);
Ok(())
}
}
pub fn code_size() -> usize {
unsafe { native::ethereum_getCodeSize() as usize }
}
pub fn unsafe_external_code_copy(address: &Address, from: usize, length: usize, ret: &mut [u8]) {
unsafe {
native::ethereum_externalCodeCopy(
address.bytes.as_ptr() as *const u32,
ret.as_mut_ptr() as *const u32,
from as u32,
length as u32,
);
}
}
#[cfg(feature = "std")]
pub fn external_code_acquire(address: &Address) -> Vec<u8> {
let length = external_code_size(address);
let mut ret: Vec<u8> = unsafe_alloc_buffer(length);
unsafe_external_code_copy(address, 0, length, &mut ret);
ret
}
pub fn external_code_copy(
address: &Address,
from: usize,
length: usize,
ret: &mut [u8],
) -> Result<(), Error> {
let size = external_code_size(address);
if (size < from) || ((size - from) < length) || (ret.len() < length) {
Err(Error::OutOfBoundsCopy)
} else {
unsafe_external_code_copy(address, from, length, ret);
Ok(())
}
}
pub fn external_code_size(address: &Address) -> usize {
unsafe { native::ethereum_getExternalCodeSize(address.bytes.as_ptr() as *const u32) as usize }
}
pub fn unsafe_returndata_copy(from: usize, length: usize, ret: &mut [u8]) {
unsafe {
native::ethereum_returnDataCopy(ret.as_mut_ptr() as *const u32, from as u32, length as u32);
}
}
#[cfg(feature = "std")]
pub fn returndata_acquire() -> Vec<u8> {
let length = returndata_size();
let mut ret: Vec<u8> = unsafe_alloc_buffer(length);
unsafe_returndata_copy(0, length, &mut ret);
ret
}
pub fn returndata_copy(from: usize, length: usize, ret: &mut [u8]) -> Result<(), Error> {
let size = returndata_size();
if (size < from) || ((size - from) < length) || (ret.len() < length) {
Err(Error::OutOfBoundsCopy)
} else {
unsafe_returndata_copy(from, length, ret);
Ok(())
}
}
pub fn returndata_size() -> usize {
unsafe { native::ethereum_getReturnDataSize() as usize }
}
pub fn abort() -> ! {
panic!()
}
pub fn revert() -> ! {
unsafe {
native::ethereum_revert(0 as *const u32, 0 as u32);
}
}
pub fn revert_data(data: &[u8]) -> ! {
unsafe {
native::ethereum_revert(data.as_ptr() as *const u32, data.len() as u32);
}
}
pub fn finish() -> ! {
unsafe {
native::ethereum_finish(0 as *const u32, 0 as u32);
}
}
pub fn finish_data(data: &[u8]) -> ! {
unsafe {
native::ethereum_finish(data.as_ptr() as *const u32, data.len() as u32);
}
}
pub fn storage_load(key: &StorageKey) -> StorageValue {
let mut ret = StorageValue::default();
unsafe {
native::ethereum_storageLoad(
key.bytes.as_ptr() as *const u32,
ret.bytes.as_mut_ptr() as *const u32,
);
}
ret
}
pub fn storage_store(key: &StorageKey, value: &StorageValue) {
unsafe {
native::ethereum_storageStore(
key.bytes.as_ptr() as *const u32,
value.bytes.as_ptr() as *const u32,
);
}
}
pub fn selfdestruct(address: &Address) -> ! {
unsafe {
native::ethereum_selfDestruct(address.bytes.as_ptr() as *const u32);
}
}