1use crate::resource::*;
2use crate::runtime::Runtime;
3use crate::*;
4use radix_common::prelude::*;
5use radix_common::traits::NonFungibleData;
6use radix_engine_interface::blueprints::resource::*;
7use runtime::LocalAuthZone;
8use scrypto::engine::scrypto_env::ScryptoVmV1Api;
9
10pub trait ScryptoUncheckedProof {
20 type CheckedProofType;
21 type ResourceManagerType;
22
23 fn check(self, expected_resource_address: ResourceAddress) -> Self::CheckedProofType;
25
26 fn check_with_message<S: ToString>(
28 self,
29 expected_resource_address: ResourceAddress,
30 custom_error_message: S,
31 ) -> Self::CheckedProofType;
32
33 fn skip_checking(self) -> Self::CheckedProofType;
39
40 fn resource_address(&self) -> ResourceAddress;
41
42 fn resource_manager(&self) -> Self::ResourceManagerType;
43
44 fn drop(self);
45
46 fn clone(&self) -> Self;
47
48 fn authorize<F: FnOnce() -> O, O>(&self, f: F) -> O;
49}
50
51pub trait ScryptoProof {
52 type ResourceManagerType;
53
54 fn contains_amount(&self, amount: Decimal) -> bool;
55
56 fn amount(&self) -> Decimal;
57
58 fn resource_address(&self) -> ResourceAddress;
59
60 fn resource_manager(&self) -> Self::ResourceManagerType;
61
62 fn drop(self);
63
64 fn clone(&self) -> Self;
65
66 fn authorize<F: FnOnce() -> O, O>(&self, f: F) -> O;
67}
68
69pub trait ScryptoGenericProof {
70 fn as_fungible(&self) -> CheckedFungibleProof;
71
72 fn as_non_fungible(&self) -> CheckedNonFungibleProof;
73}
74
75pub trait ScryptoFungibleProof {}
76
77pub trait ScryptoNonFungibleProof {
78 fn contains_non_fungible(&self, id: &NonFungibleLocalId) -> bool;
79
80 fn contains_non_fungibles(&self, ids: &IndexSet<NonFungibleLocalId>) -> bool;
81
82 fn non_fungible_local_ids(&self) -> IndexSet<NonFungibleLocalId>;
83
84 fn non_fungible_local_id(&self) -> NonFungibleLocalId;
85
86 fn non_fungible_global_id(&self) -> NonFungibleGlobalId;
87
88 fn non_fungible<T: NonFungibleData>(&self) -> NonFungible<T>;
89
90 fn non_fungibles<T: NonFungibleData>(&self) -> Vec<NonFungible<T>>;
91}
92
93#[derive(Debug, PartialEq, Eq, Hash, ScryptoSbor)]
103#[sbor(transparent)]
104pub struct CheckedProof(pub Proof);
105
106#[derive(Debug, PartialEq, Eq, Hash, ScryptoSbor)]
107#[sbor(transparent)]
108pub struct CheckedFungibleProof(pub CheckedProof);
109
110#[derive(Debug, PartialEq, Eq, Hash, ScryptoSbor)]
111#[sbor(transparent)]
112pub struct CheckedNonFungibleProof(pub CheckedProof);
113
114impl From<CheckedFungibleProof> for CheckedProof {
115 fn from(value: CheckedFungibleProof) -> Self {
116 value.0
117 }
118}
119
120impl From<CheckedNonFungibleProof> for CheckedProof {
121 fn from(value: CheckedNonFungibleProof) -> Self {
122 value.0
123 }
124}
125
126impl ScryptoUncheckedProof for Proof {
131 type CheckedProofType = CheckedProof;
132 type ResourceManagerType = ResourceManager;
133
134 fn check(self, expected_resource_address: ResourceAddress) -> CheckedProof {
135 let actual_resource_address = self.resource_address();
136
137 if actual_resource_address != expected_resource_address {
138 Runtime::panic(format!(
139 "Invalid proof: Expected {:?}, but got {:?}",
140 expected_resource_address, actual_resource_address
141 ))
142 }
143
144 CheckedProof(self)
145 }
146
147 fn check_with_message<S: ToString>(
148 self,
149 expected_resource_address: ResourceAddress,
150 custom_error_message: S,
151 ) -> CheckedProof {
152 let actual_resource_address = self.resource_address();
153
154 if actual_resource_address != expected_resource_address {
155 Runtime::panic(custom_error_message.to_string())
156 }
157
158 CheckedProof(self)
159 }
160
161 fn skip_checking(self) -> CheckedProof {
162 CheckedProof(self)
163 }
164
165 fn resource_address(&self) -> ResourceAddress {
166 let rtn = ScryptoVmV1Api::object_call(
167 self.0.as_node_id(),
168 PROOF_GET_RESOURCE_ADDRESS_IDENT,
169 scrypto_encode(&ProofGetResourceAddressInput {}).unwrap(),
170 );
171 scrypto_decode(&rtn).unwrap()
172 }
173
174 fn resource_manager(&self) -> Self::ResourceManagerType {
175 self.resource_address().into()
176 }
177
178 fn drop(self) {
179 ScryptoVmV1Api::blueprint_call(
180 RESOURCE_PACKAGE,
181 if ScryptoVmV1Api::object_instance_of(
182 self.0.as_node_id(),
183 &BlueprintId {
184 package_address: RESOURCE_PACKAGE,
185 blueprint_name: FUNGIBLE_PROOF_BLUEPRINT.to_owned(),
186 },
187 ) {
188 FUNGIBLE_PROOF_BLUEPRINT
189 } else {
190 NON_FUNGIBLE_PROOF_BLUEPRINT
191 },
192 PROOF_DROP_IDENT,
193 scrypto_encode(&ProofDropInput {
194 proof: Proof(self.0),
195 })
196 .unwrap(),
197 );
198 }
199
200 fn clone(&self) -> Self {
201 let rtn = ScryptoVmV1Api::object_call(
202 self.0.as_node_id(),
203 PROOF_CLONE_IDENT,
204 scrypto_encode(&ProofCloneInput {}).unwrap(),
205 );
206 scrypto_decode(&rtn).unwrap()
207 }
208
209 fn authorize<F: FnOnce() -> O, O>(&self, f: F) -> O {
210 LocalAuthZone::push(self.clone());
211 let output = f();
212 LocalAuthZone::pop()
213 .expect("Authorized closure changed auth zone proof stack")
214 .drop();
215 output
216 }
217}
218
219impl ScryptoUncheckedProof for FungibleProof {
220 type CheckedProofType = CheckedFungibleProof;
221 type ResourceManagerType = FungibleResourceManager;
222
223 fn check(self, expected_resource_address: ResourceAddress) -> Self::CheckedProofType {
224 CheckedFungibleProof(Proof::check(self.0, expected_resource_address))
225 }
226
227 fn check_with_message<S: ToString>(
228 self,
229 expected_resource_address: ResourceAddress,
230 custom_error_message: S,
231 ) -> Self::CheckedProofType {
232 CheckedFungibleProof(Proof::check_with_message(
233 self.0,
234 expected_resource_address,
235 custom_error_message,
236 ))
237 }
238
239 fn skip_checking(self) -> Self::CheckedProofType {
240 CheckedFungibleProof(Proof::skip_checking(self.0))
241 }
242
243 fn resource_address(&self) -> ResourceAddress {
244 self.0.resource_address()
245 }
246
247 fn resource_manager(&self) -> Self::ResourceManagerType {
248 self.resource_address().into()
249 }
250
251 fn drop(self) {
252 self.0.drop()
253 }
254
255 fn clone(&self) -> Self {
256 FungibleProof(self.0.clone())
257 }
258
259 fn authorize<F: FnOnce() -> O, O>(&self, f: F) -> O {
260 self.0.authorize(f)
261 }
262}
263
264impl ScryptoUncheckedProof for NonFungibleProof {
265 type CheckedProofType = CheckedNonFungibleProof;
266 type ResourceManagerType = NonFungibleResourceManager;
267
268 fn check(self, expected_resource_address: ResourceAddress) -> Self::CheckedProofType {
269 CheckedNonFungibleProof(Proof::check(self.0, expected_resource_address))
270 }
271
272 fn check_with_message<S: ToString>(
273 self,
274 expected_resource_address: ResourceAddress,
275 custom_error_message: S,
276 ) -> Self::CheckedProofType {
277 CheckedNonFungibleProof(Proof::check_with_message(
278 self.0,
279 expected_resource_address,
280 custom_error_message,
281 ))
282 }
283
284 fn skip_checking(self) -> Self::CheckedProofType {
285 CheckedNonFungibleProof(Proof::skip_checking(self.0))
286 }
287
288 fn resource_address(&self) -> ResourceAddress {
289 self.0.resource_address()
290 }
291
292 fn resource_manager(&self) -> Self::ResourceManagerType {
293 self.resource_address().into()
294 }
295
296 fn drop(self) {
297 self.0.drop()
298 }
299
300 fn clone(&self) -> Self {
301 NonFungibleProof(self.0.clone())
302 }
303
304 fn authorize<F: FnOnce() -> O, O>(&self, f: F) -> O {
305 self.0.authorize(f)
306 }
307}
308
309impl ScryptoProof for CheckedProof {
314 type ResourceManagerType = ResourceManager;
315
316 fn contains_amount(&self, amount: Decimal) -> bool {
317 self.amount() >= amount
318 }
319
320 fn amount(&self) -> Decimal {
321 let rtn = ScryptoVmV1Api::object_call(
322 self.0 .0.as_node_id(),
323 PROOF_GET_AMOUNT_IDENT,
324 scrypto_encode(&ProofGetAmountInput {}).unwrap(),
325 );
326 scrypto_decode(&rtn).unwrap()
327 }
328
329 fn resource_address(&self) -> ResourceAddress {
330 self.0.resource_address()
331 }
332
333 fn resource_manager(&self) -> Self::ResourceManagerType {
334 self.resource_address().into()
335 }
336
337 fn drop(self) {
338 self.0.drop()
339 }
340
341 fn clone(&self) -> Self {
342 Self(self.0.clone())
343 }
344
345 fn authorize<F: FnOnce() -> O, O>(&self, f: F) -> O {
346 self.0.authorize(f)
347 }
348}
349
350impl ScryptoGenericProof for CheckedProof {
351 fn as_fungible(&self) -> CheckedFungibleProof {
352 assert!(
353 self.resource_address()
354 .as_node_id()
355 .is_global_fungible_resource_manager(),
356 "Not a fungible proof"
357 );
358 CheckedFungibleProof(Self(Proof(self.0 .0)))
359 }
360
361 fn as_non_fungible(&self) -> CheckedNonFungibleProof {
362 assert!(
363 self.resource_address()
364 .as_node_id()
365 .is_global_non_fungible_resource_manager(),
366 "Not a non-fungible proof"
367 );
368 CheckedNonFungibleProof(Self(Proof(self.0 .0)))
369 }
370}
371
372impl ScryptoProof for CheckedFungibleProof {
377 type ResourceManagerType = FungibleResourceManager;
378
379 fn contains_amount(&self, amount: Decimal) -> bool {
380 self.0.contains_amount(amount)
381 }
382
383 fn amount(&self) -> Decimal {
384 self.0.amount()
385 }
386
387 fn resource_manager(&self) -> Self::ResourceManagerType {
388 self.resource_address().into()
389 }
390
391 fn resource_address(&self) -> ResourceAddress {
392 self.0.resource_address()
393 }
394
395 fn drop(self) {
396 self.0.drop()
397 }
398
399 fn clone(&self) -> Self {
400 Self(self.0.clone())
401 }
402
403 fn authorize<F: FnOnce() -> O, O>(&self, f: F) -> O {
404 self.0.authorize(f)
405 }
406}
407
408impl ScryptoFungibleProof for CheckedFungibleProof {}
409
410impl ScryptoProof for CheckedNonFungibleProof {
415 type ResourceManagerType = NonFungibleResourceManager;
416
417 fn contains_amount(&self, amount: Decimal) -> bool {
418 self.0.contains_amount(amount)
419 }
420
421 fn amount(&self) -> Decimal {
422 self.0.amount()
423 }
424
425 fn resource_manager(&self) -> Self::ResourceManagerType {
426 self.resource_address().into()
427 }
428
429 fn resource_address(&self) -> ResourceAddress {
430 self.0.resource_address()
431 }
432
433 fn drop(self) {
434 self.0.drop()
435 }
436
437 fn clone(&self) -> Self {
438 Self(self.0.clone())
439 }
440
441 fn authorize<F: FnOnce() -> O, O>(&self, f: F) -> O {
442 self.0.authorize(f)
443 }
444}
445
446impl ScryptoNonFungibleProof for CheckedNonFungibleProof {
447 fn contains_non_fungible(&self, id: &NonFungibleLocalId) -> bool {
448 self.non_fungible_local_ids().contains(id)
449 }
450
451 fn contains_non_fungibles(&self, ids: &IndexSet<NonFungibleLocalId>) -> bool {
452 self.non_fungible_local_ids().is_superset(ids)
453 }
454
455 fn non_fungibles<T: NonFungibleData>(&self) -> Vec<NonFungible<T>> {
460 let resource_address = self.0.resource_address();
461 self.non_fungible_local_ids()
462 .iter()
463 .map(|id| NonFungible::from(NonFungibleGlobalId::new(resource_address, id.clone())))
464 .collect()
465 }
466
467 fn non_fungible_local_id(&self) -> NonFungibleLocalId {
472 let non_fungible_local_ids = self.non_fungible_local_ids();
473 if non_fungible_local_ids.len() != 1 {
474 panic!("Expecting singleton NFT vault");
475 }
476 self.non_fungible_local_ids().into_iter().next().unwrap()
477 }
478
479 fn non_fungible_global_id(&self) -> NonFungibleGlobalId {
484 NonFungibleGlobalId::new(self.resource_address(), self.non_fungible_local_id())
485 }
486
487 fn non_fungible<T: NonFungibleData>(&self) -> NonFungible<T> {
492 let non_fungibles = self.non_fungibles();
493 if non_fungibles.len() != 1 {
494 panic!("Expecting singleton NFT proof");
495 }
496 non_fungibles.into_iter().next().unwrap()
497 }
498
499 fn non_fungible_local_ids(&self) -> IndexSet<NonFungibleLocalId> {
500 let rtn = ScryptoVmV1Api::object_call(
501 self.0 .0 .0.as_node_id(),
502 NON_FUNGIBLE_PROOF_GET_LOCAL_IDS_IDENT,
503 scrypto_encode(&NonFungibleProofGetLocalIdsInput {}).unwrap(),
504 );
505 scrypto_decode(&rtn).unwrap()
506 }
507}