radix_engine_interface/blueprints/resource/
proof_rule.rs1use crate::blueprints::resource::CompositeRequirement::{AllOf, AnyOf};
2use crate::internal_prelude::*;
3#[cfg(feature = "fuzzing")]
4use arbitrary::Arbitrary;
5
6#[cfg_attr(
7 feature = "fuzzing",
8 derive(Arbitrary, serde::Serialize, serde::Deserialize)
9)]
10#[derive(
11 Debug,
12 Clone,
13 PartialEq,
14 Eq,
15 Hash,
16 Ord,
17 PartialOrd,
18 ManifestSbor,
19 ScryptoCategorize,
20 ScryptoEncode,
21 ScryptoDecode,
22)]
23pub enum ResourceOrNonFungible {
24 NonFungible(NonFungibleGlobalId),
25 Resource(ResourceAddress),
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, ManifestSbor)]
29pub enum ManifestResourceOrNonFungible {
30 NonFungible(NonFungibleGlobalId),
31 Resource(ManifestResourceAddress),
32}
33
34impl From<ResourceOrNonFungible> for ManifestResourceOrNonFungible {
35 fn from(value: ResourceOrNonFungible) -> Self {
36 match value {
37 ResourceOrNonFungible::NonFungible(non_fungible_global_id) => {
38 Self::NonFungible(non_fungible_global_id)
39 }
40 ResourceOrNonFungible::Resource(resource_address) => {
41 Self::Resource(ManifestResourceAddress::Static(resource_address))
42 }
43 }
44 }
45}
46
47impl Describe<ScryptoCustomTypeKind> for ResourceOrNonFungible {
48 const TYPE_ID: RustTypeId =
49 RustTypeId::WellKnown(well_known_scrypto_custom_types::RESOURCE_OR_NON_FUNGIBLE_TYPE);
50
51 fn type_data() -> ScryptoTypeData<RustTypeId> {
52 well_known_scrypto_custom_types::resource_or_non_fungible_type_data()
53 }
54}
55
56impl From<NonFungibleGlobalId> for ResourceOrNonFungible {
57 fn from(non_fungible_global_id: NonFungibleGlobalId) -> Self {
58 ResourceOrNonFungible::NonFungible(non_fungible_global_id)
59 }
60}
61
62impl From<ResourceAddress> for ResourceOrNonFungible {
63 fn from(resource_address: ResourceAddress) -> Self {
64 ResourceOrNonFungible::Resource(resource_address)
65 }
66}
67
68pub struct ResourceOrNonFungibleList {
69 list: Vec<ResourceOrNonFungible>,
70}
71
72impl<T> From<Vec<T>> for ResourceOrNonFungibleList
73where
74 T: Into<ResourceOrNonFungible>,
75{
76 fn from(addresses: Vec<T>) -> Self {
77 ResourceOrNonFungibleList {
78 list: addresses.into_iter().map(|a| a.into()).collect(),
79 }
80 }
81}
82
83#[cfg_attr(
85 feature = "fuzzing",
86 derive(Arbitrary, serde::Serialize, serde::Deserialize)
87)]
88#[derive(
89 Debug,
90 Clone,
91 PartialEq,
92 Eq,
93 Hash,
94 Ord,
95 PartialOrd,
96 ManifestSbor,
97 ScryptoCategorize,
98 ScryptoEncode,
99 ScryptoDecode,
100)]
101pub enum BasicRequirement {
102 Require(ResourceOrNonFungible),
103 AmountOf(Decimal, ResourceAddress),
104 CountOf(u8, Vec<ResourceOrNonFungible>),
105 AllOf(Vec<ResourceOrNonFungible>),
106 AnyOf(Vec<ResourceOrNonFungible>),
107}
108
109impl Describe<ScryptoCustomTypeKind> for BasicRequirement {
110 const TYPE_ID: RustTypeId =
111 RustTypeId::WellKnown(well_known_scrypto_custom_types::BASIC_REQUIREMENT_TYPE);
112
113 fn type_data() -> ScryptoTypeData<RustTypeId> {
114 well_known_scrypto_custom_types::basic_requirement_type_data()
115 }
116}
117
118impl From<ResourceAddress> for CompositeRequirement {
119 fn from(resource_address: ResourceAddress) -> Self {
120 CompositeRequirement::BasicRequirement(BasicRequirement::Require(resource_address.into()))
121 }
122}
123
124impl From<NonFungibleGlobalId> for CompositeRequirement {
125 fn from(id: NonFungibleGlobalId) -> Self {
126 CompositeRequirement::BasicRequirement(BasicRequirement::Require(id.into()))
127 }
128}
129
130impl From<ResourceOrNonFungible> for CompositeRequirement {
131 fn from(resource_or_non_fungible: ResourceOrNonFungible) -> Self {
132 CompositeRequirement::BasicRequirement(BasicRequirement::Require(resource_or_non_fungible))
133 }
134}
135
136#[cfg_attr(
137 feature = "fuzzing",
138 derive(Arbitrary, serde::Serialize, serde::Deserialize)
139)]
140#[derive(
141 Debug,
142 Clone,
143 PartialEq,
144 Eq,
145 Hash,
146 Ord,
147 PartialOrd,
148 ManifestSbor,
149 ScryptoCategorize,
150 ScryptoEncode,
151 ScryptoDecode,
152)]
153pub enum CompositeRequirement {
154 BasicRequirement(BasicRequirement),
155 AnyOf(Vec<CompositeRequirement>),
156 AllOf(Vec<CompositeRequirement>),
157}
158
159impl Describe<ScryptoCustomTypeKind> for CompositeRequirement {
160 const TYPE_ID: RustTypeId =
161 RustTypeId::WellKnown(well_known_scrypto_custom_types::COMPOSITE_REQUIREMENT_TYPE);
162
163 fn type_data() -> ScryptoTypeData<RustTypeId> {
164 well_known_scrypto_custom_types::composite_requirement_type_data()
165 }
166}
167
168impl CompositeRequirement {
169 pub fn or(self, other: CompositeRequirement) -> Self {
170 match self {
171 CompositeRequirement::AnyOf(mut rules) => {
172 rules.push(other);
173 AnyOf(rules)
174 }
175 _ => AnyOf(vec![self, other]),
176 }
177 }
178
179 pub fn and(self, other: CompositeRequirement) -> Self {
180 match self {
181 CompositeRequirement::AllOf(mut rules) => {
182 rules.push(other);
183 AllOf(rules)
184 }
185 _ => AllOf(vec![self, other]),
186 }
187 }
188}
189
190pub fn package_of_direct_caller(package: PackageAddress) -> ResourceOrNonFungible {
192 ResourceOrNonFungible::NonFungible(NonFungibleGlobalId::package_of_direct_caller_badge(package))
193}
194
195pub fn global_caller(global_caller: impl Into<GlobalCaller>) -> ResourceOrNonFungible {
199 ResourceOrNonFungible::NonFungible(NonFungibleGlobalId::global_caller_badge(global_caller))
200}
201
202pub fn signature(public_key: &impl HasPublicKeyHash) -> ResourceOrNonFungible {
204 ResourceOrNonFungible::NonFungible(NonFungibleGlobalId::from_public_key(public_key))
205}
206
207pub fn system_execution(transaction_type: SystemExecution) -> NonFungibleGlobalId {
209 transaction_type.into()
210}
211
212pub fn require<T>(required: T) -> CompositeRequirement
213where
214 T: Into<CompositeRequirement>,
215{
216 required.into()
217}
218
219pub fn require_any_of<T>(resources: T) -> CompositeRequirement
220where
221 T: Into<ResourceOrNonFungibleList>,
222{
223 let list: ResourceOrNonFungibleList = resources.into();
224 CompositeRequirement::BasicRequirement(BasicRequirement::AnyOf(list.list))
225}
226
227pub fn require_all_of<T>(resources: T) -> CompositeRequirement
228where
229 T: Into<ResourceOrNonFungibleList>,
230{
231 let list: ResourceOrNonFungibleList = resources.into();
232 CompositeRequirement::BasicRequirement(BasicRequirement::AllOf(list.list))
233}
234
235pub fn require_n_of<C, T>(count: C, resources: T) -> CompositeRequirement
236where
237 C: Into<u8>,
238 T: Into<ResourceOrNonFungibleList>,
239{
240 let list: ResourceOrNonFungibleList = resources.into();
241 CompositeRequirement::BasicRequirement(BasicRequirement::CountOf(count.into(), list.list))
242}
243
244pub fn require_amount<D, T>(amount: D, resource: T) -> CompositeRequirement
245where
246 D: Into<Decimal>,
247 T: Into<ResourceAddress>,
248{
249 CompositeRequirement::BasicRequirement(BasicRequirement::AmountOf(
250 amount.into(),
251 resource.into(),
252 ))
253}
254
255#[cfg_attr(
256 feature = "fuzzing",
257 derive(Arbitrary, serde::Serialize, serde::Deserialize)
258)]
259#[derive(
260 Debug,
261 Clone,
262 PartialEq,
263 Eq,
264 Hash,
265 Ord,
266 PartialOrd,
267 ManifestSbor,
268 ScryptoCategorize,
269 ScryptoEncode,
270 ScryptoDecode,
271)]
272pub enum AccessRule {
273 AllowAll,
274 DenyAll,
275 Protected(CompositeRequirement),
276}
277
278impl Describe<ScryptoCustomTypeKind> for AccessRule {
279 const TYPE_ID: RustTypeId =
280 RustTypeId::WellKnown(well_known_scrypto_custom_types::ACCESS_RULE_TYPE);
281
282 fn type_data() -> ScryptoTypeData<RustTypeId> {
283 well_known_scrypto_custom_types::access_rule_type_data()
284 }
285}
286
287impl From<CompositeRequirement> for AccessRule {
288 fn from(value: CompositeRequirement) -> Self {
289 AccessRule::Protected(value)
290 }
291}
292
293pub trait AccessRuleVisitor {
294 type Error;
295 fn visit(&mut self, node: &CompositeRequirement, depth: usize) -> Result<(), Self::Error>;
296}
297
298impl AccessRule {
299 pub fn dfs_traverse_nodes<V: AccessRuleVisitor>(
300 &self,
301 visitor: &mut V,
302 ) -> Result<(), V::Error> {
303 match self {
304 AccessRule::Protected(node) => node.dfs_traverse_recursive(visitor, 0),
305 _ => Ok(()),
306 }
307 }
308}
309
310impl CompositeRequirement {
311 fn dfs_traverse_recursive<V: AccessRuleVisitor>(
312 &self,
313 visitor: &mut V,
314 depth: usize,
315 ) -> Result<(), V::Error> {
316 visitor.visit(self, depth)?;
317
318 match self {
319 CompositeRequirement::BasicRequirement(..) => {}
320 CompositeRequirement::AnyOf(nodes) | CompositeRequirement::AllOf(nodes) => {
321 for node in nodes {
322 node.dfs_traverse_recursive(visitor, depth + 1)?;
323 }
324 }
325 }
326
327 Ok(())
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334 use radix_common::prelude::*;
335
336 #[test]
337 fn require_signature_secp256k1() {
338 let private_key = Secp256k1PrivateKey::from_u64(1).unwrap();
339 let public_key = private_key.public_key();
340
341 let r1 = rule!(require(NonFungibleGlobalId::from_public_key(&public_key)));
342 let r2 = rule!(require(signature(&public_key)));
343
344 assert_eq!(r1, r2);
345 }
346
347 #[test]
348 fn require_signature_ed25519() {
349 let private_key = Ed25519PrivateKey::from_u64(1).unwrap();
350 let public_key = private_key.public_key();
351
352 let r1 = rule!(require(NonFungibleGlobalId::from_public_key(&public_key)));
353 let r2 = rule!(require(signature(&public_key)));
354
355 assert_eq!(r1, r2);
356 }
357}