use std::str::FromStr;
use crate::currency::Currency;
use miden_client::{Felt, Word, ZERO};
#[derive(Debug, Clone)]
pub struct Pair {
pub base: Currency,
pub quote: Currency,
}
impl Pair {
pub fn new(base: Currency, quote: Currency) -> Self {
Self { base, quote }
}
pub fn encode(&self) -> Option<u32> {
let base_encoded = self.base.encode()?;
let quote_encoded = self.quote.encode()?;
Some(base_encoded | (quote_encoded << 15))
}
pub fn to_word(&self) -> Word {
[ZERO, ZERO, ZERO, self.try_into().unwrap()]
}
}
impl TryFrom<Pair> for Felt {
type Error = anyhow::Error;
fn try_from(value: Pair) -> anyhow::Result<Self> {
let encoded = value
.encode()
.ok_or_else(|| anyhow::anyhow!("Invalid asset pair format"))?;
let value = u64::from(encoded);
Ok(Felt::new(value))
}
}
impl TryFrom<&Pair> for Felt {
type Error = anyhow::Error;
fn try_from(value: &Pair) -> anyhow::Result<Self> {
let encoded = value
.encode()
.ok_or_else(|| anyhow::anyhow!("Invalid asset pair format"))?;
let value = u64::from(encoded);
Ok(Felt::new(value))
}
}
impl FromStr for Pair {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split('/').collect();
if parts.len() != 2 {
return Err(anyhow::anyhow!("Invalid pair format. Expected BASE/QUOTE"));
}
let base = Currency::from_str(parts[0])?;
let quote = Currency::from_str(parts[1])?;
Ok(Pair::new(base, quote))
}
}
impl From<Felt> for Pair {
fn from(felt: Felt) -> Self {
let value = felt.as_int() as u32;
let base_encoded = value & 0x7FFF; let quote_encoded = (value >> 15) & 0x7FFF;
let base = decode_currency(base_encoded).unwrap();
let quote = decode_currency(quote_encoded).unwrap();
let base_currency = Currency::new(&base).unwrap();
let quote_currency = Currency::new("e).unwrap();
Pair::new(base_currency, quote_currency)
}
}
fn decode_currency(encoded: u32) -> Option<String> {
let mut result = String::new();
let mut remaining = encoded;
for _ in 0..3 {
if remaining == 0 {
break;
}
let char_value = remaining & 0x1F; if char_value >= 26 {
return None;
}
let decoded_char = char::from_u32('A' as u32 + char_value)?;
result.push(decoded_char);
remaining >>= 5;
}
if result.is_empty() {
None
} else {
Some(result)
}
}
impl std::fmt::Display for Pair {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}/{}", self.base.0, self.quote.0)
}
}