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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
//! The type of accounts stored in the Mina ledger
//!
//! This defines the complete types used by the protocol as ammended by the proposed snapps
//! specification.

use crate::pickles;
use crate::primitives::*;
use crate::sequence_event::SequenceState;
use crate::token_id;

#[derive(Clone, Copy)]
pub struct TimingInfo {
    pub initial_minimum_balance: u64,
    pub cliff_time: u32,
    pub cliff_amount: u64,
    pub vesting_period: u32,
    pub vesting_increment: u64,
}

/// Timing of the cliff and vesting for unlock of 'protocol-locked' tokens.
#[derive(Clone, Copy)]
pub enum AccountTiming {
    Timed(TimingInfo),
    Untimed,
}

/// The type of accounts stored in the ledger.
pub struct Account<'a> {
    /// Public key for the account.
    pub public_key: CompressedPublicKey,
    /// ID of the token whose balance is stored in this account.
    pub token_id: token_id::TokenID,
    /// Balance in tokens in this account.
    pub balance: u64,
    /// Nonce of the account. This is incremented by transactions with signatures to ensure that a
    /// signed transaction cannot be replayed more than once.
    pub nonce: u32,
    /// The hash of all previous signed transactions applied to this account.
    pub receipt_chain_hash: Hash,
    /// Public key to delegate staking of the balance to.
    pub delegate: CompressedPublicKey,
    /// The state hash of the Mina chain that this account is voting for.
    pub voting_for: StateHash,
    /// Timing of the cliff and vesting for token unlock.
    pub timing: AccountTiming,
    /// Authorization kinds required for account actions.
    pub permissions: Permissions,
    /// Optional information for use by snapp smart contracts.
    pub snapp: Option<SnappAccount<'a>>,
}

impl<'a> Account<'a> {
    /// The 'empty' account, used for unused positions in the ledger.
    ///
    /// ```rust
    /// empty() =
    /// Account {
    ///     public_key: CompressedPublicKey::empty(),
    ///     token_id: 1,
    ///     balance: 0,
    ///     nonce: 0,
    ///     receipt_chain_hash: Hash::empty_receipt_chain_hash(),
    ///     delegate: CompressedPublicKey::empty(),
    ///     voting_for: StateHash::invalid_hash(),
    ///     timing: AccountTiming::Untimed,
    ///     permissions: Permissions::default() ,
    ///     snapp: None,
    /// }
    /// ```
    pub fn empty() -> Account<'a> {
        Account {
            public_key: CompressedPublicKey::empty(),
            token_id: 1,
            balance: 0,
            nonce: 0,
            receipt_chain_hash: Hash::empty_receipt_chain_hash(),
            delegate: CompressedPublicKey::empty(),
            voting_for: StateHash::invalid_hash(),
            timing: AccountTiming::Untimed,
            permissions: Permissions::default(),
            snapp: None,
        }
    }
}

/// Account information for use by snapp smart contracts.
pub struct SnappAccount<'a> {
    /// General purpose storage for use by the snapp associated with this account.
    pub app_state: [Fp; 8],
    /// Verification key for the snapp associated with this account, or `None` if this account has
    /// no associated snapp.
    pub verification_key: Option<pickles::VerificationKey>,
    /// Snapp protocol version
    pub snapp_protocol_version: u32,
    /// History of sequenced event updates for the most recent 5 slots with updates
    pub sequence_state: SequenceState,
    /// `true` if the current `app_state` was initialized by a transaction authorized using a proof,
    /// and every subsequent update was also authorized by a transaction using a proof; `false`
    /// otherwise.
    ///
    /// Snapp authors may use this field to validate that their snapp was initialized honestly and
    /// correctly before being used.
    pub proved_state: bool,
    /// URI to access the code and other resources for this account's snapp smart contract
    pub uri: &'a str,
    /// The symbol for the token managed by this account.
    /// This string has a maximum length of 6 characters.
    pub token_symbol: &'a str,
}

impl<'a> SnappAccount<'a> {
    /// The 'empty' snapp account state.
    /// The `snapp` field of an account is equivalent to this value if and only if it is set to
    /// `None`.
    /// ```rust
    /// empty() =
    /// SnappAccount {
    ///     app_state: [Fp::zero(); 8],
    ///     verification_key: None,
    ///     snapp_protocol_version: 0,
    ///     sequence_state: SequenceState::empty(),
    ///     proved_state: false,
    ///     uri: "",
    ///     token_symbol: "",
    /// }
    /// ```
    pub fn empty() -> SnappAccount<'a> {
        SnappAccount {
            app_state: [Fp::zero(); 8],
            verification_key: None,
            snapp_protocol_version: 0,
            sequence_state: SequenceState::empty(),
            proved_state: false,
            uri: "",
            token_symbol: "",
        }
    }

    /// Returns true if the argument is identical to [`SnappAccount::empty`], false otherwise.
    #[allow(unused)]
    pub fn is_empty(snapp: &SnappAccount<'a>) -> bool {
        panic!("TODO")
    }
}

/// Permissions required for updates to the account.
///
/// Each update applied to the account by a snapp transaction corresponds to one of the fields of
/// this record. The [`AuthorizationRequired`] value of the field determines which authorization
/// kinds may accompany a transaction issuing that update.
#[derive(Copy, Clone)]
pub struct Permissions {
    /// Authorization required to update the account's `snapp.app_state`.
    pub edit_state: AuthorizationRequired,
    /// Authorization required to decrease the `balance` of this account.
    pub send: AuthorizationRequired,
    /// Authorization required to increase the `balance` of this account.
    pub receive: AuthorizationRequired,
    /// Authorization required to modify this account's `delegate`.
    pub set_delegate: AuthorizationRequired,
    /// Authorization required to modify this account's `permissions`.
    pub set_permissions: AuthorizationRequired,
    /// Authorization required to modify this account's `snapp.verification_key`.
    pub set_verification_key: AuthorizationRequired,
    /// Authorization required to modify this account's `snapp.uri`.
    pub set_snapp_uri: AuthorizationRequired,
    /// Authorization required to submit sequence events to this account.
    pub add_sequence_events: AuthorizationRequired,
    /// Authorization required to increment this account's `nonce`.
    pub increment_nonce: AuthorizationRequired,
}

impl Permissions {
    /// The default permissions. Sets every field of [`Permissions`] to
    /// [`AuthorizationRequired::Signature`].
    pub fn default() -> Permissions {
        Permissions {
            edit_state: AuthorizationRequired::Signature,
            send: AuthorizationRequired::Signature,
            receive: AuthorizationRequired::Signature,
            set_delegate: AuthorizationRequired::Signature,
            set_permissions: AuthorizationRequired::Signature,
            set_verification_key: AuthorizationRequired::Signature,
            set_snapp_uri: AuthorizationRequired::Signature,
            add_sequence_events: AuthorizationRequired::Signature,
            increment_nonce: AuthorizationRequired::Signature,
        }
    }
}

/// The kind of authorization that must be provided in a transaction to apply a particular kind of
/// updates.
#[derive(Copy, Clone)]
pub enum AuthorizationRequired {
    /// No authorization required.
    NoneRequired,
    /// Either a proof or a signature may be provided as authorization.
    ProofOrSignature,
    /// A proof must be provided as authorization.
    Proof,
    /// A signature must be provided as authorization.
    Signature,
    /// This kind of update is disabled.
    Disabled,
}