/
githubmirror
/
sway
Обзор
Документация
Войти
/
githubmirror
/
sway
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
sway-lib-std/src/auth.sw
255 строк
7 KB
Daniel Frederico Lins Leite
Better `Debug` tests and impls for primitives and std lib types (#7119)
02 май 2025, 12:40
Не верифицирован
02 май 2025, 12:40
324f04f
Код
Авторство
О чём код?
//! Functionality for determining who is calling a contract. library; use ::address::Address; use ::contract_id::ContractId; use ::identity::Identity; use ::option::Option::{self, *}; use ::result::Result::{self, *}; use ::inputs::{ Input, input_address, input_coin_owner, input_count, input_message_recipient, input_message_sender, input_type, }; use ::revert::revert; use ::vec::Vec; use ::codec::*; use ::debug::*; /// The error type used when an `Identity` cannot be determined. pub enum AuthError { /// The caller is external, but the inputs to the transaction are not all owned by the same address. InputsNotAllOwnedBySameAddress: (), /// The caller is internal, but the `caller_address` function was called. CallerIsInternal: (), } /// Returns `true` if the caller is external (i.e. a `script`). /// Otherwise, if the caller is a contract, returns `false`. /// /// # Additional Information /// /// For more information refer to the [VM Instruction Set](https://fuellabs.github.io/fuel-specs/master/vm/instruction_set#gm-get-metadata). /// /// # Returns /// /// * [bool] - `true` if the caller is external, `false` otherwise. /// /// # Examples /// /// ```sway /// use std::auth::caller_is_external; /// /// fn foo() { /// if caller_is_external() { /// log("Caller is external.") /// } else { /// log("Caller is a contract.") /// } /// } /// ``` pub fn caller_is_external() -> bool { asm(r1) { gm r1 i1; r1: bool } } /// If the caller is internal, returns the contract ID of the caller. /// /// # Additional Information /// /// External calls result in undefined behavior. /// /// # Returns /// /// * [ContractId] - The contract ID of the caller. /// /// # Examples /// /// ```sway /// use std::auth::{caller_is_external, caller_contract_id}; /// /// fn foo() { /// if !caller_is_external() { /// let caller_contract_id = caller_contract_id(); /// log(caller_contract_id); /// } /// } /// ``` pub fn caller_contract_id() -> ContractId { ContractId::from(asm(r1) { gm r1 i2; r1: b256 }) } /// Get the `Identity` (i.e. `Address` or `ContractId`) from which a call was made. /// Returns a `Ok(Identity)`, or `Err(AuthError)` if an identity cannot be determined. /// /// # Additional Information /// /// Returns an `AuthError::InputsNotAllOwnedBySameAddress` if the caller is external and the inputs to the transaction are not all owned by the same address. /// Should not return an `AuthError::CallerIsInternal` under any circumstances. /// /// # Returns /// /// * [Result<Identity, AuthError>] - `Ok(Identity)` if the identity can be determined, `Err(AuthError)` otherwise. /// /// # Examples /// /// ```sway /// fn foo() { /// match msg_sender() { /// Ok(Identity::Address(address)) => log(address), /// Ok(Identity::ContractId(contract_id)) => log(contract_id), /// Err(AuthError::InputsNotAllOwnedBySameAddress) => log("Inputs not all owned by same address."), /// Err(AuthError::CallerIsInternal) => log("Hell froze over."), /// } /// } /// ``` pub fn msg_sender() -> Result<Identity, AuthError> { if caller_is_external() { match caller_address() { Err(err) => Err(err), Ok(owner) => Ok(Identity::Address(owner)), } } else { // Get caller's `ContractId`. Ok(Identity::ContractId(caller_contract_id())) } } /// Get the owner of the inputs (of type `Input::Coin` or `Input::Message`) to a /// `TransactionScript` if they all share the same owner. /// /// # Returns /// /// * [Result<Address, AuthError>] - `Ok(Address)` if the single owner can be determined, `Err(AuthError)` otherwise. /// /// # Examples /// /// ```sway /// use std::auth::caller_address; /// /// fn foo() { /// match caller_address() { /// Ok(address) => log(address), /// Err(AuthError::InputsNotAllOwnedBySameAddress) => log("Inputs not all owned by the same address."), /// Err(AuthError::CallerIsInternal) => log("Hell froze over."), /// } /// } /// ``` pub fn caller_address() -> Result<Address, AuthError> { let input_count = input_count().as_u64(); let mut first_input_owner = None; let mut iter = 0; while iter < input_count { let input_owner = match input_address(iter) { Some(address) => address, None => { // Input is not `Input::Coin` or `Input::Message`, continue looping. iter += 1; continue; } }; // This is the first input seen that is either a coin or a message. if first_input_owner.is_none() { first_input_owner = Some(input_owner); iter += 1; continue; } // Compare the current input owner to the first one. // `first_input_owner` must be `Some` at this point, // so we can safely unwrap. if input_owner == first_input_owner.unwrap() { // Owner is the same, continue looping. iter += 1; continue; } // Owners are not the same, return error. return Err(AuthError::InputsNotAllOwnedBySameAddress); } // `first_input_owner` must be `Some` if the caller is an address, otherwise it's a contract. match first_input_owner { Some(address) => Ok(address), None => Err(AuthError::CallerIsInternal), } } /// Get the owners of the inputs (of type `Input::Coin` or `Input::Message`) to a /// `TransactionScript`. /// /// # Additional Information /// /// The returned `Vec` is not deduplicated, so it may contain repeated addresses. /// /// # Returns /// /// * [Vec<Address>] - The addresses of the owners of the inputs. /// /// # Examples /// /// ```sway /// use std::auth::caller_addresses; /// /// fn foo(some_address: Address) { /// let addresses = caller_addresses(); /// /// assert(addresses.get(0).unwrap() == some_address); /// } /// ``` pub fn caller_addresses() -> Vec<Address> { let input_count = input_count().as_u64(); let mut addresses = Vec::new(); let mut iter = 0; while iter < input_count { match input_address(iter) { Some(address) => { addresses.push(address); }, _ => {} } iter += 1; } addresses } /// Get the current predicate's address when called in an internal context. /// /// # Returns /// /// * [Option<Address>] - The address of this predicate. /// /// # Examples /// /// ```sway /// use std::auth::predicate_address; /// /// fn main() { /// let this_predicate = predicate_address().unwrap(); /// log(this_predicate); /// } /// ``` pub fn predicate_address() -> Option<Address> { // Get the index of the current predicate: // i3 == GM_GET_VERIFYING_PREDICATE let predicate_index = asm(r1) { gm r1 i3; r1: u64 }; input_address(predicate_index) }