use std::fmt::{self, Debug};
use alloy_primitives::U256;
use clickhouse::Row;
use colored::Colorize;
use malachite::Rational;
use redefined::Redefined;
use reth_primitives::Address;
use rkyv::{Archive, Deserialize as rDeserialize, Serialize as rSerialize};
use serde::{Deserialize, Serialize};
use super::accounting::{apply_delta, AddressDeltas, TokenAccounting};
pub use super::{Action, NormalizedSwap};
use crate::{
db::{
redefined_types::{malachite::RationalRedefined, primitives::*},
token_info::{TokenInfoWithAddress, TokenInfoWithAddressRedefined},
},
rational_to_u256_fraction, Protocol,
};
#[derive(Default, Debug, Serialize, Clone, Row, PartialEq, Eq, Deserialize, Redefined)]
#[redefined_attr(derive(Debug, PartialEq, Clone, Serialize, rSerialize, rDeserialize, Archive))]
pub struct NormalizedLiquidation {
#[redefined(same_fields)]
pub protocol: Protocol,
pub trace_index: u64,
pub pool: Address,
pub liquidator: Address,
pub debtor: Address,
pub collateral_asset: TokenInfoWithAddress,
pub debt_asset: TokenInfoWithAddress,
pub covered_debt: Rational,
pub liquidated_collateral: Rational,
pub msg_value: U256,
}
impl TokenAccounting for NormalizedLiquidation {
fn apply_token_deltas(&self, delta_map: &mut AddressDeltas) {
let debt_covered = self.covered_debt.clone();
apply_delta(self.pool, self.debt_asset.address, debt_covered.clone(), delta_map);
apply_delta(
self.pool,
self.collateral_asset.address,
-self.liquidated_collateral.clone(),
delta_map,
);
apply_delta(
self.liquidator,
self.collateral_asset.address,
self.liquidated_collateral.clone(),
delta_map,
)
}
}
impl fmt::Display for NormalizedLiquidation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let protocol = self.protocol.to_string().bold();
let pool_address = format!("{}", self.pool).cyan();
let liquidator_address = format!("{}", self.liquidator).cyan();
let debtor_address = format!("{}", self.debtor).cyan();
let collateral_asset_symbol = self.collateral_asset.inner.symbol.bold();
let debt_asset_symbol = self.debt_asset.inner.symbol.bold();
let covered_debt_formatted = format!("{:.4}", self.covered_debt).green();
let liquidated_collateral_formatted = format!("{:.4}", self.liquidated_collateral).red();
write!(
f,
"Protocol {} - Pool: {}, Liquidator: {}, Debtor: {}, Collateral: {}, Debt: {}, \
Covered Debt: {}, Liquidated Collateral: {}",
protocol,
pool_address,
liquidator_address,
debtor_address,
collateral_asset_symbol,
debt_asset_symbol,
covered_debt_formatted,
liquidated_collateral_formatted
)
}
}
impl NormalizedLiquidation {
pub fn pretty_print(&self, f: &mut fmt::Formatter<'_>, spaces: usize) -> fmt::Result {
let field_names = [
"Protocol",
"Pool",
"Liquidator",
"Debtor",
"Collateral",
"Debt",
"Covered Debt",
"Liquidated Collateral",
];
let max_field_name_length = field_names.iter().map(|name| name.len()).max().unwrap_or(0);
let indent = " ".repeat(spaces);
let protocol = self.protocol.to_string().bright_yellow();
let pool_address = format!("{}", self.pool).bright_yellow();
let liquidator_address = format!("{}", self.liquidator).bright_yellow();
let debtor_address = format!("{}", self.debtor).bright_yellow();
let collateral_asset_symbol = self.collateral_asset.inner.symbol.clone().bright_yellow();
let debt_asset_symbol = self.debt_asset.inner.symbol.clone().bright_yellow();
let covered_debt_formatted = format!("{:.4}", self.covered_debt).bright_yellow();
let liquidated_collateral_formatted =
format!("{:.4}", self.liquidated_collateral).bright_yellow();
writeln!(
f,
"{indent}{:width$}: {}\n{indent}{:width$}: {}\n{indent}{:width$}: \
{}\n{indent}{:width$}: {}\n{indent}{:width$}: {}\n{indent}{:width$}: \
{}\n{indent}{:width$}: {}\n{indent}{:width$}: {}",
"Protocol",
protocol,
"Pool",
pool_address,
"Liquidator",
liquidator_address,
"Debtor",
debtor_address,
"Collateral",
collateral_asset_symbol,
"Debt",
debt_asset_symbol,
"Covered Debt",
covered_debt_formatted,
"Liquidated Collateral",
liquidated_collateral_formatted,
indent = indent,
width = max_field_name_length + spaces + 1
)?;
Ok(())
}
}
pub struct ClickhouseVecNormalizedLiquidation {
pub trace_index: Vec<u64>,
pub pool: Vec<String>,
pub liquidator: Vec<String>,
pub debtor: Vec<String>,
pub collateral_asset: Vec<(String, String)>,
pub debt_asset: Vec<(String, String)>,
pub covered_debt: Vec<([u8; 32], [u8; 32])>,
pub liquidated_collateral: Vec<([u8; 32], [u8; 32])>,
}
impl TryFrom<Vec<NormalizedLiquidation>> for ClickhouseVecNormalizedLiquidation {
type Error = eyre::Report;
fn try_from(value: Vec<NormalizedLiquidation>) -> eyre::Result<Self> {
Ok(ClickhouseVecNormalizedLiquidation {
trace_index: value.iter().map(|val| val.trace_index).collect(),
pool: value.iter().map(|val| format!("{:?}", val.pool)).collect(),
liquidator: value
.iter()
.map(|val| format!("{:?}", val.liquidator))
.collect(),
debtor: value
.iter()
.map(|val| format!("{:?}", val.debtor))
.collect(),
collateral_asset: value
.iter()
.map(|val| val.collateral_asset.clickhouse_fmt())
.collect(),
debt_asset: value
.iter()
.map(|val| val.debt_asset.clickhouse_fmt())
.collect(),
covered_debt: value
.iter()
.map(|val| rational_to_u256_fraction(&val.covered_debt))
.collect::<eyre::Result<Vec<_>>>()?,
liquidated_collateral: value
.iter()
.map(|val| rational_to_u256_fraction(&val.liquidated_collateral))
.collect::<eyre::Result<Vec<_>>>()?,
})
}
}