icrc_ledger_client/
lib.rs1use async_trait::async_trait;
2use candid::Principal;
3use candid::types::number::Nat;
4use candid::utils::{ArgumentDecoder, ArgumentEncoder};
5use icrc_ledger_types::icrc::generic_metadata_value::MetadataValue as Value;
6use icrc_ledger_types::icrc::metadata_key::MetadataKey;
7use icrc_ledger_types::icrc1::account::Account;
8use icrc_ledger_types::icrc1::transfer::{BlockIndex, TransferArg, TransferError};
9use icrc_ledger_types::icrc2::approve::{ApproveArgs, ApproveError};
10use icrc_ledger_types::icrc2::transfer_from::{TransferFromArgs, TransferFromError};
11
12#[async_trait]
15pub trait Runtime {
16 async fn call<In, Out>(
17 &self,
18 id: Principal,
19 method: &str,
20 args: In,
21 ) -> Result<Out, (i32, String)>
22 where
23 In: ArgumentEncoder + Send,
24 Out: for<'a> ArgumentDecoder<'a>;
25}
26
27pub struct ICRC1Client<R: Runtime> {
28 pub runtime: R,
29 pub ledger_canister_id: Principal,
30}
31
32impl<R: Runtime> ICRC1Client<R> {
38 pub async fn balance_of(&self, account: Account) -> Result<Nat, (i32, String)> {
39 self.runtime
40 .call(self.ledger_canister_id, "icrc1_balance_of", (account,))
41 .await
42 .map(untuple)
43 }
44
45 pub async fn decimals(&self) -> Result<u8, (i32, String)> {
46 self.runtime
47 .call(self.ledger_canister_id, "icrc1_decimals", ())
48 .await
49 .map(untuple)
50 }
51
52 pub async fn name(&self) -> Result<String, (i32, String)> {
53 self.runtime
54 .call(self.ledger_canister_id, "icrc1_name", ())
55 .await
56 .map(untuple)
57 }
58
59 pub async fn metadata(&self) -> Result<Vec<(MetadataKey, Value)>, (i32, String)> {
60 self.runtime
61 .call(self.ledger_canister_id, "icrc1_metadata", ())
62 .await
63 .map(untuple)
64 }
65
66 pub async fn symbol(&self) -> Result<String, (i32, String)> {
67 self.runtime
68 .call(self.ledger_canister_id, "icrc1_symbol", ())
69 .await
70 .map(untuple)
71 }
72
73 pub async fn total_supply(&self) -> Result<Nat, (i32, String)> {
74 self.runtime
75 .call(self.ledger_canister_id, "icrc1_total_supply", ())
76 .await
77 .map(untuple)
78 }
79
80 pub async fn fee(&self) -> Result<Nat, (i32, String)> {
81 self.runtime
82 .call(self.ledger_canister_id, "icrc1_fee", ())
83 .await
84 .map(untuple)
85 }
86
87 pub async fn minting_account(&self) -> Result<Option<Account>, (i32, String)> {
88 self.runtime
89 .call(self.ledger_canister_id, "icrc1_minting_account", ())
90 .await
91 .map(untuple)
92 }
93
94 pub async fn transfer(
95 &self,
96 args: TransferArg,
97 ) -> Result<Result<BlockIndex, TransferError>, (i32, String)> {
98 let result: Result<Nat, TransferError> = self
99 .runtime
100 .call(self.ledger_canister_id, "icrc1_transfer", (args,))
101 .await
102 .map(untuple)?;
103 Ok(result)
104 }
105
106 pub async fn transfer_from(
107 &self,
108 args: TransferFromArgs,
109 ) -> Result<Result<BlockIndex, TransferFromError>, (i32, String)> {
110 let result: Result<Nat, TransferFromError> = self
111 .runtime
112 .call(self.ledger_canister_id, "icrc2_transfer_from", (args,))
113 .await
114 .map(untuple)?;
115 Ok(result)
116 }
117
118 pub async fn approve(
119 &self,
120 args: ApproveArgs,
121 ) -> Result<Result<BlockIndex, ApproveError>, (i32, String)> {
122 let result: Result<Nat, ApproveError> = self
123 .runtime
124 .call(self.ledger_canister_id, "icrc2_approve", (args,))
125 .await
126 .map(untuple)?;
127 Ok(result)
128 }
129}
130
131fn untuple<T>(t: (T,)) -> T {
133 t.0
134}