Skip to main content

rootchain_rs/
wallet.rs

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}