1use crate::error::Error;
2use crate::Result;
3use bip39::{Language, Mnemonic};
4use ed25519_dalek::{Signature as DalekSignature, Signer, SigningKey, VerifyingKey};
5use rand::{rngs::OsRng, RngCore};
6use rootchain_core::types::{Address, Balance, Signature, Transaction, TransactionType};
7
8pub struct Wallet {
9 signing_key: SigningKey,
10}
11
12impl Wallet {
13 pub fn generate() -> (Self, String) {
14 let mut entropy = [0u8; 16];
15 OsRng.fill_bytes(&mut entropy);
16 let mnemonic = Mnemonic::from_entropy(&entropy).expect("Valid entropy");
17 let phrase = mnemonic.words().collect::<Vec<_>>().join(" ");
18 let wallet = Self::from_mnemonic(&phrase).expect("Valid mnemonic just generated");
19 (wallet, phrase)
20 }
21
22 pub fn from_mnemonic(phrase: &str) -> Result<Self> {
23 let mnemonic = Mnemonic::parse_in_normalized(Language::English, phrase)
24 .map_err(|e| Error::Mnemonic(e.to_string()))?;
25
26 let seed = mnemonic.to_seed("");
27 let mut key_bytes = [0u8; 32];
28 key_bytes.copy_from_slice(&seed[0..32]);
29
30 let signing_key = SigningKey::from_bytes(&key_bytes);
31 Ok(Self { signing_key })
32 }
33
34 pub fn address(&self) -> Address {
35 let verifying_key: VerifyingKey = (&self.signing_key).into();
36 Address(verifying_key.to_bytes())
37 }
38
39 pub fn sign_transaction(&self, mut tx: Transaction) -> Result<Transaction> {
40 let mut body = Vec::new();
41 body.push(match tx.tx_type {
42 TransactionType::Transfer => 0,
43 TransactionType::Governance => 1,
44 TransactionType::ContractDeploy => 2,
45 TransactionType::ContractCall => 3,
46 TransactionType::SubmitEquivocationProof => 4,
47 });
48 body.extend_from_slice(&tx.from.0);
49 body.extend_from_slice(&tx.to.0);
50 body.extend_from_slice(&tx.amount.to_le_bytes());
51 body.extend_from_slice(&tx.fee.to_le_bytes());
52 body.extend_from_slice(&tx.nonce.to_le_bytes());
53 body.extend_from_slice(&tx.payload);
54
55 let dalek_sig: DalekSignature = self.signing_key.sign(&body);
56 tx.signature = Signature(dalek_sig.to_bytes());
57 Ok(tx)
58 }
59}
60
61pub struct TransactionBuilder {
62 tx_type: Option<TransactionType>,
63 from: Option<Address>,
64 to: Option<Address>,
65 amount: Balance,
66 fee: Balance,
67 nonce: u64,
68 payload: Vec<u8>,
69}
70
71impl Default for TransactionBuilder {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76
77impl TransactionBuilder {
78 pub fn new() -> Self {
79 Self {
80 tx_type: None,
81 from: None,
82 to: None,
83 amount: 0,
84 fee: 0,
85 nonce: 0,
86 payload: Vec::new(),
87 }
88 }
89
90 pub fn tx_type(mut self, tx_type: TransactionType) -> Self {
91 self.tx_type = Some(tx_type);
92 self
93 }
94
95 pub fn from(mut self, from: Address) -> Self {
96 self.from = Some(from);
97 self
98 }
99
100 pub fn to(mut self, to: Address) -> Self {
101 self.to = Some(to);
102 self
103 }
104
105 pub fn amount(mut self, amount: u128) -> Self {
106 self.amount = amount;
107 self
108 }
109
110 pub fn fee(mut self, fee: u128) -> Self {
111 self.fee = fee;
112 self
113 }
114
115 pub fn payload(mut self, payload: Vec<u8>) -> Self {
116 self.payload = payload;
117 self
118 }
119
120 pub fn nonce(mut self, nonce: u64) -> Self {
121 self.nonce = nonce;
122 self
123 }
124
125 pub fn transfer(
126 mut self,
127 from: Option<Address>,
128 to: Address,
129 amount: u128,
130 fee: u128,
131 nonce: u64,
132 ) -> Self {
133 self.tx_type = Some(TransactionType::Transfer);
134 if let Some(f) = from {
135 self.from = Some(f);
136 }
137 self.to = Some(to);
138 self.amount = amount;
139 self.fee = fee;
140 self.nonce = nonce;
141 self
142 }
143
144 pub fn build_unsigned(self) -> Result<Transaction> {
145 let tx_type = self
146 .tx_type
147 .ok_or_else(|| Error::Internal("No transaction type set".to_string()))?;
148 let from = self
149 .from
150 .ok_or_else(|| Error::Internal("No sender set".to_string()))?;
151 let to = self
152 .to
153 .ok_or_else(|| Error::Internal("No recipient set".to_string()))?;
154
155 Ok(Transaction {
156 tx_type,
157 from,
158 to,
159 amount: self.amount,
160 fee: self.fee,
161 nonce: self.nonce,
162 payload: self.payload,
163 signature: Signature([0; 64]),
164 })
165 }
166
167 pub fn build(self, wallet: &Wallet) -> Result<Transaction> {
168 let from = self.from.unwrap_or_else(|| wallet.address());
169 let mut builder = self.from(from);
170 if builder.tx_type.is_none() {
171 builder.tx_type = Some(TransactionType::Transfer);
172 }
173 let tx = builder.build_unsigned()?;
174 wallet.sign_transaction(tx)
175 }
176}