//! Helper functions for accessing data from call frames.
//! [Call frames](https://fuellabs.github.io/fuel-specs/master/vm#call-frames) store metadata across untrusted inter-contract calls.
library;
use ::asset_id::AssetId;
use ::contract_id::ContractId;
use ::intrinsics::is_reference_type;
use ::registers::frame_ptr;
use ::raw_ptr::*;
use ::codec::*;
use ::debug::*;
// Note that everything when serialized is padded to word length.
//
// Call Frame : saved registers offset = 8
// Reserved Registers: previous frame pointer offset = 6
const SAVED_REGISTERS_OFFSET: u64 = 8;
const PREV_FRAME_POINTER_OFFSET: u64 = 6;
/// Where 73 is the current offset in words from the start of the call frame.
const FIRST_PARAMETER_OFFSET: u64 = 73;
/// Where 74 (73 + 1) is the current offset in words from the start of the call frame.
const SECOND_PARAMETER_OFFSET: u64 = 74;
/// Get the `asset_id` of coins being sent from the current call frame.
///
/// # Returns
///
/// * [AssetId] - The asset included in the current call frame.
///
/// # Examples
///
/// ```sway
/// use std::call_frames::msg_asset_id;
///
/// fn foo() {
/// let asset = msg_asset_id();
/// assert(asset == AssetId::base());
/// }
/// ```
pub fn msg_asset_id() -> AssetId {
AssetId::from(asm(asset_id) {
addi asset_id fp i32;
asset_id: b256
})
}
/// Get the code size in bytes (padded to word alignment) from the current call frame.
///
/// # Additional Information
///
/// More information on data from call frames can be found in the Fuel Specs.
/// https://docs.fuel.network/docs/specs/fuel-vm/#call-frames
///
/// # Returns
///
/// * [u64] - The code size of the current call frame.
///
/// # Examples
///
/// ```sway
/// use std::call_frames::code_size;
///
/// fn foo() {
/// let size = code_size();
/// assert(size != 0);
/// }
/// ```
pub fn code_size() -> u64 {
let ptr = asm(size, ptr, offset: 576) {
add size fp offset;
size: raw_ptr
};
ptr.read::<u64>()
}
/// Get the first parameter from the current call frame.
///
/// # Additional Information
///
/// More information on data from call frames can be found in the Fuel Specs.
/// https://docs.fuel.network/docs/specs/fuel-vm/#call-frames
///
/// # Returns
///
/// * [u64] - The first parameter of the current call frame.
///
/// # Examples
///
/// ```sway
/// use std::call_frames::first_param;
///
/// fn foo() {
/// let param = first_param();
/// assert(param != 0);
/// }
/// ```
pub fn first_param() -> u64 {
frame_ptr().add::<u64>(FIRST_PARAMETER_OFFSET).read()
}
/// Get the second parameter from the current call frame.
///
/// # Additional Information
///
/// More information on data from call frames can be found in the Fuel Specs.
/// https://docs.fuel.network/docs/specs/fuel-vm/#call-frames
///
/// # Returns
///
/// * [u64] - The second parameter of the current call frame.
///
/// # Examples
///
/// ```sway
/// use std::call_frames::second_param;
///
/// fn foo() {
/// let param: u64 = second_param();
/// assert(param != 0);
/// }
/// ```
pub fn second_param() -> u64 {
frame_ptr().add::<u64>(SECOND_PARAMETER_OFFSET).read()
}
/// Get the called method name from the current call frame.
pub fn called_method() -> str {
use ::codec::decode_first_param;
decode_first_param::<str>()
}
/// Get the called arguments from the current call frame.
pub fn called_args<T>() -> T
where
T: AbiDecode,
{
use ::codec::decode_second_param;
decode_second_param::<T>()
}
// Accessing arbitrary call frames by pointer
//
/// Get a pointer to the previous (relative to the `frame_pointer` parameter) call frame using offsets from a pointer.
///
/// # Additional Information
///
/// More information on data from call frames can be found in the Fuel Specs.
/// https://docs.fuel.network/docs/specs/fuel-vm/#call-frames
///
/// # Arguments
///
/// * `frame_pointer`: [raw_ptr] - The call frame reference directly before the returned call frame pointer.
///
/// # Returns
///
/// * [raw_ptr] - The memory location of the previous call frame data.
///
/// # Examples
///
/// ```sway
/// use std::{call_frames::get_previous_frame_pointer, registers::frame_ptr};
///
/// fn foo() {
/// let current_call_frame = frame_ptr();
/// let previous_call_frame = get_previous_frame_pointer(current_call_frame);
/// assert(!previous_call_frame.is_null());
/// }
/// ```
pub fn get_previous_frame_pointer(frame_pointer: raw_ptr) -> raw_ptr {
let offset = frame_pointer.add::<u64>(SAVED_REGISTERS_OFFSET + PREV_FRAME_POINTER_OFFSET);
asm(res, ptr: offset) {
lw res ptr i0;
res: raw_ptr
}
}
/// Get the value of `ContractId` from any call frame on the stack.
///
/// # Arguments
///
/// * `frame_pointer`: [raw_ptr] - The call frame for which the Contract Id is to be returned.
///
/// # Returns
///
/// * [ContractId] - The Contract Id of for the call frame.
///
/// # Examples
///
/// ```sway
/// use std::{call_frames::get_contract_id_from_call_frame, registers::frame_ptr};
///
/// fn foo() {
/// let current_call_frame = frame_ptr();
/// let contract_id = get_contract_id_from_call_frame(current_call_frame);
/// }
/// ```
pub fn get_contract_id_from_call_frame(frame_pointer: raw_ptr) -> ContractId {
ContractId::from(asm(res, ptr: frame_pointer) {
ptr: b256
})
}