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 51329ae commit 5dde6ff
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 63 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
68 changes: 50 additions & 18 deletions crates/sui-bridge-watchdog/eth_vault_balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,56 +12,88 @@ 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) {
match self
let balance: Result<U256> = self
.coin_contract
.balance_of(self.vault_address)
.call()
.await
{
.await;
match balance {
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 normalized_balance: U256 = match self.decimals.checked_sub(8) {
// In this case, there are more decimals than needed, so we need to
// remove trailing decimals.
Some(delta) if delta > 0 => balance
.checked_div(U256::from(10).pow(U256::from(delta)))
.expect("Division by zero should be impossible here"),
// In this case, there are fewer decimals than needed, so we need to
// add zeroes.
None => {
let delta = 8 - self.decimals;
balance
.checked_mul(U256::from(10).pow(U256::from(delta)))
.expect("Integer overflow")
}
// in this case, the token contract has the target precision
// so we don't need to do anything.
Some(_) => balance,
};
self.metric.set(normalized_balance.as_u128() as i64);

info!("{:?} Vault Balance: {:?}", self.asset, normalized_balance,);
}
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
74 changes: 54 additions & 20 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,56 +12,90 @@ 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) {
match self
let balance: Result<
U256,
ethers::contract::ContractError<Provider<MeteredEthHttpProvier>>,
> = self
.coin_contract
.balance_of(self.vault_address)
.call()
.await
{
.await;
match balance {
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 normalized_balance: U256 = match self.decimals.checked_sub(8) {
// In this case, there are more decimals than needed, so we need to
// remove trailing decimals.
Some(delta) if delta > 0 => balance
.checked_div(U256::from(10).pow(U256::from(delta)))
.expect("Division by zero should be impossible here"),
// In this case, there are fewer decimals than needed, so we need to
// add zeroes.
None => {
let delta = 8 - self.decimals;
balance
.checked_mul(U256::from(10).pow(U256::from(delta)))
.expect("Integer overflow")
}
// in this case, the token contract has the target precision
// so we don't need to do anything.
Some(_) => balance,
};
self.metric.set(normalized_balance.as_u128() as i64);

info!("{:?} Vault Balance: {:?}", self.asset, normalized_balance,);
}
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
Loading

0 comments on commit 5dde6ff

Please sign in to comment.