Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ain-core lib with DFIP-2206-{D,E} #17

Merged
merged 4 commits into from
Jul 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ jobs:
run: make build-wasm-pkg
- name: Build lib
run: make build-grpc-pkg
- name: Build core
run: make build-core-pkg
- name: Run tests
run: cargo test --verbose --workspace
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[workspace]
members = [
"ain-core",
"ain-grpc",
"wasm-modules/dex",
"wasm-runtime",
Expand Down
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@ build-grpc-pkg:
cp target/release/libain_grpc.a pkg/ain-grpc/lib/
cp target/libain.hpp pkg/ain-grpc/include/
cp target/libain.cpp pkg/ain-grpc/

# TODO: Merge this with grpc package when ain links both
build-core-pkg:
$(CARGO) build --package ain-core --release
mkdir -p pkg/ain-core/include pkg/ain-core/lib
cp target/release/libain_core.a pkg/ain-core/lib/
cp target/libain_core.hpp pkg/ain-core/include/
cp target/libain_core.cpp pkg/ain-core/
18 changes: 18 additions & 0 deletions ain-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "ain-core"
version = "0.1.0"
edition = "2021"
build = "build.rs"

[lib]
crate-type = ["staticlib"]

[dependencies]
cxx = "1.0"
env_logger = "0.9"
lazy_static = "1.4"
log = "0.4"

[build-dependencies]
cxx-gen = "0.7"
proc-macro2 = "1.0"
32 changes: 32 additions & 0 deletions ain-core/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use proc_macro2::TokenStream;

use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;

fn main() {
let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let parent = root.clone();
root.pop();
let lib_path = &parent.join("src").join("lib.rs");
let target_dir = &root.join("target");

let mut content = String::new();
File::open(lib_path)
.unwrap()
.read_to_string(&mut content)
.unwrap();
let tt: TokenStream = content.parse().unwrap();
let codegen = cxx_gen::generate_header_and_cc(tt, &cxx_gen::Opt::default()).unwrap();

let cpp_stuff = String::from_utf8(codegen.implementation).unwrap();
File::create(target_dir.join("libain_core.hpp"))
.unwrap()
.write_all(&codegen.header)
.unwrap();
File::create(target_dir.join("libain_core.cpp"))
.unwrap()
.write_all(cpp_stuff.as_bytes())
.unwrap();
}
133 changes: 133 additions & 0 deletions ain-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use std::sync::RwLock;

lazy_static::lazy_static! {
static ref COEFF_DEX_FEE: RwLock<f64> = RwLock::new(1.8);
static ref COEFF_DISCOUNT: RwLock<f64> = RwLock::new(500.0);
static ref COEFF_PREMIUM: RwLock<f64> = RwLock::new(3.4);
}

#[cxx::bridge]
mod calc {
extern "Rust" {
fn set_fee_coefficient(coefficient: f64);

fn set_interest_rate_coefficients(discount: f64, premium: f64);

fn calc_dex_fee(algo_dusd: f64, dusd_supply: f64) -> f64;

fn calc_loan_interest_rate(
reserve_dfi: f64,
reserve_dusd: f64,
dfi_oracle_price: f64,
) -> f64;
}
}

/// **DFIP-2206-D**
///
/// Sets the coefficient for calculation of dex stabilization fee. Default is `1.8`
fn set_fee_coefficient(coefficient: f64) {
*COEFF_DEX_FEE.write().unwrap() = coefficient;
}

/// **DFIP-2206-E**
///
/// Sets the coefficients for discount and premium of DUSD for calculation of interest rates.
/// Default is `500` for discount and `3.4` for premium.
fn set_interest_rate_coefficients(discount: f64, premium: f64) {
*COEFF_DISCOUNT.write().unwrap() = discount;
*COEFF_PREMIUM.write().unwrap() = premium;
}

/// **DFIP-2206-D**
///
/// Calculates the dynamic dex stabilization fee for DUSD on DUSD-DFI pair. The size of the fee
/// is determined by the ratio of algorithmic DUSD to the total amount of outstanding DUSD.
fn calc_dex_fee(algo_dusd: f64, dusd_supply: f64) -> f64 {
if dusd_supply <= 0.0 {
log::warn!("DUSD supply must be positive. Received {}", dusd_supply);
return 0.0;
}
let ratio = 1.0 - (algo_dusd / dusd_supply);
let coeff = *COEFF_DEX_FEE.read().unwrap();
if ratio > 0.5 {
coeff.powf(ratio - 0.5) - 1.0
} else {
0.0
}
}

/// **DFIP-2206-E**
///
/// Calculates the dynamic interest rates on DUSD loans, based on the current discount/premium
/// of DUSD evaluated with the DFI price oracle.
fn calc_loan_interest_rate(reserve_dfi: f64, reserve_dusd: f64, dfi_oracle_price: f64) -> f64 {
if reserve_dusd <= 0.0 {
log::warn!("Reserve DUSD must be positive. Received {}", reserve_dusd);
return 0.0;
}
let dex_price = (reserve_dfi / reserve_dusd) * dfi_oracle_price;
if dex_price < 0.99 {
let coeff = *COEFF_DISCOUNT.read().unwrap();
coeff.powf(0.99 - dex_price) - 1.0
} else if dex_price < 1.01 {
0.0
} else if dex_price < 1.05 {
let coeff = *COEFF_PREMIUM.read().unwrap();
1.0 - coeff.powf(dex_price - 1.01)
} else {
-0.05
}
}

#[cfg(test)]
mod tests {
use super::{calc_dex_fee, calc_loan_interest_rate};

#[test]
fn test_default_fees() {
let cases = &[
(510.0, 0.0),
(500.0, 0.0),
(490.0, 0.005895),
(480.0, 0.011825),
(450.0, 0.029825),
(400.0, 0.06054),
(350.0, 0.092172),
(250.0, 0.158292),
(100.0, 0.265054),
];

for &(algo_dusd, fee) in cases {
let f = calc_dex_fee(algo_dusd, 1000.0);
if (fee - f).abs() > 0.000001 {
panic!("Fee {} is off from expected fee {}", f, fee);
}
}
}

#[test]
fn test_default_rates() {
let cases = &[
(1.05, -0.05),
(1.04, -0.037395),
(1.03, -0.024777),
(1.02, -0.012313),
(1.01, 0.0),
(0.99, 0.0),
(0.98, 0.0641178),
(0.97, 0.1323466),
(0.95, 0.282209),
(0.9, 0.749473),
(0.8, 2.2569),
(0.7, 5.063192),
];

for &(price, rate) in cases {
let r = calc_loan_interest_rate(1.0, 1.0, price);
if (rate - r).abs() > 0.000001 {
panic!("Rate {} is off from expected {}", r, rate);
}
}
}
}
5 changes: 3 additions & 2 deletions ain-grpc/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod types {
tonic::include_proto!("types");
}

#[allow(clippy::useless_conversion)]
pub mod rpc {
tonic::include_proto!("rpc");
}
Expand All @@ -13,7 +14,7 @@ impl Serialize for types::BlockResult {
where
S: serde::Serializer,
{
if self.hash != "" {
if !self.hash.is_empty() {
return serializer.serialize_str(&self.hash);
}

Expand All @@ -30,7 +31,7 @@ impl Serialize for types::Transaction {
where
S: serde::Serializer,
{
if self.hash != "" {
if !self.hash.is_empty() {
return serializer.serialize_str(&self.hash);
}

Expand Down
1 change: 1 addition & 0 deletions ain-grpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ fn start_servers(
Ok(runtime)
}

#[allow(clippy::boxed_local)]
fn stop_servers(mut runtime: Box<Runtime>) -> Result<(), Box<dyn Error>> {
log::info!("Stopping gRPC and JSON RPC servers");
runtime.stop();
Expand Down
4 changes: 2 additions & 2 deletions wasm-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ crate-type = ["cdylib"]

[dependencies]
wit-bindgen-wasmtime = { git = "https://github.com/bytecodealliance/wit-bindgen.git"}
wasmtime-wasi = "0.35.0"
wasmtime-wasi-crypto = "0.35.0"
wasmtime-wasi = "0.38.1"
wasmtime-wasi-crypto = "0.38.1"
lazy_static = "1.4.0"
dashmap = "5.1.0"