#![allow(dead_code)]
use crate::{
cdk::{
env::ck::{CKUSDC_LEDGER_CANISTER, CKUSDT_LEDGER_CANISTER},
spec::standards::icrc::icrc2::{
Allowance, AllowanceArgs, TransferFromArgs, TransferFromError, TransferFromResult,
},
types::{Account, Principal},
},
infra::{
InfraError,
ic::{IcInfraError, call::Call},
},
};
use thiserror::Error as ThisError;
#[derive(Debug, ThisError)]
pub enum LedgerInfraError {
#[error("{symbol} icrc2_transfer_from rejected: {error:?}")]
TransferFromRejected {
symbol: &'static str,
error: TransferFromError,
},
}
impl From<LedgerInfraError> for InfraError {
fn from(err: LedgerInfraError) -> Self {
IcInfraError::LedgerInfra(err).into()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LedgerMeta {
pub symbol: &'static str,
pub decimals: u8,
pub is_known: bool,
}
pub struct LedgerInfra;
impl LedgerInfra {
#[must_use]
pub fn ledger_meta(ledger_id: Principal) -> LedgerMeta {
if ledger_id == *CKUSDC_LEDGER_CANISTER {
return LedgerMeta {
symbol: "ckUSDC",
decimals: 6,
is_known: true,
};
}
if ledger_id == *CKUSDT_LEDGER_CANISTER {
return LedgerMeta {
symbol: "ckUSDT",
decimals: 6,
is_known: true,
};
}
LedgerMeta {
symbol: "UNKNOWN",
decimals: 6,
is_known: false,
}
}
pub async fn icrc2_allowance(
ledger_id: Principal,
account: Account,
spender: Account,
) -> Result<Allowance, InfraError> {
let args = AllowanceArgs { account, spender };
let allowance: Allowance = Call::unbounded_wait(ledger_id, "icrc2_allowance")
.with_arg(args)?
.execute()
.await?
.candid()?;
Ok(allowance)
}
pub async fn icrc2_transfer_from(
ledger_id: Principal,
args: TransferFromArgs,
) -> Result<TransferFromResult, InfraError> {
let result: TransferFromResult = Call::unbounded_wait(ledger_id, "icrc2_transfer_from")
.with_arg(args)?
.execute()
.await?
.candid()?;
match result {
TransferFromResult::Ok(_) => Ok(result),
TransferFromResult::Err(err) => Err(LedgerInfraError::TransferFromRejected {
symbol: Self::ledger_meta(ledger_id).symbol,
error: err,
}
.into()),
}
}
}