From eb5caaaa4cf3b08c0831f2beb5be77b13ef6d9e7 Mon Sep 17 00:00:00 2001 From: "kacper.golem" Date: Mon, 23 Sep 2024 10:01:57 +0200 Subject: [PATCH 1/6] OCT-1867: Add an APR value for the server --- backend/app/infrastructure/routes/epochs.py | 26 ++++++++++++++++++- .../app/modules/octant_rewards/controller.py | 6 +++++ backend/app/modules/octant_rewards/core.py | 9 +++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/backend/app/infrastructure/routes/epochs.py b/backend/app/infrastructure/routes/epochs.py index 5f148331a7..fc4b80cec2 100644 --- a/backend/app/infrastructure/routes/epochs.py +++ b/backend/app/infrastructure/routes/epochs.py @@ -3,7 +3,7 @@ from app.extensions import api, epochs from app.infrastructure import OctantResource, graphql -from app.modules.octant_rewards.controller import get_octant_rewards +from app.modules.octant_rewards.controller import get_octant_rewards, get_epoch_apr ns = Namespace("epochs", description="Octant epochs") api.add_namespace(ns) @@ -113,6 +113,14 @@ def get(self): }, ) +epoch_apr_model = api.model( + "EpochAPR", + { + "apr": fields.Float( + required=True, description="APR for the given epoch.") + } +) + @ns.route("/info/") @ns.doc( @@ -131,3 +139,19 @@ def get(self, epoch: int): app.logger.debug(f"Got: {stats}") return stats.to_dict() + + +@ns.route("/apr/") +@ns.doc( + description="Returns APR for a given epoch. Returns data for all states of epochs.", + params={ + "epoch": "Epoch number", + }, +) +class EpochAPR(OctantResource): + @ns.marshal_with(epoch_apr_model) + @ns.response(200, "Epoch's APR successfully retrieved.") + def get(self, epoch: int): + app.logger.debug("Getting APR for epoch") + return {"apr": get_epoch_apr(epoch)} + diff --git a/backend/app/modules/octant_rewards/controller.py b/backend/app/modules/octant_rewards/controller.py index b6cdd22cb0..c4630b121f 100644 --- a/backend/app/modules/octant_rewards/controller.py +++ b/backend/app/modules/octant_rewards/controller.py @@ -3,6 +3,7 @@ from app.exceptions import NotImplementedForGivenEpochState from app.modules.dto import OctantRewardsDTO from app.modules.registry import get_services +from app.modules.octant_rewards import core def get_octant_rewards(epoch_num: int) -> OctantRewardsDTO: @@ -24,3 +25,8 @@ def get_last_finalized_epoch_leverage() -> float: service = get_services(context.epoch_state).octant_rewards_service return service.get_leverage(context) + + +def get_epoch_apr(epoch_num: int) -> float: + context = epoch_context(epoch_num) + return core.get_epoch_apr(context.epoch_details.epoch_num) diff --git a/backend/app/modules/octant_rewards/core.py b/backend/app/modules/octant_rewards/core.py index f6cb96d699..6956a78bfd 100644 --- a/backend/app/modules/octant_rewards/core.py +++ b/backend/app/modules/octant_rewards/core.py @@ -7,6 +7,7 @@ from app.engine.octant_rewards.operational_cost import OperationalCostPayload from app.engine.octant_rewards.ppf import PPFPayload from app.engine.octant_rewards.total_and_individual import TotalAndAllIndividualPayload +from app.modules.staking.proceeds.core import ESTIMATED_STAKING_APR @dataclass @@ -66,3 +67,11 @@ def calculate_rewards( ppf_value=ppf_value, community_fund=cf_value, ) + + +def get_epoch_apr(_: int) -> float: + """ + Returns the APR for the given epoch. + """ + # TODO APR is a static value for now but it may be calculated dynamically in the future: https://linear.app/golemfoundation/issue/OCT-1916/make-apr-a-dynamically-computed-one + return ESTIMATED_STAKING_APR From d8cd71f91ca057cb942d29bff2175339a5911eba Mon Sep 17 00:00:00 2001 From: "kacper.golem" Date: Mon, 23 Sep 2024 10:04:14 +0200 Subject: [PATCH 2/6] refactor: improve cq --- .../tests/modules/octant_rewards/test_core.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 backend/tests/modules/octant_rewards/test_core.py diff --git a/backend/tests/modules/octant_rewards/test_core.py b/backend/tests/modules/octant_rewards/test_core.py new file mode 100644 index 0000000000..32c32411cd --- /dev/null +++ b/backend/tests/modules/octant_rewards/test_core.py @@ -0,0 +1,17 @@ +import pytest + +from app.modules.octant_rewards.core import get_epoch_apr +from app.modules.staking.proceeds.core import ESTIMATED_STAKING_APR + + +@pytest.fixture(autouse=True) +def before(app): + pass + + +@pytest.mark.parametrize("epoch_num", [1, 2, 3, 4, 5]) +def test_get_epoch_apr_return_valid_value(epoch_num: int): + actual_result = get_epoch_apr(epoch_num) + expected_result = ESTIMATED_STAKING_APR + + assert actual_result == expected_result From 0ec746342256e3943e933c7e16e6552d990f74f7 Mon Sep 17 00:00:00 2001 From: "kacper.golem" Date: Mon, 23 Sep 2024 10:37:29 +0200 Subject: [PATCH 3/6] refactor: change uts and logging --- backend/app/infrastructure/routes/epochs.py | 8 ++------ .../octant_rewards/{test_core.py => test_apr_core.py} | 0 2 files changed, 2 insertions(+), 6 deletions(-) rename backend/tests/modules/octant_rewards/{test_core.py => test_apr_core.py} (100%) diff --git a/backend/app/infrastructure/routes/epochs.py b/backend/app/infrastructure/routes/epochs.py index fc4b80cec2..56f3c74eb8 100644 --- a/backend/app/infrastructure/routes/epochs.py +++ b/backend/app/infrastructure/routes/epochs.py @@ -115,10 +115,7 @@ def get(self): epoch_apr_model = api.model( "EpochAPR", - { - "apr": fields.Float( - required=True, description="APR for the given epoch.") - } + {"apr": fields.Float(required=True, description="APR for the given epoch.")}, ) @@ -152,6 +149,5 @@ class EpochAPR(OctantResource): @ns.marshal_with(epoch_apr_model) @ns.response(200, "Epoch's APR successfully retrieved.") def get(self, epoch: int): - app.logger.debug("Getting APR for epoch") + app.logger.debug(f"Getting APR for epoch {epoch}") return {"apr": get_epoch_apr(epoch)} - diff --git a/backend/tests/modules/octant_rewards/test_core.py b/backend/tests/modules/octant_rewards/test_apr_core.py similarity index 100% rename from backend/tests/modules/octant_rewards/test_core.py rename to backend/tests/modules/octant_rewards/test_apr_core.py From b61851521516f15e1c3a8d62b590ede4cd33db01 Mon Sep 17 00:00:00 2001 From: "kacper.golem" Date: Mon, 23 Sep 2024 11:17:59 +0200 Subject: [PATCH 4/6] chore: change naming convention --- backend/app/infrastructure/routes/epochs.py | 29 ++++++++++++------- .../app/modules/octant_rewards/controller.py | 4 +-- backend/app/modules/octant_rewards/core.py | 2 +- .../modules/octant_rewards/test_apr_core.py | 6 ++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/backend/app/infrastructure/routes/epochs.py b/backend/app/infrastructure/routes/epochs.py index 56f3c74eb8..1c4b30fca2 100644 --- a/backend/app/infrastructure/routes/epochs.py +++ b/backend/app/infrastructure/routes/epochs.py @@ -3,7 +3,10 @@ from app.extensions import api, epochs from app.infrastructure import OctantResource, graphql -from app.modules.octant_rewards.controller import get_octant_rewards, get_epoch_apr +from app.modules.octant_rewards.controller import ( + get_octant_rewards, + get_epoch_rewards_rate, +) ns = Namespace("epochs", description="Octant epochs") api.add_namespace(ns) @@ -113,9 +116,13 @@ def get(self): }, ) -epoch_apr_model = api.model( - "EpochAPR", - {"apr": fields.Float(required=True, description="APR for the given epoch.")}, +epoch_rewards_rate_model = api.model( + "EpochRewardsRate", + { + "rewardsRate": fields.Float( + required=True, description="Rewards rate for the given epoch." + ) + }, ) @@ -138,16 +145,16 @@ def get(self, epoch: int): return stats.to_dict() -@ns.route("/apr/") +@ns.route("/rewards-rate/") @ns.doc( - description="Returns APR for a given epoch. Returns data for all states of epochs.", + description="Returns a rewards rate for given epoch. Returns data for all states of epochs.", params={ "epoch": "Epoch number", }, ) -class EpochAPR(OctantResource): - @ns.marshal_with(epoch_apr_model) - @ns.response(200, "Epoch's APR successfully retrieved.") +class EpochRewardsRate(OctantResource): + @ns.marshal_with(epoch_rewards_rate_model) + @ns.response(200, "Epoch's rewards rate successfully retrieved.") def get(self, epoch: int): - app.logger.debug(f"Getting APR for epoch {epoch}") - return {"apr": get_epoch_apr(epoch)} + app.logger.debug(f"Getting rewards rate for epoch {epoch}") + return {"rewardsRate": get_epoch_rewards_rate(epoch)} diff --git a/backend/app/modules/octant_rewards/controller.py b/backend/app/modules/octant_rewards/controller.py index c4630b121f..7f92a4ec0d 100644 --- a/backend/app/modules/octant_rewards/controller.py +++ b/backend/app/modules/octant_rewards/controller.py @@ -27,6 +27,6 @@ def get_last_finalized_epoch_leverage() -> float: return service.get_leverage(context) -def get_epoch_apr(epoch_num: int) -> float: +def get_epoch_rewards_rate(epoch_num: int) -> float: context = epoch_context(epoch_num) - return core.get_epoch_apr(context.epoch_details.epoch_num) + return core.get_rewards_rate(context.epoch_details.epoch_num) diff --git a/backend/app/modules/octant_rewards/core.py b/backend/app/modules/octant_rewards/core.py index 6956a78bfd..8b936058fc 100644 --- a/backend/app/modules/octant_rewards/core.py +++ b/backend/app/modules/octant_rewards/core.py @@ -69,7 +69,7 @@ def calculate_rewards( ) -def get_epoch_apr(_: int) -> float: +def get_rewards_rate(_: int) -> float: """ Returns the APR for the given epoch. """ diff --git a/backend/tests/modules/octant_rewards/test_apr_core.py b/backend/tests/modules/octant_rewards/test_apr_core.py index 32c32411cd..96185888b9 100644 --- a/backend/tests/modules/octant_rewards/test_apr_core.py +++ b/backend/tests/modules/octant_rewards/test_apr_core.py @@ -1,6 +1,6 @@ import pytest -from app.modules.octant_rewards.core import get_epoch_apr +from app.modules.octant_rewards.core import get_rewards_rate from app.modules.staking.proceeds.core import ESTIMATED_STAKING_APR @@ -10,8 +10,8 @@ def before(app): @pytest.mark.parametrize("epoch_num", [1, 2, 3, 4, 5]) -def test_get_epoch_apr_return_valid_value(epoch_num: int): - actual_result = get_epoch_apr(epoch_num) +def test_get_epoch_rewards_rate_return_valid_value(epoch_num: int): + actual_result = get_rewards_rate(epoch_num) expected_result = ESTIMATED_STAKING_APR assert actual_result == expected_result From 1d427b1c82a093196997f9ab3571df8c0ae899a7 Mon Sep 17 00:00:00 2001 From: "kacper.golem" Date: Mon, 23 Sep 2024 11:41:57 +0200 Subject: [PATCH 5/6] chore: update docstr --- backend/app/modules/octant_rewards/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/modules/octant_rewards/core.py b/backend/app/modules/octant_rewards/core.py index 8b936058fc..fdda878856 100644 --- a/backend/app/modules/octant_rewards/core.py +++ b/backend/app/modules/octant_rewards/core.py @@ -71,7 +71,7 @@ def calculate_rewards( def get_rewards_rate(_: int) -> float: """ - Returns the APR for the given epoch. + Returns the rewards rate for the given epoch. """ # TODO APR is a static value for now but it may be calculated dynamically in the future: https://linear.app/golemfoundation/issue/OCT-1916/make-apr-a-dynamically-computed-one return ESTIMATED_STAKING_APR From a82c9fc9101cf6e453b6d5cb31a27047c4cc6c18 Mon Sep 17 00:00:00 2001 From: "kacper.golem" Date: Mon, 23 Sep 2024 11:44:05 +0200 Subject: [PATCH 6/6] chore: update vars --- backend/app/modules/octant_rewards/core.py | 6 +++--- backend/app/modules/staking/proceeds/core.py | 6 +++--- backend/tests/modules/octant_rewards/test_apr_core.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/app/modules/octant_rewards/core.py b/backend/app/modules/octant_rewards/core.py index fdda878856..37476b43ce 100644 --- a/backend/app/modules/octant_rewards/core.py +++ b/backend/app/modules/octant_rewards/core.py @@ -7,7 +7,7 @@ from app.engine.octant_rewards.operational_cost import OperationalCostPayload from app.engine.octant_rewards.ppf import PPFPayload from app.engine.octant_rewards.total_and_individual import TotalAndAllIndividualPayload -from app.modules.staking.proceeds.core import ESTIMATED_STAKING_APR +from app.modules.staking.proceeds.core import ESTIMATED_STAKING_REWARDS_RATE @dataclass @@ -73,5 +73,5 @@ def get_rewards_rate(_: int) -> float: """ Returns the rewards rate for the given epoch. """ - # TODO APR is a static value for now but it may be calculated dynamically in the future: https://linear.app/golemfoundation/issue/OCT-1916/make-apr-a-dynamically-computed-one - return ESTIMATED_STAKING_APR + # TODO Staking Rewards Rate is a static value for now but it may be calculated dynamically in the future: https://linear.app/golemfoundation/issue/OCT-1916/make-apr-a-dynamically-computed-one + return ESTIMATED_STAKING_REWARDS_RATE diff --git a/backend/app/modules/staking/proceeds/core.py b/backend/app/modules/staking/proceeds/core.py index 5067607990..3bcb293953 100644 --- a/backend/app/modules/staking/proceeds/core.py +++ b/backend/app/modules/staking/proceeds/core.py @@ -8,17 +8,17 @@ ESTIMATED_STAKED_AMOUNT = 100000_000000000_000000000 # TODO call an API to get a real value instead of hardcoding: https://linear.app/golemfoundation/issue/OCT-902/api-call-to-get-validators-api -ESTIMATED_STAKING_APR = 0.038 +ESTIMATED_STAKING_REWARDS_RATE = 0.038 def estimate_staking_proceeds( epoch_duration_sec: int, staked_amount=ESTIMATED_STAKED_AMOUNT, - apr=ESTIMATED_STAKING_APR, + staking_rewards=ESTIMATED_STAKING_REWARDS_RATE, ) -> int: if epoch_duration_sec <= 0: return 0 - return int(int(staked_amount * apr) / 31536000 * epoch_duration_sec) + return int(int(staked_amount * staking_rewards) / 31536000 * epoch_duration_sec) def sum_mev( diff --git a/backend/tests/modules/octant_rewards/test_apr_core.py b/backend/tests/modules/octant_rewards/test_apr_core.py index 96185888b9..4b27c5b0c1 100644 --- a/backend/tests/modules/octant_rewards/test_apr_core.py +++ b/backend/tests/modules/octant_rewards/test_apr_core.py @@ -1,7 +1,7 @@ import pytest from app.modules.octant_rewards.core import get_rewards_rate -from app.modules.staking.proceeds.core import ESTIMATED_STAKING_APR +from app.modules.staking.proceeds.core import ESTIMATED_STAKING_REWARDS_RATE @pytest.fixture(autouse=True) @@ -12,6 +12,6 @@ def before(app): @pytest.mark.parametrize("epoch_num", [1, 2, 3, 4, 5]) def test_get_epoch_rewards_rate_return_valid_value(epoch_num: int): actual_result = get_rewards_rate(epoch_num) - expected_result = ESTIMATED_STAKING_APR + expected_result = ESTIMATED_STAKING_REWARDS_RATE assert actual_result == expected_result