use cid::Cid;
use fvm_ipld_encoding::repr::*;
use fvm_ipld_encoding::tuple::*;
use num_traits::Zero;
#[cfg(feature = "arb")]
use quickcheck::Arbitrary;
use serde::{Deserialize, Serialize};
use crate::EMPTY_ARR_CID;
use crate::address::Address;
use crate::econ::TokenAmount;
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Serialize_repr, Deserialize_repr)]
#[repr(u64)]
pub enum StateTreeVersion {
V0,
V1,
V2,
V3,
V4,
V5,
}
#[derive(Deserialize_tuple, Serialize_tuple)]
pub struct StateRoot {
pub version: StateTreeVersion,
pub actors: Cid,
pub info: Cid,
}
#[derive(Default, Deserialize, Serialize)]
#[serde(transparent)]
pub struct StateInfo0([(); 0]);
#[derive(PartialEq, Eq, Clone, Debug, Serialize_tuple, Deserialize_tuple)]
pub struct ActorState {
pub code: Cid,
pub state: Cid,
pub sequence: u64,
pub balance: TokenAmount,
pub delegated_address: Option<Address>,
}
#[derive(thiserror::Error, Debug)]
pub enum InvalidTransfer {
#[error("insufficient funds when deducting funds ({amount}) from balance ({balance})")]
InsufficientBalance {
amount: TokenAmount,
balance: TokenAmount,
},
#[error("cannot deposite/deduct a negative amount of funds ({0})")]
NegativeAmount(TokenAmount),
}
impl ActorState {
pub fn new(
code: Cid,
state: Cid,
balance: TokenAmount,
sequence: u64,
address: Option<Address>,
) -> Self {
Self {
code,
state,
sequence,
balance,
delegated_address: address,
}
}
pub fn new_empty(code: Cid, delegated_address: Option<Address>) -> Self {
ActorState {
code,
state: EMPTY_ARR_CID,
sequence: 0,
balance: TokenAmount::zero(),
delegated_address,
}
}
pub fn deduct_funds(&mut self, amt: &TokenAmount) -> Result<(), InvalidTransfer> {
if amt.is_negative() {
return Err(InvalidTransfer::NegativeAmount(amt.clone()));
}
if &self.balance < amt {
return Err(InvalidTransfer::InsufficientBalance {
amount: amt.clone(),
balance: self.balance.clone(),
});
}
self.balance -= amt;
Ok(())
}
pub fn deposit_funds(&mut self, amt: &TokenAmount) -> Result<(), InvalidTransfer> {
if amt.is_negative() {
Err(InvalidTransfer::NegativeAmount(amt.clone()))
} else {
self.balance += amt;
Ok(())
}
}
}
#[cfg(feature = "arb")]
impl Arbitrary for ActorState {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
Self {
code: Cid::arbitrary(g),
state: Cid::arbitrary(g),
sequence: u64::arbitrary(g),
balance: TokenAmount::arbitrary(g),
delegated_address: Option::arbitrary(g),
}
}
}