Exemple #1
0
def test_add_edit_token_with_wrong_swapped_for(globaldb):
    """Test that giving a non-existing swapped_for token in the DB raises InputError

    This can only be unit tested since via the API, marshmallow checks for Asset existence already
    """
    # To unit test it we need to even hack it a bit. Make a new token, add it in the DB
    # then delete it and then try to add a new one referencing the old one. Since we
    # need to obtain a valid EthereumToken object
    address_to_delete = make_ethereum_address()
    token_to_delete = EthereumToken.initialize(
        address=address_to_delete,
        decimals=18,
        name='willdell',
        symbol='DELME',
    )
    token_to_delete_id = 'DELMEID1'
    globaldb.add_asset(
        asset_id=token_to_delete_id,
        asset_type=AssetType.ETHEREUM_TOKEN,
        data=token_to_delete,
    )
    asset_to_delete = Asset(token_to_delete_id)
    assert globaldb.delete_ethereum_token(
        address_to_delete) == token_to_delete_id

    # now try to add a new token with swapped_for pointing to a non existing token in the DB
    with pytest.raises(InputError):
        globaldb.add_asset(
            asset_id='NEWID',
            asset_type=AssetType.ETHEREUM_TOKEN,
            data=EthereumToken.initialize(
                address=make_ethereum_address(),
                swapped_for=asset_to_delete,
            ),
        )

    # now edit a new token with swapped_for pointing to a non existing token in the DB
    bat_custom = globaldb.get_ethereum_token(A_BAT.ethereum_address)
    bat_custom = EthereumToken.initialize(
        address=A_BAT.ethereum_address,
        decimals=A_BAT.decimals,
        name=A_BAT.name,
        symbol=A_BAT.symbol,
        started=A_BAT.started,
        swapped_for=asset_to_delete,
        coingecko=A_BAT.coingecko,
        cryptocompare=A_BAT.cryptocompare,
        protocol=None,
        underlying_tokens=None,
    )
    with pytest.raises(InputError):
        globaldb.edit_ethereum_token(bat_custom)
Exemple #2
0
def test_price_underlying_tokens(inquirer, globaldb):
    aave_weight, link_weight, crv_weight = FVal('0.6'), FVal('0.2'), FVal(
        '0.2')
    address = make_ethereum_address()
    token = EthereumToken.initialize(
        address=address,
        decimals=18,
        name='Test',
        symbol='YAB',
        underlying_tokens=[
            UnderlyingToken(address=A_AAVE.ethereum_address,
                            weight=aave_weight),
            UnderlyingToken(address=A_LINK.ethereum_address,
                            weight=link_weight),
            UnderlyingToken(address=A_CRV.ethereum_address, weight=crv_weight),
        ],
    )
    globaldb.add_asset(
        asset_id=ethaddress_to_identifier(address),
        asset_type=AssetType.ETHEREUM_TOKEN,
        data=token,
    )

    price = inquirer.find_price(EthereumToken(address), A_USD)
    assert price == FVal(67)
Exemple #3
0
    def transform_data(  # pylint: disable=no-self-use
            self,
            data: Dict[str, Any],
            **_kwargs: Any,
    ) -> Dict[str, Any]:
        """Returns the a dictionary with:
        - The identifier
        - extra_information used by the globaldb handler
        - name
        - symbol
        - asset_type as instance of AssetType
        """
        given_underlying_tokens = data.pop('underlying_tokens', None)
        underlying_tokens = None
        if given_underlying_tokens is not None:
            underlying_tokens = []
            for entry in given_underlying_tokens:
                underlying_tokens.append(UnderlyingToken(
                    address=entry['address'],
                    weight=entry['weight'],
                ))

        asset_type = data['asset_type']
        extra_information: Union[Dict[str, Any], EthereumToken]
        swapped_for, swapped_for_ident = data.pop('swapped_for'), None
        if swapped_for is not None:
            swapped_for_ident = swapped_for.identifier

        if asset_type == AssetType.ETHEREUM_TOKEN:
            extra_information = EthereumToken.initialize(
                address=data.pop('ethereum_address'),
                name=data.get('name'),
                symbol=data.get('symbol'),
                decimals=data.pop('decimals'),
                started=data.pop('started'),
                swapped_for=swapped_for_ident,
                coingecko=data.pop('coingecko'),
                cryptocompare=data.pop('cryptocompare'),
                underlying_tokens=underlying_tokens,
            )
        else:
            forked, forked_ident = data.pop('forked'), None
            if forked is not None:
                forked_ident = forked.identifier

            extra_information = {
                'name': data.get('name'),
                'symbol': data.get('symbol'),
                'started': data.pop('started'),
                'forked': forked_ident,
                'swapper_for': swapped_for_ident,
                'coingecko': data.pop('coingecko'),
                'cryptocompare': data.pop('cryptocompare'),
            }

        data['underlying_tokens'] = underlying_tokens
        data['asset_type'] = asset_type
        data['extra_information'] = extra_information
        return data
Exemple #4
0
def test_find_uniswap_v2_lp_token_price(inquirer, globaldb, ethereum_manager):
    addess = '0xa2107FA5B38d9bbd2C461D6EDf11B11A50F6b974'
    inquirer.inject_ethereum(ethereum_manager)
    token = EthereumToken.initialize(
        address=addess,
        decimals=18,
        name='Uniswap LINK/ETH',
        symbol='UNI-V2',
        protocol='UNI-V2',
    )
    globaldb.add_asset(
        asset_id=ethaddress_to_identifier(addess),
        asset_type=AssetType.ETHEREUM_TOKEN,
        data=token,
    )

    price = inquirer.find_uniswap_v2_lp_price(EthereumToken(addess))
    assert price is not None
Exemple #5
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')),
                ),
            ],
        ),
    ]
Exemple #6
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
Exemple #7
0
def test_global_db_reset(globaldb):
    """
    Check that the user can recreate assets information from the packaged
    database with rotki (soft reset). The test adds a new asset, restores
    the database and checks that the added tokens are still in the database.
    In addition a token is edited and we check that was correctly restored.
    """
    # Add a custom eth token
    address_to_delete = make_ethereum_address()
    token_to_delete = EthereumToken.initialize(
        address=address_to_delete,
        decimals=18,
        name='willdell',
        symbol='DELME',
    )
    globaldb.add_asset(
        asset_id='DELMEID1',
        asset_type=AssetType.ETHEREUM_TOKEN,
        data=token_to_delete,
    )
    # Add a token with underlying token
    with_underlying_address = make_ethereum_address()
    with_underlying = EthereumToken.initialize(
        address=with_underlying_address,
        decimals=18,
        name="Not a scam",
        symbol="NSCM",
        started=0,
        underlying_tokens=[
            UnderlyingToken(
                address=address_to_delete,
                weight=1,
            )
        ],
    )
    globaldb.add_asset(
        asset_id='xDELMEID1',
        asset_type=AssetType.ETHEREUM_TOKEN,
        data=with_underlying,
    )
    # Add asset that is not a token
    globaldb.add_asset(
        asset_id='1',
        asset_type=AssetType.OWN_CHAIN,
        data={
            'name': 'Lolcoin',
            'symbol': 'LOLZ',
            'started': 0,
        },
    )
    # Edit one token
    one_inch_update = EthereumToken.initialize(
        address='0x111111111117dC0aa78b770fA6A738034120C302',
        name='1inch boi',
    )
    GlobalDBHandler().edit_ethereum_token(one_inch_update)

    status, _ = GlobalDBHandler().soft_reset_assets_list()
    assert status
    cursor = globaldb._conn.cursor()
    query = f'SELECT COUNT(*) FROM ethereum_tokens where address == "{address_to_delete}";'
    r = cursor.execute(query)
    assert r.fetchone() == (
        1, ), 'Custom ethereum tokens should not been deleted'
    query = f'SELECT COUNT(*) FROM assets where details_reference == "{address_to_delete}";'
    r = cursor.execute(query)
    assert r.fetchone() == (1, )
    query = f'SELECT COUNT(*) FROM ethereum_tokens where address == "{with_underlying_address}";'
    r = cursor.execute(query)
    assert r.fetchone() == (
        1, ), 'Ethereum token with underlying token should not be deleted'
    query = f'SELECT COUNT(*) FROM assets where details_reference == "{with_underlying_address}";'
    r = cursor.execute(query)
    assert r.fetchone() == (1, )
    query = f'SELECT COUNT(*) FROM underlying_tokens_list where address == "{address_to_delete}";'
    r = cursor.execute(query)
    assert r.fetchone() == (1, )
    query = 'SELECT COUNT(*) FROM assets where identifier == "1";'
    r = cursor.execute(query)
    assert r.fetchone() == (
        1, ), 'Non ethereum token added should be in the db'
    # Check that the 1inch token was correctly fixed
    assert EthereumToken(
        '0x111111111117dC0aa78b770fA6A738034120C302').name != '1inch boi'

    # Check that the number of assets is the expected
    root_dir = Path(__file__).resolve().parent.parent.parent
    builtin_database = root_dir / 'data' / 'global.db'
    conn = sqlite3.connect(builtin_database)
    cursor_clean_db = conn.cursor()
    tokens_expected = cursor_clean_db.execute('SELECT COUNT(*) FROM assets;')
    tokens_local = cursor.execute('SELECT COUNT(*) FROM assets;')
    assert tokens_expected.fetchone()[0] + 3 == tokens_local.fetchone()[0]
    conn.close()
Exemple #8
0
def test_global_db_restore(globaldb, database):
    """
    Check that the user can recreate assets information from the packaged
    database with rotki (hard reset). The test adds a new asset, restores
    the database and checks that the added token is not in there and that
    the amount of assets is the expected
    """
    # Add a custom eth token
    address_to_delete = make_ethereum_address()
    token_to_delete = EthereumToken.initialize(
        address=address_to_delete,
        decimals=18,
        name='willdell',
        symbol='DELME',
    )
    globaldb.add_asset(
        asset_id='DELMEID1',
        asset_type=AssetType.ETHEREUM_TOKEN,
        data=token_to_delete,
    )
    # Add a token with underlying token
    with_underlying_address = make_ethereum_address()
    with_underlying = EthereumToken.initialize(
        address=with_underlying_address,
        decimals=18,
        name="Not a scam",
        symbol="NSCM",
        started=0,
        underlying_tokens=[
            UnderlyingToken(
                address=address_to_delete,
                weight=1,
            )
        ],
    )
    globaldb.add_asset(
        asset_id='xDELMEID1',
        asset_type=AssetType.ETHEREUM_TOKEN,
        data=with_underlying,
    )
    # Add asset that is not a token
    globaldb.add_asset(
        asset_id='1',
        asset_type=AssetType.OWN_CHAIN,
        data={
            'name': 'Lolcoin',
            'symbol': 'LOLZ',
            'started': 0,
        },
    )

    # Add asset that is not a token
    globaldb.add_asset(
        asset_id='2',
        asset_type=AssetType.OWN_CHAIN,
        data={
            'name': 'Lolcoin2',
            'symbol': 'LOLZ2',
            'started': 0,
        },
    )

    database.add_asset_identifiers('1')
    database.add_asset_identifiers('2')

    # Try to reset DB it if we have a trade that uses a custom asset
    buy_asset = symbol_to_asset_or_token('LOLZ2')
    buy_amount = deserialize_asset_amount(1)
    sold_asset = symbol_to_asset_or_token('LOLZ')
    sold_amount = deserialize_asset_amount(2)
    rate = Price(buy_amount / sold_amount)
    trade = Trade(
        timestamp=Timestamp(12312312),
        location=Location.BLOCKFI,
        base_asset=buy_asset,
        quote_asset=sold_asset,
        trade_type=TradeType.BUY,
        amount=buy_amount,
        rate=rate,
        fee=None,
        fee_currency=None,
        link='',
        notes="",
    )

    database.add_trades([trade])
    status, _ = GlobalDBHandler().hard_reset_assets_list(database)
    assert status is False
    # Now do it without the trade
    database.delete_trade(trade.identifier)
    status, msg = GlobalDBHandler().hard_reset_assets_list(database, True)
    assert status, msg
    cursor = globaldb._conn.cursor()
    query = f'SELECT COUNT(*) FROM ethereum_tokens where address == "{address_to_delete}";'
    r = cursor.execute(query)
    assert r.fetchone() == (0, ), 'Ethereum token should have been deleted'
    query = f'SELECT COUNT(*) FROM assets where details_reference == "{address_to_delete}";'
    r = cursor.execute(query)
    assert r.fetchone() == (
        0, ), 'Ethereum token should have been deleted from assets'
    query = f'SELECT COUNT(*) FROM ethereum_tokens where address == "{with_underlying_address}";'
    r = cursor.execute(query)
    assert r.fetchone() == (
        0,
    ), 'Token with underlying token should have been deleted from assets'
    query = f'SELECT COUNT(*) FROM assets where details_reference == "{with_underlying_address}";'
    r = cursor.execute(query)
    assert r.fetchone() == (0, )
    query = f'SELECT COUNT(*) FROM underlying_tokens_list where address == "{address_to_delete}";'
    r = cursor.execute(query)
    assert r.fetchone() == (0, )
    query = 'SELECT COUNT(*) FROM assets where identifier == "1";'
    r = cursor.execute(query)
    assert r.fetchone() == (0, ), 'Non ethereum token should be deleted'
    # Check that the user database is correctly updated
    query = 'SELECT identifier from assets'
    r = cursor.execute(query)
    user_db_cursor = database.conn.cursor()
    user_db_cursor.execute(query)
    assert r.fetchall() == user_db_cursor.fetchall()

    # Check that the number of assets is the expected
    root_dir = Path(__file__).resolve().parent.parent.parent
    builtin_database = root_dir / 'data' / 'global.db'
    conn = sqlite3.connect(builtin_database)
    cursor_clean_db = conn.cursor()
    tokens_expected = cursor_clean_db.execute('SELECT COUNT(*) FROM assets;')
    tokens_local = cursor.execute('SELECT COUNT(*) FROM assets;')
    assert tokens_expected.fetchone() == tokens_local.fetchone()
    cursor.execute('SELECT asset_id FROM user_owned_assets')
    msg = 'asset id in trade should not be in the owned table'
    assert "'2'" not in [entry[0] for entry in cursor.fetchall()], msg
    conn.close()
Exemple #9
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");
*
INSERT INTO ethereum_tokens(address, decimals, protocol) VALUES("0x1B175474E89094C44Da98b954EedeAC495271d0F", 18, NULL); INSERT INTO assets(identifier,type, name, symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("_ceth_0x1B175474E89094C44Da98b954EedeAC495271d0F", "C", "Conflicting token", "CTK", 1573672677, NULL, "ctk", NULL, "0x1B175474E89094C44Da98b954EedeAC495271d0F");
*
    """  # noqa: E501
    globaldb.add_asset(  # add a conflicting token
        asset_id='_ceth_0x1B175474E89094C44Da98b954EedeAC495271d0F',
        asset_type=AssetType.ETHEREUM_TOKEN,
        data=EthereumToken.initialize(
            address=ChecksumEthAddress('0x1B175474E89094C44Da98b954EedeAC495271d0F'),
            decimals=12,
            name='Conflicting token',
            symbol='CTK',
            started=None,
            swapped_for=None,
            coingecko='ctk',
            cryptocompare=None,
            protocol=None,
            underlying_tokens=None,
        ),
    )
    globaldb.add_user_owned_assets([Asset('_ceth_0x1B175474E89094C44Da98b954EedeAC495271d0F')])
    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 3 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,
            },
        }, {
            'identifier': '_ceth_0x1B175474E89094C44Da98b954EedeAC495271d0F',
            'local': {
                'asset_type': 'ethereum token',
                'coingecko': 'ctk',
                'cryptocompare': None,
                'decimals': 12,
                'ethereum_address': '0x1B175474E89094C44Da98b954EedeAC495271d0F',
                'forked': None,
                'name': 'Conflicting token',
                'protocol': None,
                'started': None,
                'swapped_for': None,
                'symbol': 'CTK',
            },
            'remote': {
                'asset_type': 'ethereum token',
                'coingecko': 'ctk',
                'cryptocompare': None,
                'decimals': 18,
                'ethereum_address': '0x1b175474E89094C44DA98B954EeDEAC495271d0f',
                'forked': None,
                'name': 'Conflicting token',
                'protocol': None,
                'started': 1573672677,
                'swapped_for': None,
                'symbol': 'CTK',
            },
        }]
        assert result == expected_result

        # now try the update again but specify the conflicts resolution
        conflicts = {'_ceth_0x6B175474E89094C44Da98b954EedeAC495271d0F': 'remote', 'DASH': 'local', '_ceth_0x1B175474E89094C44Da98b954EedeAC495271d0F': 'remote'}  # noqa: E501
        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,
            )

        cursor = globaldb._conn.cursor()
        # 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'
        # make sure data is in both tables
        assert cursor.execute('SELECT COUNT(*) from ethereum_tokens WHERE address="0x6B175474E89094C44Da98b954EedeAC495271d0F";').fetchone()[0] == 1  # noqa: E501
        assert cursor.execute('SELECT COUNT(*) from assets WHERE identifier="_ceth_0x6B175474E89094C44Da98b954EedeAC495271d0F";').fetchone()[0] == 1  # noqa: E501

        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
        assert cursor.execute('SELECT COUNT(*) from common_asset_details WHERE asset_id="DASH";').fetchone()[0] == 1  # noqa: E501
        assert cursor.execute('SELECT COUNT(*) from assets WHERE identifier="DASH";').fetchone()[0] == 1  # noqa: E501

        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 cursor.execute('SELECT COUNT(*) from common_asset_details WHERE asset_id="121-ada-FADS-as";').fetchone()[0] == 1  # noqa: E501
        assert cursor.execute('SELECT COUNT(*) from assets WHERE identifier="121-ada-FADS-as";').fetchone()[0] == 1  # noqa: E501

        ctk = EthereumToken('0x1B175474E89094C44Da98b954EedeAC495271d0F')
        assert ctk.name == 'Conflicting token'
        assert ctk.symbol == 'CTK'
        assert ctk.asset_type == AssetType.ETHEREUM_TOKEN
        assert ctk.started == 1573672677
        assert ctk.forked is None
        assert ctk.swapped_for is None
        assert ctk.coingecko == 'ctk'
        assert ctk.cryptocompare is None
        assert ctk.ethereum_address == '0x1B175474E89094C44Da98b954EedeAC495271d0F'
        assert ctk.decimals == 18
        assert ctk.protocol is None
        assert cursor.execute('SELECT COUNT(*) from ethereum_tokens WHERE address="0x1B175474E89094C44Da98b954EedeAC495271d0F";').fetchone()[0] == 1  # noqa: E501
        assert cursor.execute('SELECT COUNT(*) from assets WHERE identifier="_ceth_0x1B175474E89094C44Da98b954EedeAC495271d0F";').fetchone()[0] == 1  # noqa: E501
Exemple #10
0
underlying_address1 = make_ethereum_address()
underlying_address2 = make_ethereum_address()
underlying_address3 = make_ethereum_address()

custom_address1 = make_ethereum_address()
custom_address2 = make_ethereum_address()
INITIAL_TOKENS = [
    EthereumToken.initialize(
        address=custom_address1,
        decimals=4,
        name='Custom 1',
        symbol='CST1',
        started=Timestamp(0),
        swapped_for=A_MKR,
        coingecko='foo',
        cryptocompare='boo',
        protocol='uniswap',
        underlying_tokens=[
            UnderlyingToken(address=underlying_address1,
                            weight=FVal('0.5055')),
            UnderlyingToken(address=underlying_address2,
                            weight=FVal('0.1545')),
            UnderlyingToken(address=underlying_address3, weight=FVal('0.34')),
        ],
    ),
    EthereumToken.initialize(
        address=custom_address2,
        decimals=18,
        name='Custom 2',
        symbol='CST2',
    ),
]
Exemple #11
0
def test_adding_custom_tokens(rotkehlchen_api_server):
    """Test that the endpoint for adding a custom ethereum token works"""
    serialized_token = CUSTOM_TOKEN3.serialize_all_info()
    del serialized_token['identifier']
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumassetsresource',
        ),
        json={'token': serialized_token},
    )
    result = assert_proper_response_with_result(response)
    assert result == {'identifier': ETHEREUM_DIRECTIVE + CUSTOM_TOKEN3.ethereum_address}

    response = requests.get(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumassetsresource',
        ),
    )
    result = assert_proper_response_with_result(response)
    expected_tokens = INITIAL_EXPECTED_TOKENS.copy() + [
        CUSTOM_TOKEN3,
        EthereumToken.initialize(address=underlying_address4),
    ]
    expected_result = [x.serialize_all_info() for x in expected_tokens]
    assert_token_entry_exists_in_result(result, expected_result)

    # test that adding an already existing address is handled properly
    serialized_token = INITIAL_TOKENS[1].serialize_all_info()
    del serialized_token['identifier']
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumassetsresource',
        ),
        json={'token': serialized_token},
    )
    expected_msg = (
        f'Ethereum token with address {INITIAL_TOKENS[1].ethereum_address} already '
        f'exists in the DB',
    )
    assert_error_response(
        response=response,
        contained_in_msg=expected_msg,
        status_code=HTTPStatus.CONFLICT,
    )

    # also test that the addition of underlying tokens has created proper asset entires for them
    cursor = GlobalDBHandler()._conn.cursor()
    result = cursor.execute(
        'SELECT COUNT(*) from assets WHERE identifier IN (?, ?, ?, ?)',
        [ETHEREUM_DIRECTIVE + x for x in [underlying_address1, underlying_address2, underlying_address3, underlying_address4]],  # noqa: E501
    ).fetchone()[0]
    assert result == 4
    result = cursor.execute(
        'SELECT COUNT(*) from ethereum_tokens WHERE address IN (?, ?, ?, ?)',
        (underlying_address1, underlying_address2, underlying_address3, underlying_address4),  # noqa: E501
    ).fetchone()[0]
    assert result == 4

    # now test that adding a token with underlying tokens adding up to more than 100% is caught
    bad_token = EthereumToken.initialize(
        address=make_ethereum_address(),
        decimals=18,
        name='foo',
        symbol='BBB',
        underlying_tokens=[
            UnderlyingToken(address=make_ethereum_address(), weight=FVal('0.5055')),
            UnderlyingToken(address=make_ethereum_address(), weight=FVal('0.7055')),
        ],
    )
    serialized_token = bad_token.serialize_all_info()
    del serialized_token['identifier']
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumassetsresource',
        ),
        json={'token': serialized_token},
    )
    expected_msg = (
        f'The sum of underlying token weights for {bad_token.ethereum_address} is '
        f'121.1000 and exceeds 100%'
    )
    assert_error_response(
        response=response,
        contained_in_msg=expected_msg,
        status_code=HTTPStatus.BAD_REQUEST,
    )
    # and test that adding a token with underlying tokens adding up to less than 100% is caught
    bad_token = EthereumToken.initialize(
        address=make_ethereum_address(),
        decimals=18,
        name='foo',
        symbol='BBB',
        underlying_tokens=[
            UnderlyingToken(address=make_ethereum_address(), weight=FVal('0.1055')),
            UnderlyingToken(address=make_ethereum_address(), weight=FVal('0.2055')),
        ],
    )
    serialized_token = bad_token.serialize_all_info()
    del serialized_token['identifier']
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumassetsresource',
        ),
        json={'token': serialized_token},
    )
    expected_msg = (
        f'The sum of underlying token weights for {bad_token.ethereum_address} is '
        f'31.1000 and does not add up to 100%'
    )
    assert_error_response(
        response=response,
        contained_in_msg=expected_msg,
        status_code=HTTPStatus.BAD_REQUEST,
    )
    # and test that adding a token with empty list of underlying tokens and not null is an error
    bad_token = EthereumToken.initialize(
        address=make_ethereum_address(),
        decimals=18,
        name='foo',
        symbol='BBB',
        underlying_tokens=[],
    )
    serialized_bad_token = bad_token.serialize_all_info()
    del serialized_bad_token['identifier']
    serialized_bad_token['underlying_tokens'] = []
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumassetsresource',
        ),
        json={'token': serialized_bad_token},
    )
    expected_msg = (
        f'Gave an empty list for underlying tokens of {bad_token.ethereum_address}'
    )
    assert_error_response(
        response=response,
        contained_in_msg=expected_msg,
        status_code=HTTPStatus.BAD_REQUEST,
    )
    # test that adding invalid coingecko fails
    bad_identifier = 'INVALIDID'
    bad_token = {
        'address': make_ethereum_address(),
        'decimals': 18,
        'name': 'Bad token',
        'symbol': 'NAUGHTY',
        'coingecko': bad_identifier,
    }
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumassetsresource',
        ),
        json={'token': bad_token},
    )
    assert_error_response(
        response=response,
        contained_in_msg=f'Given coingecko identifier {bad_identifier} is not valid',
        status_code=HTTPStatus.BAD_REQUEST,
    )
    # test that adding invalid cryptocompare fails
    bad_token['cryptocompare'] = bad_identifier
    bad_token['coingecko'] = None
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumassetsresource',
        ),
        json={'token': bad_token},
    )
    assert_error_response(
        response=response,
        contained_in_msg=f'Given cryptocompare identifier {bad_identifier} isnt valid',
        status_code=HTTPStatus.BAD_REQUEST,
    )
Exemple #12
0
def test_exporting_custom_assets_list(rotkehlchen_api_server, globaldb,
                                      with_custom_path):
    """Test that the endpoint for exporting custom assets works correctly"""
    eth_address = make_ethereum_address()
    identifier = ethaddress_to_identifier(eth_address)
    globaldb.add_asset(
        asset_id=identifier,
        asset_type=AssetType.ETHEREUM_TOKEN,
        data=EthereumToken.initialize(
            address=eth_address,
            decimals=18,
            name='yabirtoken',
            symbol='YAB',
            coingecko='YAB',
            cryptocompare='YAB',
        ),
    )
    with tempfile.TemporaryDirectory() as path:
        if with_custom_path:
            response = requests.put(
                api_url_for(
                    rotkehlchen_api_server,
                    'userassetsresource',
                ),
                json={
                    'action': 'download',
                    'destination': path
                },
            )
        else:
            response = requests.put(
                api_url_for(
                    rotkehlchen_api_server,
                    'userassetsresource',
                ),
                json={'action': 'download'},
            )

        if with_custom_path:
            result = assert_proper_response_with_result(response)
            if with_custom_path:
                assert path in result['file']
            zip_file = ZipFile(result['file'])
            data = json.loads(zip_file.read('assets.json'))
            assert int(data['version']) == GLOBAL_DB_VERSION
            assert len(data['assets']) == 1
            assert data['assets'][0] == {
                'identifier': identifier,
                'name': 'yabirtoken',
                'decimals': 18,
                'symbol': 'YAB',
                'asset_type': 'ethereum token',
                'started': None,
                'forked': None,
                'swapped_for': None,
                'cryptocompare': 'YAB',
                'coingecko': 'YAB',
                'protocol': None,
                'underlying_tokens': None,
                'ethereum_address': eth_address,
            }
        else:
            assert response.status_code == HTTPStatus.OK
            assert response.headers['Content-Type'] == 'application/zip'

        # try to download again to see if the database is properly detached
        response = requests.put(
            api_url_for(
                rotkehlchen_api_server,
                'userassetsresource',
            ),
            json={
                'action': 'download',
                'destination': path
            },
        )
        result = assert_proper_response_with_result(response)