off_grid_primitives/account/
spot.rs1use 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 #[serde(with = "serde_bytes")]
11 pub id: Vec<u8>,
12 #[serde(with = "serde_bytes")]
14 pub cid: Vec<u8>,
15 pub balances: HashMap<Vec<u8>, u64>,
17 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}