Skip to main content

off_grid_primitives/account/
spot.rs

1use blake3::Hasher;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5use super::AccountBalances;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
8pub struct SpotAccount {
9    /// Account ID
10    #[serde(with = "serde_bytes")]
11    pub id: Vec<u8>,
12    /// client id
13    #[serde(with = "serde_bytes")]
14    pub cid: Vec<u8>,
15    /// Balances of the account with asset id as key and balance as value
16    pub balances: HashMap<Vec<u8>, u64>,
17    /// state hash of the account
18    pub state_hash: Vec<u8>,
19}
20
21impl AccountBalances for SpotAccount {
22    fn balances(&self) -> &HashMap<Vec<u8>, u64> {
23        &self.balances
24    }
25}
26
27#[derive(Debug, thiserror::Error, PartialEq, Eq)]
28pub enum SpotAccountError {
29    #[error("asset not found")]
30    AssetNotFound,
31    #[error("balance not enough")]
32    BalanceNotEnough,
33}
34
35impl SpotAccount {
36    pub fn new(id: impl Into<Vec<u8>>, cid: impl Into<Vec<u8>>) -> Self {
37        Self { id: id.into(), cid: cid.into(), balances: HashMap::new(), state_hash: Vec::new() }
38    }
39
40    pub fn deposit(&mut self, asset: impl Into<Vec<u8>>, amount: u64) {
41        let entry = self.balances.entry(asset.into()).or_insert(0);
42        *entry = entry.saturating_add(amount);
43    }
44
45    pub fn withdraw(&mut self, asset: impl Into<Vec<u8>>, amount: u64) {
46        let entry = self.balances.entry(asset.into()).or_insert(0);
47        *entry = entry.saturating_sub(amount);
48    }
49
50    pub fn transfer(
51        &mut self,
52        asset: impl Into<Vec<u8>>,
53        _from: impl Into<Vec<u8>>,
54        to: impl Into<Vec<u8>>,
55        amount: u64,
56    ) -> Result<(), SpotAccountError> {
57        self.balances
58            .entry(asset.into())
59            .and_modify(|balance| {
60                *balance = balance.saturating_sub(amount);
61            })
62            .or_insert(0);
63        self.balances
64            .entry(to.into())
65            .and_modify(|balance| {
66                *balance = balance.saturating_add(amount);
67            })
68            .or_insert(amount);
69        Ok(())
70    }
71
72    pub fn update_state_hash(&mut self) {
73        self.state_hash = self.hash_state();
74    }
75
76    pub fn hash_state(&self) -> Vec<u8> {
77        let mut hasher = Hasher::new();
78        for (asset, amount) in self.balances.iter() {
79            hasher.update(asset);
80            hasher.update(&amount.to_le_bytes());
81        }
82        hasher.finalize().as_bytes().to_vec()
83    }
84}