Skip to main content

truthlinked_sdk/
context.rs

1//! Execution context accessors for contract runtime information.
2//!
3//! This module provides functions to query the current execution context,
4//! including caller information, block data, and call parameters.
5//!
6//! # Available Context
7//!
8//! - **Caller**: Who invoked this contract
9//! - **Owner**: Who deployed/owns this contract
10//! - **Contract ID**: This contract's address
11//! - **Block data**: Current height and timestamp
12//! - **Call value**: Native tokens sent with the call
13//! - **Calldata**: Function selector and arguments
14//!
15//! # Example
16//!
17//! ```ignore
18//! use truthlinked_sdk::context;
19//!
20//! fn handle_execute() -> Result<()> {
21//!     let caller = context::caller()?;
22//!     let owner = context::owner()?;
23//!     
24//!     // Only owner can call this function
25//!     if caller != owner {
26//!         return Err(Error::new(ERR_UNAUTHORIZED));
27//!     }
28//!     
29//!     let height = context::block_height()?;
30//!     let value = context::call_value()?;
31//!     
32//!     // Process transaction...
33//!     Ok(())
34//! }
35//! ```
36
37extern crate alloc;
38
39use alloc::vec;
40use alloc::vec::Vec;
41
42use crate::env;
43use crate::error::Result;
44
45/// Type alias for 32-byte account identifiers.
46pub type AccountId = [u8; 32];
47
48/// Returns the account ID of the transaction sender.
49///
50/// This is the original caller who initiated the transaction, not necessarily
51/// the immediate caller in case of cross-contract calls.
52///
53/// # Returns
54///
55/// The 32-byte account ID of the caller.
56///
57/// # Example
58///
59/// ```ignore
60/// let caller = context::caller()?;
61/// if caller == owner {
62///     // Caller is the owner
63/// }
64/// ```
65pub fn caller() -> Result<AccountId> {
66    env::get_caller_32()
67}
68
69/// Returns the account ID of the contract owner.
70///
71/// The owner is set at deployment time and can be transferred via ownership
72/// transfer mechanisms. Typically used for access control.
73///
74/// # Returns
75///
76/// The 32-byte account ID of the contract owner.
77///
78/// # Example
79///
80/// ```ignore
81/// let owner = context::owner()?;
82/// let caller = context::caller()?;
83/// 
84/// if caller != owner {
85///     return Err(Error::new(ERR_NOT_OWNER));
86/// }
87/// ```
88pub fn owner() -> Result<AccountId> {
89    env::get_owner_32()
90}
91
92/// Returns this contract's account ID.
93///
94/// Useful for:
95/// - Self-referential operations
96/// - Checking if caller is this contract (for callbacks)
97/// - Logging contract address
98///
99/// # Returns
100///
101/// The 32-byte account ID of the current contract.
102///
103/// # Example
104///
105/// ```ignore
106/// let my_address = context::contract_id()?;
107/// log::emit_event(&ContractDeployed { address: my_address })?;
108/// ```
109pub fn contract_id() -> Result<AccountId> {
110    env::get_contract_id_32()
111}
112
113/// Returns the current block height.
114///
115/// Block height increments with each finalized batch (typically every 200ms).
116/// Useful for time-based logic, expiration checks, and replay protection.
117///
118/// # Returns
119///
120/// The current block height as a `u64`.
121///
122/// # Example
123///
124/// ```ignore
125/// let current_height = context::block_height()?;
126/// let expiration = storage.read_expiration()?;
127/// 
128/// if current_height > expiration {
129///     return Err(Error::new(ERR_EXPIRED));
130/// }
131/// ```
132pub fn block_height() -> Result<u64> {
133    env::get_height_u64()
134}
135
136/// Returns the current block timestamp (Unix seconds).
137///
138/// This is the timestamp of the current batch being executed.
139/// Useful for time-based logic, but note that it updates in ~200ms intervals.
140///
141/// # Returns
142///
143/// Unix timestamp in seconds as a `u64`.
144///
145/// # Example
146///
147/// ```ignore
148/// let now = context::block_timestamp()?;
149/// let deadline = storage.read_deadline()?;
150/// 
151/// if now > deadline {
152///     return Err(Error::new(ERR_DEADLINE_PASSED));
153/// }
154/// ```
155pub fn block_timestamp() -> Result<u64> {
156    env::get_timestamp_u64()
157}
158
159/// Returns the amount of native tokens sent with this call.
160///
161/// Only non-zero when called via `call_contract_with_value()`.
162/// The value is transferred before contract execution begins.
163///
164/// # Returns
165///
166/// The amount of native tokens (in base units) sent with the call.
167///
168/// # Example
169///
170/// ```ignore
171/// let value = context::call_value()?;
172/// 
173/// if value < MINIMUM_DEPOSIT {
174///     return Err(Error::new(ERR_INSUFFICIENT_VALUE));
175/// }
176/// 
177/// // Credit the caller's balance
178/// balances.insert(&caller, &value)?;
179/// ```
180pub fn call_value() -> Result<u128> {
181    env::get_value_u128()
182}
183
184/// Returns the raw calldata (function selector + arguments).
185///
186/// Calldata format:
187/// - Bytes 0-3: Function selector (4 bytes)
188/// - Bytes 4+: Encoded arguments
189///
190/// # Returns
191///
192/// A `Vec<u8>` containing the complete calldata.
193///
194/// # Example
195///
196/// ```ignore
197/// let calldata = context::calldata()?;
198/// let selector = abi::selector(&calldata)?;
199/// 
200/// if selector == abi::selector_of("transfer") {
201///     let to = abi::read_account(&calldata, 4)?;
202///     let amount = abi::read_u64(&calldata, 36)?;
203///     // Handle transfer...
204/// }
205/// ```
206pub fn calldata() -> Result<Vec<u8>> {
207    let mut bytes = vec![0u8; env::MAX_CALLDATA_SIZE];
208    let len = env::read_calldata(&mut bytes)?;
209    bytes.truncate(len);
210    Ok(bytes)
211}
212
213/// Sets the return data for this contract call.
214///
215/// The return data is sent back to the caller and can be decoded by the client.
216/// Typically used to return function results (balances, status codes, etc.).
217///
218/// # Arguments
219///
220/// * `data` - The bytes to return to the caller
221///
222/// # Example
223///
224/// ```ignore
225/// // Return a u64 balance
226/// let balance = 1000u64;
227/// context::set_return_data(&balance.to_le_bytes())?;
228///
229/// // Return multiple values (encode them first)
230/// let mut encoder = Encoder::new();
231/// encoder.push_u64(balance);
232/// encoder.push_bool(is_active);
233/// context::set_return_data(encoder.as_slice())?;
234/// ```
235pub fn set_return_data(data: &[u8]) -> Result<()> {
236    env::set_return_data_bytes(data)
237}