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        Ok(scrypto_decode(&rtn).unwrap())
110    }
111
112    fn create<Y: SystemObjectApi<E>, E: SystemApiError>(
113        receiver: ResourceAddress,
114        api: &mut Y,
115    ) -> Result<Bucket, E> {
116        let rtn = api.call_method(
117            receiver.as_node_id(),
118            RESOURCE_MANAGER_CREATE_EMPTY_BUCKET_IDENT,
119            scrypto_encode(&ResourceManagerCreateEmptyBucketInput {}).unwrap(),
120        )?;
121        Ok(scrypto_decode(&rtn).unwrap())
122    }
123
124    fn amount<Y: SystemApi<E>, E: SystemApiError>(&self, api: &mut Y) -> Result<Decimal, E> {
125        let rtn = api.call_method(
126            self.0.as_node_id(),
127            BUCKET_GET_AMOUNT_IDENT,
128            scrypto_encode(&BucketGetAmountInput {}).unwrap(),
129        )?;
130
131        Ok(scrypto_decode(&rtn).unwrap())
132    }
133
134    fn put<Y: SystemApi<E>, E: SystemApiError>(&self, other: Self, api: &mut Y) -> Result<(), E> {
135        let _rtn = api.call_method(
136            self.0.as_node_id(),
137            BUCKET_PUT_IDENT,
138            scrypto_encode(&BucketPutInput { bucket: other }).unwrap(),
139        )?;
140
141        Ok(())
142    }
143
144    fn take<Y: SystemApi<E>, E: SystemApiError>(
145        &self,
146        amount: Decimal,
147        api: &mut Y,
148    ) -> Result<Bucket, E> {
149        let rtn = api.call_method(
150            self.0.as_node_id(),
151            BUCKET_TAKE_IDENT,
152            scrypto_encode(&BucketTakeInput { amount }).unwrap(),
153        )?;
154
155        Ok(scrypto_decode(&rtn).unwrap())
156    }
157
158    fn take_advanced<Y: SystemApi<E>, E: SystemApiError>(
159        &self,
160        amount: Decimal,
161        withdraw_strategy: WithdrawStrategy,
162        api: &mut Y,
163    ) -> Result<Bucket, E> {
164        let rtn = api.call_method(
165            self.0.as_node_id(),
166            BUCKET_TAKE_ADVANCED_IDENT,
167            scrypto_encode(&BucketTakeAdvancedInput {
168                amount,
169                withdraw_strategy,
170            })
171            .unwrap(),
172        )?;
173
174        Ok(scrypto_decode(&rtn).unwrap())
175    }
176
177    fn burn<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
178        let resource_address = self.resource_address(api)?;
179        ResourceManager(resource_address).burn(Bucket(self.0), api)
180    }
181
182    fn package_burn<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
183        let resource_address = self.resource_address(api)?;
184        ResourceManager(resource_address).package_burn(Bucket(self.0), api)
185    }
186
187    fn resource_address<Y: SystemApi<E>, E: SystemApiError>(
188        &self,
189        api: &mut Y,
190    ) -> Result<ResourceAddress, E> {
191        let resource_address = ResourceAddress::new_or_panic(
192            api.get_outer_object(self.0.as_node_id())?.as_node_id().0,
193        );
194
195        Ok(resource_address)
196    }
197
198    fn create_proof_of_all<Y: SystemApi<E>, E: SystemApiError>(
199        &self,
200        api: &mut Y,
201    ) -> Result<Proof, E> {
202        let rtn = api.call_method(
203            self.0.as_node_id(),
204            BUCKET_CREATE_PROOF_OF_ALL_IDENT,
205            scrypto_encode(&BucketCreateProofOfAllInput {}).unwrap(),
206        )?;
207        Ok(scrypto_decode(&rtn).unwrap())
208    }
209
210    fn resource_manager<Y: SystemApi<E>, E: SystemApiError>(
211        &self,
212        api: &mut Y,
213    ) -> Result<ResourceManager, E> {
214        Ok(ResourceManager(self.resource_address(api)?))
215    }
216
217    fn is_empty<Y: SystemApi<E>, E: SystemApiError>(&self, api: &mut Y) -> Result<bool, E> {
218        Ok(self.amount(api)?.is_zero())
219    }
220}
221
222pub trait SpecificBucket: AsRef<Bucket> + Into<Bucket> {
223    type ResourceManager: From<ResourceManager>;
224    type Proof: SpecializedProof;
225    fn from_bucket_of_correct_type(bucket: Bucket) -> Self;
226}
227
228impl SpecificBucket for NonFungibleBucket {
229    type ResourceManager = ResourceManager; // Change when we have a native NonFungibleResourceManager
230    type Proof = NonFungibleProof;
231
232    fn from_bucket_of_correct_type(bucket: Bucket) -> Self {
233        Self(bucket)
234    }
235}
236
237impl SpecificBucket for FungibleBucket {
238    type ResourceManager = ResourceManager; // Change when we have a native FungibleResourceManager
239    type Proof = FungibleProof;
240
241    fn from_bucket_of_correct_type(bucket: Bucket) -> Self {
242        Self(bucket)
243    }
244}
245
246impl<T: SpecificBucket> NativeBucket for T {
247    type Proof = <Self as SpecificBucket>::Proof;
248    type ResourceManager = <Self as SpecificBucket>::ResourceManager;
249
250    fn create<Y: SystemApi<E>, E: SystemApiError>(
251        receiver: ResourceAddress,
252        api: &mut Y,
253    ) -> Result<Self, E> {
254        Ok(Self::from_bucket_of_correct_type(Bucket::create(
255            receiver, api,
256        )?))
257    }
258
259    fn amount<Y: SystemApi<E>, E: SystemApiError>(&self, api: &mut Y) -> Result<Decimal, E> {
260        self.as_ref().amount(api)
261    }
262
263    fn put<Y: SystemApi<E>, E: SystemApiError>(&self, other: Self, api: &mut Y) -> Result<(), E> {
264        self.as_ref().put(other.into(), api)
265    }
266
267    fn take<Y: SystemApi<E>, E: SystemApiError>(
268        &self,
269        amount: Decimal,
270        api: &mut Y,
271    ) -> Result<Self, E>
272    where
273        Self: Sized,
274    {
275        let bucket = self.as_ref().take(amount, api)?;
276        Ok(Self::from_bucket_of_correct_type(bucket))
277    }
278
279    fn take_advanced<Y: SystemApi<E>, E: SystemApiError>(
280        &self,
281        amount: Decimal,
282        withdraw_strategy: WithdrawStrategy,
283        api: &mut Y,
284    ) -> Result<Self, E>
285    where
286        Self: Sized,
287    {
288        let bucket = self
289            .as_ref()
290            .take_advanced(amount, withdraw_strategy, api)?;
291        Ok(Self::from_bucket_of_correct_type(bucket))
292    }
293
294    fn burn<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
295        self.into().burn(api)
296    }
297
298    fn package_burn<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
299        self.into().package_burn(api)
300    }
301
302    fn resource_address<Y: SystemApi<E>, E: SystemApiError>(
303        &self,
304        api: &mut Y,
305    ) -> Result<ResourceAddress, E> {
306        self.as_ref().resource_address(api)
307    }
308
309    fn resource_manager<Y: SystemApi<E>, E: SystemApiError>(
310        &self,
311        api: &mut Y,
312    ) -> Result<Self::ResourceManager, E> {
313        Ok(self.as_ref().resource_manager(api)?.into())
314    }
315
316    fn create_proof_of_all<Y: SystemApi<E>, E: SystemApiError>(
317        &self,
318        api: &mut Y,
319    ) -> Result<Self::Proof, E> {
320        let proof = self.as_ref().create_proof_of_all(api)?;
321        Ok(<Self::Proof as SpecializedProof>::from_proof_of_correct_type(proof))
322    }
323
324    fn is_empty<Y: SystemApi<E>, E: SystemApiError>(&self, api: &mut Y) -> Result<bool, E> {
325        self.as_ref().is_empty(api)
326    }
327
328    fn drop_empty<Y: SystemApi<E>, E: SystemApiError>(self, api: &mut Y) -> Result<(), E> {
329        self.into().drop_empty(api)
330    }
331}
332
333impl NativeFungibleBucket for Bucket {
334    fn create_proof_of_amount<Y: SystemApi<E>, E: SystemApiError>(
335        &self,
336        amount: Decimal,
337        api: &mut Y,
338    ) -> Result<FungibleProof, E> {
339        let rtn = api.call_method(
340            self.0.as_node_id(),
341            FUNGIBLE_BUCKET_CREATE_PROOF_OF_AMOUNT_IDENT,
342            scrypto_encode(&FungibleBucketCreateProofOfAmountInput { amount }).unwrap(),
343        )?;
344        Ok(FungibleProof(scrypto_decode(&rtn).unwrap()))
345    }
346}
347
348impl NativeFungibleBucket for FungibleBucket {
349    fn create_proof_of_amount<Y: SystemApi<E>, E: SystemApiError>(
350        &self,
351        amount: Decimal,
352        api: &mut Y,
353    ) -> Result<FungibleProof, E> {
354        Ok(self.as_ref().create_proof_of_amount(amount, api)?.into())
355    }
356}
357
358impl NativeNonFungibleBucket for Bucket {
359    fn non_fungible_local_ids<Y: SystemApi<E>, E: SystemApiError>(
360        &self,
361        api: &mut Y,
362    ) -> Result<IndexSet<NonFungibleLocalId>, E> {
363        let rtn = api.call_method(
364            self.0.as_node_id(),
365            NON_FUNGIBLE_BUCKET_GET_NON_FUNGIBLE_LOCAL_IDS_IDENT,
366            scrypto_encode(&BucketGetNonFungibleLocalIdsInput {}).unwrap(),
367        )?;
368
369        Ok(scrypto_decode(&rtn).unwrap())
370    }
371
372    fn take_non_fungibles<Y: SystemApi<E>, E: SystemApiError>(
373        &self,
374        ids: IndexSet<NonFungibleLocalId>,
375        api: &mut Y,
376    ) -> Result<NonFungibleBucket, E> {
377        let rtn = api.call_method(
378            self.0.as_node_id(),
379            NON_FUNGIBLE_BUCKET_TAKE_NON_FUNGIBLES_IDENT,
380            scrypto_encode(&BucketTakeNonFungiblesInput { ids }).unwrap(),
381        )?;
382
383        Ok(scrypto_decode(&rtn).unwrap())
384    }
385
386    fn create_proof_of_non_fungibles<Y: SystemApi<E>, E: SystemApiError>(
387        &self,
388        ids: IndexSet<NonFungibleLocalId>,
389        api: &mut Y,
390    ) -> Result<NonFungibleProof, E> {
391        let rtn = api.call_method(
392            self.0.as_node_id(),
393            NON_FUNGIBLE_BUCKET_CREATE_PROOF_OF_NON_FUNGIBLES_IDENT,
394            scrypto_encode(&NonFungibleBucketCreateProofOfNonFungiblesInput { ids }).unwrap(),
395        )?;
396        Ok(scrypto_decode(&rtn).unwrap())
397    }
398}
399
400impl NativeNonFungibleBucket for NonFungibleBucket {
401    fn non_fungible_local_ids<Y: SystemApi<E>, E: SystemApiError>(
402        &self,
403        api: &mut Y,
404    ) -> Result<IndexSet<NonFungibleLocalId>, E> {
405        self.as_ref().non_fungible_local_ids(api)
406    }
407
408    fn take_non_fungibles<Y: SystemApi<E>, E: SystemApiError>(
409        &self,
410        ids: IndexSet<NonFungibleLocalId>,
411        api: &mut Y,
412    ) -> Result<NonFungibleBucket, E> {
413        self.as_ref().take_non_fungibles(ids, api)
414    }
415
416    fn create_proof_of_non_fungibles<Y: SystemApi<E>, E: SystemApiError>(
417        &self,
418        ids: IndexSet<NonFungibleLocalId>,
419        api: &mut Y,
420    ) -> Result<NonFungibleProof, E> {
421        self.as_ref().create_proof_of_non_fungibles(ids, api)
422    }
423}