1use crate::error::{AptosError, AptosResult};
33use crate::transaction::{EntryFunction, TransactionPayload};
34use crate::types::{AccountAddress, EntryFunctionId, MoveModuleId, TypeTag};
35use serde::{Deserialize, Serialize};
36
37#[allow(dead_code)] #[derive(Debug, Clone)]
55pub struct InputEntryFunctionData {
56 module: MoveModuleId,
57 function: String,
58 type_args: Vec<TypeTag>,
59 args: Vec<Vec<u8>>,
60}
61
62impl InputEntryFunctionData {
63 #[allow(clippy::new_ret_no_self)] pub fn new(function_id: &str) -> InputEntryFunctionDataBuilder {
76 InputEntryFunctionDataBuilder::new(function_id)
77 }
78
79 pub fn from_parts(
86 module: MoveModuleId,
87 function: impl Into<String>,
88 ) -> InputEntryFunctionDataBuilder {
89 InputEntryFunctionDataBuilder {
90 module: Ok(module),
91 function: function.into(),
92 type_args: Vec::new(),
93 args: Vec::new(),
94 errors: Vec::new(),
95 }
96 }
97
98 pub fn transfer_apt(recipient: AccountAddress, amount: u64) -> AptosResult<TransactionPayload> {
115 InputEntryFunctionData::new("0x1::aptos_account::transfer")
116 .arg(recipient)
117 .arg(amount)
118 .build()
119 }
120
121 pub fn transfer_coin(
133 coin_type: &str,
134 recipient: AccountAddress,
135 amount: u64,
136 ) -> AptosResult<TransactionPayload> {
137 InputEntryFunctionData::new("0x1::coin::transfer")
138 .type_arg(coin_type)
139 .arg(recipient)
140 .arg(amount)
141 .build()
142 }
143
144 pub fn transfer_fungible_asset(
166 metadata: AccountAddress,
167 recipient: AccountAddress,
168 amount: u64,
169 ) -> AptosResult<TransactionPayload> {
170 InputEntryFunctionData::new("0x1::primary_fungible_store::transfer")
171 .type_arg("0x1::fungible_asset::Metadata")
172 .arg(metadata)
173 .arg(recipient)
174 .arg(amount)
175 .build()
176 }
177
178 pub fn create_account(auth_key: AccountAddress) -> AptosResult<TransactionPayload> {
188 InputEntryFunctionData::new("0x1::aptos_account::create_account")
189 .arg(auth_key)
190 .build()
191 }
192
193 pub fn rotate_authentication_key(
203 from_scheme: u8,
204 from_public_key_bytes: Vec<u8>,
205 to_scheme: u8,
206 to_public_key_bytes: Vec<u8>,
207 cap_rotate_key: Vec<u8>,
208 cap_update_table: Vec<u8>,
209 ) -> AptosResult<TransactionPayload> {
210 InputEntryFunctionData::new("0x1::account::rotate_authentication_key")
211 .arg(from_scheme)
212 .arg(from_public_key_bytes)
213 .arg(to_scheme)
214 .arg(to_public_key_bytes)
215 .arg(cap_rotate_key)
216 .arg(cap_update_table)
217 .build()
218 }
219
220 pub fn register_coin(coin_type: &str) -> AptosResult<TransactionPayload> {
230 InputEntryFunctionData::new("0x1::managed_coin::register")
231 .type_arg(coin_type)
232 .build()
233 }
234
235 pub fn publish_package(
246 metadata_serialized: Vec<u8>,
247 code: Vec<Vec<u8>>,
248 ) -> AptosResult<TransactionPayload> {
249 InputEntryFunctionData::new("0x1::code::publish_package_txn")
250 .arg(metadata_serialized)
251 .arg(code)
252 .build()
253 }
254
255 pub fn transfer_object(
267 object: AccountAddress,
268 to: AccountAddress,
269 ) -> AptosResult<TransactionPayload> {
270 InputEntryFunctionData::new("0x1::object::transfer_call")
271 .arg(object)
272 .arg(to)
273 .build()
274 }
275
276 pub fn transfer_digital_asset(
288 token: AccountAddress,
289 to: AccountAddress,
290 ) -> AptosResult<TransactionPayload> {
291 InputEntryFunctionData::new("0x1::object::transfer")
292 .type_arg("0x4::token::Token")
293 .arg(token)
294 .arg(to)
295 .build()
296 }
297
298 #[allow(clippy::too_many_arguments)]
311 pub fn create_collection(
312 description: &str,
313 max_supply: u64,
314 name: &str,
315 uri: &str,
316 config: CollectionConfig,
317 royalty_numerator: u64,
318 royalty_denominator: u64,
319 ) -> AptosResult<TransactionPayload> {
320 InputEntryFunctionData::new("0x4::aptos_token::create_collection")
321 .arg(description)
322 .arg(max_supply)
323 .arg(name)
324 .arg(uri)
325 .arg(config.mutable_description)
326 .arg(config.mutable_royalty)
327 .arg(config.mutable_uri)
328 .arg(config.mutable_token_description)
329 .arg(config.mutable_token_name)
330 .arg(config.mutable_token_properties)
331 .arg(config.mutable_token_uri)
332 .arg(config.tokens_burnable_by_creator)
333 .arg(config.tokens_freezable_by_creator)
334 .arg(royalty_numerator)
335 .arg(royalty_denominator)
336 .build()
337 }
338
339 pub fn mint_digital_asset(
350 collection: &str,
351 description: &str,
352 name: &str,
353 uri: &str,
354 property_keys: Vec<String>,
355 property_types: Vec<String>,
356 property_values: Vec<Vec<u8>>,
357 ) -> AptosResult<TransactionPayload> {
358 InputEntryFunctionData::new("0x4::aptos_token::mint")
359 .arg(collection)
360 .arg(description)
361 .arg(name)
362 .arg(uri)
363 .arg(property_keys)
364 .arg(property_types)
365 .arg(property_values)
366 .build()
367 }
368
369 pub fn mint_soul_bound_digital_asset(
376 collection: &str,
377 description: &str,
378 name: &str,
379 uri: &str,
380 property_keys: Vec<String>,
381 property_types: Vec<String>,
382 property_values: Vec<Vec<u8>>,
383 soul_bound_to: AccountAddress,
384 ) -> AptosResult<TransactionPayload> {
385 InputEntryFunctionData::new("0x4::aptos_token::mint_soul_bound")
386 .arg(collection)
387 .arg(description)
388 .arg(name)
389 .arg(uri)
390 .arg(property_keys)
391 .arg(property_types)
392 .arg(property_values)
393 .arg(soul_bound_to)
394 .build()
395 }
396
397 pub fn burn_digital_asset(token: AccountAddress) -> AptosResult<TransactionPayload> {
404 InputEntryFunctionData::new("0x4::aptos_token::burn")
405 .type_arg("0x4::token::Token")
406 .arg(token)
407 .build()
408 }
409
410 pub fn freeze_digital_asset_transfer(token: AccountAddress) -> AptosResult<TransactionPayload> {
418 InputEntryFunctionData::new("0x4::aptos_token::freeze_transfer")
419 .type_arg("0x4::token::Token")
420 .arg(token)
421 .build()
422 }
423
424 pub fn unfreeze_digital_asset_transfer(
432 token: AccountAddress,
433 ) -> AptosResult<TransactionPayload> {
434 InputEntryFunctionData::new("0x4::aptos_token::unfreeze_transfer")
435 .type_arg("0x4::token::Token")
436 .arg(token)
437 .build()
438 }
439
440 pub fn delegation_add_stake(
449 pool_address: AccountAddress,
450 amount: u64,
451 ) -> AptosResult<TransactionPayload> {
452 InputEntryFunctionData::new("0x1::delegation_pool::add_stake")
453 .arg(pool_address)
454 .arg(amount)
455 .build()
456 }
457
458 pub fn delegation_unlock(
466 pool_address: AccountAddress,
467 amount: u64,
468 ) -> AptosResult<TransactionPayload> {
469 InputEntryFunctionData::new("0x1::delegation_pool::unlock")
470 .arg(pool_address)
471 .arg(amount)
472 .build()
473 }
474
475 pub fn delegation_reactivate_stake(
482 pool_address: AccountAddress,
483 amount: u64,
484 ) -> AptosResult<TransactionPayload> {
485 InputEntryFunctionData::new("0x1::delegation_pool::reactivate_stake")
486 .arg(pool_address)
487 .arg(amount)
488 .build()
489 }
490
491 pub fn delegation_withdraw(
498 pool_address: AccountAddress,
499 amount: u64,
500 ) -> AptosResult<TransactionPayload> {
501 InputEntryFunctionData::new("0x1::delegation_pool::withdraw")
502 .arg(pool_address)
503 .arg(amount)
504 .build()
505 }
506
507 pub fn add_authentication_function(
519 module_address: AccountAddress,
520 module_name: &str,
521 function_name: &str,
522 ) -> AptosResult<TransactionPayload> {
523 InputEntryFunctionData::new("0x1::account_abstraction::add_authentication_function")
524 .arg(module_address)
525 .arg(module_name)
526 .arg(function_name)
527 .build()
528 }
529
530 pub fn remove_authentication_function(
537 module_address: AccountAddress,
538 module_name: &str,
539 function_name: &str,
540 ) -> AptosResult<TransactionPayload> {
541 InputEntryFunctionData::new("0x1::account_abstraction::remove_authentication_function")
542 .arg(module_address)
543 .arg(module_name)
544 .arg(function_name)
545 .build()
546 }
547
548 pub fn remove_authenticator() -> AptosResult<TransactionPayload> {
556 InputEntryFunctionData::new("0x1::account_abstraction::remove_authenticator").build()
557 }
558}
559
560#[derive(Debug, Clone, Copy, PartialEq, Eq)]
567pub struct CollectionConfig {
568 pub mutable_description: bool,
570 pub mutable_royalty: bool,
572 pub mutable_uri: bool,
574 pub mutable_token_description: bool,
576 pub mutable_token_name: bool,
578 pub mutable_token_properties: bool,
580 pub mutable_token_uri: bool,
582 pub tokens_burnable_by_creator: bool,
584 pub tokens_freezable_by_creator: bool,
586}
587
588impl Default for CollectionConfig {
589 fn default() -> Self {
590 Self {
591 mutable_description: true,
592 mutable_royalty: true,
593 mutable_uri: true,
594 mutable_token_description: true,
595 mutable_token_name: true,
596 mutable_token_properties: true,
597 mutable_token_uri: true,
598 tokens_burnable_by_creator: true,
599 tokens_freezable_by_creator: true,
600 }
601 }
602}
603
604#[derive(Debug, Clone)]
606pub struct InputEntryFunctionDataBuilder {
607 module: Result<MoveModuleId, String>,
608 function: String,
609 type_args: Vec<TypeTag>,
610 args: Vec<Vec<u8>>,
611 errors: Vec<String>,
612}
613
614impl InputEntryFunctionDataBuilder {
615 #[must_use]
617 fn new(function_id: &str) -> Self {
618 match EntryFunctionId::from_str_strict(function_id) {
619 Ok(func_id) => Self {
620 module: Ok(func_id.module),
621 function: func_id.name.as_str().to_string(),
622 type_args: Vec::new(),
623 args: Vec::new(),
624 errors: Vec::new(),
625 },
626 Err(e) => Self {
627 module: Err(format!("Invalid function ID '{function_id}': {e}")),
628 function: String::new(),
629 type_args: Vec::new(),
630 args: Vec::new(),
631 errors: Vec::new(),
632 },
633 }
634 }
635
636 #[must_use]
649 pub fn type_arg(mut self, type_arg: &str) -> Self {
650 match TypeTag::from_str_strict(type_arg) {
651 Ok(tag) => self.type_args.push(tag),
652 Err(e) => self
653 .errors
654 .push(format!("Invalid type argument '{type_arg}': {e}")),
655 }
656 self
657 }
658
659 #[must_use]
661 pub fn type_arg_typed(mut self, type_arg: TypeTag) -> Self {
662 self.type_args.push(type_arg);
663 self
664 }
665
666 #[must_use]
668 pub fn type_args(mut self, type_args: impl IntoIterator<Item = &'static str>) -> Self {
669 for type_arg in type_args {
670 self = self.type_arg(type_arg);
671 }
672 self
673 }
674
675 #[must_use]
677 pub fn type_args_typed(mut self, type_args: impl IntoIterator<Item = TypeTag>) -> Self {
678 self.type_args.extend(type_args);
679 self
680 }
681
682 #[must_use]
705 pub fn arg<T: Serialize>(mut self, value: T) -> Self {
706 match aptos_bcs::to_bytes(&value) {
707 Ok(bytes) => self.args.push(bytes),
708 Err(e) => self
709 .errors
710 .push(format!("Failed to serialize argument: {e}")),
711 }
712 self
713 }
714
715 #[must_use]
719 pub fn arg_raw(mut self, bytes: Vec<u8>) -> Self {
720 self.args.push(bytes);
721 self
722 }
723
724 #[must_use]
726 pub fn args<T: Serialize>(mut self, values: impl IntoIterator<Item = T>) -> Self {
727 for value in values {
728 self = self.arg(value);
729 }
730 self
731 }
732
733 pub fn build(self) -> AptosResult<TransactionPayload> {
744 let module = self.module.map_err(AptosError::Transaction)?;
746
747 if !self.errors.is_empty() {
749 return Err(AptosError::Transaction(self.errors.join("; ")));
750 }
751
752 Ok(TransactionPayload::EntryFunction(EntryFunction {
753 module,
754 function: self.function,
755 type_args: self.type_args,
756 args: self.args,
757 }))
758 }
759
760 pub fn build_entry_function(self) -> AptosResult<EntryFunction> {
766 let module = self.module.map_err(AptosError::Transaction)?;
767
768 if !self.errors.is_empty() {
769 return Err(AptosError::Transaction(self.errors.join("; ")));
770 }
771
772 Ok(EntryFunction {
773 module,
774 function: self.function,
775 type_args: self.type_args,
776 args: self.args,
777 })
778 }
779}
780
781pub trait IntoMoveArg {
785 fn into_move_arg(self) -> AptosResult<Vec<u8>>;
791}
792
793impl<T: Serialize> IntoMoveArg for T {
794 fn into_move_arg(self) -> AptosResult<Vec<u8>> {
795 aptos_bcs::to_bytes(&self).map_err(AptosError::bcs)
796 }
797}
798
799pub fn move_vec<T: Serialize>(items: &[T]) -> Vec<u8> {
810 aptos_bcs::to_bytes(items).unwrap_or_default()
811}
812
813pub fn move_string(s: &str) -> String {
823 s.to_string()
824}
825
826pub fn move_some<T: Serialize>(value: T) -> Vec<u8> {
834 let mut bytes = vec![0x01];
836 if let Ok(value_bytes) = aptos_bcs::to_bytes(&value) {
837 bytes.extend(value_bytes);
838 }
839 bytes
840}
841
842pub fn move_none() -> Vec<u8> {
850 vec![0x00]
852}
853
854#[derive(Debug, Clone, Copy, PartialEq, Eq)]
858pub struct MoveU256(pub [u8; 32]);
859
860impl MoveU256 {
861 pub fn parse(s: &str) -> AptosResult<Self> {
871 let s = s.trim();
872 if s.is_empty() || !s.bytes().all(|b| b.is_ascii_digit()) {
873 return Err(AptosError::Transaction(format!("Invalid u256: {s}")));
874 }
875
876 let mut bytes = [0u8; 32];
878 for digit in s.bytes().map(|b| b - b'0') {
879 let mut carry = u16::from(digit);
880 for byte in &mut bytes {
881 let v = u16::from(*byte) * 10 + carry;
882 *byte = (v & 0xff) as u8;
883 carry = v >> 8;
884 }
885 if carry != 0 {
886 return Err(AptosError::Transaction(format!(
887 "u256 overflow: {s} exceeds 2^256 - 1"
888 )));
889 }
890 }
891
892 Ok(Self(bytes))
893 }
894
895 pub fn from_u128(val: u128) -> Self {
897 let mut bytes = [0u8; 32];
898 bytes[..16].copy_from_slice(&val.to_le_bytes());
899 Self(bytes)
900 }
901
902 pub fn from_le_bytes(bytes: [u8; 32]) -> Self {
904 Self(bytes)
905 }
906
907 pub fn to_decimal_string(&self) -> String {
909 if self.0.iter().all(|&b| b == 0) {
910 return "0".to_string();
911 }
912
913 let mut be = self.0;
917 be.reverse();
918 let mut digits = String::with_capacity(78);
919 while be.iter().any(|&b| b != 0) {
920 let mut rem = 0u16;
921 for byte in &mut be {
922 let cur = (rem << 8) | u16::from(*byte);
923 *byte = (cur / 10) as u8;
924 rem = cur % 10;
925 }
926 digits.push(char::from(b'0' + rem as u8));
927 }
928 digits.chars().rev().collect()
930 }
931}
932
933impl std::fmt::Display for MoveU256 {
934 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
935 f.write_str(&self.to_decimal_string())
936 }
937}
938
939impl Serialize for MoveU256 {
940 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
941 where
942 S: serde::Serializer,
943 {
944 if serializer.is_human_readable() {
945 serializer.serialize_str(&self.to_decimal_string())
948 } else {
949 use serde::ser::SerializeTuple;
952 let mut tuple = serializer.serialize_tuple(32)?;
953 for byte in &self.0 {
954 tuple.serialize_element(byte)?;
955 }
956 tuple.end()
957 }
958 }
959}
960
961impl<'de> Deserialize<'de> for MoveU256 {
962 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
963 where
964 D: serde::Deserializer<'de>,
965 {
966 if deserializer.is_human_readable() {
967 struct HrVisitor;
968 impl serde::de::Visitor<'_> for HrVisitor {
969 type Value = MoveU256;
970
971 fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
972 f.write_str("a u256 as a decimal string or unsigned integer")
973 }
974
975 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<MoveU256, E> {
976 MoveU256::parse(v).map_err(E::custom)
977 }
978
979 fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<MoveU256, E> {
980 Ok(MoveU256::from_u128(u128::from(v)))
981 }
982
983 fn visit_u128<E: serde::de::Error>(self, v: u128) -> Result<MoveU256, E> {
984 Ok(MoveU256::from_u128(v))
985 }
986 }
987 deserializer.deserialize_any(HrVisitor)
990 } else {
991 let bytes = <[u8; 32]>::deserialize(deserializer)?;
993 Ok(Self(bytes))
994 }
995 }
996}
997
998#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1003pub struct MoveI128(pub i128);
1004
1005impl MoveI128 {
1006 pub fn new(val: i128) -> Self {
1008 Self(val)
1009 }
1010}
1011
1012impl Serialize for MoveI128 {
1013 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1014 where
1015 S: serde::Serializer,
1016 {
1017 use serde::ser::SerializeTuple;
1019 let bytes = self.0.to_le_bytes();
1020 let mut tuple = serializer.serialize_tuple(16)?;
1021 for byte in &bytes {
1022 tuple.serialize_element(byte)?;
1023 }
1024 tuple.end()
1025 }
1026}
1027
1028impl From<i128> for MoveI128 {
1029 fn from(val: i128) -> Self {
1030 Self(val)
1031 }
1032}
1033
1034#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1039pub struct MoveI256(pub [u8; 32]);
1040
1041impl MoveI256 {
1042 pub fn from_i128(val: i128) -> Self {
1044 let mut bytes = [0u8; 32];
1045 let val_bytes = val.to_le_bytes();
1046 bytes[..16].copy_from_slice(&val_bytes);
1047 if val < 0 {
1049 bytes[16..].fill(0xFF);
1050 }
1051 Self(bytes)
1052 }
1053
1054 pub fn from_le_bytes(bytes: [u8; 32]) -> Self {
1056 Self(bytes)
1057 }
1058}
1059
1060impl Serialize for MoveI256 {
1061 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1062 where
1063 S: serde::Serializer,
1064 {
1065 use serde::ser::SerializeTuple;
1067 let mut tuple = serializer.serialize_tuple(32)?;
1068 for byte in &self.0 {
1069 tuple.serialize_element(byte)?;
1070 }
1071 tuple.end()
1072 }
1073}
1074
1075impl From<i128> for MoveI256 {
1076 fn from(val: i128) -> Self {
1077 Self::from_i128(val)
1078 }
1079}
1080
1081pub mod functions {
1083 pub const APT_TRANSFER: &str = "0x1::aptos_account::transfer";
1085 pub const COIN_TRANSFER: &str = "0x1::coin::transfer";
1087 pub const CREATE_ACCOUNT: &str = "0x1::aptos_account::create_account";
1089 pub const REGISTER_COIN: &str = "0x1::managed_coin::register";
1091 pub const PUBLISH_PACKAGE: &str = "0x1::code::publish_package_txn";
1093 pub const ROTATE_AUTH_KEY: &str = "0x1::account::rotate_authentication_key";
1095}
1096
1097pub mod types {
1099 pub const APT_COIN: &str = "0x1::aptos_coin::AptosCoin";
1101}
1102
1103#[cfg(test)]
1104mod tests {
1105 use super::*;
1106
1107 #[test]
1108 fn test_simple_transfer() {
1109 let recipient = AccountAddress::from_hex("0x123").unwrap();
1110 let payload = InputEntryFunctionData::new("0x1::aptos_account::transfer")
1111 .arg(recipient)
1112 .arg(1_000_000u64)
1113 .build()
1114 .unwrap();
1115
1116 match payload {
1117 TransactionPayload::EntryFunction(ef) => {
1118 assert_eq!(ef.function, "transfer");
1119 assert_eq!(ef.module.name.as_str(), "aptos_account");
1120 assert!(ef.type_args.is_empty());
1121 assert_eq!(ef.args.len(), 2);
1122 }
1123 _ => panic!("Expected EntryFunction"),
1124 }
1125 }
1126
1127 #[test]
1128 fn test_with_type_args() {
1129 let payload = InputEntryFunctionData::new("0x1::coin::transfer")
1130 .type_arg("0x1::aptos_coin::AptosCoin")
1131 .arg(AccountAddress::ONE)
1132 .arg(1000u64)
1133 .build()
1134 .unwrap();
1135
1136 match payload {
1137 TransactionPayload::EntryFunction(ef) => {
1138 assert_eq!(ef.function, "transfer");
1139 assert_eq!(ef.type_args.len(), 1);
1140 }
1141 _ => panic!("Expected EntryFunction"),
1142 }
1143 }
1144
1145 #[test]
1146 fn test_invalid_function_id() {
1147 let result = InputEntryFunctionData::new("invalid").arg(42u64).build();
1148
1149 assert!(result.is_err());
1150 }
1151
1152 #[test]
1153 fn test_invalid_type_arg() {
1154 let result = InputEntryFunctionData::new("0x1::coin::transfer")
1155 .type_arg("not a type")
1156 .arg(AccountAddress::ONE)
1157 .arg(1000u64)
1158 .build();
1159
1160 assert!(result.is_err());
1161 }
1162
1163 #[test]
1164 fn test_transfer_apt_helper() {
1165 let recipient = AccountAddress::from_hex("0x456").unwrap();
1166 let payload = InputEntryFunctionData::transfer_apt(recipient, 5_000_000).unwrap();
1167
1168 match payload {
1169 TransactionPayload::EntryFunction(ef) => {
1170 assert_eq!(ef.function, "transfer");
1171 assert_eq!(ef.module.name.as_str(), "aptos_account");
1172 }
1173 _ => panic!("Expected EntryFunction"),
1174 }
1175 }
1176
1177 #[test]
1178 fn test_transfer_coin_helper() {
1179 let recipient = AccountAddress::from_hex("0x789").unwrap();
1180 let payload =
1181 InputEntryFunctionData::transfer_coin("0x1::aptos_coin::AptosCoin", recipient, 1000)
1182 .unwrap();
1183
1184 match payload {
1185 TransactionPayload::EntryFunction(ef) => {
1186 assert_eq!(ef.function, "transfer");
1187 assert_eq!(ef.module.name.as_str(), "coin");
1188 assert_eq!(ef.type_args.len(), 1);
1189 }
1190 _ => panic!("Expected EntryFunction"),
1191 }
1192 }
1193
1194 #[test]
1195 fn test_transfer_fungible_asset_helper() {
1196 let metadata = AccountAddress::from_hex("0xa").unwrap();
1197 let recipient = AccountAddress::from_hex("0x789").unwrap();
1198 let payload =
1199 InputEntryFunctionData::transfer_fungible_asset(metadata, recipient, 1000).unwrap();
1200
1201 match payload {
1202 TransactionPayload::EntryFunction(ef) => {
1203 assert_eq!(ef.function, "transfer");
1204 assert_eq!(ef.module.name.as_str(), "primary_fungible_store");
1205 assert_eq!(ef.type_args.len(), 1);
1207 assert_eq!(ef.args.len(), 3);
1209 assert_eq!(ef.args[0], aptos_bcs::to_bytes(&metadata).unwrap());
1211 assert_eq!(ef.args[2], aptos_bcs::to_bytes(&1000u64).unwrap());
1212 }
1213 _ => panic!("Expected EntryFunction"),
1214 }
1215 }
1216
1217 #[test]
1218 fn test_transfer_object_helper() {
1219 let object = AccountAddress::from_hex("0xbeef").unwrap();
1220 let to = AccountAddress::from_hex("0x789").unwrap();
1221 let payload = InputEntryFunctionData::transfer_object(object, to).unwrap();
1222 match payload {
1223 TransactionPayload::EntryFunction(ef) => {
1224 assert_eq!(ef.module.name.as_str(), "object");
1225 assert_eq!(ef.function, "transfer_call");
1226 assert_eq!(ef.args.len(), 2);
1227 assert!(ef.type_args.is_empty());
1228 }
1229 _ => panic!("Expected EntryFunction"),
1230 }
1231 }
1232
1233 #[test]
1234 fn test_transfer_digital_asset_helper() {
1235 let token = AccountAddress::from_hex("0xdead").unwrap();
1236 let to = AccountAddress::from_hex("0x789").unwrap();
1237 let payload = InputEntryFunctionData::transfer_digital_asset(token, to).unwrap();
1238 match payload {
1239 TransactionPayload::EntryFunction(ef) => {
1240 assert_eq!(ef.module.name.as_str(), "object");
1241 assert_eq!(ef.function, "transfer");
1242 assert_eq!(ef.type_args.len(), 1, "should carry the Token object type");
1243 assert_eq!(ef.args.len(), 2);
1244 }
1245 _ => panic!("Expected EntryFunction"),
1246 }
1247 }
1248
1249 #[test]
1250 fn test_create_collection_arg_shape() {
1251 let payload = InputEntryFunctionData::create_collection(
1252 "desc",
1253 100,
1254 "My Collection",
1255 "https://example.com",
1256 CollectionConfig::default(),
1257 5,
1258 100,
1259 )
1260 .unwrap();
1261 match payload {
1262 TransactionPayload::EntryFunction(ef) => {
1263 assert_eq!(ef.module.address, AccountAddress::from_hex("0x4").unwrap());
1264 assert_eq!(ef.module.name.as_str(), "aptos_token");
1265 assert_eq!(ef.function, "create_collection");
1266 assert_eq!(ef.args.len(), 15);
1268 }
1269 _ => panic!("Expected EntryFunction"),
1270 }
1271 }
1272
1273 #[test]
1274 fn test_mint_digital_asset_arg_shape() {
1275 let payload = InputEntryFunctionData::mint_digital_asset(
1276 "My Collection",
1277 "desc",
1278 "Token #1",
1279 "https://example.com/1",
1280 vec!["level".to_string()],
1281 vec!["u64".to_string()],
1282 vec![aptos_bcs::to_bytes(&1u64).unwrap()],
1283 )
1284 .unwrap();
1285 match payload {
1286 TransactionPayload::EntryFunction(ef) => {
1287 assert_eq!(ef.function, "mint");
1288 assert_eq!(ef.args.len(), 7);
1289 }
1290 _ => panic!("Expected EntryFunction"),
1291 }
1292 }
1293
1294 #[test]
1295 fn test_delegation_helpers() {
1296 let pool = AccountAddress::from_hex("0x5").unwrap();
1297 for (payload, func) in [
1298 (
1299 InputEntryFunctionData::delegation_add_stake(pool, 1000).unwrap(),
1300 "add_stake",
1301 ),
1302 (
1303 InputEntryFunctionData::delegation_unlock(pool, 1000).unwrap(),
1304 "unlock",
1305 ),
1306 (
1307 InputEntryFunctionData::delegation_reactivate_stake(pool, 1000).unwrap(),
1308 "reactivate_stake",
1309 ),
1310 (
1311 InputEntryFunctionData::delegation_withdraw(pool, 1000).unwrap(),
1312 "withdraw",
1313 ),
1314 ] {
1315 match payload {
1316 TransactionPayload::EntryFunction(ef) => {
1317 assert_eq!(ef.module.name.as_str(), "delegation_pool");
1318 assert_eq!(ef.function, func);
1319 assert_eq!(ef.args.len(), 2);
1320 }
1321 _ => panic!("Expected EntryFunction"),
1322 }
1323 }
1324 }
1325
1326 #[test]
1327 fn test_account_abstraction_helpers() {
1328 let module = AccountAddress::from_hex("0x123").unwrap();
1329 let add =
1330 InputEntryFunctionData::add_authentication_function(module, "my_auth", "authenticate")
1331 .unwrap();
1332 match add {
1333 TransactionPayload::EntryFunction(ef) => {
1334 assert_eq!(ef.module.name.as_str(), "account_abstraction");
1335 assert_eq!(ef.function, "add_authentication_function");
1336 assert_eq!(ef.args.len(), 3);
1337 }
1338 _ => panic!("Expected EntryFunction"),
1339 }
1340
1341 let remove_all = InputEntryFunctionData::remove_authenticator().unwrap();
1342 match remove_all {
1343 TransactionPayload::EntryFunction(ef) => {
1344 assert_eq!(ef.function, "remove_authenticator");
1345 assert!(ef.args.is_empty());
1346 }
1347 _ => panic!("Expected EntryFunction"),
1348 }
1349 }
1350
1351 #[test]
1352 fn test_various_arg_types() {
1353 let payload = InputEntryFunctionData::new("0x1::test::test_function")
1354 .arg(42u8)
1355 .arg(1000u64)
1356 .arg(true)
1357 .arg("hello".to_string())
1358 .arg(vec![1u8, 2u8, 3u8])
1359 .arg(AccountAddress::ONE)
1360 .build()
1361 .unwrap();
1362
1363 match payload {
1364 TransactionPayload::EntryFunction(ef) => {
1365 assert_eq!(ef.args.len(), 6);
1366 }
1367 _ => panic!("Expected EntryFunction"),
1368 }
1369 }
1370
1371 #[test]
1372 fn test_move_u256() {
1373 let val = MoveU256::from_u128(12345);
1374 let bytes = aptos_bcs::to_bytes(&val).unwrap();
1375 assert_eq!(bytes.len(), 32);
1376 }
1377
1378 #[test]
1379 fn test_move_some_none() {
1380 let some_bytes = move_some(42u64);
1381 assert_eq!(some_bytes[0], 0x01);
1382
1383 let none_bytes = move_none();
1384 assert_eq!(none_bytes, vec![0x00]);
1385 }
1386
1387 #[test]
1388 fn test_from_parts() {
1389 let module = MoveModuleId::from_str_strict("0x1::coin").unwrap();
1390 let payload = InputEntryFunctionData::from_parts(module, "transfer")
1391 .type_arg("0x1::aptos_coin::AptosCoin")
1392 .arg(AccountAddress::ONE)
1393 .arg(1000u64)
1394 .build()
1395 .unwrap();
1396
1397 match payload {
1398 TransactionPayload::EntryFunction(ef) => {
1399 assert_eq!(ef.function, "transfer");
1400 assert_eq!(ef.module.name.as_str(), "coin");
1401 }
1402 _ => panic!("Expected EntryFunction"),
1403 }
1404 }
1405
1406 #[test]
1407 fn test_build_entry_function() {
1408 let ef = InputEntryFunctionData::new("0x1::aptos_account::transfer")
1409 .arg(AccountAddress::ONE)
1410 .arg(1000u64)
1411 .build_entry_function()
1412 .unwrap();
1413
1414 assert_eq!(ef.function, "transfer");
1415 assert_eq!(ef.args.len(), 2);
1416 }
1417
1418 #[test]
1419 fn test_function_constants() {
1420 assert_eq!(functions::APT_TRANSFER, "0x1::aptos_account::transfer");
1421 assert_eq!(functions::COIN_TRANSFER, "0x1::coin::transfer");
1422 }
1423
1424 #[test]
1425 fn test_move_u256_from_u128() {
1426 let val = MoveU256::from_u128(123_456_789);
1427 let expected = 123_456_789_u128.to_le_bytes();
1429 assert_eq!(&val.0[..16], &expected);
1430 assert_eq!(&val.0[16..], &[0u8; 16]);
1432 }
1433
1434 #[test]
1435 fn test_move_u256_from_le_bytes() {
1436 let bytes = [0xab; 32];
1437 let val = MoveU256::from_le_bytes(bytes);
1438 assert_eq!(val.0, bytes);
1439 }
1440
1441 #[test]
1442 fn test_move_u256_parse() {
1443 let val = MoveU256::parse("12345678901234567890").unwrap();
1444 let expected = 12_345_678_901_234_567_890_u128;
1445 let mut expected_bytes = [0u8; 32];
1446 expected_bytes[..16].copy_from_slice(&expected.to_le_bytes());
1447 assert_eq!(val.0, expected_bytes);
1448 }
1449
1450 #[test]
1451 fn test_move_u256_parse_large_value_beyond_u128() {
1452 let two_pow_128 = MoveU256::parse("340282366920938463463374607431768211456").unwrap();
1455 let mut expected = [0u8; 32];
1456 expected[16] = 1; assert_eq!(two_pow_128.0, expected);
1458 }
1459
1460 #[test]
1461 fn test_move_u256_parse_max_and_overflow() {
1462 let max = "115792089237316195423570985008687907853269984665640564039457584007913129639935";
1464 assert_eq!(MoveU256::parse(max).unwrap().0, [0xff; 32]);
1465
1466 let over = "115792089237316195423570985008687907853269984665640564039457584007913129639936";
1468 assert!(MoveU256::parse(over).is_err());
1469
1470 assert!(MoveU256::parse("12x3").is_err());
1472 assert!(MoveU256::parse("").is_err());
1473 }
1474
1475 #[test]
1476 fn test_move_u256_bcs_roundtrip() {
1477 let val = MoveU256::parse("340282366920938463463374607431768211457").unwrap();
1478 let bytes = aptos_bcs::to_bytes(&val).unwrap();
1479 assert_eq!(bytes.len(), 32);
1480 let back: MoveU256 = aptos_bcs::from_bytes(&bytes).unwrap();
1481 assert_eq!(back, val);
1482 }
1483
1484 #[test]
1485 fn test_move_u256_json_roundtrip_as_string() {
1486 let val = MoveU256::parse("340282366920938463463374607431768211457").unwrap();
1487 let json = serde_json::to_string(&val).unwrap();
1489 assert_eq!(json, "\"340282366920938463463374607431768211457\"");
1490 let back: MoveU256 = serde_json::from_str(&json).unwrap();
1491 assert_eq!(back, val);
1492 let from_num: MoveU256 = serde_json::from_str("12345").unwrap();
1494 assert_eq!(from_num, MoveU256::from_u128(12345));
1495 }
1496
1497 #[test]
1498 fn test_move_u256_to_decimal_string() {
1499 assert_eq!(MoveU256::from_u128(0).to_decimal_string(), "0");
1500 assert_eq!(
1501 MoveU256::from_u128(12_345_678_901_234_567_890).to_decimal_string(),
1502 "12345678901234567890"
1503 );
1504 assert_eq!(
1505 MoveU256([0xff; 32]).to_decimal_string(),
1506 "115792089237316195423570985008687907853269984665640564039457584007913129639935"
1507 );
1508 }
1509
1510 #[test]
1511 fn test_move_u256_serialization() {
1512 let val = MoveU256::from_u128(0x0102_0304_0506_0708);
1513 let bcs = aptos_bcs::to_bytes(&val).unwrap();
1514 assert_eq!(bcs.len(), 32);
1516 assert_eq!(&bcs[..8], &[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]);
1518 }
1519
1520 #[test]
1521 fn test_move_i128_new() {
1522 let val = MoveI128::new(42);
1523 assert_eq!(val.0, 42);
1524 }
1525
1526 #[test]
1527 fn test_move_i128_from_i128() {
1528 let val: MoveI128 = (-100i128).into();
1529 assert_eq!(val.0, -100);
1530 }
1531
1532 #[test]
1533 fn test_move_i128_serialization_positive() {
1534 let val = MoveI128::new(0x0102_0304_0506_0708);
1535 let bcs = aptos_bcs::to_bytes(&val).unwrap();
1536 assert_eq!(bcs.len(), 16);
1538 assert_eq!(&bcs[..8], &[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]);
1540 assert_eq!(&bcs[8..], &[0, 0, 0, 0, 0, 0, 0, 0]);
1542 }
1543
1544 #[test]
1545 fn test_move_i128_serialization_negative() {
1546 let val = MoveI128::new(-1);
1547 let bcs = aptos_bcs::to_bytes(&val).unwrap();
1548 assert_eq!(bcs.len(), 16);
1549 assert_eq!(bcs, vec![0xFF; 16]);
1551 }
1552
1553 #[test]
1554 fn test_move_i256_from_i128_positive() {
1555 let val = MoveI256::from_i128(42);
1556 let expected = 42i128.to_le_bytes();
1558 assert_eq!(&val.0[..16], &expected);
1559 assert_eq!(&val.0[16..], &[0u8; 16]);
1561 }
1562
1563 #[test]
1564 fn test_move_i256_from_i128_negative() {
1565 let val = MoveI256::from_i128(-1);
1566 assert_eq!(val.0, [0xFF; 32]);
1568 }
1569
1570 #[test]
1571 fn test_move_i256_from_le_bytes() {
1572 let bytes = [0xcd; 32];
1573 let val = MoveI256::from_le_bytes(bytes);
1574 assert_eq!(val.0, bytes);
1575 }
1576
1577 #[test]
1578 fn test_move_i256_from_trait() {
1579 let val: MoveI256 = (-100i128).into();
1580 let expected = MoveI256::from_i128(-100);
1581 assert_eq!(val, expected);
1582 }
1583
1584 #[test]
1585 fn test_move_i256_serialization() {
1586 let val = MoveI256::from_i128(0x0102_0304_0506_0708);
1587 let bcs = aptos_bcs::to_bytes(&val).unwrap();
1588 assert_eq!(bcs.len(), 32);
1590 assert_eq!(&bcs[..8], &[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]);
1592 }
1593
1594 #[test]
1595 fn test_move_i256_serialization_negative() {
1596 let val = MoveI256::from_i128(-1);
1597 let bcs = aptos_bcs::to_bytes(&val).unwrap();
1598 assert_eq!(bcs.len(), 32);
1599 assert_eq!(bcs, vec![0xFF; 32]);
1601 }
1602
1603 fn payload_as_entry_function(
1606 p: crate::transaction::TransactionPayload,
1607 ) -> crate::transaction::EntryFunction {
1608 match p {
1609 crate::transaction::TransactionPayload::EntryFunction(ef) => ef,
1610 other => panic!(
1611 "expected TransactionPayload::EntryFunction, got: {:?}",
1612 std::mem::discriminant(&other)
1613 ),
1614 }
1615 }
1616
1617 #[test]
1618 fn test_input_entry_function_data_new() {
1619 let builder = InputEntryFunctionData::new("0x1::coin::transfer");
1620 let entry_fn = payload_as_entry_function(builder.build().expect("build should succeed"));
1621 assert_eq!(entry_fn.module.name.as_str(), "coin");
1622 assert_eq!(entry_fn.function, "transfer");
1623 assert!(entry_fn.type_args.is_empty());
1624 assert!(entry_fn.args.is_empty());
1625 }
1626
1627 #[test]
1628 fn test_input_entry_function_data_invalid_function_id() {
1629 let builder = InputEntryFunctionData::new("invalid");
1630 let result = builder.build();
1631 assert!(result.is_err());
1632 assert!(
1633 result
1634 .unwrap_err()
1635 .to_string()
1636 .contains("Invalid function ID")
1637 );
1638 }
1639
1640 #[test]
1641 fn test_input_entry_function_data_type_arg() {
1642 let entry_fn = payload_as_entry_function(
1643 InputEntryFunctionData::new("0x1::coin::transfer")
1644 .type_arg("0x1::aptos_coin::AptosCoin")
1645 .build()
1646 .expect("build should succeed"),
1647 );
1648 assert_eq!(entry_fn.type_args.len(), 1);
1649 assert_eq!(
1650 entry_fn.type_args[0].to_string(),
1651 "0x1::aptos_coin::AptosCoin"
1652 );
1653 }
1654
1655 #[test]
1656 fn test_input_entry_function_data_invalid_type_arg() {
1657 let builder =
1658 InputEntryFunctionData::new("0x1::coin::transfer").type_arg("not a valid type");
1659 let result = builder.build();
1660 assert!(result.is_err());
1661 assert!(result.unwrap_err().to_string().contains("type argument"));
1662 }
1663
1664 #[test]
1665 fn test_input_entry_function_data_type_arg_typed() {
1666 use crate::types::TypeTag;
1667
1668 let entry_fn = payload_as_entry_function(
1669 InputEntryFunctionData::new("0x1::coin::transfer")
1670 .type_arg_typed(TypeTag::U64)
1671 .build()
1672 .expect("build should succeed"),
1673 );
1674 assert_eq!(entry_fn.type_args, vec![TypeTag::U64]);
1675 }
1676
1677 #[test]
1678 fn test_input_entry_function_data_type_args() {
1679 let entry_fn = payload_as_entry_function(
1680 InputEntryFunctionData::new("0x1::coin::transfer")
1681 .type_args(["u64", "u128"])
1682 .build()
1683 .expect("build should succeed"),
1684 );
1685 assert_eq!(entry_fn.type_args.len(), 2);
1686 assert_eq!(entry_fn.type_args[0].to_string(), "u64");
1687 assert_eq!(entry_fn.type_args[1].to_string(), "u128");
1688 }
1689
1690 #[test]
1691 fn test_input_entry_function_data_type_args_typed() {
1692 use crate::types::TypeTag;
1693
1694 let entry_fn = payload_as_entry_function(
1695 InputEntryFunctionData::new("0x1::coin::transfer")
1696 .type_args_typed([TypeTag::U64, TypeTag::Bool])
1697 .build()
1698 .expect("build should succeed"),
1699 );
1700 assert_eq!(entry_fn.type_args, vec![TypeTag::U64, TypeTag::Bool]);
1701 }
1702
1703 #[test]
1704 fn test_input_entry_function_data_arg() {
1705 let entry_fn = payload_as_entry_function(
1706 InputEntryFunctionData::new("0x1::coin::transfer")
1707 .arg(42u64)
1708 .arg(true)
1709 .arg("hello".to_string())
1710 .build()
1711 .expect("build should succeed"),
1712 );
1713 assert_eq!(entry_fn.args.len(), 3, "all three args must be present");
1714 assert_eq!(entry_fn.args[0][0], 42);
1716 assert_eq!(entry_fn.args[1], vec![0x01]);
1718 }
1719
1720 #[test]
1721 fn test_input_entry_function_data_arg_raw() {
1722 let raw_bytes = vec![0x01, 0x02, 0x03];
1723 let entry_fn = payload_as_entry_function(
1724 InputEntryFunctionData::new("0x1::coin::transfer")
1725 .arg_raw(raw_bytes.clone())
1726 .build()
1727 .expect("build should succeed"),
1728 );
1729 assert_eq!(entry_fn.args.len(), 1);
1730 assert_eq!(entry_fn.args[0], raw_bytes);
1731 }
1732
1733 #[test]
1734 fn test_input_entry_function_data_args() {
1735 let entry_fn = payload_as_entry_function(
1736 InputEntryFunctionData::new("0x1::coin::transfer")
1737 .args([1u64, 2u64, 3u64])
1738 .build()
1739 .expect("build should succeed"),
1740 );
1741 assert_eq!(entry_fn.args.len(), 3);
1742 assert_eq!(entry_fn.args[0][0], 1);
1743 assert_eq!(entry_fn.args[1][0], 2);
1744 assert_eq!(entry_fn.args[2][0], 3);
1745 }
1746
1747 #[test]
1748 fn test_input_entry_function_data_transfer_apt() {
1749 use crate::types::AccountAddress;
1750
1751 let recipient = AccountAddress::from_hex("0x123").unwrap();
1752 let entry_fn = payload_as_entry_function(
1753 InputEntryFunctionData::transfer_apt(recipient, 1000)
1754 .expect("transfer_apt should succeed"),
1755 );
1756 assert_eq!(entry_fn.module.address, AccountAddress::ONE);
1757 assert_eq!(entry_fn.module.name.as_str(), "aptos_account");
1758 assert_eq!(entry_fn.function, "transfer");
1759 assert_eq!(entry_fn.args.len(), 2);
1760 }
1761
1762 #[test]
1763 fn test_input_entry_function_data_builder_debug() {
1764 let builder = InputEntryFunctionData::new("0x1::coin::transfer");
1765 let debug = format!("{builder:?}");
1766 assert!(debug.contains("InputEntryFunctionDataBuilder"));
1767 }
1768
1769 #[test]
1770 fn test_input_entry_function_data_builder_clone() {
1771 let builder = InputEntryFunctionData::new("0x1::coin::transfer").arg(42u64);
1772 let cloned = builder.clone();
1773 let original_built = payload_as_entry_function(builder.build().expect("original builds"));
1774 let cloned_built = payload_as_entry_function(cloned.build().expect("clone builds"));
1775 assert_eq!(original_built.module.name, cloned_built.module.name);
1777 assert_eq!(original_built.function, cloned_built.function);
1778 assert_eq!(original_built.args, cloned_built.args);
1779 }
1780
1781 #[test]
1782 fn test_move_u256_debug() {
1783 let val = MoveU256::from_u128(123_456_789);
1784 let debug = format!("{val:?}");
1785 assert!(debug.contains("MoveU256"));
1786 }
1787
1788 #[test]
1789 fn test_move_i128_debug() {
1790 let val = MoveI128::new(-42);
1791 let debug = format!("{val:?}");
1792 assert!(debug.contains("MoveI128"));
1793 }
1794
1795 #[test]
1796 fn test_move_i256_debug() {
1797 let val = MoveI256::from_i128(-42);
1798 let debug = format!("{val:?}");
1799 assert!(debug.contains("MoveI256"));
1800 }
1801
1802 #[test]
1803 fn test_move_u256_equality() {
1804 let val1 = MoveU256::from_u128(100);
1805 let val2 = MoveU256::from_u128(100);
1806 let val3 = MoveU256::from_u128(200);
1807 assert_eq!(val1, val2);
1808 assert_ne!(val1, val3);
1809 }
1810
1811 #[test]
1812 fn test_move_i256_equality() {
1813 let val1 = MoveI256::from_i128(-50);
1814 let val2 = MoveI256::from_i128(-50);
1815 let val3 = MoveI256::from_i128(50);
1816 assert_eq!(val1, val2);
1817 assert_ne!(val1, val3);
1818 }
1819
1820 #[test]
1821 fn test_move_u256_clone() {
1822 let val1 = MoveU256::from_u128(999);
1823 let val2 = val1;
1824 assert_eq!(val1, val2);
1825 }
1826
1827 #[test]
1828 fn test_move_i256_clone() {
1829 let val1 = MoveI256::from_i128(-999);
1830 let val2 = val1;
1831 assert_eq!(val1, val2);
1832 }
1833
1834 #[test]
1835 fn test_create_account_helper() {
1836 let auth_key = AccountAddress::from_hex("0x123").unwrap();
1837 let ef = payload_as_entry_function(
1838 InputEntryFunctionData::create_account(auth_key).expect("create_account should build"),
1839 );
1840 assert_eq!(ef.module.name.as_str(), "aptos_account");
1841 assert_eq!(ef.function, "create_account");
1842 assert_eq!(ef.args.len(), 1);
1843 assert_eq!(ef.args[0], aptos_bcs::to_bytes(&auth_key).unwrap());
1844 }
1845
1846 #[test]
1847 fn test_register_coin_helper() {
1848 let ef = payload_as_entry_function(
1849 InputEntryFunctionData::register_coin("0x1::aptos_coin::AptosCoin")
1850 .expect("register_coin should build"),
1851 );
1852 assert_eq!(ef.module.name.as_str(), "managed_coin");
1853 assert_eq!(ef.function, "register");
1854 assert_eq!(ef.type_args.len(), 1);
1855 assert!(ef.args.is_empty());
1856 }
1857
1858 #[test]
1859 fn test_register_coin_invalid_type() {
1860 let result = InputEntryFunctionData::register_coin("not a type");
1861 assert!(result.is_err());
1862 }
1863
1864 #[test]
1865 fn test_publish_package_helper() {
1866 let metadata = vec![1u8, 2, 3];
1867 let code = vec![vec![4u8, 5], vec![6u8]];
1868 let ef = payload_as_entry_function(
1869 InputEntryFunctionData::publish_package(metadata.clone(), code.clone())
1870 .expect("publish_package should build"),
1871 );
1872 assert_eq!(ef.module.name.as_str(), "code");
1873 assert_eq!(ef.function, "publish_package_txn");
1874 assert_eq!(ef.args.len(), 2);
1875 assert_eq!(ef.args[0], aptos_bcs::to_bytes(&metadata).unwrap());
1876 assert_eq!(ef.args[1], aptos_bcs::to_bytes(&code).unwrap());
1877 }
1878
1879 #[test]
1880 fn test_mint_soul_bound_digital_asset_helper() {
1881 let soul_bound_to = AccountAddress::from_hex("0xabc").unwrap();
1882 let ef = payload_as_entry_function(
1883 InputEntryFunctionData::mint_soul_bound_digital_asset(
1884 "My Collection",
1885 "desc",
1886 "Token #1",
1887 "https://example.com/1",
1888 vec!["level".to_string()],
1889 vec!["u64".to_string()],
1890 vec![aptos_bcs::to_bytes(&1u64).unwrap()],
1891 soul_bound_to,
1892 )
1893 .expect("mint_soul_bound should build"),
1894 );
1895 assert_eq!(ef.module.name.as_str(), "aptos_token");
1896 assert_eq!(ef.function, "mint_soul_bound");
1897 assert_eq!(ef.args.len(), 8);
1899 assert_eq!(
1900 ef.args[7],
1901 aptos_bcs::to_bytes(&soul_bound_to).unwrap(),
1902 "final arg is the soul-bound recipient"
1903 );
1904 }
1905
1906 #[test]
1907 fn test_burn_digital_asset_helper() {
1908 let token = AccountAddress::from_hex("0xdead").unwrap();
1909 let ef = payload_as_entry_function(
1910 InputEntryFunctionData::burn_digital_asset(token).expect("burn should build"),
1911 );
1912 assert_eq!(ef.module.name.as_str(), "aptos_token");
1913 assert_eq!(ef.function, "burn");
1914 assert_eq!(ef.type_args.len(), 1);
1915 assert_eq!(ef.args.len(), 1);
1916 }
1917
1918 #[test]
1919 fn test_freeze_and_unfreeze_digital_asset_transfer_helpers() {
1920 let token = AccountAddress::from_hex("0xbeef").unwrap();
1921
1922 let freeze = payload_as_entry_function(
1923 InputEntryFunctionData::freeze_digital_asset_transfer(token)
1924 .expect("freeze should build"),
1925 );
1926 assert_eq!(freeze.function, "freeze_transfer");
1927 assert_eq!(freeze.type_args.len(), 1);
1928 assert_eq!(freeze.args.len(), 1);
1929
1930 let unfreeze = payload_as_entry_function(
1931 InputEntryFunctionData::unfreeze_digital_asset_transfer(token)
1932 .expect("unfreeze should build"),
1933 );
1934 assert_eq!(unfreeze.function, "unfreeze_transfer");
1935 assert_eq!(unfreeze.type_args.len(), 1);
1936 assert_eq!(unfreeze.args.len(), 1);
1937 }
1938
1939 #[test]
1940 fn test_remove_authentication_function_helper() {
1941 let module = AccountAddress::from_hex("0x123").unwrap();
1942 let ef = payload_as_entry_function(
1943 InputEntryFunctionData::remove_authentication_function(
1944 module,
1945 "my_auth",
1946 "authenticate",
1947 )
1948 .expect("remove_authentication_function should build"),
1949 );
1950 assert_eq!(ef.module.name.as_str(), "account_abstraction");
1951 assert_eq!(ef.function, "remove_authentication_function");
1952 assert_eq!(ef.args.len(), 3);
1953 }
1954
1955 #[test]
1956 fn test_arg_serialization_error_is_reported() {
1957 let result = InputEntryFunctionData::new("0x1::coin::transfer")
1960 .arg(1.5f64)
1961 .build();
1962 let err = result.unwrap_err();
1963 assert!(
1964 err.to_string().contains("Failed to serialize argument"),
1965 "unexpected error: {err}"
1966 );
1967 }
1968
1969 #[test]
1970 fn test_build_entry_function_reports_accumulated_errors() {
1971 let result = InputEntryFunctionData::new("0x1::coin::transfer")
1974 .type_arg("not a valid type")
1975 .build_entry_function();
1976 assert!(result.is_err());
1977 assert!(result.unwrap_err().to_string().contains("type argument"));
1978 }
1979
1980 #[test]
1981 fn test_build_entry_function_reports_invalid_module() {
1982 let result = InputEntryFunctionData::new("invalid").build_entry_function();
1985 assert!(result.is_err());
1986 assert!(
1987 result
1988 .unwrap_err()
1989 .to_string()
1990 .contains("Invalid function ID")
1991 );
1992 }
1993
1994 #[test]
1995 fn test_into_move_arg_success() {
1996 let bytes = 42u64.into_move_arg().unwrap();
1997 assert_eq!(bytes, aptos_bcs::to_bytes(&42u64).unwrap());
1998
1999 let addr_bytes = AccountAddress::ONE.into_move_arg().unwrap();
2000 assert_eq!(
2001 addr_bytes,
2002 aptos_bcs::to_bytes(&AccountAddress::ONE).unwrap()
2003 );
2004 }
2005
2006 #[test]
2007 fn test_into_move_arg_error() {
2008 let result = 1.5f64.into_move_arg();
2010 assert!(result.is_err());
2011 }
2012
2013 #[test]
2014 fn test_move_vec_helper() {
2015 let items = [100u64, 200u64, 300u64];
2016 let encoded = move_vec(&items);
2017 assert_eq!(encoded, aptos_bcs::to_bytes(&items.as_slice()).unwrap());
2018 assert!(!encoded.is_empty());
2019 }
2020
2021 #[test]
2022 fn test_move_string_helper() {
2023 assert_eq!(move_string("Alice"), "Alice".to_string());
2024 assert_eq!(move_string(""), String::new());
2025 }
2026
2027 #[test]
2028 fn test_move_u256_display() {
2029 assert_eq!(format!("{}", MoveU256::from_u128(12345)), "12345");
2030 assert_eq!(format!("{}", MoveU256::from_u128(0)), "0");
2031 assert_eq!(
2032 MoveU256([0xff; 32]).to_string(),
2033 "115792089237316195423570985008687907853269984665640564039457584007913129639935"
2034 );
2035 }
2036
2037 #[test]
2038 fn test_move_u256_deserialize_from_string() {
2039 let val: MoveU256 = serde_json::from_str("\"999\"").unwrap();
2041 assert_eq!(val, MoveU256::from_u128(999));
2042 }
2043
2044 #[test]
2045 fn test_move_u256_deserialize_from_u64() {
2046 let val: MoveU256 = serde_json::from_str("42").unwrap();
2048 assert_eq!(val, MoveU256::from_u128(42));
2049 }
2050
2051 #[test]
2052 fn test_move_u256_deserialize_invalid_type_uses_expecting() {
2053 let result: Result<MoveU256, _> = serde_json::from_str("true");
2056 let err = result.unwrap_err();
2057 assert!(
2058 err.to_string().contains("u256"),
2059 "expecting message should mention u256, got: {err}"
2060 );
2061 }
2062}