1use std::{collections::HashMap, str::FromStr};
6
7use fastcrypto::traits::ToFromBytes;
8use iota_types::{
9 BRIDGE_PACKAGE_ID, Identifier, TypeTag,
10 base_types::{IotaAddress, ObjectRef},
11 bridge::{
12 BRIDGE_CREATE_ADD_TOKEN_ON_IOTA_MESSAGE_FUNCTION_NAME,
13 BRIDGE_EXECUTE_SYSTEM_MESSAGE_FUNCTION_NAME, BRIDGE_MESSAGE_MODULE_NAME,
14 BRIDGE_MODULE_NAME,
15 },
16 programmable_transaction_builder::ProgrammableTransactionBuilder,
17 transaction::{CallArg, ObjectArg, TransactionData},
18};
19use move_core_types::ident_str;
20
21use crate::{
22 error::{BridgeError, BridgeResult},
23 types::{BridgeAction, VerifiedCertifiedBridgeAction},
24};
25
26pub fn build_iota_transaction(
27 client_address: IotaAddress,
28 gas_object_ref: &ObjectRef,
29 action: VerifiedCertifiedBridgeAction,
30 bridge_object_arg: ObjectArg,
31 iota_token_type_tags: &HashMap<u8, TypeTag>,
32 rgp: u64,
33) -> BridgeResult<TransactionData> {
34 match action.data() {
36 BridgeAction::EthToIotaBridgeAction(_) => build_token_bridge_approve_transaction(
37 client_address,
38 gas_object_ref,
39 action,
40 true,
41 bridge_object_arg,
42 iota_token_type_tags,
43 rgp,
44 ),
45 BridgeAction::IotaToEthBridgeAction(_) => build_token_bridge_approve_transaction(
46 client_address,
47 gas_object_ref,
48 action,
49 false,
50 bridge_object_arg,
51 iota_token_type_tags,
52 rgp,
53 ),
54 BridgeAction::BlocklistCommitteeAction(_) => build_committee_blocklist_approve_transaction(
55 client_address,
56 gas_object_ref,
57 action,
58 bridge_object_arg,
59 rgp,
60 ),
61 BridgeAction::EmergencyAction(_) => build_emergency_op_approve_transaction(
62 client_address,
63 gas_object_ref,
64 action,
65 bridge_object_arg,
66 rgp,
67 ),
68 BridgeAction::LimitUpdateAction(_) => build_limit_update_approve_transaction(
69 client_address,
70 gas_object_ref,
71 action,
72 bridge_object_arg,
73 rgp,
74 ),
75 BridgeAction::AssetPriceUpdateAction(_) => build_asset_price_update_approve_transaction(
76 client_address,
77 gas_object_ref,
78 action,
79 bridge_object_arg,
80 rgp,
81 ),
82 BridgeAction::EvmContractUpgradeAction(_) => {
83 unreachable!()
85 }
86 BridgeAction::AddTokensOnIotaAction(_) => build_add_tokens_on_iota_transaction(
87 client_address,
88 gas_object_ref,
89 action,
90 bridge_object_arg,
91 rgp,
92 ),
93 BridgeAction::AddTokensOnEvmAction(_) => {
94 unreachable!()
96 }
97 }
98}
99
100fn build_token_bridge_approve_transaction(
101 client_address: IotaAddress,
102 gas_object_ref: &ObjectRef,
103 action: VerifiedCertifiedBridgeAction,
104 claim: bool,
105 bridge_object_arg: ObjectArg,
106 iota_token_type_tags: &HashMap<u8, TypeTag>,
107 rgp: u64,
108) -> BridgeResult<TransactionData> {
109 let (bridge_action, sigs) = action.into_inner().into_data_and_sig();
110 let mut builder = ProgrammableTransactionBuilder::new();
111
112 let (source_chain, seq_num, sender, target_chain, target, token_type, amount) =
113 match bridge_action {
114 BridgeAction::IotaToEthBridgeAction(a) => {
115 let bridge_event = a.iota_bridge_event;
116 (
117 bridge_event.iota_chain_id,
118 bridge_event.nonce,
119 bridge_event.iota_address.to_vec(),
120 bridge_event.eth_chain_id,
121 bridge_event.eth_address.to_fixed_bytes().to_vec(),
122 bridge_event.token_id,
123 bridge_event.amount_iota_adjusted,
124 )
125 }
126 BridgeAction::EthToIotaBridgeAction(a) => {
127 let bridge_event = a.eth_bridge_event;
128 (
129 bridge_event.eth_chain_id,
130 bridge_event.nonce,
131 bridge_event.eth_address.to_fixed_bytes().to_vec(),
132 bridge_event.iota_chain_id,
133 bridge_event.iota_address.to_vec(),
134 bridge_event.token_id,
135 bridge_event.iota_adjusted_amount,
136 )
137 }
138 _ => unreachable!(),
139 };
140
141 let source_chain = builder.pure(source_chain as u8).unwrap();
142 let seq_num = builder.pure(seq_num).unwrap();
143 let sender = builder.pure(sender.clone()).map_err(|e| {
144 BridgeError::BridgeSerialization(format!(
145 "Failed to serialize sender: {:?}. Err: {:?}",
146 sender, e
147 ))
148 })?;
149 let target_chain = builder.pure(target_chain as u8).unwrap();
150 let target = builder.pure(target.clone()).map_err(|e| {
151 BridgeError::BridgeSerialization(format!(
152 "Failed to serialize target: {:?}. Err: {:?}",
153 target, e
154 ))
155 })?;
156 let arg_token_type = builder.pure(token_type).unwrap();
157 let amount = builder.pure(amount).unwrap();
158
159 let arg_msg = builder.programmable_move_call(
160 BRIDGE_PACKAGE_ID,
161 ident_str!("message").to_owned(),
162 ident_str!("create_token_bridge_message").to_owned(),
163 vec![],
164 vec![
165 source_chain,
166 seq_num,
167 sender,
168 target_chain,
169 target,
170 arg_token_type,
171 amount,
172 ],
173 );
174
175 let arg_bridge = builder.obj(bridge_object_arg).unwrap();
177 let arg_clock = builder.input(CallArg::CLOCK_IMM).unwrap();
178
179 let mut sig_bytes = vec![];
180 for (_, sig) in sigs.signatures {
181 sig_bytes.push(sig.as_bytes().to_vec());
182 }
183 let arg_signatures = builder.pure(sig_bytes.clone()).map_err(|e| {
184 BridgeError::BridgeSerialization(format!(
185 "Failed to serialize signatures: {:?}. Err: {:?}",
186 sig_bytes, e
187 ))
188 })?;
189
190 builder.programmable_move_call(
191 BRIDGE_PACKAGE_ID,
192 iota_types::bridge::BRIDGE_MODULE_NAME.to_owned(),
193 ident_str!("approve_token_transfer").to_owned(),
194 vec![],
195 vec![arg_bridge, arg_msg, arg_signatures],
196 );
197
198 if claim {
199 builder.programmable_move_call(
200 BRIDGE_PACKAGE_ID,
201 iota_types::bridge::BRIDGE_MODULE_NAME.to_owned(),
202 ident_str!("claim_and_transfer_token").to_owned(),
203 vec![
204 iota_token_type_tags
205 .get(&token_type)
206 .ok_or(BridgeError::UnknownTokenId(token_type))?
207 .clone(),
208 ],
209 vec![arg_bridge, arg_clock, source_chain, seq_num],
210 );
211 }
212
213 let pt = builder.finish();
214
215 Ok(TransactionData::new_programmable(
216 client_address,
217 vec![*gas_object_ref],
218 pt,
219 100_000_000,
220 rgp,
221 ))
222}
223
224fn build_emergency_op_approve_transaction(
225 client_address: IotaAddress,
226 gas_object_ref: &ObjectRef,
227 action: VerifiedCertifiedBridgeAction,
228 bridge_object_arg: ObjectArg,
229 rgp: u64,
230) -> BridgeResult<TransactionData> {
231 let (bridge_action, sigs) = action.into_inner().into_data_and_sig();
232
233 let mut builder = ProgrammableTransactionBuilder::new();
234
235 let (source_chain, seq_num, action_type) = match bridge_action {
236 BridgeAction::EmergencyAction(a) => (a.chain_id, a.nonce, a.action_type),
237 _ => unreachable!(),
238 };
239
240 let source_chain = builder.pure(source_chain as u8).unwrap();
242 let seq_num = builder.pure(seq_num).unwrap();
243 let action_type = builder.pure(action_type as u8).unwrap();
244 let arg_bridge = builder.obj(bridge_object_arg).unwrap();
245
246 let arg_msg = builder.programmable_move_call(
247 BRIDGE_PACKAGE_ID,
248 ident_str!("message").to_owned(),
249 ident_str!("create_emergency_op_message").to_owned(),
250 vec![],
251 vec![source_chain, seq_num, action_type],
252 );
253
254 let mut sig_bytes = vec![];
255 for (_, sig) in sigs.signatures {
256 sig_bytes.push(sig.as_bytes().to_vec());
257 }
258 let arg_signatures = builder.pure(sig_bytes.clone()).map_err(|e| {
259 BridgeError::BridgeSerialization(format!(
260 "Failed to serialize signatures: {:?}. Err: {:?}",
261 sig_bytes, e
262 ))
263 })?;
264
265 builder.programmable_move_call(
266 BRIDGE_PACKAGE_ID,
267 ident_str!("bridge").to_owned(),
268 ident_str!("execute_system_message").to_owned(),
269 vec![],
270 vec![arg_bridge, arg_msg, arg_signatures],
271 );
272
273 let pt = builder.finish();
274
275 Ok(TransactionData::new_programmable(
276 client_address,
277 vec![*gas_object_ref],
278 pt,
279 100_000_000,
280 rgp,
281 ))
282}
283
284fn build_committee_blocklist_approve_transaction(
285 client_address: IotaAddress,
286 gas_object_ref: &ObjectRef,
287 action: VerifiedCertifiedBridgeAction,
288 bridge_object_arg: ObjectArg,
289 rgp: u64,
290) -> BridgeResult<TransactionData> {
291 let (bridge_action, sigs) = action.into_inner().into_data_and_sig();
292
293 let mut builder = ProgrammableTransactionBuilder::new();
294
295 let (source_chain, seq_num, blocklist_type, members_to_update) = match bridge_action {
296 BridgeAction::BlocklistCommitteeAction(a) => {
297 (a.chain_id, a.nonce, a.blocklist_type, a.members_to_update)
298 }
299 _ => unreachable!(),
300 };
301
302 let source_chain = builder.pure(source_chain as u8).unwrap();
304 let seq_num = builder.pure(seq_num).unwrap();
305 let blocklist_type = builder.pure(blocklist_type as u8).unwrap();
306 let members_to_update = members_to_update
307 .into_iter()
308 .map(|m| m.to_eth_address().as_bytes().to_vec())
309 .collect::<Vec<_>>();
310 let members_to_update = builder.pure(members_to_update).unwrap();
311 let arg_bridge = builder.obj(bridge_object_arg).unwrap();
312
313 let arg_msg = builder.programmable_move_call(
314 BRIDGE_PACKAGE_ID,
315 ident_str!("message").to_owned(),
316 ident_str!("create_blocklist_message").to_owned(),
317 vec![],
318 vec![source_chain, seq_num, blocklist_type, members_to_update],
319 );
320
321 let mut sig_bytes = vec![];
322 for (_, sig) in sigs.signatures {
323 sig_bytes.push(sig.as_bytes().to_vec());
324 }
325 let arg_signatures = builder.pure(sig_bytes.clone()).map_err(|e| {
326 BridgeError::BridgeSerialization(format!(
327 "Failed to serialize signatures: {:?}. Err: {:?}",
328 sig_bytes, e
329 ))
330 })?;
331
332 builder.programmable_move_call(
333 BRIDGE_PACKAGE_ID,
334 ident_str!("bridge").to_owned(),
335 ident_str!("execute_system_message").to_owned(),
336 vec![],
337 vec![arg_bridge, arg_msg, arg_signatures],
338 );
339
340 let pt = builder.finish();
341
342 Ok(TransactionData::new_programmable(
343 client_address,
344 vec![*gas_object_ref],
345 pt,
346 100_000_000,
347 rgp,
348 ))
349}
350
351fn build_limit_update_approve_transaction(
352 client_address: IotaAddress,
353 gas_object_ref: &ObjectRef,
354 action: VerifiedCertifiedBridgeAction,
355 bridge_object_arg: ObjectArg,
356 rgp: u64,
357) -> BridgeResult<TransactionData> {
358 let (bridge_action, sigs) = action.into_inner().into_data_and_sig();
359
360 let mut builder = ProgrammableTransactionBuilder::new();
361
362 let (receiving_chain_id, seq_num, sending_chain_id, new_usd_limit) = match bridge_action {
363 BridgeAction::LimitUpdateAction(a) => {
364 (a.chain_id, a.nonce, a.sending_chain_id, a.new_usd_limit)
365 }
366 _ => unreachable!(),
367 };
368
369 let receiving_chain_id = builder.pure(receiving_chain_id as u8).unwrap();
371 let seq_num = builder.pure(seq_num).unwrap();
372 let sending_chain_id = builder.pure(sending_chain_id as u8).unwrap();
373 let new_usd_limit = builder.pure(new_usd_limit).unwrap();
374 let arg_bridge = builder.obj(bridge_object_arg).unwrap();
375
376 let arg_msg = builder.programmable_move_call(
377 BRIDGE_PACKAGE_ID,
378 ident_str!("message").to_owned(),
379 ident_str!("create_update_bridge_limit_message").to_owned(),
380 vec![],
381 vec![receiving_chain_id, seq_num, sending_chain_id, new_usd_limit],
382 );
383
384 let mut sig_bytes = vec![];
385 for (_, sig) in sigs.signatures {
386 sig_bytes.push(sig.as_bytes().to_vec());
387 }
388 let arg_signatures = builder.pure(sig_bytes.clone()).map_err(|e| {
389 BridgeError::BridgeSerialization(format!(
390 "Failed to serialize signatures: {:?}. Err: {:?}",
391 sig_bytes, e
392 ))
393 })?;
394
395 builder.programmable_move_call(
396 BRIDGE_PACKAGE_ID,
397 ident_str!("bridge").to_owned(),
398 ident_str!("execute_system_message").to_owned(),
399 vec![],
400 vec![arg_bridge, arg_msg, arg_signatures],
401 );
402
403 let pt = builder.finish();
404
405 Ok(TransactionData::new_programmable(
406 client_address,
407 vec![*gas_object_ref],
408 pt,
409 100_000_000,
410 rgp,
411 ))
412}
413
414fn build_asset_price_update_approve_transaction(
415 client_address: IotaAddress,
416 gas_object_ref: &ObjectRef,
417 action: VerifiedCertifiedBridgeAction,
418 bridge_object_arg: ObjectArg,
419 rgp: u64,
420) -> BridgeResult<TransactionData> {
421 let (bridge_action, sigs) = action.into_inner().into_data_and_sig();
422
423 let mut builder = ProgrammableTransactionBuilder::new();
424
425 let (source_chain, seq_num, token_id, new_usd_price) = match bridge_action {
426 BridgeAction::AssetPriceUpdateAction(a) => {
427 (a.chain_id, a.nonce, a.token_id, a.new_usd_price)
428 }
429 _ => unreachable!(),
430 };
431
432 let source_chain = builder.pure(source_chain as u8).unwrap();
434 let token_id = builder.pure(token_id).unwrap();
435 let seq_num = builder.pure(seq_num).unwrap();
436 let new_price = builder.pure(new_usd_price).unwrap();
437 let arg_bridge = builder.obj(bridge_object_arg).unwrap();
438
439 let arg_msg = builder.programmable_move_call(
440 BRIDGE_PACKAGE_ID,
441 ident_str!("message").to_owned(),
442 ident_str!("create_update_asset_price_message").to_owned(),
443 vec![],
444 vec![token_id, source_chain, seq_num, new_price],
445 );
446
447 let mut sig_bytes = vec![];
448 for (_, sig) in sigs.signatures {
449 sig_bytes.push(sig.as_bytes().to_vec());
450 }
451 let arg_signatures = builder.pure(sig_bytes.clone()).map_err(|e| {
452 BridgeError::BridgeSerialization(format!(
453 "Failed to serialize signatures: {:?}. Err: {:?}",
454 sig_bytes, e
455 ))
456 })?;
457
458 builder.programmable_move_call(
459 BRIDGE_PACKAGE_ID,
460 ident_str!("bridge").to_owned(),
461 ident_str!("execute_system_message").to_owned(),
462 vec![],
463 vec![arg_bridge, arg_msg, arg_signatures],
464 );
465
466 let pt = builder.finish();
467
468 Ok(TransactionData::new_programmable(
469 client_address,
470 vec![*gas_object_ref],
471 pt,
472 100_000_000,
473 rgp,
474 ))
475}
476
477pub fn build_add_tokens_on_iota_transaction(
478 client_address: IotaAddress,
479 gas_object_ref: &ObjectRef,
480 action: VerifiedCertifiedBridgeAction,
481 bridge_object_arg: ObjectArg,
482 rgp: u64,
483) -> BridgeResult<TransactionData> {
484 let (bridge_action, sigs) = action.into_inner().into_data_and_sig();
485
486 let mut builder = ProgrammableTransactionBuilder::new();
487
488 let (source_chain, seq_num, native, token_ids, token_type_names, token_prices) =
489 match bridge_action {
490 BridgeAction::AddTokensOnIotaAction(a) => (
491 a.chain_id,
492 a.nonce,
493 a.native,
494 a.token_ids,
495 a.token_type_names,
496 a.token_prices,
497 ),
498 _ => unreachable!(),
499 };
500 let token_type_names = token_type_names
501 .iter()
502 .map(|type_name| type_name.to_canonical_string(false))
503 .collect::<Vec<_>>();
504 let source_chain = builder.pure(source_chain as u8).unwrap();
505 let seq_num = builder.pure(seq_num).unwrap();
506 let native_token = builder.pure(native).unwrap();
507 let token_ids = builder.pure(token_ids).unwrap();
508 let token_type_names = builder.pure(token_type_names).unwrap();
509 let token_prices = builder.pure(token_prices).unwrap();
510
511 let message_arg = builder.programmable_move_call(
512 BRIDGE_PACKAGE_ID,
513 BRIDGE_MESSAGE_MODULE_NAME.into(),
514 BRIDGE_CREATE_ADD_TOKEN_ON_IOTA_MESSAGE_FUNCTION_NAME.into(),
515 vec![],
516 vec![
517 source_chain,
518 seq_num,
519 native_token,
520 token_ids,
521 token_type_names,
522 token_prices,
523 ],
524 );
525
526 let bridge_arg = builder.obj(bridge_object_arg).unwrap();
527
528 let mut sig_bytes = vec![];
529 for (_, sig) in sigs.signatures {
530 sig_bytes.push(sig.as_bytes().to_vec());
531 }
532 let sigs_arg = builder.pure(sig_bytes.clone()).unwrap();
533
534 builder.programmable_move_call(
535 BRIDGE_PACKAGE_ID,
536 BRIDGE_MODULE_NAME.into(),
537 BRIDGE_EXECUTE_SYSTEM_MESSAGE_FUNCTION_NAME.into(),
538 vec![],
539 vec![bridge_arg, message_arg, sigs_arg],
540 );
541
542 let pt = builder.finish();
543
544 Ok(TransactionData::new_programmable(
545 client_address,
546 vec![*gas_object_ref],
547 pt,
548 100_000_000,
549 rgp,
550 ))
551}
552
553pub fn build_committee_register_transaction(
554 validator_address: IotaAddress,
555 gas_object_ref: &ObjectRef,
556 bridge_object_arg: ObjectArg,
557 bridge_authority_pub_key_bytes: Vec<u8>,
558 bridge_url: &str,
559 ref_gas_price: u64,
560 gas_budget: u64,
561) -> BridgeResult<TransactionData> {
562 let mut builder = ProgrammableTransactionBuilder::new();
563 let system_state = builder.obj(ObjectArg::IOTA_SYSTEM_MUT).unwrap();
564 let bridge = builder.obj(bridge_object_arg).unwrap();
565 let bridge_pubkey = builder
566 .input(CallArg::Pure(
567 bcs::to_bytes(&bridge_authority_pub_key_bytes).unwrap(),
568 ))
569 .unwrap();
570 let url = builder
571 .input(CallArg::Pure(bcs::to_bytes(bridge_url.as_bytes()).unwrap()))
572 .unwrap();
573 builder.programmable_move_call(
574 BRIDGE_PACKAGE_ID,
575 BRIDGE_MODULE_NAME.into(),
576 Identifier::from_str("committee_registration").unwrap(),
577 vec![],
578 vec![bridge, system_state, bridge_pubkey, url],
579 );
580 let data = TransactionData::new_programmable(
581 validator_address,
582 vec![*gas_object_ref],
583 builder.finish(),
584 gas_budget,
585 ref_gas_price,
586 );
587 Ok(data)
588}
589
590pub fn build_committee_update_url_transaction(
591 validator_address: IotaAddress,
592 gas_object_ref: &ObjectRef,
593 bridge_object_arg: ObjectArg,
594 bridge_url: &str,
595 ref_gas_price: u64,
596 gas_budget: u64,
597) -> BridgeResult<TransactionData> {
598 let mut builder = ProgrammableTransactionBuilder::new();
599 let bridge = builder.obj(bridge_object_arg).unwrap();
600 let url = builder
601 .input(CallArg::Pure(bcs::to_bytes(bridge_url.as_bytes()).unwrap()))
602 .unwrap();
603 builder.programmable_move_call(
604 BRIDGE_PACKAGE_ID,
605 BRIDGE_MODULE_NAME.into(),
606 Identifier::from_str("update_node_url").unwrap(),
607 vec![],
608 vec![bridge, url],
609 );
610 let data = TransactionData::new_programmable(
611 validator_address,
612 vec![*gas_object_ref],
613 builder.finish(),
614 gas_budget,
615 ref_gas_price,
616 );
617 Ok(data)
618}
619
620#[cfg(test)]
621mod tests {
622 use std::collections::HashMap;
623
624 use ethers::types::Address as EthAddress;
625 use iota_types::{
626 bridge::{BridgeChainId, TOKEN_ID_BTC, TOKEN_ID_USDC},
627 crypto::{ToFromBytes, get_key_pair},
628 };
629 use test_cluster::TestClusterBuilder;
630
631 use crate::{
632 BRIDGE_ENABLE_PROTOCOL_VERSION,
633 crypto::{BridgeAuthorityKeyPair, BridgeAuthorityPublicKeyBytes},
634 iota_client::IotaClient,
635 test_utils::{
636 approve_action_with_validator_secrets, bridge_token,
637 get_test_eth_to_iota_bridge_action, get_test_iota_to_eth_bridge_action,
638 },
639 types::{BridgeAction, EmergencyAction, EmergencyActionType, *},
640 };
641
642 #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
643 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
644 async fn test_build_iota_transaction_for_token_transfer() {
645 telemetry_subscribers::init_for_testing();
646 let mut bridge_keys = vec![];
647 for _ in 0..=3 {
648 let (_, kp): (_, BridgeAuthorityKeyPair) = get_key_pair();
649 bridge_keys.push(kp);
650 }
651 let mut test_cluster: test_cluster::TestCluster = TestClusterBuilder::new()
652 .with_protocol_version((BRIDGE_ENABLE_PROTOCOL_VERSION).into())
653 .build_with_bridge(bridge_keys, true)
654 .await;
655
656 let iota_client = IotaClient::new(&test_cluster.fullnode_handle.rpc_url)
657 .await
658 .unwrap();
659 let bridge_authority_keys = test_cluster.bridge_authority_keys.take().unwrap();
660
661 test_cluster
665 .trigger_reconfiguration_if_not_yet_and_assert_bridge_committee_initialized()
666 .await;
667 let context = &mut test_cluster.wallet;
668 let sender = context.active_address().unwrap();
669 let usdc_amount = 5000000;
670 let bridge_object_arg = iota_client
671 .get_mutable_bridge_object_arg_must_succeed()
672 .await;
673 let id_token_map = iota_client.get_token_id_map().await.unwrap();
674
675 let action =
677 get_test_eth_to_iota_bridge_action(None, Some(usdc_amount), Some(sender), None);
678 let usdc_object_ref = approve_action_with_validator_secrets(
680 context,
681 bridge_object_arg,
682 action.clone(),
683 &bridge_authority_keys,
684 Some(sender),
685 &id_token_map,
686 )
687 .await
688 .unwrap();
689
690 let bridge_event = bridge_token(
692 context,
693 EthAddress::random(),
694 usdc_object_ref,
695 id_token_map.get(&TOKEN_ID_USDC).unwrap().clone(),
696 bridge_object_arg,
697 )
698 .await;
699
700 let action = get_test_iota_to_eth_bridge_action(
701 None,
702 None,
703 Some(bridge_event.nonce),
704 Some(bridge_event.amount_iota_adjusted),
705 Some(bridge_event.iota_address),
706 Some(bridge_event.eth_address),
707 Some(TOKEN_ID_USDC),
708 );
709 approve_action_with_validator_secrets(
711 context,
712 bridge_object_arg,
713 action.clone(),
714 &bridge_authority_keys,
715 None,
716 &id_token_map,
717 )
718 .await;
719 }
720
721 #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
722 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
723 async fn test_build_iota_transaction_for_emergency_op() {
724 telemetry_subscribers::init_for_testing();
725 let mut bridge_keys = vec![];
726 for _ in 0..=3 {
727 let (_, kp): (_, BridgeAuthorityKeyPair) = get_key_pair();
728 bridge_keys.push(kp);
729 }
730 let mut test_cluster: test_cluster::TestCluster = TestClusterBuilder::new()
731 .with_protocol_version((BRIDGE_ENABLE_PROTOCOL_VERSION).into())
732 .build_with_bridge(bridge_keys, true)
733 .await;
734 let iota_client = IotaClient::new(&test_cluster.fullnode_handle.rpc_url)
735 .await
736 .unwrap();
737 let bridge_authority_keys = test_cluster.bridge_authority_keys.take().unwrap();
738
739 test_cluster
741 .trigger_reconfiguration_if_not_yet_and_assert_bridge_committee_initialized()
742 .await;
743 let summary = iota_client.get_bridge_summary().await.unwrap();
744 assert!(!summary.is_frozen);
745
746 let context = &mut test_cluster.wallet;
747 let bridge_object_arg = iota_client
748 .get_mutable_bridge_object_arg_must_succeed()
749 .await;
750 let id_token_map = iota_client.get_token_id_map().await.unwrap();
751
752 let action = BridgeAction::EmergencyAction(EmergencyAction {
754 nonce: 0,
755 chain_id: BridgeChainId::IotaCustom,
756 action_type: EmergencyActionType::Pause,
757 });
758 approve_action_with_validator_secrets(
760 context,
761 bridge_object_arg,
762 action.clone(),
763 &bridge_authority_keys,
764 None,
765 &id_token_map,
766 )
767 .await;
768 let summary = iota_client.get_bridge_summary().await.unwrap();
769 assert!(summary.is_frozen);
770
771 let action = BridgeAction::EmergencyAction(EmergencyAction {
773 nonce: 1,
774 chain_id: BridgeChainId::IotaCustom,
775 action_type: EmergencyActionType::Unpause,
776 });
777 approve_action_with_validator_secrets(
779 context,
780 bridge_object_arg,
781 action.clone(),
782 &bridge_authority_keys,
783 None,
784 &id_token_map,
785 )
786 .await;
787 let summary = iota_client.get_bridge_summary().await.unwrap();
788 assert!(!summary.is_frozen);
789 }
790
791 #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
792 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
793 async fn test_build_iota_transaction_for_committee_blocklist() {
794 telemetry_subscribers::init_for_testing();
795 let mut bridge_keys = vec![];
796 for _ in 0..=3 {
797 let (_, kp): (_, BridgeAuthorityKeyPair) = get_key_pair();
798 bridge_keys.push(kp);
799 }
800 let mut test_cluster: test_cluster::TestCluster = TestClusterBuilder::new()
801 .with_protocol_version((BRIDGE_ENABLE_PROTOCOL_VERSION).into())
802 .build_with_bridge(bridge_keys, true)
803 .await;
804 let iota_client = IotaClient::new(&test_cluster.fullnode_handle.rpc_url)
805 .await
806 .unwrap();
807 let bridge_authority_keys = test_cluster.bridge_authority_keys.take().unwrap();
808
809 test_cluster
811 .trigger_reconfiguration_if_not_yet_and_assert_bridge_committee_initialized()
812 .await;
813 let committee = iota_client.get_bridge_summary().await.unwrap().committee;
814 let victim = committee.members.first().unwrap().clone().1;
815 for member in committee.members {
816 assert!(!member.1.blocklisted);
817 }
818
819 let context = &mut test_cluster.wallet;
820 let bridge_object_arg = iota_client
821 .get_mutable_bridge_object_arg_must_succeed()
822 .await;
823 let id_token_map = iota_client.get_token_id_map().await.unwrap();
824
825 let action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction {
827 nonce: 0,
828 chain_id: BridgeChainId::IotaCustom,
829 blocklist_type: BlocklistType::Blocklist,
830 members_to_update: vec![
831 BridgeAuthorityPublicKeyBytes::from_bytes(&victim.bridge_pubkey_bytes).unwrap(),
832 ],
833 });
834 approve_action_with_validator_secrets(
836 context,
837 bridge_object_arg,
838 action.clone(),
839 &bridge_authority_keys,
840 None,
841 &id_token_map,
842 )
843 .await;
844 let committee = iota_client.get_bridge_summary().await.unwrap().committee;
845 for member in committee.members {
846 if member.1.bridge_pubkey_bytes == victim.bridge_pubkey_bytes {
847 assert!(member.1.blocklisted);
848 } else {
849 assert!(!member.1.blocklisted);
850 }
851 }
852
853 let action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction {
855 nonce: 1,
856 chain_id: BridgeChainId::IotaCustom,
857 blocklist_type: BlocklistType::Unblocklist,
858 members_to_update: vec![
859 BridgeAuthorityPublicKeyBytes::from_bytes(&victim.bridge_pubkey_bytes).unwrap(),
860 ],
861 });
862 approve_action_with_validator_secrets(
864 context,
865 bridge_object_arg,
866 action.clone(),
867 &bridge_authority_keys,
868 None,
869 &id_token_map,
870 )
871 .await;
872 let committee = iota_client.get_bridge_summary().await.unwrap().committee;
873 for member in committee.members {
874 assert!(!member.1.blocklisted);
875 }
876 }
877
878 #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
879 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
880 async fn test_build_iota_transaction_for_limit_update() {
881 telemetry_subscribers::init_for_testing();
882 let mut bridge_keys = vec![];
883 for _ in 0..=3 {
884 let (_, kp): (_, BridgeAuthorityKeyPair) = get_key_pair();
885 bridge_keys.push(kp);
886 }
887 let mut test_cluster: test_cluster::TestCluster = TestClusterBuilder::new()
888 .with_protocol_version((BRIDGE_ENABLE_PROTOCOL_VERSION).into())
889 .build_with_bridge(bridge_keys, true)
890 .await;
891 let iota_client = IotaClient::new(&test_cluster.fullnode_handle.rpc_url)
892 .await
893 .unwrap();
894 let bridge_authority_keys = test_cluster.bridge_authority_keys.take().unwrap();
895
896 test_cluster
898 .trigger_reconfiguration_if_not_yet_and_assert_bridge_committee_initialized()
899 .await;
900 let transfer_limit = iota_client
901 .get_bridge_summary()
902 .await
903 .unwrap()
904 .limiter
905 .transfer_limit
906 .into_iter()
907 .map(|(s, d, l)| ((s, d), l))
908 .collect::<HashMap<_, _>>();
909
910 let context = &mut test_cluster.wallet;
911 let bridge_object_arg = iota_client
912 .get_mutable_bridge_object_arg_must_succeed()
913 .await;
914 let id_token_map = iota_client.get_token_id_map().await.unwrap();
915
916 let action = BridgeAction::LimitUpdateAction(LimitUpdateAction {
918 nonce: 0,
919 chain_id: BridgeChainId::IotaCustom,
920 sending_chain_id: BridgeChainId::EthCustom,
921 new_usd_limit: 6_666_666 * USD_MULTIPLIER, });
923 approve_action_with_validator_secrets(
925 context,
926 bridge_object_arg,
927 action.clone(),
928 &bridge_authority_keys,
929 None,
930 &id_token_map,
931 )
932 .await;
933 let new_transfer_limit = iota_client
934 .get_bridge_summary()
935 .await
936 .unwrap()
937 .limiter
938 .transfer_limit;
939 for limit in new_transfer_limit {
940 if limit.0 == BridgeChainId::EthCustom && limit.1 == BridgeChainId::IotaCustom {
941 assert_eq!(limit.2, 6_666_666 * USD_MULTIPLIER);
942 } else {
943 assert_eq!(limit.2, *transfer_limit.get(&(limit.0, limit.1)).unwrap());
944 }
945 }
946 }
947
948 #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
949 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
950 async fn test_build_iota_transaction_for_price_update() {
951 telemetry_subscribers::init_for_testing();
952 let mut bridge_keys = vec![];
953 for _ in 0..=3 {
954 let (_, kp): (_, BridgeAuthorityKeyPair) = get_key_pair();
955 bridge_keys.push(kp);
956 }
957 let mut test_cluster: test_cluster::TestCluster = TestClusterBuilder::new()
958 .with_protocol_version((BRIDGE_ENABLE_PROTOCOL_VERSION).into())
959 .build_with_bridge(bridge_keys, true)
960 .await;
961 let iota_client = IotaClient::new(&test_cluster.fullnode_handle.rpc_url)
962 .await
963 .unwrap();
964 let bridge_authority_keys = test_cluster.bridge_authority_keys.take().unwrap();
965
966 test_cluster
970 .trigger_reconfiguration_if_not_yet_and_assert_bridge_committee_initialized()
971 .await;
972 let notional_values = iota_client.get_notional_values().await.unwrap();
973 assert_ne!(notional_values[&TOKEN_ID_USDC], 69_000 * USD_MULTIPLIER);
974
975 let context = &mut test_cluster.wallet;
976 let bridge_object_arg = iota_client
977 .get_mutable_bridge_object_arg_must_succeed()
978 .await;
979 let id_token_map = iota_client.get_token_id_map().await.unwrap();
980
981 let action = BridgeAction::AssetPriceUpdateAction(AssetPriceUpdateAction {
983 nonce: 0,
984 chain_id: BridgeChainId::IotaCustom,
985 token_id: TOKEN_ID_BTC,
986 new_usd_price: 69_000 * USD_MULTIPLIER, });
988 approve_action_with_validator_secrets(
990 context,
991 bridge_object_arg,
992 action.clone(),
993 &bridge_authority_keys,
994 None,
995 &id_token_map,
996 )
997 .await;
998 let new_notional_values = iota_client.get_notional_values().await.unwrap();
999 for (token_id, price) in new_notional_values {
1000 if token_id == TOKEN_ID_BTC {
1001 assert_eq!(price, 69_000 * USD_MULTIPLIER);
1002 } else {
1003 assert_eq!(price, *notional_values.get(&token_id).unwrap());
1004 }
1005 }
1006 }
1007}