pub mod compliance;
pub mod conservation;
pub mod evaluate;
pub mod fold;
pub mod pools;
pub mod resolve;
pub mod transition;
pub use compliance::{disposal_compliance, ComplianceStatus, DisposalCompliance};
pub use conservation::{conservation_report, ConservationReport};
pub use evaluate::{evaluate_disposal, CandidateDisposal, EvaluateError, EvaluateOutcome};
pub use resolve::{PseudoDefault, PseudoKind};
use crate::event::LedgerEvent;
use crate::price::PriceProvider;
use crate::state::LedgerState;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FeeTreatment {
TreatmentC,
TreatmentB,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
pub enum LotMethod {
#[default]
Fifo,
Lifo,
Hifo,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ProjectionConfig {
pub self_transfer_fee: FeeTreatment,
pub pre2025_method: LotMethod,
pub pre2025_method_attested: bool,
pub pseudo_reconcile: bool,
}
impl Default for ProjectionConfig {
fn default() -> Self {
ProjectionConfig {
self_transfer_fee: FeeTreatment::TreatmentC,
pre2025_method: LotMethod::Hifo,
pre2025_method_attested: false,
pseudo_reconcile: false,
}
}
}
pub fn project(
events: &[LedgerEvent],
prices: &dyn PriceProvider,
config: &ProjectionConfig,
) -> LedgerState {
let resolution = resolve::resolve(events, prices, config);
fold::fold(resolution, prices, config)
}
pub fn pseudo_plan(
events: &[LedgerEvent],
prices: &dyn PriceProvider,
config: &ProjectionConfig,
) -> Vec<PseudoDefault> {
let mut cfg = *config;
cfg.pseudo_reconcile = true;
resolve::resolve(events, prices, &cfg).pseudo_decisions
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InForceMethod {
pub method: LotMethod,
pub scoped: bool,
}
pub fn in_force_methods(
events: &[LedgerEvent],
prices: &dyn PriceProvider,
config: &ProjectionConfig,
date: crate::conventions::TaxDate,
wallets: &[crate::identity::WalletId],
) -> Vec<InForceMethod> {
let res = resolve::resolve(events, prices, config);
wallets
.iter()
.map(|w| {
if date < crate::conventions::TRANSITION_DATE {
InForceMethod {
method: config.pre2025_method,
scoped: false,
}
} else {
match resolve::resolve_election(date, w, &res.elections) {
Some(e) => InForceMethod {
method: e.method,
scoped: e.wallet.is_some(),
},
None => InForceMethod {
method: LotMethod::Hifo,
scoped: false,
},
}
}
})
.collect()
}