synor/crates/synor-sdk/src/context.rs
Gulshan Yadav 48949ebb3f Initial commit: Synor blockchain monorepo
A complete blockchain implementation featuring:
- synord: Full node with GHOSTDAG consensus
- explorer-web: Modern React blockchain explorer with 3D DAG visualization
- CLI wallet and tools
- Smart contract SDK and example contracts (DEX, NFT, token)
- WASM crypto library for browser/mobile
2026-01-08 05:22:17 +05:30

178 lines
4.1 KiB
Rust

//! 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<u8> {
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<u8> {
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<u8>,
}
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;
}
}