defuse_core/intents/
account.rs

1use defuse_crypto::PublicKey;
2use defuse_serde_utils::base64::Base64;
3use near_sdk::{AccountIdRef, CryptoHash, near};
4use serde_with::serde_as;
5
6use crate::{
7    Nonce, Result,
8    accounts::AccountEvent,
9    engine::{Engine, Inspector, State},
10};
11
12use super::ExecutableIntent;
13
14#[near(serializers = [borsh, json])]
15#[derive(Debug, Clone)]
16/// Given an account id, the user can add public keys. The added public keys can sign
17/// intents on behalf of these accounts, even to add new ones.
18/// Warning: Implicit account ids, by default, have their corresponding public keys added.
19/// Meaning: For a leaked private key, whose implicit account id had been used in intents,
20/// the user must manually rotate the underlying public key within intents, too.
21pub struct AddPublicKey {
22    pub public_key: PublicKey,
23}
24
25impl ExecutableIntent for AddPublicKey {
26    #[inline]
27    fn execute_intent<S, I>(
28        self,
29        signer_id: &AccountIdRef,
30        engine: &mut Engine<S, I>,
31        _intent_hash: CryptoHash,
32    ) -> Result<()>
33    where
34        S: State,
35        I: Inspector,
36    {
37        engine
38            .state
39            .add_public_key(signer_id.to_owned(), self.public_key)
40    }
41}
42
43#[near(serializers = [borsh, json])]
44#[derive(Debug, Clone)]
45/// Remove the public key associated with a given account. See `AddPublicKey`.
46pub struct RemovePublicKey {
47    pub public_key: PublicKey,
48}
49
50impl ExecutableIntent for RemovePublicKey {
51    #[inline]
52    fn execute_intent<S, I>(
53        self,
54        signer_id: &AccountIdRef,
55        engine: &mut Engine<S, I>,
56        _intent_hash: CryptoHash,
57    ) -> crate::Result<()>
58    where
59        S: State,
60        I: Inspector,
61    {
62        engine
63            .state
64            .remove_public_key(signer_id.to_owned(), self.public_key)
65    }
66}
67
68#[cfg_attr(
69    all(feature = "abi", not(target_arch = "wasm32")),
70    serde_as(schemars = true)
71)]
72#[cfg_attr(
73    not(all(feature = "abi", not(target_arch = "wasm32"))),
74    serde_as(schemars = false)
75)]
76#[near(serializers = [borsh, json])]
77#[derive(Debug, Clone)]
78/// Every intent execution requires a nonce. Each account id gets (over time, while using the intents contract) more nonces,
79/// and this ensures that nonces are not reused to avoid replay attacks. This "marks" the nonce as used.
80pub struct InvalidateNonces {
81    #[serde_as(as = "Vec<Base64>")]
82    pub nonces: Vec<Nonce>,
83}
84
85impl ExecutableIntent for InvalidateNonces {
86    #[inline]
87    fn execute_intent<S, I>(
88        self,
89        signer_id: &AccountIdRef,
90        engine: &mut Engine<S, I>,
91        _intent_hash: CryptoHash,
92    ) -> crate::Result<()>
93    where
94        S: State,
95        I: Inspector,
96    {
97        self.nonces
98            .into_iter()
99            .try_for_each(|n| engine.state.commit_nonce(signer_id.to_owned(), n))
100    }
101}
102
103#[cfg_attr(
104    all(feature = "abi", not(target_arch = "wasm32")),
105    serde_as(schemars = true)
106)]
107#[cfg_attr(
108    not(all(feature = "abi", not(target_arch = "wasm32"))),
109    serde_as(schemars = false)
110)]
111#[near(serializers = [borsh, json])]
112#[derive(Debug, Clone)]
113pub struct SetAuthByPredecessorId {
114    pub enabled: bool,
115}
116
117impl ExecutableIntent for SetAuthByPredecessorId {
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        engine
129            .state
130            .set_auth_by_predecessor_id(signer_id.to_owned(), self.enabled)?;
131
132        engine
133            .inspector
134            .on_event(AccountEvent::new(signer_id, self).into());
135
136        Ok(())
137    }
138}