Skip to content

Commit b66ef6a

Browse files
authored
a library for creating fungible tokens (#1)
* tidy fvm_dispatch * define token interfaces * basic token functionality * author an actor that uses fil_token * better params and return types * cleanup * cleaner error handling * add readme for token example actor * remove mint from token interface * integration test * non-running integration tests * clippy fixes * revert dependency overrides * add docs; separate api interface from library interface * wip: test * hide ipld data structures behind the state abstraction * refactor allowance code * finish core implementation of frc-xxx token * failing tests * HACK: save changes into blockstore properly for some operations * remove unecessary runtime abstraction
1 parent 4bc27ca commit b66ef6a

File tree

18 files changed

+1446
-1
lines changed

18 files changed

+1446
-1
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ Cargo.lock
1010
**/*.rs.bk
1111

1212
# IDE specific user-config
13-
.vscode/
13+
.vscode/

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22

33
members = [
44
"fvm_dispatch",
5+
"fil_token",
6+
"testing/fil_token_integration",
7+
"testing/fil_token_integration/actors/wfil_token_actor",
58
]

fil_token/Cargo.toml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "fil_token"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
anyhow = "1.0.56"
8+
cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] }
9+
fvm_ipld_blockstore = "0.1.1"
10+
fvm_ipld_hamt = "0.5.1"
11+
fvm_ipld_amt = { version = "0.4.2", features = ["go-interop"] }
12+
fvm_ipld_encoding = "0.2.2"
13+
fvm_sdk = { version = "1.0.0" }
14+
fvm_shared = { version = "0.8.0" }
15+
serde = { version = "1.0.136", features = ["derive"] }
16+
serde_tuple = { version = "0.5.0" }
17+
thiserror = { version = "1.0.31" }

fil_token/src/blockstore.rs

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//! Blockstore implementation is borrowed from https://github.com/filecoin-project/builtin-actors/blob/6df845dcdf9872beb6e871205eb34dcc8f7550b5/runtime/src/runtime/actor_blockstore.rs
2+
//! This impl will likely be made redundant if low-level SDKs export blockstore implementations
3+
use std::convert::TryFrom;
4+
5+
use anyhow::{anyhow, Result};
6+
use cid::multihash::Code;
7+
use cid::Cid;
8+
use fvm_ipld_blockstore::Block;
9+
use fvm_sdk::ipld;
10+
11+
/// A blockstore that delegates to IPLD syscalls.
12+
#[derive(Default, Debug, Copy, Clone)]
13+
pub struct Blockstore;
14+
15+
impl fvm_ipld_blockstore::Blockstore for Blockstore {
16+
fn get(&self, cid: &Cid) -> Result<Option<Vec<u8>>> {
17+
// If this fails, the _CID_ is invalid. I.e., we have a bug.
18+
ipld::get(cid)
19+
.map(Some)
20+
.map_err(|e| anyhow!("get failed with {:?} on CID '{}'", e, cid))
21+
}
22+
23+
fn put_keyed(&self, k: &Cid, block: &[u8]) -> Result<()> {
24+
let code = Code::try_from(k.hash().code()).map_err(|e| anyhow!(e.to_string()))?;
25+
let k2 = self.put(code, &Block::new(k.codec(), block))?;
26+
if k != &k2 {
27+
return Err(anyhow!("put block with cid {} but has cid {}", k, k2));
28+
}
29+
Ok(())
30+
}
31+
32+
fn put<D>(&self, code: Code, block: &Block<D>) -> Result<Cid>
33+
where
34+
D: AsRef<[u8]>,
35+
{
36+
// TODO: Don't hard-code the size. Unfortunately, there's no good way to get it from the
37+
// codec at the moment.
38+
const SIZE: u32 = 32;
39+
let k = ipld::put(code.into(), SIZE, block.codec, block.data.as_ref())
40+
.map_err(|e| anyhow!("put failed with {:?}", e))?;
41+
Ok(k)
42+
}
43+
}
44+
45+
// TODO: put this somewhere more appropriate when a tests folder exists
46+
/// An in-memory blockstore impl taken from filecoin-project/ref-fvm
47+
#[derive(Debug, Default, Clone)]
48+
pub struct MemoryBlockstore {
49+
blocks: RefCell<HashMap<Cid, Vec<u8>>>,
50+
}
51+
52+
use std::{cell::RefCell, collections::HashMap};
53+
impl MemoryBlockstore {
54+
pub fn new() -> Self {
55+
Self::default()
56+
}
57+
}
58+
59+
impl fvm_ipld_blockstore::Blockstore for MemoryBlockstore {
60+
fn has(&self, k: &Cid) -> Result<bool> {
61+
Ok(self.blocks.borrow().contains_key(k))
62+
}
63+
64+
fn get(&self, k: &Cid) -> Result<Option<Vec<u8>>> {
65+
Ok(self.blocks.borrow().get(k).cloned())
66+
}
67+
68+
fn put_keyed(&self, k: &Cid, block: &[u8]) -> Result<()> {
69+
self.blocks.borrow_mut().insert(*k, block.into());
70+
Ok(())
71+
}
72+
}

fil_token/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub mod blockstore;
2+
pub mod token;
3+
4+
#[cfg(test)]
5+
mod tests {}

fil_token/src/token/errors.rs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use std::{error::Error, fmt::Display};
2+
3+
use fvm_ipld_hamt::Error as HamtError;
4+
use fvm_shared::address::Address;
5+
6+
#[derive(Debug)]
7+
pub enum RuntimeError {
8+
AddrNotFound(Address),
9+
}
10+
11+
impl Display for RuntimeError {
12+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13+
match self {
14+
RuntimeError::AddrNotFound(_) => write!(f, "Address not found"),
15+
}
16+
}
17+
}
18+
19+
impl Error for RuntimeError {}
20+
21+
#[derive(Debug)]
22+
pub enum StateError {}
23+
24+
impl Display for StateError {
25+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26+
write!(f, "State error")
27+
}
28+
}
29+
30+
impl Error for StateError {}
31+
32+
#[derive(Debug)]
33+
pub enum ActorError {
34+
AddrNotFound(Address),
35+
Arithmetic(String),
36+
IpldState(StateError),
37+
IpldHamt(HamtError),
38+
RuntimeError(RuntimeError),
39+
}
40+
41+
impl Display for ActorError {
42+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43+
match self {
44+
ActorError::AddrNotFound(e) => write!(f, "{}", e),
45+
ActorError::Arithmetic(e) => write!(f, "{}", e),
46+
ActorError::IpldState(e) => write!(f, "{}", e),
47+
ActorError::IpldHamt(e) => write!(f, "{}", e),
48+
ActorError::RuntimeError(e) => write!(f, "{}", e),
49+
}
50+
}
51+
}
52+
53+
impl Error for ActorError {}
54+
55+
impl From<StateError> for ActorError {
56+
fn from(e: StateError) -> Self {
57+
Self::IpldState(e)
58+
}
59+
}
60+
61+
impl From<HamtError> for ActorError {
62+
fn from(e: HamtError) -> Self {
63+
Self::IpldHamt(e)
64+
}
65+
}
66+
67+
impl From<RuntimeError> for ActorError {
68+
fn from(e: RuntimeError) -> Self {
69+
ActorError::RuntimeError(e)
70+
}
71+
}

0 commit comments

Comments
 (0)