Skip to content

Commit

Permalink
OCT-815: Double Total Rewards for Epoch 1
Browse files Browse the repository at this point in the history
  • Loading branch information
0xartem committed Aug 29, 2023
1 parent bdcd47f commit e2a2e77
Show file tree
Hide file tree
Showing 17 changed files with 188 additions and 54 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.env
.idea/
.vscode/
.yarn/
node_modules/

Expand Down
10 changes: 7 additions & 3 deletions backend/app/controllers/rewards.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@

from dataclass_wizard import JSONWizard

from app.core.epochs import epoch_snapshots as core_epoch_snapshots
from app import database
from app import exceptions
from app.core import proposals, merkle_tree, epochs as core_epochs
from app.core import proposals, merkle_tree
from app.core.proposals import get_proposals_with_allocations
from app.core.rewards import calculate_matched_rewards, get_matched_rewards_from_epoch
from app.core.rewards.rewards import (
calculate_matched_rewards,
get_matched_rewards_from_epoch,
)
from app.extensions import epochs


Expand Down Expand Up @@ -92,7 +96,7 @@ def get_proposals_rewards(epoch: int = None) -> List[ProposalReward]:


def get_rewards_merkle_tree(epoch: int) -> RewardsMerkleTree:
if not core_epochs.has_finalized_epoch_snapshot(epoch):
if not core_epoch_snapshots.has_finalized_epoch_snapshot(epoch):
raise exceptions.InvalidEpoch

mt = merkle_tree.get_merkle_tree_for_epoch(epoch)
Expand Down
14 changes: 10 additions & 4 deletions backend/app/controllers/snapshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@
from app import exceptions, database
from app.core import glm, user as user_core, merkle_tree
from app.core.deposits.deposits import get_users_deposits, calculate_locked_ratio
from app.core.epochs import has_pending_epoch_snapshot, has_finalized_epoch_snapshot
from app.core.epochs.epoch_snapshots import (
has_pending_epoch_snapshot,
has_finalized_epoch_snapshot,
)
from app.core.proposals import get_proposal_rewards_above_threshold
from app.core.rewards import calculate_total_rewards, calculate_all_individual_rewards
from app.core.rewards.rewards import (
calculate_total_rewards,
calculate_all_individual_rewards,
)
from app.database import pending_epoch_snapshot, finalized_epoch_snapshot
from app.extensions import db, w3, epochs

Expand Down Expand Up @@ -44,9 +50,9 @@ def snapshot_pending_epoch() -> Optional[int]:
eth_proceeds = w3.eth.get_balance(app.config["WITHDRAWALS_TARGET_CONTRACT_ADDRESS"])
user_deposits, total_effective_deposit = get_users_deposits(pending_epoch)
locked_ratio = calculate_locked_ratio(total_effective_deposit, glm_supply)
total_rewards = calculate_total_rewards(eth_proceeds, locked_ratio)
total_rewards = calculate_total_rewards(eth_proceeds, locked_ratio, pending_epoch)
all_individual_rewards = calculate_all_individual_rewards(
eth_proceeds, locked_ratio
eth_proceeds, locked_ratio, pending_epoch
)

database.deposits.add_all(pending_epoch, user_deposits)
Expand Down
2 changes: 1 addition & 1 deletion backend/app/core/allocations.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from dataclass_wizard import JSONWizard

from app import database, exceptions
from app.core.epochs import has_pending_epoch_snapshot
from app.core.epochs.epoch_snapshots import has_pending_epoch_snapshot
from app.core.user import get_budget
from app.crypto.eip712 import recover_address, build_allocations_eip712_data
from app.extensions import proposals
Expand Down
Empty file.
File renamed without changes.
23 changes: 23 additions & 0 deletions backend/app/core/epochs/epochs_registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from dataclasses import dataclass

from app.core.rewards.rewards_strategy import RewardsStrategy
from app.core.rewards.standard_rewards_strategy import StandardRewardsStrategy


@dataclass(frozen=True)
class EpochSettings:
rewardsStrategy: RewardsStrategy = StandardRewardsStrategy()


class EpochsRegistry:
rewards_registry: dict[int, EpochSettings] = {}

@classmethod
def register_epoch_settings(
cls, epoch_number: int, rewardsStrategy: RewardsStrategy
):
cls.rewards_registry[epoch_number] = EpochSettings(rewardsStrategy)

@classmethod
def get_epoch_settings(cls, epoch_number: int) -> EpochSettings:
return cls.rewards_registry.setdefault(epoch_number, EpochSettings())
2 changes: 1 addition & 1 deletion backend/app/core/proposals.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from app import database
from app.core.common import AccountFunds
from app.core.rewards import (
from app.core.rewards.rewards import (
get_matched_rewards_from_epoch,
calculate_matched_rewards_threshold,
)
Expand Down
28 changes: 0 additions & 28 deletions backend/app/core/rewards.py

This file was deleted.

4 changes: 4 additions & 0 deletions backend/app/core/rewards/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from app.core.epochs.epochs_registry import EpochsRegistry
from app.core.rewards.double_rewards_strategy import DoubleRewardsStrategy

EpochsRegistry.register_epoch_settings(1, DoubleRewardsStrategy())
24 changes: 24 additions & 0 deletions backend/app/core/rewards/double_rewards_strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from decimal import Decimal
from app.core.rewards.rewards_strategy import RewardsStrategy


class DoubleRewardsStrategy(RewardsStrategy):
DOUBLING_GLM_SUPPLY_LIMIT = 0.25
REWARDS_MULTIPLY_RATIO_LIMIT = 0.5
REWARDS_MULTIPLY_FACTOR = 2

def calculate_total_rewards(self, eth_proceeds: int, locked_ratio: Decimal) -> int:
if locked_ratio < self.DOUBLING_GLM_SUPPLY_LIMIT:
return (
int(eth_proceeds * locked_ratio.sqrt()) * self.REWARDS_MULTIPLY_FACTOR
)
else:
return eth_proceeds

def calculate_all_individual_rewards(
self, eth_proceeds: int, locked_ratio: Decimal
) -> int:
if locked_ratio < self.DOUBLING_GLM_SUPPLY_LIMIT:
return int(eth_proceeds * locked_ratio) * self.REWARDS_MULTIPLY_FACTOR
else:
return int(eth_proceeds * self.REWARDS_MULTIPLY_RATIO_LIMIT)
38 changes: 38 additions & 0 deletions backend/app/core/rewards/rewards.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from decimal import Decimal

from app import database
from app.database.models import PendingEpochSnapshot

from app.core.epochs.epochs_registry import EpochsRegistry


def calculate_total_rewards(
eth_proceeds: int, locked_ratio: Decimal, pending_epoch: int
) -> int:
registry = EpochsRegistry.get_epoch_settings(pending_epoch)
return registry.rewardsStrategy.calculate_total_rewards(eth_proceeds, locked_ratio)


def calculate_all_individual_rewards(
eth_proceeds: int, locked_ratio: Decimal, pending_epoch: int
) -> int:
registry = EpochsRegistry.get_epoch_settings(pending_epoch)
return registry.rewardsStrategy.calculate_all_individual_rewards(
eth_proceeds, locked_ratio
)


def calculate_matched_rewards(snapshot: PendingEpochSnapshot) -> int:
return int(snapshot.total_rewards) - int(snapshot.all_individual_rewards)


def get_matched_rewards_from_epoch(epoch: int) -> int:
snapshot = database.pending_epoch_snapshot.get_by_epoch_num(epoch)

return calculate_matched_rewards(snapshot)


def calculate_matched_rewards_threshold(
total_allocated: int, proposals_count: int
) -> int:
return int(total_allocated / (proposals_count * 2))
14 changes: 14 additions & 0 deletions backend/app/core/rewards/rewards_strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from decimal import Decimal
from abc import ABC, abstractmethod


class RewardsStrategy(ABC):
@abstractmethod
def calculate_total_rewards(self, eth_proceeds: int, locked_ratio: Decimal) -> int:
pass

@abstractmethod
def calculate_all_individual_rewards(
self, eth_proceeds: int, locked_ratio: Decimal
) -> int:
pass
12 changes: 12 additions & 0 deletions backend/app/core/rewards/standard_rewards_strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from decimal import Decimal
from app.core.rewards.rewards_strategy import RewardsStrategy


class StandardRewardsStrategy(RewardsStrategy):
def calculate_total_rewards(self, eth_proceeds: int, locked_ratio: Decimal) -> int:
return int(eth_proceeds * locked_ratio.sqrt())

def calculate_all_individual_rewards(
self, eth_proceeds: int, locked_ratio: Decimal
) -> int:
return int(eth_proceeds * locked_ratio)
2 changes: 1 addition & 1 deletion backend/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from app.contracts.vault import Vault
from app.controllers.allocations import allocate
from app.core.allocations import AllocationRequest, Allocation
from app.core.rewards import calculate_matched_rewards
from app.core.rewards.rewards import calculate_matched_rewards
from app.crypto.eip712 import sign, build_allocations_eip712_data
from app.extensions import db, w3
from app.settings import TestConfig
Expand Down
2 changes: 1 addition & 1 deletion backend/tests/test_allocations.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
AllocationRequest,
Allocation,
)
from app.core.rewards import calculate_matched_rewards_threshold
from app.core.rewards.rewards import calculate_matched_rewards_threshold
from app.crypto.eip712 import sign, build_allocations_eip712_data
from app.extensions import db
from tests.conftest import (
Expand Down
66 changes: 51 additions & 15 deletions backend/tests/test_rewards.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from app.core.allocations import (
AllocationRequest,
)
from app.core.rewards import (
from app.core.rewards.rewards import (
calculate_total_rewards,
calculate_all_individual_rewards,
get_matched_rewards_from_epoch,
Expand Down Expand Up @@ -43,30 +43,66 @@ def before(


@pytest.mark.parametrize(
"eth_proceeds,locked_ratio,expected",
"eth_proceeds,locked_ratio,pending_epoch,expected",
[
(4_338473610_477382755, Decimal("0.0000004"), 2743891_635528535),
(600_000000000_000000000, Decimal("0.0003298799699"), 10_897558862_607717064),
(10_000000000_000000000, Decimal("0.43"), 6_557438524_302000652),
(1200_000000000_000000000, Decimal("1"), 1200_000000000_000000000),
(4_338473610_477382755, Decimal("0.0000004"), 1, 5487783_271057070),
(4_338473610_477382755, Decimal("0.0000004"), 2, 2743891_635528535),
(
600_000000000_000000000,
Decimal("0.0003298799699"),
1,
21_795117725_215434128,
),
(
600_000000000_000000000,
Decimal("0.0003298799699"),
2,
10_897558862_607717064,
),
(10_000000000_000000000, Decimal("0.2"), 1, 8_944271909_999158784),
(10_000000000_000000000, Decimal("0.2"), 2, 4472135954999579392),
(10_000000000_000000000, Decimal("0.2"), 3, 4472135954999579392),
(10_000000000_000000000, Decimal("0.25"), 1, 10_000000000_000000000),
(10_000000000_000000000, Decimal("0.25"), 2, 5_000000000_000000000),
(10_000000000_000000000, Decimal("0.25"), 3, 5_000000000_000000000),
(10_000000000_000000000, Decimal("0.43"), 1, 10_000000000_000000000),
(10_000000000_000000000, Decimal("0.43"), 2, 6_557438524_302000652),
(10_000000000_000000000, Decimal("0.43"), 3, 6_557438524_302000652),
(1200_000000000_000000000, Decimal("1"), 1, 1200_000000000_000000000),
(1200_000000000_000000000, Decimal("1"), 2, 1200_000000000_000000000),
(1200_000000000_000000000, Decimal("1"), 3, 1200_000000000_000000000),
],
)
def test_calculate_total_rewards(eth_proceeds, locked_ratio, expected):
result = calculate_total_rewards(eth_proceeds, locked_ratio)
def test_calculate_total_rewards(eth_proceeds, locked_ratio, pending_epoch, expected):
result = calculate_total_rewards(eth_proceeds, locked_ratio, pending_epoch)
assert result == expected


@pytest.mark.parametrize(
"eth_proceeds,locked_ratio,expected",
"eth_proceeds,locked_ratio,pending_epoch,expected",
[
(4_338473610_477382755, Decimal("0.0000004"), 1735_389444190),
(600_000000000_000000000, Decimal("0.0003298799699"), 197927981_940000000),
(10_000000000_000000000, Decimal("0.43"), 4_300000000_000000000),
(1200_000000000_000000000, Decimal("1"), 1200_000000000_000000000),
(4_338473610_477382755, Decimal("0.0000004"), 1, 3470_778888380),
(4_338473610_477382755, Decimal("0.0000004"), 2, 1735_389444190),
(600_000000000_000000000, Decimal("0.0003298799699"), 1, 395855963_880000000),
(600_000000000_000000000, Decimal("0.0003298799699"), 2, 197927981_940000000),
(10_000000000_000000000, Decimal("0.2"), 1, 4_000000000_000000000),
(10_000000000_000000000, Decimal("0.2"), 2, 2_000000000_000000000),
(10_000000000_000000000, Decimal("0.2"), 3, 2_000000000_000000000),
(10_000000000_000000000, Decimal("0.25"), 1, 5_000000000_000000000),
(10_000000000_000000000, Decimal("0.25"), 2, 2_500000000_000000000),
(10_000000000_000000000, Decimal("0.25"), 3, 2_500000000_000000000),
(10_000000000_000000000, Decimal("0.43"), 1, 5_000000000_000000000),
(10_000000000_000000000, Decimal("0.43"), 2, 4_300000000_000000000),
(10_000000000_000000000, Decimal("0.43"), 3, 4_300000000_000000000),
(1200_000000000_000000000, Decimal("1"), 1, 600_000000000_000000000),
(1200_000000000_000000000, Decimal("1"), 2, 1200_000000000_000000000),
(1200_000000000_000000000, Decimal("1"), 3, 1200_000000000_000000000),
],
)
def test_calculate_all_individual_rewards(eth_proceeds, locked_ratio, expected):
result = calculate_all_individual_rewards(eth_proceeds, locked_ratio)
def test_calculate_all_individual_rewards(
eth_proceeds, locked_ratio, pending_epoch, expected
):
result = calculate_all_individual_rewards(eth_proceeds, locked_ratio, pending_epoch)
assert result == expected


Expand Down

0 comments on commit e2a2e77

Please sign in to comment.