1use crate::MOVE_STDLIB_ADDRESS;
6use crate::MoveTypeTagTrait;
7use crate::MoveTypeTagTraitGeneric;
8use crate::SUI_CLOCK_OBJECT_ID;
9use crate::SUI_FRAMEWORK_ADDRESS;
10use crate::SUI_SYSTEM_ADDRESS;
11use crate::accumulator_root::accumulator_metadata_balance_type_maybe;
12use crate::accumulator_root::accumulator_value_balance_type_maybe;
13use crate::accumulator_root::is_balance_accumulator_owner_field;
14use crate::balance::Balance;
15use crate::coin::COIN_MODULE_NAME;
16use crate::coin::COIN_STRUCT_NAME;
17use crate::coin::Coin;
18use crate::coin::CoinMetadata;
19use crate::coin::TreasuryCap;
20use crate::coin_registry::Currency;
21pub use crate::committee::EpochId;
22use crate::crypto::{
23 AuthorityPublicKeyBytes, DefaultHash, PublicKey, SignatureScheme, SuiPublicKey, SuiSignature,
24};
25pub use crate::digests::{ObjectDigest, TransactionDigest, TransactionEffectsDigest};
26use crate::dynamic_field::DynamicFieldInfo;
27use crate::dynamic_field::DynamicFieldType;
28use crate::dynamic_field::{DYNAMIC_FIELD_FIELD_STRUCT_NAME, DYNAMIC_FIELD_MODULE_NAME};
29use crate::effects::TransactionEffects;
30use crate::effects::TransactionEffectsAPI;
31use crate::epoch_data::EpochData;
32use crate::error::ExecutionErrorKind;
33use crate::error::SuiError;
34use crate::error::SuiErrorKind;
35use crate::error::{ExecutionError, SuiResult};
36use crate::gas_coin::GAS;
37use crate::gas_coin::GasCoin;
38use crate::governance::STAKED_SUI_STRUCT_NAME;
39use crate::governance::STAKING_POOL_MODULE_NAME;
40use crate::governance::StakedSui;
41use crate::id::RESOLVED_SUI_ID;
42use crate::messages_checkpoint::CheckpointTimestamp;
43use crate::multisig::MultiSigPublicKey;
44use crate::object::{Object, Owner};
45use crate::parse_sui_struct_tag;
46use crate::signature::GenericSignature;
47use crate::sui_serde::Readable;
48use crate::sui_serde::to_custom_deser_error;
49use crate::sui_serde::to_sui_struct_tag_string;
50use crate::transaction::Transaction;
51use crate::transaction::VerifiedTransaction;
52use crate::zk_login_authenticator::ZkLoginAuthenticator;
53use anyhow::anyhow;
54use fastcrypto::encoding::decode_bytes_hex;
55use fastcrypto::encoding::{Encoding, Hex};
56use fastcrypto::hash::HashFunction;
57use fastcrypto::traits::AllowedRng;
58use fastcrypto_zkp::bn254::zk_login::ZkLoginInputs;
59use move_binary_format::CompiledModule;
60use move_binary_format::file_format::SignatureToken;
61use move_bytecode_utils::resolve_struct;
62use move_core_types::account_address::AccountAddress;
63use move_core_types::annotated_value as A;
64use move_core_types::ident_str;
65use move_core_types::identifier::IdentStr;
66use move_core_types::language_storage::ModuleId;
67use move_core_types::language_storage::StructTag;
68use move_core_types::language_storage::TypeTag;
69use rand::Rng;
70use schemars::JsonSchema;
71use serde::Deserializer;
72use serde::Serializer;
73use serde::ser::Error;
74use serde::ser::SerializeSeq;
75use serde::{Deserialize, Serialize};
76use serde_with::DeserializeAs;
77use serde_with::SerializeAs;
78use serde_with::serde_as;
79use shared_crypto::intent::HashingIntentScope;
80use std::borrow::Cow;
81use std::cmp::max;
82use std::convert::{TryFrom, TryInto};
83use std::fmt;
84use std::str::FromStr;
85use sui_protocol_config::ProtocolConfig;
86
87#[cfg(test)]
88#[path = "unit_tests/base_types_tests.rs"]
89mod base_types_tests;
90
91#[cfg(test)]
92#[path = "unit_tests/accumulator_types_tests.rs"]
93mod accumulator_types_tests;
94
95#[derive(
96 Eq,
97 PartialEq,
98 Ord,
99 PartialOrd,
100 Copy,
101 Clone,
102 Hash,
103 Default,
104 Debug,
105 Serialize,
106 Deserialize,
107 JsonSchema,
108)]
109#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))]
110pub struct SequenceNumber(u64);
111
112impl SequenceNumber {
113 pub fn one_before(&self) -> Option<SequenceNumber> {
114 if self.0 == 0 {
115 None
116 } else {
117 Some(SequenceNumber(self.0 - 1))
118 }
119 }
120
121 pub fn next(&self) -> SequenceNumber {
122 SequenceNumber(self.0 + 1)
123 }
124}
125
126pub type TxSequenceNumber = u64;
127
128impl fmt::Display for SequenceNumber {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 write!(f, "{:#x}", self.0)
131 }
132}
133
134pub type VersionNumber = SequenceNumber;
135
136#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Hash, Default, Debug, Serialize, Deserialize)]
137pub struct UserData(pub Option<[u8; 32]>);
138
139pub type AuthorityName = AuthorityPublicKeyBytes;
140
141pub trait ConciseableName<'a> {
142 type ConciseTypeRef: std::fmt::Debug;
143 type ConciseType: std::fmt::Debug;
144
145 fn concise(&'a self) -> Self::ConciseTypeRef;
146 fn concise_owned(&self) -> Self::ConciseType;
147}
148
149#[serde_as]
150#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema)]
151pub struct ObjectID(
152 #[schemars(with = "Hex")]
153 #[serde_as(as = "Readable<HexAccountAddress, _>")]
154 AccountAddress,
155);
156
157#[serde_as]
158#[derive(Debug, Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize)]
159pub enum FullObjectID {
160 Fastpath(ObjectID),
161 Consensus(ConsensusObjectSequenceKey),
162}
163
164impl FullObjectID {
165 pub fn new(object_id: ObjectID, start_version: Option<SequenceNumber>) -> Self {
166 if let Some(start_version) = start_version {
167 Self::Consensus((object_id, start_version))
168 } else {
169 Self::Fastpath(object_id)
170 }
171 }
172
173 pub fn id(&self) -> ObjectID {
174 match &self {
175 FullObjectID::Fastpath(object_id) => *object_id,
176 FullObjectID::Consensus(consensus_object_sequence_key) => {
177 consensus_object_sequence_key.0
178 }
179 }
180 }
181}
182
183pub type VersionDigest = (SequenceNumber, ObjectDigest);
184
185pub type ObjectRef = (ObjectID, SequenceNumber, ObjectDigest);
186
187pub fn random_object_ref() -> ObjectRef {
188 (
189 ObjectID::random(),
190 SequenceNumber::new(),
191 ObjectDigest::new([0; 32]),
192 )
193}
194
195pub fn update_object_ref_for_testing(object_ref: ObjectRef) -> ObjectRef {
196 (
197 object_ref.0,
198 object_ref.1.next(),
199 ObjectDigest::new([0; 32]),
200 )
201}
202
203#[derive(Debug, Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize)]
204pub struct FullObjectRef(pub FullObjectID, pub SequenceNumber, pub ObjectDigest);
205
206impl FullObjectRef {
207 pub fn from_fastpath_ref(object_ref: ObjectRef) -> Self {
208 Self(
209 FullObjectID::Fastpath(object_ref.0),
210 object_ref.1,
211 object_ref.2,
212 )
213 }
214
215 pub fn from_object_ref_and_owner(object_ref: ObjectRef, owner: &Owner) -> Self {
216 let full_id = if let Some(start_version) = owner.start_version() {
217 FullObjectID::Consensus((object_ref.0, start_version))
218 } else {
219 FullObjectID::Fastpath(object_ref.0)
220 };
221 Self(full_id, object_ref.1, object_ref.2)
222 }
223
224 pub fn as_object_ref(&self) -> ObjectRef {
225 (self.0.id(), self.1, self.2)
226 }
227}
228pub type ConsensusObjectSequenceKey = (ObjectID, SequenceNumber);
231
232#[derive(Eq, PartialEq, PartialOrd, Ord, Debug, Clone, Deserialize, Serialize, Hash)]
237pub struct MoveObjectType(MoveObjectType_);
238
239#[derive(Eq, PartialEq, PartialOrd, Ord, Debug, Clone, Deserialize, Serialize, Hash)]
242pub enum MoveObjectType_ {
243 Other(StructTag),
245 GasCoin,
247 StakedSui,
249 Coin(TypeTag),
251 SuiBalanceAccumulatorField,
254 BalanceAccumulatorField(TypeTag),
258
259 BalanceAccumulatorOwnerField,
261
262 SuiBalanceAccumulatorMetadataField,
265 BalanceAccumulatorMetadataField(TypeTag),
269 }
273
274impl MoveObjectType {
275 pub fn gas_coin() -> Self {
276 Self(MoveObjectType_::GasCoin)
277 }
278
279 pub fn is_efficient_representation(&self) -> bool {
280 !matches!(self.0, MoveObjectType_::Other(_))
281 }
282
283 pub fn coin(coin_type: TypeTag) -> Self {
284 Self(if GAS::is_gas_type(&coin_type) {
285 MoveObjectType_::GasCoin
286 } else {
287 MoveObjectType_::Coin(coin_type)
288 })
289 }
290
291 pub fn staked_sui() -> Self {
292 Self(MoveObjectType_::StakedSui)
293 }
294
295 pub fn address(&self) -> AccountAddress {
296 match &self.0 {
297 MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => SUI_FRAMEWORK_ADDRESS,
298 MoveObjectType_::StakedSui => SUI_SYSTEM_ADDRESS,
299 MoveObjectType_::SuiBalanceAccumulatorField
300 | MoveObjectType_::BalanceAccumulatorField(_)
301 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
302 | MoveObjectType_::BalanceAccumulatorMetadataField(_)
303 | MoveObjectType_::BalanceAccumulatorOwnerField => SUI_FRAMEWORK_ADDRESS,
304 MoveObjectType_::Other(s) => s.address,
305 }
306 }
307
308 pub fn module(&self) -> &IdentStr {
309 match &self.0 {
310 MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => COIN_MODULE_NAME,
311 MoveObjectType_::StakedSui => STAKING_POOL_MODULE_NAME,
312 MoveObjectType_::SuiBalanceAccumulatorField
313 | MoveObjectType_::BalanceAccumulatorField(_)
314 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
315 | MoveObjectType_::BalanceAccumulatorMetadataField(_)
316 | MoveObjectType_::BalanceAccumulatorOwnerField => DYNAMIC_FIELD_MODULE_NAME,
317 MoveObjectType_::Other(s) => &s.module,
318 }
319 }
320
321 pub fn name(&self) -> &IdentStr {
322 match &self.0 {
323 MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => COIN_STRUCT_NAME,
324 MoveObjectType_::StakedSui => STAKED_SUI_STRUCT_NAME,
325 MoveObjectType_::SuiBalanceAccumulatorField
326 | MoveObjectType_::BalanceAccumulatorField(_)
327 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
328 | MoveObjectType_::BalanceAccumulatorMetadataField(_)
329 | MoveObjectType_::BalanceAccumulatorOwnerField => DYNAMIC_FIELD_FIELD_STRUCT_NAME,
330 MoveObjectType_::Other(s) => &s.name,
331 }
332 }
333
334 pub fn type_params(&self) -> Vec<Cow<'_, TypeTag>> {
335 match &self.0 {
336 MoveObjectType_::GasCoin => vec![Cow::Owned(GAS::type_tag())],
337 MoveObjectType_::StakedSui => vec![],
338 MoveObjectType_::Coin(inner) => vec![Cow::Borrowed(inner)],
339 MoveObjectType_::SuiBalanceAccumulatorField => {
340 Self::balance_accumulator_field_type_params(GAS::type_tag())
341 .into_iter()
342 .map(Cow::Owned)
343 .collect()
344 }
345 MoveObjectType_::BalanceAccumulatorOwnerField => {
346 Self::balance_accumulator_owner_field_type_params()
347 .into_iter()
348 .map(Cow::Owned)
349 .collect()
350 }
351 MoveObjectType_::BalanceAccumulatorField(inner) => {
352 Self::balance_accumulator_field_type_params(inner.clone())
353 .into_iter()
354 .map(Cow::Owned)
355 .collect()
356 }
357 MoveObjectType_::SuiBalanceAccumulatorMetadataField => {
358 Self::balance_accumulator_metadata_field_type_params(GAS::type_tag())
359 .into_iter()
360 .map(Cow::Owned)
361 .collect()
362 }
363 MoveObjectType_::BalanceAccumulatorMetadataField(inner) => {
364 Self::balance_accumulator_metadata_field_type_params(inner.clone())
365 .into_iter()
366 .map(Cow::Owned)
367 .collect()
368 }
369 MoveObjectType_::Other(s) => s.type_params.iter().map(Cow::Borrowed).collect(),
370 }
371 }
372
373 pub fn into_type_params(self) -> Vec<TypeTag> {
374 match self.0 {
375 MoveObjectType_::GasCoin => vec![GAS::type_tag()],
376 MoveObjectType_::StakedSui => vec![],
377 MoveObjectType_::Coin(inner) => vec![inner],
378 MoveObjectType_::SuiBalanceAccumulatorField => {
379 Self::balance_accumulator_field_type_params(GAS::type_tag())
380 }
381 MoveObjectType_::BalanceAccumulatorField(inner) => {
382 Self::balance_accumulator_field_type_params(inner)
383 }
384 MoveObjectType_::BalanceAccumulatorOwnerField => vec![],
385 MoveObjectType_::SuiBalanceAccumulatorMetadataField => {
386 Self::balance_accumulator_metadata_field_type_params(GAS::type_tag())
387 }
388 MoveObjectType_::BalanceAccumulatorMetadataField(inner) => {
389 Self::balance_accumulator_metadata_field_type_params(inner.clone())
390 }
391 MoveObjectType_::Other(s) => s.type_params,
392 }
393 }
394
395 pub fn coin_type_maybe(&self) -> Option<TypeTag> {
396 match &self.0 {
397 MoveObjectType_::GasCoin => Some(GAS::type_tag()),
398 MoveObjectType_::Coin(inner) => Some(inner.clone()),
399 MoveObjectType_::StakedSui => None,
400 MoveObjectType_::SuiBalanceAccumulatorField => None,
401 MoveObjectType_::BalanceAccumulatorField(_) => None,
402 MoveObjectType_::BalanceAccumulatorOwnerField => None,
403 MoveObjectType_::SuiBalanceAccumulatorMetadataField => None,
404 MoveObjectType_::BalanceAccumulatorMetadataField(_) => None,
405 MoveObjectType_::Other(_) => None,
406 }
407 }
408
409 pub fn balance_accumulator_field_type_maybe(&self) -> Option<TypeTag> {
410 match &self.0 {
411 MoveObjectType_::SuiBalanceAccumulatorField => Some(GAS::type_tag()),
412 MoveObjectType_::BalanceAccumulatorField(inner) => Some(inner.clone()),
413 _ => None,
414 }
415 }
416
417 pub fn is_balance_accumulator_field(&self) -> bool {
418 matches!(
419 self.0,
420 MoveObjectType_::SuiBalanceAccumulatorField
421 | MoveObjectType_::BalanceAccumulatorField(_)
422 )
423 }
424
425 pub fn is_sui_balance_accumulator_field(&self) -> bool {
426 matches!(self.0, MoveObjectType_::SuiBalanceAccumulatorField)
427 }
428
429 pub fn balance_accumulator_metadata_field_type_maybe(&self) -> Option<TypeTag> {
430 match &self.0 {
431 MoveObjectType_::SuiBalanceAccumulatorMetadataField => Some(GAS::type_tag()),
432 MoveObjectType_::BalanceAccumulatorMetadataField(inner) => Some(inner.clone()),
433 _ => None,
434 }
435 }
436
437 pub fn is_balance_accumulator_metadata_field(&self) -> bool {
438 matches!(
439 self.0,
440 MoveObjectType_::SuiBalanceAccumulatorMetadataField
441 | MoveObjectType_::BalanceAccumulatorMetadataField(_)
442 )
443 }
444
445 pub fn is_balance_accumulator_owner_field(&self) -> bool {
446 matches!(self.0, MoveObjectType_::BalanceAccumulatorOwnerField)
447 }
448
449 pub fn module_id(&self) -> ModuleId {
450 ModuleId::new(self.address(), self.module().to_owned())
451 }
452
453 pub fn size_for_gas_metering(&self) -> usize {
454 match &self.0 {
456 MoveObjectType_::GasCoin => 1,
457 MoveObjectType_::StakedSui => 1,
458 MoveObjectType_::Coin(inner) => bcs::serialized_size(inner).unwrap() + 1,
459 MoveObjectType_::SuiBalanceAccumulatorField => 1,
460 MoveObjectType_::BalanceAccumulatorField(inner) => {
461 bcs::serialized_size(inner).unwrap() + 1
462 }
463 MoveObjectType_::BalanceAccumulatorOwnerField => 1,
464 MoveObjectType_::SuiBalanceAccumulatorMetadataField => 1,
465 MoveObjectType_::BalanceAccumulatorMetadataField(inner) => {
466 bcs::serialized_size(inner).unwrap() + 1
467 }
468 MoveObjectType_::Other(s) => bcs::serialized_size(s).unwrap() + 1,
469 }
470 }
471
472 pub fn is_coin(&self) -> bool {
474 match &self.0 {
475 MoveObjectType_::GasCoin | MoveObjectType_::Coin(_) => true,
476 MoveObjectType_::StakedSui
477 | MoveObjectType_::SuiBalanceAccumulatorField
478 | MoveObjectType_::BalanceAccumulatorField(_)
479 | MoveObjectType_::BalanceAccumulatorOwnerField
480 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
481 | MoveObjectType_::BalanceAccumulatorMetadataField(_)
482 | MoveObjectType_::Other(_) => false,
483 }
484 }
485
486 pub fn is_gas_coin(&self) -> bool {
488 match &self.0 {
489 MoveObjectType_::GasCoin => true,
490 MoveObjectType_::StakedSui
491 | MoveObjectType_::Coin(_)
492 | MoveObjectType_::SuiBalanceAccumulatorField
493 | MoveObjectType_::BalanceAccumulatorField(_)
494 | MoveObjectType_::BalanceAccumulatorOwnerField
495 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
496 | MoveObjectType_::BalanceAccumulatorMetadataField(_)
497 | MoveObjectType_::Other(_) => false,
498 }
499 }
500
501 pub fn is_coin_t(&self, t: &TypeTag) -> bool {
503 match &self.0 {
504 MoveObjectType_::GasCoin => GAS::is_gas_type(t),
505 MoveObjectType_::Coin(c) => t == c,
506 MoveObjectType_::StakedSui
507 | MoveObjectType_::SuiBalanceAccumulatorField
508 | MoveObjectType_::BalanceAccumulatorField(_)
509 | MoveObjectType_::BalanceAccumulatorOwnerField
510 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
511 | MoveObjectType_::BalanceAccumulatorMetadataField(_)
512 | MoveObjectType_::Other(_) => false,
513 }
514 }
515
516 pub fn is_staked_sui(&self) -> bool {
517 match &self.0 {
518 MoveObjectType_::StakedSui => true,
519 MoveObjectType_::GasCoin
520 | MoveObjectType_::Coin(_)
521 | MoveObjectType_::SuiBalanceAccumulatorField
522 | MoveObjectType_::BalanceAccumulatorField(_)
523 | MoveObjectType_::BalanceAccumulatorOwnerField
524 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
525 | MoveObjectType_::BalanceAccumulatorMetadataField(_)
526 | MoveObjectType_::Other(_) => false,
527 }
528 }
529
530 pub fn is_coin_metadata(&self) -> bool {
531 match &self.0 {
532 MoveObjectType_::GasCoin
533 | MoveObjectType_::StakedSui
534 | MoveObjectType_::Coin(_)
535 | MoveObjectType_::SuiBalanceAccumulatorField
536 | MoveObjectType_::BalanceAccumulatorField(_)
537 | MoveObjectType_::BalanceAccumulatorOwnerField
538 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
539 | MoveObjectType_::BalanceAccumulatorMetadataField(_) => false,
540 MoveObjectType_::Other(s) => CoinMetadata::is_coin_metadata(s),
541 }
542 }
543
544 pub fn is_currency(&self) -> bool {
545 match &self.0 {
546 MoveObjectType_::GasCoin
547 | MoveObjectType_::StakedSui
548 | MoveObjectType_::Coin(_)
549 | MoveObjectType_::SuiBalanceAccumulatorField
550 | MoveObjectType_::BalanceAccumulatorField(_)
551 | MoveObjectType_::BalanceAccumulatorOwnerField
552 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
553 | MoveObjectType_::BalanceAccumulatorMetadataField(_) => false,
554 MoveObjectType_::Other(s) => Currency::is_currency(s),
555 }
556 }
557
558 pub fn is_treasury_cap(&self) -> bool {
559 match &self.0 {
560 MoveObjectType_::GasCoin
561 | MoveObjectType_::StakedSui
562 | MoveObjectType_::Coin(_)
563 | MoveObjectType_::SuiBalanceAccumulatorField
564 | MoveObjectType_::BalanceAccumulatorField(_)
565 | MoveObjectType_::BalanceAccumulatorOwnerField
566 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
567 | MoveObjectType_::BalanceAccumulatorMetadataField(_) => false,
568 MoveObjectType_::Other(s) => TreasuryCap::is_treasury_type(s),
569 }
570 }
571
572 pub fn is_upgrade_cap(&self) -> bool {
573 self.address() == SUI_FRAMEWORK_ADDRESS
574 && self.module().as_str() == "package"
575 && self.name().as_str() == "UpgradeCap"
576 }
577
578 pub fn is_regulated_coin_metadata(&self) -> bool {
579 self.address() == SUI_FRAMEWORK_ADDRESS
580 && self.module().as_str() == "coin"
581 && self.name().as_str() == "RegulatedCoinMetadata"
582 }
583
584 pub fn is_coin_deny_cap(&self) -> bool {
585 self.address() == SUI_FRAMEWORK_ADDRESS
586 && self.module().as_str() == "coin"
587 && self.name().as_str() == "DenyCap"
588 }
589
590 pub fn is_coin_deny_cap_v2(&self) -> bool {
591 self.address() == SUI_FRAMEWORK_ADDRESS
592 && self.module().as_str() == "coin"
593 && self.name().as_str() == "DenyCapV2"
594 }
595
596 pub fn is_dynamic_field(&self) -> bool {
597 match &self.0 {
598 MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => {
599 false
600 }
601 MoveObjectType_::SuiBalanceAccumulatorField
602 | MoveObjectType_::BalanceAccumulatorField(_)
603 | MoveObjectType_::BalanceAccumulatorOwnerField
604 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
605 | MoveObjectType_::BalanceAccumulatorMetadataField(_) => {
606 true }
608 MoveObjectType_::Other(s) => DynamicFieldInfo::is_dynamic_field(s),
609 }
610 }
611
612 pub fn try_extract_field_name(&self, type_: &DynamicFieldType) -> SuiResult<TypeTag> {
613 match &self.0 {
614 MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => {
615 Err(SuiErrorKind::ObjectDeserializationError {
616 error: "Error extracting dynamic object name from specialized object type"
617 .to_string(),
618 }
619 .into())
620 }
621 MoveObjectType_::SuiBalanceAccumulatorField
622 | MoveObjectType_::BalanceAccumulatorField(_)
623 | MoveObjectType_::BalanceAccumulatorOwnerField
624 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
625 | MoveObjectType_::BalanceAccumulatorMetadataField(_) => {
626 let struct_tag: StructTag = self.clone().into();
627 DynamicFieldInfo::try_extract_field_name(&struct_tag, type_)
628 }
629 MoveObjectType_::Other(s) => DynamicFieldInfo::try_extract_field_name(s, type_),
630 }
631 }
632
633 pub fn try_extract_field_value(&self) -> SuiResult<TypeTag> {
634 match &self.0 {
635 MoveObjectType_::GasCoin | MoveObjectType_::StakedSui | MoveObjectType_::Coin(_) => {
636 Err(SuiErrorKind::ObjectDeserializationError {
637 error: "Error extracting dynamic object value from specialized object type"
638 .to_string(),
639 }
640 .into())
641 }
642 MoveObjectType_::SuiBalanceAccumulatorField
643 | MoveObjectType_::BalanceAccumulatorField(_)
644 | MoveObjectType_::BalanceAccumulatorOwnerField
645 | MoveObjectType_::SuiBalanceAccumulatorMetadataField
646 | MoveObjectType_::BalanceAccumulatorMetadataField(_) => {
647 let struct_tag: StructTag = self.clone().into();
648 DynamicFieldInfo::try_extract_field_value(&struct_tag)
649 }
650 MoveObjectType_::Other(s) => DynamicFieldInfo::try_extract_field_value(s),
651 }
652 }
653
654 pub fn is(&self, s: &StructTag) -> bool {
655 match &self.0 {
656 MoveObjectType_::GasCoin => GasCoin::is_gas_coin(s),
657 MoveObjectType_::StakedSui => StakedSui::is_staked_sui(s),
658 MoveObjectType_::Coin(inner) => {
659 Coin::is_coin(s) && s.type_params.len() == 1 && inner == &s.type_params[0]
660 }
661 MoveObjectType_::SuiBalanceAccumulatorField => accumulator_value_balance_type_maybe(s)
662 .map(|t| GAS::is_gas_type(&t))
663 .unwrap_or(false),
664 MoveObjectType_::BalanceAccumulatorField(inner) => {
665 accumulator_value_balance_type_maybe(s)
666 .map(|t| &t == inner)
667 .unwrap_or(false)
668 }
669 MoveObjectType_::BalanceAccumulatorOwnerField => is_balance_accumulator_owner_field(s),
670 MoveObjectType_::SuiBalanceAccumulatorMetadataField => {
671 accumulator_metadata_balance_type_maybe(s)
672 .map(|t| GAS::is_gas_type(&t))
673 .unwrap_or(false)
674 }
675 MoveObjectType_::BalanceAccumulatorMetadataField(inner) => {
676 accumulator_metadata_balance_type_maybe(s)
677 .map(|t| &t == inner)
678 .unwrap_or(false)
679 }
680 MoveObjectType_::Other(o) => s == o,
681 }
682 }
683
684 pub fn other(&self) -> Option<&StructTag> {
685 if let MoveObjectType_::Other(s) = &self.0 {
686 Some(s)
687 } else {
688 None
689 }
690 }
691
692 pub fn to_canonical_string(&self, with_prefix: bool) -> String {
694 StructTag::from(self.clone()).to_canonical_string(with_prefix)
695 }
696
697 fn balance_accumulator_field_type_params(inner_type: TypeTag) -> Vec<TypeTag> {
700 use crate::accumulator_root::{AccumulatorKey, U128};
701 let balance_type = Balance::type_tag(inner_type);
702 let key_type = AccumulatorKey::get_type_tag(&[balance_type]);
703 let u128_type = U128::get_type_tag();
704 vec![key_type, u128_type]
705 }
706
707 fn balance_accumulator_field_struct_tag(inner_type: TypeTag) -> StructTag {
709 use crate::accumulator_root::{AccumulatorKey, U128};
710 let balance_type = Balance::type_tag(inner_type);
711 let key_type = AccumulatorKey::get_type_tag(&[balance_type]);
712 let u128_type = U128::get_type_tag();
713 DynamicFieldInfo::dynamic_field_type(key_type, u128_type)
714 }
715
716 fn balance_accumulator_owner_field_struct_tag() -> StructTag {
717 use crate::accumulator_metadata::{AccumulatorOwner, OwnerKey};
718 let key_type = OwnerKey::get_type_tag();
719 let value_type = AccumulatorOwner::get_type_tag();
720 DynamicFieldInfo::dynamic_field_type(key_type, value_type)
721 }
722
723 fn balance_accumulator_owner_field_type_params() -> Vec<TypeTag> {
724 use crate::accumulator_metadata::{AccumulatorOwner, OwnerKey};
725 let key_type = OwnerKey::get_type_tag();
726 let value_type = AccumulatorOwner::get_type_tag();
727 vec![key_type, value_type]
728 }
729
730 fn balance_accumulator_metadata_field_struct_tag(inner_type: TypeTag) -> StructTag {
731 use crate::accumulator_metadata::{AccumulatorMetadata, MetadataKey};
732 let balance_type = Balance::type_tag(inner_type);
733 let key_type = MetadataKey::get_type_tag(std::slice::from_ref(&balance_type));
734 let value_type = AccumulatorMetadata::get_type_tag(&[balance_type]);
736 DynamicFieldInfo::dynamic_field_type(key_type, value_type)
737 }
738
739 fn balance_accumulator_metadata_field_type_params(inner_type: TypeTag) -> Vec<TypeTag> {
740 use crate::accumulator_metadata::{AccumulatorMetadata, MetadataKey};
741 let balance_type = Balance::type_tag(inner_type);
742 let key_type = MetadataKey::get_type_tag(std::slice::from_ref(&balance_type));
743 let value_type = AccumulatorMetadata::get_type_tag(&[balance_type]);
745 vec![key_type, value_type]
746 }
747}
748
749impl From<StructTag> for MoveObjectType {
750 fn from(mut s: StructTag) -> Self {
751 Self(if GasCoin::is_gas_coin(&s) {
752 MoveObjectType_::GasCoin
753 } else if Coin::is_coin(&s) {
754 MoveObjectType_::Coin(s.type_params.pop().unwrap())
756 } else if StakedSui::is_staked_sui(&s) {
757 MoveObjectType_::StakedSui
758 } else if let Some(balance_type) = accumulator_value_balance_type_maybe(&s) {
759 if GAS::is_gas_type(&balance_type) {
760 MoveObjectType_::SuiBalanceAccumulatorField
761 } else {
762 MoveObjectType_::BalanceAccumulatorField(balance_type)
763 }
764 } else if let Some(balance_type) = accumulator_metadata_balance_type_maybe(&s) {
765 if GAS::is_gas_type(&balance_type) {
766 MoveObjectType_::SuiBalanceAccumulatorMetadataField
767 } else {
768 MoveObjectType_::BalanceAccumulatorMetadataField(balance_type)
769 }
770 } else if is_balance_accumulator_owner_field(&s) {
771 MoveObjectType_::BalanceAccumulatorOwnerField
772 } else {
773 MoveObjectType_::Other(s)
774 })
775 }
776}
777
778impl From<MoveObjectType> for StructTag {
779 fn from(t: MoveObjectType) -> Self {
780 match t.0 {
781 MoveObjectType_::GasCoin => GasCoin::type_(),
782 MoveObjectType_::StakedSui => StakedSui::type_(),
783 MoveObjectType_::Coin(inner) => Coin::type_(inner),
784 MoveObjectType_::SuiBalanceAccumulatorField => {
785 MoveObjectType::balance_accumulator_field_struct_tag(GAS::type_tag())
786 }
787 MoveObjectType_::BalanceAccumulatorField(inner) => {
788 MoveObjectType::balance_accumulator_field_struct_tag(inner)
789 }
790 MoveObjectType_::BalanceAccumulatorOwnerField => {
791 MoveObjectType::balance_accumulator_owner_field_struct_tag()
792 }
793 MoveObjectType_::SuiBalanceAccumulatorMetadataField => {
794 MoveObjectType::balance_accumulator_metadata_field_struct_tag(GAS::type_tag())
795 }
796 MoveObjectType_::BalanceAccumulatorMetadataField(inner) => {
797 MoveObjectType::balance_accumulator_metadata_field_struct_tag(inner)
798 }
799 MoveObjectType_::Other(s) => s,
800 }
801 }
802}
803
804impl From<MoveObjectType> for TypeTag {
805 fn from(o: MoveObjectType) -> TypeTag {
806 let s: StructTag = o.into();
807 TypeTag::Struct(Box::new(s))
808 }
809}
810
811pub fn is_primitive_type_tag(t: &TypeTag) -> bool {
813 use TypeTag as T;
814
815 match t {
816 T::Bool | T::U8 | T::U16 | T::U32 | T::U64 | T::U128 | T::U256 | T::Address => true,
817 T::Vector(inner) => is_primitive_type_tag(inner),
818 T::Struct(st) => {
819 let StructTag {
820 address,
821 module,
822 name,
823 type_params: type_args,
824 } = &**st;
825 let resolved_struct = (address, module.as_ident_str(), name.as_ident_str());
826 if resolved_struct == RESOLVED_SUI_ID {
828 return true;
829 }
830 if resolved_struct == RESOLVED_UTF8_STR {
832 return true;
833 }
834 if resolved_struct == RESOLVED_ASCII_STR {
836 return true;
837 }
838 resolved_struct == RESOLVED_STD_OPTION
840 && type_args.len() == 1
841 && is_primitive_type_tag(&type_args[0])
842 }
843 T::Signer => false,
844 }
845}
846
847#[derive(Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Debug)]
849pub enum ObjectType {
850 Package,
852 Struct(MoveObjectType),
854}
855
856impl From<&Object> for ObjectType {
857 fn from(o: &Object) -> Self {
858 o.data
859 .type_()
860 .map(|t| ObjectType::Struct(t.clone()))
861 .unwrap_or(ObjectType::Package)
862 }
863}
864
865impl TryFrom<ObjectType> for StructTag {
866 type Error = anyhow::Error;
867
868 fn try_from(o: ObjectType) -> Result<Self, anyhow::Error> {
869 match o {
870 ObjectType::Package => Err(anyhow!("Cannot create StructTag from Package")),
871 ObjectType::Struct(move_object_type) => Ok(move_object_type.into()),
872 }
873 }
874}
875
876impl FromStr for ObjectType {
877 type Err = anyhow::Error;
878
879 fn from_str(s: &str) -> Result<Self, Self::Err> {
880 if s.to_lowercase() == PACKAGE {
881 Ok(ObjectType::Package)
882 } else {
883 let tag = parse_sui_struct_tag(s)?;
884 Ok(ObjectType::Struct(MoveObjectType::from(tag)))
885 }
886 }
887}
888
889#[derive(Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Debug)]
890pub struct ObjectInfo {
891 pub object_id: ObjectID,
892 pub version: SequenceNumber,
893 pub digest: ObjectDigest,
894 pub type_: ObjectType,
895 pub owner: Owner,
896 pub previous_transaction: TransactionDigest,
897}
898
899impl ObjectInfo {
900 pub fn new(oref: &ObjectRef, o: &Object) -> Self {
901 let (object_id, version, digest) = *oref;
902 Self {
903 object_id,
904 version,
905 digest,
906 type_: o.into(),
907 owner: o.owner.clone(),
908 previous_transaction: o.previous_transaction,
909 }
910 }
911
912 pub fn from_object(object: &Object) -> Self {
913 Self {
914 object_id: object.id(),
915 version: object.version(),
916 digest: object.digest(),
917 type_: object.into(),
918 owner: object.owner.clone(),
919 previous_transaction: object.previous_transaction,
920 }
921 }
922}
923const PACKAGE: &str = "package";
924impl ObjectType {
925 pub fn is_gas_coin(&self) -> bool {
926 matches!(self, ObjectType::Struct(s) if s.is_gas_coin())
927 }
928
929 pub fn is_coin(&self) -> bool {
930 matches!(self, ObjectType::Struct(s) if s.is_coin())
931 }
932
933 pub fn is_coin_t(&self, t: &TypeTag) -> bool {
935 matches!(self, ObjectType::Struct(s) if s.is_coin_t(t))
936 }
937
938 pub fn is_package(&self) -> bool {
939 matches!(self, ObjectType::Package)
940 }
941}
942
943impl From<ObjectInfo> for ObjectRef {
944 fn from(info: ObjectInfo) -> Self {
945 (info.object_id, info.version, info.digest)
946 }
947}
948
949impl From<&ObjectInfo> for ObjectRef {
950 fn from(info: &ObjectInfo) -> Self {
951 (info.object_id, info.version, info.digest)
952 }
953}
954
955pub const SUI_ADDRESS_LENGTH: usize = ObjectID::LENGTH;
956
957#[serde_as]
958#[derive(
959 Eq, Default, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Serialize, Deserialize, JsonSchema,
960)]
961#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))]
962pub struct SuiAddress(
963 #[schemars(with = "Hex")]
964 #[serde_as(as = "Readable<Hex, _>")]
965 [u8; SUI_ADDRESS_LENGTH],
966);
967
968impl SuiAddress {
969 pub const ZERO: Self = Self([0u8; SUI_ADDRESS_LENGTH]);
970
971 pub fn to_vec(&self) -> Vec<u8> {
973 self.0.to_vec()
974 }
975
976 pub fn random_for_testing_only() -> Self {
978 AccountAddress::random().into()
979 }
980
981 pub fn generate<R: rand::RngCore + rand::CryptoRng>(mut rng: R) -> Self {
982 let buf: [u8; SUI_ADDRESS_LENGTH] = rng.r#gen();
983 Self(buf)
984 }
985
986 pub fn optional_address_as_hex<S>(
988 key: &Option<SuiAddress>,
989 serializer: S,
990 ) -> Result<S::Ok, S::Error>
991 where
992 S: serde::ser::Serializer,
993 {
994 serializer.serialize_str(&key.map(Hex::encode).unwrap_or_default())
995 }
996
997 pub fn optional_address_from_hex<'de, D>(
999 deserializer: D,
1000 ) -> Result<Option<SuiAddress>, D::Error>
1001 where
1002 D: serde::de::Deserializer<'de>,
1003 {
1004 let s = String::deserialize(deserializer)?;
1005 let value = decode_bytes_hex(&s).map_err(serde::de::Error::custom)?;
1006 Ok(Some(value))
1007 }
1008
1009 pub fn to_inner(self) -> [u8; SUI_ADDRESS_LENGTH] {
1011 self.0
1012 }
1013
1014 pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, SuiError> {
1016 <[u8; SUI_ADDRESS_LENGTH]>::try_from(bytes.as_ref())
1017 .map_err(|_| SuiErrorKind::InvalidAddress.into())
1018 .map(SuiAddress)
1019 }
1020
1021 pub fn try_from_padded(inputs: &ZkLoginInputs) -> SuiResult<Self> {
1025 Ok((&PublicKey::from_zklogin_inputs(inputs)?).into())
1026 }
1027
1028 pub fn try_from_unpadded(inputs: &ZkLoginInputs) -> SuiResult<Self> {
1030 let mut hasher = DefaultHash::default();
1031 hasher.update([SignatureScheme::ZkLoginAuthenticator.flag()]);
1032 let iss_bytes = inputs.get_iss().as_bytes();
1033 hasher.update([iss_bytes.len() as u8]);
1034 hasher.update(iss_bytes);
1035 hasher.update(inputs.get_address_seed().unpadded());
1036 Ok(SuiAddress(hasher.finalize().digest))
1037 }
1038}
1039
1040impl From<ObjectID> for SuiAddress {
1041 fn from(object_id: ObjectID) -> SuiAddress {
1042 Self(object_id.into_bytes())
1043 }
1044}
1045
1046impl From<AccountAddress> for SuiAddress {
1047 fn from(address: AccountAddress) -> SuiAddress {
1048 Self(address.into_bytes())
1049 }
1050}
1051
1052impl TryFrom<&[u8]> for SuiAddress {
1053 type Error = SuiError;
1054
1055 fn try_from(bytes: &[u8]) -> Result<Self, SuiError> {
1057 Self::from_bytes(bytes)
1058 }
1059}
1060
1061impl TryFrom<Vec<u8>> for SuiAddress {
1062 type Error = SuiError;
1063
1064 fn try_from(bytes: Vec<u8>) -> Result<Self, SuiError> {
1066 Self::from_bytes(bytes)
1067 }
1068}
1069
1070impl AsRef<[u8]> for SuiAddress {
1071 fn as_ref(&self) -> &[u8] {
1072 &self.0[..]
1073 }
1074}
1075
1076impl FromStr for SuiAddress {
1077 type Err = anyhow::Error;
1078 fn from_str(s: &str) -> Result<Self, Self::Err> {
1079 decode_bytes_hex(s).map_err(|e| anyhow!(e))
1080 }
1081}
1082
1083impl<T: SuiPublicKey> From<&T> for SuiAddress {
1084 fn from(pk: &T) -> Self {
1085 let mut hasher = DefaultHash::default();
1086 hasher.update([T::SIGNATURE_SCHEME.flag()]);
1087 hasher.update(pk);
1088 let g_arr = hasher.finalize();
1089 SuiAddress(g_arr.digest)
1090 }
1091}
1092
1093impl From<&PublicKey> for SuiAddress {
1094 fn from(pk: &PublicKey) -> Self {
1095 let mut hasher = DefaultHash::default();
1096 hasher.update([pk.flag()]);
1097 hasher.update(pk);
1098 let g_arr = hasher.finalize();
1099 SuiAddress(g_arr.digest)
1100 }
1101}
1102
1103impl From<&MultiSigPublicKey> for SuiAddress {
1104 fn from(multisig_pk: &MultiSigPublicKey) -> Self {
1113 let mut hasher = DefaultHash::default();
1114 hasher.update([SignatureScheme::MultiSig.flag()]);
1115 hasher.update(multisig_pk.threshold().to_le_bytes());
1116 multisig_pk.pubkeys().iter().for_each(|(pk, w)| {
1117 hasher.update([pk.flag()]);
1118 hasher.update(pk.as_ref());
1119 hasher.update(w.to_le_bytes());
1120 });
1121 SuiAddress(hasher.finalize().digest)
1122 }
1123}
1124
1125impl TryFrom<&ZkLoginAuthenticator> for SuiAddress {
1128 type Error = SuiError;
1129 fn try_from(authenticator: &ZkLoginAuthenticator) -> SuiResult<Self> {
1130 SuiAddress::try_from_unpadded(&authenticator.inputs)
1131 }
1132}
1133
1134impl TryFrom<&GenericSignature> for SuiAddress {
1135 type Error = SuiError;
1136 fn try_from(sig: &GenericSignature) -> SuiResult<Self> {
1138 match sig {
1139 GenericSignature::Signature(sig) => {
1140 let scheme = sig.scheme();
1141 let pub_key_bytes = sig.public_key_bytes();
1142 let pub_key = PublicKey::try_from_bytes(scheme, pub_key_bytes).map_err(|_| {
1143 SuiErrorKind::InvalidSignature {
1144 error: "Cannot parse pubkey".to_string(),
1145 }
1146 })?;
1147 Ok(SuiAddress::from(&pub_key))
1148 }
1149 GenericSignature::MultiSig(ms) => Ok(ms.get_pk().into()),
1150 GenericSignature::MultiSigLegacy(ms) => {
1151 Ok(crate::multisig::MultiSig::try_from(ms.clone())
1152 .map_err(|_| SuiErrorKind::InvalidSignature {
1153 error: "Invalid legacy multisig".to_string(),
1154 })?
1155 .get_pk()
1156 .into())
1157 }
1158 GenericSignature::ZkLoginAuthenticator(zklogin) => {
1159 SuiAddress::try_from_unpadded(&zklogin.inputs)
1160 }
1161 GenericSignature::PasskeyAuthenticator(s) => Ok(SuiAddress::from(&s.get_pk()?)),
1162 }
1163 }
1164}
1165
1166impl fmt::Display for SuiAddress {
1167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1168 write!(f, "0x{}", Hex::encode(self.0))
1169 }
1170}
1171
1172impl fmt::Debug for SuiAddress {
1173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1174 write!(f, "0x{}", Hex::encode(self.0))
1175 }
1176}
1177
1178pub fn dbg_addr(name: u8) -> SuiAddress {
1180 let addr = [name; SUI_ADDRESS_LENGTH];
1181 SuiAddress(addr)
1182}
1183
1184#[derive(
1185 Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Serialize, Deserialize, JsonSchema, Debug,
1186)]
1187pub struct ExecutionDigests {
1188 pub transaction: TransactionDigest,
1189 pub effects: TransactionEffectsDigest,
1190}
1191
1192impl ExecutionDigests {
1193 pub fn new(transaction: TransactionDigest, effects: TransactionEffectsDigest) -> Self {
1194 Self {
1195 transaction,
1196 effects,
1197 }
1198 }
1199
1200 pub fn random() -> Self {
1201 Self {
1202 transaction: TransactionDigest::random(),
1203 effects: TransactionEffectsDigest::random(),
1204 }
1205 }
1206}
1207
1208#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
1209pub struct ExecutionData {
1210 pub transaction: Transaction,
1211 pub effects: TransactionEffects,
1212}
1213
1214impl ExecutionData {
1215 pub fn new(transaction: Transaction, effects: TransactionEffects) -> ExecutionData {
1216 debug_assert_eq!(transaction.digest(), effects.transaction_digest());
1217 Self {
1218 transaction,
1219 effects,
1220 }
1221 }
1222
1223 pub fn digests(&self) -> ExecutionDigests {
1224 self.effects.execution_digests()
1225 }
1226}
1227
1228#[derive(Clone, Eq, PartialEq, Debug)]
1229pub struct VerifiedExecutionData {
1230 pub transaction: VerifiedTransaction,
1231 pub effects: TransactionEffects,
1232}
1233
1234impl VerifiedExecutionData {
1235 pub fn new(transaction: VerifiedTransaction, effects: TransactionEffects) -> Self {
1236 debug_assert_eq!(transaction.digest(), effects.transaction_digest());
1237 Self {
1238 transaction,
1239 effects,
1240 }
1241 }
1242
1243 pub fn new_unchecked(data: ExecutionData) -> Self {
1244 Self {
1245 transaction: VerifiedTransaction::new_unchecked(data.transaction),
1246 effects: data.effects,
1247 }
1248 }
1249
1250 pub fn into_inner(self) -> ExecutionData {
1251 ExecutionData {
1252 transaction: self.transaction.into_inner(),
1253 effects: self.effects,
1254 }
1255 }
1256
1257 pub fn digests(&self) -> ExecutionDigests {
1258 self.effects.execution_digests()
1259 }
1260}
1261
1262pub const STD_OPTION_MODULE_NAME: &IdentStr = ident_str!("option");
1263pub const STD_OPTION_STRUCT_NAME: &IdentStr = ident_str!("Option");
1264pub const RESOLVED_STD_OPTION: (&AccountAddress, &IdentStr, &IdentStr) = (
1265 &MOVE_STDLIB_ADDRESS,
1266 STD_OPTION_MODULE_NAME,
1267 STD_OPTION_STRUCT_NAME,
1268);
1269
1270pub const STD_ASCII_MODULE_NAME: &IdentStr = ident_str!("ascii");
1271pub const STD_ASCII_STRUCT_NAME: &IdentStr = ident_str!("String");
1272pub const RESOLVED_ASCII_STR: (&AccountAddress, &IdentStr, &IdentStr) = (
1273 &MOVE_STDLIB_ADDRESS,
1274 STD_ASCII_MODULE_NAME,
1275 STD_ASCII_STRUCT_NAME,
1276);
1277
1278pub const STD_UTF8_MODULE_NAME: &IdentStr = ident_str!("string");
1279pub const STD_UTF8_STRUCT_NAME: &IdentStr = ident_str!("String");
1280pub const RESOLVED_UTF8_STR: (&AccountAddress, &IdentStr, &IdentStr) = (
1281 &MOVE_STDLIB_ADDRESS,
1282 STD_UTF8_MODULE_NAME,
1283 STD_UTF8_STRUCT_NAME,
1284);
1285
1286pub const TX_CONTEXT_MODULE_NAME: &IdentStr = ident_str!("tx_context");
1287pub const TX_CONTEXT_STRUCT_NAME: &IdentStr = ident_str!("TxContext");
1288pub const RESOLVED_TX_CONTEXT: (&AccountAddress, &IdentStr, &IdentStr) = (
1289 &SUI_FRAMEWORK_ADDRESS,
1290 TX_CONTEXT_MODULE_NAME,
1291 TX_CONTEXT_STRUCT_NAME,
1292);
1293
1294pub const URL_MODULE_NAME: &IdentStr = ident_str!("url");
1295pub const URL_STRUCT_NAME: &IdentStr = ident_str!("Url");
1296
1297pub const VEC_MAP_MODULE_NAME: &IdentStr = ident_str!("vec_map");
1298pub const VEC_MAP_STRUCT_NAME: &IdentStr = ident_str!("VecMap");
1299pub const VEC_MAP_ENTRY_STRUCT_NAME: &IdentStr = ident_str!("Entry");
1300
1301pub fn move_ascii_str_layout() -> A::MoveStructLayout {
1302 A::MoveStructLayout {
1303 type_: StructTag {
1304 address: MOVE_STDLIB_ADDRESS,
1305 module: STD_ASCII_MODULE_NAME.to_owned(),
1306 name: STD_ASCII_STRUCT_NAME.to_owned(),
1307 type_params: vec![],
1308 },
1309 fields: vec![A::MoveFieldLayout::new(
1310 ident_str!("bytes").into(),
1311 A::MoveTypeLayout::Vector(Box::new(A::MoveTypeLayout::U8)),
1312 )],
1313 }
1314}
1315
1316pub fn move_utf8_str_layout() -> A::MoveStructLayout {
1317 A::MoveStructLayout {
1318 type_: StructTag {
1319 address: MOVE_STDLIB_ADDRESS,
1320 module: STD_UTF8_MODULE_NAME.to_owned(),
1321 name: STD_UTF8_STRUCT_NAME.to_owned(),
1322 type_params: vec![],
1323 },
1324 fields: vec![A::MoveFieldLayout::new(
1325 ident_str!("bytes").into(),
1326 A::MoveTypeLayout::Vector(Box::new(A::MoveTypeLayout::U8)),
1327 )],
1328 }
1329}
1330
1331pub fn url_layout() -> A::MoveStructLayout {
1332 A::MoveStructLayout {
1333 type_: StructTag {
1334 address: SUI_FRAMEWORK_ADDRESS,
1335 module: URL_MODULE_NAME.to_owned(),
1336 name: URL_STRUCT_NAME.to_owned(),
1337 type_params: vec![],
1338 },
1339 fields: vec![A::MoveFieldLayout::new(
1340 ident_str!("url").to_owned(),
1341 A::MoveTypeLayout::Struct(Box::new(move_ascii_str_layout())),
1342 )],
1343 }
1344}
1345
1346#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
1356pub struct MoveLegacyTxContext {
1357 sender: AccountAddress,
1359 digest: Vec<u8>,
1361 epoch: EpochId,
1363 epoch_timestamp_ms: CheckpointTimestamp,
1365 ids_created: u64,
1367}
1368
1369impl From<&TxContext> for MoveLegacyTxContext {
1370 fn from(tx_context: &TxContext) -> Self {
1371 Self {
1372 sender: tx_context.sender,
1373 digest: tx_context.digest.clone(),
1374 epoch: tx_context.epoch,
1375 epoch_timestamp_ms: tx_context.epoch_timestamp_ms,
1376 ids_created: tx_context.ids_created,
1377 }
1378 }
1379}
1380
1381#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
1384pub struct TxContext {
1385 sender: AccountAddress,
1387 digest: Vec<u8>,
1389 epoch: EpochId,
1391 epoch_timestamp_ms: CheckpointTimestamp,
1393 ids_created: u64,
1395 rgp: u64,
1397 gas_price: u64,
1399 gas_budget: u64,
1401 sponsor: Option<AccountAddress>,
1403 is_native: bool,
1406}
1407
1408#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1409pub enum TxContextKind {
1410 None,
1412 Mutable,
1414 Immutable,
1416}
1417
1418impl TxContext {
1419 pub fn new(
1420 sender: &SuiAddress,
1421 digest: &TransactionDigest,
1422 epoch_data: &EpochData,
1423 rgp: u64,
1424 gas_price: u64,
1425 gas_budget: u64,
1426 sponsor: Option<SuiAddress>,
1427 protocol_config: &ProtocolConfig,
1428 ) -> Self {
1429 Self::new_from_components(
1430 sender,
1431 digest,
1432 &epoch_data.epoch_id(),
1433 epoch_data.epoch_start_timestamp(),
1434 rgp,
1435 gas_price,
1436 gas_budget,
1437 sponsor,
1438 protocol_config,
1439 )
1440 }
1441
1442 pub fn new_from_components(
1443 sender: &SuiAddress,
1444 digest: &TransactionDigest,
1445 epoch_id: &EpochId,
1446 epoch_timestamp_ms: u64,
1447 rgp: u64,
1448 gas_price: u64,
1449 gas_budget: u64,
1450 sponsor: Option<SuiAddress>,
1451 protocol_config: &ProtocolConfig,
1452 ) -> Self {
1453 Self {
1454 sender: AccountAddress::new(sender.0),
1455 digest: digest.into_inner().to_vec(),
1456 epoch: *epoch_id,
1457 epoch_timestamp_ms,
1458 ids_created: 0,
1459 rgp,
1460 gas_price,
1461 gas_budget,
1462 sponsor: sponsor.map(|s| s.into()),
1463 is_native: protocol_config.move_native_context(),
1464 }
1465 }
1466
1467 pub fn kind(view: &CompiledModule, s: &SignatureToken) -> TxContextKind {
1469 use SignatureToken as S;
1470 let (kind, s) = match s {
1471 S::MutableReference(s) => (TxContextKind::Mutable, s),
1472 S::Reference(s) => (TxContextKind::Immutable, s),
1473 _ => return TxContextKind::None,
1474 };
1475
1476 let S::Datatype(idx) = &**s else {
1477 return TxContextKind::None;
1478 };
1479
1480 if resolve_struct(view, *idx) == RESOLVED_TX_CONTEXT {
1481 kind
1482 } else {
1483 TxContextKind::None
1484 }
1485 }
1486
1487 pub fn type_() -> StructTag {
1488 StructTag {
1489 address: SUI_FRAMEWORK_ADDRESS,
1490 module: TX_CONTEXT_MODULE_NAME.to_owned(),
1491 name: TX_CONTEXT_STRUCT_NAME.to_owned(),
1492 type_params: vec![],
1493 }
1494 }
1495
1496 pub fn epoch(&self) -> EpochId {
1497 self.epoch
1498 }
1499
1500 pub fn sender(&self) -> SuiAddress {
1501 self.sender.into()
1502 }
1503
1504 pub fn epoch_timestamp_ms(&self) -> u64 {
1505 self.epoch_timestamp_ms
1506 }
1507
1508 pub fn digest(&self) -> TransactionDigest {
1510 TransactionDigest::new(self.digest.clone().try_into().unwrap())
1511 }
1512
1513 pub fn sponsor(&self) -> Option<SuiAddress> {
1514 self.sponsor.map(SuiAddress::from)
1515 }
1516
1517 pub fn rgp(&self) -> u64 {
1518 self.rgp
1519 }
1520
1521 pub fn gas_price(&self) -> u64 {
1522 self.gas_price
1523 }
1524
1525 pub fn gas_budget(&self) -> u64 {
1526 self.gas_budget
1527 }
1528
1529 pub fn ids_created(&self) -> u64 {
1530 self.ids_created
1531 }
1532
1533 pub fn fresh_id(&mut self) -> ObjectID {
1535 let id = ObjectID::derive_id(self.digest(), self.ids_created);
1536
1537 self.ids_created += 1;
1538 id
1539 }
1540
1541 pub fn to_bcs_legacy_context(&self) -> Vec<u8> {
1542 let move_context: MoveLegacyTxContext = if self.is_native {
1543 let tx_context = &TxContext {
1544 sender: AccountAddress::ZERO,
1545 digest: self.digest.clone(),
1546 epoch: 0,
1547 epoch_timestamp_ms: 0,
1548 ids_created: 0,
1549 rgp: 0,
1550 gas_price: 0,
1551 gas_budget: 0,
1552 sponsor: None,
1553 is_native: true,
1554 };
1555 tx_context.into()
1556 } else {
1557 self.into()
1558 };
1559 bcs::to_bytes(&move_context).unwrap()
1560 }
1561
1562 pub fn to_vec(&self) -> Vec<u8> {
1563 bcs::to_bytes(&self).unwrap()
1564 }
1565
1566 pub fn update_state(&mut self, other: MoveLegacyTxContext) -> Result<(), ExecutionError> {
1571 if !self.is_native {
1572 if self.sender != other.sender
1573 || self.digest != other.digest
1574 || other.ids_created < self.ids_created
1575 {
1576 return Err(ExecutionError::new_with_source(
1577 ExecutionErrorKind::InvariantViolation,
1578 "Immutable fields for TxContext changed",
1579 ));
1580 }
1581 self.ids_created = other.ids_created;
1582 }
1583 Ok(())
1584 }
1585
1586 pub fn replace(
1590 &mut self,
1591 sender: AccountAddress,
1592 tx_hash: Vec<u8>,
1593 epoch: u64,
1594 epoch_timestamp_ms: u64,
1595 ids_created: u64,
1596 rgp: u64,
1597 gas_price: u64,
1598 gas_budget: u64,
1599 sponsor: Option<AccountAddress>,
1600 ) {
1601 self.sender = sender;
1602 self.digest = tx_hash;
1603 self.epoch = epoch;
1604 self.epoch_timestamp_ms = epoch_timestamp_ms;
1605 self.ids_created = ids_created;
1606 self.rgp = rgp;
1607 self.gas_price = gas_price;
1608 self.gas_budget = gas_budget;
1609 self.sponsor = sponsor;
1610 }
1611}
1612
1613impl SequenceNumber {
1615 pub const MIN: SequenceNumber = SequenceNumber(u64::MIN);
1616 pub const MAX: SequenceNumber = SequenceNumber(0x7fff_ffff_ffff_ffff);
1617 pub const CANCELLED_READ: SequenceNumber = SequenceNumber(SequenceNumber::MAX.value() + 1);
1618 pub const CONGESTED: SequenceNumber = SequenceNumber(SequenceNumber::MAX.value() + 2);
1619 pub const RANDOMNESS_UNAVAILABLE: SequenceNumber =
1620 SequenceNumber(SequenceNumber::MAX.value() + 3);
1621 pub const UNKNOWN: SequenceNumber = SequenceNumber(SequenceNumber::MAX.value() + 4);
1624
1625 pub const fn new() -> Self {
1626 SequenceNumber(0)
1627 }
1628
1629 pub const fn value(&self) -> u64 {
1630 self.0
1631 }
1632
1633 pub const fn from_u64(u: u64) -> Self {
1634 SequenceNumber(u)
1635 }
1636
1637 pub fn increment(&mut self) {
1638 assert_ne!(self.0, u64::MAX);
1639 self.0 += 1;
1640 }
1641
1642 pub fn increment_to(&mut self, next: SequenceNumber) {
1643 debug_assert!(*self < next, "Not an increment: {} to {}", self, next);
1644 *self = next;
1645 }
1646
1647 pub fn decrement(&mut self) {
1648 assert_ne!(self.0, 0);
1649 self.0 -= 1;
1650 }
1651
1652 pub fn decrement_to(&mut self, prev: SequenceNumber) {
1653 debug_assert!(prev < *self, "Not a decrement: {} to {}", self, prev);
1654 *self = prev;
1655 }
1656
1657 #[must_use]
1660 pub fn lamport_increment(inputs: impl IntoIterator<Item = SequenceNumber>) -> SequenceNumber {
1661 let max_input = inputs.into_iter().fold(SequenceNumber::new(), max);
1662
1663 assert_ne!(max_input.0, u64::MAX);
1668
1669 SequenceNumber(max_input.0 + 1)
1670 }
1671
1672 pub fn is_cancelled(&self) -> bool {
1673 self == &SequenceNumber::CANCELLED_READ
1674 || self == &SequenceNumber::CONGESTED
1675 || self == &SequenceNumber::RANDOMNESS_UNAVAILABLE
1676 }
1677
1678 pub fn is_valid(&self) -> bool {
1679 self < &SequenceNumber::MAX
1680 }
1681}
1682
1683impl From<SequenceNumber> for u64 {
1684 fn from(val: SequenceNumber) -> Self {
1685 val.0
1686 }
1687}
1688
1689impl From<u64> for SequenceNumber {
1690 fn from(value: u64) -> Self {
1691 SequenceNumber(value)
1692 }
1693}
1694
1695impl From<SequenceNumber> for usize {
1696 fn from(value: SequenceNumber) -> Self {
1697 value.0 as usize
1698 }
1699}
1700
1701impl ObjectID {
1702 pub const LENGTH: usize = AccountAddress::LENGTH;
1704 pub const ZERO: Self = Self::new([0u8; Self::LENGTH]);
1706 pub const MAX: Self = Self::new([0xff; Self::LENGTH]);
1707 pub const fn new(obj_id: [u8; Self::LENGTH]) -> Self {
1709 Self(AccountAddress::new(obj_id))
1710 }
1711
1712 pub const fn from_address(addr: AccountAddress) -> Self {
1714 Self(addr)
1715 }
1716
1717 pub fn random() -> Self {
1719 Self::from(AccountAddress::random())
1720 }
1721
1722 pub fn random_from_rng<R>(rng: &mut R) -> Self
1724 where
1725 R: AllowedRng,
1726 {
1727 let buf: [u8; Self::LENGTH] = rng.r#gen();
1728 ObjectID::new(buf)
1729 }
1730
1731 pub fn to_vec(&self) -> Vec<u8> {
1733 self.0.to_vec()
1734 }
1735
1736 pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, ObjectIDParseError> {
1738 <[u8; Self::LENGTH]>::try_from(bytes.as_ref())
1739 .map_err(|_| ObjectIDParseError::TryFromSliceError)
1740 .map(ObjectID::new)
1741 }
1742
1743 pub fn into_bytes(self) -> [u8; Self::LENGTH] {
1745 self.0.into_bytes()
1746 }
1747
1748 pub const fn from_single_byte(byte: u8) -> ObjectID {
1750 let mut bytes = [0u8; Self::LENGTH];
1751 bytes[Self::LENGTH - 1] = byte;
1752 ObjectID::new(bytes)
1753 }
1754
1755 pub fn from_hex_literal(literal: &str) -> Result<Self, ObjectIDParseError> {
1758 if !literal.starts_with("0x") {
1759 return Err(ObjectIDParseError::HexLiteralPrefixMissing);
1760 }
1761
1762 let hex_len = literal.len() - 2;
1763
1764 if hex_len < Self::LENGTH * 2 {
1766 let mut hex_str = String::with_capacity(Self::LENGTH * 2);
1767 for _ in 0..Self::LENGTH * 2 - hex_len {
1768 hex_str.push('0');
1769 }
1770 hex_str.push_str(&literal[2..]);
1771 Self::from_str(&hex_str)
1772 } else {
1773 Self::from_str(&literal[2..])
1774 }
1775 }
1776
1777 pub fn derive_id(digest: TransactionDigest, creation_num: u64) -> Self {
1780 let mut hasher = DefaultHash::default();
1781 hasher.update([HashingIntentScope::RegularObjectId as u8]);
1782 hasher.update(digest);
1783 hasher.update(creation_num.to_le_bytes());
1784 let hash = hasher.finalize();
1785
1786 ObjectID::try_from(&hash.as_ref()[0..ObjectID::LENGTH]).unwrap()
1789 }
1790
1791 pub fn advance(&self, step: usize) -> Result<ObjectID, anyhow::Error> {
1793 let mut curr_vec = self.to_vec();
1794 let mut step_copy = step;
1795
1796 let mut carry = 0;
1797 for idx in (0..Self::LENGTH).rev() {
1798 if step_copy == 0 {
1799 break;
1801 }
1802 let g = (step_copy % 0x100) as u16;
1804 step_copy >>= 8;
1806 let mut val = curr_vec[idx] as u16;
1807 (carry, val) = ((val + carry + g) / 0x100, (val + carry + g) % 0x100);
1808 curr_vec[idx] = val as u8;
1809 }
1810
1811 if carry > 0 {
1812 return Err(anyhow!("Increment will cause overflow"));
1813 }
1814 ObjectID::try_from(curr_vec).map_err(|w| w.into())
1815 }
1816
1817 pub fn next_increment(&self) -> Result<ObjectID, anyhow::Error> {
1819 let mut prev_val = self.to_vec();
1820 let mx = [0xFF; Self::LENGTH];
1821
1822 if prev_val == mx {
1823 return Err(anyhow!("Increment will cause overflow"));
1824 }
1825
1826 for idx in (0..Self::LENGTH).rev() {
1828 if prev_val[idx] == 0xFF {
1829 prev_val[idx] = 0;
1830 } else {
1831 prev_val[idx] += 1;
1832 break;
1833 };
1834 }
1835 ObjectID::try_from(prev_val.clone()).map_err(|w| w.into())
1836 }
1837
1838 pub fn in_range(offset: ObjectID, count: u64) -> Result<Vec<ObjectID>, anyhow::Error> {
1840 let mut ret = Vec::new();
1841 let mut prev = offset;
1842 for o in 0..count {
1843 if o != 0 {
1844 prev = prev.next_increment()?;
1845 }
1846 ret.push(prev);
1847 }
1848 Ok(ret)
1849 }
1850
1851 pub fn to_hex_uncompressed(&self) -> String {
1854 format!("{self}")
1855 }
1856
1857 pub fn is_clock(&self) -> bool {
1858 *self == SUI_CLOCK_OBJECT_ID
1859 }
1860}
1861
1862impl From<SuiAddress> for ObjectID {
1863 fn from(address: SuiAddress) -> ObjectID {
1864 let tmp: AccountAddress = address.into();
1865 tmp.into()
1866 }
1867}
1868
1869impl From<AccountAddress> for ObjectID {
1870 fn from(address: AccountAddress) -> Self {
1871 Self(address)
1872 }
1873}
1874
1875impl fmt::Display for ObjectID {
1876 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1877 write!(f, "0x{}", Hex::encode(self.0))
1878 }
1879}
1880
1881impl fmt::Debug for ObjectID {
1882 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1883 write!(f, "0x{}", Hex::encode(self.0))
1884 }
1885}
1886
1887impl AsRef<[u8]> for ObjectID {
1888 fn as_ref(&self) -> &[u8] {
1889 self.0.as_slice()
1890 }
1891}
1892
1893impl TryFrom<&[u8]> for ObjectID {
1894 type Error = ObjectIDParseError;
1895
1896 fn try_from(bytes: &[u8]) -> Result<ObjectID, ObjectIDParseError> {
1898 Self::from_bytes(bytes)
1899 }
1900}
1901
1902impl TryFrom<Vec<u8>> for ObjectID {
1903 type Error = ObjectIDParseError;
1904
1905 fn try_from(bytes: Vec<u8>) -> Result<ObjectID, ObjectIDParseError> {
1907 Self::from_bytes(bytes)
1908 }
1909}
1910
1911impl FromStr for ObjectID {
1912 type Err = ObjectIDParseError;
1913
1914 fn from_str(s: &str) -> Result<Self, ObjectIDParseError> {
1916 decode_bytes_hex(s).or_else(|_| Self::from_hex_literal(s))
1917 }
1918}
1919
1920impl std::ops::Deref for ObjectID {
1921 type Target = AccountAddress;
1922
1923 fn deref(&self) -> &Self::Target {
1924 &self.0
1925 }
1926}
1927
1928pub fn dbg_object_id(name: u8) -> ObjectID {
1930 ObjectID::new([name; ObjectID::LENGTH])
1931}
1932
1933#[derive(PartialEq, Eq, Clone, Debug, thiserror::Error)]
1934pub enum ObjectIDParseError {
1935 #[error("ObjectID hex literal must start with 0x")]
1936 HexLiteralPrefixMissing,
1937
1938 #[error("Could not convert from bytes slice")]
1939 TryFromSliceError,
1940}
1941
1942impl From<ObjectID> for AccountAddress {
1943 fn from(obj_id: ObjectID) -> Self {
1944 obj_id.0
1945 }
1946}
1947
1948impl From<SuiAddress> for AccountAddress {
1949 fn from(address: SuiAddress) -> Self {
1950 Self::new(address.0)
1951 }
1952}
1953
1954struct HexAccountAddress;
1956
1957impl SerializeAs<AccountAddress> for HexAccountAddress {
1958 fn serialize_as<S>(value: &AccountAddress, serializer: S) -> Result<S::Ok, S::Error>
1959 where
1960 S: Serializer,
1961 {
1962 Hex::serialize_as(value, serializer)
1963 }
1964}
1965
1966impl<'de> DeserializeAs<'de, AccountAddress> for HexAccountAddress {
1967 fn deserialize_as<D>(deserializer: D) -> Result<AccountAddress, D::Error>
1968 where
1969 D: Deserializer<'de>,
1970 {
1971 let s = String::deserialize(deserializer)?;
1972 if s.starts_with("0x") {
1973 AccountAddress::from_hex_literal(&s)
1974 } else {
1975 AccountAddress::from_hex(&s)
1976 }
1977 .map_err(to_custom_deser_error::<'de, D, _>)
1978 }
1979}
1980
1981impl fmt::Display for MoveObjectType {
1982 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
1983 let s: StructTag = self.clone().into();
1984 write!(
1985 f,
1986 "{}",
1987 to_sui_struct_tag_string(&s).map_err(fmt::Error::custom)?
1988 )
1989 }
1990}
1991
1992impl fmt::Display for ObjectType {
1993 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
1994 match self {
1995 ObjectType::Package => write!(f, "{}", PACKAGE),
1996 ObjectType::Struct(t) => write!(f, "{}", t),
1997 }
1998 }
1999}
2000
2001#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
2007#[serde(try_from = "Vec<T>")]
2008pub struct SizeOneVec<T> {
2009 e: T,
2010}
2011
2012impl<T> SizeOneVec<T> {
2013 pub fn new(e: T) -> Self {
2014 Self { e }
2015 }
2016
2017 pub fn element(&self) -> &T {
2018 &self.e
2019 }
2020
2021 pub fn element_mut(&mut self) -> &mut T {
2022 &mut self.e
2023 }
2024
2025 pub fn into_inner(self) -> T {
2026 self.e
2027 }
2028
2029 pub fn iter(&self) -> std::iter::Once<&T> {
2030 std::iter::once(&self.e)
2031 }
2032}
2033
2034impl<T> Serialize for SizeOneVec<T>
2035where
2036 T: Serialize,
2037{
2038 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2039 where
2040 S: Serializer,
2041 {
2042 let mut seq = serializer.serialize_seq(Some(1))?;
2043 seq.serialize_element(&self.e)?;
2044 seq.end()
2045 }
2046}
2047
2048impl<T> TryFrom<Vec<T>> for SizeOneVec<T> {
2049 type Error = anyhow::Error;
2050
2051 fn try_from(mut v: Vec<T>) -> Result<Self, Self::Error> {
2052 if v.len() != 1 {
2053 Err(anyhow!("Expected a vec of size 1"))
2054 } else {
2055 Ok(SizeOneVec {
2056 e: v.pop().unwrap(),
2057 })
2058 }
2059 }
2060}
2061
2062#[test]
2063fn test_size_one_vec_is_transparent() {
2064 let regular = vec![42u8];
2065 let size_one = SizeOneVec::new(42u8);
2066
2067 let regular_ser = bcs::to_bytes(®ular).unwrap();
2069 let size_one_deser = bcs::from_bytes::<SizeOneVec<u8>>(®ular_ser).unwrap();
2070 assert_eq!(size_one, size_one_deser);
2071
2072 let size_one_ser = bcs::to_bytes(&SizeOneVec::new(43u8)).unwrap();
2074 let regular_deser = bcs::from_bytes::<Vec<u8>>(&size_one_ser).unwrap();
2075 assert_eq!(regular_deser, vec![43u8]);
2076
2077 let empty_ser = bcs::to_bytes(&Vec::<u8>::new()).unwrap();
2079 bcs::from_bytes::<SizeOneVec<u8>>(&empty_ser).unwrap_err();
2080
2081 let size_greater_than_one_ser = bcs::to_bytes(&vec![1u8, 2u8]).unwrap();
2082 bcs::from_bytes::<SizeOneVec<u8>>(&size_greater_than_one_ser).unwrap_err();
2083}