Skip to content

Commit

Permalink
Merge pull request #39 from ChainCashLabs/collateral-algo
Browse files Browse the repository at this point in the history
Implement collateral algorithm, more whitelist types & blacklisting
  • Loading branch information
ross-weir authored Dec 11, 2023
2 parents 897b078 + 9ba7f7d commit ae23eea
Show file tree
Hide file tree
Showing 17 changed files with 847 additions and 248 deletions.
82 changes: 82 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[workspace]
members = ["crates/*"]
resolver = "2"

[workspace.package]
version = "0.1.0"
Expand Down
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,39 @@ Currently the following predicates are supported:

#### Whitelist

A `whitelist` predicate evaluates to `true` if any of the suppplied agents are the current owner of the note.
A `whitelist` predicate evaluates to `true` if any of the suppplied agents match depending on the `kind` field.

`whitelist` has subtypes defined in the `kind` field, the following are supported:

- `owner` whitelist is based on the current note holder
- `issuer` whitelist is based on the note issuer
- `historical` whitelist checks each holder of the note

If the owner is known to us and trusted we can accept the note without any other consideration.

For example, this could be configured like so:

```toml
type = "whitelist"
kind = "owner"
agents = ["PK1", "OWNER2"]
```

#### Blacklist

A `blacklist` predicate evaluates to `true` if none of the suppplied agents match depending on the `kind` field.

`blacklist` has subtypes defined in the `kind` field, the following are supported:

- `owner` blacklist is based on the current note holder
- `issuer` blacklist is based on the note issuer
- `historical` blacklist checks each holder of the note

If we want to blacklist all notes issued by `PK1` this could be done like so:

```toml
type = "blacklist"
kind = "issuer"
agents = ["PK1", "OWNER2"]
```

Expand Down Expand Up @@ -111,7 +136,7 @@ For example, if we want to express that a note is accepted if the note is over c
type = "or"
conditions = [
# the owner of the note is either PK1 or PK2
{type = "whitelist", agents = ["PK1", "PK2"]},
{type = "whitelist", kind = "owner", agents = ["PK1", "PK2"]},
# the note has at least 100% collateral
{type = "collateral", percent = 100}
]
Expand Down
2 changes: 1 addition & 1 deletion crates/chaincash_app/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use chaincash_offchain::node::node_from_config;
use chaincash_predicate::Predicate;
use chaincash_predicate::predicates::Predicate;
use chaincash_server::{Server, ServerState};
use chaincash_store::{ChainCashStore, Update};
use config::{Environment, File};
Expand Down
2 changes: 1 addition & 1 deletion crates/chaincash_offchain/src/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use self::notes::{mint_note_transaction, MintNoteRequest};
use self::reserves::{mint_reserve_transaction, MintReserveRequest};
use ergo_client::node::NodeClient;
use ergo_lib::chain::ergo_box::box_builder::ErgoBoxCandidateBuilderError;
use ergo_lib::ergo_chain_types::{blake2b256_hash, Digest32};
use ergo_lib::ergo_chain_types::blake2b256_hash;
use ergo_lib::ergotree_ir::chain::address::AddressEncoderError;
use ergo_lib::ergotree_ir::chain::ergo_box::box_value::BoxValue;
use ergo_lib::ergotree_ir::chain::ergo_box::{box_value::BoxValueError, ErgoBox};
Expand Down
57 changes: 0 additions & 57 deletions crates/chaincash_predicate/src/collateral.rs

This file was deleted.

66 changes: 66 additions & 0 deletions crates/chaincash_predicate/src/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
pub type NanoErg = u64;
pub type PubKeyHex = String;

/// Context related to a note that holds information required by predicates
/// to determine if the note is acceptable.
#[derive(Debug, Clone)]
pub struct NoteContext {
/// The nanoerg value of the related note
/// The denomination of the note converted to its erg value
pub nanoerg: NanoErg,
/// Owner of the note as hex encoded public key
pub owner: PubKeyHex,
/// Issuer of the note as hex encoded public key
pub issuer: PubKeyHex,
/// Agents that have signed and traded the note
pub signers: Vec<PubKeyHex>,
}

/// Implementors provide a way to access extra context when processing a note
/// inside a predicate.
pub trait ContextProvider {
/// Get all notes as `NoteContext` issued by the specified agent
fn agent_issued_notes(&self, agent: &str) -> Vec<NoteContext>;

/// Get the amount of reserves the specified agent has
fn agent_reserves_nanoerg(&self, agent: &str) -> NanoErg;
}

/// Context passed to predicates during evaluation
pub struct PredicateContext<P: ContextProvider> {
pub note: NoteContext,
pub provider: P,
}

#[cfg(test)]
pub(crate) mod test_util {
use super::*;

pub struct TestAgent {
pub pk: String,
pub issued_notes: Vec<NoteContext>,
pub reserves: u64,
}

pub struct TestContextProvider {
pub agents: Vec<TestAgent>,
}

impl ContextProvider for TestContextProvider {
fn agent_issued_notes(&self, agent: &str) -> Vec<NoteContext> {
self.agents
.iter()
.find(|n| n.pk == agent)
.map(|a| a.issued_notes.clone())
.unwrap_or_default()
}

fn agent_reserves_nanoerg(&self, agent: &str) -> u64 {
self.agents
.iter()
.find(|n| n.pk == agent)
.map(|a| a.reserves)
.unwrap_or_default()
}
}
}
Loading

0 comments on commit ae23eea

Please sign in to comment.