use crate::types::*;
#[derive(Debug)]
pub struct Error;
mod eth {
extern "C" {
pub fn ccall(
gas: i64,
address: *const u8,
val_ptr: *const u8,
input_ptr: *const u8,
input_len: u32,
result_ptr: *mut u8,
result_len: u32,
) -> i32;
pub fn dcall(
gas: i64,
address: *const u8,
input_ptr: *const u8,
input_len: u32,
result_ptr: *mut u8,
result_len: u32,
) -> i32;
pub fn scall(
gas: i64,
address: *const u8,
input_ptr: *const u8,
input_len: u32,
result_ptr: *mut u8,
result_len: u32,
) -> i32;
pub fn address(dest: *mut u8);
pub fn balance(address: *const u8, dest: *mut u8);
pub fn blockhash(number: i64, dest: *mut u8);
pub fn blocknumber() -> i64;
pub fn coinbase(dest: *mut u8);
pub fn create(
endowment: *const u8,
code_ptr: *const u8,
code_len: u32,
result_ptr: *mut u8,
) -> i32;
pub fn create2(
endowment: *const u8,
salt: *const u8,
code_ptr: *const u8,
code_len: u32,
result_ptr: *mut u8,
) -> i32;
pub fn difficulty(dest: *mut u8);
pub fn elog(topic_ptr: *const u8, topic_count: u32, data_ptr: *const u8, data_len: u32);
pub fn fetch_input(dst: *mut u8);
pub fn gasleft() -> i64;
pub fn gaslimit(dest: *mut u8);
pub fn input_length() -> u32;
pub fn origin(dest: *mut u8);
pub fn ret(ptr: *const u8, len: u32) -> !;
pub fn sender(dest: *mut u8);
pub fn suicide(refund: *const u8) -> !;
pub fn timestamp() -> i64;
pub fn value(dest: *mut u8);
}
}
extern "C" {
fn storage_read(key: *const u8, dst: *mut u8);
fn storage_write(key: *const u8, src: *const u8);
}
pub fn suicide(refund: &Address) -> ! {
unsafe {
eth::suicide(refund.as_ptr());
}
}
pub fn balance(address: &Address) -> U256 {
unsafe { fetch_u256(|x| eth::balance(address.as_ptr(), x)) }
}
pub fn create(endowment: U256, code: &[u8]) -> Result<Address, Error> {
let mut endowment_arr = [0u8; 32];
endowment.to_big_endian(&mut endowment_arr);
let mut result = Address::zero();
unsafe {
if eth::create(
endowment_arr.as_ptr(),
code.as_ptr(),
code.len() as u32,
(&mut result).as_mut_ptr(),
) == 0
{
Ok(result)
} else {
Err(Error)
}
}
}
pub fn create2(endowment: U256, salt: H256, code: &[u8]) -> Result<Address, Error> {
let mut endowment_arr = [0u8; 32];
endowment.to_big_endian(&mut endowment_arr);
let mut result = Address::zero();
unsafe {
if eth::create2(
endowment_arr.as_ptr(),
salt.as_ptr(),
code.as_ptr(),
code.len() as u32,
(&mut result).as_mut_ptr(),
) == 0
{
Ok(result)
} else {
Err(Error)
}
}
}
pub fn call(
gas: u64,
address: &Address,
value: U256,
input: &[u8],
result: &mut [u8],
) -> Result<(), Error> {
let mut value_arr = [0u8; 32];
value.to_big_endian(&mut value_arr);
unsafe {
if eth::ccall(
gas as i64,
address.as_ptr(),
value_arr.as_ptr(),
input.as_ptr(),
input.len() as u32,
result.as_mut_ptr(),
result.len() as u32,
) == 0
{
Ok(())
} else {
Err(Error)
}
}
}
pub fn call_code(
gas: u64,
address: &Address,
input: &[u8],
result: &mut [u8],
) -> Result<(), Error> {
unsafe {
if eth::dcall(
gas as i64,
address.as_ptr(),
input.as_ptr(),
input.len() as u32,
result.as_mut_ptr(),
result.len() as u32,
) == 0
{
Ok(())
} else {
Err(Error)
}
}
}
pub fn static_call(
gas: u64,
address: &Address,
input: &[u8],
result: &mut [u8],
) -> Result<(), Error> {
unsafe {
if eth::scall(
gas as i64,
address.as_ptr(),
input.as_ptr(),
input.len() as u32,
result.as_mut_ptr(),
result.len() as u32,
) == 0
{
Ok(())
} else {
Err(Error)
}
}
}
pub fn block_hash(block_number: u64) -> H256 {
let mut res = H256::zero();
unsafe { eth::blockhash(block_number as i64, res.as_mut_ptr()) }
res
}
pub fn coinbase() -> Address {
unsafe { fetch_address(|x| eth::coinbase(x)) }
}
pub fn timestamp() -> u64 {
unsafe { eth::timestamp() as u64 }
}
pub fn block_number() -> u64 {
unsafe { eth::blocknumber() as u64 }
}
pub fn difficulty() -> U256 {
unsafe { fetch_u256(|x| eth::difficulty(x)) }
}
pub fn gas_limit() -> U256 {
unsafe { fetch_u256(|x| eth::gaslimit(x)) }
}
pub fn gas_left() -> u64 {
unsafe { eth::gasleft() as u64 }
}
pub fn sender() -> Address {
unsafe { fetch_address(|x| eth::sender(x)) }
}
pub fn origin() -> Address {
unsafe { fetch_address(|x| eth::origin(x)) }
}
pub fn value() -> U256 {
unsafe { fetch_u256(|x| eth::value(x)) }
}
pub fn address() -> Address {
unsafe { fetch_address(|x| eth::address(x)) }
}
pub fn log(topics: &[H256], data: &[u8]) {
unsafe {
eth::elog(
topics.as_ptr() as *const u8,
topics.len() as u32,
data.as_ptr(),
data.len() as u32,
);
}
}
pub fn input() -> Vec<u8> {
let len = unsafe { eth::input_length() };
match len {
0 => Vec::new(),
non_zero => {
let mut data = Vec::with_capacity(non_zero as usize);
unsafe {
data.set_len(non_zero as usize);
eth::fetch_input(data.as_mut_ptr());
}
data
}
}
}
pub fn ret(data: &[u8]) -> ! {
unsafe {
eth::ret(data.as_ptr(), data.len() as u32);
}
}
pub fn read(key: &H256) -> [u8; 32] {
let mut dst = [0u8; 32];
unsafe {
storage_read(key.as_ptr(), dst.as_mut_ptr());
}
dst
}
pub fn write(key: &H256, val: &[u8; 32]) {
unsafe {
storage_write(key.as_ptr(), val.as_ptr());
}
}
unsafe fn fetch_address<F: Fn(*mut u8)>(f: F) -> Address {
let mut res = Address::zero();
f(res.as_mut_ptr());
res
}
unsafe fn fetch_u256<F: Fn(*mut u8)>(f: F) -> U256 {
let mut res = [0u8; 32];
f(res.as_mut_ptr());
U256::from_big_endian(&res)
}