use elrond_wasm::{H256, Address};
use crate::big_int::*;
use crate::big_uint::*;
use crate::ext_error;
use elrond_wasm::BigUintApi;
use elrond_wasm::ContractHookApi;
use elrond_wasm::err_msg;
use alloc::vec::Vec;
const ADDRESS_LENGTH: usize = 32;
const TOPIC_LENGTH: usize = 32;
extern {
fn getSCAddress(resultOffset: *mut u8);
fn getOwnerAddress(resultOffset: *mut u8);
fn blockHash(nonce: i64, resultOffset: *mut u8) -> i32;
fn getNumArguments() -> i32;
fn getArgumentLength(id: i32) -> i32;
fn getArgument(id: i32, dstOffset: *mut u8) -> i32;
fn getFunction(functionOffset: *const u8) -> i32;
fn storageStore(keyOffset: *const u8, keyLength: i32, dataOffset: *const u8, dataLength: i32) -> i32;
fn storageLoadLength(keyOffset: *const u8, keyLength: i32) -> i32;
fn storageLoad(keyOffset: *const u8, keyLength: i32, dataOffset: *mut u8) -> i32;
fn transferValue(dstOffset: *const u8, valueOffset: *const u8, dataOffset: *const u8, length: i32) -> i32;
fn asyncCall(dstOffset: *const u8, valueOffset: *const u8, dataOffset: *const u8, length: i32);
fn getCaller(resultOffset: *mut u8);
fn callValue(resultOffset: *const u8) -> i32;
fn getESDTValue(resultOffset: *const u8) -> usize;
fn getESDTTokenName(resultOffset: *const u8) -> usize;
fn writeLog(pointer: *const u8, length: i32, topicPtr: *const u8, numTopics: i32);
fn finish(dataOffset: *const u8, length: i32);
fn getGasLeft() -> i64;
fn getBlockTimestamp() -> i64;
fn getBlockNonce() -> i64;
fn getBlockRound() -> i64;
fn getBlockEpoch() -> i64;
fn getBlockRandomSeed(resultOffset: *mut u8);
fn getStateRootHash(resultOffset: *mut u8);
fn getPrevBlockTimestamp() -> i64;
fn getPrevBlockNonce() -> i64;
fn getPrevBlockRound() -> i64;
fn getPrevBlockEpoch() -> i64;
fn getPrevBlockRandomSeed(resultOffset: *const u8);
fn getOriginalTxHash(resultOffset: *const u8);
fn bigIntNew(value: i64) -> i32;
fn bigIntStorageStoreUnsigned(keyOffset: *const u8, keyLength: i32, source: i32) -> i32;
fn bigIntStorageLoadUnsigned(keyOffset: *const u8, keyLength: i32, destination: i32) -> i32;
fn bigIntGetExternalBalance(address_ptr: *const u8, dest: i32);
fn bigIntGetUnsignedArgument(arg_id: i32, dest: i32);
fn bigIntGetSignedArgument(arg_id: i32, dest: i32);
fn bigIntGetCallValue(dest: i32);
fn bigIntGetESDTCallValue(dest: i32);
fn bigIntFinishUnsigned(bih: i32);
fn bigIntFinishSigned(bih: i32);
fn int64getArgument(id: i32) -> i64;
fn int64finish(value: i64);
fn int64storageStore(keyOffset: *const u8, keyLength: i32, value: i64) -> i32;
fn int64storageLoad(keyOffset: *const u8, keyLength: i32) -> i64;
fn sha256(dataOffset: *const u8, length: i32, resultOffset: *mut u8) -> i32;
fn keccak256(dataOffset: *const u8, length: i32, resultOffset: *mut u8) -> i32;
}
pub struct ArwenApiImpl {}
impl elrond_wasm::ContractHookApi<ArwenBigInt, ArwenBigUint> for ArwenApiImpl {
#[inline]
fn get_sc_address(&self) -> Address {
unsafe {
let mut res = [0u8; 32];
getSCAddress(res.as_mut_ptr());
res.into()
}
}
#[inline]
fn get_owner_address(&self) -> Address {
unsafe {
let mut res = [0u8; 32];
getOwnerAddress(res.as_mut_ptr());
res.into()
}
}
#[inline]
fn get_caller(&self) -> Address {
unsafe {
let mut res = [0u8; 32];
getCaller(res.as_mut_ptr());
res.into()
}
}
fn get_balance(&self, address: &Address) -> ArwenBigUint {
unsafe {
let result = bigIntNew(0);
bigIntGetExternalBalance(address.as_ref().as_ptr(), result);
ArwenBigUint {handle: result}
}
}
fn storage_store(&self, key: &[u8], value: &[u8]) {
unsafe {
storageStore(key.as_ref().as_ptr(), key.len() as i32, value.as_ptr(), value.len() as i32);
}
}
fn storage_load(&self, key: &[u8]) -> Vec<u8> {
unsafe {
let value_len = self.storage_load_len(key);
let mut res = Vec::with_capacity(value_len);
storageLoad(key.as_ref().as_ptr(), key.len() as i32, res.as_mut_ptr());
res.set_len(value_len);
res
}
}
#[inline]
fn storage_load_len(&self, key: &[u8]) -> usize {
unsafe {
storageLoadLength(key.as_ref().as_ptr(), key.len() as i32) as usize
}
}
#[inline]
fn storage_store_bytes32(&self, key: &[u8], value: &[u8; 32]) {
unsafe {
storageStore(key.as_ref().as_ptr(), key.len() as i32, value.as_ptr(), 32);
}
}
fn storage_load_bytes32(&self, key: &[u8]) -> [u8; 32] {
unsafe {
let mut res = [0u8; 32];
let len = storageLoad(key.as_ref().as_ptr(), key.len() as i32, res.as_mut_ptr());
if len != 32 {
ext_error::signal_error(err_msg::STORAGE_NOT_32_BYTES);
}
res
}
}
#[inline]
fn storage_store_big_uint(&self, key: &[u8], value: &ArwenBigUint) {
unsafe {
bigIntStorageStoreUnsigned(key.as_ref().as_ptr(), key.len() as i32, value.handle);
}
}
#[inline]
fn storage_load_big_uint(&self, key: &[u8]) -> ArwenBigUint {
unsafe {
let result = bigIntNew(0);
bigIntStorageLoadUnsigned(key.as_ref().as_ptr(), key.len() as i32, result);
ArwenBigUint {handle: result}
}
}
#[inline]
fn storage_store_big_int(&self, key: &[u8], value: &ArwenBigInt) {
unsafe {
bigIntStorageStoreUnsigned(key.as_ref().as_ptr(), key.len() as i32, value.handle);
}
}
#[inline]
fn storage_load_big_int(&self, key: &[u8]) -> ArwenBigInt {
unsafe {
let result = bigIntNew(0);
bigIntStorageLoadUnsigned(key.as_ref().as_ptr(), key.len() as i32, result);
ArwenBigInt {handle: result}
}
}
#[inline]
fn storage_store_i64(&self, key: &[u8], value: i64) {
unsafe {
int64storageStore(key.as_ref().as_ptr(), key.len() as i32, value);
}
}
#[inline]
fn storage_load_i64(&self, key: &[u8]) -> Option<i64> {
unsafe{
Some(int64storageLoad(key.as_ref().as_ptr(), key.len() as i32))
}
}
#[inline]
fn get_call_value_big_uint(&self) -> ArwenBigUint {
unsafe {
let result = bigIntNew(0);
bigIntGetCallValue(result);
ArwenBigUint {handle: result}
}
}
#[inline]
fn get_esdt_value_big_uint(&self) -> ArwenBigUint {
unsafe {
let result = bigIntNew(0);
bigIntGetESDTCallValue(result);
ArwenBigUint {handle: result}
}
}
#[inline]
fn get_esdt_token_name(&self) -> Option<Vec<u8>> {
unsafe {
let mut name = Vec::with_capacity(32);
let name_len = getESDTTokenName(name.as_mut_ptr());
match name_len {
0 => None,
_ => {
name.set_len(name_len);
Some(name)
}
}
}
}
fn send_tx(&self, to: &Address, amount: &ArwenBigUint, message: &str) {
let amount_bytes32 = amount.to_bytes_be_pad_right(32).unwrap();
unsafe {
transferValue(
to.as_ref().as_ptr(),
amount_bytes32.as_ptr(),
message.as_ptr(),
message.len() as i32
);
}
}
fn async_call(&self, to: &Address, amount: &ArwenBigUint, data: &[u8]) {
let amount_bytes32 = amount.to_bytes_be_pad_right(32).unwrap();
unsafe {
asyncCall(
to.as_ref().as_ptr(),
amount_bytes32.as_ptr(),
data.as_ptr(),
data.len() as i32
);
}
}
#[inline]
fn get_tx_hash(&self) -> H256 {
unsafe {
let mut res = [0u8; 32];
getOriginalTxHash(res.as_mut_ptr());
res.into()
}
}
#[inline]
fn get_gas_left(&self) -> u64 {
unsafe { getGasLeft() as u64 }
}
#[inline]
fn get_block_timestamp(&self) -> u64 {
unsafe{ getBlockTimestamp() as u64 }
}
#[inline]
fn get_block_nonce(&self) -> u64 {
unsafe{ getBlockNonce() as u64 }
}
#[inline]
fn get_block_round(&self) -> u64 {
unsafe{ getBlockRound() as u64 }
}
#[inline]
fn get_block_epoch(&self) -> u64 {
unsafe{ getBlockEpoch() as u64 }
}
#[inline]
fn get_prev_block_timestamp(&self) -> u64 {
unsafe{ getPrevBlockTimestamp() as u64 }
}
#[inline]
fn get_prev_block_nonce(&self) -> u64 {
unsafe{ getPrevBlockNonce() as u64 }
}
#[inline]
fn get_prev_block_round(&self) -> u64 {
unsafe{ getPrevBlockRound() as u64 }
}
#[inline]
fn get_prev_block_epoch(&self) -> u64 {
unsafe{ getPrevBlockEpoch() as u64 }
}
fn sha256(&self, data: &[u8]) -> [u8; 32] {
unsafe {
let mut res = [0u8; 32];
sha256(data.as_ptr(), data.len() as i32, res.as_mut_ptr());
res
}
}
fn keccak256(&self, data: &[u8]) -> [u8; 32] {
unsafe {
let mut res = [0u8; 32];
keccak256(data.as_ptr(), data.len() as i32, res.as_mut_ptr());
res
}
}
}
impl elrond_wasm::ContractIOApi<ArwenBigInt, ArwenBigUint> for ArwenApiImpl {
#[inline]
fn get_num_arguments(&self) -> i32 {
unsafe { getNumArguments() }
}
fn check_not_payable(&self) {
if self.get_call_value_big_uint() > 0 {
self.signal_error(err_msg::NON_PAYABLE);
}
}
#[inline]
fn get_argument_len(&self, arg_index: i32) -> usize {
unsafe { getArgumentLength(arg_index) as usize }
}
fn copy_argument_to_slice(&self, arg_index: i32, slice: &mut [u8]) {
unsafe {
let byte_len = getArgument(arg_index, slice.as_mut_ptr()) as usize;
if byte_len != slice.len() {
self.signal_error(err_msg::ARG_BAD_LENGTH);
}
}
}
fn get_argument_vec(&self, arg_index: i32) -> Vec<u8> {
let len = self.get_argument_len(arg_index);
unsafe {
let mut res = Vec::with_capacity(len);
res.set_len(len);
getArgument(arg_index, res.as_mut_ptr());
res
}
}
#[inline]
fn get_argument_bytes32(&self, arg_index: i32) -> [u8; 32] {
unsafe {
let mut res = [0u8; 32];
let len = getArgument(arg_index, res.as_mut_ptr());
if len != 32 {
self.signal_error(err_msg::ARG_BAD_LENGTH_32);
}
res
}
}
#[inline]
fn get_argument_big_uint(&self, arg_id: i32) -> ArwenBigUint {
unsafe {
let result = bigIntNew(0);
bigIntGetUnsignedArgument(arg_id, result);
ArwenBigUint {handle: result}
}
}
#[inline]
fn get_argument_big_int(&self, arg_id: i32) -> ArwenBigInt {
unsafe {
let result = bigIntNew(0);
bigIntGetSignedArgument(arg_id, result);
ArwenBigInt {handle: result}
}
}
#[inline]
fn get_argument_i64(&self, arg_id: i32) -> i64 {
unsafe { int64getArgument(arg_id) }
}
#[inline]
fn finish_slice_u8(&self, slice: &[u8]) {
unsafe {
finish(slice.as_ptr(), slice.len() as i32);
}
}
#[inline]
fn finish_bytes32(&self, bytes: &[u8; 32]) {
unsafe {
finish(bytes.as_ptr(), 32i32);
}
}
#[inline]
fn finish_big_int(&self, b: &ArwenBigInt) {
unsafe {
bigIntFinishSigned(b.handle);
}
}
#[inline]
fn finish_big_uint(&self, b: &ArwenBigUint) {
unsafe {
bigIntFinishUnsigned(b.handle);
}
}
#[inline]
fn finish_i64(&self, value: i64) {
unsafe { int64finish(value); }
}
#[inline]
fn signal_error(&self, message: &[u8]) -> ! {
ext_error::signal_error(message)
}
fn write_log(&self, topics: &[[u8;32]], data: &[u8]) {
let mut topics_raw = [0u8; TOPIC_LENGTH * 10];
for i in 0..topics.len() {
topics_raw[TOPIC_LENGTH*i..TOPIC_LENGTH*(i+1)].copy_from_slice(&topics[i]);
}
unsafe {
writeLog(data.as_ptr(), data.len() as i32, topics_raw.as_ptr(), topics.len() as i32);
}
}
}
impl Clone for ArwenApiImpl {
#[inline]
fn clone(&self) -> Self {
ArwenApiImpl {}
}
}