Пример #1
0
def asset_to_atoken(asset: Asset, version: int) -> Optional[EthereumToken]:
    if asset == A_ETH:
        return A_AETH_V1

    protocol = 'aave' if version == 1 else 'aave-v2'
    cursor = GlobalDBHandler()._conn.cursor()
    result = cursor.execute(
        'SELECT A.address from ethereum_tokens as A LEFT OUTER JOIN assets as B '
        'WHERE A.protocol==? AND A.address=B.details_reference AND B.symbol=?',
        (protocol, 'a' + asset.symbol),
    ).fetchall()
    if len(result) != 1:
        log.error(f'Could not derive atoken from {asset} since multiple or no results were returned')  # noqa: E501
        return None

    try:
        return EthereumToken(result[0][0])
    except UnknownAsset:  # should not happen
        log.error(f'Could not derive atoken from {asset}. Couldnt turn {result[0]} to EthereumToken')  # noqa: E501
        return None
Пример #2
0
    def get_current_dsr(self) -> DSRCurrentBalances:
        """Gets the current DSR balance for all accounts that have DAI in DSR
        and the current DSR percentage

        May raise:
        - RemoteError if etherscan is used and there is a problem with
        reaching it or with the returned result.
        - BlockchainQueryError if an ethereum node is used and the contract call
        queries fail for some reason
        """
        with self.lock:
            proxy_mappings = self._get_accounts_having_maker_proxy()
            balances = {}
            try:
                current_dai_price = Inquirer().find_usd_price(
                    EthereumToken('DAI'))
            except RemoteError:
                current_dai_price = Price(FVal(1))
            for account, proxy in proxy_mappings.items():
                guy_slice = MAKERDAO_POT.call(self.ethereum,
                                              'pie',
                                              arguments=[proxy])
                if guy_slice == 0:
                    # no current DSR balance for this proxy
                    continue
                chi = MAKERDAO_POT.call(self.ethereum, 'chi')
                dai_balance = _dsrdai_to_dai(guy_slice * chi)
                balances[account] = Balance(
                    amount=dai_balance,
                    usd_value=current_dai_price * dai_balance,
                )

            current_dsr = MAKERDAO_POT.call(self.ethereum, 'dsr')
            # Calculation is from here:
            # https://docs.makerdao.com/smart-contract-modules/rates-module#a-note-on-setting-rates
            current_dsr_percentage = (
                (FVal(current_dsr / RAY)**31622400) % 1) * 100
            result = DSRCurrentBalances(balances=balances,
                                        current_dsr=current_dsr_percentage)

        return result
Пример #3
0
    def get_token_balances(self, account: ChecksumEthAddress) -> Dict[EthereumToken, FVal]:
        """Auto-detect which tokens are owned and get token balances for the account

        The returned balance is already normalized for the token's decimals.

        May raise:
        - RemoteError if there is a problem contacting aleth.io
        """
        balances = {}
        data = self._query(root_endpoint='accounts', path=f'{account}/tokenBalances')
        for entry in data:
            entry_type = entry.get('type', None)
            if entry_type == 'TokenBalance':

                attributes = entry.get('attributes', None)
                balance = None
                if attributes is not None:
                    balance = attributes.get('balance', None)
                if balance is None:
                    continue

                relationships = entry.get('relationships', None)
                if relationships is None:
                    continue
                token = relationships.get('token', None)
                if token is None:
                    continue
                if 'data' not in token:
                    continue
                if 'id' not in token['data']:
                    continue

                token_address = to_checksum_address(token['data']['id'])
                token_info = self.token_address_to_identifier(token_address)
                if token_info is None:
                    continue

                amount = FVal(balance) / (FVal(10) ** FVal(token_info.decimal))
                balances[EthereumToken(token_info.symbol)] = amount

        return balances
Пример #4
0
    def get_owned_tokens(self) -> List[EthereumToken]:
        cursor = self.conn.cursor()
        query = cursor.execute(
            'SELECT value FROM multisettings WHERE name="eth_token";', )
        result = []
        for q in query:
            try:
                result.append(EthereumToken(q[0]))
            except UnknownAsset:
                self.msg_aggregator.add_warning(
                    f'Unknown/unsupported asset {q[0]} found in the database. '
                    f'If you believe this should be supported open an issue in github',
                )
                continue
            except DeserializationError:
                self.msg_aggregator.add_error(
                    f'Non-string type asset: {type(q[0])} found in the database. Ignoring it.',
                )
                continue

        return result
Пример #5
0
def get_asset_balance_total(asset_symbol: str,
                            setup: BalancesTestSetup) -> FVal:
    conversion_function = satoshis_to_btc if asset_symbol == 'BTC' else from_wei
    total = ZERO
    asset = Asset(asset_symbol)

    if asset_symbol in ('ETH', 'BTC'):
        asset_balances = getattr(setup, f'{asset_symbol.lower()}_balances')
        total += sum(conversion_function(FVal(b)) for b in asset_balances)
    elif asset.is_eth_token():
        asset_balances = setup.token_balances[EthereumToken(asset_symbol)]
        total += sum(conversion_function(FVal(b)) for b in asset_balances)

    total += setup.binance_balances.get(asset_symbol, ZERO)
    total += setup.poloniex_balances.get(asset_symbol, ZERO)

    if setup.manually_tracked_balances:
        for entry in setup.manually_tracked_balances:
            if entry.asset.identifier == asset_symbol:
                total += entry.amount

    return total
Пример #6
0
def test_asset_and_price_not_found_in_history_processing(accountant):
    """
    Make sure that in history processing if no price is found for a trade it's added to a
    `missing_prices` list and no error is logged.

    Regression for https://github.com/rotki/rotki/issues/432
    Updated with https://github.com/rotki/rotki/pull/4196
    """
    fgp = EthereumToken('0xd9A8cfe21C232D485065cb62a96866799d4645f7')
    time = Timestamp(1492685761)
    trade = Trade(
        timestamp=time,
        location=Location.KRAKEN,
        base_asset=fgp,
        quote_asset=A_BTC,
        trade_type=TradeType.BUY,
        amount=FVal('2.5'),
        rate=FVal(.11000),
        fee=FVal('0.15'),
        fee_currency=fgp,
        link=None,
    )
    history = [trade, trade]  # duplicate missing price
    accounting_history_process(
        accountant,
        start_ts=0,
        end_ts=1514764799,  # 31/12/2017
        history_list=history,
    )
    errors = accountant.msg_aggregator.consume_errors()
    assert len(errors) == 0
    assert len(accountant.pots[0].cost_basis.missing_prices) == 1
    assert list(
        accountant.pots[0].cost_basis.missing_prices)[0] == MissingPrice(
            from_asset=fgp,
            to_asset=A_EUR,
            time=time,
        )
Пример #7
0
    def handle_protocols(
        self,
        protocol_name: str,
        token_symbol: str,
        normalized_balance: FVal,
        token_address: str,
        token_name: str,
    ) -> Optional[DefiBalance]:
        """Special handling for price for token/protocols which are easier to do onchain
        or need some kind of special treatment.
        This method can raise DeserializationError
        """
        if protocol_name == 'PoolTogether':
            result = _handle_pooltogether(normalized_balance, token_name)
            if result is not None:
                return result

        asset = get_asset_by_symbol(token_symbol)
        if asset is None:
            return None

        token = EthereumToken.from_asset(asset)
        if token is None:
            return None
        underlying_asset_price = get_underlying_asset_price(token)
        usd_price = handle_defi_price_query(self.ethereum, token,
                                            underlying_asset_price)
        if usd_price is None:
            return None

        return DefiBalance(
            token_address=deserialize_ethereum_address(token_address),
            token_name=token_name,
            token_symbol=token_symbol,
            balance=Balance(amount=normalized_balance,
                            usd_value=normalized_balance * usd_price),
        )
Пример #8
0
    def mock_requests_get(url, *args, **kwargs):
        if not use_alethio:
            response = '{"message": "fail so that test switches to etherscan"}'
            return MockResponse(400, response)

        if 'tokenBalances' in url:
            addr = url[33:75]
            assert addr in eth_map, f'Queried alethio for {addr} which is not in the eth_map'
            response = '{"data":['
            for symbol, balance in eth_map[addr].items():
                if symbol == 'ETH':
                    continue

                token = EthereumToken(symbol)
                if FVal(balance) == ZERO:
                    continue
                response += f"""{{"type":"TokenBalance","id":"foo","attributes":{{"balance":"{balance}"}},"relationships":{{"account":{{"data":{{"type":"Account","id":"foo"}},"links":{{"related":"https://api.aleth.io/v1/token-balances/0x9531c059098e3d194ff87febb587ab07b30b13066b175474e89094c44da98b954eedeac495271d0f/account"}},"token":{{"data":{{"type":"Token","id":"{token.ethereum_address}" }}}}}}"""  # noqa: E501

            response += ']}'

        else:
            raise AssertionError(f'Unimplemented alethio mock for url: {url}')

        return MockResponse(200, response)
Пример #9
0
 def _get_tokens_balance_and_price(
     self,
     address: ChecksumEthAddress,
     tokens: List[CustomEthereumTokenWithIdentifier],
     balances: Dict[EthereumToken, FVal],
     token_usd_price: Dict[EthereumToken, Price],
     call_order: Optional[Sequence[NodeName]],
 ) -> None:
     ret = self._get_multitoken_account_balance(
         tokens=tokens,
         account=address,
         call_order=call_order,
     )
     for token_identifier, value in ret.items():
         token = EthereumToken(token_identifier)
         balances[token] += value
         if token in token_usd_price:
             continue
         # else get the price
         try:
             usd_price = Inquirer().find_usd_price(token)
         except RemoteError:
             usd_price = Price(ZERO)
         token_usd_price[token] = usd_price
Пример #10
0
# Top holder of WBTC-WETH pool (0x1eff8af5d577060ba4ac8a29a13525bb0ee2a3d5)
BALANCER_TEST_ADDR1 = string_to_ethereum_address(
    '0x49a2DcC237a65Cc1F412ed47E0594602f6141936')
BALANCER_TEST_ADDR2 = string_to_ethereum_address(
    '0x029f388aC4D5C8BfF490550ce0853221030E822b')
BALANCER_TEST_ADDR3 = string_to_ethereum_address(
    '0x7716a99194d758c8537F056825b75Dd0C8FDD89f')
BALANCER_TEST_ADDR4 = string_to_ethereum_address(
    '0x231DC6af3C66741f6Cf618884B953DF0e83C1A2A')
BALANCER_TEST_ADDR3_POOL1 = EthereumToken.initialize(
    address=string_to_ethereum_address(
        '0x59A19D8c652FA0284f44113D0ff9aBa70bd46fB4'),
    symbol='BPT',
    protocol='balancer',
    underlying_tokens=[
        UnderlyingToken(address=string_to_ethereum_address(
            '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'),
                        weight=FVal(0.2)),  # noqa: E501  # WETH
        UnderlyingToken(address=string_to_ethereum_address(
            '0xba100000625a3754423978a60c9317c58a424e3D'),
                        weight=FVal(0.8)),  # noqa: E501  # BAL
    ],
)
BALANCER_TEST_ADDR3_POOL2 = EthereumToken.initialize(
    address=string_to_ethereum_address(
        '0x574FdB861a0247401B317a3E68a83aDEAF758cf6'),
    symbol='BPT',
    protocol='balancer',
    underlying_tokens=[
        UnderlyingToken(address=string_to_ethereum_address(
            '0x0D8775F648430679A709E98d2b0Cb6250d2887EF'),
                        weight=FVal(0.1)),  # noqa: E501  # BAT
Пример #11
0
def test_simple_update(rotkehlchen_api_server, globaldb):
    """Test that the happy case of update works.

    - Test that up_to_version argument works
    - Test that only versions above current local are applied
    - Test that versions with min/max schema mismatch are skipped
    """
    async_query = random.choice([False, True])
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    update_3 = """INSERT INTO ethereum_tokens(address, decimals, protocol) VALUES("0xC2FEC534c461c45533e142f724d0e3930650929c", 18, NULL);INSERT INTO assets(identifier,type, name, symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("_ceth_0xC2FEC534c461c45533e142f724d0e3930650929c", "C", "AKB token", "AKB",123, NULL,   NULL, "AIDU", "0xC2FEC534c461c45533e142f724d0e3930650929c");
*
INSERT INTO assets(identifier,type,name,symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("121-ada-FADS-as", "F","A name","SYMBOL",NULL, NULL,"", "", "121-ada-FADS-as");INSERT INTO common_asset_details(asset_id, forked) VALUES("121-ada-FADS-as", "BTC");
*
UPDATE assets SET name="Ευρώ" WHERE identifier="EUR";
INSERT INTO assets(identifier,type,name,symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("EUR", "A","Ευρώ","EUR",NULL, NULL,NULL,NULL, "EUR");INSERT INTO common_asset_details(asset_id, forked) VALUES("EUR", NULL);
    """  # noqa: E501
    update_patch = mock_asset_updates(
        original_requests_get=requests.get,
        latest=999999996,
        updates={
            "999999991": {
                "changes": 1,
                "min_schema_version": GLOBAL_DB_VERSION,
                "max_schema_version": GLOBAL_DB_VERSION,
            },
            "999999992": {
                "changes": 1,
                "min_schema_version": GLOBAL_DB_VERSION,
                "max_schema_version": GLOBAL_DB_VERSION,
            },
            "999999993": {
                "changes": 3,
                "min_schema_version": GLOBAL_DB_VERSION,
                "max_schema_version": GLOBAL_DB_VERSION,
            },
            "999999994": {
                "changes": 5,
                "min_schema_version": GLOBAL_DB_VERSION + 1,
                "max_schema_version": GLOBAL_DB_VERSION - 1,
            },
            "999999995": {
                "changes": 5,
                "min_schema_version": GLOBAL_DB_VERSION,
                "max_schema_version": GLOBAL_DB_VERSION,
            },
            "999999996": {
                "changes": 5,
                "min_schema_version": GLOBAL_DB_VERSION,
                "max_schema_version": GLOBAL_DB_VERSION,
            },
        },
        sql_actions={
            "999999991": "",
            "999999992": "",
            "999999993": update_3,
            "999999994": "",
            "999999995": ""
        },  # noqa: E501
    )
    globaldb.add_setting_value(ASSETS_VERSION_KEY, 999999992)
    with update_patch:
        response = requests.get(
            api_url_for(
                rotkehlchen_api_server,
                'assetupdatesresource',
            ),
            json={'async_query': async_query},
        )
        if async_query:
            task_id = assert_ok_async_response(response)
            outcome = wait_for_async_task(
                rotkehlchen_api_server,
                task_id,
            )
            result = outcome['result']
            assert outcome['message'] == ''
        else:
            result = assert_proper_response_with_result(response)
        assert result['local'] == 999999992
        assert result['remote'] == 999999996
        assert result[
            'new_changes'] == 13  # changes from 99[3 + 4 + 6], skipping 5

        response = requests.post(
            api_url_for(
                rotkehlchen_api_server,
                'assetupdatesresource',
            ),
            json={
                'async_query': async_query,
                'up_to_version': 999999995
            },
        )
        if async_query:
            task_id = assert_ok_async_response(response)
            outcome = wait_for_async_task(
                rotkehlchen_api_server,
                task_id,
            )
            assert outcome['message'] == ''
            result = outcome['result']
        else:
            result = assert_proper_response_with_result(response)

        errors = rotki.msg_aggregator.consume_errors()
        warnings = rotki.msg_aggregator.consume_warnings()
        assert len(errors) == 0, f'Found errors: {errors}'
        assert len(warnings) == 1
        assert 'Skipping assets update 999999994 since it requires a min schema of' in warnings[
            0]

        assert result is True
        assert globaldb.get_setting_value(ASSETS_VERSION_KEY,
                                          None) == 999999995
        new_token = EthereumToken('0xC2FEC534c461c45533e142f724d0e3930650929c')
        assert new_token.identifier == strethaddress_to_identifier(
            '0xC2FEC534c461c45533e142f724d0e3930650929c')  # noqa: E501
        assert new_token.name == 'AKB token'
        assert new_token.symbol == 'AKB'
        assert new_token.asset_type == AssetType.ETHEREUM_TOKEN
        assert new_token.started == 123
        assert new_token.forked is None
        assert new_token.swapped_for is None
        assert new_token.coingecko is None
        assert new_token.cryptocompare == 'AIDU'
        assert new_token.ethereum_address == '0xC2FEC534c461c45533e142f724d0e3930650929c'
        assert new_token.decimals == 18
        assert new_token.protocol is None

        new_asset = Asset('121-ada-FADS-as')
        assert new_asset.identifier == '121-ada-FADS-as'
        assert new_asset.name == 'A name'
        assert new_asset.symbol == 'SYMBOL'
        assert new_asset.asset_type == AssetType.COUNTERPARTY_TOKEN
        assert new_asset.started is None
        assert new_asset.forked == 'BTC'
        assert new_asset.swapped_for is None
        assert new_asset.coingecko == ''
        assert new_asset.cryptocompare == ''

        assert Asset('EUR').name == 'Ευρώ'
Пример #12
0
def test_update_conflicts(rotkehlchen_api_server, globaldb):
    """Test that conflicts in an asset update are handled properly"""
    async_query = random.choice([False, True])
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    update_1 = """INSERT INTO assets(identifier,type,name,symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("121-ada-FADS-as", "F","A name","SYMBOL",NULL, NULL,"", "", "121-ada-FADS-as");INSERT INTO common_asset_details(asset_id, forked) VALUES("121-ada-FADS-as", "BTC");
*
INSERT INTO ethereum_tokens(address, decimals, protocol) VALUES("0x6B175474E89094C44Da98b954EedeAC495271d0F", 8, "maker");INSERT INTO assets(identifier,type, name, symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("_ceth_0x6B175474E89094C44Da98b954EedeAC495271d0F", "C", "New Multi Collateral DAI", "NDAI", 1573672677, NULL, "dai", NULL, "0x6B175474E89094C44Da98b954EedeAC495271d0F");
*
INSERT INTO assets(identifier,type,name,symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("DASH", "B","Dash","DASH",1337, NULL, "dash-coingecko", NULL, "DASH");INSERT INTO common_asset_details(asset_id, forked) VALUES("DASH", "BTC");
*
    """  # noqa: E501
    update_patch = mock_asset_updates(
        original_requests_get=requests.get,
        latest=999999991,
        updates={
            "999999991": {
                "changes": 3,
                "min_schema_version": GLOBAL_DB_VERSION,
                "max_schema_version": GLOBAL_DB_VERSION,
            }
        },
        sql_actions={"999999991": update_1},
    )
    globaldb.add_setting_value(ASSETS_VERSION_KEY, 999999990)
    start_assets_num = len(globaldb.get_all_asset_data(mapping=False))
    with update_patch:
        response = requests.get(
            api_url_for(
                rotkehlchen_api_server,
                'assetupdatesresource',
            ),
            json={'async_query': async_query},
        )
        if async_query:
            task_id = assert_ok_async_response(response)
            outcome = wait_for_async_task(
                rotkehlchen_api_server,
                task_id,
            )
            result = outcome['result']
            assert outcome['message'] == ''
        else:
            result = assert_proper_response_with_result(response)
        assert result['local'] == 999999990
        assert result['remote'] == 999999991
        assert result['new_changes'] == 3

        response = requests.post(
            api_url_for(
                rotkehlchen_api_server,
                'assetupdatesresource',
            ),
            json={'async_query': async_query},
        )
        if async_query:
            task_id = assert_ok_async_response(response)
            outcome = wait_for_async_task(
                rotkehlchen_api_server,
                task_id,
            )
            assert outcome[
                'message'] == 'Found conflicts during assets upgrade'
            result = outcome['result']
        else:
            result = assert_proper_response_with_result(
                response,
                message='Found conflicts during assets upgrade',
                status_code=HTTPStatus.CONFLICT,
            )

        # Make sure that nothing was committed
        assert globaldb.get_setting_value(ASSETS_VERSION_KEY,
                                          None) == 999999990
        assert len(
            globaldb.get_all_asset_data(mapping=False)) == start_assets_num
        with pytest.raises(UnknownAsset):
            Asset('121-ada-FADS-as')
        errors = rotki.msg_aggregator.consume_errors()
        warnings = rotki.msg_aggregator.consume_warnings()
        assert len(errors) == 0, f'Found errors: {errors}'
        assert len(warnings) == 0, f'Found warnings: {warnings}'
        # See that we get two conflicts
        expected_result = [{
            'identifier': '_ceth_0x6B175474E89094C44Da98b954EedeAC495271d0F',
            'local': {
                'name': 'Multi Collateral Dai',
                'symbol': 'DAI',
                'asset_type': 'ethereum token',
                'started': 1573672677,
                'forked': None,
                'swapped_for': None,
                'ethereum_address':
                '0x6B175474E89094C44Da98b954EedeAC495271d0F',
                'decimals': 18,
                'cryptocompare': None,
                'coingecko': 'dai',
                'protocol': None,
            },
            'remote': {
                'name': 'New Multi Collateral DAI',
                'symbol': 'NDAI',
                'asset_type': 'ethereum token',
                'started': 1573672677,
                'forked': None,
                'swapped_for': None,
                'ethereum_address':
                '0x6B175474E89094C44Da98b954EedeAC495271d0F',
                'decimals': 8,
                'cryptocompare': None,
                'coingecko': 'dai',
                'protocol': 'maker',
            },
        }, {
            'identifier': 'DASH',
            'local': {
                'name': 'Dash',
                'symbol': 'DASH',
                'asset_type': 'own chain',
                'started': 1390095618,
                'forked': None,
                'swapped_for': None,
                'ethereum_address': None,
                'decimals': None,
                'cryptocompare': None,
                'coingecko': 'dash',
                'protocol': None,
            },
            'remote': {
                'name': 'Dash',
                'symbol': 'DASH',
                'asset_type': 'own chain',
                'started': 1337,
                'forked': 'BTC',
                'swapped_for': None,
                'ethereum_address': None,
                'decimals': None,
                'cryptocompare': None,
                'coingecko': 'dash-coingecko',
                'protocol': None,
            },
        }]
        assert result == expected_result

        # now try the update again but specify the conflicts resolution
        conflicts = {
            '_ceth_0x6B175474E89094C44Da98b954EedeAC495271d0F': 'remote',
            'DASH': 'local'
        }
        response = requests.post(
            api_url_for(
                rotkehlchen_api_server,
                'assetupdatesresource',
            ),
            json={
                'async_query': async_query,
                'conflicts': conflicts
            },
        )
        if async_query:
            task_id = assert_ok_async_response(response)
            outcome = wait_for_async_task(
                rotkehlchen_api_server,
                task_id,
            )
            assert outcome['message'] == ''
            result = outcome['result']
        else:
            result = assert_proper_response_with_result(
                response,
                message='',
                status_code=HTTPStatus.OK,
            )

        # check conflicts were solved as per the given choices and new asset also added
        assert result is True
        assert globaldb.get_setting_value(ASSETS_VERSION_KEY,
                                          None) == 999999991
        errors = rotki.msg_aggregator.consume_errors()
        warnings = rotki.msg_aggregator.consume_warnings()
        assert len(errors) == 0, f'Found errors: {errors}'
        assert len(warnings) == 0, f'Found warnings: {warnings}'
        dai = EthereumToken('0x6B175474E89094C44Da98b954EedeAC495271d0F')
        assert dai.identifier == strethaddress_to_identifier(
            '0x6B175474E89094C44Da98b954EedeAC495271d0F')  # noqa: E501
        assert dai.name == 'New Multi Collateral DAI'
        assert dai.symbol == 'NDAI'
        assert dai.asset_type == AssetType.ETHEREUM_TOKEN
        assert dai.started == 1573672677
        assert dai.forked is None
        assert dai.swapped_for is None
        assert dai.coingecko == 'dai'
        assert dai.cryptocompare is None
        assert dai.ethereum_address == '0x6B175474E89094C44Da98b954EedeAC495271d0F'
        assert dai.decimals == 8
        assert dai.protocol == 'maker'

        dash = Asset('DASH')
        assert dash.identifier == 'DASH'
        assert dash.name == 'Dash'
        assert dash.symbol == 'DASH'
        assert dash.asset_type == AssetType.OWN_CHAIN
        assert dash.started == 1390095618
        assert dash.forked is None
        assert dash.swapped_for is None
        assert dash.coingecko == 'dash'
        assert dash.cryptocompare is None

        new_asset = Asset('121-ada-FADS-as')
        assert new_asset.identifier == '121-ada-FADS-as'
        assert new_asset.name == 'A name'
        assert new_asset.symbol == 'SYMBOL'
        assert new_asset.asset_type == AssetType.COUNTERPARTY_TOKEN
        assert new_asset.started is None
        assert new_asset.forked == 'BTC'
        assert new_asset.swapped_for is None
        assert new_asset.coingecko == ''
        assert new_asset.cryptocompare == ''
Пример #13
0
from rotkehlchen.fval import FVal
from rotkehlchen.serialization.deserialize import deserialize_ethereum_address
from rotkehlchen.typing import AssetAmount, Price, Timestamp

# Logic: Get balances

# Addresses
TEST_ADDRESS_1 = deserialize_ethereum_address(
    '0xfeF0E7635281eF8E3B705e9C5B86e1d3B0eAb397')
TEST_ADDRESS_2 = deserialize_ethereum_address(
    '0xcf2B8EeC2A9cE682822b252a1e9B78EedebEFB02')
TEST_ADDRESS_3 = deserialize_ethereum_address(
    '0x7777777777777777777777777777777777777777')

# Known tokens
ASSET_USDT = EthereumToken('USDT')
ASSET_WETH = EthereumToken('WETH')
TOKEN_BASED = EthereumToken('$BASED')

# Unknown tokens
ASSET_SHUF = UnknownEthereumToken(
    ethereum_address=deserialize_ethereum_address(
        '0x3A9FfF453d50D4Ac52A6890647b823379ba36B9E'),
    symbol='SHUF',
    name='Shuffle.Monster V3',
    decimals=18,
)
ASSET_TGX = UnknownEthereumToken(
    ethereum_address=deserialize_ethereum_address(
        '0x364A7381A5b378CeD7AB33d1CDf6ff1bf162Bfd6'),
    symbol='TGX',
Пример #14
0
from rotkehlchen.history.price import query_usd_price_zero_if_error
from rotkehlchen.inquirer import Inquirer
from rotkehlchen.premium.premium import Premium
from rotkehlchen.typing import ChecksumEthAddress, Timestamp
from rotkehlchen.user_messages import MessagesAggregator
from rotkehlchen.utils.interfaces import EthereumModule
from rotkehlchen.utils.misc import hexstr_to_int

if TYPE_CHECKING:
    from rotkehlchen.chain.ethereum.manager import EthereumManager

ADDRESS_TO_ASSETS = Dict[ChecksumEthAddress, Dict[Asset, Balance]]
BLOCKS_PER_DAY = 4 * 60 * 24
DAYS_PER_YEAR = 365
ETH_MANTISSA = 10**18
A_COMP = EthereumToken('COMP')

COMPTROLLER_PROXY = EthereumConstants().contract('COMPTROLLER_PROXY')
COMP_DEPLOYED_BLOCK = 9601359

LEND_EVENTS_QUERY_PREFIX = """{graph_event_name}
(where: {{blockTime_lte: $end_ts, blockTime_gte: $start_ts, {addr_position}: $address}}) {{
    id
    amount
    to
    from
    blockNumber
    blockTime
    cTokenSymbol
    underlyingAmount
}}}}"""
Пример #15
0
def test_curve_remove_imbalanced(database, ethereum_manager, eth_transactions):
    """Data for deposit taken from
    https://etherscan.io/tx/0xd8832abcf4773abe24d8cda5581fb53bfb3850c535c1956d1d120a72a4ebcbd8
    This tests uses the steth pool to verify that withdrawals are correctly decoded when an
    internal transaction is made for eth transfers
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0xd8832abcf4773abe24d8cda5581fb53bfb3850c535c1956d1d120a72a4ebcbd8'
    location_label = '0x2fac74A3a04B031F240923621a578724C40678af'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1650276061,
        block_number=14647221,
        from_address=location_label,
        to_address='0xbBC81d23Ea2c3ec7e56D39296F0cbB648873a5d3',
        value=0,
        gas=171249,
        gas_price=22990000000,
        gas_used=171249,
        input_data=hexstring_to_bytes('0x517a55a300000000000000000000000000000000000000000000001fa9ee7266a543831f00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000003f487c50000000000000000000000000000000000000000000000000000000000000001'),  # noqa: E501
        nonce=5,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=2183,
                data=hexstring_to_bytes('0x00000000000000000000000000000000000000000000001fa9ee7266a543831f'),  # noqa: E501
                address=string_to_ethereum_address('0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000002fac74a3a04b031f240923621a578724c40678af'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2184,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                address=string_to_ethereum_address('0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000045f783cce6b7ff23b2ab2d70e416cdb7d6055f51'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2185,
                data=hexstring_to_bytes('0x000000000000000000000000000000000000000000000000000000001fdb750a'),  # noqa: E501
                address=string_to_ethereum_address('0xd6aD7a6750A7593E092a9B218d66C0A814a3436e'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000045f783cce6b7ff23b2ab2d70e416cdb7d6055f51'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2186,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                address=string_to_ethereum_address('0x83f798e925BcD4017Eb265844FDDAbb448f1707D'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000045f783cce6b7ff23b2ab2d70e416cdb7d6055f51'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2187,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                address=string_to_ethereum_address('0x73a052500105205d34Daf004eAb301916DA8190f'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000045f783cce6b7ff23b2ab2d70e416cdb7d6055f51'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2188,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                address=string_to_ethereum_address('0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2189,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fdb750a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045cf4bec2e53f0000000000000000000000000000000000000000000000000000000000000e07e000000000000000000000000000000000000000000000000000000000000570d0000000000000000000000000000000000000000000000000051077d9dc293100000000000000000000000000000000000000000000c740195f187122987a9ef0000000000000000000000000000000000000000000aeddccb3976328f7d90bd'),  # noqa: E501
                address=string_to_ethereum_address('0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xb964b72f73f5ef5bf0fdc559b2fab9a7b12a39e47817a547f1f0aee47febd602'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2189,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000027a72df9'),  # noqa: E501
                address=string_to_ethereum_address('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000002fac74a3a04b031f240923621a578724c40678af'),  # noqa: E501
                ],
            ),
        ],
    )
    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction, tx_receipt=receipt)
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=0,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.00393701451),
                usd_value=ZERO,
            ),
            location_label=location_label,
            notes='Burned 0.00393701451 ETH in gas from 0x2fac74A3a04B031F240923621a578724C40678af',  # noqa: E501
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=2184,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.RETURN_WRAPPED,
            asset=EthereumToken('0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8'),
            balance=Balance(amount=FVal('584.093916507047953183'), usd_value=ZERO),
            location_label=location_label,
            notes='Return 584.093916507047953183 yDAI+yUSDC+yUSDT+yTUSD',
            counterparty=CPT_CURVE,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=2190,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.WITHDRAWAL,
            event_subtype=HistoryEventSubType.REMOVE_ASSET,
            asset=A_USDC,
            balance=Balance(amount=FVal('665.267705'), usd_value=ZERO),
            location_label=location_label,
            notes='Receive 665.267705 USDC from the curve pool 0xbBC81d23Ea2c3ec7e56D39296F0cbB648873a5d3',  # noqa: E501
            counterparty=CPT_CURVE,
        )]
    assert expected_events == events
Пример #16
0
    A_SUSD,
    A_TUSD,
    A_UNI,
    A_USDC,
    A_USDT,
    A_WBTC,
    A_WETH,
    A_YFI,
    A_ZRX,
)
from rotkehlchen.constants.misc import ZERO
from rotkehlchen.fval import FVal
from rotkehlchen.tests.utils.constants import A_ADAI
from rotkehlchen.typing import Timestamp

A_AENJ_V1 = EthereumToken('0x712DB54daA836B53Ef1EcBb9c6ba3b9Efb073F40')
A_ADAI_V1 = EthereumToken('0xfC1E690f61EFd961294b3e1Ce3313fBD8aa4f85d')
A_ASUSD_V1 = EthereumToken('0x625aE63000f46200499120B906716420bd059240')
A_ATUSD_V1 = EthereumToken('0x4DA9b813057D04BAef4e5800E36083717b4a0341')
A_AUSDT_V1 = EthereumToken('0x71fc860F7D3A592A4a98740e39dB31d25db65ae8')
A_ABUSD_V1 = EthereumToken('0x6Ee0f7BB50a54AB5253dA0667B0Dc2ee526C30a8')
A_ABAT_V1 = EthereumToken('0xE1BA0FB44CCb0D11b80F92f4f8Ed94CA3fF51D00')
A_AKNC_V1 = EthereumToken('0x9D91BE44C06d373a8a226E1f3b146956083803eB')
A_ALEND_V1 = EthereumToken('0x7D2D3688Df45Ce7C552E19c27e007673da9204B8')
A_AMANA_V1 = EthereumToken('0x6FCE4A401B6B80ACe52baAefE4421Bd188e76F6f')
A_AMKR_V1 = EthereumToken('0x7deB5e830be29F91E298ba5FF1356BB7f8146998')
A_AREN_V1 = EthereumToken('0x69948cC03f478B95283F7dbf1CE764d0fc7EC54C')
A_ASNX_V1 = EthereumToken('0x328C4c80BC7aCa0834Db37e6600A6c49E12Da4DE')
A_AWBTC_V1 = EthereumToken('0xFC4B8ED459e00e5400be803A9BB3954234FD50e3')
A_AYFI_V1 = EthereumToken('0x12e51E77DAAA58aA0E9247db7510Ea4B46F9bEAd')
A_AZRX_V1 = EthereumToken('0x6Fb0855c404E09c47C3fBCA25f08d4E41f9F062f')
Пример #17
0
from rotkehlchen.assets.asset import Asset, EthereumToken

A_RDN = EthereumToken('RDN')
A_GNO = EthereumToken('GNO')
A_DAO = EthereumToken('DAO')
A_DOGE = Asset('DOGE')
A_XMR = Asset('XMR')
A_DASH = Asset('DASH')
A_IOTA = Asset('IOTA')
A_BSV = Asset('BSV')
A_BCH = Asset('BCH')
A_GBP = Asset('GBP')
A_SNGLS = Asset('SNGLS')
A_BNB = Asset('BNB')
A_USDT = Asset('USDT')
Пример #18
0
    def find_usd_price(
        asset: Asset,
        ignore_cache: bool = False,
    ) -> Price:
        """Returns the current USD price of the asset

        Returns Price(ZERO) if all options have been exhausted and errors are logged in the logs
        """
        if asset == A_USD:
            return Price(FVal(1))

        instance = Inquirer()
        cache_key = (asset, A_USD)
        if ignore_cache is False:
            cache = instance.get_cached_current_price_entry(
                cache_key=cache_key)
            if cache is not None:
                return cache.price

        if asset.is_fiat():
            try:
                return instance._query_fiat_pair(base=asset, quote=A_USD)
            except RemoteError:
                pass  # continue, a price can be found by one of the oracles (CC for example)

        # Try and check if it is an ethereum token with specified protocol or underlying tokens
        is_known_protocol = False
        underlying_tokens = None
        try:
            token = EthereumToken.from_asset(asset)
            if token is not None:
                if token.protocol is not None:
                    is_known_protocol = token.protocol in KnownProtocolsAssets
                underlying_tokens = GlobalDBHandler(
                ).get_ethereum_token(  # type: ignore
                    token.ethereum_address, ).underlying_tokens
        except UnknownAsset:
            pass

        # Check if it is a special token
        if asset in instance.special_tokens:
            ethereum = instance._ethereum
            assert ethereum, 'Inquirer should never be called before the injection of ethereum'
            assert token, 'all assets in special tokens are already ethereum tokens'
            underlying_asset_price = get_underlying_asset_price(token)
            usd_price = handle_defi_price_query(
                ethereum=ethereum,
                token=token,
                underlying_asset_price=underlying_asset_price,
            )
            if usd_price is None:
                price = Price(ZERO)
            else:
                price = Price(usd_price)

            Inquirer._cached_current_price[cache_key] = CachedPriceEntry(
                price=price, time=ts_now())  # noqa: E501
            return price

        if is_known_protocol is True or underlying_tokens is not None:
            assert token is not None
            result = get_underlying_asset_price(token)
            if result is None:
                usd_price = Price(ZERO)
                if instance._ethereum is not None:
                    instance._ethereum.msg_aggregator.add_warning(
                        f'Could not find price for {token}', )
            else:
                usd_price = Price(result)
            Inquirer._cached_current_price[cache_key] = CachedPriceEntry(
                price=usd_price,
                time=ts_now(),
            )
            return usd_price

        # BSQ is a special asset that doesnt have oracle information but its custom API
        if asset == A_BSQ:
            try:
                price_in_btc = get_bisq_market_price(asset)
                btc_price = Inquirer().find_usd_price(A_BTC)
                usd_price = Price(price_in_btc * btc_price)
                Inquirer._cached_current_price[cache_key] = CachedPriceEntry(
                    price=usd_price,
                    time=ts_now(),
                )
                return usd_price
            except (RemoteError, DeserializationError) as e:
                msg = f'Could not find price for BSQ. {str(e)}'
                if instance._ethereum is not None:
                    instance._ethereum.msg_aggregator.add_warning(msg)
                return Price(BTC_PER_BSQ * price_in_btc)

        if asset == A_KFEE:
            # KFEE is a kraken special asset where 1000 KFEE = 10 USD
            return Price(FVal(0.01))

        return instance._query_oracle_instances(from_asset=asset,
                                                to_asset=A_USD)
Пример #19
0
    def get_balances(
        self,
        given_defi_balances: GIVEN_DEFI_BALANCES,
    ) -> Dict[ChecksumEthAddress, Dict]:
        compound_balances = {}
        if isinstance(given_defi_balances, dict):
            defi_balances = given_defi_balances
        else:
            defi_balances = given_defi_balances()

        for account, balance_entries in defi_balances.items():
            lending_map = {}
            borrowing_map = {}
            rewards_map = {}
            for balance_entry in balance_entries:
                if balance_entry.protocol.name not in ('Compound Governance',
                                                       'Compound'):
                    continue

                entry = balance_entry.base_balance
                try:
                    asset = Asset(entry.token_symbol)
                except UnknownAsset:
                    log.error(
                        f'Encountered unknown asset {entry.token_symbol} in compound. Skipping',
                    )
                    continue

                unclaimed_comp_rewards = (
                    entry.token_address == A_COMP.ethereum_address
                    and balance_entry.protocol.name == 'Compound Governance')
                if unclaimed_comp_rewards:
                    rewards_map[A_COMP] = CompoundBalance(
                        balance_type=BalanceType.ASSET,
                        balance=entry.balance,
                        apy=None,
                    )
                    continue

                if balance_entry.balance_type == 'Asset':
                    # Get the underlying balance
                    underlying_symbol = balance_entry.underlying_balances[
                        0].token_symbol
                    try:
                        underlying_asset = Asset(underlying_symbol)
                    except UnknownAsset:
                        log.error(
                            f'Encountered unknown asset {underlying_symbol} in compound. Skipping',
                        )
                        continue

                    lending_map[underlying_asset.identifier] = CompoundBalance(
                        balance_type=BalanceType.ASSET,
                        balance=balance_entry.underlying_balances[0].balance,
                        apy=self._get_apy(entry.token_address, supply=True),
                    )
                else:  # 'Debt'
                    try:
                        ctoken = EthereumToken('c' + entry.token_symbol)
                    except UnknownAsset:
                        log.error(
                            f'Encountered unknown asset {entry.token_symbol} in '
                            f'compound while figuring out cToken. Skipping', )
                        continue

                    borrowing_map[asset.identifier] = CompoundBalance(
                        balance_type=BalanceType.LIABILITY,
                        balance=entry.balance,
                        apy=self._get_apy(ctoken.ethereum_address,
                                          supply=False),
                    )

            if lending_map == {} and borrowing_map == {} and rewards_map == {}:
                # no balances for the account
                continue
            compound_balances[account] = {
                'rewards': rewards_map,
                'lending': lending_map,
                'borrowing': borrowing_map,
            }

        return compound_balances
Пример #20
0
    def find_uniswap_v2_lp_price(
        self,
        token: EthereumToken,
    ) -> Optional[Price]:
        """
        Calculate the price for a uniswap v2 LP token. That is
        value = (Total value of liquidity pool) / (Current suply of LP tokens)
        We need:
        - Price of token 0
        - Price of token 1
        - Pooled amount of token 0
        - Pooled amount of token 1
        - Total supply of of pool token
        """
        assert self._ethereum is not None, 'Inquirer ethereum manager should have been initialized'  # noqa: E501

        address = token.ethereum_address
        contract = EthereumContract(address=address,
                                    abi=UNISWAP_V2_LP_ABI,
                                    deployed_block=0)
        methods = [
            'token0', 'token1', 'totalSupply', 'getReserves', 'decimals'
        ]
        try:
            output = multicall_2(
                ethereum=self._ethereum,
                require_success=True,
                calls=[(address, contract.encode(method_name=method))
                       for method in methods],
            )
        except RemoteError as e:
            log.error(
                f'Remote error calling multicall contract for uniswap v2 lp '
                f'token {token.ethereum_address} properties: {str(e)}', )
            return None

        # decode output
        decoded = []
        for (method_output, method_name) in zip(output, methods):
            if method_output[0] and len(method_output[1]) != 0:
                decoded_method = contract.decode(method_output[1], method_name)
                if len(decoded_method) == 1:
                    # https://github.com/PyCQA/pylint/issues/4739
                    decoded.append(decoded_method[0])  # pylint: disable=unsubscriptable-object
                else:
                    decoded.append(decoded_method)
            else:
                log.debug(
                    f'Multicall to Uniswap V2 LP failed to fetch field {method_name} '
                    f'for token {token.ethereum_address}', )
                return None

        try:
            token0 = EthereumToken(decoded[0])
            token1 = EthereumToken(decoded[1])
        except UnknownAsset:
            return None

        try:
            token0_supply = FVal(decoded[3][0] * 10**-token0.decimals)
            token1_supply = FVal(decoded[3][1] * 10**-token1.decimals)
            total_supply = FVal(decoded[2] * 10**-decoded[4])
        except ValueError as e:
            log.debug(
                f'Failed to deserialize token amounts for token {address} '
                f'with values {str(decoded)}. f{str(e)}', )
            return None
        token0_price = self.find_usd_price(token0)
        token1_price = self.find_usd_price(token1)

        if ZERO in (token0_price, token1_price):
            log.debug(
                f'Couldnt retrieve non zero price information for tokens {token0}, {token1} '
                f'with result {token0_price}, {token1_price}', )
        numerator = (token0_supply * token0_price +
                     token1_supply * token1_price)
        share_value = numerator / total_supply
        return Price(share_value)
Пример #21
0
from rotkehlchen.assets.asset import Asset, EthereumToken
from rotkehlchen.chain.ethereum.typing import string_to_ethereum_address

A_RDN = EthereumToken('0x255Aa6DF07540Cb5d3d297f0D0D4D84cb52bc8e6')
A_GNO = EthereumToken('0x6810e776880C02933D47DB1b9fc05908e5386b96')
A_DAO = EthereumToken('0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413')
A_MKR = EthereumToken('0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2')
A_SNGLS = EthereumToken('0xaeC2E87E0A235266D9C5ADc9DEb4b2E29b54D009')
A_PAXG = EthereumToken('0x45804880De22913dAFE09f4980848ECE6EcbAf78')
A_ADAI = EthereumToken('0xfC1E690f61EFd961294b3e1Ce3313fBD8aa4f85d')
A_KCS = EthereumToken('0xf34960d9d60be18cC1D5Afc1A6F012A723a28811')
A_MCO = EthereumToken('0xB63B606Ac810a52cCa15e44bB630fd42D8d1d83d')
A_CRO = EthereumToken('0xA0b73E1Ff0B80914AB6fe0444E65848C4C34450b')
A_SUSHI = EthereumToken('0x6B3595068778DD592e39A122f4f5a5cF09C90fE2')
A_SDT2 = EthereumToken('0x73968b9a57c6E53d41345FD57a6E6ae27d6CDB2F')
A_QTUM = EthereumToken('0x9a642d6b3368ddc662CA244bAdf32cDA716005BC')
A_OCEAN = EthereumToken('0x967da4048cD07aB37855c090aAF366e4ce1b9F48')
A_GLM = EthereumToken('0x7DD9c5Cba05E151C895FDe1CF355C9A1D5DA6429')
A_BUSD = EthereumToken('0x4Fabb145d64652a948d72533023f6E7A623C7C53')
A_AMPL = EthereumToken('0xD46bA6D942050d489DBd938a2C909A5d5039A161')
A_SYN = EthereumToken('0x1695936d6a953df699C38CA21c2140d497C08BD9')
A_API3 = EthereumToken('0x0b38210ea11411557c13457D4dA7dC6ea731B88a')
A_MFT = EthereumToken('0xDF2C7238198Ad8B389666574f2d8bc411A4b7428')
A_SLP = EthereumToken('0x37236CD05b34Cc79d3715AF2383E96dd7443dCF1')
A_DOLLAR_BASED = EthereumToken('0x68A118Ef45063051Eac49c7e647CE5Ace48a68a5')
A_BAND = EthereumToken('0xBA11D00c5f74255f56a5E366F4F77f5A186d7f55')
A_YAM_V1 = EthereumToken('0x0e2298E3B3390e3b945a5456fBf59eCc3f55DA16')
A_CHI = EthereumToken('0x0000000000004946c0e9F43F4Dee607b0eF1fA1c')

A_ADAI_V2 = EthereumToken('0x028171bCA77440897B824Ca71D1c56caC55b68A3')
Пример #22
0
    def find_curve_pool_price(
        self,
        lp_token: EthereumToken,
    ) -> Optional[Price]:
        """
        1. Obtain the pool for this token
        2. Obtain prices for assets in pool
        3. Obtain the virtual price for share and the balances of each
        token in the pool
        4. Calc the price for a share

        Returns the price of 1 LP token from the pool
        """
        assert self._ethereum is not None, 'Inquirer ethereum manager should have been initialized'  # noqa: E501

        pools = get_curve_pools()
        if lp_token.ethereum_address not in pools:
            return None
        pool = pools[lp_token.ethereum_address]
        tokens = []
        # Translate addresses to tokens
        try:
            for asset in pool.assets:
                if asset == '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE':
                    tokens.append(A_WETH)
                else:
                    tokens.append(EthereumToken(asset))
        except UnknownAsset:
            return None

        # Get price for each token in the pool
        prices = []
        for token in tokens:
            price = self.find_usd_price(token)
            if price == Price(ZERO):
                log.error(
                    f'Could not calculate price for {lp_token} due to inability to '
                    f'fetch price for {token}.', )
                return None
            prices.append(price)

        # Query virtual price of LP share and balances in the pool for each token
        contract = EthereumContract(
            address=pool.pool_address,
            abi=CURVE_POOL_ABI,
            deployed_block=0,
        )
        calls = [(pool.pool_address,
                  contract.encode(method_name='get_virtual_price'))]
        calls += [(pool.pool_address,
                   contract.encode(method_name='balances', arguments=[i]))
                  for i in range(len(pool.assets))]
        output = multicall_2(
            ethereum=self._ethereum,
            require_success=False,
            calls=calls,
        )

        # Check that the output has the correct structure
        if not all([len(call_result) == 2 for call_result in output]):
            log.debug(
                f'Failed to query contract methods while finding curve pool price. '
                f'Not every outcome has length 2. {output}', )
            return None
        # Check that all the requests were successful
        if not all([contract_output[0] for contract_output in output]):
            log.debug(
                f'Failed to query contract methods while finding curve price. {output}'
            )
            return None
        # Deserialize information obtained in the multicall execution
        data = []
        # https://github.com/PyCQA/pylint/issues/4739
        virtual_price_decoded = contract.decode(output[0][1],
                                                'get_virtual_price')  # pylint: disable=unsubscriptable-object  # noqa: E501
        if not _check_curve_contract_call(virtual_price_decoded):
            log.debug(
                f'Failed to decode get_virtual_price while finding curve price. {output}'
            )
            return None
        data.append(FVal(virtual_price_decoded[0]))  # pylint: disable=unsubscriptable-object
        for i in range(len(pool.assets)):
            amount_decoded = contract.decode(output[i + 1][1],
                                             'balances',
                                             arguments=[i])
            if not _check_curve_contract_call(amount_decoded):
                log.debug(
                    f'Failed to decode balances {i} while finding curve price. {output}'
                )
                return None
            # https://github.com/PyCQA/pylint/issues/4739
            amount = amount_decoded[0]  # pylint: disable=unsubscriptable-object
            normalized_amount = token_normalized_value_decimals(
                amount, tokens[i].decimals)
            data.append(normalized_amount)

        # Prices and data should verify this relation for the following operations
        if len(prices) != len(data) - 1:
            log.debug(
                f'Length of prices {len(prices)} does not match len of data {len(data)} '
                f'while querying curve pool price.', )
            return None
        # Total number of assets price in the pool
        total_assets_price = sum(map(operator.mul, data[1:], prices))
        if total_assets_price == 0:
            log.error(
                f'Curve pool price returned unexpected data {data} that lead to a zero price.',
            )
            return None

        # Calculate weight of each asset as the proportion of tokens value
        weights = map(lambda x: data[x + 1] * prices[x] / total_assets_price,
                      range(len(tokens)))
        assets_price = FVal(sum(map(operator.mul, weights, prices)))
        return (assets_price * FVal(data[0])) / (10**lp_token.decimals)
Пример #23
0
def test_foreignkey_conflict(rotkehlchen_api_server, globaldb):
    """Test that when a conflict that's not solvable happens the entry is ignored

    One such case is when the update of an asset would violate a foreign key constraint"""
    async_query = random.choice([False, True])
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    update_1 = """INSERT INTO assets(identifier,type,name,symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("121-ada-FADS-as", "F","A name","SYMBOL",NULL, NULL,"", "", "121-ada-FADS-as");INSERT INTO common_asset_details(asset_id, forked) VALUES("121-ada-FADS-as", "BTC");
*
UPDATE assets SET swapped_for="_ceth_0xA8d35739EE92E69241A2Afd9F513d41021A07972" WHERE identifier="_ceth_0xa74476443119A942dE498590Fe1f2454d7D4aC0d";
INSERT INTO ethereum_tokens(address, decimals, protocol) VALUES("0xa74476443119A942dE498590Fe1f2454d7D4aC0d", 18, NULL);INSERT INTO assets(identifier,type, name, symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("_ceth_0xa74476443119A942dE498590Fe1f2454d7D4aC0d", "C", "Golem", "GNT", 1478810650, "_ceth_0xA8d35739EE92E69241A2Afd9F513d41021A07972", "golem", NULL, "0xa74476443119A942dE498590Fe1f2454d7D4aC0d");
    """  # noqa: E501
    update_patch = mock_asset_updates(
        original_requests_get=requests.get,
        latest=999999991,
        updates={
            "999999991": {
                "changes": 2,
                "min_schema_version": GLOBAL_DB_VERSION,
                "max_schema_version": GLOBAL_DB_VERSION,
            }
        },
        sql_actions={"999999991": update_1},
    )
    globaldb.add_setting_value(ASSETS_VERSION_KEY, 999999990)
    start_assets_num = len(globaldb.get_all_asset_data(mapping=False))
    with update_patch:
        response = requests.get(
            api_url_for(
                rotkehlchen_api_server,
                'assetupdatesresource',
            ),
            json={'async_query': async_query},
        )
        if async_query:
            task_id = assert_ok_async_response(response)
            outcome = wait_for_async_task(
                rotkehlchen_api_server,
                task_id,
            )
            result = outcome['result']
            assert outcome['message'] == ''
        else:
            result = assert_proper_response_with_result(response)
        assert result['local'] == 999999990
        assert result['remote'] == 999999991
        assert result['new_changes'] == 2

        response = requests.post(
            api_url_for(
                rotkehlchen_api_server,
                'assetupdatesresource',
            ),
            json={'async_query': async_query},
        )
        if async_query:
            task_id = assert_ok_async_response(response)
            outcome = wait_for_async_task(
                rotkehlchen_api_server,
                task_id,
            )
            assert outcome[
                'message'] == 'Found conflicts during assets upgrade'
            result = outcome['result']
        else:
            result = assert_proper_response_with_result(
                response,
                message='Found conflicts during assets upgrade',
                status_code=HTTPStatus.CONFLICT,
            )

        # Make sure that nothing was committed
        assert globaldb.get_setting_value(ASSETS_VERSION_KEY,
                                          None) == 999999990
        assert len(
            globaldb.get_all_asset_data(mapping=False)) == start_assets_num
        with pytest.raises(UnknownAsset):
            Asset('121-ada-FADS-as')
        errors = rotki.msg_aggregator.consume_errors()
        warnings = rotki.msg_aggregator.consume_warnings()
        assert len(errors) == 0, f'Found errors: {errors}'
        assert len(warnings) == 0, f'Found warnings: {warnings}'
        # See that we get a conflict
        expected_result = [{
            'identifier': '_ceth_0xa74476443119A942dE498590Fe1f2454d7D4aC0d',
            'local': {
                'name': 'Golem',
                'symbol': 'GNT',
                'asset_type': 'ethereum token',
                'started': 1478810650,
                'forked': None,
                'swapped_for':
                '_ceth_0x7DD9c5Cba05E151C895FDe1CF355C9A1D5DA6429',
                'ethereum_address':
                '0xa74476443119A942dE498590Fe1f2454d7D4aC0d',
                'decimals': 18,
                'cryptocompare': None,
                'coingecko': 'golem',
                'protocol': None,
            },
            'remote': {
                'name': 'Golem',
                'symbol': 'GNT',
                'asset_type': 'ethereum token',
                'started': 1478810650,
                'forked': None,
                'swapped_for':
                '_ceth_0xA8d35739EE92E69241A2Afd9F513d41021A07972',
                'ethereum_address':
                '0xa74476443119A942dE498590Fe1f2454d7D4aC0d',
                'decimals': 18,
                'cryptocompare': None,
                'coingecko': 'golem',
                'protocol': None,
            },
        }]
        assert result == expected_result

        # now try the update again but specify the conflicts resolution
        conflicts = {
            '_ceth_0xa74476443119A942dE498590Fe1f2454d7D4aC0d': 'remote'
        }
        response = requests.post(
            api_url_for(
                rotkehlchen_api_server,
                'assetupdatesresource',
            ),
            json={
                'async_query': async_query,
                'conflicts': conflicts
            },
        )
        if async_query:
            task_id = assert_ok_async_response(response)
            outcome = wait_for_async_task(
                rotkehlchen_api_server,
                task_id,
            )
            assert outcome['message'] == ''
            result = outcome['result']
        else:
            result = assert_proper_response_with_result(
                response,
                message='',
                status_code=HTTPStatus.OK,
            )

        # check new asset was added and conflict was ignored with an error due to
        # inability to do anything with the missing swapped_for
        assert result is True
        assert globaldb.get_setting_value(ASSETS_VERSION_KEY,
                                          None) == 999999991
        gnt = EthereumToken('0xa74476443119A942dE498590Fe1f2454d7D4aC0d')
        assert gnt.identifier == strethaddress_to_identifier(
            '0xa74476443119A942dE498590Fe1f2454d7D4aC0d')  # noqa: E501
        assert gnt.name == 'Golem'
        assert gnt.symbol == 'GNT'
        assert gnt.asset_type == AssetType.ETHEREUM_TOKEN
        assert gnt.started == 1478810650
        assert gnt.forked is None
        assert gnt.swapped_for == A_GLM.identifier
        assert gnt.coingecko == 'golem'
        assert gnt.cryptocompare is None
        assert gnt.ethereum_address == '0xa74476443119A942dE498590Fe1f2454d7D4aC0d'
        assert gnt.decimals == 18
        assert gnt.protocol is None

        new_asset = Asset('121-ada-FADS-as')
        assert new_asset.identifier == '121-ada-FADS-as'
        assert new_asset.name == 'A name'
        assert new_asset.symbol == 'SYMBOL'
        assert new_asset.asset_type == AssetType.COUNTERPARTY_TOKEN
        assert new_asset.started is None
        assert new_asset.forked == 'BTC'
        assert new_asset.swapped_for is None
        assert new_asset.coingecko == ''
        assert new_asset.cryptocompare == ''

        errors = rotki.msg_aggregator.consume_errors()
        warnings = rotki.msg_aggregator.consume_warnings()
        assert len(errors) == 0, f'Found errors: {errors}'
        assert len(warnings) == 1
        assert f'Failed to resolve conflict for {gnt.identifier} in the DB during the v999999991 assets update. Skipping entry' in warnings[
            0]  # noqa: E501
Пример #24
0
from rotkehlchen.constants import ZERO
from rotkehlchen.constants.assets import A_USDT, A_WETH
from rotkehlchen.fval import FVal
from rotkehlchen.tests.utils.constants import A_DOLLAR_BASED
from rotkehlchen.typing import AssetAmount, Price, Timestamp

# Logic: Get balances

# Addresses
TEST_ADDRESS_1 = string_to_ethereum_address('0xfeF0E7635281eF8E3B705e9C5B86e1d3B0eAb397')
TEST_ADDRESS_2 = string_to_ethereum_address('0xcf2B8EeC2A9cE682822b252a1e9B78EedebEFB02')
TEST_ADDRESS_3 = string_to_ethereum_address('0x7777777777777777777777777777777777777777')


# Tokens without oracle data (unknown tokens)
A_SHL = EthereumToken('0x8542325B72C6D9fC0aD2Ca965A78435413a915A0')
A_CAR = EthereumToken('0x4D9e23a3842fE7Eb7682B9725cF6c507C424A41B')
A_BTR = EthereumToken('0xcbf15FB8246F679F9Df0135881CB29a3746f734b')

# Method: `_get_balances_graph`
# 'liquidityPositions' subgraph response data for TEST_ADDRESS_1
LIQUIDITY_POSITION_1 = {
    'id': '0x260e069dead76baac587b5141bb606ef8b9bab6c-0xfef0e7635281ef8e3b705e9c5b86e1d3b0eab397',
    'liquidityTokenBalance': '52.974048199782328795',
    'pair': {
        'id': '0x260e069dead76baac587b5141bb606ef8b9bab6c',
        'reserve0': '135433.787685858453561892',
        'reserve1': '72.576018267058292417',
        'token0': {
            'decimals': '18',
            'id': '0x8542325b72c6d9fc0ad2ca965a78435413a915a0',
Пример #25
0
    'aBAT': 9241085,
    'aKNC': 9241097,
    'aLEND': 9241081,
    'aLINK': 9241091,
    'aMANA': 9241110,
    'aMKR': 9241106,
    'aREP': 9241100,
    'aREN': 10472062,
    'aSNX': 9241118,
    'aWBTC': 9241225,
    'aYFI': 10748286,
    'aZRX': 9241114,
    'aAAVE': 11093579,
    'aUNI': 11132284,
}
ATOKENS_LIST = [EthereumToken(x) for x in ATOKEN_TO_DEPLOYED_BLOCK]

AAVE_RESERVE_TO_ASSET = {
    AAVE_ETH_RESERVE_ADDRESS: Asset('ETH'),
    '0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c': EthereumToken('ENJ'),
    '0x6B175474E89094C44Da98b954EedeAC495271d0F': EthereumToken('DAI'),
    '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': EthereumToken('USDC'),
    '0x57Ab1ec28D129707052df4dF418D58a2D46d5f51': EthereumToken('sUSD'),
    '0x0000000000085d4780B73119b644AE5ecd22b376': EthereumToken('TUSD'),
    '0xdAC17F958D2ee523a2206206994597C13D831ec7': EthereumToken('USDT'),
    '0x4Fabb145d64652a948d72533023f6E7A623C7C53': EthereumToken('BUSD'),
    '0x0D8775F648430679A709E98d2b0Cb6250d2887EF': EthereumToken('BAT'),
    '0xdd974D5C2e2928deA5F71b9825b8b646686BD200': EthereumToken('KNC'),
    '0x80fB784B7eD66730e8b1DBd9820aFD29931aab03': EthereumToken('LEND'),
    '0x514910771AF9Ca656af840dff83E8264EcF986CA': EthereumToken('LINK'),
    '0x0F5D2fB29fb7d3CFeE444a200298f468908cC942': EthereumToken('MANA'),
Пример #26
0
            )
        ],
        profit_loss=Balance(amount=FVal('0.006054124919207989'),
                            usd_value=ONE),
    ),
}

EXPECTED_V2_HISTORY = {
    '_ceth_0x1C6a9783F812b3Af3aBbf7de64c3cD7CC7D1af44':
    YearnVaultHistory(
        events=[
            YearnVaultEvent(
                event_type='deposit',
                block_number=12462638,
                timestamp=Timestamp(1621397797),
                from_asset=EthereumToken(
                    '0x94e131324b6054c0D789b190b2dAC504e4361b53'),
                from_value=Balance(amount=FVal('32064.715735449204040742'),
                                   usd_value=ONE),
                to_asset=EthereumToken(
                    '0x1C6a9783F812b3Af3aBbf7de64c3cD7CC7D1af44'),
                to_value=Balance(amount=FVal('32064.715735449204040742'),
                                 usd_value=ONE),
                realized_pnl=None,
                tx_hash=
                '0x0a53f8817f44ac0f8b516b7fa7ecba2861c001f506dbc465fe289a7110fcc1ca',
                log_index=16,
                version=1,
            ),
            YearnVaultEvent(
                event_type='withdraw',
                block_number=12494161,
Пример #27
0
def test_add_and_get_aave_events(data_dir, username):
    """Test that get aave events works fine and returns only events for what we need"""
    msg_aggregator = MessagesAggregator()
    data = DataHandler(data_dir, msg_aggregator)
    data.unlock(username, '123', create_new=True)

    addr1 = make_ethereum_address()
    addr1_events = [AaveSimpleEvent(
        event_type='deposit',
        asset=A_DAI,
        value=Balance(amount=FVal(1), usd_value=FVal(1)),
        block_number=1,
        timestamp=Timestamp(1),
        tx_hash='0x01653e88600a6492ad6e9ae2af415c990e623479057e4e93b163e65cfb2d4436',
        log_index=1,
    ), AaveSimpleEvent(
        event_type='withdrawal',
        asset=A_DAI,
        value=Balance(amount=FVal(1), usd_value=FVal(1)),
        block_number=2,
        timestamp=Timestamp(2),
        tx_hash='0x4147da3e5d3c0565a99192ce0b32182ab30b8e1067921d9b2a8ef3bd60b7e2ce',
        log_index=2,
    )]
    data.db.add_aave_events(address=addr1, events=addr1_events)

    addr2 = make_ethereum_address()
    addr2_events = [AaveSimpleEvent(
        event_type='deposit',
        asset=A_DAI,
        value=Balance(amount=FVal(1), usd_value=FVal(1)),
        block_number=1,
        timestamp=Timestamp(1),
        tx_hash='0x8c094d58f33e8dedcd348cb33b58f3bd447602f1fecb99e51b1c2868029eab55',
        log_index=1,
    ), AaveSimpleEvent(
        event_type='withdrawal',
        asset=A_DAI,
        value=Balance(amount=FVal(1), usd_value=FVal(1)),
        block_number=2,
        timestamp=Timestamp(2),
        tx_hash='0x58c67445d26679623f9b7d56a8be260a275cb6744a1c1ae5a8d6883a5a5c03de',
        log_index=2,
    )]
    data.db.add_aave_events(address=addr2, events=addr2_events)

    # addr3 has all types of aave events so we test serialization/deserialization
    addr3 = make_ethereum_address()
    addr3_events = [AaveSimpleEvent(
        event_type='deposit',
        asset=A_DAI,
        value=Balance(amount=FVal(1), usd_value=FVal(1)),
        block_number=1,
        timestamp=Timestamp(1),
        tx_hash='0x9e394d58f33e8dedcd348cb33b58f3bd447602f1fecb99e51b1c2868029eab55',
        log_index=1,
    ), AaveSimpleEvent(
        event_type='withdrawal',
        asset=A_DAI,
        value=Balance(amount=FVal(1), usd_value=FVal(1)),
        block_number=2,
        timestamp=Timestamp(2),
        tx_hash='0x4c167445d26679623f9b7d56a8be260a275cb6744a1c1ae5a8d6883a5a5c03de',
        log_index=2,
    ), AaveSimpleEvent(
        event_type='interest',
        asset=Asset('WBTC'),
        value=Balance(amount=FVal(1), usd_value=FVal(1)),
        block_number=4,
        timestamp=Timestamp(4),
        tx_hash='0x49c67445d26679623f9b7d56a8be260a275cb6744a1c1ae5a8d6883a5a5c03de',
        log_index=4,
    ), AaveBorrowEvent(
        event_type='borrow',
        asset=Asset('ETH'),
        value=Balance(amount=FVal(1), usd_value=FVal(1)),
        block_number=5,
        timestamp=Timestamp(5),
        tx_hash='0x19c67445d26679623f9b7d56a8be260a275cb6744a1c1ae5a8d6883a5a5c03de',
        log_index=5,
        borrow_rate_mode='stable',
        borrow_rate=FVal('0.05233232323423432'),
        accrued_borrow_interest=FVal('5.112234'),
    ), AaveRepayEvent(
        event_type='repay',
        asset=Asset('MANA'),
        value=Balance(amount=FVal(1), usd_value=FVal(1)),
        block_number=6,
        timestamp=Timestamp(6),
        tx_hash='0x29c67445d26679623f9b7d56a8be260a275cb6744a1c1ae5a8d6883a5a5c03de',
        log_index=6,
        fee=Balance(amount=FVal('0.1'), usd_value=FVal('0.1')),
    ), AaveLiquidationEvent(
        event_type='liquidation',
        collateral_asset=Asset('ETH'),
        collateral_balance=Balance(amount=FVal(1), usd_value=FVal(1)),
        principal_asset=Asset('ETH'),
        principal_balance=Balance(amount=FVal(1), usd_value=FVal(1)),
        block_number=7,
        log_index=7,
        timestamp=Timestamp(7),
        tx_hash='0x39c67445d26679623f9b7d56a8be260a275cb6744a1c1ae5a8d6883a5a5c03de',
    )]
    data.db.add_aave_events(address=addr3, events=addr3_events)

    events = data.db.get_aave_events(address=addr1, atoken=EthereumToken('aDAI'))
    assert events == addr1_events
    events = data.db.get_aave_events(address=addr2, atoken=EthereumToken('aDAI'))
    assert events == addr2_events
    events = data.db.get_aave_events(address=addr3)
    assert events == addr3_events

    # check that all aave events are properly hashable (aka can go in a set)
    test_set = set()
    for event in addr3_events:
        test_set.add(event)
    assert len(test_set) == len(addr3_events)
Пример #28
0
from rotkehlchen.constants.misc import ZERO
from rotkehlchen.fval import FVal
from rotkehlchen.serialization.deserialize import deserialize_ethereum_address
from rotkehlchen.tests.api.test_balancer import BALANCER_TEST_ADDR2_EXPECTED_TRADES
from rotkehlchen.typing import AssetAmount, Location, Price, Timestamp, TradeType

TEST_SWAPS_TX_1 = [
    AMMSwap(
        tx_hash='0x1b0d3525964d8e5fbcc0dcdeebcced4bec9017f648e97c3c9761fda1ca6e7b22',
        log_index=254,
        address=deserialize_ethereum_address('0x8e670b4d6651C4051e65B21AA4a575F3f99b8B83'),
        from_address=deserialize_ethereum_address('0x65003947dC16956AfC4400008606001500940000'),
        to_address=deserialize_ethereum_address('0x7860E28ebFB8Ae052Bfe279c07aC5d94c9cD2937'),
        timestamp=Timestamp(1614094145),
        location=Location.BALANCER,
        token0=EthereumToken('USDC'),
        token1=EthereumToken('AMPL'),
        amount0_in=AssetAmount(FVal('12401.224639')),
        amount1_in=AssetAmount(ZERO),
        amount0_out=AssetAmount(ZERO),
        amount1_out=AssetAmount(FVal('14285.153512382')),
    ),
]
TEST_SWAPS_TX_2 = [
    AMMSwap(
        tx_hash='0x1b0d3525964d8e5fbcc0dcdeebcced4bec9017f648e97c3c9761fda1ca6e7b22',
        log_index=254,
        address=deserialize_ethereum_address('0x8e670b4d6651C4051e65B21AA4a575F3f99b8B83'),
        from_address=deserialize_ethereum_address('0x65003947dC16956AfC4400008606001500940000'),
        to_address=deserialize_ethereum_address('0x7860E28ebFB8Ae052Bfe279c07aC5d94c9cD2937'),
        timestamp=Timestamp(1614094145),
Пример #29
0
def get_balancer_test_addr2_expected_trades():
    """In a function since the new(unknown) assets needs to have been loaded in the DB"""
    A_WCRES = EthereumToken.initialize(  # noqa: N806
        address=string_to_ethereum_address(
            '0xa0afAA285Ce85974c3C881256cB7F225e3A1178a'),
        decimals=18,
        symbol='wCRES',
    )
    return [
        AMMTrade(
            trade_type=TradeType.BUY,
            base_asset=A_WETH,
            quote_asset=A_AAVE,
            amount=AssetAmount(FVal('1.616934038985744521')),
            rate=Price(FVal('6.963972908793392530935439799')),
            trade_index=1,
            swaps=[
                AMMSwap(
                    tx_hash=
                    '0x3c457da9b541ae39a7dc781ab04a03938b98b5649512aec2a2d32635c9bbf589',  # noqa: E501
                    log_index=24,
                    address=string_to_ethereum_address(
                        '0x029f388aC4D5C8BfF490550ce0853221030E822b'
                    ),  # noqa: E501
                    from_address=string_to_ethereum_address(
                        '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56'
                    ),  # noqa: E501
                    to_address=string_to_ethereum_address(
                        '0x7c90a3cd7Ec80dd2F633ed562480AbbEEd3bE546'
                    ),  # noqa: E501
                    timestamp=Timestamp(1607008178),
                    location=Location.BALANCER,
                    token0=A_AAVE,
                    token1=A_WETH,
                    amount0_in=AssetAmount(FVal('11.260284842802604032')),
                    amount1_in=AssetAmount(ZERO),
                    amount0_out=AssetAmount(ZERO),
                    amount1_out=AssetAmount(FVal('1.616934038985744521')),
                ),
            ],
        ),
        AMMTrade(
            trade_type=TradeType.BUY,
            base_asset=A_AAVE,
            quote_asset=A_WETH,
            amount=AssetAmount(FVal('11.260286362820602094')),
            rate=Price(FVal('0.1416068599966922676173010716')),
            trade_index=0,
            swaps=[
                AMMSwap(
                    tx_hash=
                    '0x3c457da9b541ae39a7dc781ab04a03938b98b5649512aec2a2d32635c9bbf589',  # noqa: E501
                    log_index=18,
                    address=string_to_ethereum_address(
                        '0x029f388aC4D5C8BfF490550ce0853221030E822b'
                    ),  # noqa: E501
                    from_address=string_to_ethereum_address(
                        '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56'
                    ),  # noqa: E501
                    to_address=string_to_ethereum_address(
                        '0x70985E557aE0CD6dC88189a532e54FbC61927BAd'
                    ),  # noqa: E501
                    timestamp=Timestamp(1607008178),
                    location=Location.BALANCER,
                    token0=A_WETH,
                    token1=A_AAVE,
                    amount0_in=AssetAmount(FVal('1.594533794502600192')),
                    amount1_in=AssetAmount(ZERO),
                    amount0_out=AssetAmount(ZERO),
                    amount1_out=AssetAmount(FVal('11.260286362820602094')),
                ),
            ],
        ),
        AMMTrade(
            trade_type=TradeType.BUY,
            base_asset=A_WETH,
            quote_asset=A_SYN,
            amount=AssetAmount(FVal('1.352902561458047718')),
            rate=Price(FVal('724.4303350385182691258363763')),
            trade_index=0,
            swaps=[
                AMMSwap(
                    tx_hash=
                    '0x5e235216cb03e4eb234014f5ccf3efbfddd40c4576424e2a8204f1d12b96ed35',  # noqa: E501
                    log_index=143,
                    address=string_to_ethereum_address(
                        '0x029f388aC4D5C8BfF490550ce0853221030E822b'
                    ),  # noqa: E501
                    from_address=string_to_ethereum_address(
                        '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56'
                    ),  # noqa: E501
                    to_address=string_to_ethereum_address(
                        '0x8982E9bBf7AC6A49c434aD81D2fF8e16895318e5'
                    ),  # noqa: E501
                    timestamp=Timestamp(1607008218),
                    location=Location.BALANCER,
                    token0=A_SYN,
                    token1=A_WETH,
                    amount0_in=AssetAmount(FVal('980.08365587152306176')),
                    amount1_in=AssetAmount(ZERO),
                    amount0_out=AssetAmount(ZERO),
                    amount1_out=AssetAmount(FVal('1.352902561458047718')),
                ),
            ],
        ),
        AMMTrade(
            trade_type=TradeType.BUY,
            base_asset=A_WETH,
            quote_asset=A_WCRES,
            amount=AssetAmount(FVal('0.205709519074945018')),
            rate=Price(FVal('232.7409943164679514496089589')),
            trade_index=0,
            swaps=[
                AMMSwap(
                    tx_hash=
                    '0xf54be824b4619777f1db0e3da91b0cd52f6dba730c95a75644e2b085e6ab9824',  # noqa: E501
                    log_index=300,
                    address=string_to_ethereum_address(
                        '0x029f388aC4D5C8BfF490550ce0853221030E822b'
                    ),  # noqa: E501
                    from_address=string_to_ethereum_address(
                        '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56'
                    ),  # noqa: E501
                    to_address=string_to_ethereum_address(
                        '0x10996eC4f3E7A1b314EbD966Fa8b1ad0fE0f8307'
                    ),  # noqa: E501
                    timestamp=Timestamp(1607009877),
                    location=Location.BALANCER,
                    token0=A_WCRES,
                    token1=A_WETH,
                    amount0_in=AssetAmount(FVal('47.87703800986513408')),
                    amount1_in=AssetAmount(ZERO),
                    amount0_out=AssetAmount(ZERO),
                    amount1_out=AssetAmount(FVal('0.205709519074945018')),
                ),
            ],
        ),
        AMMTrade(
            trade_type=TradeType.BUY,
            base_asset=A_API3,
            quote_asset=A_WETH,
            amount=AssetAmount(FVal('295.881648100500428692')),
            rate=Price(FVal('0.003346787723157288562491614498')),
            trade_index=0,
            swaps=[
                AMMSwap(
                    tx_hash=
                    '0xfed4e15051e3ce4dc0d2816f719701e5920e40bf41614b5feaa3c5a6a0186c03',  # noqa: E501
                    log_index=22,
                    address=string_to_ethereum_address(
                        '0x029f388aC4D5C8BfF490550ce0853221030E822b'
                    ),  # noqa: E501
                    from_address=string_to_ethereum_address(
                        '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56'
                    ),  # noqa: E501
                    to_address=string_to_ethereum_address(
                        '0x997c0fc9578a8194EFDdE2E0cD7aa6A69cFCD7c1'
                    ),  # noqa: E501
                    timestamp=Timestamp(1607010888),
                    location=Location.BALANCER,
                    token0=A_WETH,
                    token1=A_API3,
                    amount0_in=AssetAmount(FVal('0.990253067370299904')),
                    amount1_in=AssetAmount(ZERO),
                    amount0_out=AssetAmount(ZERO),
                    amount1_out=AssetAmount(FVal('295.881648100500428692')),
                ),
            ],
        ),
        AMMTrade(
            trade_type=TradeType.BUY,
            base_asset=A_WETH,
            quote_asset=A_MFT,
            amount=AssetAmount(FVal('0.686544199299304057')),
            rate=Price(FVal('243775.0324093115004367119900')),
            trade_index=0,
            swaps=[
                AMMSwap(
                    tx_hash=
                    '0xf0147c4b81098676c08ae20ae5bf8f8b60d0ad79eec484f3f93ac6ab49a3c51c',  # noqa: E501
                    log_index=97,
                    address=string_to_ethereum_address(
                        '0x029f388aC4D5C8BfF490550ce0853221030E822b'
                    ),  # noqa: E501
                    from_address=string_to_ethereum_address(
                        '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56'
                    ),  # noqa: E501
                    to_address=string_to_ethereum_address(
                        '0x2Eb6CfbFFC8785Cd0D9f2d233d0a617bF4269eeF'
                    ),  # noqa: E501
                    timestamp=Timestamp(1607015059),
                    location=Location.BALANCER,
                    token0=A_MFT,
                    token1=A_WETH,
                    amount0_in=AssetAmount(FVal('167362.334434612660404224')),
                    amount1_in=AssetAmount(ZERO),
                    amount0_out=AssetAmount(ZERO),
                    amount1_out=AssetAmount(FVal('0.686544199299304057')),
                ),
            ],
        ),
        AMMTrade(
            trade_type=TradeType.BUY,
            base_asset=A_WETH,
            quote_asset=A_AAVE,
            amount=AssetAmount(FVal('3.055412574642681758')),
            rate=Price(FVal('6.916116208273240607778771150')),
            trade_index=1,
            swaps=[
                AMMSwap(
                    tx_hash=
                    '0x67c0e9a0fdd002d0b9d1cca0c8e4ca4d30435bbf57bbf0091396275efaea414b',  # noqa: E501
                    log_index=37,
                    address=string_to_ethereum_address(
                        '0x029f388aC4D5C8BfF490550ce0853221030E822b'
                    ),  # noqa: E501
                    from_address=string_to_ethereum_address(
                        '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56'
                    ),  # noqa: E501
                    to_address=string_to_ethereum_address(
                        '0x0E552307659E70bF61f918f96AA880Cdec40d7E2'
                    ),  # noqa: E501
                    timestamp=Timestamp(1607015339),
                    location=Location.BALANCER,
                    token0=A_AAVE,
                    token1=A_WETH,
                    amount0_in=AssetAmount(FVal('21.131588430448123904')),
                    amount1_in=AssetAmount(ZERO),
                    amount0_out=AssetAmount(ZERO),
                    amount1_out=AssetAmount(FVal('3.055412574642681758')),
                ),
            ],
        ),
        AMMTrade(
            trade_type=TradeType.BUY,
            base_asset=A_AAVE,
            quote_asset=A_WETH,
            amount=AssetAmount(FVal('21.131588567541018817')),
            rate=Price(FVal('0.1435213742524287826717337545')),
            trade_index=0,
            swaps=[
                AMMSwap(
                    tx_hash=
                    '0x67c0e9a0fdd002d0b9d1cca0c8e4ca4d30435bbf57bbf0091396275efaea414b',  # noqa: E501
                    log_index=31,
                    address=string_to_ethereum_address(
                        '0x029f388aC4D5C8BfF490550ce0853221030E822b'
                    ),  # noqa: E501
                    from_address=string_to_ethereum_address(
                        '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56'
                    ),  # noqa: E501
                    to_address=string_to_ethereum_address(
                        '0x7c90a3cd7Ec80dd2F633ed562480AbbEEd3bE546'
                    ),  # noqa: E501
                    timestamp=Timestamp(1607015339),
                    location=Location.BALANCER,
                    token0=A_WETH,
                    token1=A_AAVE,
                    amount0_in=AssetAmount(FVal('3.0328346313504')),
                    amount1_in=AssetAmount(ZERO),
                    amount0_out=AssetAmount(ZERO),
                    amount1_out=AssetAmount(FVal('21.131588567541018817')),
                ),
            ],
        ),
    ]
Пример #30
0
from rotkehlchen.utils.interfaces import EthereumModule
from rotkehlchen.utils.misc import address_to_bytes32, hex_or_bytes_to_int, ts_now

if TYPE_CHECKING:
    from rotkehlchen.chain.ethereum.manager import EthereumManager
    from rotkehlchen.chain.ethereum.zerion import GIVEN_DEFI_BALANCES, DefiProtocolBalances
    from rotkehlchen.db.dbhandler import DBHandler

BLOCKS_PER_YEAR = 2425846

YEARN_VAULTS = {
    'yyDAI+yUSDC+yUSDT+yTUSD':
    YearnVault(
        name='YCRV Vault',
        contract=YEARN_YCRV_VAULT,
        underlying_token=EthereumToken('yDAI+yUSDC+yUSDT+yTUSD'),
        token=EthereumToken('yyDAI+yUSDC+yUSDT+yTUSD'),
    ),
    'yDAI':
    YearnVault(
        name='YDAI Vault',
        contract=YEARN_DAI_VAULT,
        underlying_token=EthereumToken('DAI'),
        token=EthereumToken('yDAI'),
    ),
    'yWETH':
    YearnVault(
        name='YWETH Vault',
        contract=YEARN_WETH_VAULT,
        underlying_token=EthereumToken('WETH'),
        token=EthereumToken('yWETH'),