use crate::types::Vec;
use crate::{sys, AccountId, Balance, Gas};
use core::mem::size_of;
const ATOMIC_OP_REGISTER: u64 = core::u64::MAX - 1;
const EVICTED_REGISTER: u64 = core::u64::MAX - 2;
const STATE_KEY: &[u8] = b"STATE";
macro_rules! try_method_into_register {
( $method:ident, $v:expr ) => {{
unsafe { sys::$method(ATOMIC_OP_REGISTER) };
read_register(ATOMIC_OP_REGISTER, $v).unwrap_or_else(|_| abort())
}};
}
macro_rules! method_into_register {
( $method:ident, $v:expr ) => {{
try_method_into_register!($method, $v)
}};
}
pub struct PromiseIndex(pub u64);
pub fn abort() -> ! {
#[cfg(target_arch = "wasm32")]
{
core::arch::wasm32::unreachable()
}
#[cfg(not(target_arch = "wasm32"))]
unsafe {
sys::panic()
}
}
#[allow(clippy::result_unit_err)]
pub fn read_register(register_id: u64, buf: &mut [u8]) -> Result<usize, ()> {
let len = register_len(register_id).ok_or(())? as usize;
if buf.len() < len {
return Err(());
}
unsafe { sys::read_register(register_id, buf.as_ptr() as _) };
Ok(len)
}
pub fn register_len(register_id: u64) -> Option<u64> {
let len = unsafe { sys::register_len(register_id) };
if len == core::u64::MAX {
None
} else {
Some(len)
}
}
pub fn current_account_id() -> AccountId {
let mut a = Vec::<u8, 64>::new();
a.resize(64, 0).unwrap_or_else(|_| abort());
let len = method_into_register!(current_account_id, a.as_mut());
unsafe {
a.set_len(len);
AccountId::new_raw(a)
}
}
pub fn block_index() -> u64 {
unsafe { sys::block_index() }
}
pub fn block_timestamp() -> u64 {
unsafe { sys::block_timestamp() }
}
pub fn epoch_height() -> u64 {
unsafe { sys::epoch_height() }
}
pub fn storage_usage() -> u64 {
unsafe { sys::storage_usage() }
}
pub fn account_balance() -> Balance {
let data = [0u8; size_of::<Balance>()];
unsafe { sys::account_balance(data.as_ptr() as u64) };
Balance::from_le_bytes(data)
}
pub fn account_locked_balance() -> Balance {
let data = [0u8; size_of::<Balance>()];
unsafe { sys::account_locked_balance(data.as_ptr() as u64) };
Balance::from_le_bytes(data)
}
pub fn attached_deposit() -> Balance {
let data = [0u8; size_of::<Balance>()];
unsafe { sys::attached_deposit(data.as_ptr() as u64) };
Balance::from_le_bytes(data)
}
pub fn prepaid_gas() -> Gas {
unsafe { sys::prepaid_gas() }
}
pub fn used_gas() -> Gas {
unsafe { sys::used_gas() }
}
pub fn sha256(value: &[u8]) -> [u8; 32] {
unsafe { sys::sha256(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER) };
let mut hash = [0u8; 32];
read_register(ATOMIC_OP_REGISTER, &mut hash).unwrap_or_else(|_| abort());
hash
}
pub fn keccak256(value: &[u8]) -> [u8; 32] {
unsafe { sys::keccak256(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER) };
let mut hash = [0u8; 32];
read_register(ATOMIC_OP_REGISTER, &mut hash).unwrap_or_else(|_| abort());
hash
}
pub fn keccak512(value: &[u8]) -> [u8; 64] {
unsafe { sys::keccak512(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER) };
let mut hash = [0u8; 64];
read_register(ATOMIC_OP_REGISTER, &mut hash).unwrap_or_else(|_| abort());
hash
}
pub fn validator_stake(account_id: &str) -> Balance {
let data = [0u8; size_of::<Balance>()];
unsafe {
sys::validator_stake(
account_id.len() as _,
account_id.as_ptr() as _,
data.as_ptr() as u64,
)
};
Balance::from_le_bytes(data)
}
pub fn validator_total_stake() -> Balance {
let data = [0u8; size_of::<Balance>()];
unsafe { sys::validator_total_stake(data.as_ptr() as u64) };
Balance::from_le_bytes(data)
}
pub fn value_return(value: &[u8]) {
unsafe { sys::value_return(value.len() as _, value.as_ptr() as _) }
}
pub fn panic_str(message: &str) -> ! {
unsafe { sys::panic_utf8(message.len() as _, message.as_ptr() as _) }
}
pub fn log_str(message: &str) {
#[cfg(all(debug_assertions, not(target_arch = "wasm32")))]
eprintln!("{}", message);
unsafe { sys::log_utf8(message.len() as _, message.as_ptr() as _) }
}
pub fn storage_write(key: &[u8], value: &[u8]) -> bool {
match unsafe {
sys::storage_write(
key.len() as _,
key.as_ptr() as _,
value.len() as _,
value.as_ptr() as _,
EVICTED_REGISTER,
)
} {
0 => false,
1 => true,
_ => abort(),
}
}
pub fn storage_read(key: &[u8], buf: &mut [u8]) -> Option<usize> {
match unsafe { sys::storage_read(key.len() as _, key.as_ptr() as _, ATOMIC_OP_REGISTER) } {
0 => None,
1 => Some(read_register(ATOMIC_OP_REGISTER, buf).unwrap_or_else(|_| abort())),
_ => abort(),
}
}
pub fn storage_remove(key: &[u8]) -> bool {
match unsafe { sys::storage_remove(key.len() as _, key.as_ptr() as _, EVICTED_REGISTER) } {
0 => false,
1 => true,
_ => abort(),
}
}
pub fn storage_get_evicted(buf: &mut [u8]) -> Option<usize> {
read_register(EVICTED_REGISTER, buf).ok()
}
pub fn storage_has_key(key: &[u8]) -> bool {
match unsafe { sys::storage_has_key(key.len() as _, key.as_ptr() as _) } {
0 => false,
1 => true,
_ => abort(),
}
}
pub fn state_read_raw(buf: &mut [u8]) -> Option<usize> {
storage_read(STATE_KEY, buf)
}
pub fn state_write_raw(data: &[u8]) {
storage_write(STATE_KEY, data);
}
pub fn state_exists() -> bool {
storage_has_key(STATE_KEY)
}
pub fn promise_create(
account_id: &str,
method_name: &str,
arguments: &[u8],
amount: Balance,
gas: Gas,
) -> PromiseIndex {
unsafe {
PromiseIndex(sys::promise_create(
account_id.len() as _,
account_id.as_ptr() as _,
method_name.len() as _,
method_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount as *const Balance as _,
gas,
))
}
}
pub fn promise_then(
promise_idx: PromiseIndex,
account_id: &str,
method_name: &str,
arguments: &[u8],
amount: Balance,
gas: Gas,
) -> PromiseIndex {
unsafe {
PromiseIndex(sys::promise_then(
promise_idx.0,
account_id.len() as _,
account_id.as_ptr() as _,
method_name.len() as _,
method_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount as *const Balance as _,
gas,
))
}
}
pub fn promise_batch_create(account_id: &str) -> PromiseIndex {
unsafe {
PromiseIndex(sys::promise_batch_create(
account_id.len() as _,
account_id.as_ptr() as _,
))
}
}
pub fn promise_batch_then(promise_index: PromiseIndex, account_id: &str) -> PromiseIndex {
unsafe {
PromiseIndex(sys::promise_batch_then(
promise_index.0,
account_id.len() as _,
account_id.as_ptr() as _,
))
}
}
pub fn promise_batch_action_create_account(promise_index: PromiseIndex) {
unsafe { sys::promise_batch_action_create_account(promise_index.0) }
}
pub fn promise_batch_action_deploy_contract(promise_index: u64, code: &[u8]) {
unsafe {
sys::promise_batch_action_deploy_contract(
promise_index,
code.len() as _,
code.as_ptr() as _,
)
}
}
pub fn promise_batch_action_function_call(
promise_index: PromiseIndex,
method_name: &str,
arguments: &[u8],
amount: Balance,
gas: Gas,
) {
unsafe {
sys::promise_batch_action_function_call(
promise_index.0,
method_name.len() as _,
method_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount as *const Balance as _,
gas,
)
}
}
pub fn promise_batch_action_transfer(promise_index: PromiseIndex, amount: Balance) {
unsafe { sys::promise_batch_action_transfer(promise_index.0, &amount as *const Balance as _) }
}
pub fn promise_batch_action_stake(promise_index: PromiseIndex, amount: Balance, public_key: &[u8]) {
unsafe {
sys::promise_batch_action_stake(
promise_index.0,
&amount as *const Balance as _,
public_key.len() as _,
public_key.as_ptr() as _,
)
}
}
pub fn promise_batch_action_add_key_with_full_access(
promise_index: PromiseIndex,
public_key: &[u8],
nonce: u64,
) {
unsafe {
sys::promise_batch_action_add_key_with_full_access(
promise_index.0,
public_key.len() as _,
public_key.as_ptr() as _,
nonce,
)
}
}
pub fn promise_batch_action_add_key_with_function_call(
promise_index: PromiseIndex,
public_key: &[u8],
nonce: u64,
allowance: Balance,
receiver_id: &str,
method_names: &str,
) {
unsafe {
sys::promise_batch_action_add_key_with_function_call(
promise_index.0,
public_key.len() as _,
public_key.as_ptr() as _,
nonce,
&allowance as *const Balance as _,
receiver_id.len() as _,
receiver_id.as_ptr() as _,
method_names.len() as _,
method_names.as_ptr() as _,
)
}
}
pub fn promise_batch_action_delete_key(promise_index: PromiseIndex, public_key: &[u8]) {
unsafe {
sys::promise_batch_action_delete_key(
promise_index.0,
public_key.len() as _,
public_key.as_ptr() as _,
)
}
}
pub fn promise_batch_action_delete_account(promise_index: PromiseIndex, beneficiary_id: &str) {
unsafe {
sys::promise_batch_action_delete_account(
promise_index.0,
beneficiary_id.len() as _,
beneficiary_id.as_ptr() as _,
)
}
}
const STORAGE_PRICE_PER_BYTE: Balance = 10_000_000_000_000_000_000;
pub fn storage_byte_cost() -> Balance {
STORAGE_PRICE_PER_BYTE
}