Skip to content

Commit

Permalink
Merge pull request #31 from stakewise/feature/full-range
Browse files Browse the repository at this point in the history
Implement incentives for full range uni v3 positions
  • Loading branch information
tsudmi authored Nov 21, 2021
2 parents 833d0ae + f727d9c commit fbb5422
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/merkle_distributor/distribution_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
OraclesSettings,
Rewards,
get_uniswap_v3_staked_eth_balances,
get_uniswap_v3_full_range_balances
)

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -72,6 +73,9 @@ def __init__(
self.uniswap_v3_staked_eth_pairs: Set[ChecksumAddress] = oracles_settings[
"uniswap_v3_staked_eth_pairs"
]
self.uniswap_v3_full_range_pairs: Set[ChecksumAddress] = oracles_settings[
"uniswap_v3_full_range_pairs"
]
self.erc20_tokens: Dict[ChecksumAddress, BlockNumber] = oracles_settings[
"erc20_tokens"
]
Expand Down Expand Up @@ -237,6 +241,13 @@ def get_balances(
staked_eth_token_address=self.staked_eth_token_address,
to_block=block_number,
)
elif contract_address in self.uniswap_v3_full_range_pairs:
logger.info(f"Fetching Uniswap V3 infinity positions balances: pool={contract_address}")
return get_uniswap_v3_full_range_balances(
subgraph_url=self.uniswap_v3_subgraph_url,
pool_address=contract_address,
to_block=block_number,
)
elif contract_address in self.uniswap_v3_pairs:
logger.info(f"Fetching Uniswap V3 balances: pool={contract_address}")
return get_uniswap_v3_balances(
Expand Down
104 changes: 104 additions & 0 deletions src/merkle_distributor/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ class OraclesSettings(TypedDict):
# set of Uniswap V3 supported staked ETH pairs
uniswap_v3_staked_eth_pairs: Set[ChecksumAddress]

# set of Uniswap V3 full range pairs
uniswap_v3_full_range_pairs: Set[ChecksumAddress]

# dictionary of supported ERC-20 tokens and the block number when they were created
erc20_tokens: Dict[ChecksumAddress, BlockNumber]

Expand Down Expand Up @@ -334,6 +337,12 @@ def get_oracles_config(
for pair in oracles_settings.get("uniswap_v3_staked_eth_pairs", [])
]
),
uniswap_v3_full_range_pairs=set(
[
Web3.toChecksumAddress(pair)
for pair in oracles_settings.get("uniswap_v3_full_range_pairs", [])
]
),
erc20_tokens={
Web3.toChecksumAddress(token_address): int(block_number)
for token_address, block_number in oracles_settings.get(
Expand Down Expand Up @@ -841,6 +850,101 @@ def get_uniswap_v3_balances(
return account_to_liquidity, total_liquidity


@retry(
reraise=True,
wait=backoff,
stop=stop_attempts,
before_sleep=before_sleep_log(logger, logging.WARNING),
)
def get_uniswap_v3_full_range_balances(
subgraph_url: str, pool_address: ChecksumAddress, to_block: BlockNumber
) -> Tuple[Dict[ChecksumAddress, Wei], Wei]:
"""Fetches balances of the Uniswap V3 positions with full range."""
transport = RequestsHTTPTransport(url=subgraph_url)

# create a GraphQL client using the defined transport
client = Client(transport=transport, fetch_schema_from_transport=False)

# fetch positions that cover the current tick
query = gql(
"""
query getPositions(
$block_number: Int
$pool_address: String
$last_id: ID
) {
positions(
first: 1000
block: { number: $block_number }
where: {
tickLower: -887220
tickUpper: 887220
pool: $pool_address
id_gt: $last_id
}
orderBy: id
orderDirection: asc
) {
owner
liquidity
}
}
"""
)

# execute the query on the transport in chunks of 1000 entities
last_id = ""
result: Dict = execute_graphql_query(
client=client,
query=query,
variables=dict(
block_number=to_block,
pool_address=pool_address.lower(),
last_id=last_id,
),
)
positions_chunk = result.get("positions", [])
positions = positions_chunk

# accumulate chunks
while len(positions_chunk) >= 1000:
last_id = positions_chunk[-1]["id"]
if not last_id:
break

result = execute_graphql_query(
client=client,
query=query,
variables=dict(
block_number=to_block,
pool_address=pool_address.lower(),
last_id=last_id,
),
)
positions_chunk = result.get("positions", [])
positions.extend(positions_chunk)

# process positions
account_to_liquidity: Dict[ChecksumAddress, Wei] = {}
total_liquidity: Wei = Wei(0)
for position in positions:
account: ChecksumAddress = position.get("owner", EMPTY_ADDR_HEX)
if account in (EMPTY_ADDR_HEX, ""):
continue

account = Web3.toChecksumAddress(account)
liquidity: Wei = Wei(int(position.get("liquidity", "0")))
if liquidity <= 0:
continue

account_to_liquidity[account] = Wei(
account_to_liquidity.setdefault(account, Wei(0)) + liquidity
)
total_liquidity += liquidity

return account_to_liquidity, total_liquidity


@retry(
reraise=True,
wait=backoff,
Expand Down

0 comments on commit fbb5422

Please sign in to comment.