iota_genesis_builder/stardust/migration/verification/
alias.rs1use std::collections::HashMap;
5
6use anyhow::{anyhow, bail, ensure};
7use iota_sdk::types::block::output as stardust;
8use iota_types::{
9 TypeTag,
10 balance::Balance,
11 base_types::{IotaAddress, ObjectID},
12 dynamic_field::{DynamicFieldInfo, Field, derive_dynamic_field_id},
13 in_memory_storage::InMemoryStorage,
14 object::Owner,
15 stardust::output::{
16 ALIAS_DYNAMIC_OBJECT_FIELD_KEY, ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE, Alias, AliasOutput,
17 },
18};
19
20use crate::stardust::{
21 migration::{
22 executor::FoundryLedgerData,
23 verification::{
24 created_objects::CreatedObjects,
25 util::{
26 TokensAmountCounter, verify_address_owner, verify_issuer_feature,
27 verify_metadata_feature, verify_native_tokens, verify_parent,
28 verify_sender_feature,
29 },
30 },
31 },
32 types::address_swap_map::AddressSwapMap,
33};
34
35pub(super) fn verify_alias_output(
36 output_id: stardust::OutputId,
37 output: &stardust::AliasOutput,
38 created_objects: &CreatedObjects,
39 foundry_data: &HashMap<stardust::TokenId, FoundryLedgerData>,
40 storage: &InMemoryStorage,
41 tokens_counter: &mut TokensAmountCounter,
42 address_swap_map: &AddressSwapMap,
43) -> anyhow::Result<()> {
44 let alias_id = ObjectID::new(*output.alias_id_non_null(&output_id));
45
46 let created_output_obj = created_objects.output().and_then(|id| {
47 storage
48 .get_object(id)
49 .ok_or_else(|| anyhow!("missing alias output object"))
50 })?;
51
52 let created_alias_obj = storage
53 .get_object(&alias_id)
54 .ok_or_else(|| anyhow!("missing alias object"))?;
55
56 verify_address_owner(
58 output.governor_address(),
59 created_output_obj,
60 "alias output",
61 address_swap_map,
62 )?;
63
64 let expected_alias_owner = Owner::ObjectOwner(
66 derive_dynamic_field_id(
67 created_output_obj.id(),
68 &DynamicFieldInfo::dynamic_object_field_wrapper(
69 ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE.parse::<TypeTag>()?,
70 )
71 .into(),
72 &bcs::to_bytes(ALIAS_DYNAMIC_OBJECT_FIELD_KEY)?,
73 )?
74 .into(),
75 );
76
77 ensure!(
78 created_alias_obj.owner == expected_alias_owner,
79 "alias owner mismatch: found {}, expected {}",
80 created_alias_obj.owner,
81 expected_alias_owner
82 );
83
84 let created_alias = created_alias_obj
85 .to_rust::<Alias>()
86 .ok_or_else(|| anyhow!("invalid alias object"))?;
87
88 let created_output = created_output_obj
89 .to_rust::<AliasOutput>()
90 .ok_or_else(|| anyhow!("invalid alias output object"))?;
91
92 ensure!(
94 created_output.balance.value() == output.amount(),
95 "amount mismatch: found {}, expected {}",
96 created_output.balance.value(),
97 output.amount()
98 );
99 tokens_counter.update_total_value_for_iota(created_output.balance.value());
100
101 verify_native_tokens::<Field<String, Balance>>(
103 output.native_tokens(),
104 foundry_data,
105 created_output.native_tokens,
106 created_objects.native_tokens().ok(),
107 storage,
108 tokens_counter,
109 )?;
110
111 let expected_state_controller = output
113 .state_controller_address()
114 .to_string()
115 .parse::<IotaAddress>()?;
116 ensure!(
117 created_alias.legacy_state_controller == expected_state_controller,
118 "legacy state controller mismatch: found {}, expected {}",
119 created_alias.legacy_state_controller,
120 expected_state_controller
121 );
122
123 ensure!(
125 created_alias.state_index == output.state_index(),
126 "state index mismatch: found {}, expected {}",
127 created_alias.state_index,
128 output.state_index()
129 );
130
131 if output.state_metadata().is_empty() {
133 ensure!(
134 created_alias.state_metadata.is_none(),
135 "unexpected state metadata found"
136 );
137 } else {
138 let Some(state_metadata) = created_alias.state_metadata.as_ref() else {
139 bail!("missing state metadata")
140 };
141
142 ensure!(
143 state_metadata.as_slice() == output.state_metadata(),
144 "state metadata mismatch: found {:?}, expected {:?}",
145 state_metadata,
146 output.state_metadata()
147 );
148 }
149
150 verify_sender_feature(output.features().sender(), created_alias.sender)?;
152
153 verify_metadata_feature(
155 output.features().metadata(),
156 created_alias.metadata.as_ref(),
157 )?;
158
159 verify_issuer_feature(
161 output.immutable_features().issuer(),
162 created_alias.immutable_issuer,
163 )?;
164
165 verify_metadata_feature(
167 output.immutable_features().metadata(),
168 created_alias.immutable_metadata.as_ref(),
169 )?;
170
171 verify_parent(&output_id, output.governor_address(), storage)?;
172
173 ensure!(created_objects.coin().is_err(), "unexpected coin found");
174
175 ensure!(
176 created_objects.native_token_coin().is_err(),
177 "unexpected native token coin found"
178 );
179
180 ensure!(
181 created_objects.coin_manager().is_err(),
182 "unexpected coin manager found"
183 );
184
185 ensure!(
186 created_objects.coin_manager_treasury_cap().is_err(),
187 "unexpected coin manager treasury cap found"
188 );
189
190 ensure!(
191 created_objects.package().is_err(),
192 "unexpected package found"
193 );
194
195 Ok(())
196}