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