Example #1
0
def pairs_from_ethereum(ethereum: EthereumManager) -> Dict[str, Any]:
    """Detect the uniswap v2 pool tokens by using an ethereum node"""
    contracts_file = Path(__file__).resolve().parent / 'contracts.json'
    with contracts_file.open('r') as f:
        contracts = json.loads(f.read())

    univ2factory = EthereumContract(
        address=contracts['UNISWAPV2FACTORY']['address'],
        abi=contracts['UNISWAPV2FACTORY']['abi'],
        deployed_block=0,  # whatever
    )
    pairs_num = univ2factory.call(ethereum, 'allPairsLength')
    chunks = list(get_chunks([[x] for x in range(pairs_num)], n=500))
    pairs = []
    for idx, chunk in enumerate(chunks):
        print(f'Querying univ2 pairs chunk {idx + 1} / {len(chunks)}')
        result = multicall_specific(ethereum, univ2factory, 'allPairs', chunk)
        try:
            pairs.extend([deserialize_ethereum_address(x[0]) for x in result])
        except DeserializationError:
            print(
                'Error deserializing address while fetching uniswap v2 pool tokens'
            )
            sys.exit(1)

    return pairs
Example #2
0
    def _decode_order_placement(  # pylint: disable=no-self-use
        self,
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,  # pylint: disable=unused-argument
        decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
        all_logs: List[EthereumTxReceiptLog],  # pylint: disable=unused-argument
        action_items: List[ActionItem],  # pylint: disable=unused-argument
    ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]:
        """Some docs: https://docs.gnosis.io/protocol/docs/tutorial-limit-orders/"""
        topic_data, log_data = self.contract.decode_event(
            tx_log=tx_log,
            event_name='OrderPlacement',
            argument_names=('owner', 'index', 'buyToken', 'sellToken',
                            'validFrom', 'validUntil', 'priceNumerator',
                            'priceDenominator'),  # noqa: E501
        )
        owner = topic_data[0]
        if not self.base.is_tracked(owner):
            return None, None

        result = multicall_specific(
            ethereum=self.ethereum,
            contract=self.contract,
            method_name='tokenIdToAddressMap',
            arguments=[[topic_data[1]], [topic_data[2]]],
        )  # The resulting addresses are non checksumed but they can be found in the DB
        buy_token = ethaddress_to_asset(result[0][0])
        if buy_token is None:
            return None, None
        sell_token = ethaddress_to_asset(result[1][0])
        if sell_token is None:
            return None, None

        buy_amount = asset_normalized_value(amount=log_data[3],
                                            asset=buy_token)
        sell_amount = asset_normalized_value(amount=log_data[4],
                                             asset=sell_token)
        event = HistoryBaseEntry(
            event_identifier=transaction.tx_hash.hex(),
            sequence_index=self.base.get_sequence_index(tx_log),
            timestamp=ts_sec_to_ms(transaction.timestamp),
            location=Location.BLOCKCHAIN,
            location_label=owner,
            # Asset means nothing here since the event is informational. TODO: Improve?
            asset=sell_token,
            balance=Balance(amount=sell_amount),
            notes=
            f'Place an order in DXDao Mesa to sell {sell_amount} {sell_token.symbol} for {buy_amount} {buy_token.symbol}',  # noqa: E501
            event_type=HistoryEventType.INFORMATIONAL,
            event_subtype=HistoryEventSubType.PLACE_ORDER,
            counterparty=CPT_DXDAO_MESA,
        )
        return event, None
Example #3
0
    def query_defi_balances(
        self,
        addresses: List[ChecksumEthAddress],
    ) -> Dict[ChecksumEthAddress, List[DefiProtocolBalances]]:
        defi_balances = defaultdict(list)
        for account in addresses:
            balances = self.zerion_sdk.all_balances_for_account(account)
            if len(balances) != 0:
                defi_balances[account] = balances

        # and also query balances of tokens that are not detected by zerion adapter contract
        result = multicall_specific(
            ethereum=self.ethereum,
            contract=VOTE_ESCROWED_CRV,
            method_name='locked',
            arguments=[[x] for x in addresses],
        )
        crv_price = Price(ZERO)
        if any(x[0] != 0 for x in result):
            crv_price = Inquirer().find_usd_price(A_CRV)
        for idx, address in enumerate(addresses):
            balance = result[idx][0]
            if balance == 0:
                continue
            # else the address has vote escrowed CRV
            amount = token_normalized_value_decimals(token_amount=balance,
                                                     token_decimals=18)
            protocol_balance = DefiProtocolBalances(
                protocol=DefiProtocol(
                    name='Curve • Vesting',
                    description='Curve vesting or locked in escrow for voting',
                    url='https://www.curve.fi/',
                    version=1,
                ),
                balance_type='Asset',
                base_balance=DefiBalance(
                    token_address=VOTE_ESCROWED_CRV.address,
                    token_name='Vote-escrowed CRV',
                    token_symbol='veCRV',
                    balance=Balance(
                        amount=amount,
                        usd_value=amount * crv_price,
                    ),
                ),
                underlying_balances=[],
            )
            defi_balances[address].append(protocol_balance)

        return defi_balances
Example #4
0
    def get_balances(
        self,
        addresses: List[ChecksumAddress],
    ) -> Dict[ChecksumAddress, Balance]:
        """Return the addresses' balances (staked amount per pool) in the AdEx
        protocol.

        May raise:
        - RemoteError: Problem querying the chain
        """
        if len(addresses) == 0:
            return {}

        result = multicall_specific(
            ethereum=self.ethereum,
            contract=self.staking_pool,
            method_name='balanceOf',
            arguments=[[x] for x in addresses],
        )
        if all(x[0] == 0 for x in result):
            return {}  # no balances found

        staking_balances = {}
        usd_price = Inquirer().find_usd_price(A_ADX)
        share_price = self.staking_pool.call(self.ethereum, 'shareValue')
        for idx, address in enumerate(addresses):
            balance = result[idx][0]
            if balance == 0:
                continue
            # else the address has staked adex
            amount = token_normalized_value_decimals(
                token_amount=balance * share_price / (FVal(10)**18),
                token_decimals=18,
            )
            staking_balances[address] = Balance(amount=amount,
                                                usd_value=amount * usd_price)

        return staking_balances
Example #5
0
    def get_pool(
        self,
        token_0: EthereumToken,
        token_1: EthereumToken,
    ) -> List[str]:
        result = multicall_specific(
            ethereum=self.eth_manager,
            contract=UNISWAP_V3_FACTORY,
            method_name='getPool',
            arguments=[[
                token_0.ethereum_address,
                token_1.ethereum_address,
                fee,
            ] for fee in (3000, 500, 10000)],
        )

        # get liquidity for each pool and choose the pool with the highest liquidity
        best_pool, max_liquidity = to_checksum_address(result[0][0]), 0
        for query in result:
            if query[0] == ZERO_ADDRESS:
                continue
            pool_address = to_checksum_address(query[0])
            pool_contract = EthereumContract(
                address=pool_address,
                abi=UNISWAP_V3_POOL_ABI,
                deployed_block=UNISWAP_FACTORY_DEPLOYED_BLOCK,
            )
            pool_liquidity = pool_contract.call(
                ethereum=self.eth_manager,
                method_name='liquidity',
                arguments=[],
                call_order=None,
            )
            if pool_liquidity > max_liquidity:
                best_pool = pool_address

        return [best_pool]