Skip to content

Commit

Permalink
[Native Bridge] Support other vault balances
Browse files Browse the repository at this point in the history
  • Loading branch information
williampsmith committed Nov 27, 2024
1 parent a139ef2 commit 10e65a3
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 47 deletions.
34 changes: 28 additions & 6 deletions crates/sui-bridge-indexer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ use mysten_metrics::start_prometheus_server;

use sui_bridge::metrics::BridgeMetrics;
use sui_bridge::sui_bridge_watchdog::{
eth_bridge_status::EthBridgeStatus, eth_vault_balance::EthVaultBalance,
metrics::WatchdogMetrics, sui_bridge_status::SuiBridgeStatus, BridgeWatchDog,
eth_bridge_status::EthBridgeStatus,
eth_vault_balance::{EthereumVaultBalance, VaultAsset},
metrics::WatchdogMetrics,
sui_bridge_status::SuiBridgeStatus,
BridgeWatchDog,
};
use sui_bridge_indexer::config::IndexerConfig;
use sui_bridge_indexer::metrics::BridgeIndexerMetrics;
Expand Down Expand Up @@ -143,15 +146,33 @@ async fn start_watchdog(
let watchdog_metrics = WatchdogMetrics::new(registry);
let eth_provider =
Arc::new(new_metered_eth_provider(&config.eth_rpc_url, bridge_metrics.clone()).unwrap());
let (_committee_address, _limiter_address, vault_address, _config_address, weth_address) =
get_eth_contract_addresses(eth_bridge_proxy_address, &eth_provider).await?;
let (
_committee_address,
_limiter_address,
vault_address,
_config_address,
weth_address,
usdt_address,
) = get_eth_contract_addresses(eth_bridge_proxy_address, &eth_provider).await?;

let eth_vault_balance = EthVaultBalance::new(
let eth_vault_balance = EthereumVaultBalance::new(
eth_provider.clone(),
vault_address,
weth_address,
VaultAsset::WETH,
watchdog_metrics.eth_vault_balance.clone(),
);
)
.await
.unwrap_or_else(|e| panic!("Failed to create eth vault balance: {}", e));
let usdt_vault_balance = EthereumVaultBalance::new(
eth_provider.clone(),
vault_address,
usdt_address,
VaultAsset::USDT,
watchdog_metrics.usdt_vault_balance.clone(),
)
.await
.unwrap_or_else(|e| panic!("Failed to create usdt vault balance: {}", e));

let eth_bridge_status = EthBridgeStatus::new(
eth_provider,
Expand All @@ -163,6 +184,7 @@ async fn start_watchdog(
SuiBridgeStatus::new(sui_client, watchdog_metrics.sui_bridge_paused.clone());
let observables: Vec<Box<dyn Observable + Send + Sync>> = vec![
Box::new(eth_vault_balance),
Box::new(usdt_vault_balance),
Box::new(eth_bridge_status),
Box::new(sui_bridge_status),
];
Expand Down
48 changes: 33 additions & 15 deletions crates/sui-bridge-watchdog/eth_vault_balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,48 @@ use sui_bridge::metered_eth_provider::MeteredEthHttpProvier;
use tokio::time::Duration;
use tracing::{error, info};

const TEN_ZEROS: u64 = 10_u64.pow(10);
#[derive(Debug)]
pub enum VaultAsset {
WETH,
USDT,
}

pub struct EthVaultBalance {
pub struct EthereumVaultBalance {
coin_contract: EthERC20<Provider<MeteredEthHttpProvier>>,
asset: VaultAsset,
decimals: u8,
vault_address: EthAddress,
ten_zeros: U256,
metric: IntGauge,
}

impl EthVaultBalance {
impl EthereumVaultBalance {
pub fn new(
provider: Arc<Provider<MeteredEthHttpProvier>>,
vault_address: EthAddress,
coin_address: EthAddress, // for now this only support one coin which is WETH
asset: VaultAsset,
metric: IntGauge,
) -> Self {
let ten_zeros = U256::from(TEN_ZEROS);
) -> anyhow::Result<Self> {
let coin_contract = EthERC20::new(coin_address, provider);
Self {
let decimals = coin_contract
.decimals()
.call()
.await
.map_err(|e| anyhow::anyhow!("Failed to get decimals from token contract: {e}"))?;
Ok(Self {
coin_contract,
vault_address,
ten_zeros,
decimals,
asset,
metric,
}
})
}
}

#[async_trait]
impl Observable for EthVaultBalance {
impl Observable for EthereumVaultBalance {
fn name(&self) -> &str {
"EthVaultBalance"
"EthereumVaultBalance"
}

async fn observe_and_report(&self) {
Expand All @@ -55,13 +66,20 @@ impl Observable for EthVaultBalance {
Ok(balance) => {
// Why downcasting is safe:
// 1. On Ethereum we only take the first 8 decimals into account,
// meaning the trailing 10 digits can be ignored
// meaning the trailing 10 digits can be ignored. For other assets,
// we will also assume this max level of precision for metrics purposes.
// 2. i64::MAX is 9_223_372_036_854_775_807, with 8 decimal places is
// 92_233_720_368. We likely won't see any balance higher than this
// in the next 12 months.
let balance = (balance / self.ten_zeros).as_u64() as i64;
self.metric.set(balance);
info!("Eth Vault Balance: {:?}", balance);
// For USDT, for example, this will be 10^6 - 8 = 10^(-2) = 0.01,
// therefore we will add 2 zeroes of precision.
let denom = U256::from(10).pow(self.decimals - 8);
let normalized_balance = (balance / denom).as_u64() as i64;
self.metric.set(normalized_balance);
info!(
"{:?} Vault Balance: {:?} ({:?} {:?})",
self.asset, balance, normalized_balance, self.asset,
);
}
Err(e) => {
error!("Error getting balance from vault: {:?}", e);
Expand Down
10 changes: 8 additions & 2 deletions crates/sui-bridge/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,14 @@ impl BridgeNodeConfig {
.interval(std::time::Duration::from_millis(2000)),
);
let chain_id = provider.get_chainid().await?;
let (committee_address, limiter_address, vault_address, config_address, _weth_address) =
get_eth_contract_addresses(bridge_proxy_address, &provider).await?;
let (
committee_address,
limiter_address,
vault_address,
config_address,
_weth_address,
_usdt_address,
) = get_eth_contract_addresses(bridge_proxy_address, &provider).await?;
let config = EthBridgeConfig::new(config_address, provider.clone());

if self.run_client && self.eth.eth_contracts_start_block_fallback.is_none() {
Expand Down
33 changes: 26 additions & 7 deletions crates/sui-bridge/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::config::WatchdogConfig;
use crate::crypto::BridgeAuthorityPublicKeyBytes;
use crate::metered_eth_provider::MeteredEthHttpProvier;
use crate::sui_bridge_watchdog::eth_bridge_status::EthBridgeStatus;
use crate::sui_bridge_watchdog::eth_vault_balance::EthVaultBalance;
use crate::sui_bridge_watchdog::eth_vault_balance::{EthereumVaultBalance, VaultAsset};
use crate::sui_bridge_watchdog::metrics::WatchdogMetrics;
use crate::sui_bridge_watchdog::sui_bridge_status::SuiBridgeStatus;
use crate::sui_bridge_watchdog::total_supplies::TotalSupplies;
Expand Down Expand Up @@ -158,17 +158,35 @@ async fn start_watchdog(
sui_client: Arc<SuiBridgeClient>,
) {
let watchdog_metrics = WatchdogMetrics::new(registry);
let (_committee_address, _limiter_address, vault_address, _config_address, weth_address) =
get_eth_contract_addresses(eth_bridge_proxy_address, &eth_provider)
.await
.unwrap_or_else(|e| panic!("get_eth_contract_addresses should not fail: {}", e));
let (
_committee_address,
_limiter_address,
vault_address,
_config_address,
weth_address,
usdt_address,
) = get_eth_contract_addresses(eth_bridge_proxy_address, &eth_provider)
.await
.unwrap_or_else(|e| panic!("get_eth_contract_addresses should not fail: {}", e));

let eth_vault_balance = EthVaultBalance::new(
let eth_vault_balance = EthereumVaultBalance::new(
eth_provider.clone(),
vault_address,
weth_address,
VaultAsset::WETH,
watchdog_metrics.eth_vault_balance.clone(),
);
)
.await
.unwrap_or_else(|e| panic!("Failed to create eth vault balance: {}", e));
let usdt_vault_balance = EthereumVaultBalance::new(
eth_provider.clone(),
vault_address,
usdt_address,
VaultAsset::USDT,
watchdog_metrics.usdt_vault_balance.clone(),
)
.await
.unwrap_or_else(|e| panic!("Failed to create usdt vault balance: {}", e));

let eth_bridge_status = EthBridgeStatus::new(
eth_provider,
Expand All @@ -183,6 +201,7 @@ async fn start_watchdog(

let mut observables: Vec<Box<dyn Observable + Send + Sync>> = vec![
Box::new(eth_vault_balance),
Box::new(usdt_vault_balance),
Box::new(eth_bridge_status),
Box::new(sui_bridge_status),
];
Expand Down
50 changes: 34 additions & 16 deletions crates/sui-bridge/src/sui_bridge_watchdog/eth_vault_balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,48 @@ use std::sync::Arc;
use tokio::time::Duration;
use tracing::{error, info};

const TEN_ZEROS: u64 = 10_u64.pow(10);
#[derive(Debug)]
pub enum VaultAsset {
WETH,
USDT,
}

pub struct EthVaultBalance {
pub struct EthereumVaultBalance {
coin_contract: EthERC20<Provider<MeteredEthHttpProvier>>,
asset: VaultAsset,
decimals: u8,
vault_address: EthAddress,
ten_zeros: U256,
metric: IntGauge,
}

impl EthVaultBalance {
pub fn new(
impl EthereumVaultBalance {
pub async fn new(
provider: Arc<Provider<MeteredEthHttpProvier>>,
vault_address: EthAddress,
coin_address: EthAddress, // for now this only support one coin which is WETH
asset: VaultAsset,
metric: IntGauge,
) -> Self {
let ten_zeros = U256::from(TEN_ZEROS);
) -> anyhow::Result<Self> {
let coin_contract = EthERC20::new(coin_address, provider);
Self {
let decimals = coin_contract
.decimals()
.call()
.await
.map_err(|e| anyhow::anyhow!("Failed to get decimals from token contract: {e}"))?;
Ok(Self {
coin_contract,
vault_address,
ten_zeros,
decimals,
asset,
metric,
}
})
}
}

#[async_trait]
impl Observable for EthVaultBalance {
impl Observable for EthereumVaultBalance {
fn name(&self) -> &str {
"EthVaultBalance"
"EthereumVaultBalance"
}

async fn observe_and_report(&self) {
Expand All @@ -55,13 +66,20 @@ impl Observable for EthVaultBalance {
Ok(balance) => {
// Why downcasting is safe:
// 1. On Ethereum we only take the first 8 decimals into account,
// meaning the trailing 10 digits can be ignored
// meaning the trailing 10 digits can be ignored. For other assets,
// we will also assume this max level of precision for metrics purposes.
// 2. i64::MAX is 9_223_372_036_854_775_807, with 8 decimal places is
// 92_233_720_368. We likely won't see any balance higher than this
// in the next 12 months.
let balance = (balance / self.ten_zeros).as_u64() as i64;
self.metric.set(balance);
info!("Eth Vault Balance: {:?}", balance);
// For USDT, for example, this will be 10^6 - 8 = 10^(-2) = 0.01,
// therefore we will add 2 zeroes of precision.
let denom = U256::from(10).pow((self.decimals - 8).into());
let normalized_balance = (balance / denom).as_u64() as i64;
self.metric.set(normalized_balance);
info!(
"{:?} Vault Balance: {:?} ({:?} {:?})",
self.asset, balance, normalized_balance, self.asset,
);
}
Err(e) => {
error!("Error getting balance from vault: {:?}", e);
Expand Down
7 changes: 7 additions & 0 deletions crates/sui-bridge/src/sui_bridge_watchdog/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use prometheus::{
#[derive(Clone, Debug)]
pub struct WatchdogMetrics {
pub eth_vault_balance: IntGauge,
pub usdt_vault_balance: IntGauge,
pub total_supplies: IntGaugeVec,
pub eth_bridge_paused: IntGauge,
pub sui_bridge_paused: IntGauge,
Expand All @@ -23,6 +24,12 @@ impl WatchdogMetrics {
registry,
)
.unwrap(),
usdt_vault_balance: register_int_gauge_with_registry!(
"bridge_usdt_vault_balance",
"Current balance of usdt eth vault",
registry,
)
.unwrap(),
total_supplies: register_int_gauge_vec_with_registry!(
"bridge_total_supplies",
"Current total supplies of coins on Sui based on Treasury Cap",
Expand Down
12 changes: 11 additions & 1 deletion crates/sui-bridge/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,22 @@ pub fn generate_bridge_client_key_and_write_to_file(
pub async fn get_eth_contract_addresses<P: ethers::providers::JsonRpcClient + 'static>(
bridge_proxy_address: EthAddress,
provider: &Arc<Provider<P>>,
) -> anyhow::Result<(EthAddress, EthAddress, EthAddress, EthAddress, EthAddress)> {
) -> anyhow::Result<(
EthAddress,
EthAddress,
EthAddress,
EthAddress,
EthAddress,
EthAddress,
)> {
let sui_bridge = EthSuiBridge::new(bridge_proxy_address, provider.clone());
let bridge_config = EthBridgeConfig::new(bridge_proxy_address, provider.clone());
let committee_address: EthAddress = sui_bridge.committee().call().await?;
let limiter_address: EthAddress = sui_bridge.limiter().call().await?;
let vault_address: EthAddress = sui_bridge.vault().call().await?;
let vault = EthBridgeVault::new(vault_address, provider.clone());
let weth_address: EthAddress = vault.w_eth().call().await?;
let usdt_address: EthAddress = bridge_config.token_address_of(4).call().await?;
let committee = EthBridgeCommittee::new(committee_address, provider.clone());
let config_address: EthAddress = committee.config().call().await?;

Expand All @@ -123,6 +132,7 @@ pub async fn get_eth_contract_addresses<P: ethers::providers::JsonRpcClient + 's
vault_address,
config_address,
weth_address,
usdt_address,
))
}

Expand Down

0 comments on commit 10e65a3

Please sign in to comment.