use crate::{
InternalError,
cdk::spec::standards::icrc::icrc2::{Allowance, TransferFromArgs, TransferFromResult},
infra::{InfraError, ic::ledger::LedgerInfra},
ops::{ic::IcOpsError, prelude::*},
};
use thiserror::Error as ThisError;
#[derive(Debug, ThisError)]
pub enum LedgerOpsError {
#[error(transparent)]
Infra(#[from] InfraError),
}
impl From<LedgerOpsError> for InternalError {
fn from(err: LedgerOpsError) -> Self {
IcOpsError::from(err).into()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LedgerMeta {
pub symbol: &'static str,
pub decimals: u8,
pub is_known: bool,
}
pub struct LedgerOps;
impl LedgerOps {
#[must_use]
pub fn ledger_meta(ledger_id: Principal) -> LedgerMeta {
let meta = LedgerInfra::ledger_meta(ledger_id);
LedgerMeta {
symbol: meta.symbol,
decimals: meta.decimals,
is_known: meta.is_known,
}
}
pub async fn allowance(
ledger_id: Principal,
payer: Account,
spender: Account,
) -> Result<Allowance, InternalError> {
let allowance = LedgerInfra::icrc2_allowance(ledger_id, payer, spender)
.await
.map_err(LedgerOpsError::from)?;
Ok(allowance)
}
pub async fn transfer_from(
ledger_id: Principal,
from: Principal,
to: Account,
amount: u64,
memo: Option<Vec<u8>>,
) -> Result<u64, InternalError> {
let from_account = Account {
owner: from,
subaccount: None,
};
let args = TransferFromArgs {
from: from_account,
to,
amount,
memo,
created_at_time: Some(crate::cdk::api::time()),
};
let result: TransferFromResult = LedgerInfra::icrc2_transfer_from(ledger_id, args)
.await
.map_err(LedgerOpsError::from)?;
match result {
TransferFromResult::Ok(block_index) => Ok(block_index),
TransferFromResult::Err(_) => {
unreachable!()
}
}
}
}