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

Add support for rari fuse pools #43

Merged
merged 1 commit into from
Jan 10, 2022
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ docker-compose -f docker-compose.yml up -d
| AWS_SECRET_ACCESS_KEY | The AWS secret access key used to make the oracle vote public | Yes | - |
| STAKEWISE_SUBGRAPH_URL | The StakeWise subgraph URL | No | https://api.thegraph.com/subgraphs/name/stakewise/stakewise-mainnet |
| UNISWAP_V3_SUBGRAPH_URL | The Uniswap V3 subgraph URL | No | https://api.thegraph.com/subgraphs/name/stakewise/uniswap-v3-mainnet |
| RARI_FUSE_SUBGRAPH_URL | Rari Capital Fuse subgraph URL | No | https://api.thegraph.com/subgraphs/name/stakewise/rari-fuse-mainnet |
| ETHEREUM_SUBGRAPH_URL | The Ethereum subgraph URL | No | https://api.thegraph.com/subgraphs/name/stakewise/ethereum-mainnet |
| ORACLE_PROCESS_INTERVAL | How long to wait before processing again (in seconds) | No | 180 |
| ETH1_CONFIRMATION_BLOCKS | The required number of ETH1 confirmation blocks used to fetch the data | No | 15 |
Expand Down
1 change: 1 addition & 0 deletions deploy/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ AWS_SECRET_ACCESS_KEY=""
# STAKEWISE_SUBGRAPH_URL=http://graph-node:8000/subgraphs/name/stakewise/stakewise
# UNISWAP_V3_SUBGRAPH_URL=http://graph-node:8000/subgraphs/name/stakewise/uniswap-v3
# ETHEREUM_SUBGRAPH_URL=http://graph-node:8000/subgraphs/name/stakewise/ethereum
# RARI_FUSE_SUBGRAPH_URL=http://graph-node:8000/subgraphs/name/stakewise/rari-fuse

# KEEPER
WEB3_ENDPOINT=""
Expand Down
11 changes: 11 additions & 0 deletions oracle/oracle/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
ETHEREUM_SUBGRAPH_URL,
IPFS_FETCH_ENDPOINTS,
IPFS_PIN_ENDPOINTS,
RARI_FUSE_SUBGRAPH_URL,
STAKEWISE_SUBGRAPH_URL,
UNISWAP_V3_SUBGRAPH_URL,
)
Expand Down Expand Up @@ -58,6 +59,16 @@ async def execute_ethereum_gql_query(query: DocumentNode, variables: Dict) -> Di
return await session.execute(query, variable_values=variables)


@backoff.on_exception(backoff.expo, Exception, max_time=300, logger=gql_logger)
async def execute_rari_fuse_pools_gql_query(
query: DocumentNode, variables: Dict
) -> Dict:
"""Executes GraphQL query."""
transport = AIOHTTPTransport(url=RARI_FUSE_SUBGRAPH_URL)
async with Client(transport=transport, execute_timeout=EXECUTE_TIMEOUT) as session:
return await session.execute(query, variable_values=variables)


@backoff.on_exception(backoff.expo, Exception, max_time=900)
async def ipfs_fetch(ipfs_hash: str) -> Union[Dict[Any, Any], List[Dict[Any, Any]]]:
"""Tries to fetch IPFS hash from different sources."""
Expand Down
13 changes: 10 additions & 3 deletions oracle/oracle/distributor/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ async def process(self, voting_params: DistributorVotingParameters) -> None:
current_nonce = voting_params["rewards_nonce"]

# skip submitting vote if too early or vote has been already submitted
if to_block <= last_updated_at_block or self.last_to_block == to_block:
if (
to_block <= last_updated_at_block
or self.last_to_block == to_block
or from_block >= to_block
):
return

logger.info(
Expand All @@ -71,6 +75,7 @@ async def process(self, voting_params: DistributorVotingParameters) -> None:
disabled_stakers_distributions = (
await get_disabled_stakers_reward_eth_distributions(
distributor_reward=voting_params["distributor_reward"],
from_block=from_block,
to_block=to_block,
)
)
Expand Down Expand Up @@ -102,7 +107,8 @@ async def process(self, voting_params: DistributorVotingParameters) -> None:
for dist in all_distributions:
distributor_rewards = DistributorRewards(
uniswap_v3_pools=uniswap_v3_pools,
block_number=dist["block_number"],
from_block=dist["from_block"],
to_block=dist["to_block"],
reward_token=dist["reward_token"],
uni_v3_token=dist["uni_v3_token"],
swise_holders=swise_holders,
Expand Down Expand Up @@ -131,7 +137,8 @@ async def process(self, voting_params: DistributorVotingParameters) -> None:
swise_holders_rewards = await DistributorRewards(
uniswap_v3_pools=uniswap_v3_pools,
swise_holders=swise_holders,
block_number=to_block,
from_block=from_block,
to_block=to_block,
uni_v3_token=SWISE_TOKEN_CONTRACT_ADDRESS,
reward_token=REWARD_ETH_TOKEN_CONTRACT_ADDRESS,
).get_rewards(SWISE_TOKEN_CONTRACT_ADDRESS, left_reward)
Expand Down
5 changes: 3 additions & 2 deletions oracle/oracle/distributor/eth1.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ async def get_periodic_allocations(

@backoff.on_exception(backoff.expo, Exception, max_time=900)
async def get_disabled_stakers_reward_eth_distributions(
distributor_reward: Wei, to_block: BlockNumber
distributor_reward: Wei, from_block: BlockNumber, to_block: BlockNumber
) -> Distributions:
"""Fetches disabled stakers reward ETH distributions based on their staked ETH balances."""
if distributor_reward <= 0:
Expand Down Expand Up @@ -149,7 +149,8 @@ async def get_disabled_stakers_reward_eth_distributions(

distribution = Distribution(
contract=staker_address,
block_number=to_block,
from_block=from_block,
to_block=to_block,
uni_v3_token=STAKED_ETH_TOKEN_CONTRACT_ADDRESS,
reward_token=REWARD_ETH_TOKEN_CONTRACT_ADDRESS,
reward=reward,
Expand Down
70 changes: 70 additions & 0 deletions oracle/oracle/distributor/rari.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from typing import Dict

import backoff
from ens.constants import EMPTY_ADDR_HEX
from eth_typing import BlockNumber, ChecksumAddress
from web3 import Web3

from oracle.oracle.clients import execute_rari_fuse_pools_gql_query

from ..graphql_queries import RARI_FUSE_POOLS_CTOKENS_QUERY
from .types import Balances


@backoff.on_exception(backoff.expo, Exception, max_time=900)
async def get_rari_fuse_liquidity_points(
ctoken_address: ChecksumAddress, from_block: BlockNumber, to_block: BlockNumber
) -> Balances:
"""Fetches Rari Fuse pools."""
lowered_ctoken_address = ctoken_address.lower()
last_id = ""
result: Dict = await execute_rari_fuse_pools_gql_query(
query=RARI_FUSE_POOLS_CTOKENS_QUERY,
variables=dict(
ctoken_address=lowered_ctoken_address,
block_number=to_block,
last_id=last_id,
),
)
positions_chunk = result.get("accountCTokens", [])
positions = positions_chunk

# accumulate chunks of positions
while len(positions_chunk) >= 1000:
last_id = positions_chunk[-1]["id"]
result: Dict = await execute_rari_fuse_pools_gql_query(
query=RARI_FUSE_POOLS_CTOKENS_QUERY,
variables=dict(
ctoken_address=lowered_ctoken_address,
block_number=to_block,
last_id=last_id,
),
)
positions_chunk = result.get("accountCTokens", [])
positions.extend(positions_chunk)

# process fuse pools balances
points: Dict[ChecksumAddress, int] = {}
total_points = 0
for position in positions:
account = Web3.toChecksumAddress(position["account"])
if account == EMPTY_ADDR_HEX:
continue

principal = int(position["cTokenBalance"])
prev_account_points = int(position["distributorPoints"])
updated_at_block = BlockNumber(int(position["updatedAtBlock"]))
if from_block > updated_at_block:
updated_at_block = from_block
prev_account_points = 0

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

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

return Balances(total_supply=total_points, balances=points)
28 changes: 21 additions & 7 deletions oracle/oracle/distributor/rewards.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

from oracle.oracle.settings import (
DISTRIBUTOR_FALLBACK_ADDRESS,
RARI_FUSE_POOL_ADDRESSES,
REWARD_ETH_TOKEN_CONTRACT_ADDRESS,
STAKED_ETH_TOKEN_CONTRACT_ADDRESS,
SWISE_TOKEN_CONTRACT_ADDRESS,
)

from .rari import get_rari_fuse_liquidity_points
from .types import Balances, Rewards, UniswapV3Pools
from .uniswap_v3 import (
get_uniswap_v3_liquidity_points,
Expand All @@ -26,7 +28,8 @@ class DistributorRewards(object):
def __init__(
self,
uniswap_v3_pools: UniswapV3Pools,
block_number: BlockNumber,
from_block: BlockNumber,
to_block: BlockNumber,
reward_token: ChecksumAddress,
uni_v3_token: ChecksumAddress,
swise_holders: Balances,
Expand All @@ -37,7 +40,8 @@ def __init__(
self.uni_v3_pools = self.uni_v3_swise_pools.union(
self.uni_v3_staked_eth_pools
).union(self.uni_v3_reward_eth_pools)
self.block_number = block_number
self.from_block = from_block
self.to_block = to_block
self.uni_v3_token = uni_v3_token
self.reward_token = reward_token
self.swise_holders = swise_holders
Expand All @@ -47,6 +51,7 @@ def is_supported_contract(self, contract_address: ChecksumAddress) -> bool:
return (
contract_address in self.uni_v3_pools
or contract_address == SWISE_TOKEN_CONTRACT_ADDRESS
or contract_address in RARI_FUSE_POOL_ADDRESSES
)

@staticmethod
Expand Down Expand Up @@ -110,7 +115,7 @@ async def get_balances(self, contract_address: ChecksumAddress) -> Balances:
return await get_uniswap_v3_single_token_balances(
pool_address=contract_address,
token=STAKED_ETH_TOKEN_CONTRACT_ADDRESS,
block_number=self.block_number,
block_number=self.to_block,
)
elif (
self.uni_v3_token == REWARD_ETH_TOKEN_CONTRACT_ADDRESS
Expand All @@ -120,7 +125,7 @@ async def get_balances(self, contract_address: ChecksumAddress) -> Balances:
return await get_uniswap_v3_single_token_balances(
pool_address=contract_address,
token=REWARD_ETH_TOKEN_CONTRACT_ADDRESS,
block_number=self.block_number,
block_number=self.to_block,
)
elif (
self.uni_v3_token == SWISE_TOKEN_CONTRACT_ADDRESS
Expand All @@ -130,7 +135,7 @@ async def get_balances(self, contract_address: ChecksumAddress) -> Balances:
return await get_uniswap_v3_single_token_balances(
pool_address=contract_address,
token=SWISE_TOKEN_CONTRACT_ADDRESS,
block_number=self.block_number,
block_number=self.to_block,
)
elif (
self.uni_v3_token == EMPTY_ADDR_HEX
Expand All @@ -143,15 +148,24 @@ async def get_balances(self, contract_address: ChecksumAddress) -> Balances:
tick_lower=-887220,
tick_upper=887220,
pool_address=contract_address,
block_number=self.block_number,
block_number=self.to_block,
)
elif contract_address in self.uni_v3_pools:
logger.info(
f"Fetching Uniswap V3 liquidity points: pool={contract_address}"
)
return await get_uniswap_v3_liquidity_points(
pool_address=contract_address,
block_number=self.block_number,
block_number=self.to_block,
)
elif contract_address in RARI_FUSE_POOL_ADDRESSES:
logger.info(
f"Fetching Rari Fuse Pool liquidity points: pool={contract_address}"
)
return await get_rari_fuse_liquidity_points(
ctoken_address=contract_address,
from_block=self.from_block,
to_block=self.to_block,
)
elif contract_address == SWISE_TOKEN_CONTRACT_ADDRESS:
logger.info("Distributing rewards to SWISE holders")
Expand Down
3 changes: 2 additions & 1 deletion oracle/oracle/distributor/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class DistributorVotingParameters(TypedDict):

class Distribution(TypedDict):
contract: ChecksumAddress
block_number: BlockNumber
from_block: BlockNumber
to_block: BlockNumber
uni_v3_token: ChecksumAddress
reward_token: ChecksumAddress
reward: int
Expand Down
8 changes: 5 additions & 3 deletions oracle/oracle/distributor/uniswap_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,24 +125,26 @@ async def get_uniswap_v3_distributions(
if reward > 0:
distribution = Distribution(
contract=pool_address,
block_number=BlockNumber(start + interval),
from_block=start,
to_block=BlockNumber(start + interval),
reward_token=allocation["reward_token"],
reward=reward,
uni_v3_token=EMPTY_ADDR_HEX,
)
distributions.append(distribution)
break

start += BLOCKS_INTERVAL
if interval_reward > 0:
distribution = Distribution(
contract=pool_address,
block_number=start,
from_block=start,
to_block=BlockNumber(start + BLOCKS_INTERVAL),
reward_token=allocation["reward_token"],
reward=interval_reward,
uni_v3_token=EMPTY_ADDR_HEX,
)
distributions.append(distribution)
start += BLOCKS_INTERVAL

return distributions

Expand Down
24 changes: 24 additions & 0 deletions oracle/oracle/graphql_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,30 @@
"""
)

RARI_FUSE_POOLS_CTOKENS_QUERY = gql(
"""
query getCTokens(
$block_number: Int
$ctoken_address: Bytes
$last_id: ID
) {
accountCTokens(
block: { number: $block_number }
where: { ctoken: $ctoken_address, id_gt: $last_id }
first: 1000
orderBy: id
orderDirection: asc
) {
id
account
cTokenBalance
distributorPoints
updatedAtBlock
}
}
"""
)

DISTRIBUTOR_CLAIMED_ACCOUNTS_QUERY = gql(
"""
query getDistributorClaims($merkle_root: Bytes, $last_id: ID) {
Expand Down
10 changes: 10 additions & 0 deletions oracle/oracle/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@
DISTRIBUTOR_FALLBACK_ADDRESS = Web3.toChecksumAddress(
"0x144a98cb1CdBb23610501fE6108858D9B7D24934"
)
RARI_FUSE_POOL_ADDRESSES = [
Web3.toChecksumAddress("0x18F49849D20Bc04059FE9d775df9a38Cd1f5eC9F"),
Web3.toChecksumAddress("0x83d534Ab1d4002249B0E6d22410b62CF31978Ca2"),
]
WITHDRAWAL_CREDENTIALS: HexStr = HexStr(
"0x0100000000000000000000002296e122c1a20fca3cac3371357bdad3be0df079"
)
Expand All @@ -78,6 +82,10 @@
"ETHEREUM_SUBGRAPH_URL",
default="https://api.thegraph.com/subgraphs/name/stakewise/ethereum-mainnet",
)
RARI_FUSE_SUBGRAPH_URL = config(
"RARI_FUSE_SUBGRAPH_URL",
default="https://api.thegraph.com/subgraphs/name/stakewise/rari-fuse-mainnet",
)
elif NETWORK == GOERLI:
SYNC_PERIOD = timedelta(hours=1)
SWISE_TOKEN_CONTRACT_ADDRESS = Web3.toChecksumAddress(
Expand All @@ -92,6 +100,7 @@
DISTRIBUTOR_FALLBACK_ADDRESS = Web3.toChecksumAddress(
"0x1867c96601bc5fE24F685d112314B8F3Fe228D5A"
)
RARI_FUSE_POOL_ADDRESSES = []
WITHDRAWAL_CREDENTIALS: HexStr = HexStr(
"0x010000000000000000000000040f15c6b5bfc5f324ecab5864c38d4e1eef4218"
)
Expand All @@ -107,3 +116,4 @@
"ETHEREUM_SUBGRAPH_URL",
default="https://api.thegraph.com/subgraphs/name/stakewise/ethereum-goerli",
)
RARI_FUSE_SUBGRAPH_URL = ""