Skip to content

Commit d343eb0

Browse files
committed
custom error enums for state and token methods
1 parent 207f6b7 commit d343eb0

File tree

3 files changed

+90
-132
lines changed

3 files changed

+90
-132
lines changed

fil_fungible_token/src/token/errors.rs

Lines changed: 0 additions & 71 deletions
This file was deleted.

fil_fungible_token/src/token/mod.rs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
1-
pub mod errors;
21
pub mod receiver;
32
mod state;
43
mod types;
5-
use std::ops::Neg;
64

7-
use self::state::TokenState;
5+
use self::state::{StateError, TokenState};
86
pub use self::types::*;
97

10-
use anyhow::bail;
11-
use anyhow::Ok;
12-
use anyhow::Result;
138
use cid::Cid;
149
use fvm_ipld_blockstore::Blockstore as IpldStore;
1510
use fvm_shared::econ::TokenAmount;
1611
use fvm_shared::ActorID;
1712
use num_traits::Signed;
13+
use std::ops::Neg;
14+
use thiserror::Error;
15+
16+
#[derive(Error, Debug)]
17+
pub enum TokenError {
18+
#[error("error in underlying state {0}")]
19+
State(#[from] StateError),
20+
#[error("invalid negative: {0}")]
21+
InvalidNegative(String),
22+
}
23+
24+
type Result<T> = std::result::Result<T, TokenError>;
1825

1926
/// Library functions that implement core FRC-??? standards
2027
///
@@ -44,7 +51,7 @@ where
4451
/// Constructs the token state tree and saves it at a CID
4552
pub fn init_state(&self) -> Result<Cid> {
4653
let init_state = TokenState::new(&self.bs)?;
47-
init_state.save(&self.bs)
54+
Ok(init_state.save(&self.bs)?)
4855
}
4956

5057
/// Helper function that loads the root of the state tree related to token-accounting
@@ -60,7 +67,10 @@ where
6067
/// The mint amount must be non-negative or the method returns an error
6168
pub fn mint(&self, initial_holder: ActorID, value: TokenAmount) -> Result<()> {
6269
if value.is_negative() {
63-
bail!("value of mint was negative {}", value);
70+
return Err(TokenError::InvalidNegative(format!(
71+
"mint amount {} cannot be negative",
72+
value
73+
)));
6474
}
6575

6676
// Increase the balance of the actor and increase total supply
@@ -92,7 +102,7 @@ where
92102
pub fn balance_of(&self, holder: ActorID) -> Result<TokenAmount> {
93103
// Load the HAMT holding balances
94104
let state = self.load_state();
95-
state.get_balance(&self.bs, holder)
105+
Ok(state.get_balance(&self.bs, holder)?)
96106
}
97107

98108
/// Gets the allowance between owner and spender
@@ -116,7 +126,10 @@ where
116126
delta: TokenAmount,
117127
) -> Result<TokenAmount> {
118128
if delta.is_negative() {
119-
bail!("value of delta was negative {}", delta);
129+
return Err(TokenError::InvalidNegative(format!(
130+
"increase allowance delta {} cannot be negative",
131+
delta
132+
)));
120133
}
121134

122135
let mut state = self.load_state();
@@ -138,7 +151,10 @@ where
138151
delta: TokenAmount,
139152
) -> Result<TokenAmount> {
140153
if delta.is_negative() {
141-
bail!("value of delta was negative {}", delta);
154+
return Err(TokenError::InvalidNegative(format!(
155+
"decrease allowance delta {} cannot be negative",
156+
delta
157+
)));
142158
}
143159

144160
let mut state = self.load_state();
@@ -186,7 +202,10 @@ where
186202
value: TokenAmount,
187203
) -> Result<TokenAmount> {
188204
if value.is_negative() {
189-
bail!("cannot burn a negative amount");
205+
return Err(TokenError::InvalidNegative(format!(
206+
"burn amount {} cannot be negative",
207+
value
208+
)));
190209
}
191210

192211
let mut state = self.load_state();
@@ -235,7 +254,10 @@ where
235254
value: TokenAmount,
236255
) -> Result<()> {
237256
if value.is_negative() {
238-
bail!("cannot transfer a negative amount");
257+
return Err(TokenError::InvalidNegative(format!(
258+
"transfer amount {} cannot be negative",
259+
value
260+
)));
239261
}
240262

241263
let mut state = self.load_state();

fil_fungible_token/src/token/state.rs

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,52 @@
1-
use anyhow::anyhow;
2-
use anyhow::bail;
3-
use anyhow::Result;
41
use cid::multihash::Code;
52
use cid::Cid;
6-
73
use fvm_ipld_blockstore::Block;
84
use fvm_ipld_blockstore::Blockstore as IpldStore;
95
use fvm_ipld_encoding::tuple::*;
106
use fvm_ipld_encoding::Cbor;
117
use fvm_ipld_encoding::CborStore;
128
use fvm_ipld_encoding::DAG_CBOR;
9+
use fvm_ipld_hamt::Error as HamtError;
1310
use fvm_ipld_hamt::Hamt;
1411
use fvm_shared::bigint::bigint_ser;
1512
use fvm_shared::bigint::bigint_ser::BigIntDe;
1613
use fvm_shared::bigint::Zero;
1714
use fvm_shared::econ::TokenAmount;
1815
use fvm_shared::ActorID;
1916
use num_traits::Signed;
17+
use thiserror::Error;
2018

2119
const HAMT_BIT_WIDTH: u32 = 5;
2220

21+
#[derive(Error, Debug)]
22+
pub enum StateError {
23+
#[error("ipld hamt error: {0}")]
24+
IpldHamt(#[from] HamtError),
25+
#[error("missing state at cid: {0}")]
26+
MissingState(Cid),
27+
#[error("underlying serialization error: {0}")]
28+
Serialization(String),
29+
#[error(
30+
"negative balance caused by subtracting {delta:?} from {owner:?}'s balance of {balance:?}"
31+
)]
32+
NegativeBalance {
33+
owner: ActorID,
34+
balance: TokenAmount,
35+
delta: TokenAmount,
36+
},
37+
#[error(
38+
"{spender:?} attempted to utilise {delta:?} of allowance {allowance:?} set by {owner:?}"
39+
)]
40+
InsufficentAllowance {
41+
owner: ActorID,
42+
spender: ActorID,
43+
allowance: TokenAmount,
44+
delta: TokenAmount,
45+
},
46+
}
47+
48+
type Result<T> = std::result::Result<T, StateError>;
49+
2350
/// Token state IPLD structure
2451
#[derive(Serialize_tuple, Deserialize_tuple, PartialEq, Clone, Debug)]
2552
pub struct TokenState {
@@ -63,24 +90,24 @@ impl TokenState {
6390
// Load the actor state from the state tree.
6491
match bs.get_cbor::<Self>(cid) {
6592
Ok(Some(state)) => Ok(state),
66-
Ok(None) => Err(anyhow!("no state at this cid {:?}", cid)),
67-
Err(err) => Err(anyhow!("failed to get state: {}", err)),
93+
Ok(None) => Err(StateError::MissingState(cid.clone())),
94+
Err(err) => Err(StateError::Serialization(err.to_string())),
6895
}
6996
}
7097

7198
/// Saves the current state to the blockstore, returning the cid
7299
pub fn save<BS: IpldStore>(&self, bs: &BS) -> Result<Cid> {
73100
let serialized = match fvm_ipld_encoding::to_vec(self) {
74101
Ok(s) => s,
75-
Err(err) => return Err(anyhow!("failed to serialize state: {:?}", err)),
102+
Err(err) => return Err(StateError::Serialization(err.to_string())),
76103
};
77104
let block = Block {
78105
codec: DAG_CBOR,
79106
data: serialized,
80107
};
81108
let cid = match bs.put(Code::Blake2b256, &block) {
82109
Ok(cid) => cid,
83-
Err(err) => return Err(anyhow!("failed to store initial state: {:}", err)),
110+
Err(err) => return Err(StateError::Serialization(err.to_string())),
84111
};
85112
Ok(cid)
86113
}
@@ -126,11 +153,11 @@ impl TokenState {
126153

127154
// if the new_balance is negative, return an error
128155
if new_balance.is_negative() {
129-
bail!(
130-
"resulting balance was negative adding {:?} to {:?}",
131-
delta,
132-
balance.unwrap_or(&BigIntDe(TokenAmount::zero())).0
133-
);
156+
return Err(StateError::NegativeBalance {
157+
balance: new_balance,
158+
delta: delta.clone(),
159+
owner,
160+
});
134161
}
135162

136163
balance_map.set(owner, BigIntDe(new_balance.clone()))?;
@@ -144,30 +171,19 @@ impl TokenState {
144171
&self,
145172
bs: &BS,
146173
) -> Result<Hamt<BS, BigIntDe, ActorID>> {
147-
match Hamt::<BS, BigIntDe, ActorID>::load_with_bit_width(
174+
Ok(Hamt::<BS, BigIntDe, ActorID>::load_with_bit_width(
148175
&self.balances,
149176
(*bs).clone(),
150177
HAMT_BIT_WIDTH,
151-
) {
152-
Ok(map) => Ok(map),
153-
Err(err) => return Err(anyhow!("failed to load balances hamt: {:?}", err)),
154-
}
178+
)?)
155179
}
156180

157181
/// Increase the total supply by the specified value
158182
///
159-
/// The requested amount must be non-negative.
160-
/// Returns an error if the total supply overflows, else returns the new total supply
161-
pub fn increase_supply(&mut self, value: &TokenAmount) -> Result<TokenAmount> {
162-
let new_supply = self.supply.checked_add(value).ok_or_else(|| {
163-
anyhow!(
164-
"Overflow when adding {} to the total_supply of {}",
165-
value,
166-
self.supply
167-
)
168-
})?;
169-
self.supply = new_supply.clone();
170-
Ok(new_supply)
183+
/// The requested amount must be non-negative. Returns the new total supply
184+
pub fn increase_supply(&mut self, value: &TokenAmount) -> Result<&TokenAmount> {
185+
self.supply += value;
186+
Ok(&self.supply)
171187
}
172188

173189
/// Get the allowance that an owner has approved for a spender
@@ -296,25 +312,17 @@ impl TokenState {
296312
return Ok(current_allowance);
297313
}
298314

299-
let new_allowance = current_allowance.checked_sub(value).ok_or_else(|| {
300-
anyhow!(
301-
"Overflow when subtracting {} from {}'s allowance of {}",
302-
value,
303-
owner,
304-
current_allowance
305-
)
306-
})?;
307-
308-
if new_allowance.is_negative() {
309-
return Err(anyhow!(
310-
"Attempted to use {} of {}'s tokens from {}'s allowance of {}",
311-
value,
315+
if current_allowance.lt(value) {
316+
return Err(StateError::InsufficentAllowance {
312317
owner,
313318
spender,
314-
current_allowance
315-
));
319+
allowance: current_allowance,
320+
delta: value.clone(),
321+
});
316322
}
317323

324+
let new_allowance = current_allowance - value;
325+
318326
// TODO: helper function to set a new allowance and flush hamts
319327
let owner_allowances = self.get_owner_allowance_map(bs, owner)?;
320328
// to reach here, allowance must have been previously non zero; so safe to assume the map exists
@@ -353,12 +361,11 @@ impl TokenState {
353361
///
354362
/// Gets a HAMT with CIDs linking to other HAMTs
355363
fn get_allowances_map<BS: IpldStore + Clone>(&self, bs: &BS) -> Result<Hamt<BS, Cid, ActorID>> {
356-
Hamt::<BS, Cid, ActorID>::load_with_bit_width(
364+
Ok(Hamt::<BS, Cid, ActorID>::load_with_bit_width(
357365
&self.allowances,
358366
(*bs).clone(),
359367
HAMT_BIT_WIDTH,
360-
)
361-
.map_err(|e| anyhow!("failed to load base allowances map {}", e))
368+
)?)
362369
}
363370
}
364371

0 commit comments

Comments
 (0)