1use std::error::Error;
2use std::str::FromStr;
3use rust_decimal::Decimal;
4use serde::{Deserialize, Serialize};
5use serde_json::{json, Value};
6use crate::icon_service::IconService;
7use crate::transaction_builder::TransactionBuilder;
8use crate::utils::helpers::icx_to_hex;
9use crate::wallet::Wallet;
10
11#[derive(Default, Serialize, Deserialize)]
12pub struct IRC2 {
13 icon_service: IconService,
14 contract_address: String,
15}
16
17impl IRC2 {
18 pub fn new(icon_service: IconService, contract_address: String) -> Self {
19 Self {
20 icon_service,
21 contract_address,
22 }
23 }
24
25 pub async fn name(&self) -> Result<Value, Box<dyn Error>> {
26 let transaction = TransactionBuilder::new(&self.icon_service)
27 .method("icx_call")
28 .to(&self.contract_address)
29 .call(
30 json!({
31 "method": "name",
32 })
33 )
34 .build();
35
36 let response: Value = transaction.send().await.map_err(|e| Box::new(e) as Box<dyn Error>)?;
37
38 Ok(response)
39 }
40
41 pub async fn symbol(&self) -> Result<Value, Box<dyn Error>> {
42 let transaction = TransactionBuilder::new(&self.icon_service)
43 .method("icx_call")
44 .to(&self.contract_address)
45 .call(
46 json!({
47 "method": "symbol",
48 })
49 )
50 .build();
51
52 let response: Value = transaction.send().await.map_err(|e| Box::new(e) as Box<dyn Error>)?;
53
54 Ok(response)
55 }
56
57 pub async fn decimals(&self) -> Result<Value, Box<dyn Error>> {
58 let transaction = TransactionBuilder::new(&self.icon_service)
59 .method("icx_call")
60 .to(&self.contract_address)
61 .call(
62 json!({
63 "method": "decimals",
64 })
65 )
66 .build();
67
68 let response: Value = transaction.send().await.map_err(|e| Box::new(e) as Box<dyn Error>)?;
69
70 Ok(response)
71 }
72
73 pub async fn total_supply(&self) -> Result<Value, Box<dyn Error>> {
74 let transaction = TransactionBuilder::new(&self.icon_service)
75 .method("icx_call")
76 .to(&self.contract_address)
77 .call(
78 json!({
79 "method": "totalSupply",
80 })
81 )
82 .build();
83
84 let response: Value = transaction.send().await.map_err(|e| Box::new(e) as Box<dyn Error>)?;
85
86 Ok(response)
87 }
88
89 pub async fn balance_of(&self, account: String) -> Result<Value, Box<dyn Error>> {
90 let transaction = TransactionBuilder::new(&self.icon_service)
91 .method("icx_call")
92 .to(&self.contract_address)
93 .call(
94 json!({
95 "method": "balanceOf",
96 "params": {
97 "_owner": account,
98 }
99 })
100 )
101 .build();
102
103 let response: Value = transaction.send().await.map_err(|e| Box::new(e) as Box<dyn Error>)?;
104
105 Ok(response)
106 }
107
108 pub async fn transfer(&self, wallet: Wallet, to: &str, value: &str, version: &str, nid: &str, nonce: &str, step_limit: &str) -> Result<Value, Box<dyn Error>> {
109 let mut parsed_value = value.to_string();
110
111 if !parsed_value.starts_with("0x") {
112 match icx_to_hex(Decimal::from_str(value).expect("Invalid value")) {
113 Some(v) => {
114 parsed_value = v;
115 }
116 None => panic!("Failed to convert value to hex"),
117 }
118 }
119
120 let transaction = TransactionBuilder::new(&self.icon_service)
121 .method("icx_sendTransaction")
122 .from(wallet.get_public_address().as_str())
123 .to(&self.contract_address)
124 .version(version)
125 .nid(nid)
126 .timestamp()
127 .nonce(nonce)
128 .step_limit(step_limit)
129 .call(
130 json!({
131 "method": "transfer",
132 "params": {
133 "_to": to,
134 "_value": parsed_value,
135 }
136 })
137 )
138 .sign(wallet.get_private_key().as_str())
139 .build();
140
141 let response: Value = transaction.send().await.map_err(|e| Box::new(e) as Box<dyn Error>)?;
142
143 Ok(response)
144 }
145
146}