async def get_uniswap_v3_range_liquidity_points( network: str, tick_lower: int, tick_upper: int, pool_address: ChecksumAddress, block_number: BlockNumber, ) -> Balances: """Fetches users' liquidity points of the Uniswap V3 pool in the specific range.""" lowered_pool_address = pool_address.lower() last_id = "" result: Dict = await execute_uniswap_v3_gql_query( network=network, query=UNISWAP_V3_RANGE_POSITIONS_QUERY, variables=dict( block_number=block_number, tick_lower=tick_lower, tick_upper=tick_upper, pool_address=lowered_pool_address, last_id=last_id, ), ) positions_chunk = result.get("positions", []) positions = positions_chunk # accumulate chunks of positions while len(positions_chunk) >= 1000: last_id = positions_chunk[-1]["id"] result: Dict = await execute_uniswap_v3_gql_query( network=network, query=UNISWAP_V3_RANGE_POSITIONS_QUERY, variables=dict( block_number=block_number, tick_lower=tick_lower, tick_upper=tick_upper, pool_address=lowered_pool_address, last_id=last_id, ), ) positions_chunk = result.get("positions", []) positions.extend(positions_chunk) # process positions balances: Dict[ChecksumAddress, int] = {} total_supply = 0 for position in positions: account = Web3.toChecksumAddress(position["owner"]) if account == EMPTY_ADDR_HEX: continue liquidity = int(position.get("liquidity", "0")) if liquidity <= 0: continue balances[account] = balances.setdefault(account, 0) + liquidity total_supply += liquidity return Balances(total_supply=total_supply, balances=balances)
def get_token_price(self, token_address: ChecksumAddress) -> float: """ :param token_address: :return: usd price for token address, 0. if not found """ token_address = token_address.lower() url = urljoin(self.base_url, f'api/v3/simple/token_price/ethereum?contract_addresses={token_address}&vs_currencies=usd') return self._get_price(url, token_address)
def test_trace_raw_transaction( self, web3: "Web3", raw_transaction: HexStr, funded_account_for_raw_txn: ChecksumAddress, ) -> None: trace = web3.parity.traceRawTransaction(raw_transaction) assert trace['stateDiff'] is None assert trace['vmTrace'] is None assert trace['trace'][0]['action']['from'] == funded_account_for_raw_txn.lower()
def get_token_info( self, token_address: ChecksumAddress) -> Optional[Dict[str, Any]]: token_address = token_address.lower() url = urljoin( self.base_url, f"api/v3/coins/{self.asset_platform}/contract/{token_address}", ) try: return self._do_request(url) except Coingecko404: return None
def test_trace_raw_transaction( self, web3: "Web3", raw_transaction: HexStr, funded_account_for_raw_txn: ChecksumAddress, ) -> None: # address 0x39EEed73fb1D3855E90Cbd42f348b3D7b340aAA6 raw_transaction = HexStr( '0xf8648085174876e8008252089439eeed73fb1d3855e90cbd42f348b3d7b340aaa601801ba0ec1295f00936acd0c2cb90ab2cdaacb8bf5e11b3d9957833595aca9ceedb7aada05dfc8937baec0e26029057abd3a1ef8c505dca2cdc07ffacb046d090d2bea06a' ) # noqa: E501 trace = web3.parity.trace_raw_transaction(raw_transaction) assert trace['stateDiff'] is None assert trace['vmTrace'] is None assert trace['trace'][0]['action'][ 'from'] == funded_account_for_raw_txn.lower()
def test_eth_sendTransaction_addr_checksum_required( self, web3: "Web3", unlocked_account: ChecksumAddress) -> None: non_checksum_addr = unlocked_account.lower() txn_params = { 'from': unlocked_account, 'to': unlocked_account, 'value': 1, 'gas': 21000, 'gasPrice': web3.eth.gasPrice, } with pytest.raises(InvalidAddress): invalid_params = dict(txn_params, **{'from': non_checksum_addr}) web3.eth.sendTransaction(invalid_params) with pytest.raises(InvalidAddress): invalid_params = dict(txn_params, **{'to': non_checksum_addr}) web3.eth.sendTransaction(invalid_params)
async def get_uniswap_v3_single_token_balances( network: str, pool_address: ChecksumAddress, token: ChecksumAddress, block_number: BlockNumber, ) -> Balances: """Fetches users' single token balances of the Uniswap V3 pair across all the ticks.""" lowered_pool_address = pool_address.lower() result: Dict = await execute_uniswap_v3_gql_query( network=network, query=UNISWAP_V3_POOL_QUERY, variables=dict(block_number=block_number, pool_address=lowered_pool_address), ) pools = result.get("pools", []) if not pools: return Balances(total_supply=0, balances={}) pool = pools[0] try: tick_current: int = int(pool["tick"]) except TypeError: return Balances(total_supply=0, balances={}) sqrt_price: int = pool.get("sqrtPrice", "") if not sqrt_price: return Balances(total_supply=0, balances={}) sqrt_price = int(sqrt_price) token0_address: ChecksumAddress = Web3.toChecksumAddress(pool["token0"]) token1_address: ChecksumAddress = Web3.toChecksumAddress(pool["token1"]) last_id = "" result: Dict = await execute_uniswap_v3_gql_query( network=network, query=UNISWAP_V3_POSITIONS_QUERY, variables=dict( block_number=block_number, pool_address=lowered_pool_address, last_id=last_id, ), ) positions_chunk = result.get("positions", []) positions = positions_chunk # TODO: calculated earned fees # accumulate chunks of positions while len(positions_chunk) >= 1000: last_id = positions_chunk[-1]["id"] result: Dict = await execute_uniswap_v3_gql_query( network=network, query=UNISWAP_V3_POSITIONS_QUERY, variables=dict( block_number=block_number, pool_address=lowered_pool_address, last_id=last_id, ), ) positions_chunk = result.get("positions", []) positions.extend(positions_chunk) # process positions balances: Dict[ChecksumAddress, int] = {} total_supply = 0 for position in positions: account = Web3.toChecksumAddress(position["owner"]) if account == EMPTY_ADDR_HEX: continue liquidity: int = int(position["liquidity"]) if liquidity <= 0: continue try: tick_lower: int = int(position["tickLower"]) tick_upper: int = int(position["tickUpper"]) except TypeError: continue if token0_address == token: token0_amount = get_amount0( tick_current=tick_current, sqrt_ratio_x96=sqrt_price, tick_lower=tick_lower, tick_upper=tick_upper, liquidity=liquidity, ) balances[account] = balances.setdefault(account, 0) + token0_amount total_supply += token0_amount elif token1_address == token: token1_amount = get_amount1( tick_current=tick_current, sqrt_ratio_x96=sqrt_price, tick_lower=tick_lower, tick_upper=tick_upper, liquidity=liquidity, ) balances[account] = balances.setdefault(account, 0) + token1_amount total_supply += token1_amount return Balances(total_supply=total_supply, balances=balances)
async def get_token_liquidity_points( network: str, token_address: ChecksumAddress, from_block: BlockNumber, to_block: BlockNumber, ) -> Balances: """Fetches distributor token holders' balances.""" lowered_token_address = token_address.lower() last_id = "" result: Dict = await execute_sw_gql_query( network=network, query=DISTRIBUTOR_TOKEN_HOLDERS_QUERY, variables=dict( token_address=lowered_token_address, block_number=to_block, last_id=last_id, ), ) positions_chunk = result.get("distributorTokenHolders", []) positions = positions_chunk # accumulate chunks of positions while len(positions_chunk) >= 1000: last_id = positions_chunk[-1]["id"] result: Dict = await execute_sw_gql_query( network=network, query=DISTRIBUTOR_TOKEN_HOLDERS_QUERY, variables=dict( token_address=lowered_token_address, block_number=to_block, last_id=last_id, ), ) positions_chunk = result.get("distributorTokenHolders", []) positions.extend(positions_chunk) # process 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["amount"]) 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)