scrypto_test/sdk/resource/
bucket_factory.rs1use crate::prelude::*;
2
3pub struct BucketFactory;
5
6impl BucketFactory {
7 pub fn create_fungible_bucket<S>(
8 resource_address: ResourceAddress,
9 amount: Decimal,
10 creation_strategy: CreationStrategy,
11 env: &mut TestEnvironment<S>,
12 ) -> Result<FungibleBucket, RuntimeError>
13 where
14 S: SubstateDatabase + CommittableSubstateDatabase + 'static,
15 {
16 let bucket = Self::create_bucket(
17 FactoryResourceSpecifier::Amount(resource_address, amount),
18 creation_strategy,
19 env,
20 )?;
21 Ok(FungibleBucket(bucket))
22 }
23
24 pub fn create_non_fungible_bucket<I, D, S>(
25 resource_address: ResourceAddress,
26 non_fungibles: I,
27 creation_strategy: CreationStrategy,
28 env: &mut TestEnvironment<S>,
29 ) -> Result<NonFungibleBucket, RuntimeError>
30 where
31 I: IntoIterator<Item = (NonFungibleLocalId, D)>,
32 D: ScryptoEncode,
33 S: SubstateDatabase + CommittableSubstateDatabase + 'static,
34 {
35 let bucket = Self::create_bucket(
36 FactoryResourceSpecifier::Ids(
37 resource_address,
38 non_fungibles
39 .into_iter()
40 .map(|(id, data)| {
41 (
42 id,
43 scrypto_decode::<ScryptoValue>(&scrypto_encode(&data).unwrap())
44 .unwrap(),
45 )
46 })
47 .collect(),
48 ),
49 creation_strategy,
50 env,
51 )?;
52 Ok(NonFungibleBucket(bucket))
53 }
54
55 pub fn create_bucket<S>(
56 resource_specifier: FactoryResourceSpecifier,
57 creation_strategy: CreationStrategy,
58 env: &mut TestEnvironment<S>,
59 ) -> Result<Bucket, RuntimeError>
60 where
61 S: SubstateDatabase + CommittableSubstateDatabase + 'static,
62 {
63 match (&resource_specifier, creation_strategy) {
64 (
65 FactoryResourceSpecifier::Amount(resource_address, amount),
66 CreationStrategy::DisableAuthAndMint,
67 ) => env.with_auth_module_disabled(|env| {
68 let bucket = ResourceManager(*resource_address).mint_fungible(*amount, env)?;
69 Ok(bucket.into())
70 }),
71 (
72 FactoryResourceSpecifier::Ids(resource_address, ids),
73 CreationStrategy::DisableAuthAndMint,
74 ) => env.with_auth_module_disabled(|env| {
75 let bucket = ResourceManager(*resource_address).mint_non_fungible(ids.clone(), env)?;
76 Ok(bucket.into())
77 }),
78 (
79 FactoryResourceSpecifier::Amount(resource_address, amount),
80 CreationStrategy::Mock,
81 ) => env.with_auth_module_disabled(|env| {
82 assert!(Self::validate_resource_specifier(&resource_specifier, env)?);
83
84 env.as_method_actor(
85 resource_address.into_node_id(),
86 ModuleId::Main,
87 FUNGIBLE_RESOURCE_MANAGER_MINT_IDENT,
88 |env| {
89 env.new_simple_object(
90 FUNGIBLE_BUCKET_BLUEPRINT,
91 indexmap!(
92 FungibleBucketField::Liquid.into() => FieldValue::new(LiquidFungibleResource::new(*amount)),
93 FungibleBucketField::Locked.into() => FieldValue::new(LockedFungibleResource::default()),
94 )
95 ).map(|node_id| Bucket(Own(node_id)))
96 },
97 )?
98 }),
99 (
100 FactoryResourceSpecifier::Ids(resource_address, non_fungibles),
101 CreationStrategy::Mock,
102 ) => env.with_auth_module_disabled(|env| {
103 assert!(Self::validate_resource_specifier(&resource_specifier, env)?);
104
105 env.as_method_actor(
106 resource_address.into_node_id(),
107 ModuleId::Main,
108 NON_FUNGIBLE_RESOURCE_MANAGER_MINT_IDENT,
109 |env| {
110 for (local_id, data) in non_fungibles.iter() {
111 let non_fungible_handle = env.actor_open_key_value_entry(
112 ACTOR_STATE_SELF,
113 NonFungibleResourceManagerCollection::DataKeyValue.collection_index(),
114 &local_id.to_key(),
115 LockFlags::MUTABLE,
116 )?;
117
118 let cur_non_fungible = env
119 .key_value_entry_get_typed::<NonFungibleResourceManagerDataEntryPayload>(
120 non_fungible_handle,
121 )?;
122
123 if cur_non_fungible.is_some() {
124 return Err(RuntimeError::ApplicationError(
125 ApplicationError::NonFungibleResourceManagerError(
126 NonFungibleResourceManagerError::NonFungibleAlreadyExists(Box::new(
127 NonFungibleGlobalId::new(*resource_address, local_id.clone()),
128 )),
129 ),
130 ));
131 }
132
133 env.key_value_entry_set_typed(
134 non_fungible_handle,
135 NonFungibleResourceManagerDataEntryPayload::from_content_source(data.clone()),
136 )?;
137 env.key_value_entry_close(non_fungible_handle)?;
138 }
139
140 env.new_simple_object(
141 NON_FUNGIBLE_BUCKET_BLUEPRINT,
142 indexmap!(
143 NonFungibleBucketField::Liquid.into() => FieldValue::new(LiquidNonFungibleResource::new(non_fungibles.keys().cloned().collect())),
144 NonFungibleBucketField::Locked.into() => FieldValue::new(LockedNonFungibleResource::default()),
145 )
146 ).map(|node_id| Bucket(Own(node_id)))
147 },
148 )?
149 }),
150 }
151 }
152
153 fn validate_resource_specifier<S>(
154 resource_specifier: &FactoryResourceSpecifier,
155 env: &mut TestEnvironment<S>,
156 ) -> Result<bool, RuntimeError>
157 where
158 S: SubstateDatabase + CommittableSubstateDatabase + 'static,
159 {
160 match resource_specifier {
163 FactoryResourceSpecifier::Amount(resource_address, ..)
164 if resource_address.is_fungible() =>
165 {
166 }
168 FactoryResourceSpecifier::Ids(resource_address, non_fungibles)
169 if !resource_address.is_fungible() =>
170 {
171 let id_type = {
177 let mut iter = non_fungibles
178 .keys()
179 .map(|id| id.id_type())
180 .collect::<IndexSet<NonFungibleIdType>>()
181 .into_iter();
182 let Some(id_type) = iter.next() else {
183 return Ok(true);
184 };
185 if iter.next().is_some() {
186 return Ok(false);
187 }
188 id_type
189 };
190
191 let ResourceType::NonFungible {
192 id_type: expected_id_type,
193 } = ResourceManager(*resource_address).resource_type(env)?
194 else {
195 return Ok(false);
196 };
197
198 if id_type != expected_id_type {
199 return Ok(false);
200 }
201 }
202 _ => return Ok(false),
203 }
204 Ok(true)
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211
212 #[test]
213 fn verify_validate_resource_specifier_method() {
214 let mut env = TestEnvironment::new();
216 let bucket = ResourceBuilder::new_integer_non_fungible::<()>(OwnerRole::None)
217 .mint_initial_supply([], &mut env)
218 .unwrap();
219
220 let items = indexmap!(
221 NonFungibleLocalId::integer(1u64) => SborValue::U8 { value: 1 },
222 NonFungibleLocalId::integer(2u64) => SborValue::U8 { value: 2 },
223 );
224
225 let resource =
226 FactoryResourceSpecifier::Ids(bucket.resource_address(&mut env).unwrap(), items);
227
228 let result = BucketFactory::validate_resource_specifier(&resource, &mut env).unwrap();
230
231 assert!(result);
233 }
234
235 #[test]
236 fn verify_validate_resource_specifier_method_should_fail() {
237 let mut env = TestEnvironment::new();
239 let bucket = ResourceBuilder::new_integer_non_fungible::<()>(OwnerRole::None)
240 .mint_initial_supply([], &mut env)
241 .unwrap();
242
243 let items = indexmap!(
244 NonFungibleLocalId::integer(1u64) => SborValue::U8 { value: 1 },
245 NonFungibleLocalId::string("value").unwrap() => SborValue::U8 { value: 2 },
246 );
247
248 let resource =
249 FactoryResourceSpecifier::Ids(bucket.resource_address(&mut env).unwrap(), items);
250
251 let result = BucketFactory::validate_resource_specifier(&resource, &mut env).unwrap();
253
254 assert!(!result);
256 }
257}