//! Execution context information. //! //! Provides access to information about the current execution context, //! such as the caller, block info, and transaction data. use alloc::vec::Vec; use crate::host; use crate::types::{Address, Hash256}; /// Returns the address that called this contract. /// /// For external calls, this is the transaction sender. /// For internal calls, this is the calling contract. pub fn caller() -> Address { Address(host::get_caller()) } /// Returns the contract's own address. pub fn self_address() -> Address { Address(host::get_address()) } /// Returns the original transaction sender. /// /// Unlike `caller()`, this always returns the externally owned account /// that initiated the transaction, even in nested contract calls. pub fn origin() -> Address { Address(host::get_origin()) } /// Returns the value (in sompi) sent with this call. pub fn value() -> u64 { host::get_value() } /// Returns the call data. pub fn calldata() -> Vec { let size = host::get_calldata_size(); if size == 0 { return Vec::new(); } let mut data = alloc::vec![0u8; size]; host::get_calldata(&mut data, 0); data } /// Returns a slice of the call data. pub fn calldata_slice(offset: usize, length: usize) -> Vec { let size = host::get_calldata_size(); if offset >= size { return Vec::new(); } let actual_length = core::cmp::min(length, size - offset); let mut data = alloc::vec![0u8; actual_length]; host::get_calldata(&mut data, offset); data } /// Returns the current block timestamp (Unix timestamp in seconds). pub fn timestamp() -> u64 { host::get_timestamp() } /// Returns the current block height (DAA score). pub fn block_height() -> u64 { host::get_block_height() } /// Returns the current block hash. pub fn block_hash() -> Hash256 { Hash256(host::get_block_hash()) } /// Returns the remaining gas for this execution. pub fn gas_remaining() -> u64 { host::get_gas_remaining() } /// Returns the chain ID. pub fn chain_id() -> u64 { host::get_chain_id() } /// Checks if this is a static (read-only) call. /// /// Static calls cannot modify state or emit events. pub fn is_static_call() -> bool { // In a static call, attempting to write storage will fail. // We can detect this by the chain ID being set to a special value // or by trying a no-op write (expensive, so avoided). // For now, assume not static unless VM provides a way to check. false } /// Block information structure. #[derive(Clone, Debug)] pub struct BlockInfo { /// Block height (DAA score). pub height: u64, /// Block timestamp. pub timestamp: u64, /// Block hash. pub hash: Hash256, } impl BlockInfo { /// Gets current block info. pub fn current() -> Self { BlockInfo { height: block_height(), timestamp: timestamp(), hash: block_hash(), } } } /// Transaction information structure. #[derive(Clone, Debug)] pub struct TxInfo { /// Transaction origin (sender). pub origin: Address, /// Value sent with transaction. pub value: u64, /// Call data. pub data: Vec, } impl TxInfo { /// Gets current transaction info. pub fn current() -> Self { TxInfo { origin: origin(), value: value(), data: calldata(), } } } /// Gets the balance of an address. pub fn balance_of(address: &Address) -> u64 { host::get_balance(&address.0) } /// Gets the balance of this contract. pub fn self_balance() -> u64 { let addr = self_address(); host::get_balance(&addr.0) } /// Transfers value to an address. /// /// Returns `true` on success, `false` on failure. pub fn transfer(to: &Address, amount: u64) -> bool { host::transfer(&to.0, amount) } #[cfg(test)] mod tests { use super::*; #[test] fn test_block_info() { let info = BlockInfo::current(); // Just verify it compiles and runs let _ = info.height; let _ = info.timestamp; } #[test] fn test_tx_info() { let info = TxInfo::current(); let _ = info.origin; let _ = info.value; } }