|
| 1 | +//! Standard `require_auth` composition helpers (issue #243). |
| 2 | +//! |
| 3 | +//! Every state-changing entry-point in the Quantara protocol must require the |
| 4 | +//! caller to authenticate against the operation before mutating any storage. |
| 5 | +//! Forgetting a single `require_auth()` call is a critical vulnerability. |
| 6 | +//! |
| 7 | +//! This module provides two ergonomic helpers: |
| 8 | +//! |
| 9 | +//! * [`assert_caller_auth`] — the primary guard. Call it at the top of every |
| 10 | +//! state-mutating entry-point. It combines `Address::require_auth_for_args` |
| 11 | +//! with a compile-time-checked operation tag so reviewers can see exactly |
| 12 | +//! what each call is authorising. |
| 13 | +//! |
| 14 | +//! * [`for_each_auth`] — iterate a list of `(Address, Vec<Val>)` pairs and |
| 15 | +//! call `require_auth_for_args` on each one in a single expression. Useful |
| 16 | +//! when an entry-point must authenticate multiple principals (e.g. a |
| 17 | +//! relayer and a user simultaneously). |
| 18 | +//! |
| 19 | +//! # Usage |
| 20 | +//! |
| 21 | +//! ```ignore |
| 22 | +//! use common::auth::{assert_caller_auth, for_each_auth}; |
| 23 | +//! use soroban_sdk::{symbol_short, vec, Address, Env}; |
| 24 | +//! |
| 25 | +//! pub fn deposit(env: Env, user: Address, amount: i128) { |
| 26 | +//! assert_caller_auth(&env, &user, symbol_short!("deposit"), &(amount,)); |
| 27 | +//! // ... state mutations ... |
| 28 | +//! } |
| 29 | +//! ``` |
| 30 | +
|
| 31 | +#![allow(dead_code)] |
| 32 | + |
| 33 | +use soroban_sdk::{Address, Env, IntoVal, Symbol, Val, Vec}; |
| 34 | + |
| 35 | +// --------------------------------------------------------------------------- |
| 36 | +// Primary guard |
| 37 | +// --------------------------------------------------------------------------- |
| 38 | + |
| 39 | +/// Require that `caller` has authorised `operation` with the provided |
| 40 | +/// `args` before any storage mutation occurs. |
| 41 | +/// |
| 42 | +/// # Arguments |
| 43 | +/// |
| 44 | +/// * `env` – The Soroban environment. |
| 45 | +/// * `caller` – The principal that must authorise this operation. |
| 46 | +/// * `operation` – A short `Symbol` naming the entry-point (used as the |
| 47 | +/// sub-contract-call function name in the auth context). |
| 48 | +/// * `args` – A tuple (or any `IntoVal<Env, Vec<Val>>`) of the |
| 49 | +/// arguments being authorised. Pass `&()` when there are no arguments. |
| 50 | +/// |
| 51 | +/// # Panics |
| 52 | +/// |
| 53 | +/// Panics (via the Soroban host's auth machinery) if `caller` has not |
| 54 | +/// provided a valid signature for `operation(args…)`. |
| 55 | +/// |
| 56 | +/// # Example |
| 57 | +/// |
| 58 | +/// ```ignore |
| 59 | +/// assert_caller_auth(&env, &user, symbol_short!("withdraw"), &(amount,)); |
| 60 | +/// ``` |
| 61 | +pub fn assert_caller_auth<T>(env: &Env, caller: &Address, operation: Symbol, args: &T) |
| 62 | +where |
| 63 | + T: IntoVal<Env, Vec<Val>>, |
| 64 | +{ |
| 65 | + caller.require_auth_for_args(args.into_val(env)); |
| 66 | + // The `operation` symbol is intentionally unused at runtime — it exists |
| 67 | + // solely to make call-sites self-documenting and to enable static grep |
| 68 | + // audits. |
| 69 | + let _ = operation; |
| 70 | +} |
| 71 | + |
| 72 | +// --------------------------------------------------------------------------- |
| 73 | +// Multi-principal helper |
| 74 | +// --------------------------------------------------------------------------- |
| 75 | + |
| 76 | +/// Require auth from every `(Address, args)` pair in `principals`. |
| 77 | +/// |
| 78 | +/// Use this when a single transaction must be authorised by multiple parties |
| 79 | +/// (e.g., a relayer address *and* the end-user address). |
| 80 | +/// |
| 81 | +/// # Arguments |
| 82 | +/// |
| 83 | +/// * `env` – The Soroban environment. |
| 84 | +/// * `principals` – Slice of `(Address, Vec<Val>)` tuples. |
| 85 | +pub fn for_each_auth(env: &Env, principals: &[(Address, Vec<Val>)]) { |
| 86 | + for (addr, args) in principals { |
| 87 | + addr.require_auth_for_args(args.clone()); |
| 88 | + } |
| 89 | + let _ = env; |
| 90 | +} |
0 commit comments