elrond_rust/
transaction.rs1use serde::Serialize;
4use super::{Account, ElrondAddress, ElrondClientError, Result};
5use bigdecimal::BigDecimal;
6use std::str::FromStr;
7
8pub enum Network {
10 MainNet,
11 Custom(String)
12}
13
14impl Network {
15 pub fn chain_id(&self) -> String {
17 match self {
18 Network::MainNet => "1".to_string(),
19 Network::Custom(s) => s.clone()
20 }
21 }
22}
23
24#[derive(Clone, Debug, PartialEq)]
26pub struct ElrondCurrencyAmount {
27 inner: String
28}
29
30impl ElrondCurrencyAmount {
31 pub fn new(amount: &str) -> Result<Self> {
33 let amount = BigDecimal::from_str(amount).map_err(|_| {
34 ElrondClientError::new("could not parse amount as bigdecimal")
35 })?;
36 let multiplier = BigDecimal::from_str("1000000000000000000").unwrap(); let converted_amount = (amount * multiplier).with_scale(0);
38 let inner = format!("{}", converted_amount);
39 Ok(Self { inner })
40 }
41 pub fn from_blockchain_precision(blockchain_amount: &str) -> Result<Self> {
43 let amount = BigDecimal::from_str(blockchain_amount).map_err(|_| {
44 ElrondClientError::new("could not parse amount as bigdecimal")
45 })?;
46 let divisor = BigDecimal::from_str("1000000000000000000").unwrap(); let converted_amount = amount / divisor;
48 let inner = format!("{}", converted_amount);
49 Ok(Self { inner })
50 }
51 pub fn to_string(&self) -> String {
53 self.inner.clone()
54 }
55}
56
57#[derive(Clone, Debug, Serialize)]
59#[serde(rename_all = "camelCase")]
60pub struct UnsignedTransaction{
61 nonce: u64,
62 value: String,
63 receiver: String,
64 sender: String,
65 gas_price: u64,
66 gas_limit: u64,
67 chain_ID: String,
69 version: u64
70}
71
72impl UnsignedTransaction {
73 pub fn new(
75 nonce: u64,
76 value: &str,
77 receiver: &str,
78 sender: &str,
79 network: Network,
80 ) -> Result<Self> {
81 Ok(Self {
82 nonce,
83 value: ElrondCurrencyAmount::new(value)?.to_string(),
84 receiver: ElrondAddress::new(receiver)?.to_string(),
85 sender: ElrondAddress::new(sender)?.to_string(),
86 gas_price: 1000000000,
87 gas_limit: 50000,
88 chain_ID: network.chain_id(),
89 version: 1
90 })
91 }
92 pub fn serialize(&self) -> Result<String> {
94 serde_json::to_string(self).map_err(|_| {
95 ElrondClientError::new("could not serialize unsigned transaction")
96 })
97 }
98 pub fn sign(&self, account: &Account) -> Result<SignedTransaction> {
100 let serialized_tx = self.serialize()?;
101 let signature = account.sign(&serialized_tx)?;
102 Ok(SignedTransaction {
103 nonce: self.nonce,
104 value: self.value.clone(),
105 receiver: self.receiver.clone(),
106 sender: self.sender.clone(),
107 gas_price: self.gas_price,
108 gas_limit: self.gas_limit,
109 chain_ID: self.chain_ID.clone(),
110 version: self.version,
111 data: "".to_string(),
113 signature
114 })
115 }
116}
117
118#[derive(Clone, Debug, Serialize)]
121#[serde(rename_all = "camelCase")]
122pub struct SignedTransaction{
123 nonce: u64,
124 value: String,
125 receiver: String,
126 sender: String,
127 gas_price: u64,
128 gas_limit: u64,
129 data: String,
130 chain_ID: String,
132 version: u64,
133 signature: String
134}
135
136impl SignedTransaction {
137 pub fn serialize(&self) -> Result<String> {
138 serde_json::to_string(self).map_err(|_| {
139 ElrondClientError::new("could not serialize signed transaction")
140 })
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::{UnsignedTransaction, Network, ElrondCurrencyAmount};
147 use super::super::account::Account;
148 #[test]
149 fn create_serialize_and_sign_tx(){
150 let private_key = "a4b36a5d97176618b5a7fcc9228d2fd98ee2f14ddd3d6462ae03e40eb487d15b";
151 let account = Account::from_string(private_key).unwrap();
152 let tx = UnsignedTransaction::new(
153 0,
154 "0.001",
155 "erd16jats393r8rnut88yhvu5wvxxje57qzlj3tqk7n6jnf7f6cxs4uqfeh65k",
156 &account.address.to_string(),
157 Network::MainNet
158 ).unwrap();
159 let signed_tx = tx.sign(&account).unwrap();
160 let serialized_correct = "{\"nonce\":0,\"value\":\"1000000000000000\",\"receiver\":\"erd16jats393r8rnut88yhvu5wvxxje57qzlj3tqk7n6jnf7f6cxs4uqfeh65k\",\"sender\":\"erd146apxa83wr7paz3gsg07dhcpg98ascjtpg9p8l8g5rpmg6chhchq9ccvmc\",\"gasPrice\":1000000000,\"gasLimit\":50000,\"data\":\"\",\"chainID\":\"1\",\"version\":1,\"signature\":\"78b7a59aeb9ff1a51637e23f29e0e22528a92a3508d69479806af93114496977ee1eacf045146fdbae89efd2cd3d9e0bcb2c52406515fa0548e2873554a0ac0d\"}";
161 assert_eq!(serialized_correct, signed_tx.serialize().unwrap());
162 }
163
164 #[test]
165 fn test_currency_precision(){
166 let amount = ElrondCurrencyAmount::new("0.001").unwrap();
167 assert_eq!(amount.to_string(), "1000000000000000")
168 }
169}