use crate::client::evm::chain::NATIVE_DECIMALS;
use crate::client::evm::tx::Call;
use crate::client::evm::u256::{BadAmount, U256};
use crate::transfer::erc20;
use crate::utils::{Address, Dec};
pub use crate::transfer::system::{HYPE_SYSTEM, is_system_address, system_address};
pub use crate::transfer::system_token;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Linked {
pub index: u64,
pub contract: Option<Address>,
pub wei_decimals: u32,
pub evm_extra_wei_decimals: i32,
}
impl Linked {
#[must_use]
pub const fn hype(wei_decimals: u32) -> Linked {
Linked { index: 0, contract: None, wei_decimals, evm_extra_wei_decimals: 0 }
}
#[must_use]
pub const fn erc20(index: u64, contract: Address, wei_decimals: u32, evm_extra_wei_decimals: i32) -> Linked {
Linked { index, contract: Some(contract), wei_decimals, evm_extra_wei_decimals }
}
#[must_use]
pub fn system(&self) -> Address {
match self.contract {
None => HYPE_SYSTEM,
Some(_) => system_address(self.index),
}
}
#[must_use]
pub fn evm_decimals(&self) -> Option<u32> {
match self.contract {
None => Some(NATIVE_DECIMALS),
Some(_) => u32::try_from(i64::from(self.wei_decimals) + i64::from(self.evm_extra_wei_decimals)).ok(),
}
}
#[must_use]
pub fn core_places(&self) -> Option<u32> {
self.evm_decimals().map(|evm| evm.min(self.wei_decimals))
}
pub fn to_core(&self, amount: Dec) -> Result<Call, BadAmount> {
let places = self.core_places().ok_or(BadAmount::TooLarge)?;
let decimals = self.evm_decimals().ok_or(BadAmount::TooLarge)?;
if !amount.is_positive() {
return Err(BadAmount::NotPositive(amount));
}
if amount.places() > places {
return Err(BadAmount::TooFine { value: amount, decimals: places });
}
let units = U256::from_dec(amount, decimals)?;
Ok(match self.contract {
None => Call { to: Some(HYPE_SYSTEM), value: units, data: Vec::new() },
Some(contract) => {
Call { to: Some(contract), value: U256::ZERO, data: erc20::transfer(self.system(), units) }
}
})
}
}
#[cfg(test)]
#[path = "tests/link.rs"]
mod tests;