1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use chain_addr::Discrimination;
use chain_impl_mockchain::transaction::{
    TransactionSignDataHash, UnspecifiedAccountIdentifier, Witness,
};
use jormungandr_lib::{
    crypto::{
        account::Identifier as AccountIdentifier,
        hash::Hash,
        key::{Identifier, SigningKey},
    },
    interfaces::Address,
};
use rand_chacha::ChaChaRng;
use rand_core::{CryptoRng, RngCore, SeedableRng};
pub type SpendingKey = SigningKey<chain_crypto::Ed25519Extended>;

/// wallet for an delegation
#[derive(Debug, Clone)]
pub struct Wallet {
    rng: ChaChaRng,

    /// the spending key
    signing_keys: Vec<SpendingKey>,

    /// the identifier of delegated account
    delegations: Vec<AccountIdentifier>,

    discrimination: Discrimination,
}

impl Wallet {
    pub fn generate<RNG>(rng: &mut RNG, discrimination: Discrimination) -> Self
    where
        RNG: CryptoRng + RngCore,
    {
        let mut seed = [0; 32];
        rng.fill_bytes(&mut seed);
        Self {
            signing_keys: Vec::new(),
            rng: ChaChaRng::from_seed(seed),
            delegations: Vec::new(),
            discrimination,
        }
    }

    pub fn generate_new_signing_key(&mut self, delegation: AccountIdentifier) -> &SpendingKey {
        let key = SigningKey::generate(&mut self.rng);
        self.signing_keys.push(key);
        self.delegations.push(delegation);
        self.signing_keys.last().unwrap()
    }

    pub fn stake_key(&self) -> UnspecifiedAccountIdentifier {
        UnspecifiedAccountIdentifier::from_single_account(
            self.last_delegation_identifier().to_inner(),
        )
    }

    pub fn delegation(&self, i: usize) -> &AccountIdentifier {
        self.delegations.get(i).unwrap()
    }

    pub fn address(&self) -> Address {
        self.address_nth(0)
    }

    pub fn address_nth(&self, i: usize) -> Address {
        self.signing_key(i)
            .identifier()
            .to_group_address(
                self.discrimination,
                self.delegation(i).clone().to_inner().into(),
            )
            .into()
    }

    pub fn identifier(&self) -> Identifier<chain_crypto::Ed25519> {
        self.last_signing_key().identifier()
    }

    pub fn signing_key(&self, i: usize) -> &SpendingKey {
        self.signing_keys.get(i).expect("no signing key found")
    }

    pub fn last_delegation_identifier(&self) -> AccountIdentifier {
        let index = self.delegations.len() - 1;
        self.delegations.get(index).unwrap().clone()
    }

    pub fn last_signing_key(&self) -> &SpendingKey {
        let index = self.signing_keys.len() - 1;
        self.signing_keys.get(index).expect("no signing key found")
    }

    pub fn mk_witness(
        &self,
        block0_hash: &Hash,
        signing_data: &TransactionSignDataHash,
    ) -> Witness {
        Witness::new_utxo(&(*block0_hash).into_hash(), signing_data, |d| {
            self.last_signing_key().as_ref().sign(d)
        })
    }
}