neo3/neo_contract/traits/
fungible_token.rs1use crate::{
2 builder::{AccountSigner, TransactionBuilder},
3 neo_clients::JsonRpcProvider,
4 neo_contract::{ContractError, FungibleTokenContract, TokenTrait},
5 neo_protocol::{Account, AccountTrait},
6 neo_wallets::Wallet,
7 Bytes, ContractParameter, NNSName, ScriptHash,
8};
9use async_trait::async_trait;
10use primitive_types::H160;
11
12#[async_trait]
13pub trait FungibleTokenTrait<'a, P: JsonRpcProvider>: TokenTrait<'a, P> {
14 const BALANCE_OF: &'static str = "balanceOf";
15 const TRANSFER: &'static str = "transfer";
16
17 async fn get_balance_of(&self, script_hash: &ScriptHash) -> Result<i32, ContractError> {
18 self.get_balance_of_hash160(script_hash).await
19 }
20
21 async fn get_balance_of_hash160(&self, script_hash: &H160) -> Result<i32, ContractError> {
22 self.call_function_returning_int(Self::BALANCE_OF, vec![script_hash.into()])
23 .await
24 }
25
26 async fn get_total_balance(&self, wallet: &Wallet) -> Result<i32, ContractError> {
27 let mut sum = 0;
28 for (_, account) in &wallet.accounts {
29 sum += self
30 .get_balance_of(&account.address_or_scripthash().script_hash())
31 .await
32 .unwrap();
33 }
34 Ok(sum)
35 }
36
37 async fn transfer_from_account(
38 &self,
39 from: &Account,
40 to: &ScriptHash,
41 amount: i32,
42 data: Option<ContractParameter>,
43 ) -> Result<TransactionBuilder<P>, ContractError> {
44 let mut builder = self
45 .transfer_from_hash160(&from.address_or_scripthash().script_hash(), to, amount, data)
46 .await?;
47 builder.set_signers(vec![AccountSigner::called_by_entry(from).unwrap().into()]);
48
49 Ok(builder)
50 }
51
52 async fn transfer_from_hash160(
53 &self,
54 from: &ScriptHash,
55 to: &ScriptHash,
56 amount: i32,
57 data: Option<ContractParameter>,
58 ) -> Result<TransactionBuilder<P>, ContractError> {
59 if amount < 0 {
60 return Err(ContractError::InvalidArgError(
61 "The amount must be greater than or equal to 0.".to_string(),
62 ));
63 }
64
65 let transfer_script = self.build_transfer_script(from, to, amount, data).await.unwrap();
66 let mut builder = TransactionBuilder::new();
67 builder.set_script(Some(transfer_script));
68 Ok(builder)
69 }
70
71 async fn build_transfer_script(
72 &self,
73 from: &ScriptHash,
74 to: &ScriptHash,
75 amount: i32,
76 data: Option<ContractParameter>,
77 ) -> Result<Bytes, ContractError> {
78 self.build_invoke_function_script(
79 <FungibleTokenContract<P> as FungibleTokenTrait<P>>::TRANSFER,
80 vec![from.into(), to.into(), amount.into(), data.unwrap()],
81 )
82 .await
83 }
84
85 async fn transfer_from_account_to_nns(
88 &self,
89 from: &Account,
90 to: &NNSName,
91 amount: i32,
92 data: Option<ContractParameter>,
93 ) -> Result<TransactionBuilder<P>, ContractError> {
94 let mut builder = self
95 .transfer_from_hash160_to_nns(&from.get_script_hash(), to, amount, data)
96 .await
97 .unwrap();
98 builder.set_signers(vec![AccountSigner::called_by_entry(from).unwrap().into()]);
99
100 Ok(builder)
101 }
102
103 async fn transfer_from_hash160_to_nns(
104 &self,
105 from: &ScriptHash,
106 to: &NNSName,
107 amount: i32,
108 data: Option<ContractParameter>,
109 ) -> Result<TransactionBuilder<P>, ContractError> {
110 let script_hash = self.resolve_nns_text_record(to).await.unwrap();
111 self.transfer_from_hash160(from, &script_hash, amount, data).await
112 }
113}