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

Update operator rewards #164

Merged
merged 3 commits into from
Dec 16, 2024
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
26 changes: 8 additions & 18 deletions oracle/networks.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@
"0x144a98cb1CdBb23610501fE6108858D9B7D24934"
),
ORACLE_PRIVATE_KEY=config("ORACLE_PRIVATE_KEY", default=""),
ORACLE_STAKEWISE_OPERATOR=Web3.toChecksumAddress(
"0x5fc60576b92c5ce5c341c43e3b2866eb9e0cddd1"
OPERATOR_ADDRESS=Web3.toChecksumAddress(
"0xf330b5fE72E91d1a3782E65eED876CF3624c7802"
),
WITHDRAWALS_GENESIS_EPOCH=194048,
AWS_BUCKET_NAME=config("AWS_BUCKET_NAME", default="oracle-votes-mainnet"),
Expand All @@ -75,11 +75,6 @@
SYNC_PERIOD=timedelta(days=1),
IS_POA=False,
DEPOSIT_TOKEN_SYMBOL="ETH",
VALIDATORS_SPLIT={
Web3.toChecksumAddress("0xfe26832d3580e0ade4813f9e60e7c17b45e92cba"): 64,
Web3.toChecksumAddress("0x59ecf48345a221e0731e785ed79ed40d0a94e2a5"): 63,
Web3.toChecksumAddress("0x01f26d7f195a37d368cb772ed75ef70dd29700f5"): 64,
},
),
HARBOUR_MAINNET: dict(
STAKEWISE_SUBGRAPH_URLS=config(
Expand Down Expand Up @@ -117,7 +112,7 @@
"0x6C7692dB59FDC7A659208EEE57C2c876aE54a448"
),
ORACLE_PRIVATE_KEY=config("ORACLE_PRIVATE_KEY", default=""),
ORACLE_STAKEWISE_OPERATOR=EMPTY_ADDR_HEX,
OPERATOR_ADDRESS=EMPTY_ADDR_HEX,
WITHDRAWALS_GENESIS_EPOCH=194048,
AWS_BUCKET_NAME=config(
"AWS_BUCKET_NAME",
Expand All @@ -140,7 +135,6 @@
SYNC_PERIOD=timedelta(days=1),
IS_POA=False,
DEPOSIT_TOKEN_SYMBOL="ETH",
VALIDATORS_SPLIT={},
),
GOERLI: dict(
STAKEWISE_SUBGRAPH_URLS=config(
Expand Down Expand Up @@ -178,7 +172,7 @@
"0x1867c96601bc5fE24F685d112314B8F3Fe228D5A"
),
ORACLE_PRIVATE_KEY=config("ORACLE_PRIVATE_KEY", default=""),
ORACLE_STAKEWISE_OPERATOR=EMPTY_ADDR_HEX,
OPERATOR_ADDRESS=EMPTY_ADDR_HEX,
WITHDRAWALS_GENESIS_EPOCH=162304,
AWS_BUCKET_NAME=config("AWS_BUCKET_NAME", default="oracle-votes-goerli"),
AWS_REGION=config("AWS_REGION", default="eu-central-1"),
Expand All @@ -198,7 +192,6 @@
SYNC_PERIOD=timedelta(hours=1),
IS_POA=True,
DEPOSIT_TOKEN_SYMBOL="ETH",
VALIDATORS_SPLIT={},
),
HARBOUR_GOERLI: dict(
STAKEWISE_SUBGRAPH_URLS=config(
Expand Down Expand Up @@ -236,7 +229,7 @@
"0x66D6c253084d8d51c7CFfDb3C188A0b53D998a3d"
),
ORACLE_PRIVATE_KEY=config("ORACLE_PRIVATE_KEY", default=""),
ORACLE_STAKEWISE_OPERATOR=EMPTY_ADDR_HEX,
OPERATOR_ADDRESS=EMPTY_ADDR_HEX,
WITHDRAWALS_GENESIS_EPOCH=162304,
AWS_BUCKET_NAME=config(
"AWS_BUCKET_NAME",
Expand All @@ -259,7 +252,6 @@
SYNC_PERIOD=timedelta(days=1),
IS_POA=True,
DEPOSIT_TOKEN_SYMBOL="ETH",
VALIDATORS_SPLIT={},
),
GNOSIS_CHAIN: dict(
STAKEWISE_SUBGRAPH_URLS=config(
Expand Down Expand Up @@ -297,7 +289,9 @@
"0x8737f638E9af54e89ed9E1234dbC68B115CD169e"
),
ORACLE_PRIVATE_KEY=config("ORACLE_PRIVATE_KEY", default=""),
ORACLE_STAKEWISE_OPERATOR=EMPTY_ADDR_HEX,
OPERATOR_ADDRESS=Web3.toChecksumAddress(
"0x6Da6B1EfCCb7216078B9004535941b71EeD30b0F"
),
WITHDRAWALS_GENESIS_EPOCH=648704,
AWS_BUCKET_NAME=config("AWS_BUCKET_NAME", default="oracle-votes-gnosis"),
AWS_REGION=config("AWS_REGION", default="eu-north-1"),
Expand All @@ -317,9 +311,5 @@
SYNC_PERIOD=timedelta(days=1),
IS_POA=True,
DEPOSIT_TOKEN_SYMBOL="GNO",
VALIDATORS_SPLIT={
Web3.toChecksumAddress("0x59ecf48345a221e0731e785ed79ed40d0a94e2a5"): 4971,
Web3.toChecksumAddress("0xf37c8f35fc820354b402054699610c098559ae44"): 4971,
},
),
}
28 changes: 0 additions & 28 deletions oracle/oracle/common/graphql_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,31 +341,3 @@
}
"""
)

OPERATORS_REWARDS_QUERY = gql(
"""
query getOperatorsRewards($block_number: Int) {
operators(block: { number: $block_number }) {
id
validatorsCount
revenueShare
distributorPoints
updatedAtBlock
}
}
"""
)

PARTNERS_QUERY = gql(
"""
query getPartners($block_number: Int) {
partners(block: { number: $block_number }) {
id
contributedAmount
revenueShare
distributorPoints
updatedAtBlock
}
}
"""
)
166 changes: 12 additions & 154 deletions oracle/oracle/distributor/common/eth1.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
DISABLED_STAKER_ACCOUNTS_QUERY,
DISTRIBUTOR_CLAIMED_ACCOUNTS_QUERY,
ONE_TIME_DISTRIBUTIONS_QUERY,
OPERATORS_REWARDS_QUERY,
PARTNERS_QUERY,
PERIODIC_DISTRIBUTIONS_QUERY,
)
from oracle.oracle.distributor.common.ipfs import get_one_time_rewards_allocations
Expand Down Expand Up @@ -162,171 +160,31 @@ async def get_distributor_claimed_accounts(


async def get_operators_rewards(
network: str,
from_block: BlockNumber,
to_block: BlockNumber,
total_reward: Wei,
operator_address: ChecksumAddress,
reward_token_address: ChecksumAddress,
validators_split: dict,
) -> Tuple[Rewards, Wei]:
"""Fetches operators rewards."""
result: Dict = await execute_sw_gql_query(
network=network,
query=OPERATORS_REWARDS_QUERY,
variables=dict(
block_number=to_block,
),
)
operators = result["operators"]

# process operators
points: Dict[ChecksumAddress, int] = {}
total_points = 0
total_validators = 0
for operator in operators:
account = Web3.toChecksumAddress(operator["id"])
if account == EMPTY_ADDR_HEX:
continue

validators_count = int(operator["validatorsCount"]) + validators_split.get(
account, 0
)
total_validators += validators_count

revenue_share = int(operator["revenueShare"])
prev_account_points = int(operator["distributorPoints"])
updated_at_block = BlockNumber(int(operator["updatedAtBlock"]))
if from_block > updated_at_block:
updated_at_block = from_block
prev_account_points = 0

account_points = prev_account_points + (
validators_count * revenue_share * (to_block - updated_at_block)
)
if account_points <= 0:
continue

points[account] = points.get(account, 0) + account_points
total_points += account_points

if total_validators <= 0:
"""Send half of rewards to a single operator address."""
if operator_address == EMPTY_ADDR_HEX:
logger.error("Invalid operator address")
return {}, total_reward

operators_reward = Wei(
(total_reward * total_points)
// (total_validators * 10000 * (to_block - from_block))
)
operators_reward = Wei(total_reward // 2)

if operators_reward <= 0:
return {}, total_reward

operators_reward = min(total_reward, operators_reward)
rewards = calculate_points_based_rewards(
total_reward=operators_reward,
points=points,
total_points=total_points,
reward_token=reward_token_address,
)

return rewards, Wei(total_reward - operators_reward)


async def get_partners_rewards(
network: str,
from_block: BlockNumber,
to_block: BlockNumber,
total_reward: Wei,
reward_token_address: ChecksumAddress,
) -> Tuple[Rewards, Wei]:
"""Fetches partners rewards."""
result: Dict = await execute_sw_gql_query(
network=network,
query=PARTNERS_QUERY,
variables=dict(
block_number=to_block,
),
)
partners = result["partners"]

# process partners
points: Dict[ChecksumAddress, int] = {}
total_points = 0
total_contributed = 0
for partner in partners:
account = Web3.toChecksumAddress(partner["id"])
if account == EMPTY_ADDR_HEX:
continue

contributed_amount = Wei(int(partner["contributedAmount"]))
total_contributed += contributed_amount

revenue_share = int(partner["revenueShare"])
prev_account_points = int(partner["distributorPoints"])
updated_at_block = BlockNumber(int(partner["updatedAtBlock"]))
if from_block > updated_at_block:
updated_at_block = from_block
prev_account_points = 0

account_points = prev_account_points + (
contributed_amount * revenue_share * (to_block - updated_at_block)
)
if account_points <= 0:
continue

points[account] = account_points
total_points += account_points

if total_contributed <= 0:
return {}, total_reward

partners_reward = Wei(
(total_reward * total_points)
// (total_contributed * 10000 * (to_block - from_block))
)
if partners_reward <= 0:
return {}, total_reward

partners_reward = min(total_reward, partners_reward)
rewards = calculate_points_based_rewards(
total_reward=partners_reward,
points=points,
total_points=total_points,
rewards: Rewards = {}
DistributorRewards.add_value(
rewards=rewards,
to=operator_address,
reward_token=reward_token_address,
amount=operators_reward,
)

return rewards, Wei(total_reward - partners_reward)


def calculate_points_based_rewards(
total_reward: int,
points: Dict[ChecksumAddress, int],
total_points: int,
reward_token: ChecksumAddress,
) -> Rewards:
"""Calculates points based rewards."""
if total_reward <= 0 or total_points <= 0:
return {}

rewards: Rewards = {}
last_account_index = len(points) - 1
distributed = 0
for i, account in enumerate(points):
if i == last_account_index:
reward = total_reward - distributed
else:
reward = (total_reward * points[account]) // total_points

if reward <= 0:
continue

DistributorRewards.add_value(
rewards=rewards,
to=account,
reward_token=reward_token,
amount=reward,
)
distributed += reward

return rewards
return rewards, Wei(total_reward - operators_reward)


async def get_one_time_rewards(
Expand Down
16 changes: 3 additions & 13 deletions oracle/oracle/distributor/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
get_distributor_claimed_accounts,
get_one_time_rewards,
get_operators_rewards,
get_partners_rewards,
get_periodic_allocations,
)
from oracle.oracle.distributor.common.merkle_tree import calculate_merkle_root
Expand Down Expand Up @@ -163,20 +162,11 @@ async def process(self, voting_params: DistributorVotingParameters) -> None:

protocol_reward = voting_params["protocol_reward"]
operators_rewards, left_reward = await get_operators_rewards(
network=NETWORK,
from_block=from_block,
to_block=to_block,
total_reward=protocol_reward,
reward_token_address=NETWORK_CONFIG["REWARD_TOKEN_CONTRACT_ADDRESS"],
validators_split=NETWORK_CONFIG["VALIDATORS_SPLIT"],
)
partners_rewards, left_reward = await get_partners_rewards(
network=NETWORK,
from_block=from_block,
to_block=to_block,
total_reward=left_reward,
reward_token_address=NETWORK_CONFIG["REWARD_TOKEN_CONTRACT_ADDRESS"],
operator_address=NETWORK_CONFIG["OPERATOR_ADDRESS"],
)

if left_reward > 0:
fallback_rewards: Rewards = {
self.distributor_fallback_address: {
Expand All @@ -188,7 +178,7 @@ async def process(self, voting_params: DistributorVotingParameters) -> None:
rewards2=fallback_rewards,
)

for rewards in [operators_rewards, partners_rewards]:
for rewards in [operators_rewards]:
final_rewards = DistributorRewards.merge_rewards(final_rewards, rewards)

# merge final rewards with unclaimed rewards
Expand Down
2 changes: 1 addition & 1 deletion oracle/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
IPFS_FETCH_ENDPOINTS = config(
"IPFS_FETCH_ENDPOINTS",
cast=Csv(),
default="http://cloudflare-ipfs.com,https://ipfs.io,https://gateway.pinata.cloud",
default="https://ipfs.io,https://gateway.pinata.cloud",
)

LOCAL_IPFS_CLIENT_ENDPOINT = config("LOCAL_IPFS_CLIENT_ENDPOINT", default="")
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "oracle"
version = "3.3.1"
version = "3.4.0"
description = "StakeWise Oracles are responsible for submitting off-chain data."
authors = ["Dmitri Tsumak <[email protected]>"]
license = "AGPL-3.0-only"
Expand Down
Loading