1use radix_common::prelude::*;
7use radix_engine_interface::prelude::*;
8use radix_transactions::data::{from_decimal, from_non_fungible_local_id, from_precise_decimal};
9use radix_transactions::prelude::*;
10
11use super::{parse_resource_specifier, ResourceSpecifier};
12
13#[derive(Debug, Clone)]
15pub enum BuildCallInstructionError {
16 FunctionNotFound(String),
18
19 MethodNotFound(String),
21
22 FailedToBuildArguments(BuildCallArgumentsError),
24
25 FailedToExportFunctionSchema(PackageAddress, String, String),
27
28 FailedToExportMethodSchema(ComponentAddress, String),
30
31 AccountNotProvided,
33}
34
35#[derive(Debug, Clone)]
37pub enum BuildCallArgumentsError {
38 WrongNumberOfArguments(usize, usize),
39 BuildCallArgumentError(BuildCallArgumentError),
40 RustToManifestValueError(RustToManifestValueError),
41}
42
43#[derive(Debug, Clone)]
45pub enum BuildCallArgumentError {
46 UnsupportedType(ScryptoTypeKind<LocalTypeId>),
48
49 FailedToParse(String),
51
52 InvalidResourceSpecifier(String),
54}
55
56impl From<BuildCallArgumentsError> for BuildCallInstructionError {
57 fn from(error: BuildCallArgumentsError) -> Self {
58 Self::FailedToBuildArguments(error)
59 }
60}
61
62impl From<BuildCallArgumentError> for BuildCallArgumentsError {
63 fn from(error: BuildCallArgumentError) -> Self {
64 Self::BuildCallArgumentError(error)
65 }
66}
67
68impl From<RustToManifestValueError> for BuildCallArgumentsError {
69 fn from(error: RustToManifestValueError) -> Self {
70 Self::RustToManifestValueError(error)
71 }
72}
73
74pub fn create_proof_from_account(
76 builder: ManifestBuilder,
77 address_bech32_decoder: &AddressBech32Decoder,
78 account: ComponentAddress,
79 resource_specifier: String,
80) -> Result<ManifestBuilder, BuildCallArgumentError> {
81 let resource_specifier = parse_resource_specifier(&resource_specifier, address_bech32_decoder)
82 .map_err(|_| BuildCallArgumentError::InvalidResourceSpecifier(resource_specifier))?;
83 let builder = match resource_specifier {
84 ResourceSpecifier::Amount(amount, resource_address) => {
85 builder.create_proof_from_account_of_amount(account, resource_address, amount)
86 }
87 ResourceSpecifier::Ids(non_fungible_local_ids, resource_address) => builder
88 .create_proof_from_account_of_non_fungibles(
89 account,
90 resource_address,
91 non_fungible_local_ids,
92 ),
93 };
94 Ok(builder)
95}
96
97pub fn build_call_arguments(
98 mut builder: ManifestBuilder,
99 address_bech32_decoder: &AddressBech32Decoder,
100 schema: &VersionedScryptoSchema,
101 type_id: LocalTypeId,
102 args: Vec<String>,
103 account: Option<ComponentAddress>,
104) -> Result<(ManifestBuilder, ManifestValue), BuildCallArgumentsError> {
105 let mut built_args = Vec::<ManifestValue>::new();
106 match schema.v1().resolve_type_kind(type_id) {
107 Some(TypeKind::Tuple { field_types }) => {
108 if args.len() != field_types.len() {
109 return Err(BuildCallArgumentsError::WrongNumberOfArguments(
110 args.len(),
111 field_types.len(),
112 ));
113 }
114
115 for (i, f) in field_types.iter().enumerate() {
116 let (returned_builder, value) = build_call_argument(
117 builder,
118 address_bech32_decoder,
119 schema
120 .v1()
121 .resolve_type_kind(*f)
122 .expect("Inconsistent schema"),
123 schema
124 .v1()
125 .resolve_type_validation(*f)
126 .expect("Inconsistent schema"),
127 args[i].clone(),
128 account,
129 )?;
130 builder = returned_builder;
131 built_args.push(value);
132 }
133 }
134 _ => panic!("Inconsistent schema"),
135 }
136 let manifest_value = to_manifest_value(&ManifestValue::Tuple { fields: built_args })?;
137 Ok((builder, manifest_value))
138}
139
140macro_rules! parse_basic_type {
141 ($builder:expr, $argument:expr, $type:tt) => {
142 Ok((
143 $builder,
144 ManifestValue::$type {
145 value: $argument
146 .parse()
147 .map_err(|_| BuildCallArgumentError::FailedToParse($argument))?,
148 },
149 ))
150 };
151}
152
153macro_rules! matches_bucket {
154 ($type_validation:expr) => {
155 matches!(
156 $type_validation,
157 TypeValidation::Custom(
158 ScryptoCustomTypeValidation::Own(OwnValidation::IsBucket)
159 )
160 )
161 };
162 ($type_validation:expr, $bucket_blueprint:expr) => {
163 matches!(
164 $type_validation,
165 TypeValidation::Custom(
166 ScryptoCustomTypeValidation::Own(
167 OwnValidation::IsTypedObject(Some(RESOURCE_PACKAGE), blueprint)
168 )
169 ) if blueprint == $bucket_blueprint
170 )
171 };
172}
173
174fn build_call_argument(
175 mut builder: ManifestBuilder,
176 address_bech32_decoder: &AddressBech32Decoder,
177 type_kind: &ScryptoTypeKind<LocalTypeId>,
178 type_validation: &TypeValidation<ScryptoCustomTypeValidation>,
179 argument: String,
180 account: Option<ComponentAddress>,
181) -> Result<(ManifestBuilder, ManifestValue), BuildCallArgumentError> {
182 match type_kind {
183 ScryptoTypeKind::Bool => parse_basic_type!(builder, argument, Bool),
184 ScryptoTypeKind::I8 => parse_basic_type!(builder, argument, I8),
185 ScryptoTypeKind::I16 => parse_basic_type!(builder, argument, I16),
186 ScryptoTypeKind::I32 => parse_basic_type!(builder, argument, I32),
187 ScryptoTypeKind::I64 => parse_basic_type!(builder, argument, I64),
188 ScryptoTypeKind::I128 => parse_basic_type!(builder, argument, I128),
189 ScryptoTypeKind::U8 => parse_basic_type!(builder, argument, U8),
190 ScryptoTypeKind::U16 => parse_basic_type!(builder, argument, U16),
191 ScryptoTypeKind::U32 => parse_basic_type!(builder, argument, U32),
192 ScryptoTypeKind::U64 => parse_basic_type!(builder, argument, U64),
193 ScryptoTypeKind::U128 => parse_basic_type!(builder, argument, U128),
194 ScryptoTypeKind::String => Ok((builder, ManifestValue::String { value: argument })),
195 ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Decimal) => Ok((
196 builder,
197 ManifestValue::Custom {
198 value: ManifestCustomValue::Decimal(from_decimal(
199 argument
200 .parse()
201 .map_err(|_| BuildCallArgumentError::FailedToParse(argument))?,
202 )),
203 },
204 )),
205 ScryptoTypeKind::Custom(ScryptoCustomTypeKind::PreciseDecimal) => Ok((
206 builder,
207 ManifestValue::Custom {
208 value: ManifestCustomValue::PreciseDecimal(from_precise_decimal(
209 argument
210 .parse()
211 .map_err(|_| BuildCallArgumentError::FailedToParse(argument))?,
212 )),
213 },
214 )),
215 ScryptoTypeKind::Custom(ScryptoCustomTypeKind::NonFungibleLocalId) => Ok((
216 builder,
217 ManifestValue::Custom {
218 value: ManifestCustomValue::NonFungibleLocalId(from_non_fungible_local_id(
219 argument
220 .parse()
221 .map_err(|_| BuildCallArgumentError::FailedToParse(argument))?,
222 )),
223 },
224 )),
225 ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Reference)
226 if matches!(
227 type_validation,
228 TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
229 ReferenceValidation::IsGlobalPackage
230 ))
231 ) =>
232 {
233 let value = PackageAddress::try_from_bech32(address_bech32_decoder, &argument)
234 .ok_or(BuildCallArgumentError::FailedToParse(argument))?;
235 Ok((
236 builder,
237 ManifestValue::Custom {
238 value: ManifestCustomValue::Address(value.into()),
239 },
240 ))
241 }
242 ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Reference)
243 if matches!(
244 type_validation,
245 TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
246 ReferenceValidation::IsGlobalComponent
247 ))
248 ) =>
249 {
250 let value = ComponentAddress::try_from_bech32(address_bech32_decoder, &argument)
251 .ok_or(BuildCallArgumentError::FailedToParse(argument))?;
252 Ok((
253 builder,
254 ManifestValue::Custom {
255 value: ManifestCustomValue::Address(value.into()),
256 },
257 ))
258 }
259 ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Reference)
260 if matches!(
261 type_validation,
262 TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
263 ReferenceValidation::IsGlobalResourceManager
264 ))
265 ) =>
266 {
267 let value = ResourceAddress::try_from_bech32(address_bech32_decoder, &argument)
268 .ok_or(BuildCallArgumentError::FailedToParse(argument))?;
269 Ok((
270 builder,
271 ManifestValue::Custom {
272 value: ManifestCustomValue::Address(value.into()),
273 },
274 ))
275 }
276 ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Reference)
277 if matches!(
278 type_validation,
279 TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
280 ReferenceValidation::IsGlobal
281 ))
282 ) =>
283 {
284 let value = GlobalAddress::try_from_bech32(address_bech32_decoder, &argument)
285 .ok_or(BuildCallArgumentError::FailedToParse(argument))?;
286 Ok((
287 builder,
288 ManifestValue::Custom {
289 value: ManifestCustomValue::Address(value.into()),
290 },
291 ))
292 }
293 ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Reference)
294 if matches!(
295 type_validation,
296 TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
297 ReferenceValidation::IsGlobalTyped(_package_address, _bp_name)
298 ))
299 ) =>
300 {
301 let value = GlobalAddress::try_from_bech32(address_bech32_decoder, &argument)
302 .ok_or(BuildCallArgumentError::FailedToParse(argument))?;
303 Ok((
304 builder,
305 ManifestValue::Custom {
306 value: ManifestCustomValue::Address(value.into()),
307 },
308 ))
309 }
310 ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Own)
311 if matches_bucket!(type_validation)
312 || matches_bucket!(type_validation, FUNGIBLE_BUCKET_BLUEPRINT)
313 || matches_bucket!(type_validation, NON_FUNGIBLE_BUCKET_BLUEPRINT) =>
314 {
315 let resource_specifier = parse_resource_specifier(&argument, address_bech32_decoder)
316 .map_err(|_| BuildCallArgumentError::FailedToParse(argument))?;
317
318 let bucket_name = builder.generate_bucket_name("taken");
319 let builder = match resource_specifier {
320 ResourceSpecifier::Amount(amount, resource_address) => {
321 if let Some(account) = account {
322 builder = builder.withdraw_from_account(account, resource_address, amount);
323 }
324 builder.take_from_worktop(resource_address, amount, &bucket_name)
325 }
326 ResourceSpecifier::Ids(ids, resource_address) => {
327 if let Some(account) = account {
328 builder = builder.withdraw_non_fungibles_from_account(
329 account,
330 resource_address,
331 ids.clone(),
332 );
333 }
334 builder.take_non_fungibles_from_worktop(resource_address, ids, &bucket_name)
335 }
336 };
337 let bucket = builder.bucket(bucket_name);
338 Ok((
339 builder,
340 ManifestValue::Custom {
341 value: ManifestCustomValue::Bucket(bucket),
342 },
343 ))
344 }
345 ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Own)
346 if matches!(
347 type_validation,
348 TypeValidation::Custom(ScryptoCustomTypeValidation::Own(OwnValidation::IsProof))
349 ) =>
350 {
351 let resource_specifier = parse_resource_specifier(&argument, address_bech32_decoder)
352 .map_err(|_| BuildCallArgumentError::FailedToParse(argument))?;
353 let proof_name = builder.generate_proof_name("proof");
354 let builder = match resource_specifier {
355 ResourceSpecifier::Amount(amount, resource_address) => {
356 if let Some(account) = account {
357 builder
358 .create_proof_from_account_of_amount(account, resource_address, amount)
359 .pop_from_auth_zone(&proof_name)
360 } else {
361 todo!("Take from worktop and create proof")
362 }
363 }
364 ResourceSpecifier::Ids(ids, resource_address) => {
365 if let Some(account) = account {
366 builder
367 .create_proof_from_account_of_non_fungibles(
368 account,
369 resource_address,
370 ids,
371 )
372 .pop_from_auth_zone(&proof_name)
373 } else {
374 todo!("Take from worktop and create proof")
375 }
376 }
377 };
378 let proof = builder.proof(proof_name);
379 Ok((
380 builder,
381 ManifestValue::Custom {
382 value: ManifestCustomValue::Proof(proof),
383 },
384 ))
385 }
386 _ => Err(BuildCallArgumentError::UnsupportedType(type_kind.clone())),
387 }
388}
389
390#[cfg(test)]
391mod test {
392 use super::*;
393 use radix_engine_interface::blueprints::identity::IDENTITY_BLUEPRINT;
394 use radix_transactions::manifest::*;
395 use radix_transactions::model::InstructionV1;
396
397 #[test]
398 pub fn parsing_of_u8_succeeds() {
399 let arg = "12";
401 let type_kind = ScryptoTypeKind::U8;
402
403 let parsed_arg: u8 = build_and_decode_arg(arg, type_kind, TypeValidation::None)
405 .expect("Failed to parse arg");
406
407 assert_eq!(parsed_arg, 12u8)
409 }
410
411 #[test]
412 pub fn parsing_of_u16_succeeds() {
413 let arg = "12";
415 let type_kind = ScryptoTypeKind::U16;
416
417 let parsed_arg: u16 = build_and_decode_arg(arg, type_kind, TypeValidation::None)
419 .expect("Failed to parse arg");
420
421 assert_eq!(parsed_arg, 12u16)
423 }
424
425 #[test]
426 pub fn parsing_of_u32_succeeds() {
427 let arg = "12";
429 let type_kind = ScryptoTypeKind::U32;
430
431 let parsed_arg: u32 = build_and_decode_arg(arg, type_kind, TypeValidation::None)
433 .expect("Failed to parse arg");
434
435 assert_eq!(parsed_arg, 12u32)
437 }
438
439 #[test]
440 pub fn parsing_of_u64_succeeds() {
441 let arg = "12";
443 let type_kind = ScryptoTypeKind::U64;
444
445 let parsed_arg: u64 = build_and_decode_arg(arg, type_kind, TypeValidation::None)
447 .expect("Failed to parse arg");
448
449 assert_eq!(parsed_arg, 12u64)
451 }
452
453 #[test]
454 pub fn parsing_of_u128_succeeds() {
455 let arg = "12";
457 let type_kind = ScryptoTypeKind::U128;
458
459 let parsed_arg: u128 = build_and_decode_arg(arg, type_kind, TypeValidation::None)
461 .expect("Failed to parse arg");
462
463 assert_eq!(parsed_arg, 12u128)
465 }
466
467 #[test]
468 pub fn parsing_of_i8_succeeds() {
469 let arg = "12";
471 let type_kind = ScryptoTypeKind::I8;
472
473 let parsed_arg: i8 = build_and_decode_arg(arg, type_kind, TypeValidation::None)
475 .expect("Failed to parse arg");
476
477 assert_eq!(parsed_arg, 12i8)
479 }
480
481 #[test]
482 pub fn parsing_of_i16_succeeds() {
483 let arg = "12";
485 let type_kind = ScryptoTypeKind::I16;
486
487 let parsed_arg: i16 = build_and_decode_arg(arg, type_kind, TypeValidation::None)
489 .expect("Failed to parse arg");
490
491 assert_eq!(parsed_arg, 12i16)
493 }
494
495 #[test]
496 pub fn parsing_of_i32_succeeds() {
497 let arg = "12";
499 let type_kind = ScryptoTypeKind::I32;
500
501 let parsed_arg: i32 = build_and_decode_arg(arg, type_kind, TypeValidation::None)
503 .expect("Failed to parse arg");
504
505 assert_eq!(parsed_arg, 12i32)
507 }
508
509 #[test]
510 pub fn parsing_of_i64_succeeds() {
511 let arg = "12";
513 let type_kind = ScryptoTypeKind::I64;
514
515 let parsed_arg: i64 = build_and_decode_arg(arg, type_kind, TypeValidation::None)
517 .expect("Failed to parse arg");
518
519 assert_eq!(parsed_arg, 12i64)
521 }
522
523 #[test]
524 pub fn parsing_of_i128_succeeds() {
525 let arg = "12";
527 let type_kind = ScryptoTypeKind::I128;
528
529 let parsed_arg: i128 = build_and_decode_arg(arg, type_kind, TypeValidation::None)
531 .expect("Failed to parse arg");
532
533 assert_eq!(parsed_arg, 12i128)
535 }
536
537 #[test]
538 pub fn parsing_of_decimal_succeeds() {
539 let arg = "12";
541 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Decimal);
542
543 let parsed_arg: Decimal = build_and_decode_arg(arg, type_kind, TypeValidation::None)
545 .expect("Failed to parse arg");
546
547 assert_eq!(parsed_arg, Decimal::from_str("12").unwrap())
549 }
550
551 #[test]
552 pub fn parsing_of_component_address_succeeds() {
553 let component_address = component_address(EntityType::GlobalAccount, 5);
555
556 let arg = AddressBech32Encoder::for_simulator()
557 .encode(component_address.as_ref())
558 .unwrap();
559 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Reference);
560 let type_validation = TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
561 ReferenceValidation::IsGlobalComponent,
562 ));
563
564 let parsed_arg: ComponentAddress =
566 build_and_decode_arg(arg, type_kind, type_validation).expect("Failed to parse arg");
567
568 assert_eq!(parsed_arg, component_address)
570 }
571
572 #[test]
573 pub fn parsing_of_global_address_succeeds() {
574 let component_address = component_address(EntityType::GlobalAccount, 5);
576 let global_address: GlobalAddress = component_address.into();
577
578 let arg = AddressBech32Encoder::for_simulator()
579 .encode(global_address.as_ref())
580 .unwrap();
581 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Reference);
582 let type_validation = TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
583 ReferenceValidation::IsGlobal,
584 ));
585
586 let parsed_arg: GlobalAddress =
588 build_and_decode_arg(arg, type_kind, type_validation).expect("Failed to parse arg");
589
590 assert_eq!(parsed_arg, global_address)
592 }
593
594 #[test]
595 pub fn parsing_of_global_address_typed_succeeds() {
596 let package_address = package_address(EntityType::GlobalPackage, 5);
598 let global_address: GlobalAddress = package_address.into();
599
600 let arg = AddressBech32Encoder::for_simulator()
601 .encode(global_address.as_ref())
602 .unwrap();
603
604 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Reference);
605 let type_validation = TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
606 ReferenceValidation::IsGlobalTyped(
607 Some(IDENTITY_PACKAGE),
608 IDENTITY_BLUEPRINT.to_string(),
609 ),
610 ));
611
612 let parsed_arg: GlobalAddress =
614 build_and_decode_arg(arg, type_kind, type_validation).expect("Failed to parse arg");
615
616 assert_eq!(parsed_arg, global_address)
618 }
619
620 #[test]
621 pub fn parsing_of_package_address_succeeds() {
622 let package_address = package_address(EntityType::GlobalPackage, 5);
624
625 let arg = AddressBech32Encoder::for_simulator()
626 .encode(package_address.as_ref())
627 .unwrap();
628 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Reference);
629 let type_validation = TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
630 ReferenceValidation::IsGlobalPackage,
631 ));
632
633 let parsed_arg: PackageAddress =
635 build_and_decode_arg(arg, type_kind, type_validation).expect("Failed to parse arg");
636
637 assert_eq!(parsed_arg, package_address)
639 }
640
641 #[test]
642 pub fn parsing_of_resource_address_succeeds() {
643 let resource_address = resource_address(EntityType::GlobalFungibleResourceManager, 5);
645
646 let arg = AddressBech32Encoder::for_simulator()
647 .encode(resource_address.as_ref())
648 .unwrap();
649 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Reference);
650 let type_validation = TypeValidation::Custom(ScryptoCustomTypeValidation::Reference(
651 ReferenceValidation::IsGlobalResourceManager,
652 ));
653
654 let parsed_arg: ResourceAddress =
656 build_and_decode_arg(arg, type_kind, type_validation).expect("Failed to parse arg");
657
658 assert_eq!(parsed_arg, resource_address)
660 }
661
662 #[test]
663 pub fn parsing_of_precise_decimal_succeeds() {
664 let arg = "12";
666 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::PreciseDecimal);
667
668 let parsed_arg: PreciseDecimal = build_and_decode_arg(arg, type_kind, TypeValidation::None)
670 .expect("Failed to parse arg");
671
672 assert_eq!(parsed_arg, PreciseDecimal::from_str("12").unwrap())
674 }
675
676 #[test]
677 pub fn parsing_of_string_non_fungible_local_id_succeeds() {
678 let arg = "<HelloWorld>";
680 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::NonFungibleLocalId);
681
682 let parsed_arg: NonFungibleLocalId =
684 build_and_decode_arg(arg, type_kind, TypeValidation::None)
685 .expect("Failed to parse arg");
686
687 assert_eq!(
689 parsed_arg,
690 NonFungibleLocalId::string("HelloWorld").unwrap()
691 )
692 }
693
694 #[test]
695 pub fn parsing_of_bytes_non_fungible_local_id_succeeds() {
696 let arg = "[c41fa9ef2ab31f5db2614c1c4c626e9c279349b240af7cb939ead29058fdff2c]";
698 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::NonFungibleLocalId);
699
700 let parsed_arg: NonFungibleLocalId =
702 build_and_decode_arg(arg, type_kind, TypeValidation::None)
703 .expect("Failed to parse arg");
704
705 assert_eq!(
707 parsed_arg,
708 NonFungibleLocalId::bytes(vec![
709 196, 31, 169, 239, 42, 179, 31, 93, 178, 97, 76, 28, 76, 98, 110, 156, 39, 147, 73,
710 178, 64, 175, 124, 185, 57, 234, 210, 144, 88, 253, 255, 44
711 ])
712 .unwrap()
713 )
714 }
715
716 #[test]
717 pub fn parsing_of_u64_non_fungible_local_id_succeeds() {
718 let arg = "#12#";
720 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::NonFungibleLocalId);
721
722 let parsed_arg: NonFungibleLocalId =
724 build_and_decode_arg(arg, type_kind, TypeValidation::None)
725 .expect("Failed to parse arg");
726
727 assert_eq!(parsed_arg, NonFungibleLocalId::integer(12))
729 }
730
731 #[test]
732 pub fn parsing_of_ruid_non_fungible_local_id_succeeds() {
733 let arg = "{1111111111111111-2222222222222222-3333333333333333-4444444444444444}";
735 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::NonFungibleLocalId);
736
737 let parsed_arg: NonFungibleLocalId =
739 build_and_decode_arg(arg, type_kind, TypeValidation::None)
740 .expect("Failed to parse arg");
741
742 assert_eq!(
744 parsed_arg,
745 NonFungibleLocalId::ruid([
746 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
747 0x22, 0x22, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x44, 0x44,
748 0x44, 0x44, 0x44, 0x44,
749 ])
750 )
751 }
752
753 #[test]
754 pub fn parsing_of_fungible_bucket_succeeds() {
755 let amount = 2000;
756 let arg = format!(
757 "{}:{}",
758 AddressBech32Encoder::for_simulator()
759 .encode(XRD.as_ref())
760 .unwrap(),
761 amount
762 );
763
764 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Own);
765 let type_validations = vec![
766 TypeValidation::Custom(ScryptoCustomTypeValidation::Own(OwnValidation::IsBucket)),
767 TypeValidation::Custom(ScryptoCustomTypeValidation::Own(
768 OwnValidation::IsTypedObject(
769 Some(RESOURCE_PACKAGE),
770 FUNGIBLE_BUCKET_BLUEPRINT.to_string(),
771 ),
772 )),
773 ];
774
775 for type_validation in type_validations {
776 let (builder, parsed_arg): (ManifestBuilder, ManifestBucket) =
778 build_and_decode(&arg, type_kind.clone(), type_validation)
779 .expect("Failed to parse arg");
780 let instructions = builder.build_no_validate().instructions;
781
782 assert_eq!(
784 instructions.first().unwrap(),
785 &InstructionV1::TakeFromWorktop(TakeFromWorktop {
786 resource_address: XRD,
787 amount: amount.into()
788 })
789 );
790 assert_eq!(parsed_arg, ManifestBucket(0u32));
791 }
792 }
793
794 #[test]
795 pub fn parsing_of_non_fungible_bucket_succeeds() {
796 let local_ids: [u64; 3] = [12, 600, 123];
798 let resource_address = resource_address(EntityType::GlobalNonFungibleResourceManager, 5);
799
800 let arg = format!(
801 "{}:#{}#,#{}#,#{}#",
802 AddressBech32Encoder::for_simulator()
803 .encode(resource_address.as_ref())
804 .unwrap(),
805 local_ids[0],
806 local_ids[1],
807 local_ids[2]
808 );
809
810 let type_kind = ScryptoTypeKind::Custom(ScryptoCustomTypeKind::Own);
811 let type_validations = vec![
812 TypeValidation::Custom(ScryptoCustomTypeValidation::Own(OwnValidation::IsBucket)),
813 TypeValidation::Custom(ScryptoCustomTypeValidation::Own(
814 OwnValidation::IsTypedObject(
815 Some(RESOURCE_PACKAGE),
816 NON_FUNGIBLE_BUCKET_BLUEPRINT.to_string(),
817 ),
818 )),
819 ];
820
821 for type_validation in type_validations {
822 let (builder, parsed_arg): (ManifestBuilder, ManifestBucket) =
824 build_and_decode(&arg, type_kind.clone(), type_validation)
825 .expect("Failed to parse arg");
826 let instructions = builder.build_no_validate().instructions;
827 let ids = local_ids
828 .map(|id| NonFungibleLocalId::Integer(IntegerNonFungibleLocalId::new(id)))
829 .to_vec();
830
831 assert_eq!(
833 instructions.first().unwrap(),
834 &InstructionV1::TakeNonFungiblesFromWorktop(TakeNonFungiblesFromWorktop {
835 resource_address,
836 ids
837 })
838 );
839 assert_eq!(parsed_arg, ManifestBucket(0u32));
840 }
841 }
842
843 pub fn build_and_decode<S: AsRef<str>, T: ManifestDecode>(
844 arg: S,
845 type_kind: ScryptoTypeKind<LocalTypeId>,
846 type_validation: TypeValidation<ScryptoCustomTypeValidation>,
847 ) -> Result<(ManifestBuilder, T), BuildAndDecodeArgError> {
848 let builder = ManifestBuilder::new();
849 let (builder, built_arg) = build_call_argument(
850 builder,
851 &AddressBech32Decoder::for_simulator(),
852 &type_kind,
853 &type_validation,
854 arg.as_ref().to_owned(),
855 None,
856 )
857 .map_err(BuildAndDecodeArgError::BuildCallArgumentError)?;
858
859 let bytes = manifest_encode(&built_arg).map_err(BuildAndDecodeArgError::EncodeError)?;
860
861 Ok((
862 builder,
863 manifest_decode(&bytes).map_err(BuildAndDecodeArgError::DecodeError)?,
864 ))
865 }
866
867 pub fn build_and_decode_arg<S: AsRef<str>, T: ManifestDecode>(
868 arg: S,
869 type_kind: ScryptoTypeKind<LocalTypeId>,
870 type_validation: TypeValidation<ScryptoCustomTypeValidation>,
871 ) -> Result<T, BuildAndDecodeArgError> {
872 build_and_decode(arg, type_kind, type_validation).map(|(_, arg)| arg)
873 }
874
875 #[allow(dead_code)] #[derive(Debug, Clone)]
877 #[allow(clippy::enum_variant_names)]
878 pub enum BuildAndDecodeArgError {
879 BuildCallArgumentError(BuildCallArgumentError),
880 EncodeError(EncodeError),
881 DecodeError(DecodeError),
882 }
883}