From adc22e1035cc8b2f373e9627174f103ba6ec4dde Mon Sep 17 00:00:00 2001 From: longbowlu Date: Tue, 28 May 2024 22:35:25 -0700 Subject: [PATCH] add PrintBridgeCommitteeInfo subcommand and more governance command --- crates/sui-bridge-cli/src/lib.rs | 95 ++++++++++++++++++++++++++++--- crates/sui-bridge-cli/src/main.rs | 88 +++++++++++++++++++++++++--- 2 files changed, 168 insertions(+), 15 deletions(-) diff --git a/crates/sui-bridge-cli/src/lib.rs b/crates/sui-bridge-cli/src/lib.rs index 485ea13cdf7cf..4258d12ffab54 100644 --- a/crates/sui-bridge-cli/src/lib.rs +++ b/crates/sui-bridge-cli/src/lib.rs @@ -16,14 +16,16 @@ use shared_crypto::intent::IntentMessage; use std::path::PathBuf; use std::str::FromStr; use std::sync::Arc; +use sui_bridge::abi::EthBridgeCommittee; use sui_bridge::abi::{eth_sui_bridge, EthSuiBridge}; use sui_bridge::crypto::BridgeAuthorityPublicKeyBytes; use sui_bridge::error::BridgeResult; use sui_bridge::sui_client::SuiBridgeClient; use sui_bridge::types::BridgeAction; use sui_bridge::types::{ - AssetPriceUpdateAction, BlocklistCommitteeAction, BlocklistType, EmergencyAction, - EmergencyActionType, EvmContractUpgradeAction, LimitUpdateAction, + AddTokensOnEvmAction, AddTokensOnSuiAction, AssetPriceUpdateAction, BlocklistCommitteeAction, + BlocklistType, EmergencyAction, EmergencyActionType, EvmContractUpgradeAction, + LimitUpdateAction, }; use sui_bridge::utils::{get_eth_signer_client, EthSigner}; use sui_config::Config; @@ -96,6 +98,12 @@ pub enum BridgeCommand { #[clap(long = "sui-rpc-url")] sui_rpc_url: String, }, + /// Print current committee info + #[clap(name = "print-bridge-committee-info")] + PrintBridgeCommitteeInfo { + #[clap(long = "sui-rpc-url")] + sui_rpc_url: String, + }, /// Client to facilitate and execute Bridge actions #[clap(name = "client")] Client { @@ -123,7 +131,7 @@ pub enum GovernanceClientCommands { nonce: u64, #[clap(name = "blocklist-type", long)] blocklist_type: BlocklistType, - #[clap(name = "pubkey-hex", long)] + #[clap(name = "pubkey-hex", use_value_delimiter = true, long)] pubkeys_hex: Vec, }, #[clap(name = "update-limit")] @@ -144,6 +152,30 @@ pub enum GovernanceClientCommands { #[clap(name = "new-usd-price", long)] new_usd_price: u64, }, + #[clap(name = "add-tokens-on-sui")] + AddTokensOnSui { + #[clap(name = "nonce", long)] + nonce: u64, + #[clap(name = "token-ids", use_value_delimiter = true, long)] + token_ids: Vec, + #[clap(name = "token-type-names", use_value_delimiter = true, long)] + token_type_names: Vec, + #[clap(name = "token-prices", use_value_delimiter = true, long)] + token_prices: Vec, + }, + #[clap(name = "add-tokens-on-evm")] + AddTokensOnEvm { + #[clap(name = "nonce", long)] + nonce: u64, + #[clap(name = "token-ids", use_value_delimiter = true, long)] + token_ids: Vec, + #[clap(name = "token-type-names", use_value_delimiter = true, long)] + token_addresses: Vec, + #[clap(name = "token-prices", use_value_delimiter = true, long)] + token_prices: Vec, + #[clap(name = "token-sui-decimals", use_value_delimiter = true, long)] + token_sui_decimals: Vec, + }, #[clap(name = "upgrade-evm-contract")] UpgradeEVMContract { #[clap(name = "nonce", long)] @@ -157,7 +189,7 @@ pub enum GovernanceClientCommands { #[clap(name = "function-selector", long)] function_selector: String, /// Params to be passed to the function, e.g. `420,false,hello` - #[clap(name = "params", long)] + #[clap(name = "params", use_value_delimiter = true, long)] params: Vec, }, } @@ -205,6 +237,43 @@ pub fn make_action(chain_id: BridgeChainId, cmd: &GovernanceClientCommands) -> B token_id: *token_id, new_usd_price: *new_usd_price, }), + GovernanceClientCommands::AddTokensOnSui { + nonce, + token_ids, + token_type_names, + token_prices, + } => { + assert_eq!(token_ids.len(), token_type_names.len()); + assert_eq!(token_ids.len(), token_prices.len()); + BridgeAction::AddTokensOnSuiAction(AddTokensOnSuiAction { + nonce: *nonce, + chain_id, + native: false, // only foreign tokens are supported now + token_ids: token_ids.clone(), + token_type_names: token_type_names.clone(), + token_prices: token_prices.clone(), + }) + } + GovernanceClientCommands::AddTokensOnEvm { + nonce, + token_ids, + token_addresses, + token_prices, + token_sui_decimals, + } => { + assert_eq!(token_ids.len(), token_addresses.len()); + assert_eq!(token_ids.len(), token_prices.len()); + assert_eq!(token_ids.len(), token_sui_decimals.len()); + BridgeAction::AddTokensOnEvmAction(AddTokensOnEvmAction { + nonce: *nonce, + native: true, // only eth native tokens are supported now + chain_id, + token_ids: token_ids.clone(), + token_addresses: token_addresses.clone(), + token_prices: token_prices.clone(), + token_sui_decimals: token_sui_decimals.clone(), + }) + } GovernanceClientCommands::UpgradeEVMContract { nonce, proxy_address, @@ -274,10 +343,10 @@ pub fn select_contract_address( config.eth_bridge_committee_proxy_address } GovernanceClientCommands::UpdateLimit { .. } => config.eth_bridge_limiter_proxy_address, - GovernanceClientCommands::UpdateAssetPrice { .. } => { - config.eth_bridge_limiter_proxy_address - } + GovernanceClientCommands::UpdateAssetPrice { .. } => config.eth_bridge_config_proxy_address, GovernanceClientCommands::UpgradeEVMContract { proxy_address, .. } => *proxy_address, + GovernanceClientCommands::AddTokensOnSui { .. } => unreachable!(), + GovernanceClientCommands::AddTokensOnEvm { .. } => config.eth_bridge_config_proxy_address, } } @@ -313,6 +382,8 @@ pub struct LoadedBridgeCliConfig { pub eth_bridge_proxy_address: EthAddress, /// Proxy address for BridgeCommittee deployed on Eth pub eth_bridge_committee_proxy_address: EthAddress, + /// Proxy address for BridgeConfig deployed on Eth + pub eth_bridge_config_proxy_address: EthAddress, /// Proxy address for BridgeLimiter deployed on Eth pub eth_bridge_limiter_proxy_address: EthAddress, /// Key pair for Sui operations @@ -365,6 +436,10 @@ impl LoadedBridgeCliConfig { let sui_bridge = EthSuiBridge::new(cli_config.eth_bridge_proxy_address, provider.clone()); let eth_bridge_committee_proxy_address: EthAddress = sui_bridge.committee().call().await?; let eth_bridge_limiter_proxy_address: EthAddress = sui_bridge.limiter().call().await?; + let eth_committee = + EthBridgeCommittee::new(eth_bridge_committee_proxy_address, provider.clone()); + let eth_bridge_committee_proxy_address: EthAddress = sui_bridge.committee().call().await?; + let eth_bridge_config_proxy_address: EthAddress = eth_committee.config().call().await?; let eth_address = eth_signer.address(); let eth_chain_id = provider.get_chainid().await?; @@ -379,6 +454,7 @@ impl LoadedBridgeCliConfig { eth_bridge_proxy_address: cli_config.eth_bridge_proxy_address, eth_bridge_committee_proxy_address, eth_bridge_limiter_proxy_address, + eth_bridge_config_proxy_address, sui_key, eth_signer, }) @@ -407,7 +483,10 @@ impl LoadedBridgeCliConfig { let gas = gases .into_iter() .find(|coin| coin.balance >= 5_000_000_000) - .ok_or(anyhow!("Did not find gas object with enough balance"))?; + .ok_or(anyhow!( + "Did not find gas object with enough balance for {}", + sui_client_address + ))?; println!("Using Gas object: {}", gas.coin_object_id); Ok((self.sui_key.copy(), sui_client_address, gas.object_ref())) } diff --git a/crates/sui-bridge-cli/src/main.rs b/crates/sui-bridge-cli/src/main.rs index abfcba21ec321..86c511cfdd0ed 100644 --- a/crates/sui-bridge-cli/src/main.rs +++ b/crates/sui-bridge-cli/src/main.rs @@ -9,7 +9,7 @@ use std::collections::HashMap; use std::str::from_utf8; use std::sync::Arc; use sui_bridge::client::bridge_authority_aggregator::BridgeAuthorityAggregator; -use sui_bridge::crypto::BridgeAuthorityPublicKey; +use sui_bridge::crypto::{BridgeAuthorityPublicKey, BridgeAuthorityPublicKeyBytes}; use sui_bridge::eth_transaction_builder::build_eth_transaction; use sui_bridge::sui_client::SuiClient; use sui_bridge::sui_transaction_builder::build_sui_transaction; @@ -26,7 +26,7 @@ use sui_config::Config; use sui_sdk::SuiClient as SuiSdkClient; use sui_sdk::SuiClientBuilder; use sui_types::bridge::BridgeChainId; -use sui_types::bridge::MoveTypeCommitteeMemberRegistration; +use sui_types::bridge::{MoveTypeCommitteeMember, MoveTypeCommitteeMemberRegistration}; use sui_types::committee::TOTAL_VOTING_POWER; use sui_types::crypto::AuthorityPublicKeyBytes; use sui_types::crypto::Signature; @@ -237,6 +237,7 @@ async fn main() -> anyhow::Result<()> { ); continue; }; + let eth_address = BridgeAuthorityPublicKeyBytes::from(&pubkey).to_eth_address(); let Ok(base_url) = from_utf8(&http_rest_url) else { println!( "Invalid bridge http url for validator: {}: {:?}", @@ -248,24 +249,97 @@ async fn main() -> anyhow::Result<()> { let (protocol_key, name) = names.get(&sui_address).unwrap(); let stake = stakes.get(protocol_key).unwrap(); - authorities.push((name, sui_address, pubkey, base_url, stake)); + authorities.push((name, sui_address, pubkey, eth_address, base_url, stake)); } let total_stake = authorities .iter() - .map(|(_, _, _, _, stake)| **stake) + .map(|(_, _, _, _, _, stake)| **stake) .sum::(); println!( "Total registered stake: {}%", total_stake as f32 / TOTAL_VOTING_POWER as f32 * 100.0 ); - for (name, sui_address, pubkey, base_url, stake) in authorities { + println!("Name, Sui Address, Eth Address, Pubkey, Base URL, Stake"); + for (name, sui_address, pubkey, eth_address, base_url, stake) in authorities { println!( - "Name: {}, Sui Address: {}, Bridge Authority Pubkey: {}, Bridge Node URL: {}, Stake: {}", - name, sui_address, pubkey, base_url, stake + "{}, {}, {}, {}, {}, {}", + name, sui_address, eth_address, pubkey, base_url, stake ); } } + BridgeCommand::PrintBridgeCommitteeInfo { sui_rpc_url } => { + let sui_bridge_client = SuiClient::::new(&sui_rpc_url).await?; + let bridge_summary = sui_bridge_client + .get_bridge_summary() + .await + .map_err(|e| anyhow::anyhow!("Failed to get bridge summary: {:?}", e))?; + let move_type_bridge_committee = bridge_summary.committee; + let sui_client = SuiClientBuilder::default().build(sui_rpc_url).await?; + let names = sui_client + .governance_api() + .get_latest_sui_system_state() + .await? + .active_validators + .into_iter() + .map(|summary| (summary.sui_address, summary.name)) + .collect::>(); + let mut authorities = vec![]; + for (_, member) in move_type_bridge_committee.members { + let MoveTypeCommitteeMember { + sui_address, + bridge_pubkey_bytes, + voting_power, + http_rest_url, + blocklisted, + } = member; + let Ok(pubkey) = BridgeAuthorityPublicKey::from_bytes(&bridge_pubkey_bytes) else { + println!( + "Invalid bridge pubkey for validator {}: {:?}", + sui_address, bridge_pubkey_bytes + ); + continue; + }; + let eth_address = BridgeAuthorityPublicKeyBytes::from(&pubkey).to_eth_address(); + let Ok(base_url) = from_utf8(&http_rest_url) else { + println!( + "Invalid bridge http url for validator: {}: {:?}", + sui_address, http_rest_url + ); + continue; + }; + let base_url = base_url.to_string(); + + let name = names.get(&sui_address).unwrap(); + authorities.push(( + name, + sui_address, + pubkey, + eth_address, + base_url, + voting_power, + blocklisted, + )); + } + let total_stake = authorities + .iter() + .map(|(_, _, _, _, _, stake, _)| *stake) + .sum::(); + println!( + "Total stake (static): {}%", + total_stake as f32 / TOTAL_VOTING_POWER as f32 * 100.0 + ); + + println!("Name, Sui Address, Eth Address, Pubkey, Base URL, Stake, Blocklisted"); + for (name, sui_address, pubkey, eth_address, base_url, stake, blocklisted) in + authorities + { + println!( + "{}, {}, 0x{:x}, {}, {}, {}, {}", + name, sui_address, eth_address, pubkey, base_url, stake, blocklisted + ); + } + } BridgeCommand::Client { config_path, cmd } => { let config = BridgeCliConfig::load(config_path).expect("Couldn't load BridgeCliConfig"); let config = LoadedBridgeCliConfig::load(config).await?;