radix_native_sdk/resource/
bucket.rs

1use radix_common::data::scrypto::model::*;
2use radix_common::data::scrypto::{scrypto_decode, scrypto_encode};
3use radix_common::math::Decimal;
4use radix_engine_interface::api::*;
5use radix_engine_interface::blueprints::resource::*;
6use radix_engine_interface::types::*;
7use sbor::rust::collections::IndexSet;
8
9use super::{ResourceManager, SpecializedProof};
10
11// TODO: Move the fungible/non-fungible parts out of NativeBucket,
12//       and require the user opt in with `as_fungible` / `as_non_fungible` like in Scrypto.
13//       This will be a breaking change, so likely need some communication.
14
15pub trait NativeBucket {
16    type ResourceManager;
17    type Proof;
18
19    fn create<Y: SystemApi<E>, E: SystemApiError>(
20        receiver: ResourceAddress,
21        api: &mut Y,
22    ) -> Result<Self, E>
23    where
24        Self: Sized;
25
26    fn amount<Y: SystemApi<E>, E: SystemApiError>(&self, api: &mut Y) -> Result<Decimal, E>;
27
28    fn put<Y: SystemApi<E>, E: SystemApiError>(&self, other: Self, api: &mut Y) -> Result<(), E>;
29
30    fn take<Y: SystemApi<E>, E: SystemApiError>(
31        &self,
32        amount: Decimal,
33        api: &mut Y,
34    ) -> Result<Self, E>
35    where
36        Self: Sized;
37
38    fn take_advanced<Y: SystemApi<E>, E: SystemApiError>(
39        &self,
40        amount: Decimal,
41        withdraw_strategy: WithdrawStrategy,
42        api: &mut Y,
43    ) -> Result<Self, E>
44    where
45        Self: Sized;
46
47    fn burn<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E>;
48
49    fn package_burn<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E>;
50
51    fn resource_address<Y: SystemApi<E>, E: SystemApiError>(
52        &self,
53        api: &mut Y,
54    ) -> Result<ResourceAddress, E>;
55
56    fn resource_manager<Y: SystemApi<E>, E: SystemApiError>(
57        &self,
58        api: &mut Y,
59    ) -> Result<Self::ResourceManager, E>;
60
61    fn create_proof_of_all<Y: SystemApi<E>, E: SystemApiError>(
62        &self,
63        api: &mut Y,
64    ) -> Result<Self::Proof, E>;
65
66    fn is_empty<Y: SystemApi<E>, E: SystemApiError>(&self, api: &mut Y) -> Result<bool, E>;
67
68    fn drop_empty<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E>;
69}
70
71pub trait NativeFungibleBucket {
72    fn create_proof_of_amount<Y: SystemApi<E>, E: SystemApiError>(
73        &self,
74        amount: Decimal,
75        api: &mut Y,
76    ) -> Result<FungibleProof, E>;
77}
78
79pub trait NativeNonFungibleBucket {
80    fn non_fungible_local_ids<Y: SystemApi<E>, E: SystemApiError>(
81        &self,
82        api: &mut Y,
83    ) -> Result<IndexSet<NonFungibleLocalId>, E>;
84
85    fn take_non_fungibles<Y: SystemApi<E>, E: SystemApiError>(
86        &self,
87        ids: IndexSet<NonFungibleLocalId>,
88        api: &mut Y,
89    ) -> Result<NonFungibleBucket, E>;
90
91    fn create_proof_of_non_fungibles<Y: SystemApi<E>, E: SystemApiError>(
92        &self,
93        ids: IndexSet<NonFungibleLocalId>,
94        api: &mut Y,
95    ) -> Result<NonFungibleProof, E>;
96}
97
98impl NativeBucket for Bucket {
99    type ResourceManager = ResourceManager;
100    type Proof = Proof;
101
102    fn drop_empty<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
103        let resource_address = self.resource_address(api)?;
104        let rtn = api.call_method(
105            resource_address.as_node_id(),
106            RESOURCE_MANAGER_DROP_EMPTY_BUCKET_IDENT,
107            scrypto_encode(&ResourceManagerDropEmptyBucketInput { bucket: self }).unwrap(),
108        )?;
109        let _: () = scrypto_decode(&rtn).unwrap();
110        Ok(())
111    }
112
113    fn create<Y: SystemObjectApi<E>, E: SystemApiError>(
114        receiver: ResourceAddress,
115        api: &mut Y,
116    ) -> Result<Bucket, E> {
117        let rtn = api.call_method(
118            receiver.as_node_id(),
119            RESOURCE_MANAGER_CREATE_EMPTY_BUCKET_IDENT,
120            scrypto_encode(&ResourceManagerCreateEmptyBucketInput {}).unwrap(),
121        )?;
122        Ok(scrypto_decode(&rtn).unwrap())
123    }
124
125    fn amount<Y: SystemApi<E>, E: SystemApiError>(&self, api: &mut Y) -> Result<Decimal, E> {
126        let rtn = api.call_method(
127            self.0.as_node_id(),
128            BUCKET_GET_AMOUNT_IDENT,
129            scrypto_encode(&BucketGetAmountInput {}).unwrap(),
130        )?;
131
132        Ok(scrypto_decode(&rtn).unwrap())
133    }
134
135    fn put<Y: SystemApi<E>, E: SystemApiError>(&self, other: Self, api: &mut Y) -> Result<(), E> {
136        let _rtn = api.call_method(
137            self.0.as_node_id(),
138            BUCKET_PUT_IDENT,
139            scrypto_encode(&BucketPutInput { bucket: other }).unwrap(),
140        )?;
141
142        Ok(())
143    }
144
145    fn take<Y: SystemApi<E>, E: SystemApiError>(
146        &self,
147        amount: Decimal,
148        api: &mut Y,
149    ) -> Result<Bucket, E> {
150        let rtn = api.call_method(
151            self.0.as_node_id(),
152            BUCKET_TAKE_IDENT,
153            scrypto_encode(&BucketTakeInput { amount }).unwrap(),
154        )?;
155
156        Ok(scrypto_decode(&rtn).unwrap())
157    }
158
159    fn take_advanced<Y: SystemApi<E>, E: SystemApiError>(
160        &self,
161        amount: Decimal,
162        withdraw_strategy: WithdrawStrategy,
163        api: &mut Y,
164    ) -> Result<Bucket, E> {
165        let rtn = api.call_method(
166            self.0.as_node_id(),
167            BUCKET_TAKE_ADVANCED_IDENT,
168            scrypto_encode(&BucketTakeAdvancedInput {
169                amount,
170                withdraw_strategy,
171            })
172            .unwrap(),
173        )?;
174
175        Ok(scrypto_decode(&rtn).unwrap())
176    }
177
178    fn burn<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
179        let resource_address = self.resource_address(api)?;
180        ResourceManager(resource_address).burn(Bucket(self.0), api)
181    }
182
183    fn package_burn<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
184        let resource_address = self.resource_address(api)?;
185        ResourceManager(resource_address).package_burn(Bucket(self.0), api)
186    }
187
188    fn resource_address<Y: SystemApi<E>, E: SystemApiError>(
189        &self,
190        api: &mut Y,
191    ) -> Result<ResourceAddress, E> {
192        let resource_address = ResourceAddress::new_or_panic(
193            api.get_outer_object(self.0.as_node_id())?.as_node_id().0,
194        );
195
196        Ok(resource_address)
197    }
198
199    fn create_proof_of_all<Y: SystemApi<E>, E: SystemApiError>(
200        &self,
201        api: &mut Y,
202    ) -> Result<Proof, E> {
203        let rtn = api.call_method(
204            self.0.as_node_id(),
205            BUCKET_CREATE_PROOF_OF_ALL_IDENT,
206            scrypto_encode(&BucketCreateProofOfAllInput {}).unwrap(),
207        )?;
208        Ok(scrypto_decode(&rtn).unwrap())
209    }
210
211    fn resource_manager<Y: SystemApi<E>, E: SystemApiError>(
212        &self,
213        api: &mut Y,
214    ) -> Result<ResourceManager, E> {
215        Ok(ResourceManager(self.resource_address(api)?))
216    }
217
218    fn is_empty<Y: SystemApi<E>, E: SystemApiError>(&self, api: &mut Y) -> Result<bool, E> {
219        Ok(self.amount(api)?.is_zero())
220    }
221}
222
223pub trait SpecificBucket: AsRef<Bucket> + Into<Bucket> {
224    type ResourceManager: From<ResourceManager>;
225    type Proof: SpecializedProof;
226    fn from_bucket_of_correct_type(bucket: Bucket) -> Self;
227}
228
229impl SpecificBucket for NonFungibleBucket {
230    type ResourceManager = ResourceManager; // Change when we have a native NonFungibleResourceManager
231    type Proof = NonFungibleProof;
232
233    fn from_bucket_of_correct_type(bucket: Bucket) -> Self {
234        Self(bucket)
235    }
236}
237
238impl SpecificBucket for FungibleBucket {
239    type ResourceManager = ResourceManager; // Change when we have a native FungibleResourceManager
240    type Proof = FungibleProof;
241
242    fn from_bucket_of_correct_type(bucket: Bucket) -> Self {
243        Self(bucket)
244    }
245}
246
247impl<T: SpecificBucket> NativeBucket for T {
248    type Proof = <Self as SpecificBucket>::Proof;
249    type ResourceManager = <Self as SpecificBucket>::ResourceManager;
250
251    fn create<Y: SystemApi<E>, E: SystemApiError>(
252        receiver: ResourceAddress,
253        api: &mut Y,
254    ) -> Result<Self, E> {
255        Ok(Self::from_bucket_of_correct_type(Bucket::create(
256            receiver, api,
257        )?))
258    }
259
260    fn amount<Y: SystemApi<E>, E: SystemApiError>(&self, api: &mut Y) -> Result<Decimal, E> {
261        self.as_ref().amount(api)
262    }
263
264    fn put<Y: SystemApi<E>, E: SystemApiError>(&self, other: Self, api: &mut Y) -> Result<(), E> {
265        self.as_ref().put(other.into(), api)
266    }
267
268    fn take<Y: SystemApi<E>, E: SystemApiError>(
269        &self,
270        amount: Decimal,
271        api: &mut Y,
272    ) -> Result<Self, E>
273    where
274        Self: Sized,
275    {
276        let bucket = self.as_ref().take(amount, api)?;
277        Ok(Self::from_bucket_of_correct_type(bucket))
278    }
279
280    fn take_advanced<Y: SystemApi<E>, E: SystemApiError>(
281        &self,
282        amount: Decimal,
283        withdraw_strategy: WithdrawStrategy,
284        api: &mut Y,
285    ) -> Result<Self, E>
286    where
287        Self: Sized,
288    {
289        let bucket = self
290            .as_ref()
291            .take_advanced(amount, withdraw_strategy, api)?;
292        Ok(Self::from_bucket_of_correct_type(bucket))
293    }
294
295    fn burn<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
296        self.into().burn(api)
297    }
298
299    fn package_burn<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
300        self.into().package_burn(api)
301    }
302
303    fn resource_address<Y: SystemApi<E>, E: SystemApiError>(
304        &self,
305        api: &mut Y,
306    ) -> Result<ResourceAddress, E> {
307        self.as_ref().resource_address(api)
308    }
309
310    fn resource_manager<Y: SystemApi<E>, E: SystemApiError>(
311        &self,
312        api: &mut Y,
313    ) -> Result<Self::ResourceManager, E> {
314        Ok(self.as_ref().resource_manager(api)?.into())
315    }
316
317    fn create_proof_of_all<Y: SystemApi<E>, E: SystemApiError>(
318        &self,
319        api: &mut Y,
320    ) -> Result<Self::Proof, E> {
321        let proof = self.as_ref().create_proof_of_all(api)?;
322        Ok(<Self::Proof as SpecializedProof>::from_proof_of_correct_type(proof))
323    }
324
325    fn is_empty<Y: SystemApi<E>, E: SystemApiError>(&self, api: &mut Y) -> Result<bool, E> {
326        self.as_ref().is_empty(api)
327    }
328
329    fn drop_empty<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
330        self.into().drop_empty(api)
331    }
332}
333
334impl NativeFungibleBucket for Bucket {
335    fn create_proof_of_amount<Y: SystemApi<E>, E: SystemApiError>(
336        &self,
337        amount: Decimal,
338        api: &mut Y,
339    ) -> Result<FungibleProof, E> {
340        let rtn = api.call_method(
341            self.0.as_node_id(),
342            FUNGIBLE_BUCKET_CREATE_PROOF_OF_AMOUNT_IDENT,
343            scrypto_encode(&FungibleBucketCreateProofOfAmountInput { amount }).unwrap(),
344        )?;
345        Ok(FungibleProof(scrypto_decode(&rtn).unwrap()))
346    }
347}
348
349impl NativeFungibleBucket for FungibleBucket {
350    fn create_proof_of_amount<Y: SystemApi<E>, E: SystemApiError>(
351        &self,
352        amount: Decimal,
353        api: &mut Y,
354    ) -> Result<FungibleProof, E> {
355        self.as_ref().create_proof_of_amount(amount, api)
356    }
357}
358
359impl NativeNonFungibleBucket for Bucket {
360    fn non_fungible_local_ids<Y: SystemApi<E>, E: SystemApiError>(
361        &self,
362        api: &mut Y,
363    ) -> Result<IndexSet<NonFungibleLocalId>, E> {
364        let rtn = api.call_method(
365            self.0.as_node_id(),
366            NON_FUNGIBLE_BUCKET_GET_NON_FUNGIBLE_LOCAL_IDS_IDENT,
367            scrypto_encode(&BucketGetNonFungibleLocalIdsInput {}).unwrap(),
368        )?;
369
370        Ok(scrypto_decode(&rtn).unwrap())
371    }
372
373    fn take_non_fungibles<Y: SystemApi<E>, E: SystemApiError>(
374        &self,
375        ids: IndexSet<NonFungibleLocalId>,
376        api: &mut Y,
377    ) -> Result<NonFungibleBucket, E> {
378        let rtn = api.call_method(
379            self.0.as_node_id(),
380            NON_FUNGIBLE_BUCKET_TAKE_NON_FUNGIBLES_IDENT,
381            scrypto_encode(&BucketTakeNonFungiblesInput { ids }).unwrap(),
382        )?;
383
384        Ok(scrypto_decode(&rtn).unwrap())
385    }
386
387    fn create_proof_of_non_fungibles<Y: SystemApi<E>, E: SystemApiError>(
388        &self,
389        ids: IndexSet<NonFungibleLocalId>,
390        api: &mut Y,
391    ) -> Result<NonFungibleProof, E> {
392        let rtn = api.call_method(
393            self.0.as_node_id(),
394            NON_FUNGIBLE_BUCKET_CREATE_PROOF_OF_NON_FUNGIBLES_IDENT,
395            scrypto_encode(&NonFungibleBucketCreateProofOfNonFungiblesInput { ids }).unwrap(),
396        )?;
397        Ok(scrypto_decode(&rtn).unwrap())
398    }
399}
400
401impl NativeNonFungibleBucket for NonFungibleBucket {
402    fn non_fungible_local_ids<Y: SystemApi<E>, E: SystemApiError>(
403        &self,
404        api: &mut Y,
405    ) -> Result<IndexSet<NonFungibleLocalId>, E> {
406        self.as_ref().non_fungible_local_ids(api)
407    }
408
409    fn take_non_fungibles<Y: SystemApi<E>, E: SystemApiError>(
410        &self,
411        ids: IndexSet<NonFungibleLocalId>,
412        api: &mut Y,
413    ) -> Result<NonFungibleBucket, E> {
414        self.as_ref().take_non_fungibles(ids, api)
415    }
416
417    fn create_proof_of_non_fungibles<Y: SystemApi<E>, E: SystemApiError>(
418        &self,
419        ids: IndexSet<NonFungibleLocalId>,
420        api: &mut Y,
421    ) -> Result<NonFungibleProof, E> {
422        self.as_ref().create_proof_of_non_fungibles(ids, api)
423    }
424}