ic_papi_guard/guards/
patron_pays_icrc2_tokens.rs1use super::{PaymentError, PaymentGuardTrait};
3use candid::{Nat, Principal};
4use ic_cycles_ledger_client::TransferFromArgs;
5use ic_papi_api::{caller::TokenAmount, principal2account, Account};
6
7pub struct PatronPaysIcrc2TokensPaymentGuard {
10 pub ledger: Principal,
12 pub patron: Account,
14}
15
16impl PaymentGuardTrait for PatronPaysIcrc2TokensPaymentGuard {
17 async fn deduct(&self, cost: TokenAmount) -> Result<(), PaymentError> {
18 let caller = ic_cdk::api::caller();
19 let own_canister_id = ic_cdk::api::id();
20 let spender_subaccount = principal2account(&caller);
21 if self.patron.owner == own_canister_id {
23 return Err(PaymentError::InvalidPatron);
24 }
25 ic_cycles_ledger_client::Service(self.ledger)
27 .icrc_2_transfer_from(&TransferFromArgs {
28 from: self.patron.clone(),
29 to: Account {
30 owner: ic_cdk::api::id(),
31 subaccount: None,
32 },
33 amount: Nat::from(cost),
34 spender_subaccount: Some(spender_subaccount),
35 created_at_time: None,
36 memo: None,
37 fee: None,
38 })
39 .await
40 .map_err(|(rejection_code, string)| {
41 eprintln!(
42 "Failed to reach ledger canister at {}: {rejection_code:?}: {string}",
43 self.ledger
44 );
45 PaymentError::LedgerUnreachable {
46 ledger: self.ledger,
47 }
48 })?
49 .0
50 .map_err(|error| {
51 eprintln!(
52 "Failed to withdraw from ledger canister at {}: {error:?}",
53 self.ledger
54 );
55 PaymentError::LedgerTransferFromError {
56 ledger: self.ledger,
57 error,
58 }
59 })
60 .map(|_| ())
61 }
62}