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

Briq factory #14

Merged
merged 6 commits into from
Aug 24, 2023
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: 1 addition & 1 deletion src/attributes/attributes.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use zeroable::Zeroable;
use clone::Clone;

use briq_protocol::types::{FTSpec, ShapeItem};
use briq_protocol::felt_math::{feltBitAnd, feltOrd};
use briq_protocol::felt_math::{FeltBitAnd, FeltOrd};
use briq_protocol::cumulative_balance::{CUM_BALANCE_TOKEN, CB_BRIQ, CB_ATTRIBUTES};

use dojo::world::{Context, IWorldDispatcherTrait};
Expand Down
2 changes: 1 addition & 1 deletion src/attributes/collection.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use option::OptionTrait;
use clone::Clone;
use serde::Serde;

use briq_protocol::felt_math::{feltBitAnd, feltOrd};
use briq_protocol::felt_math::{FeltBitAnd, FeltOrd};

#[derive(Component, Copy, Drop, Serde, SerdeLen)]
struct Collection {
Expand Down
3 changes: 3 additions & 0 deletions src/briq_factory.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod components;
mod systems;
mod constants;
187 changes: 187 additions & 0 deletions src/briq_factory/components.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
use starknet::ContractAddress;
use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};

use zeroable::Zeroable;
use array::{ArrayTrait, SpanTrait};
use option::OptionTrait;
use traits::{Into, TryInto};

use briq_protocol::world_config::SYSTEM_CONFIG_ID;

use briq_protocol::briq_factory::constants::{
DECIMALS, INFLECTION_POINT, SLOPE, RAW_FLOOR,
LOWER_FLOOR, LOWER_SLOPE, DECAY_PER_SECOND, SURGE_SLOPE, MINIMAL_SURGE, SURGE_DECAY_PER_SECOND,
MIN_PURCHASE, BRIQ_MATERIAL
};

use briq_protocol::felt_math::{FeltOrd, FeltDiv};

use debug::PrintTrait;

#[derive(Component, Copy, Drop, Serde, SerdeLen)]
struct BriqFactoryStore {
#[key]
store_id: u64,
buy_token: ContractAddress,
last_stored_t: felt252,
surge_t: felt252,
last_purchase_time: u64,
}

trait BriqFactoryTrait {
fn get_briq_factory(world: IWorldDispatcher) -> BriqFactoryStore;
fn set_briq_factory(world: IWorldDispatcher, new_store: BriqFactoryStore);

fn get_current_t(self: @BriqFactoryStore) -> felt252;
fn get_surge_t(self: @BriqFactoryStore) -> felt252;
fn get_surge_price(self: @BriqFactoryStore, amount: felt252) -> felt252;
fn get_price(self: @BriqFactoryStore, amount: felt252) -> felt252;
fn get_lin_integral(
self: @BriqFactoryStore, slope: felt252, floor: felt252, t2: felt252, t1: felt252
) -> felt252;
fn get_lin_integral_negative_floor(
self: @BriqFactoryStore, slope: felt252, floor: felt252, t2: felt252, t1: felt252
) -> felt252;
fn integrate(self: @BriqFactoryStore, t: felt252, amount: felt252) -> felt252;
}

// #[generate_trait]
impl BriqFactoryStoreImpl of BriqFactoryTrait {
#[always(inline)]
fn get_briq_factory(world: IWorldDispatcher) -> BriqFactoryStore {
get!(world, (SYSTEM_CONFIG_ID), BriqFactoryStore)
}

#[always(inline)]
fn set_briq_factory(world: IWorldDispatcher, new_store: BriqFactoryStore) {
set!(world, (new_store));
}

fn get_current_t(self: @BriqFactoryStore) -> felt252 {
let store = *self; // TODO: clean this up

let time_since_last_purchase: felt252 = (starknet::info::get_block_timestamp()
- store.last_purchase_time)
.into();
let decay = time_since_last_purchase * DECAY_PER_SECOND();

if store.last_stored_t <= decay {
0
} else {
store.last_stored_t - decay
}
}

fn get_surge_t(self: @BriqFactoryStore) -> felt252 {
let store = *self; // TODO: clean this up

let time_since_last_purchase: felt252 = (starknet::info::get_block_timestamp()
- store.last_purchase_time)
.into();

let decay = time_since_last_purchase * SURGE_DECAY_PER_SECOND();

if store.surge_t <= decay {
0
} else {
store.surge_t - decay
}
}

fn get_surge_price(self: @BriqFactoryStore, amount: felt252) -> felt252 {
let surge_t = self.get_surge_t();

if (surge_t + amount) <= MINIMAL_SURGE() {
return 0;
};

if surge_t > MINIMAL_SURGE() {
self.get_lin_integral(
SURGE_SLOPE(),
0,
surge_t - MINIMAL_SURGE(),
surge_t + amount - MINIMAL_SURGE()
)
} else {
self.get_lin_integral(
SURGE_SLOPE(), 0, 0, surge_t + amount - MINIMAL_SURGE()
)
}
}


fn get_price(self: @BriqFactoryStore, amount: felt252) -> felt252 {
let t = self.get_current_t();
let price = self.integrate(t, amount * DECIMALS());
let surge = self.get_surge_price(amount * DECIMALS());

price + surge
}

fn get_lin_integral(
self: @BriqFactoryStore, slope: felt252, floor: felt252, t2: felt252, t1: felt252,
) -> felt252 {
assert(t2 < t1, 't1 >= t2');
// briq machine broke above 10^12 bricks of demand.
assert(t2 < DECIMALS() * 1000000000000, 't2 >= 10**12');
assert(t1 - t2 < DECIMALS() * 10000000000, 't1-t2 >= 10**10');

// Integral between t2 and t1:
// slope * t1 * t1 / 2 + floor * t1 - (slope * t2 * t2 / 2 + floor * t2);
// Factored as slope * (t1 + t2) * (t1 - t2) / 2 + floor * (t1 - t2);
// Then adding divisors for decimals, trying to avoid overflows and precision loss.

let interm = slope * (t1 + t2);
let q = interm / DECIMALS();
let interm = q * (t1 - t2);
let q = interm / DECIMALS() / 2;

let floor_q = floor * (t1 - t2) / DECIMALS();
q + floor_q
}


fn get_lin_integral_negative_floor(
self: @BriqFactoryStore, slope: felt252, floor: felt252, t2: felt252, t1: felt252,
) -> felt252 {
assert(t2 < t1, 't1 >= t2');
// briq machine broke above 10^12 bricks of demand.
assert(t2 < DECIMALS() * 1000000000000, 't2 >= 10**12');
assert(t1 - t2 < DECIMALS() * 10000000000, 't1-t2 >= 10**10');

// Integral between t2 and t1:
// slope * t1 * t1 / 2 + floor * t1 - (slope * t2 * t2 / 2 + floor * t2);
// Factored as slope * (t1 + t2) * (t1 - t2) / 2 + floor * (t1 - t2);
// Then adding divisors for decimals, trying to avoid overflows and precision loss.

let interm = slope * (t1 + t2);
let q = interm / DECIMALS();
let interm = q * (t1 - t2);
let q = interm / DECIMALS() / 2;
// Floor is negative. t2 < t1 so invert these, then subtract instead of adding.
let floor_q = floor * (t2 - t1) / DECIMALS();
q - floor_q
}


fn integrate(self: @BriqFactoryStore, t: felt252, amount: felt252) -> felt252 {
if (t + amount) <= INFLECTION_POINT() {
return self.get_lin_integral(
LOWER_SLOPE(), LOWER_FLOOR(), t, t + amount
);
}

if INFLECTION_POINT() <= t {
return self.get_lin_integral_negative_floor(
SLOPE(), RAW_FLOOR(), t, t + amount
);
}

self.get_lin_integral(
LOWER_SLOPE(), LOWER_FLOOR(), t, INFLECTION_POINT()
)
+ self.get_lin_integral_negative_floor(
SLOPE(), RAW_FLOOR(), INFLECTION_POINT(), t + amount
)
}
}
53 changes: 53 additions & 0 deletions src/briq_factory/constants.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// 10**18
fn DECIMALS() -> felt252 {
1000000000000000000
}

// Arbitrary inflection point below which to use the lower_* curve
fn INFLECTION_POINT() -> felt252 {
400000 * DECIMALS()
}
// Slope: Buying 100 000 briqs increases price per briq by 0.00001
fn SLOPE() -> felt252 {
100000000 // 10**8
}

// Computed to hit the inflection point at 0.00003 per briq
fn RAW_FLOOR() -> felt252 {
-1 * 10000000000000 // - 10**13
}

// Actual floor price of the briqs = 0.0001
fn LOWER_FLOOR() -> felt252 {
10000000000000 // 10**13
}

// Computed to hit the inflection point at 0.00003 per briq
fn LOWER_SLOPE() -> felt252 {
consteval_int!(5 * 10000000) // 5 * 10**7
}

// decay: for each second, reduce the price by so many wei. Computed to hit 200K per year.
fn DECAY_PER_SECOND() -> felt252 {
6337791082068820
}

fn SURGE_SLOPE() -> felt252 {
100000000 // 10**8
}

fn MINIMAL_SURGE() -> felt252 {
250000 * DECIMALS()
}

fn SURGE_DECAY_PER_SECOND() -> felt252 {
4134 * 100000000000000 // 4134 * 10**14 : Decays over a week
}

fn MIN_PURCHASE() -> felt252 {
9
}

fn BRIQ_MATERIAL() -> felt252 {
1
}
Loading
Loading