1use crate::resource::*;
2use crate::*;
3use radix_common::data::scrypto::model::*;
4use radix_common::data::scrypto::{scrypto_decode, scrypto_encode};
5use radix_common::math::Decimal;
6use radix_common::traits::NonFungibleData;
7use radix_engine_interface::blueprints::resource::*;
8use radix_engine_interface::types::*;
9use runtime::LocalAuthZone;
10use sbor::rust::prelude::*;
11use scrypto::engine::scrypto_env::ScryptoVmV1Api;
12
13pub trait ScryptoVault {
18 type BucketType;
19 type ResourceManagerType;
20
21 fn with_bucket(bucket: Self::BucketType) -> Self;
22
23 fn new(resource_address: ResourceAddress) -> Self;
24
25 fn put(&mut self, bucket: Self::BucketType) -> ();
26
27 fn amount(&self) -> Decimal;
28
29 fn resource_address(&self) -> ResourceAddress;
30
31 fn resource_manager(&self) -> Self::ResourceManagerType;
32
33 fn is_empty(&self) -> bool;
34
35 fn take<A: Into<Decimal>>(&mut self, amount: A) -> Self::BucketType;
36
37 fn take_all(&mut self) -> Self::BucketType;
38
39 fn take_advanced<A: Into<Decimal>>(
40 &mut self,
41 amount: A,
42 withdraw_strategy: WithdrawStrategy,
43 ) -> Self::BucketType;
44
45 fn burn<A: Into<Decimal>>(&mut self, amount: A);
46}
47
48pub trait ScryptoGenericVault {
49 fn as_fungible(&self) -> FungibleVault;
50
51 fn as_non_fungible(&self) -> NonFungibleVault;
52}
53
54pub trait ScryptoFungibleVault {
55 fn lock_fee<A: Into<Decimal>>(&mut self, amount: A);
56
57 fn lock_contingent_fee<A: Into<Decimal>>(&mut self, amount: A);
58
59 fn create_proof_of_amount<A: Into<Decimal>>(&self, amount: A) -> FungibleProof;
60
61 fn authorize_with_amount<A: Into<Decimal>, F: FnOnce() -> O, O>(&self, amount: A, f: F) -> O;
62}
63
64pub trait ScryptoNonFungibleVault {
65 fn non_fungible_local_ids(&self, limit: u32) -> IndexSet<NonFungibleLocalId>;
66
67 fn contains_non_fungible(&self, id: &NonFungibleLocalId) -> bool;
68
69 fn non_fungibles<T: NonFungibleData>(&self, limit: u32) -> Vec<NonFungible<T>>;
70
71 fn non_fungible_local_id(&self) -> NonFungibleLocalId;
72
73 fn non_fungible_global_id(&self) -> NonFungibleGlobalId;
74
75 fn non_fungible<T: NonFungibleData>(&self) -> NonFungible<T>;
76
77 fn take_non_fungible(
78 &mut self,
79 non_fungible_local_id: &NonFungibleLocalId,
80 ) -> NonFungibleBucket;
81
82 fn take_non_fungibles(
83 &mut self,
84 non_fungible_local_ids: &IndexSet<NonFungibleLocalId>,
85 ) -> NonFungibleBucket;
86
87 fn burn_non_fungibles(&mut self, non_fungible_local_ids: &IndexSet<NonFungibleLocalId>);
88
89 fn create_proof_of_non_fungibles(
90 &self,
91 non_fungible_local_ids: &IndexSet<NonFungibleLocalId>,
92 ) -> NonFungibleProof;
93
94 fn authorize_with_non_fungibles<F: FnOnce() -> O, O>(
95 &self,
96 non_fungible_local_ids: &IndexSet<NonFungibleLocalId>,
97 f: F,
98 ) -> O;
99}
100
101impl ScryptoVault for Vault {
106 type BucketType = Bucket;
107 type ResourceManagerType = ResourceManager;
108
109 fn with_bucket(bucket: Self::BucketType) -> Self {
111 let mut vault = Vault::new(bucket.resource_address());
112 vault.put(bucket);
113 vault
114 }
115
116 fn new(resource_address: ResourceAddress) -> Self {
117 let rtn = ScryptoVmV1Api::object_call(
118 resource_address.as_node_id(),
119 RESOURCE_MANAGER_CREATE_EMPTY_VAULT_IDENT,
120 scrypto_encode(&ResourceManagerCreateEmptyVaultInput {}).unwrap(),
121 );
122 scrypto_decode(&rtn).unwrap()
123 }
124
125 fn put(&mut self, bucket: Self::BucketType) -> () {
126 let rtn = ScryptoVmV1Api::object_call(
127 self.0.as_node_id(),
128 VAULT_PUT_IDENT,
129 scrypto_encode(&VaultPutInput { bucket }).unwrap(),
130 );
131 scrypto_decode(&rtn).unwrap()
132 }
133
134 fn amount(&self) -> Decimal {
135 let rtn = ScryptoVmV1Api::object_call(
136 self.0.as_node_id(),
137 VAULT_GET_AMOUNT_IDENT,
138 scrypto_encode(&VaultGetAmountInput {}).unwrap(),
139 );
140 scrypto_decode(&rtn).unwrap()
141 }
142
143 fn resource_address(&self) -> ResourceAddress {
144 let address = ScryptoVmV1Api::object_get_outer_object(self.0.as_node_id());
145 ResourceAddress::try_from(address).unwrap()
146 }
147
148 fn resource_manager(&self) -> Self::ResourceManagerType {
149 self.resource_address().into()
150 }
151
152 fn take<A: Into<Decimal>>(&mut self, amount: A) -> Self::BucketType {
154 let rtn = ScryptoVmV1Api::object_call(
155 self.0.as_node_id(),
156 VAULT_TAKE_IDENT,
157 scrypto_encode(&VaultTakeInput {
158 amount: amount.into(),
159 })
160 .unwrap(),
161 );
162 scrypto_decode(&rtn).unwrap()
163 }
164
165 fn take_all(&mut self) -> Self::BucketType {
167 self.take(self.amount())
168 }
169
170 fn take_advanced<A: Into<Decimal>>(
171 &mut self,
172 amount: A,
173 withdraw_strategy: WithdrawStrategy,
174 ) -> Self::BucketType {
175 let rtn = ScryptoVmV1Api::object_call(
176 self.0.as_node_id(),
177 VAULT_TAKE_ADVANCED_IDENT,
178 scrypto_encode(&VaultTakeAdvancedInput {
179 amount: amount.into(),
180 withdraw_strategy,
181 })
182 .unwrap(),
183 );
184 scrypto_decode(&rtn).unwrap()
185 }
186
187 fn is_empty(&self) -> bool {
189 self.amount() == 0.into()
190 }
191
192 fn burn<A: Into<Decimal>>(&mut self, amount: A) {
193 let rtn = ScryptoVmV1Api::object_call(
194 self.0.as_node_id(),
195 VAULT_BURN_IDENT,
196 scrypto_encode(&VaultBurnInput {
197 amount: amount.into(),
198 })
199 .unwrap(),
200 );
201 scrypto_decode(&rtn).unwrap()
202 }
203}
204
205impl ScryptoGenericVault for Vault {
206 fn as_fungible(&self) -> FungibleVault {
207 assert!(
208 self.0.as_node_id().is_internal_fungible_vault(),
209 "Not a fungible vault"
210 );
211 FungibleVault(Self(self.0))
212 }
213
214 fn as_non_fungible(&self) -> NonFungibleVault {
215 assert!(
216 self.0.as_node_id().is_internal_non_fungible_vault(),
217 "Not a non-fungible vault"
218 );
219 NonFungibleVault(Self(self.0))
220 }
221}
222
223impl ScryptoVault for FungibleVault {
228 type BucketType = FungibleBucket;
229 type ResourceManagerType = FungibleResourceManager;
230
231 fn with_bucket(bucket: Self::BucketType) -> Self {
232 Self(Vault::with_bucket(bucket.0))
233 }
234
235 fn new(resource_address: ResourceAddress) -> Self {
236 assert!(resource_address
237 .as_node_id()
238 .is_global_fungible_resource_manager());
239 Self(Vault::new(resource_address))
240 }
241
242 fn put(&mut self, bucket: Self::BucketType) -> () {
243 self.0.put(bucket.0)
244 }
245
246 fn amount(&self) -> Decimal {
247 self.0.amount()
248 }
249
250 fn resource_address(&self) -> ResourceAddress {
251 self.0.resource_address()
252 }
253
254 fn resource_manager(&self) -> Self::ResourceManagerType {
255 self.resource_address().into()
256 }
257
258 fn is_empty(&self) -> bool {
259 self.0.is_empty()
260 }
261
262 fn take<A: Into<Decimal>>(&mut self, amount: A) -> Self::BucketType {
263 FungibleBucket(self.0.take(amount))
264 }
265
266 fn take_all(&mut self) -> Self::BucketType {
267 FungibleBucket(self.0.take_all())
268 }
269
270 fn take_advanced<A: Into<Decimal>>(
271 &mut self,
272 amount: A,
273 withdraw_strategy: WithdrawStrategy,
274 ) -> Self::BucketType {
275 FungibleBucket(self.0.take_advanced(amount, withdraw_strategy))
276 }
277
278 fn burn<A: Into<Decimal>>(&mut self, amount: A) {
279 self.0.burn(amount)
280 }
281}
282
283impl ScryptoFungibleVault for FungibleVault {
284 fn lock_fee<A: Into<Decimal>>(&mut self, amount: A) {
288 let _rtn = ScryptoVmV1Api::object_call(
289 self.0 .0.as_node_id(),
290 FUNGIBLE_VAULT_LOCK_FEE_IDENT,
291 scrypto_encode(&FungibleVaultLockFeeInput {
292 amount: amount.into(),
293 contingent: false,
294 })
295 .unwrap(),
296 );
297 }
298
299 fn lock_contingent_fee<A: Into<Decimal>>(&mut self, amount: A) {
304 let _rtn = ScryptoVmV1Api::object_call(
305 self.0 .0.as_node_id(),
306 FUNGIBLE_VAULT_LOCK_FEE_IDENT,
307 scrypto_encode(&FungibleVaultLockFeeInput {
308 amount: amount.into(),
309 contingent: true,
310 })
311 .unwrap(),
312 );
313 }
314
315 fn create_proof_of_amount<A: Into<Decimal>>(&self, amount: A) -> FungibleProof {
316 let rtn = ScryptoVmV1Api::object_call(
317 self.0 .0.as_node_id(),
318 FUNGIBLE_VAULT_CREATE_PROOF_OF_AMOUNT_IDENT,
319 scrypto_encode(&FungibleVaultCreateProofOfAmountInput {
320 amount: amount.into(),
321 })
322 .unwrap(),
323 );
324 scrypto_decode(&rtn).unwrap()
325 }
326
327 fn authorize_with_amount<A: Into<Decimal>, F: FnOnce() -> O, O>(&self, amount: A, f: F) -> O {
328 LocalAuthZone::push(self.create_proof_of_amount(amount));
329 let output = f();
330 LocalAuthZone::pop()
331 .expect("Authorized closure changed auth zone proof stack")
332 .drop();
333 output
334 }
335}
336
337impl ScryptoVault for NonFungibleVault {
342 type BucketType = NonFungibleBucket;
343 type ResourceManagerType = NonFungibleResourceManager;
344
345 fn with_bucket(bucket: Self::BucketType) -> Self {
346 Self(Vault::with_bucket(bucket.0))
347 }
348
349 fn new(resource_address: ResourceAddress) -> Self {
350 assert!(resource_address
351 .as_node_id()
352 .is_global_non_fungible_resource_manager());
353 Self(Vault::new(resource_address))
354 }
355
356 fn put(&mut self, bucket: Self::BucketType) -> () {
357 self.0.put(bucket.0)
358 }
359
360 fn amount(&self) -> Decimal {
361 self.0.amount()
362 }
363
364 fn resource_address(&self) -> ResourceAddress {
365 self.0.resource_address()
366 }
367
368 fn resource_manager(&self) -> Self::ResourceManagerType {
369 self.resource_address().into()
370 }
371
372 fn is_empty(&self) -> bool {
373 self.0.is_empty()
374 }
375
376 fn take<A: Into<Decimal>>(&mut self, amount: A) -> Self::BucketType {
377 NonFungibleBucket(self.0.take(amount))
378 }
379
380 fn take_all(&mut self) -> Self::BucketType {
381 NonFungibleBucket(self.0.take_all())
382 }
383
384 fn take_advanced<A: Into<Decimal>>(
385 &mut self,
386 amount: A,
387 withdraw_strategy: WithdrawStrategy,
388 ) -> Self::BucketType {
389 NonFungibleBucket(self.0.take_advanced(amount, withdraw_strategy))
390 }
391
392 fn burn<A: Into<Decimal>>(&mut self, amount: A) {
393 self.0.burn(amount)
394 }
395}
396
397impl ScryptoNonFungibleVault for NonFungibleVault {
398 fn non_fungible_local_ids(&self, limit: u32) -> IndexSet<NonFungibleLocalId> {
399 let rtn = ScryptoVmV1Api::object_call(
400 self.0 .0.as_node_id(),
401 NON_FUNGIBLE_VAULT_GET_NON_FUNGIBLE_LOCAL_IDS_IDENT,
402 scrypto_encode(&NonFungibleVaultGetNonFungibleLocalIdsInput { limit }).unwrap(),
403 );
404 scrypto_decode(&rtn).unwrap()
405 }
406
407 fn contains_non_fungible(&self, id: &NonFungibleLocalId) -> bool {
408 let rtn = ScryptoVmV1Api::object_call(
409 self.0 .0.as_node_id(),
410 NON_FUNGIBLE_VAULT_CONTAINS_NON_FUNGIBLE_IDENT,
411 scrypto_encode(&NonFungibleVaultContainsNonFungibleInput { id: id.clone() }).unwrap(),
412 );
413 scrypto_decode(&rtn).unwrap()
414 }
415
416 fn non_fungibles<T: NonFungibleData>(&self, limit: u32) -> Vec<NonFungible<T>> {
421 let resource_address = self.0.resource_address();
422 self.non_fungible_local_ids(limit)
423 .iter()
424 .map(|id| NonFungible::from(NonFungibleGlobalId::new(resource_address, id.clone())))
425 .collect()
426 }
427
428 fn non_fungible_local_id(&self) -> NonFungibleLocalId {
433 let non_fungible_local_ids = self.non_fungible_local_ids(2);
434 if non_fungible_local_ids.len() != 1 {
435 panic!("Expecting singleton NFT vault");
436 }
437 non_fungible_local_ids.into_iter().next().unwrap()
438 }
439
440 fn non_fungible_global_id(&self) -> NonFungibleGlobalId {
445 NonFungibleGlobalId::new(self.resource_address(), self.non_fungible_local_id())
446 }
447
448 fn non_fungible<T: NonFungibleData>(&self) -> NonFungible<T> {
453 let non_fungibles = self.non_fungibles(2);
455 if non_fungibles.len() != 1 {
456 panic!("Expecting singleton NFT vault");
457 }
458 non_fungibles.into_iter().next().unwrap()
459 }
460
461 fn take_non_fungible(
466 &mut self,
467 non_fungible_local_id: &NonFungibleLocalId,
468 ) -> NonFungibleBucket {
469 self.take_non_fungibles(&indexset!(non_fungible_local_id.clone()))
470 }
471
472 fn take_non_fungibles(
473 &mut self,
474 non_fungible_local_ids: &IndexSet<NonFungibleLocalId>,
475 ) -> NonFungibleBucket {
476 let rtn = ScryptoVmV1Api::object_call(
477 self.0 .0.as_node_id(),
478 NON_FUNGIBLE_VAULT_TAKE_NON_FUNGIBLES_IDENT,
479 scrypto_encode(&NonFungibleVaultTakeNonFungiblesInput {
480 non_fungible_local_ids: non_fungible_local_ids.clone(),
481 })
482 .unwrap(),
483 );
484 scrypto_decode(&rtn).unwrap()
485 }
486
487 fn create_proof_of_non_fungibles(
488 &self,
489 ids: &IndexSet<NonFungibleLocalId>,
490 ) -> NonFungibleProof {
491 let rtn = ScryptoVmV1Api::object_call(
492 self.0 .0.as_node_id(),
493 NON_FUNGIBLE_VAULT_CREATE_PROOF_OF_NON_FUNGIBLES_IDENT,
494 scrypto_encode(&NonFungibleVaultCreateProofOfNonFungiblesInput { ids: ids.clone() })
495 .unwrap(),
496 );
497 scrypto_decode(&rtn).unwrap()
498 }
499
500 fn burn_non_fungibles(&mut self, non_fungible_local_ids: &IndexSet<NonFungibleLocalId>) {
501 let rtn = ScryptoVmV1Api::object_call(
502 self.0 .0.as_node_id(),
503 NON_FUNGIBLE_VAULT_BURN_NON_FUNGIBLES_IDENT,
504 scrypto_encode(&NonFungibleVaultBurnNonFungiblesInput {
505 non_fungible_local_ids: non_fungible_local_ids.clone(),
506 })
507 .unwrap(),
508 );
509 scrypto_decode(&rtn).unwrap()
510 }
511
512 fn authorize_with_non_fungibles<F: FnOnce() -> O, O>(
513 &self,
514 non_fungible_local_ids: &IndexSet<NonFungibleLocalId>,
515 f: F,
516 ) -> O {
517 LocalAuthZone::push(self.create_proof_of_non_fungibles(non_fungible_local_ids));
518 let output = f();
519 LocalAuthZone::pop()
520 .expect("Authorized closure changed auth zone proof stack")
521 .drop();
522 output
523 }
524}