//! Getters for fields on transaction inputs.
//! This includes `Input::Coin`, `Input::Message`, and `Input::Contract`.
library;
use ::address::Address;
use ::alloc::alloc_bytes;
use ::assert::assert;
use ::asset_id::AssetId;
use ::bytes::Bytes;
use ::contract_id::ContractId;
use ::option::Option::{self, *};
use ::hash::{Hash, Hasher};
use ::tx::{
GTF_CREATE_INPUT_AT_INDEX,
GTF_CREATE_INPUTS_COUNT,
GTF_SCRIPT_INPUT_AT_INDEX,
GTF_SCRIPT_INPUTS_COUNT,
GTF_TYPE,
Transaction,
tx_type,
TX_TYPE_CREATE,
TX_TYPE_MINT,
};
use ::ops::*;
use ::revert::revert;
use ::primitive_conversions::u16::*;
use ::codec::*;
use ::debug::*;
use ::raw_slice::*;
// GTF Opcode const selectors
pub const GTF_INPUT_TYPE = 0x200;
// pub const GTF_INPUT_COIN_TX_ID = 0x201;
// pub const GTF_INPUT_COIN_OUTPUT_INDEX = 0x202;
pub const GTF_INPUT_COIN_OWNER = 0x203;
pub const GTF_INPUT_COIN_AMOUNT = 0x204;
pub const GTF_INPUT_COIN_ASSET_ID = 0x205;
pub const GTF_INPUT_COIN_WITNESS_INDEX = 0x207;
pub const GTF_INPUT_COIN_PREDICATE_LENGTH = 0x209;
pub const GTF_INPUT_COIN_PREDICATE_DATA_LENGTH = 0x20A;
pub const GTF_INPUT_COIN_PREDICATE = 0x20B;
pub const GTF_INPUT_COIN_PREDICATE_DATA = 0x20C;
// pub const GTF_INPUT_COIN_PREDICATE_GAS_USED = 0x20D;
// pub const GTF_INPUT_CONTRACT_CONTRACT_ID = 0x225;
pub const GTF_INPUT_MESSAGE_SENDER = 0x240;
pub const GTF_INPUT_MESSAGE_RECIPIENT = 0x241;
pub const GTF_INPUT_MESSAGE_AMOUNT = 0x242;
pub const GTF_INPUT_MESSAGE_NONCE = 0x243;
pub const GTF_INPUT_MESSAGE_WITNESS_INDEX = 0x244;
pub const GTF_INPUT_MESSAGE_DATA_LENGTH = 0x245;
pub const GTF_INPUT_MESSAGE_PREDICATE_LENGTH = 0x246;
pub const GTF_INPUT_MESSAGE_PREDICATE_DATA_LENGTH = 0x247;
pub const GTF_INPUT_MESSAGE_DATA = 0x248;
pub const GTF_INPUT_MESSAGE_PREDICATE = 0x249;
pub const GTF_INPUT_MESSAGE_PREDICATE_DATA = 0x24A;
// pub const GTF_INPUT_MESSAGE_PREDICATE_GAS_USED = 0x24B;
/// The input type for a transaction.
pub enum Input {
/// A coin input.
Coin: (),
/// A contract input.
Contract: (),
/// A message input.
Message: (),
}
impl PartialEq for Input {
fn eq(self, other: Self) -> bool {
match (self, other) {
(Input::Coin, Input::Coin) => true,
(Input::Contract, Input::Contract) => true,
(Input::Message, Input::Message) => true,
_ => false,
}
}
}
impl Eq for Input {}
impl Hash for Input {
fn is_hash_trivial() -> bool {
// TODO: (HASH-TRIVIAL-ENUMS) The enum tag is stored in memory as a `u64`,
// but hashed as a `u8`.
false
}
fn hash(self, ref mut state: Hasher) {
match self {
Self::Coin => {
0_u8.hash(state);
},
Self::Contract => {
1_u8.hash(state);
},
Self::Message => {
2_u8.hash(state);
},
}
}
}
const INPUT_TYPE_COIN: u8 = 0;
const INPUT_TYPE_CONTRACT: u8 = 1;
const INPUT_TYPE_MESSAGE: u8 = 2;
// Returns the `u8` type id of the input at `index` if such input exists,
// or a non-existing type id if the `index` is out of input bounds.
//
// This private function is used to avoid the overhead of creating and
// inspecting `Option`s for the input type.
fn input_type_id(index: u64) -> u8 {
if index < input_count().as_u64() {
__gtf::<u8>(index, GTF_INPUT_TYPE)
} else {
u8::max()
}
}
/// Gets the type of the input at `index`.
///
/// # Additional Information
///
/// The `Input` can be of three variants, `Input::Coin`, `Input::Contract`, or `Input::Message`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<Input>] - The type of the input at `index`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_type;
///
/// fn foo() {
/// let input_type = input_type(0).unwrap();
/// assert(input_type == Input::Coin);
/// }
/// ```
pub fn input_type(index: u64) -> Option<Input> {
match input_type_id(index) {
INPUT_TYPE_COIN => Some(Input::Coin),
INPUT_TYPE_CONTRACT => Some(Input::Contract),
INPUT_TYPE_MESSAGE => Some(Input::Message),
_ => None,
}
}
/// Gets the transaction inputs count.
///
/// # Returns
///
/// * [u16] - The number of inputs in the transaction.
///
/// # Reverts
///
/// * When the input type is unrecognized. This should never happen.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_count;
///
/// fn foo() {
/// let input_count = input_count();
/// assert(input_count == 1_u16);
/// }
/// ```
pub fn input_count() -> u16 {
match __gtf::<u8>(0, GTF_TYPE) {
TX_TYPE_CREATE => __gtf::<u16>(0, GTF_CREATE_INPUTS_COUNT),
TX_TYPE_MINT => revert(0),
_ => __gtf::<u16>(0, GTF_SCRIPT_INPUTS_COUNT),
}
}
/// Gets the pointer of the input at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<raw_ptr>] - The pointer of the input at `index`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_pointer;
///
/// fn foo() {
/// let input_pointer = input_pointer(0).unwrap();
/// }
/// ```
#[allow(dead_code)]
fn input_pointer(index: u64) -> Option<raw_ptr> {
if index >= input_count().as_u64() {
return None
}
match __gtf::<u8>(0, GTF_TYPE) {
TX_TYPE_CREATE => Some(__gtf::<raw_ptr>(index, GTF_CREATE_INPUT_AT_INDEX)),
TX_TYPE_MINT => None,
_ => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_INPUT_AT_INDEX)),
}
}
/// Gets the amount field from the input at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<u64>] - The amount of the input at `index`, if the input's type is `Input::Coin` or `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_amount;
///
/// fn foo() {
/// let input_amount = input_amount(0);
/// assert(input_amount.unwrap() == 100);
/// }
/// ```
pub fn input_amount(index: u64) -> Option<u64> {
match input_type_id(index) {
INPUT_TYPE_COIN => Some(__gtf::<u64>(index, GTF_INPUT_COIN_AMOUNT)),
INPUT_TYPE_MESSAGE => Some(__gtf::<u64>(index, GTF_INPUT_MESSAGE_AMOUNT)),
_ => None,
}
}
/// Gets the owner field from the input at `index` if it's a coin.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<Address>] - The owner of the input at `index`, if the input's type is `Input::Coin`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_coin_owner;
///
/// fn foo() {
/// let input_coin_owner = input_coin_owner(0);
/// assert(input_coin_owner.is_some()); // Ensure the input is a coin input.
/// }
/// ```
pub fn input_coin_owner(index: u64) -> Option<Address> {
match input_type_id(index) {
INPUT_TYPE_COIN => Some(Address::from(__gtf::<b256>(index, GTF_INPUT_COIN_OWNER))),
_ => None,
}
}
/// Gets the predicate data pointer from the input at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<raw_ptr>] - The predicate data pointer of the input at `index`, if the input's type is `Input::Coin` or `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_predicate_data_pointer;
///
/// fn foo() {
/// let input_predicate_data_pointer = input_predicate_data_pointer(0);
/// assert(input_predicate_data_pointer.is_some()); // Ensure the input is a coin or message input.
/// }
#[allow(dead_code)]
fn input_predicate_data_pointer(index: u64) -> Option<raw_ptr> {
match input_type_id(index) {
INPUT_TYPE_COIN => Some(__gtf::<raw_ptr>(index, GTF_INPUT_COIN_PREDICATE_DATA)),
INPUT_TYPE_MESSAGE => Some(__gtf::<raw_ptr>(index, GTF_INPUT_MESSAGE_PREDICATE_DATA)),
_ => None,
}
}
/// Gets the predicate data from the input at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<T>] - The predicate data of the input at `index`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_predicate_data;
///
/// fn foo() {
/// let input_predicate_data: u64 = input_predicate_data::<u64>(0).unwrap();
/// assert(input_predicate_data == 100);
/// }
/// ```
pub fn input_predicate_data<T>(index: u64) -> Option<T>
where
T: AbiDecode,
{
match input_type_id(index) {
INPUT_TYPE_COIN | INPUT_TYPE_MESSAGE => Some(decode_predicate_data_by_index::<T>(index)),
_ => None,
}
}
/// Gets the asset id of the input at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<AssetId>] - The asset id of the input at `index`, if the input's type is `Input::Coin` or `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_asset_id;
///
/// fn foo() {
/// let input_asset_id = input_asset_id(0);
/// assert(input_asset_id.unwrap() == AssetId::base());
/// }
/// ```
pub fn input_asset_id(index: u64) -> Option<AssetId> {
match input_type_id(index) {
INPUT_TYPE_COIN => Some(AssetId::from(__gtf::<b256>(index, GTF_INPUT_COIN_ASSET_ID))),
INPUT_TYPE_MESSAGE => Some(AssetId::base()),
_ => None,
}
}
/// Gets the witness index from the input at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<u16>] - The witness index of the input at `index`, if the input's type is `Input::Coin` or `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_witness_index;
///
/// fn foo() {
/// let input_witness_index = input_witness_index(0);
/// assert(input_witness_index.is_some()); // Ensure the input has a witness index.
/// }
/// ```
pub fn input_witness_index(index: u64) -> Option<u16> {
match input_type_id(index) {
INPUT_TYPE_COIN => Some(__gtf::<u16>(index, GTF_INPUT_COIN_WITNESS_INDEX)),
INPUT_TYPE_MESSAGE => Some(__gtf::<u16>(index, GTF_INPUT_MESSAGE_WITNESS_INDEX)),
_ => None,
}
}
/// Gets the predicate length from the input at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<u64>] - The predicate length of the input at `index`, if the input's type is `Input::Coin` or `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_predicate_length;
///
/// fn foo() {
/// let input_predicate_length = input_predicate_length(0);
/// assert(input_predicate_length.unwrap() != 0u64);
/// }
/// ```
pub fn input_predicate_length(index: u64) -> Option<u64> {
match input_type_id(index) {
INPUT_TYPE_COIN => Some(__gtf::<u64>(index, GTF_INPUT_COIN_PREDICATE_LENGTH)),
INPUT_TYPE_MESSAGE => Some(__gtf::<u64>(index, GTF_INPUT_MESSAGE_PREDICATE_LENGTH)),
_ => None,
}
}
/// Gets the predicate pointer from the input at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<raw_ptr>] - The predicate pointer of the input at `index`, if the input's type is `Input::Coin` or `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_predicate_pointer;
///
/// fn foo() {
/// let input_predicate_pointer = input_predicate_pointer(0);
/// assert(input_predicate_pointer.is_some());
/// }
/// ```
pub fn input_predicate_pointer(index: u64) -> Option<raw_ptr> {
match input_type_id(index) {
INPUT_TYPE_COIN => Some(__gtf::<raw_ptr>(index, GTF_INPUT_COIN_PREDICATE)),
INPUT_TYPE_MESSAGE => Some(__gtf::<raw_ptr>(index, GTF_INPUT_MESSAGE_PREDICATE)),
_ => None,
}
}
/// Gets the predicate bytecode from the input at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<Bytes>] - The predicate bytecode of the input at `index`, if the input's type is `Input::Coin` or `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_predicate;
///
/// fn foo() {
/// let input_predicate = input_predicate(0).unwrap();
/// assert(input_predicate.len() != 0);
/// }
/// ```
pub fn input_predicate(index: u64) -> Option<Bytes> {
let (length, ptr) = match input_type_id(index) {
INPUT_TYPE_COIN => (
__gtf::<u64>(index, GTF_INPUT_COIN_PREDICATE_LENGTH),
__gtf::<raw_ptr>(index, GTF_INPUT_COIN_PREDICATE),
),
INPUT_TYPE_MESSAGE => (
__gtf::<u64>(index, GTF_INPUT_MESSAGE_PREDICATE_LENGTH),
__gtf::<raw_ptr>(index, GTF_INPUT_MESSAGE_PREDICATE),
),
_ => return None,
};
let new_ptr = alloc_bytes(length);
ptr.copy_bytes_to(new_ptr, length);
Some(Bytes::from(raw_slice::from_parts::<u8>(new_ptr, length)))
}
/// Gets the predicate data length from the input at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<u64>] - The predicate data length of the input at `index`, if the input's type is `Input::Coin` or `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_predicate_data_length;
///
/// fn foo() {
/// let input_predicate_data_length = input_predicate_data_length(0);
/// assert(input_predicate_data_length.unwrap() != 0_u64);
/// }
/// ```
pub fn input_predicate_data_length(index: u64) -> Option<u64> {
match input_type_id(index) {
INPUT_TYPE_COIN => Some(__gtf::<u64>(index, GTF_INPUT_COIN_PREDICATE_DATA_LENGTH)),
INPUT_TYPE_MESSAGE => Some(__gtf::<u64>(index, GTF_INPUT_MESSAGE_PREDICATE_DATA_LENGTH)),
_ => None,
}
}
/// Gets the sender of the input message at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<Address>] - The sender of the input message at `index`, if the input's type is `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_message_sender;
///
/// fn foo() {
/// let input_message_sender = input_message_sender(0).unwrap();
/// assert(input_message_sender != Address::zero());
/// }
/// ```
pub fn input_message_sender(index: u64) -> Option<Address> {
match input_type_id(index) {
INPUT_TYPE_MESSAGE => Some(Address::from(__gtf::<b256>(index, GTF_INPUT_MESSAGE_SENDER))),
_ => None,
}
}
/// Gets the recipient of the input message at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<Address>] - The recipient of the input message at `index`, if the input's type is `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_message_recipient;
///
/// fn foo() {
/// let input_message_recipient = input_message_recipient(0).unwrap();
/// assert(input_message_recipient != Address::zero());
/// }
/// ```
pub fn input_message_recipient(index: u64) -> Option<Address> {
match input_type_id(index) {
INPUT_TYPE_MESSAGE => Some(Address::from(__gtf::<b256>(index, GTF_INPUT_MESSAGE_RECIPIENT))),
_ => None,
}
}
/// Gets the nonce of the input message at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [b256] - The nonce of the input message at `index`, if the input's type is `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_message_nonce;
///
/// fn foo() {
/// let input_message_nonce = input_message_nonce(0);
/// assert(input_message_nonce != b256::zero());
/// }
/// ```
pub fn input_message_nonce(index: u64) -> Option<b256> {
match input_type_id(index) {
INPUT_TYPE_MESSAGE => Some(__gtf::<b256>(index, GTF_INPUT_MESSAGE_NONCE)),
_ => None,
}
}
/// Gets the length of the input message at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<u64>] - The length of the input message at `index`, if the input's type is `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_message_length;
///
/// fn foo() {
/// let input_message_length = input_message_length(0).unwrap();
/// assert(input_message_length != 0_u64);
/// }
/// ```
pub fn input_message_data_length(index: u64) -> Option<u64> {
match input_type_id(index) {
INPUT_TYPE_MESSAGE => Some(__gtf::<u64>(index, GTF_INPUT_MESSAGE_DATA_LENGTH)),
_ => None,
}
}
/// Gets the data of the input message at `index`.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
/// * `offset`: [u64] - The offset to start reading the data from.
///
/// # Returns
///
/// * [Option<Bytes>] - The data of the input message at `index`, if the input's type is `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_message_data;
///
/// fn foo() {
/// let input_message_data = input_message_data(0, 0).unwrap();
/// assert(input_message_data.len() != 0);
/// }
/// ```
pub fn input_message_data(index: u64, offset: u64) -> Option<Bytes> {
match input_type_id(index) {
INPUT_TYPE_MESSAGE => {
let total_length = __gtf::<u64>(index, GTF_INPUT_MESSAGE_DATA_LENGTH);
if offset > total_length {
None
} else {
let offset_length = total_length - offset;
let new_ptr = alloc_bytes(offset_length);
let data = __gtf::<raw_ptr>(index, GTF_INPUT_MESSAGE_DATA);
let data_with_offset = data.add_uint_offset(offset);
data_with_offset.copy_bytes_to(new_ptr, offset_length);
Some(Bytes::from(raw_slice::from_parts::<u8>(new_ptr, offset_length)))
}
},
_ => None,
}
}
/// Gets the owner field from the input at `index`, if it's a coin,
/// or the recipient of the input message, if it is a message.
///
/// # Arguments
///
/// * `index`: [u64] - The index of the input to check.
///
/// # Returns
///
/// * [Option<Address>] - The owner of the input at `index`, if the input's type is `Input::Coin`, or the recipient of the input message, if the input's type is `Input::Message`, else `None`.
///
/// # Examples
///
/// ```sway
/// use std::inputs::input_address;
///
/// fn foo() {
/// let input_address = input_address(0).unwrap();
/// assert(input_address != Address::zero());
/// }
/// ```
pub fn input_address(index: u64) -> Option<Address> {
match input_type_id(index) {
INPUT_TYPE_COIN => Some(Address::from(__gtf::<b256>(index, GTF_INPUT_COIN_OWNER))),
INPUT_TYPE_MESSAGE => Some(Address::from(__gtf::<b256>(index, GTF_INPUT_MESSAGE_RECIPIENT))),
_ => None,
}
}