Skip to content

Commit

Permalink
scarb fmt
Browse files Browse the repository at this point in the history
  • Loading branch information
baitcode committed Jan 13, 2025
1 parent c6102a1 commit e3067ab
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 130 deletions.
6 changes: 3 additions & 3 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ pub mod governor;
mod governor_test;

pub mod staker;
#[cfg(test)]
mod staker_test;

pub mod staker_log;
#[cfg(test)]
pub mod staker_log_test;
#[cfg(test)]
mod staker_test;

mod interfaces {
pub(crate) mod erc20;
}
mod utils {
pub(crate) mod exp2;
pub(crate) mod exp2;
}

#[cfg(test)]
Expand Down
62 changes: 32 additions & 30 deletions src/staker.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,19 @@ pub trait IStaker<TContractState> {

#[starknet::contract]
pub mod Staker {
use starknet::storage::VecTrait;
use core::num::traits::zero::{Zero};
use core::integer::{u512, u512_safe_div_rem_by_u256};
use core::num::traits::zero::{Zero};
use crate::staker_log::{LogOperations, MAX_FP, StakingLog};
use governance::interfaces::erc20::{IERC20Dispatcher, IERC20DispatcherTrait};
use starknet::storage::VecTrait;
use starknet::storage::{
Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePathEntry,
StoragePointerReadAccess, StoragePointerWriteAccess,
};
use crate::staker_log::{StakingLog, LogOperations, MAX_FP};

use starknet::{
get_block_timestamp, get_caller_address, get_contract_address,
storage_access::{StorePacking}, ContractAddress,
ContractAddress, get_block_timestamp, get_caller_address, get_contract_address,
storage_access::{StorePacking},
};
use super::{IStaker};

Expand All @@ -84,7 +84,7 @@ pub mod Staker {
const TWO_POW_64: u128 = 0x10000000000000000;
const TWO_POW_192: u256 = 0x1000000000000000000000000000000000000000000000000;
const TWO_POW_192_DIVISOR: NonZero<u256> = 0x1000000000000000000000000000000000000000000000000;
const TWO_POW_127: u128 = 0x80000000000000000000000000000000_u128;
const TWO_POW_127: u128 = 0x80000000000000000000000000000000_u128;

pub(crate) impl DelegatedSnapshotStorePacking of StorePacking<DelegatedSnapshot, felt252> {
fn pack(value: DelegatedSnapshot) -> felt252 {
Expand Down Expand Up @@ -262,12 +262,12 @@ pub mod Staker {
self
.amount_delegated
.write(delegate, self.insert_snapshot(delegate, get_block_timestamp()) + amount);

let total_staked = self.total_staked.read();

self.total_staked.write(total_staked + amount);
self.staking_log.log_change(amount, total_staked);
self.staking_log.log_change(amount, total_staked);

self.emit(Staked { from, delegate, amount });
}

Expand Down Expand Up @@ -295,11 +295,11 @@ pub mod Staker {
.amount_delegated
.write(delegate, self.insert_snapshot(delegate, get_block_timestamp()) - amount);
assert(self.token.read().transfer(recipient, amount.into()), 'TRANSFER_FAILED');
let total_staked = self.total_staked.read();

let total_staked = self.total_staked.read();
self.total_staked.write(total_staked - amount);
self.staking_log.log_change(amount, total_staked);

self.emit(Withdrawn { from, delegate, to: recipient, amount });
}

Expand Down Expand Up @@ -354,36 +354,41 @@ pub mod Staker {
self.get_average_delegated(delegate, now - period, now)
}

fn get_cumulative_seconds_per_total_staked_at(self: @ContractState, timestamp: u64) -> u256 {
fn get_cumulative_seconds_per_total_staked_at(
self: @ContractState, timestamp: u64,
) -> u256 {
let timestamp_seconds = timestamp / 1000;

if let Option::Some((log_record, idx)) = self.staking_log.find_in_change_log(timestamp_seconds) {
if let Option::Some((log_record, idx)) = self
.staking_log
.find_in_change_log(timestamp_seconds) {
let total_staked = if (idx == self.staking_log.len() - 1) {
// if last rescord found
self.total_staked.read()
} else {
// otherwise calculate using cumulative_seconds_per_total_staked difference
let next_log_record = self.staking_log.at(idx+1).read();
let next_log_record = self.staking_log.at(idx + 1).read();

// substract fixed point values
let divisor = next_log_record.cumulative_seconds_per_total_staked - log_record.cumulative_seconds_per_total_staked;
let divisor = next_log_record.cumulative_seconds_per_total_staked
- log_record.cumulative_seconds_per_total_staked;
assert(divisor.high < MAX_FP, 'FP_OVERFLOW');

if divisor.is_zero() {
return 0_u64.into();
}

let diff_seconds: u128 = (next_log_record.timestamp - log_record.timestamp).into();
let diff_seconds: u128 = (next_log_record.timestamp - log_record.timestamp)
.into();

// Divide u64 by fixed point
let (total_staked_fp_medium, _) = u512_safe_div_rem_by_u256(
u512 { limb0: 0, limb1: 0, limb2: 0, limb3: diff_seconds },
divisor.try_into().unwrap()
divisor.try_into().unwrap(),
);

let total_staked_fp = u256 {
low: total_staked_fp_medium.limb1,
high: total_staked_fp_medium.limb2,
low: total_staked_fp_medium.limb1, high: total_staked_fp_medium.limb2,
};

assert(total_staked_fp.high < MAX_FP, 'FP_OVERFLOW');
Expand All @@ -395,24 +400,21 @@ pub mod Staker {
0
}
};

let seconds_diff = timestamp_seconds - log_record.timestamp;

let staked_seconds: u256 = if total_staked == 0 {
0_u256
} else {
// Divide u64 by u128
u256 {
low: 0,
high: seconds_diff.into()
} / total_staked.into()
u256 { low: 0, high: seconds_diff.into() } / total_staked.into()
};

// Sum fixed posits
let result = log_record.cumulative_seconds_per_total_staked + staked_seconds;
assert(result.high < MAX_FP, 'FP_OVERFLOW');
return result;
}
}

return 0_u256;
}
Expand Down
114 changes: 60 additions & 54 deletions src/staker_log.cairo
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
use starknet::storage::MutableVecTrait;
use starknet::{get_block_timestamp};
use starknet::storage_access::{StorePacking};

use starknet::storage::{
Vec, VecTrait
};
use starknet::storage::{
StorageBase, Mutable, StorageAsPath,
StoragePointerReadAccess, StoragePointerWriteAccess
Mutable, StorageAsPath, StorageBase, StoragePointerReadAccess, StoragePointerWriteAccess,
};

use starknet::storage::{Vec, VecTrait};
use starknet::storage_access::{StorePacking};
use starknet::{get_block_timestamp};

pub type StakingLog = Vec<StakingLogRecord>;

const TWO_POW_32: u64 = 0x100000000_u64;
Expand All @@ -20,20 +17,20 @@ pub const MAX_FP: u128 = 0x8000000000000110000000000000000_u128;
#[derive(Drop, Serde, Copy)]
pub(crate) struct StakingLogRecord {
pub(crate) timestamp: u64,

// Only 128+32=160 bits are used
pub(crate) cumulative_total_staked: u256,
pub(crate) cumulative_seconds_per_total_staked: u256,
pub(crate) cumulative_total_staked: u256,
pub(crate) cumulative_seconds_per_total_staked: u256,
}

#[generate_trait]
pub impl StakingLogOperations of LogOperations {

fn get_total_staked(self: @StorageBase<StakingLog>, timestamp: u64) -> Option<u128> {
Option::Some(0)
}

fn find_in_change_log(self: @StorageBase<StakingLog>, timestamp: u64) -> Option<(StakingLogRecord, u64)> {
fn find_in_change_log(
self: @StorageBase<StakingLog>, timestamp: u64,
) -> Option<(StakingLogRecord, u64)> {
let log = self.as_path();
if log.len() == 0 {
return Option::None;
Expand All @@ -43,12 +40,12 @@ pub impl StakingLogOperations of LogOperations {

// To avoid reading from the storage multiple times.
let mut result_ptr: Option<(StakingLogRecord, u64)> = Option::None;

while (left <= right) {
let center = (right + left) / 2;
let record_ptr = log.at(center);
let record = record_ptr.read();

if record.timestamp <= timestamp {
result_ptr = Option::Some((record, center));
left = center + 1;
Expand All @@ -60,7 +57,7 @@ pub impl StakingLogOperations of LogOperations {
if let Option::Some((result, idx)) = result_ptr {
return Option::Some((result, idx));
}

return Option::None;
}

Expand All @@ -70,32 +67,34 @@ pub impl StakingLogOperations of LogOperations {
let block_timestamp = get_block_timestamp() / 1000;

if log.len() == 0 {
log.append().write(
StakingLogRecord {
timestamp: block_timestamp,
cumulative_total_staked: 0_u256,
cumulative_seconds_per_total_staked: 0_u64.into(),
}
);

log
.append()
.write(
StakingLogRecord {
timestamp: block_timestamp,
cumulative_total_staked: 0_u256,
cumulative_seconds_per_total_staked: 0_u64.into(),
},
);

return;
}

let last_record_ptr = log.at(log.len() - 1);

let mut last_record = last_record_ptr.read();

let mut record = if last_record.timestamp == block_timestamp {
// update record
last_record_ptr
last_record_ptr
} else {
// create new record
log.append()
};

// Might be zero
let seconds_diff = block_timestamp - last_record.timestamp;

let total_staked_by_elapsed_seconds = total_staked.into() * seconds_diff.into();

let staked_seconds_per_total_staked: u256 = if total_staked == 0 {
Expand All @@ -107,44 +106,50 @@ pub impl StakingLogOperations of LogOperations {
};

// Add a new record.
record.write(
StakingLogRecord {
timestamp: block_timestamp,

cumulative_total_staked:
last_record.cumulative_total_staked + total_staked_by_elapsed_seconds,

cumulative_seconds_per_total_staked:
last_record.cumulative_seconds_per_total_staked + staked_seconds_per_total_staked,
}
);
record
.write(
StakingLogRecord {
timestamp: block_timestamp,
cumulative_total_staked: last_record.cumulative_total_staked
+ total_staked_by_elapsed_seconds,
cumulative_seconds_per_total_staked: last_record
.cumulative_seconds_per_total_staked
+ staked_seconds_per_total_staked,
},
);
}
}

//
//
// Storage layout for StakingLogRecord
//
//

pub(crate) impl StakingLogRecordStorePacking of StorePacking<StakingLogRecord, (felt252, felt252)> {
fn pack(value: StakingLogRecord) -> (felt252, felt252) {
let packed_ts_cumulative_total_staked: felt252 =
pack_u64_u256_tuple(value.timestamp, value.cumulative_total_staked);

let cumulative_seconds_per_total_staked: felt252 = value.cumulative_seconds_per_total_staked
let packed_ts_cumulative_total_staked: felt252 = pack_u64_u256_tuple(
value.timestamp, value.cumulative_total_staked,
);

let cumulative_seconds_per_total_staked: felt252 = value
.cumulative_seconds_per_total_staked
.try_into()
.unwrap();

(packed_ts_cumulative_total_staked, cumulative_seconds_per_total_staked)
}

fn unpack(value: (felt252, felt252)) -> StakingLogRecord {
let (packed_ts_cumulative_total_staked, cumulative_seconds_per_total_staked) = value;
let (timestamp, cumulative_total_staked) = unpack_u64_u256_tuple(packed_ts_cumulative_total_staked);

let (timestamp, cumulative_total_staked) = unpack_u64_u256_tuple(
packed_ts_cumulative_total_staked,
);

StakingLogRecord {
timestamp: timestamp,
cumulative_total_staked: cumulative_total_staked,
cumulative_seconds_per_total_staked: cumulative_seconds_per_total_staked.try_into().unwrap(),
cumulative_seconds_per_total_staked: cumulative_seconds_per_total_staked
.try_into()
.unwrap(),
}
}
}
Expand All @@ -154,19 +159,20 @@ pub(crate) fn pack_u64_u256_tuple(val1: u64, val2: u256) -> felt252 {
u256 {
high: val1.into() * TWO_POW_32.into() + cumulative_total_staked_high_32_bits.into(),
low: val2.low,
}.try_into().unwrap()
}
.try_into()
.unwrap()
}

pub(crate) fn unpack_u64_u256_tuple(value: felt252) -> (u64, u256) {
let packed_ts_total_staked_u256: u256 = value.into();

let cumulative_total_staked = u256 {
high: packed_ts_total_staked_u256.high & MASK_32_BITS,
low: packed_ts_total_staked_u256.low
high: packed_ts_total_staked_u256.high & MASK_32_BITS, low: packed_ts_total_staked_u256.low,
};

return (
(packed_ts_total_staked_u256.high / TWO_POW_32.into()).try_into().unwrap(),
cumulative_total_staked
cumulative_total_staked,
);
}
Loading

0 comments on commit e3067ab

Please sign in to comment.