use std::io::{Read, Write};
use crate::crypto::PublicKey;
use crate::error::{Error, Result};
use crate::xdr;
use chrono::{DateTime, Duration, TimeZone, Utc};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClaimableBalanceId(Vec<u8>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Claimant {
destination: PublicKey,
predicate: ClaimPredicate,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClaimPredicate {
Unconditional,
And(Box<ClaimPredicate>, Box<ClaimPredicate>),
Or(Box<ClaimPredicate>, Box<ClaimPredicate>),
Not(Box<ClaimPredicate>),
BeforeAbsoluteTime(DateTime<Utc>),
BeforeRelativeTime(Duration),
}
impl ClaimableBalanceId {
pub fn new(hash: Vec<u8>) -> Result<ClaimableBalanceId> {
if hash.len() != 32 {
Err(Error::InvalidClaimableBalanceIdLength)
} else {
Ok(ClaimableBalanceId(hash))
}
}
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
pub fn to_xdr(&self) -> xdr::ClaimableBalanceId {
let hash = xdr::Hash(self.0.as_slice().try_into().unwrap());
xdr::ClaimableBalanceId::ClaimableBalanceIdTypeV0(hash)
}
pub fn from_xdr(x: &xdr::ClaimableBalanceId) -> Result<ClaimableBalanceId> {
match x {
xdr::ClaimableBalanceId::ClaimableBalanceIdTypeV0(hash) => {
ClaimableBalanceId::new(hash.0.to_vec())
}
}
}
}
impl Claimant {
pub fn new(destination: PublicKey, predicate: ClaimPredicate) -> Claimant {
Claimant {
destination,
predicate,
}
}
pub fn to_xdr(&self) -> Result<xdr::Claimant> {
let destination = self.destination.to_xdr_account_id()?;
let predicate = self.predicate.to_xdr()?;
let inner = xdr::ClaimantV0 {
destination,
predicate,
};
Ok(xdr::Claimant::ClaimantTypeV0(inner))
}
pub fn from_xdr(x: &xdr::Claimant) -> Result<Claimant> {
match x {
xdr::Claimant::ClaimantTypeV0(inner) => {
let destination = PublicKey::from_xdr_account_id(&inner.destination)?;
let predicate = ClaimPredicate::from_xdr(&inner.predicate)?;
Ok(Claimant::new(destination, predicate))
}
}
}
}
impl ClaimPredicate {
pub fn new_unconditional() -> ClaimPredicate {
ClaimPredicate::Unconditional
}
pub fn new_and(p1: ClaimPredicate, p2: ClaimPredicate) -> ClaimPredicate {
ClaimPredicate::And(Box::new(p1), Box::new(p2))
}
pub fn new_or(p1: ClaimPredicate, p2: ClaimPredicate) -> ClaimPredicate {
ClaimPredicate::Or(Box::new(p1), Box::new(p2))
}
pub fn new_not(predicate: ClaimPredicate) -> ClaimPredicate {
ClaimPredicate::Not(Box::new(predicate))
}
pub fn new_before_absolute_time(datetime: DateTime<Utc>) -> ClaimPredicate {
ClaimPredicate::BeforeAbsoluteTime(datetime)
}
pub fn new_before_relative_time(duration: Duration) -> ClaimPredicate {
ClaimPredicate::BeforeRelativeTime(duration)
}
pub fn to_xdr(&self) -> Result<xdr::ClaimPredicate> {
match self {
ClaimPredicate::Unconditional => Ok(xdr::ClaimPredicate::Unconditional),
ClaimPredicate::And(p1, p2) => {
let p1_xdr = p1.to_xdr()?;
let p2_xdr = p2.to_xdr()?;
let predicates = vec![p1_xdr, p2_xdr];
Ok(xdr::ClaimPredicate::And(predicates.try_into().unwrap()))
}
ClaimPredicate::Or(p1, p2) => {
let p1_xdr = p1.to_xdr()?;
let p2_xdr = p2.to_xdr()?;
let predicates = vec![p1_xdr, p2_xdr];
Ok(xdr::ClaimPredicate::Or(predicates.try_into().unwrap()))
}
ClaimPredicate::Not(p) => {
let p_xdr = p.to_xdr()?;
let predicate = Some(Box::new(p_xdr));
Ok(xdr::ClaimPredicate::Not(predicate))
}
ClaimPredicate::BeforeAbsoluteTime(datetime) => {
let time = datetime.timestamp();
Ok(xdr::ClaimPredicate::BeforeAbsoluteTime(time))
}
ClaimPredicate::BeforeRelativeTime(duration) => {
let time = duration.num_seconds();
Ok(xdr::ClaimPredicate::BeforeRelativeTime(time))
}
}
}
pub fn from_xdr(x: &xdr::ClaimPredicate) -> Result<ClaimPredicate> {
match x {
xdr::ClaimPredicate::Unconditional => Ok(ClaimPredicate::new_unconditional()),
xdr::ClaimPredicate::And(predicates) => {
let mut p = predicates.iter();
match (p.next(), p.next()) {
(Some(p1), Some(p2)) => {
let p1 = ClaimPredicate::from_xdr(p1)?;
let p2 = ClaimPredicate::from_xdr(p2)?;
Ok(ClaimPredicate::new_and(p1, p2))
}
_ => Err(Error::XdrClaimPredicateError),
}
}
xdr::ClaimPredicate::Or(predicates) => {
let mut p = predicates.iter();
match (p.next(), p.next()) {
(Some(p1), Some(p2)) => {
let p1 = ClaimPredicate::from_xdr(p1)?;
let p2 = ClaimPredicate::from_xdr(p2)?;
Ok(ClaimPredicate::new_or(p1, p2))
}
_ => Err(Error::XdrClaimPredicateError),
}
}
xdr::ClaimPredicate::Not(predicate) => {
if let Some(predicate) = predicate {
let p = ClaimPredicate::from_xdr(predicate)?;
Ok(ClaimPredicate::new_not(p))
} else {
Err(Error::XdrClaimPredicateError)
}
}
xdr::ClaimPredicate::BeforeAbsoluteTime(time) => {
let datetime = Utc.timestamp_opt(*time, 0).single();
datetime
.map(ClaimPredicate::new_before_absolute_time)
.ok_or(Error::XdrClaimPredicateError)
}
xdr::ClaimPredicate::BeforeRelativeTime(time) => {
let duration = Duration::seconds(*time);
Ok(ClaimPredicate::new_before_relative_time(duration))
}
}
}
}
impl xdr::WriteXdr for Claimant {
fn write_xdr<W: Write>(&self, w: &mut xdr::Limited<W>) -> xdr::Result<()> {
let xdr = self.to_xdr().map_err(|_| xdr::Error::Invalid)?;
xdr.write_xdr(w)
}
}
impl xdr::ReadXdr for Claimant {
fn read_xdr<R: Read>(r: &mut xdr::Limited<R>) -> xdr::Result<Self> {
let xdr_result = xdr::Claimant::read_xdr(r)?;
Self::from_xdr(&xdr_result).map_err(|_| xdr::Error::Invalid)
}
}
impl xdr::WriteXdr for ClaimPredicate {
fn write_xdr<W: Write>(&self, w: &mut xdr::Limited<W>) -> xdr::Result<()> {
let xdr = self.to_xdr().map_err(|_| xdr::Error::Invalid)?;
xdr.write_xdr(w)
}
}
impl xdr::ReadXdr for ClaimPredicate {
fn read_xdr<R: Read>(r: &mut xdr::Limited<R>) -> xdr::Result<Self> {
let xdr_result = xdr::ClaimPredicate::read_xdr(r)?;
Self::from_xdr(&xdr_result).map_err(|_| xdr::Error::Invalid)
}
}