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

OCT-2297: Fix grace period for Sablier #607

Merged
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
9 changes: 2 additions & 7 deletions backend/app/engine/epochs_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ def register_epoch_settings():
),
user=UserSettings(
budget=PreliminaryUserBudget(),
effective_deposit=DefaultWeightedAverageEffectiveDeposit(),
),
project=ProjectSettings(
rewards=PreliminaryProjectRewards(
Expand All @@ -95,10 +94,6 @@ def register_epoch_settings():
user=UserSettings(effective_deposit=DefaultWeightedAverageEffectiveDeposit()),
project=ProjectSettings(rewards=PreliminaryProjectRewards()),
)
SETTINGS[4] = EpochSettings(
user=UserSettings(effective_deposit=DefaultWeightedAverageEffectiveDeposit())
)
SETTINGS[5] = EpochSettings(
user=UserSettings(effective_deposit=DefaultWeightedAverageEffectiveDeposit())
)
SETTINGS[4] = EpochSettings()
SETTINGS[5] = EpochSettings()
SETTINGS[6] = EpochSettings()
6 changes: 3 additions & 3 deletions backend/app/engine/user/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
from app.engine.user.budget import UserBudget
from app.engine.user.budget.with_ppf import UserBudgetWithPPF
from app.engine.user.effective_deposit import UserEffectiveDeposit
from app.engine.user.effective_deposit.weighted_average.default_with_sablier_timebox import (
DefaultWeightedAverageWithSablierTimebox,
from app.engine.user.effective_deposit.weighted_average.default import (
DefaultWeightedAverageEffectiveDeposit,
)


@dataclass
class UserSettings:
effective_deposit: UserEffectiveDeposit = field(
default_factory=DefaultWeightedAverageWithSablierTimebox
default_factory=DefaultWeightedAverageEffectiveDeposit
)
budget: UserBudget = field(default_factory=UserBudgetWithPPF)
1 change: 0 additions & 1 deletion backend/app/engine/user/effective_deposit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ class UserEffectiveDepositPayload:
epoch_start: int = None
epoch_end: int = None
lock_events_by_addr: LockEventsByAddr = None
sablier_unlock_grace_period: int = None


@dataclass
Expand Down

This file was deleted.

6 changes: 1 addition & 5 deletions backend/app/modules/common/effective_deposits.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,13 @@ def calculate_effective_deposits(
epoch_details: EpochDetails,
epoch_settings: EpochSettings,
events: Dict[str, List[DepositEvent]],
sablier_unlock_grace_period: int = None,
) -> Tuple[List[UserDeposit], int]:
start = epoch_details.start_sec
end = epoch_details.end_sec
effective_deposit_calculator = epoch_settings.user.effective_deposit

return effective_deposit_calculator.calculate_users_effective_deposits(
UserEffectiveDepositPayload(
epoch_start=start,
epoch_end=end,
lock_events_by_addr=events,
sablier_unlock_grace_period=sablier_unlock_grace_period,
epoch_start=start, epoch_end=end, lock_events_by_addr=events
)
)
13 changes: 8 additions & 5 deletions backend/app/modules/modules_factory/current.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,15 @@ def _prepare_simulation_data(
@staticmethod
def create(chain_id: int) -> "CurrentServices":
is_mainnet = compare_blockchain_types(chain_id, ChainTypes.MAINNET)

user_deposits = CalculatedUserDeposits(
events_generator=DbAndGraphEventsGenerator(),
sablier_unlock_grace_period=SABLIER_UNLOCK_GRACE_PERIOD_24_HRS
sablier_unlock_grace_period = (
SABLIER_UNLOCK_GRACE_PERIOD_24_HRS
if is_mainnet
else TEST_SABLIER_UNLOCK_GRACE_PERIOD_15_MIN,
else TEST_SABLIER_UNLOCK_GRACE_PERIOD_15_MIN
)
user_deposits = CalculatedUserDeposits(
events_generator=DbAndGraphEventsGenerator(
sablier_unlock_grace_period=sablier_unlock_grace_period
)
)

octant_rewards = CurrentServices._prepare_simulation_data(
Expand Down
12 changes: 8 additions & 4 deletions backend/app/modules/modules_factory/pre_pending.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,16 @@ class PrePendingServices(Model):
@staticmethod
def create(chain_id: int) -> "PrePendingServices":
is_mainnet = compare_blockchain_types(chain_id, ChainTypes.MAINNET)
sablier_unlock_grace_period = (
SABLIER_UNLOCK_GRACE_PERIOD_24_HRS
if is_mainnet
else TEST_SABLIER_UNLOCK_GRACE_PERIOD_15_MIN
)

user_deposits = CalculatedUserDeposits(
events_generator=DbAndGraphEventsGenerator(),
sablier_unlock_grace_period=SABLIER_UNLOCK_GRACE_PERIOD_24_HRS
if is_mainnet
else TEST_SABLIER_UNLOCK_GRACE_PERIOD_15_MIN,
events_generator=DbAndGraphEventsGenerator(
sablier_unlock_grace_period=sablier_unlock_grace_period
)
)
octant_rewards = CalculatedOctantRewards(
staking_proceeds=(
Expand Down
5 changes: 1 addition & 4 deletions backend/app/modules/user/budgets/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,7 @@ def estimate_epoch_budget(
ZERO_ADDRESS: simulate_user_events(epoch_details, lock_duration, glm_amount)
}
user_effective_deposits, _ = calculate_effective_deposits(
epoch_details,
epoch_settings,
events,
sablier_unlock_grace_period=sablier_unlock_grace_period,
epoch_details, epoch_settings, events
)
effective_deposit = (
user_effective_deposits[0].effective_deposit if user_effective_deposits else 0
Expand Down
17 changes: 3 additions & 14 deletions backend/app/modules/user/deposits/service/calculated.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,28 @@ def get_all_users_events(self, context: Context) -> Dict[str, List[DepositEvent]

class CalculatedUserDeposits(Model):
events_generator: EventsGenerator
sablier_unlock_grace_period: int

def get_all_effective_deposits(
self, context: Context
) -> Tuple[List[UserDeposit], int]:
events = self.events_generator.get_all_users_events(context)
return calculate_effective_deposits(
context.epoch_details,
context.epoch_settings,
events,
self.sablier_unlock_grace_period,
context.epoch_details, context.epoch_settings, events
)

def get_total_effective_deposit(self, context: Context) -> int:
events = self.events_generator.get_all_users_events(context)
_, total = calculate_effective_deposits(
context.epoch_details,
context.epoch_settings,
events,
self.sablier_unlock_grace_period,
context.epoch_details, context.epoch_settings, events
)
return total

def get_user_effective_deposit(self, context: Context, user_address: str) -> int:
events = {
user_address: self.events_generator.get_user_events(context, user_address)
}
print("events", events)
deposits, _ = calculate_effective_deposits(
context.epoch_details,
context.epoch_settings,
events,
self.sablier_unlock_grace_period,
context.epoch_details, context.epoch_settings, events
)
return deposits[0].effective_deposit

Expand Down
72 changes: 59 additions & 13 deletions backend/app/modules/user/events_generator/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from app.engine.user.effective_deposit import DepositEvent, EventType, DepositSource


def unify_deposit_balances(events: List[DepositEvent]) -> List[DepositEvent]:
def unify_deposit_balances(
events: List[DepositEvent], sablier_unlock_grace_period: int
) -> List[DepositEvent]:
"""
Unify deposit balance for each event in the list of events. Events are expected to be sorted by timestamp.
The first event is taken from deposits, but it already includes deposit from Sablier from the past.
Expand All @@ -17,23 +19,67 @@ def unify_deposit_balances(events: List[DepositEvent]) -> List[DepositEvent]:
acc_balance_sablier = 0
acc_balance_octant = events[0].deposit_before # balance from previous epoch

for event in modified_events[1:]:
i = 0
while i < len(modified_events) - 1:
current_event = modified_events[i]
next_event = modified_events[i + 1]

if current_event.type == EventType.UNLOCK and next_event.type == EventType.LOCK:
if (
current_event.source == DepositSource.SABLIER
and next_event.source == DepositSource.OCTANT
and next_event.timestamp - current_event.timestamp
< sablier_unlock_grace_period
):
unlocked_amount = current_event.amount
locked_amount = next_event.amount

if locked_amount == unlocked_amount:
# Scenario 1: Transparent unlock and lock
del modified_events[i : i + 2]
continue
elif locked_amount > unlocked_amount:
# Scenario 3: Transparent unlock, only record the excess lock
excess_amount = locked_amount - unlocked_amount
next_event.amount = excess_amount
next_event.deposit_before = acc_balance_sablier + acc_balance_octant
next_event.deposit_after = next_event.deposit_before + excess_amount
del modified_events[i] # Remove the unlock event
continue

# Update balances for normal event processing
combined_balance = acc_balance_sablier + acc_balance_octant
event.deposit_before = combined_balance
current_event.deposit_before = combined_balance

if event.type == EventType.LOCK:
if event.source == DepositSource.SABLIER:
acc_balance_sablier += event.amount
if current_event.type == EventType.LOCK:
if current_event.source == DepositSource.SABLIER:
acc_balance_sablier += current_event.amount
else:
acc_balance_octant += event.amount
acc_balance_octant += current_event.amount

event.deposit_after = event.deposit_before + event.amount
elif event.type == EventType.UNLOCK:
if event.source == DepositSource.SABLIER:
acc_balance_sablier -= event.amount
current_event.deposit_after = (
current_event.deposit_before + current_event.amount
)
elif current_event.type == EventType.UNLOCK:
if current_event.source == DepositSource.SABLIER:
acc_balance_sablier -= current_event.amount
else:
acc_balance_octant -= event.amount
acc_balance_octant -= current_event.amount

event.deposit_after = event.deposit_before - event.amount
current_event.deposit_after = (
current_event.deposit_before - current_event.amount
)

i += 1

# Process the last event
if modified_events:
last_event = modified_events[-1]
combined_balance = acc_balance_sablier + acc_balance_octant
last_event.deposit_before = combined_balance
if last_event.type == EventType.LOCK:
last_event.deposit_after = last_event.deposit_before + last_event.amount
elif last_event.type == EventType.UNLOCK:
last_event.deposit_after = last_event.deposit_before - last_event.amount

return modified_events
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@


class DbAndGraphEventsGenerator(Model):
sablier_unlock_grace_period: int

def get_user_events(
self, context: Context, user_address: str
) -> List[DepositEvent]:
Expand Down Expand Up @@ -70,7 +72,9 @@ def get_user_events(
if len(sorted_events) == 1 and sorted_events[0].deposit_after == 0:
return []

sorted_events_with_unified_deposits = unify_deposit_balances(sorted_events)
sorted_events_with_unified_deposits = unify_deposit_balances(
sorted_events, self.sablier_unlock_grace_period
)

return sorted_events_with_unified_deposits

Expand Down Expand Up @@ -125,7 +129,7 @@ def get_all_users_events(self, context: Context) -> Dict[str, List[DepositEvent]
)

user_events[user_address] = unify_deposit_balances(
user_events[user_address]
user_events[user_address], self.sablier_unlock_grace_period
)

return user_events
Expand Down
5 changes: 2 additions & 3 deletions backend/tests/engine/test_epoch_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
from app.engine.octant_rewards import LeftoverWithPPFAndUnusedMR
from app.engine.octant_rewards.leftover.with_ppf import LeftoverWithPPF
from app.engine.octant_rewards.leftover.default import PreliminaryLeftover
from app.engine.user import DefaultWeightedAverageWithSablierTimebox
from app.engine.user.effective_deposit.weighted_average.default import (
DefaultWeightedAverageEffectiveDeposit,
)
Expand All @@ -74,7 +73,7 @@ def test_default_epoch_settings():
projects_rewards=CappedQuadraticFundingProjectRewards(),
projects_allocations=QuadraticFundingAllocations(),
leftover=LeftoverWithPPFAndUnusedMR(),
effective_deposit=DefaultWeightedAverageWithSablierTimebox(
effective_deposit=DefaultWeightedAverageEffectiveDeposit(
timebased_weights=TimebasedWithoutUnlocksWeights()
),
)
Expand Down Expand Up @@ -230,7 +229,7 @@ def test_epoch_6_settings():
),
projects_allocations=QuadraticFundingAllocations(),
leftover=LeftoverWithPPFAndUnusedMR(),
effective_deposit=DefaultWeightedAverageWithSablierTimebox(
effective_deposit=DefaultWeightedAverageEffectiveDeposit(
timebased_weights=TimebasedWithoutUnlocksWeights()
),
)
Expand Down
Loading