percli 0.2.4

Offline CLI simulator for the Percolator risk engine
use anyhow::Result;
use percli_core::POS_SCALE;
use std::path::Path;

use super::state::{self, Operation};
use crate::format::{self, OutputFormat};
use crate::StepAction;

pub fn run(state_path: &str, action: StepAction, fmt: OutputFormat) -> Result<()> {
    let path = Path::new(state_path);
    let mut state = state::load_or_create(path)?;

    let op = action_to_op(&action);
    state.operations.push(op);

    match &action {
        StepAction::Crank { oracle, slot } => {
            state.oracle_price = *oracle;
            state.slot = *slot;
        }
        StepAction::SetOracle { price } => {
            state.oracle_price = *price;
        }
        StepAction::SetSlot { slot } => {
            state.slot = *slot;
        }
        StepAction::SetFundingRate { rate } => {
            state.funding_rate = *rate;
        }
        _ => {}
    }

    let engine = state::replay(&state)?;
    state::save(path, &state)?;

    let snap = engine.snapshot();
    format::print_snapshot(&snap, fmt)?;

    Ok(())
}

fn action_to_op(action: &StepAction) -> Operation {
    match action {
        StepAction::Deposit { account, amount } => Operation::Deposit {
            account: account.clone(),
            amount: *amount as u64,
        },
        StepAction::Withdraw { account, amount } => Operation::Withdraw {
            account: account.clone(),
            amount: *amount as u64,
        },
        StepAction::Trade {
            long,
            short,
            size,
            price,
        } => Operation::Trade {
            long: long.clone(),
            short: short.clone(),
            size_q: (*size * POS_SCALE as i128) as i64,
            price: *price,
        },
        StepAction::Crank { oracle, slot } => Operation::Crank {
            oracle: *oracle,
            slot: *slot,
        },
        StepAction::Liquidate { account } => Operation::Liquidate {
            account: account.clone(),
        },
        StepAction::Settle { account } => Operation::Settle {
            account: account.clone(),
        },
        StepAction::SetOracle { price } => Operation::SetOracle { price: *price },
        StepAction::SetSlot { slot } => Operation::SetSlot { slot: *slot },
        StepAction::SetFundingRate { rate } => Operation::SetFundingRate { rate: *rate },
    }
}