stylus_core/calls/
mod.rs

1// Copyright 2025-2026, Offchain Labs, Inc.
2// For licensing, see https://github.com/OffchainLabs/stylus-sdk-rs/blob/main/licenses/COPYRIGHT.md
3
4use alloy_primitives::U256;
5
6use crate::TopLevelStorage;
7
8pub mod errors;
9
10/// Trait for calling other contracts.
11/// Users should rarely implement this trait outside of proc macros.
12pub trait CallContext {
13    /// Amount of gas to supply the call.
14    /// Note: values are clipped to the amount of gas remaining.
15    fn gas(&self) -> u64;
16}
17
18/// Trait for calling the `view` or `pure` methods of other contracts.
19/// Users should rarely implement this trait outside of proc macros.
20pub trait StaticCallContext: CallContext {}
21
22/// Trait for calling the mutable methods of other contracts.
23/// Users should rarely implement this trait outside of proc macros.
24///
25/// # Safety
26///
27/// The type initializer must be a [`TopLevelStorage`][TLS] to prevent aliasing in cases of reentrancy.
28///
29/// [TLS]: stylus_core::storage::TopLevelStorage
30pub unsafe trait MutatingCallContext: CallContext {
31    /// Amount of ETH in wei to give the other contract.
32    fn value(&self) -> U256;
33}
34
35/// Trait for calling the `write` methods of other contracts.
36/// Users should rarely implement this trait outside of proc macros.
37///
38/// Note: any implementations of this must return zero for [`MutatingCallContext::value`].
39pub trait NonPayableCallContext: MutatingCallContext {}
40
41/// Enables configurable calls to other contracts.
42#[derive(Debug, Clone)]
43pub struct Call<const MUTATING: bool = false, const HAS_VALUE: bool = false> {
44    gas: u64,
45    value: Option<U256>,
46}
47
48impl<const MUTATING: bool, const HAS_VALUE: bool> Call<MUTATING, HAS_VALUE> {
49    /// Amount of gas to supply the call.
50    /// Values greater than the amount provided will be clipped to all gas left.
51    pub fn gas(self, gas: u64) -> Self {
52        Self { gas, ..self }
53    }
54
55    /// Amount of ETH in wei to give the other contract.
56    /// Note: adding value will prevent calls to non-payable methods.
57    pub fn value(self, value: U256) -> Call<true, true> {
58        Call {
59            value: Some(value),
60            gas: self.gas,
61        }
62    }
63}
64
65impl<const MUTATING: bool, const HAS_VALUE: bool> CallContext for Call<MUTATING, HAS_VALUE> {
66    fn gas(&self) -> u64 {
67        self.gas
68    }
69}
70
71impl StaticCallContext for Call<false, false> {}
72
73impl NonPayableCallContext for Call<true, false> {}
74
75unsafe impl<const HAS_VALUE: bool> MutatingCallContext for Call<true, HAS_VALUE> {
76    fn value(&self) -> U256 {
77        self.value.unwrap_or_default()
78    }
79}
80
81impl Default for Call<false, false> {
82    fn default() -> Self {
83        Self::new()
84    }
85}
86
87impl Call<false, false> {
88    pub fn new() -> Self {
89        Self {
90            gas: u64::MAX,
91            value: None,
92        }
93    }
94}
95
96impl Call<true, false> {
97    pub fn new_mutating(_storage: &mut impl TopLevelStorage) -> Self {
98        Self {
99            gas: u64::MAX,
100            value: None,
101        }
102    }
103}
104
105impl Call<true, true> {
106    pub fn new_payable(_storage: &mut impl TopLevelStorage, value: U256) -> Self {
107        Self {
108            gas: u64::MAX,
109            value: Some(value),
110        }
111    }
112}