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
11pub 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; 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; 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}