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
// Copyright 2019-2022 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT
pub mod abi;
pub mod v10;
pub mod v11;
pub mod v8;
pub mod v9;
// code copied from `frc46_token`
pub mod frc46_token {
use cid::Cid;
use fvm_ipld_blockstore::Blockstore;
use fvm_ipld_encoding::tuple::*;
use fvm_ipld_hamt::Hamt;
use fvm_ipld_hamt::{BytesKey, Error as HamtError};
use fvm_shared3::econ::TokenAmount;
type Map<'bs, BS, K, V> = Hamt<&'bs BS, V, K>;
type BalanceMap<'bs, BS> = Map<'bs, BS, BytesKey, TokenAmount>;
type AllowanceMap<'bs, BS> = Map<'bs, BS, BytesKey, Cid>;
type Result<T> = std::result::Result<T, HamtError>;
/// This value has been chosen to optimise to reduce gas-costs when accessing the balances map. Non-
/// standard use cases of the token library might find a different value to be more efficient.
pub const DEFAULT_HAMT_BIT_WIDTH: u32 = 3;
/// An abstraction over the IPLD layer to get and modify token state without dealing with HAMTs etc.
///
/// This is a simple wrapper of state and in general does not account for token protocol level
/// checks such as ensuring necessary approvals are enforced during transfers. This is left for the
/// caller to handle. However, some invariants such as non-negative balances, allowances and total
/// supply are enforced.
#[derive(Serialize_tuple, Deserialize_tuple, PartialEq, Eq, Clone, Debug)]
pub struct TokenState {
/// Total supply of token
pub supply: TokenAmount,
/// Map<ActorId, TokenAmount> of balances as a Hamt
pub balances: Cid,
/// Map<ActorId, Map<ActorId, TokenAmount>> as a Hamt. Allowances are stored balances[owner][operator]
pub allowances: Cid,
/// Bit-width to use when loading Hamts
hamt_bit_width: u32,
}
impl TokenState {
/// Create a new token state-tree, without committing it (the root cid) to a blockstore
pub fn new<BS: Blockstore>(store: &BS) -> Result<Self> {
Self::new_with_bit_width(store, DEFAULT_HAMT_BIT_WIDTH)
}
/// Create a new token state-tree, without committing it (the root cid) to a blockstore
///
/// Explicitly sets the bit width of underlying Hamt structures. Caller must ensure
/// 1 <= hamt_bit_width <= 8.
pub fn new_with_bit_width<BS: Blockstore>(store: &BS, hamt_bit_width: u32) -> Result<Self> {
// Blockstore is still needed to create valid Cids for the Hamts
let empty_balance_map =
BalanceMap::new_with_bit_width(store, hamt_bit_width).flush()?;
let empty_allowances_map =
AllowanceMap::new_with_bit_width(store, hamt_bit_width).flush()?;
Ok(Self {
supply: Default::default(),
balances: empty_balance_map,
allowances: empty_allowances_map,
hamt_bit_width,
})
}
}
}