1#![allow(clippy::inconsistent_digit_grouping)]
6use std::{net::SocketAddr, str::FromStr, sync::Arc};
7
8use axum::{
9 Json, Router,
10 extract::{Path, State},
11 http::StatusCode,
12 routing::get,
13};
14use ethers::types::Address as EthAddress;
15use fastcrypto::{
16 encoding::{Encoding, Hex},
17 traits::ToFromBytes,
18};
19use iota_types::{TypeTag, bridge::BridgeChainId};
20use tracing::{info, instrument};
21
22use crate::{
23 crypto::BridgeAuthorityPublicKeyBytes,
24 error::BridgeError,
25 metrics::BridgeMetrics,
26 server::handler::{BridgeRequestHandler, BridgeRequestHandlerTrait},
27 types::{
28 AddTokensOnEvmAction, AddTokensOnIotaAction, AssetPriceUpdateAction,
29 BlocklistCommitteeAction, BlocklistType, BridgeAction, EmergencyAction,
30 EmergencyActionType, EvmContractUpgradeAction, LimitUpdateAction, SignedBridgeAction,
31 },
32 with_metrics,
33};
34
35pub mod governance_verifier;
36pub mod handler;
37
38#[cfg(test)]
39pub(crate) mod mock_handler;
40
41pub const APPLICATION_JSON: &str = "application/json";
42
43pub const PING_PATH: &str = "/ping";
44
45pub const ETH_TO_IOTA_TX_PATH: &str = "/sign/bridge_tx/eth/iota/:tx_hash/:event_index";
48pub const IOTA_TO_ETH_TX_PATH: &str = "/sign/bridge_tx/iota/eth/:tx_digest/:event_index";
49pub const COMMITTEE_BLOCKLIST_UPDATE_PATH: &str =
50 "/sign/update_committee_blocklist/:chain_id/:nonce/:type/:keys";
51pub const EMERGENCY_BUTTON_PATH: &str = "/sign/emergency_button/:chain_id/:nonce/:type";
52pub const LIMIT_UPDATE_PATH: &str =
53 "/sign/update_limit/:chain_id/:nonce/:sending_chain_id/:new_usd_limit";
54pub const ASSET_PRICE_UPDATE_PATH: &str =
55 "/sign/update_asset_price/:chain_id/:nonce/:token_id/:new_usd_price";
56pub const EVM_CONTRACT_UPGRADE_PATH_WITH_CALLDATA: &str =
57 "/sign/upgrade_evm_contract/:chain_id/:nonce/:proxy_address/:new_impl_address/:calldata";
58pub const EVM_CONTRACT_UPGRADE_PATH: &str =
59 "/sign/upgrade_evm_contract/:chain_id/:nonce/:proxy_address/:new_impl_address";
60pub const ADD_TOKENS_ON_IOTA_PATH: &str =
61 "/sign/add_tokens_on_iota/:chain_id/:nonce/:native/:token_ids/:token_type_names/:token_prices";
62pub const ADD_TOKENS_ON_EVM_PATH: &str = "/sign/add_tokens_on_evm/:chain_id/:nonce/:native/:token_ids/:token_addresses/:token_iota_decimals/:token_prices";
63
64#[derive(serde::Serialize, Clone)]
67pub struct BridgeNodePublicMetadata {
68 pub version: Option<String>,
69}
70
71impl BridgeNodePublicMetadata {
72 pub fn new(version: String) -> Self {
73 Self {
74 version: Some(version),
75 }
76 }
77
78 pub fn empty_for_testing() -> Self {
79 Self { version: None }
80 }
81}
82
83pub fn run_server(
84 socket_address: &SocketAddr,
85 handler: BridgeRequestHandler,
86 metrics: Arc<BridgeMetrics>,
87 metadata: Arc<BridgeNodePublicMetadata>,
88) -> tokio::task::JoinHandle<()> {
89 let socket_address = *socket_address;
90 tokio::spawn(async move {
91 let listener = tokio::net::TcpListener::bind(socket_address).await.unwrap();
92 axum::serve(
93 listener,
94 make_router(Arc::new(handler), metrics, metadata).into_make_service(),
95 )
96 .await
97 .unwrap();
98 })
99}
100
101pub(crate) fn make_router(
102 handler: Arc<impl BridgeRequestHandlerTrait + Sync + Send + 'static>,
103 metrics: Arc<BridgeMetrics>,
104 metadata: Arc<BridgeNodePublicMetadata>,
105) -> Router {
106 Router::new()
107 .route("/", get(health_check))
108 .route(PING_PATH, get(ping))
109 .route(ETH_TO_IOTA_TX_PATH, get(handle_eth_tx_hash))
110 .route(IOTA_TO_ETH_TX_PATH, get(handle_iota_tx_digest))
111 .route(
112 COMMITTEE_BLOCKLIST_UPDATE_PATH,
113 get(handle_update_committee_blocklist_action),
114 )
115 .route(EMERGENCY_BUTTON_PATH, get(handle_emergency_action))
116 .route(LIMIT_UPDATE_PATH, get(handle_limit_update_action))
117 .route(
118 ASSET_PRICE_UPDATE_PATH,
119 get(handle_asset_price_update_action),
120 )
121 .route(EVM_CONTRACT_UPGRADE_PATH, get(handle_evm_contract_upgrade))
122 .route(
123 EVM_CONTRACT_UPGRADE_PATH_WITH_CALLDATA,
124 get(handle_evm_contract_upgrade_with_calldata),
125 )
126 .route(ADD_TOKENS_ON_IOTA_PATH, get(handle_add_tokens_on_iota))
127 .route(ADD_TOKENS_ON_EVM_PATH, get(handle_add_tokens_on_evm))
128 .with_state((handler, metrics, metadata))
129}
130
131impl axum::response::IntoResponse for BridgeError {
132 fn into_response(self) -> axum::response::Response {
134 (
135 StatusCode::INTERNAL_SERVER_ERROR,
136 format!("Something went wrong: {:?}", self),
137 )
138 .into_response()
139 }
140}
141
142impl<E> From<E> for BridgeError
143where
144 E: Into<anyhow::Error>,
145{
146 fn from(err: E) -> Self {
147 Self::Generic(err.into().to_string())
148 }
149}
150
151async fn health_check() -> StatusCode {
152 StatusCode::OK
153}
154
155async fn ping(
156 State((_handler, _metrics, metadata)): State<(
157 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
158 Arc<BridgeMetrics>,
159 Arc<BridgeNodePublicMetadata>,
160 )>,
161) -> Result<Json<BridgeNodePublicMetadata>, BridgeError> {
162 Ok(Json(metadata.as_ref().clone()))
163}
164
165#[instrument(level = "error", skip_all, fields(tx_hash_hex=tx_hash_hex, event_idx=event_idx))]
166async fn handle_eth_tx_hash(
167 Path((tx_hash_hex, event_idx)): Path<(String, u16)>,
168 State((handler, metrics, _metadata)): State<(
169 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
170 Arc<BridgeMetrics>,
171 Arc<BridgeNodePublicMetadata>,
172 )>,
173) -> Result<Json<SignedBridgeAction>, BridgeError> {
174 let future = async {
175 let sig = handler.handle_eth_tx_hash(tx_hash_hex, event_idx).await?;
176 Ok(sig)
177 };
178 with_metrics!(metrics.clone(), "handle_eth_tx_hash", future).await
179}
180
181#[instrument(level = "error", skip_all, fields(tx_digest_base58=tx_digest_base58, event_idx=event_idx))]
182async fn handle_iota_tx_digest(
183 Path((tx_digest_base58, event_idx)): Path<(String, u16)>,
184 State((handler, metrics, _metadata)): State<(
185 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
186 Arc<BridgeMetrics>,
187 Arc<BridgeNodePublicMetadata>,
188 )>,
189) -> Result<Json<SignedBridgeAction>, BridgeError> {
190 let future = async {
191 let sig: Json<SignedBridgeAction> = handler
192 .handle_iota_tx_digest(tx_digest_base58, event_idx)
193 .await?;
194 Ok(sig)
195 };
196 with_metrics!(metrics.clone(), "handle_iota_tx_digest", future).await
197}
198
199#[instrument(level = "error", skip_all, fields(chain_id=chain_id, nonce=nonce, blocklist_type=blocklist_type, keys=keys))]
200async fn handle_update_committee_blocklist_action(
201 Path((chain_id, nonce, blocklist_type, keys)): Path<(u8, u64, u8, String)>,
202 State((handler, metrics, _metadata)): State<(
203 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
204 Arc<BridgeMetrics>,
205 Arc<BridgeNodePublicMetadata>,
206 )>,
207) -> Result<Json<SignedBridgeAction>, BridgeError> {
208 let future = async {
209 let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| {
210 BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err))
211 })?;
212 let blocklist_type = BlocklistType::try_from(blocklist_type).map_err(|err| {
213 BridgeError::InvalidBridgeClientRequest(format!(
214 "Invalid blocklist action type: {:?}",
215 err
216 ))
217 })?;
218 let members_to_update = keys
219 .split(',')
220 .map(|s| {
221 let bytes = Hex::decode(s).map_err(|e| anyhow::anyhow!("{:?}", e))?;
222 BridgeAuthorityPublicKeyBytes::from_bytes(&bytes)
223 .map_err(|e| anyhow::anyhow!("{:?}", e))
224 })
225 .collect::<Result<Vec<_>, _>>()
226 .map_err(|e| BridgeError::InvalidBridgeClientRequest(format!("{:?}", e)))?;
227 let action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction {
228 chain_id,
229 nonce,
230 blocklist_type,
231 members_to_update,
232 });
233
234 let sig: Json<SignedBridgeAction> = handler.handle_governance_action(action).await?;
235 Ok(sig)
236 };
237 with_metrics!(
238 metrics.clone(),
239 "handle_update_committee_blocklist_action",
240 future
241 )
242 .await
243}
244
245#[instrument(level = "error", skip_all, fields(chain_id=chain_id, nonce=nonce, action_type=action_type))]
246async fn handle_emergency_action(
247 Path((chain_id, nonce, action_type)): Path<(u8, u64, u8)>,
248 State((handler, metrics, _metadata)): State<(
249 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
250 Arc<BridgeMetrics>,
251 Arc<BridgeNodePublicMetadata>,
252 )>,
253) -> Result<Json<SignedBridgeAction>, BridgeError> {
254 let future = async {
255 let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| {
256 BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err))
257 })?;
258 let action_type = EmergencyActionType::try_from(action_type).map_err(|err| {
259 BridgeError::InvalidBridgeClientRequest(format!(
260 "Invalid emergency action type: {:?}",
261 err
262 ))
263 })?;
264 let action = BridgeAction::EmergencyAction(EmergencyAction {
265 chain_id,
266 nonce,
267 action_type,
268 });
269 let sig: Json<SignedBridgeAction> = handler.handle_governance_action(action).await?;
270 Ok(sig)
271 };
272 with_metrics!(metrics.clone(), "handle_emergency_action", future).await
273}
274
275#[instrument(level = "error", skip_all, fields(chain_id=chain_id, nonce=nonce, sending_chain_id=sending_chain_id, new_usd_limit=new_usd_limit))]
276async fn handle_limit_update_action(
277 Path((chain_id, nonce, sending_chain_id, new_usd_limit)): Path<(u8, u64, u8, u64)>,
278 State((handler, metrics, _metadata)): State<(
279 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
280 Arc<BridgeMetrics>,
281 Arc<BridgeNodePublicMetadata>,
282 )>,
283) -> Result<Json<SignedBridgeAction>, BridgeError> {
284 let future = async {
285 let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| {
286 BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err))
287 })?;
288 let sending_chain_id = BridgeChainId::try_from(sending_chain_id).map_err(|err| {
289 BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err))
290 })?;
291 let action = BridgeAction::LimitUpdateAction(LimitUpdateAction {
292 chain_id,
293 nonce,
294 sending_chain_id,
295 new_usd_limit,
296 });
297 let sig: Json<SignedBridgeAction> = handler.handle_governance_action(action).await?;
298 Ok(sig)
299 };
300 with_metrics!(metrics.clone(), "handle_limit_update_action", future).await
301}
302
303#[instrument(level = "error", skip_all, fields(chain_id=chain_id, nonce=nonce, token_id=token_id, new_usd_price=new_usd_price))]
304async fn handle_asset_price_update_action(
305 Path((chain_id, nonce, token_id, new_usd_price)): Path<(u8, u64, u8, u64)>,
306 State((handler, metrics, _metadata)): State<(
307 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
308 Arc<BridgeMetrics>,
309 Arc<BridgeNodePublicMetadata>,
310 )>,
311) -> Result<Json<SignedBridgeAction>, BridgeError> {
312 let future = async {
313 let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| {
314 BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err))
315 })?;
316 let action = BridgeAction::AssetPriceUpdateAction(AssetPriceUpdateAction {
317 chain_id,
318 nonce,
319 token_id,
320 new_usd_price,
321 });
322 let sig: Json<SignedBridgeAction> = handler.handle_governance_action(action).await?;
323 Ok(sig)
324 };
325 with_metrics!(metrics.clone(), "handle_asset_price_update_action", future).await
326}
327
328#[instrument(level = "error", skip_all, fields(chain_id=chain_id, nonce=nonce, proxy_address=format!("{:x}", proxy_address), new_impl_address=format!("{:x}", new_impl_address)))]
329async fn handle_evm_contract_upgrade_with_calldata(
330 Path((chain_id, nonce, proxy_address, new_impl_address, calldata)): Path<(
331 u8,
332 u64,
333 EthAddress,
334 EthAddress,
335 String,
336 )>,
337 State((handler, metrics, _metadata)): State<(
338 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
339 Arc<BridgeMetrics>,
340 Arc<BridgeNodePublicMetadata>,
341 )>,
342) -> Result<Json<SignedBridgeAction>, BridgeError> {
343 let future = async {
344 let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| {
345 BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err))
346 })?;
347 let call_data = Hex::decode(&calldata).map_err(|e| {
348 BridgeError::InvalidBridgeClientRequest(format!("Invalid call data: {:?}", e))
349 })?;
350 let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction {
351 chain_id,
352 nonce,
353 proxy_address,
354 new_impl_address,
355 call_data,
356 });
357 let sig: Json<SignedBridgeAction> = handler.handle_governance_action(action).await?;
358 Ok(sig)
359 };
360 with_metrics!(
361 metrics.clone(),
362 "handle_evm_contract_upgrade_with_calldata",
363 future
364 )
365 .await
366}
367
368#[instrument(
369 level = "error",
370 skip_all,
371 fields(chain_id, nonce, proxy_address, new_impl_address)
372)]
373async fn handle_evm_contract_upgrade(
374 Path((chain_id, nonce, proxy_address, new_impl_address)): Path<(
375 u8,
376 u64,
377 EthAddress,
378 EthAddress,
379 )>,
380 State((handler, metrics, _metadata)): State<(
381 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
382 Arc<BridgeMetrics>,
383 Arc<BridgeNodePublicMetadata>,
384 )>,
385) -> Result<Json<SignedBridgeAction>, BridgeError> {
386 let future = async {
387 let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| {
388 BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err))
389 })?;
390 let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction {
391 chain_id,
392 nonce,
393 proxy_address,
394 new_impl_address,
395 call_data: vec![],
396 });
397 let sig: Json<SignedBridgeAction> = handler.handle_governance_action(action).await?;
398
399 Ok(sig)
400 };
401 with_metrics!(metrics.clone(), "handle_evm_contract_upgrade", future).await
402}
403
404#[instrument(level = "error", skip_all, fields(chain_id=chain_id, nonce=nonce, native=native, token_ids=token_ids, token_type_names=token_type_names, token_prices=token_prices))]
405async fn handle_add_tokens_on_iota(
406 Path((chain_id, nonce, native, token_ids, token_type_names, token_prices)): Path<(
407 u8,
408 u64,
409 u8,
410 String,
411 String,
412 String,
413 )>,
414 State((handler, metrics, _metadata)): State<(
415 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
416 Arc<BridgeMetrics>,
417 Arc<BridgeNodePublicMetadata>,
418 )>,
419) -> Result<Json<SignedBridgeAction>, BridgeError> {
420 let future = async {
421 let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| {
422 BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err))
423 })?;
424
425 if !chain_id.is_iota_chain() {
426 return Err(BridgeError::InvalidBridgeClientRequest(
427 "handle_add_tokens_on_iota only expects IOTA chain id".to_string(),
428 ));
429 }
430
431 let native = match native {
432 1 => true,
433 0 => false,
434 _ => {
435 return Err(BridgeError::InvalidBridgeClientRequest(format!(
436 "Invalid native flag: {}",
437 native
438 )));
439 }
440 };
441 let token_ids = token_ids
442 .split(',')
443 .map(|s| {
444 s.parse::<u8>().map_err(|err| {
445 BridgeError::InvalidBridgeClientRequest(format!("Invalid token id: {:?}", err))
446 })
447 })
448 .collect::<Result<Vec<_>, _>>()?;
449 let token_type_names = token_type_names
450 .split(',')
451 .map(|s| {
452 TypeTag::from_str(s).map_err(|err| {
453 BridgeError::InvalidBridgeClientRequest(format!(
454 "Invalid token type name: {:?}",
455 err
456 ))
457 })
458 })
459 .collect::<Result<Vec<_>, _>>()?;
460 let token_prices = token_prices
461 .split(',')
462 .map(|s| {
463 s.parse::<u64>().map_err(|err| {
464 BridgeError::InvalidBridgeClientRequest(format!(
465 "Invalid token price: {:?}",
466 err
467 ))
468 })
469 })
470 .collect::<Result<Vec<_>, _>>()?;
471 let action = BridgeAction::AddTokensOnIotaAction(AddTokensOnIotaAction {
472 chain_id,
473 nonce,
474 native,
475 token_ids,
476 token_type_names,
477 token_prices,
478 });
479 let sig: Json<SignedBridgeAction> = handler.handle_governance_action(action).await?;
480 Ok(sig)
481 };
482 with_metrics!(metrics.clone(), "handle_add_tokens_on_iota", future).await
483}
484
485#[instrument(level = "error", skip_all, fields(chain_id=chain_id, nonce=nonce, native=native, token_ids=token_ids, token_addresses=token_addresses, token_iota_decimals=token_iota_decimals, token_prices=token_prices))]
486async fn handle_add_tokens_on_evm(
487 Path((chain_id, nonce, native, token_ids, token_addresses, token_iota_decimals, token_prices)): Path<(
488 u8,
489 u64,
490 u8,
491 String,
492 String,
493 String,
494 String,
495 )>,
496 State((handler, metrics, _metadata)): State<(
497 Arc<impl BridgeRequestHandlerTrait + Sync + Send>,
498 Arc<BridgeMetrics>,
499 Arc<BridgeNodePublicMetadata>,
500 )>,
501) -> Result<Json<SignedBridgeAction>, BridgeError> {
502 let future = async {
503 let chain_id = BridgeChainId::try_from(chain_id).map_err(|err| {
504 BridgeError::InvalidBridgeClientRequest(format!("Invalid chain id: {:?}", err))
505 })?;
506 if chain_id.is_iota_chain() {
507 return Err(BridgeError::InvalidBridgeClientRequest(
508 "handle_add_tokens_on_evm does not expect IOTA chain id".to_string(),
509 ));
510 }
511
512 let native = match native {
513 1 => true,
514 0 => false,
515 _ => {
516 return Err(BridgeError::InvalidBridgeClientRequest(format!(
517 "Invalid native flag: {}",
518 native
519 )));
520 }
521 };
522 let token_ids = token_ids
523 .split(',')
524 .map(|s| {
525 s.parse::<u8>().map_err(|err| {
526 BridgeError::InvalidBridgeClientRequest(format!("Invalid token id: {:?}", err))
527 })
528 })
529 .collect::<Result<Vec<_>, _>>()?;
530 let token_addresses = token_addresses
531 .split(',')
532 .map(|s| {
533 EthAddress::from_str(s).map_err(|err| {
534 BridgeError::InvalidBridgeClientRequest(format!(
535 "Invalid token address: {:?}",
536 err
537 ))
538 })
539 })
540 .collect::<Result<Vec<_>, _>>()?;
541 let token_iota_decimals = token_iota_decimals
542 .split(',')
543 .map(|s| {
544 s.parse::<u8>().map_err(|err| {
545 BridgeError::InvalidBridgeClientRequest(format!(
546 "Invalid token iota decimals: {:?}",
547 err
548 ))
549 })
550 })
551 .collect::<Result<Vec<_>, _>>()?;
552 let token_prices = token_prices
553 .split(',')
554 .map(|s| {
555 s.parse::<u64>().map_err(|err| {
556 BridgeError::InvalidBridgeClientRequest(format!(
557 "Invalid token price: {:?}",
558 err
559 ))
560 })
561 })
562 .collect::<Result<Vec<_>, _>>()?;
563 let action = BridgeAction::AddTokensOnEvmAction(AddTokensOnEvmAction {
564 chain_id,
565 nonce,
566 native,
567 token_ids,
568 token_addresses,
569 token_iota_decimals,
570 token_prices,
571 });
572 let sig: Json<SignedBridgeAction> = handler.handle_governance_action(action).await?;
573 Ok(sig)
574 };
575 with_metrics!(metrics.clone(), "handle_add_tokens_on_evm", future).await
576}
577
578#[macro_export]
579macro_rules! with_metrics {
580 ($metrics:expr, $type_:expr, $func:expr) => {
581 async move {
582 info!("Received {} request", $type_);
583 $metrics
584 .requests_received
585 .with_label_values(&[$type_])
586 .inc();
587 $metrics
588 .requests_inflight
589 .with_label_values(&[$type_])
590 .inc();
591
592 let result = $func.await;
593
594 match &result {
595 Ok(_) => {
596 info!("{} request succeeded", $type_);
597 $metrics.requests_ok.with_label_values(&[$type_]).inc();
598 }
599 Err(e) => {
600 info!("{} request failed: {:?}", $type_, e);
601 $metrics.err_requests.with_label_values(&[$type_]).inc();
602 }
603 }
604
605 $metrics
606 .requests_inflight
607 .with_label_values(&[$type_])
608 .dec();
609 result
610 }
611 };
612}
613
614#[cfg(test)]
615mod tests {
616 use iota_types::bridge::TOKEN_ID_BTC;
617
618 use super::*;
619 use crate::{
620 client::bridge_client::BridgeClient, server::mock_handler::BridgeRequestMockHandler,
621 test_utils::get_test_authorities_and_run_mock_bridge_server, types::BridgeCommittee,
622 };
623
624 #[tokio::test]
625 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
626 async fn test_bridge_server_handle_blocklist_update_action_path() {
627 let client = setup();
628
629 let pub_key_bytes = BridgeAuthorityPublicKeyBytes::from_bytes(
630 &Hex::decode("02321ede33d2c2d7a8a152f275a1484edef2098f034121a602cb7d767d38680aa4")
631 .unwrap(),
632 )
633 .unwrap();
634 let action = BridgeAction::BlocklistCommitteeAction(BlocklistCommitteeAction {
635 nonce: 129,
636 chain_id: BridgeChainId::IotaCustom,
637 blocklist_type: BlocklistType::Blocklist,
638 members_to_update: vec![pub_key_bytes.clone()],
639 });
640 client.request_sign_bridge_action(action).await.unwrap();
641 }
642
643 #[tokio::test]
644 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
645 async fn test_bridge_server_handle_emergency_action_path() {
646 let client = setup();
647
648 let action = BridgeAction::EmergencyAction(EmergencyAction {
649 nonce: 55,
650 chain_id: BridgeChainId::IotaCustom,
651 action_type: EmergencyActionType::Pause,
652 });
653 client.request_sign_bridge_action(action).await.unwrap();
654 }
655
656 #[tokio::test]
657 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
658 async fn test_bridge_server_handle_limit_update_action_path() {
659 let client = setup();
660
661 let action = BridgeAction::LimitUpdateAction(LimitUpdateAction {
662 nonce: 15,
663 chain_id: BridgeChainId::IotaCustom,
664 sending_chain_id: BridgeChainId::EthCustom,
665 new_usd_limit: 1_000_000_0000, });
667 client.request_sign_bridge_action(action).await.unwrap();
668 }
669
670 #[tokio::test]
671 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
672 async fn test_bridge_server_handle_asset_price_update_action_path() {
673 let client = setup();
674
675 let action = BridgeAction::AssetPriceUpdateAction(AssetPriceUpdateAction {
676 nonce: 266,
677 chain_id: BridgeChainId::IotaCustom,
678 token_id: TOKEN_ID_BTC,
679 new_usd_price: 100_000_0000, });
681 client.request_sign_bridge_action(action).await.unwrap();
682 }
683
684 #[tokio::test]
685 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
686 async fn test_bridge_server_handle_evm_contract_upgrade_action_path() {
687 let client = setup();
688
689 let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction {
690 nonce: 123,
691 chain_id: BridgeChainId::EthCustom,
692 proxy_address: EthAddress::repeat_byte(6),
693 new_impl_address: EthAddress::repeat_byte(9),
694 call_data: vec![],
695 });
696 client.request_sign_bridge_action(action).await.unwrap();
697
698 let action = BridgeAction::EvmContractUpgradeAction(EvmContractUpgradeAction {
699 nonce: 123,
700 chain_id: BridgeChainId::EthCustom,
701 proxy_address: EthAddress::repeat_byte(6),
702 new_impl_address: EthAddress::repeat_byte(9),
703 call_data: vec![12, 34, 56],
704 });
705 client.request_sign_bridge_action(action).await.unwrap();
706 }
707
708 #[tokio::test]
709 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
710 async fn test_bridge_server_handle_add_tokens_on_iota_action_path() {
711 let client = setup();
712
713 let action = BridgeAction::AddTokensOnIotaAction(AddTokensOnIotaAction {
714 nonce: 266,
715 chain_id: BridgeChainId::IotaCustom,
716 native: false,
717 token_ids: vec![100, 101, 102],
718 token_type_names: vec![
719 TypeTag::from_str("0x0000000000000000000000000000000000000000000000000000000000000abc::my_coin::MyCoin1").unwrap(),
720 TypeTag::from_str("0x0000000000000000000000000000000000000000000000000000000000000abc::my_coin::MyCoin2").unwrap(),
721 TypeTag::from_str("0x0000000000000000000000000000000000000000000000000000000000000abc::my_coin::MyCoin3").unwrap(),
722 ],
723 token_prices: vec![100_000_0000, 200_000_0000, 300_000_0000],
724 });
725 client.request_sign_bridge_action(action).await.unwrap();
726 }
727
728 #[tokio::test]
729 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
730 async fn test_bridge_server_handle_add_tokens_on_evm_action_path() {
731 let client = setup();
732
733 let action = BridgeAction::AddTokensOnEvmAction(crate::types::AddTokensOnEvmAction {
734 nonce: 0,
735 chain_id: BridgeChainId::EthCustom,
736 native: false,
737 token_ids: vec![99, 100, 101],
738 token_addresses: vec![
739 EthAddress::repeat_byte(1),
740 EthAddress::repeat_byte(2),
741 EthAddress::repeat_byte(3),
742 ],
743 token_iota_decimals: vec![5, 6, 7],
744 token_prices: vec![1_000_000_000, 2_000_000_000, 3_000_000_000],
745 });
746 client.request_sign_bridge_action(action).await.unwrap();
747 }
748
749 fn setup() -> BridgeClient {
750 let mock = BridgeRequestMockHandler::new();
751 let (_handles, authorities, mut secrets) =
752 get_test_authorities_and_run_mock_bridge_server(vec![10000], vec![mock.clone()]);
753 mock.set_signer(secrets.swap_remove(0));
754 let committee = BridgeCommittee::new(authorities).unwrap();
755 let pub_key = committee.members().keys().next().unwrap();
756 BridgeClient::new(pub_key.clone(), Arc::new(committee)).unwrap()
757 }
758}