defuse_core/intents/
mod.rs

1pub mod account;
2pub mod auth;
3pub mod token_diff;
4pub mod tokens;
5
6#[cfg(feature = "imt")]
7pub mod imt;
8
9use defuse_serde_utils::base58::Base58;
10use derive_more::derive::From;
11use near_sdk::{AccountIdRef, CryptoHash, near};
12use serde_with::serde_as;
13use tokens::{NativeWithdraw, StorageDeposit};
14
15#[cfg(feature = "imt")]
16use crate::intents::imt::{ImtBurn, ImtMint};
17
18use crate::{
19    Result,
20    engine::{Engine, Inspector, State},
21    intents::{account::SetAuthByPredecessorId, auth::AuthCall},
22};
23
24use self::{
25    account::{AddPublicKey, RemovePublicKey},
26    token_diff::TokenDiff,
27    tokens::{FtWithdraw, MtWithdraw, NftWithdraw, Transfer},
28};
29
30#[near(serializers = [json])]
31#[derive(Debug, Clone)]
32pub struct DefuseIntents {
33    /// Sequence of intents to execute in given order. Empty list is also
34    /// a valid sequence, i.e. it doesn't do anything, but still invalidates
35    /// the `nonce` for the signer
36    /// WARNING: Promises created by different intents are executed concurrently and does not rely on the order of the intents in this structure
37    #[serde(default, skip_serializing_if = "Vec::is_empty")]
38    pub intents: Vec<Intent>,
39}
40
41#[near(serializers = [json])]
42#[serde(tag = "intent", rename_all = "snake_case")]
43#[derive(Debug, Clone, From)]
44pub enum Intent {
45    /// See [`AddPublicKey`]
46    AddPublicKey(AddPublicKey),
47
48    /// See [`RemovePublicKey`]
49    RemovePublicKey(RemovePublicKey),
50
51    /// See [`Transfer`]
52    Transfer(Transfer),
53
54    /// See [`FtWithdraw`]
55    FtWithdraw(FtWithdraw),
56
57    /// See [`NftWithdraw`]
58    NftWithdraw(NftWithdraw),
59
60    /// See [`MtWithdraw`]
61    MtWithdraw(MtWithdraw),
62
63    /// See [`NativeWithdraw`]
64    NativeWithdraw(NativeWithdraw),
65
66    /// See [`StorageDeposit`]
67    StorageDeposit(StorageDeposit),
68
69    /// See [`TokenDiff`]
70    TokenDiff(TokenDiff),
71
72    /// See [`SetAuthByPredecessorId`]
73    SetAuthByPredecessorId(SetAuthByPredecessorId),
74
75    /// See [`AuthCall`]
76    AuthCall(AuthCall),
77
78    // See [`ImtMint`]
79    #[cfg(feature = "imt")]
80    ImtMint(ImtMint),
81
82    // See [`ImtBurn`]
83    #[cfg(feature = "imt")]
84    ImtBurn(ImtBurn),
85}
86
87pub trait ExecutableIntent {
88    fn execute_intent<S, I>(
89        self,
90        signer_id: &AccountIdRef,
91        engine: &mut Engine<S, I>,
92        intent_hash: CryptoHash,
93    ) -> Result<()>
94    where
95        S: State,
96        I: Inspector;
97}
98
99impl ExecutableIntent for DefuseIntents {
100    fn execute_intent<S, I>(
101        self,
102        signer_id: &AccountIdRef,
103        engine: &mut Engine<S, I>,
104        intent_hash: CryptoHash,
105    ) -> Result<()>
106    where
107        S: State,
108        I: Inspector,
109    {
110        for intent in self.intents {
111            intent.execute_intent(signer_id, engine, intent_hash)?;
112        }
113        Ok(())
114    }
115}
116
117impl ExecutableIntent for Intent {
118    fn execute_intent<S, I>(
119        self,
120        signer_id: &AccountIdRef,
121        engine: &mut Engine<S, I>,
122        intent_hash: CryptoHash,
123    ) -> Result<()>
124    where
125        S: State,
126        I: Inspector,
127    {
128        match self {
129            Self::AddPublicKey(intent) => intent.execute_intent(signer_id, engine, intent_hash),
130            Self::RemovePublicKey(intent) => intent.execute_intent(signer_id, engine, intent_hash),
131            Self::Transfer(intent) => intent.execute_intent(signer_id, engine, intent_hash),
132            Self::FtWithdraw(intent) => intent.execute_intent(signer_id, engine, intent_hash),
133            Self::NftWithdraw(intent) => intent.execute_intent(signer_id, engine, intent_hash),
134            Self::MtWithdraw(intent) => intent.execute_intent(signer_id, engine, intent_hash),
135            Self::NativeWithdraw(intent) => intent.execute_intent(signer_id, engine, intent_hash),
136            Self::StorageDeposit(intent) => intent.execute_intent(signer_id, engine, intent_hash),
137            Self::TokenDiff(intent) => intent.execute_intent(signer_id, engine, intent_hash),
138            Self::SetAuthByPredecessorId(intent) => {
139                intent.execute_intent(signer_id, engine, intent_hash)
140            }
141            Self::AuthCall(intent) => intent.execute_intent(signer_id, engine, intent_hash),
142            #[cfg(feature = "imt")]
143            Self::ImtMint(intent) => intent.execute_intent(signer_id, engine, intent_hash),
144            #[cfg(feature = "imt")]
145            Self::ImtBurn(intent) => intent.execute_intent(signer_id, engine, intent_hash),
146        }
147    }
148}
149
150/// Event that can be emitted either from a
151/// function call or after intent execution
152#[must_use = "make sure to `.emit()` this event"]
153#[near(serializers = [json])]
154#[derive(Debug, Clone)]
155pub struct MaybeIntentEvent<T> {
156    #[serde_as(as = "Option<Base58>")]
157    #[serde(default, skip_serializing_if = "Option::is_none")]
158    pub intent_hash: Option<CryptoHash>,
159
160    #[serde(flatten)]
161    pub event: T,
162}
163
164impl<T> MaybeIntentEvent<T> {
165    #[inline]
166    pub const fn new_fn_call(event: T) -> Self {
167        Self {
168            intent_hash: None,
169            event,
170        }
171    }
172
173    #[inline]
174    pub const fn new_intent(event: T, intent_hash: CryptoHash) -> Self {
175        Self {
176            intent_hash: Some(intent_hash),
177            event,
178        }
179    }
180}
181
182impl<T> From<T> for MaybeIntentEvent<T> {
183    fn from(event: T) -> Self {
184        Self::new_fn_call(event)
185    }
186}
187
188// fix JsonSchema macro bug
189#[cfg(feature = "abi")]
190use near_sdk::serde;