iota_config/
transaction_deny_config.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::collections::HashSet;
6
7use iota_types::base_types::{IotaAddress, ObjectID};
8use once_cell::sync::OnceCell;
9use serde::{Deserialize, Serialize};
10
11#[derive(Clone, Debug, Default, Deserialize, Serialize)]
12#[serde(rename_all = "kebab-case")]
13pub struct TransactionDenyConfig {
14    /// A list of object IDs that are not allowed to be accessed/used in
15    /// transactions. Note that since this is checked during transaction
16    /// signing, only root object ids are supported here (i.e. no
17    /// child-objects). Similarly this does not apply to wrapped objects as
18    /// they are not directly accessible.
19    #[serde(default, skip_serializing_if = "Vec::is_empty")]
20    object_deny_list: Vec<ObjectID>,
21
22    /// A list of package object IDs that are not allowed to be called into in
23    /// transactions, either directly or indirectly through transitive
24    /// dependencies. Note that this does not apply to type arguments.
25    /// Also since we only compare the deny list against the upgraded package ID
26    /// of each dependency in the used package, when a package ID is denied,
27    /// newer versions of that package are still allowed. If we want to deny
28    /// the entire upgrade family of a package, we need to explicitly
29    /// specify all the package IDs in the deny list. TODO: We could
30    /// consider making this more flexible, e.g. whether to check in type args,
31    /// whether to block entire upgrade family, whether to allow upgrade and
32    /// etc.
33    #[serde(default, skip_serializing_if = "Vec::is_empty")]
34    package_deny_list: Vec<ObjectID>,
35
36    /// A list of iota addresses that are not allowed to be used as the sender
37    /// or sponsor.
38    #[serde(default, skip_serializing_if = "Vec::is_empty")]
39    address_deny_list: Vec<IotaAddress>,
40
41    /// Whether publishing new packages is disabled.
42    #[serde(default)]
43    package_publish_disabled: bool,
44
45    /// Whether upgrading existing packages is disabled.
46    #[serde(default)]
47    package_upgrade_disabled: bool,
48
49    /// Whether usage of shared objects is disabled.
50    #[serde(default)]
51    shared_object_disabled: bool,
52
53    /// Whether user transactions are disabled (i.e. only system transactions
54    /// are allowed). This is essentially a kill switch for transactions
55    /// processing to a degree.
56    #[serde(default)]
57    user_transaction_disabled: bool,
58
59    /// In-memory maps for faster lookup of various lists.
60    #[serde(skip)]
61    object_deny_set: OnceCell<HashSet<ObjectID>>,
62
63    #[serde(skip)]
64    package_deny_set: OnceCell<HashSet<ObjectID>>,
65
66    #[serde(skip)]
67    address_deny_set: OnceCell<HashSet<IotaAddress>>,
68
69    /// Whether receiving objects transferred to other objects is allowed
70    #[serde(default)]
71    receiving_objects_disabled: bool,
72
73    /// Whether zklogin transaction is disabled
74    #[serde(default)]
75    zklogin_sig_disabled: bool,
76
77    /// A list of disabled OAuth providers for zkLogin
78    #[serde(default)]
79    zklogin_disabled_providers: HashSet<String>,
80    // TODO: We could consider add a deny list for types that we want to disable public transfer.
81    // TODO: We could also consider disable more types of commands, such as transfer, split and
82    // etc.
83}
84
85impl TransactionDenyConfig {
86    pub fn get_object_deny_set(&self) -> &HashSet<ObjectID> {
87        self.object_deny_set
88            .get_or_init(|| self.object_deny_list.iter().cloned().collect())
89    }
90
91    pub fn get_package_deny_set(&self) -> &HashSet<ObjectID> {
92        self.package_deny_set
93            .get_or_init(|| self.package_deny_list.iter().cloned().collect())
94    }
95
96    pub fn get_address_deny_set(&self) -> &HashSet<IotaAddress> {
97        self.address_deny_set
98            .get_or_init(|| self.address_deny_list.iter().cloned().collect())
99    }
100
101    pub fn package_publish_disabled(&self) -> bool {
102        self.package_publish_disabled
103    }
104
105    pub fn package_upgrade_disabled(&self) -> bool {
106        self.package_upgrade_disabled
107    }
108
109    pub fn shared_object_disabled(&self) -> bool {
110        self.shared_object_disabled
111    }
112
113    pub fn user_transaction_disabled(&self) -> bool {
114        self.user_transaction_disabled
115    }
116
117    pub fn receiving_objects_disabled(&self) -> bool {
118        self.receiving_objects_disabled
119    }
120
121    pub fn zklogin_sig_disabled(&self) -> bool {
122        self.zklogin_sig_disabled
123    }
124
125    pub fn zklogin_disabled_providers(&self) -> &HashSet<String> {
126        &self.zklogin_disabled_providers
127    }
128}
129
130#[derive(Default)]
131pub struct TransactionDenyConfigBuilder {
132    config: TransactionDenyConfig,
133}
134
135impl TransactionDenyConfigBuilder {
136    pub fn new() -> Self {
137        Self::default()
138    }
139
140    pub fn build(self) -> TransactionDenyConfig {
141        self.config
142    }
143
144    pub fn disable_user_transaction(mut self) -> Self {
145        self.config.user_transaction_disabled = true;
146        self
147    }
148
149    pub fn disable_shared_object_transaction(mut self) -> Self {
150        self.config.shared_object_disabled = true;
151        self
152    }
153
154    pub fn disable_package_publish(mut self) -> Self {
155        self.config.package_publish_disabled = true;
156        self
157    }
158
159    pub fn disable_package_upgrade(mut self) -> Self {
160        self.config.package_upgrade_disabled = true;
161        self
162    }
163
164    pub fn disable_receiving_objects(mut self) -> Self {
165        self.config.receiving_objects_disabled = true;
166        self
167    }
168
169    pub fn add_denied_object(mut self, id: ObjectID) -> Self {
170        self.config.object_deny_list.push(id);
171        self
172    }
173
174    pub fn add_denied_address(mut self, address: IotaAddress) -> Self {
175        self.config.address_deny_list.push(address);
176        self
177    }
178
179    pub fn add_denied_package(mut self, id: ObjectID) -> Self {
180        self.config.package_deny_list.push(id);
181        self
182    }
183
184    pub fn disable_zklogin_sig(mut self) -> Self {
185        self.config.zklogin_sig_disabled = true;
186        self
187    }
188
189    pub fn add_zklogin_disabled_provider(mut self, provider: String) -> Self {
190        self.config.zklogin_disabled_providers.insert(provider);
191        self
192    }
193}