Repository: rotki/rotki

Issue:
Allow refreshing of only current prices/exchange rates
## Abstract

We should have a way to simply refresh price information, independent of balance queries. Since balance queries are rather more expensive than just getting a price for a token we should find a way to differentiate price and balance queries and allow for both to be refreshed independently.

Perhaps the price part can be done only on the frontend when the following are implented?

- https://github.com/rotki/rotki/issues/1789 - Endpoint to query an asset's price
-  https://github.com/rotki/rotki/issues/1228 - Show price of asset along with balance and usd/eur value in the frontend

Prices should also be automatically queried periodically (see https://github.com/rotki/rotki/issues/916)

## Task

Think how to handle it and implement this



Discussion:

Resolving patch:
diff --git a/rotkehlchen/api/rest.py b/rotkehlchen/api/rest.py
--- a/rotkehlchen/api/rest.py
+++ b/rotkehlchen/api/rest.py
@@ -2330,6 +2330,7 @@ def get_asset_icon(
     def _get_current_assets_price(
             assets: List[Asset],
             target_asset: Asset,
+            ignore_cache: bool,
     ) -> Dict[str, Any]:
         """Return the current price of the assets in the target asset currency.
         """
@@ -2337,9 +2338,11 @@ def _get_current_assets_price(
             f'Querying the current {target_asset.identifier} price of these assets: '
             f'{", ".join([asset.identifier for asset in assets])}',
         )
-        assets_price = {asset: Inquirer().find_usd_price(asset) for asset in assets}
+        assets_price = {
+            asset: Inquirer().find_usd_price(asset, ignore_cache=ignore_cache) for asset in assets
+        }
         if target_asset != A_USD:
-            target_asset_price = Inquirer().find_usd_price(target_asset)
+            target_asset_price = Inquirer().find_usd_price(target_asset, ignore_cache=ignore_cache)
             for asset in assets_price.keys():
                 if asset != target_asset:
                     assets_price[asset] = Price(assets_price[asset] / target_asset_price)
@@ -2356,6 +2359,7 @@ def get_current_assets_price(
             self,
             assets: List[Asset],
             target_asset: Asset,
+            ignore_cache: bool,
             async_query: bool,
     ) -> Response:
         if async_query:
@@ -2363,11 +2367,13 @@ def get_current_assets_price(
                 command='_get_current_assets_price',
                 assets=assets,
                 target_asset=target_asset,
+                ignore_cache=ignore_cache,
             )
 
         response = self._get_current_assets_price(
             assets=assets,
             target_asset=target_asset,
+            ignore_cache=ignore_cache,
         )
         return api_response(_wrap_in_ok_result(response['result']), status_code=HTTPStatus.OK)
 
diff --git a/rotkehlchen/api/v1/encoding.py b/rotkehlchen/api/v1/encoding.py
--- a/rotkehlchen/api/v1/encoding.py
+++ b/rotkehlchen/api/v1/encoding.py
@@ -1398,12 +1398,13 @@ class AssetIconsSchema(Schema):
 
 
 class CurrentAssetsPriceSchema(Schema):
-    assets = fields.List(
+    assets = DelimitedOrNormalList(
         AssetField(required=True),
         required=True,
         validate=webargs.validate.Length(min=1),
     )
     target_asset = AssetField(required=True)
+    ignore_cache = fields.Boolean(missing=False)
     async_query = fields.Boolean(missing=False)
 
 
diff --git a/rotkehlchen/api/v1/resources.py b/rotkehlchen/api/v1/resources.py
--- a/rotkehlchen/api/v1/resources.py
+++ b/rotkehlchen/api/v1/resources.py
@@ -1261,14 +1261,16 @@ class CurrentAssetsPriceResource(BaseResource):
 
     @use_kwargs(get_schema, location='json_and_query')  # type: ignore
     def get(
-        self,
-        assets: List[Asset],
-        target_asset: Asset,
-        async_query: bool,
+            self,
+            assets: List[Asset],
+            target_asset: Asset,
+            ignore_cache: bool,
+            async_query: bool,
     ) -> Response:
         return self.rest_api.get_current_assets_price(
             assets=assets,
             target_asset=target_asset,
+            ignore_cache=ignore_cache,
             async_query=async_query,
         )
 
@@ -1279,10 +1281,10 @@ class HistoricalAssetsPriceResource(BaseResource):
 
     @use_kwargs(get_schema, location='json_and_query')  # type: ignore
     def get(
-        self,
-        assets_timestamp: List[Tuple[Asset, Timestamp]],
-        target_asset: Asset,
-        async_query: bool,
+            self,
+            assets_timestamp: List[Tuple[Asset, Timestamp]],
+            target_asset: Asset,
+            async_query: bool,
     ) -> Response:
         return self.rest_api.get_historical_assets_price(
             assets_timestamp=assets_timestamp,


Test patch:
diff --git a/frontend/app/tests/unit/services/axios-transformers.spec.ts b/frontend/app/tests/unit/services/axios-transformers.spec.ts
--- a/frontend/app/tests/unit/services/axios-transformers.spec.ts
+++ b/frontend/app/tests/unit/services/axios-transformers.spec.ts
@@ -26,4 +26,24 @@ describe('axios transformers', () => {
       '{"data":[{"usd_value":"10"},{"usd_value":"11"}],"label":"test"}'
     );
   });
+
+  test('null keys transformer converts all numeric keys', () => {
+    const json = '{"amount":"10","test_label":"1","data":[{"amount":"2"}]}';
+    const parsed = setupJsonTransformer(null)(json);
+    expect(axiosCamelCaseTransformer(parsed)).toMatchObject({
+      amount: bigNumberify(10),
+      testLabel: bigNumberify(1),
+      data: [{ amount: bigNumberify(2) }]
+    });
+  });
+
+  test('empty array transformer converts nothing', () => {
+    const json = '{"amount":"10","test_label":"1","data":[{"amount":"2"}]}';
+    const parsed = setupJsonTransformer([])(json);
+    expect(axiosCamelCaseTransformer(parsed)).toMatchObject({
+      amount: '10',
+      testLabel: '1',
+      data: [{ amount: '2' }]
+    });
+  });
 });