Beispiel #1
0
def test_add_remove_exchange(user_data_dir):
    """Tests that adding and removing an exchange in the DB works.

    Also unknown exchanges should fail
    """
    msg_aggregator = MessagesAggregator()
    db = DBHandler(user_data_dir, '123', msg_aggregator, None)

    # Test that an unknown exchange fails
    with pytest.raises(InputError):
        db.add_exchange('non_existing_exchange', 'api_key', 'api_secret')
    credentials = db.get_exchange_credentials()
    assert len(credentials) == 0

    kraken_api_key = ApiKey('kraken_api_key')
    kraken_api_secret = ApiSecret(b'kraken_api_secret')
    binance_api_key = ApiKey('binance_api_key')
    binance_api_secret = ApiSecret(b'binance_api_secret')

    # add mock kraken and binance
    db.add_exchange('kraken', kraken_api_key, kraken_api_secret)
    db.add_exchange('binance', binance_api_key, binance_api_secret)
    # and check the credentials can be retrieved
    credentials = db.get_exchange_credentials()
    assert len(credentials) == 2
    assert credentials['kraken'].api_key == kraken_api_key
    assert credentials['kraken'].api_secret == kraken_api_secret
    assert credentials['binance'].api_key == binance_api_key
    assert credentials['binance'].api_secret == binance_api_secret

    # remove an exchange and see it works
    db.remove_exchange('kraken')
    credentials = db.get_exchange_credentials()
    assert len(credentials) == 1
Beispiel #2
0
 def _serialize(
     value: ApiSecret,
     attr: str,  # pylint: disable=unused-argument
     obj: Any,  # pylint: disable=unused-argument
     **_kwargs: Any,
 ) -> str:
     return str(value.decode())
Beispiel #3
0
def test_binance_query_trade_history_custom_markets(function_scope_binance,
                                                    user_data_dir):
    """Test that custom pairs are queried correctly"""
    msg_aggregator = MessagesAggregator()
    db = DBHandler(user_data_dir, '123', msg_aggregator, None)

    binance_api_key = ApiKey('binance_api_key')
    binance_api_secret = ApiSecret(b'binance_api_secret')
    db.add_exchange('binance', Location.BINANCE, binance_api_key,
                    binance_api_secret)

    binance = function_scope_binance

    markets = ['ETHBTC', 'BNBBTC', 'BTCUSDC']
    db.set_binance_pairs('binance', markets, Location.BINANCE)

    count = 0
    p = re.compile(r'symbol=[A-Z]*')
    seen = set()

    def mock_my_trades(url, timeout):  # pylint: disable=unused-argument
        nonlocal count
        count += 1
        market = p.search(url).group()[7:]
        assert market in markets and market not in seen
        seen.add(market)
        text = '[]'
        return MockResponse(200, text)

    with patch.object(binance.session, 'get', side_effect=mock_my_trades):
        binance.query_trade_history(start_ts=0,
                                    end_ts=1564301134,
                                    only_cache=False)

    assert count == len(markets)
Beispiel #4
0
    def __init__(self, args: argparse.Namespace) -> None:
        args.logfile = 'data_faker.log'
        self.rotki = Rotkehlchen(args)

        random_seed = datetime.datetime.now()
        logger.info(f'Random seed used: {random_seed}')
        random.seed(random_seed)

        self.create_new_user(args.user_name, args.user_password)

        # Start the fake exchanges API for the duration of the fake
        # history creation. We need it up so that we can emulate responses
        # from the exchanges
        self.fake_kraken = FakeKraken()
        self.fake_binance = FakeBinance()
        mock_api = RestAPI(fake_kraken=self.fake_kraken,
                           fake_binance=self.fake_binance)
        self.mock_server = APIServer(rest_api=mock_api)
        self.mock_server.start()

        self.rotki.setup_exchange(
            name='kraken',
            location=Location.KRAKEN,
            api_key=ApiKey(str(make_random_b64bytes(128))),
            api_secret=ApiSecret(make_random_b64bytes(128)),
        )
        self.rotki.setup_exchange(
            name='binance',
            location=Location.BINANCE,
            api_key=ApiKey(str(make_random_b64bytes(128))),
            api_secret=ApiSecret(make_random_b64bytes(128)),
        )

        self.writer = ActionWriter(
            trades_number=args.trades_number,
            seconds_between_trades=args.seconds_between_trades,
            seconds_between_balance_save=args.seconds_between_balance_save,
            rotkehlchen=self.rotki,
            fake_kraken=self.fake_kraken,
            fake_binance=self.fake_binance,
        )

        self.writer.generate_history()
        # stop the fake exchange API. Will be started again once we are finished,
        # ready to serve the Rotkehlchen client
        self.mock_server.stop()
Beispiel #5
0
 def _deserialize(
     self,
     value: str,
     attr: Optional[str],  # pylint: disable=unused-argument
     data: Optional[Mapping[str, Any]],  # pylint: disable=unused-argument
     **_kwargs: Any,
 ) -> ApiSecret:
     if not isinstance(value, str):
         raise ValidationError('Given API Secret should be a string')
     return ApiSecret(value.encode())
Beispiel #6
0
 def _deserialize(
         self,
         value: str,
         attr,  # pylint: disable=unused-argument
         data,  # pylint: disable=unused-argument
         **kwargs,  # pylint: disable=unused-argument
 ) -> ApiSecret:
     if not isinstance(value, str):
         raise ValidationError('Given API Secret should be a string')
     return ApiSecret(value.encode())
Beispiel #7
0
def create_test_bitmex(
    database: DBHandler,
    msg_aggregator: MessagesAggregator,
) -> Bitmex:
    # API key/secret from tests cases here: https://www.bitmex.com/app/apiKeysUsage
    bitmex = Bitmex(
        api_key=ApiKey('LAqUlngMIQkIUjXMUreyu3qn'),
        secret=ApiSecret(b'chNOOS4KvNXR_Xq4k4c9qsfoKWvnDecLATCRlcBwyKDYnWgO'),
        database=database,
        msg_aggregator=msg_aggregator,
    )
    bitmex.first_connection_made = True
    return bitmex
Beispiel #8
0
def test_binance_pairs(user_data_dir):
    msg_aggregator = MessagesAggregator()
    db = DBHandler(user_data_dir, '123', msg_aggregator, None)

    binance_api_key = ApiKey('binance_api_key')
    binance_api_secret = ApiSecret(b'binance_api_secret')
    db.add_exchange('binance', Location.BINANCE, binance_api_key,
                    binance_api_secret)

    db.set_binance_pairs('binance', ['ETHUSDC', 'ETHBTC', 'BNBBTC'],
                         Location.BINANCE)
    query = db.get_binance_pairs('binance', Location.BINANCE)
    assert query == ['ETHUSDC', 'ETHBTC', 'BNBBTC']

    db.set_binance_pairs('binance', [], Location.BINANCE)
    query = db.get_binance_pairs('binance', Location.BINANCE)
    assert query == []
Beispiel #9
0
def create_patched_premium_with_keypair(
    patch_get: bool,
    metadata_last_modify_ts=None,
    metadata_data_hash=None,
    saved_data=None,
):
    api_key = ApiKey(base64.b64encode(make_random_b64bytes(128)))
    api_secret = ApiSecret(base64.b64encode(make_random_b64bytes(128)))
    patches = patched_create_premium(
        api_key,
        api_secret,
        patch_get,
        metadata_last_modify_ts,
        metadata_data_hash,
        saved_data,
    )
    return api_key, api_secret, patches[0], patches[1]
Beispiel #10
0
    def set_credentials(self, api_key: ApiKey, api_secret: ApiSecret) -> None:
        """Try to set the credentials for a premium rotkehlchen subscription

        Raises IncorrectApiKeyFormat if the given key is not in a proper format
        Raises AuthenticationError if the given key is rejected by the Rotkehlchen server
        """
        old_api_key = self.api_key
        old_secret = ApiSecret(base64.b64encode(self.secret))

        # Forget the last active value since we are trying new credentials
        self.status = SubscriptionStatus.UNKNOWN

        # If what's given is not even valid b64 encoding then stop here
        try:
            self.reset_credentials(api_key, api_secret)
        except BinasciiError as e:
            raise IncorrectApiKeyFormat(f'Secret Key formatting error: {str(e)}')

        active = self.is_active()
        if not active:
            self.reset_credentials(old_api_key, old_secret)
            raise AuthenticationError('Rotkehlchen API key was rejected by server')
Beispiel #11
0
def test_add_remove_exchange(user_data_dir):
    """Tests that adding and removing an exchange in the DB works.

    Also unknown exchanges should fail
    """
    msg_aggregator = MessagesAggregator()
    db = DBHandler(user_data_dir, '123', msg_aggregator, None)

    # Test that an unknown exchange fails
    with pytest.raises(InputError):
        db.add_exchange('foo', Location.EXTERNAL, 'api_key', 'api_secret')
    credentials = db.get_exchange_credentials()
    assert len(credentials) == 0

    kraken_api_key1 = ApiKey('kraken_api_key')
    kraken_api_secret1 = ApiSecret(b'kraken_api_secret')
    kraken_api_key2 = ApiKey('kraken_api_key2')
    kraken_api_secret2 = ApiSecret(b'kraken_api_secret2')
    binance_api_key = ApiKey('binance_api_key')
    binance_api_secret = ApiSecret(b'binance_api_secret')

    # add mock kraken and binance
    db.add_exchange('kraken1', Location.KRAKEN, kraken_api_key1,
                    kraken_api_secret1)
    db.add_exchange('kraken2', Location.KRAKEN, kraken_api_key2,
                    kraken_api_secret2)
    db.add_exchange('binance', Location.BINANCE, binance_api_key,
                    binance_api_secret)
    # and check the credentials can be retrieved
    credentials = db.get_exchange_credentials()
    assert len(credentials) == 2
    assert len(credentials[Location.KRAKEN]) == 2
    kraken1 = credentials[Location.KRAKEN][0]
    assert kraken1.name == 'kraken1'
    assert kraken1.api_key == kraken_api_key1
    assert kraken1.api_secret == kraken_api_secret1
    kraken2 = credentials[Location.KRAKEN][1]
    assert kraken2.name == 'kraken2'
    assert kraken2.api_key == kraken_api_key2
    assert kraken2.api_secret == kraken_api_secret2
    assert len(credentials[Location.BINANCE]) == 1
    binance = credentials[Location.BINANCE][0]
    assert binance.name == 'binance'
    assert binance.api_key == binance_api_key
    assert binance.api_secret == binance_api_secret

    # remove an exchange and see it works
    db.remove_exchange('kraken1', Location.KRAKEN)
    credentials = db.get_exchange_credentials()
    assert len(credentials) == 2
    assert len(credentials[Location.KRAKEN]) == 1
    kraken2 = credentials[Location.KRAKEN][0]
    assert kraken2.name == 'kraken2'
    assert kraken2.api_key == kraken_api_key2
    assert kraken2.api_secret == kraken_api_secret2
    assert len(credentials[Location.BINANCE]) == 1
    binance = credentials[Location.BINANCE][0]
    assert binance.name == 'binance'
    assert binance.api_key == binance_api_key
    assert binance.api_secret == binance_api_secret

    # remove last exchange of a location and see nothing is returned
    db.remove_exchange('kraken2', Location.KRAKEN)
    credentials = db.get_exchange_credentials()
    assert len(credentials) == 1
    assert len(credentials[Location.BINANCE]) == 1
    binance = credentials[Location.BINANCE][0]
    assert binance.name == 'binance'
    assert binance.api_key == binance_api_key
    assert binance.api_secret == binance_api_secret
Beispiel #12
0
def make_api_secret() -> ApiSecret:
    return ApiSecret(base64.b64encode(make_random_b64bytes(128)))
Beispiel #13
0
def test_associated_locations(database):
    """Test that locations imported in different places are correctly stored in database"""
    # Add trades from different locations
    trades = [Trade(
        timestamp=Timestamp(1595833195),
        location=Location.CRYPTOCOM,
        base_asset=A_ETH,
        quote_asset=A_EUR,
        trade_type=TradeType.BUY,
        amount=AssetAmount(FVal('1.0')),
        rate=Price(FVal('281.14')),
        fee=Fee(ZERO),
        fee_currency=A_USD,
        link='',
        notes='',
    ), Trade(
        timestamp=Timestamp(1587825824),
        location=Location.CRYPTOCOM,
        base_asset=A_ETH,
        quote_asset=A_EUR,
        trade_type=TradeType.BUY,
        amount=AssetAmount(FVal('50.0')),
        rate=Price(FVal('3.521')),
        fee=Fee(ZERO),
        fee_currency=A_USD,
        link='',
        notes='',
    ), Trade(
        timestamp=Timestamp(1596014214),
        location=Location.BLOCKFI,
        base_asset=A_ETH,
        quote_asset=A_EUR,
        trade_type=TradeType.BUY,
        amount=AssetAmount(FVal('50.0')),
        rate=Price(FVal('3.521')),
        fee=Fee(ZERO),
        fee_currency=A_USD,
        link='',
        notes='',
    ), Trade(
        timestamp=Timestamp(1565888464),
        location=Location.NEXO,
        base_asset=A_ETH,
        quote_asset=A_EUR,
        trade_type=TradeType.BUY,
        amount=AssetAmount(FVal('50.0')),
        rate=Price(FVal('3.521')),
        fee=Fee(ZERO),
        fee_currency=A_USD,
        link='',
        notes='',
    ), Trade(
        timestamp=Timestamp(1596014214),
        location=Location.NEXO,
        base_asset=A_ETH,
        quote_asset=A_EUR,
        trade_type=TradeType.BUY,
        amount=AssetAmount(FVal('50.0')),
        rate=Price(FVal('3.521')),
        fee=Fee(ZERO),
        fee_currency=A_USD,
        link='',
        notes='',
    ), Trade(
        timestamp=Timestamp(1612051199),
        location=Location.BLOCKFI,
        base_asset=symbol_to_asset_or_token('USDC'),
        quote_asset=symbol_to_asset_or_token('LTC'),
        trade_type=TradeType.BUY,
        amount=AssetAmount(FVal('6404.6')),
        rate=Price(FVal('151.6283999982779809352223797')),
        fee=None,
        fee_currency=None,
        link='',
        notes='One Time',
    ), Trade(
        timestamp=Timestamp(1595833195),
        location=Location.POLONIEX,
        base_asset=A_ETH,
        quote_asset=A_EUR,
        trade_type=TradeType.BUY,
        amount=AssetAmount(FVal('1.0')),
        rate=Price(FVal('281.14')),
        fee=Fee(ZERO),
        fee_currency=A_USD,
        link='',
        notes='',
    ), Trade(
        timestamp=Timestamp(1596429934),
        location=Location.COINBASE,
        base_asset=A_ETH,
        quote_asset=A_EUR,
        trade_type=TradeType.BUY,
        amount=AssetAmount(FVal('0.00061475')),
        rate=Price(FVal('309.0687271248474989833265555')),
        fee=Fee(ZERO),
        fee_currency=A_USD,
        link='',
        notes='',
    ), Trade(
        timestamp=Timestamp(1596429934),
        location=Location.EXTERNAL,
        base_asset=A_ETH,
        quote_asset=A_EUR,
        trade_type=TradeType.BUY,
        amount=AssetAmount(FVal('1')),
        rate=Price(FVal('320')),
        fee=Fee(ZERO),
        fee_currency=A_USD,
        link='',
        notes='',
    )]

    # Add multiple entries for same exchange + connected exchange
    database.add_trades(trades)
    kraken_api_key1 = ApiKey('kraken_api_key')
    kraken_api_secret1 = ApiSecret(b'kraken_api_secret')
    kraken_api_key2 = ApiKey('kraken_api_key2')
    kraken_api_secret2 = ApiSecret(b'kraken_api_secret2')
    binance_api_key = ApiKey('binance_api_key')
    binance_api_secret = ApiSecret(b'binance_api_secret')

    # add mock kraken and binance
    database.add_exchange('kraken1', Location.KRAKEN, kraken_api_key1, kraken_api_secret1)
    database.add_exchange('kraken2', Location.KRAKEN, kraken_api_key2, kraken_api_secret2)
    database.add_exchange('binance', Location.BINANCE, binance_api_key, binance_api_secret)

    # Add uniswap and sushiswap events
    database.add_amm_events([
        LiquidityPoolEvent(
            tx_hash='0x47ea26957ce09e84a51b51dfdab6a4ac1c3672a372eef77b15ef7677174ac847',
            log_index=23,
            address=ChecksumEthAddress('0x3163Bb273E8D9960Ce003fD542bF26b4C529f515'),
            timestamp=Timestamp(1590011534),
            event_type=EventType.MINT_SUSHISWAP,
            pool_address=ChecksumEthAddress('0xa2107FA5B38d9bbd2C461D6EDf11B11A50F6b974'),
            token0=EthereumToken('0x514910771AF9Ca656af840dff83E8264EcF986CA'),
            token1=EthereumToken('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'),
            amount0=FVal('3.313676003468974932'),
            amount1=FVal('0.064189269269768657'),
            usd_price=FVal('26.94433946158740371839009166230438'),
            lp_amount=FVal('0.460858304063739927'),
        ),
    ])
    database.add_amm_swaps([
        AMMSwap(
            tx_hash='0xa54bf4c68d435e3c8f432fd7e62b7f8aca497a831a3d3fca305a954484ddd7b2',
            log_index=208,
            address=ChecksumEthAddress('0xa2107FA5B38d9bbd2C461D6EDf11B11A50F6b974'),
            from_address=string_to_ethereum_address('0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F'),
            to_address=string_to_ethereum_address('0xC9cB53B48A2f3A9e75982685644c1870F1405CCb'),
            timestamp=Timestamp(1609301469),
            location=Location.UNISWAP,
            token0=EthereumToken('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'),
            token1=EthereumToken('0xdAC17F958D2ee523a2206206994597C13D831ec7'),
            amount0_in=AssetAmount(FVal('2.6455727132446468')),
            amount1_in=AssetAmount(ZERO),
            amount0_out=AssetAmount(ZERO),
            amount1_out=AssetAmount(FVal('1936.810111')),
        ),
    ])
    database.add_balancer_events([
        BalancerEvent(
            tx_hash='0xa54bf4c68d435e3c8f432fd7e62b7f8aca497a831a3d3fca305a954484ddd7b3',
            log_index=23,
            address=ChecksumEthAddress('0xa2107FA5B38d9bbd2C461D6EDf11B11A50F6b974'),
            timestamp=Timestamp(1609301469),
            event_type=BalancerBPTEventType.MINT,
            pool_address_token=EthereumToken('0x514910771AF9Ca656af840dff83E8264EcF986CA'),
            lp_balance=Balance(amount=FVal(2), usd_value=FVal(3)),
            amounts=[
                AssetAmount(FVal(1)),
                AssetAmount(FVal(2)),
            ],
        ),
    ])
    expected_locations = {
        Location.KRAKEN,
        Location.BINANCE,
        Location.BLOCKFI,
        Location.NEXO,
        Location.CRYPTOCOM,
        Location.POLONIEX,
        Location.COINBASE,
        Location.EXTERNAL,
        Location.SUSHISWAP,
        Location.UNISWAP,
        Location.BALANCER,
    }

    assert set(database.get_associated_locations()) == expected_locations