Skip to content

Commit

Permalink
Remove price calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
moisses89 committed Nov 17, 2023
1 parent 233a0ad commit 225cdc9
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 1,263 deletions.
55 changes: 14 additions & 41 deletions safe_transaction_service/history/services/balance_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import operator
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from typing import List, Optional, Sequence

from django.conf import settings
Expand All @@ -16,13 +17,7 @@
from gnosis.eth import EthereumClient, EthereumClientProvider
from gnosis.eth.utils import fast_is_checksum_address

from safe_transaction_service.tokens.clients import CannotGetPrice
from safe_transaction_service.tokens.models import Token
from safe_transaction_service.tokens.services.price_service import (
FiatCode,
PriceService,
PriceServiceProvider,
)
from safe_transaction_service.utils.redis import get_redis
from safe_transaction_service.utils.utils import chunks

Expand Down Expand Up @@ -72,6 +67,11 @@ def get_price_address(self) -> ChecksumAddress:
return self.token_address


class FiatCode(Enum):
USD = 1
EUR = 2


@dataclass
class BalanceWithFiat(Balance):
eth_value: float # Value in ether
Expand All @@ -84,9 +84,7 @@ class BalanceWithFiat(Balance):
class BalanceServiceProvider:
def __new__(cls):
if not hasattr(cls, "instance"):
cls.instance = BalanceService(
EthereumClientProvider(), PriceServiceProvider(), get_redis()
)
cls.instance = BalanceService(EthereumClientProvider(), get_redis())
return cls.instance

@classmethod
Expand All @@ -96,12 +94,9 @@ def del_singleton(cls):


class BalanceService:
def __init__(
self, ethereum_client: EthereumClient, price_service: PriceService, redis: Redis
):
def __init__(self, ethereum_client: EthereumClient, redis: Redis):
self.ethereum_client = ethereum_client
self.ethereum_network = self.ethereum_client.get_network()
self.price_service = price_service
self.redis = redis
self.cache_token_info = TTLCache(
maxsize=4096, ttl=60 * 30
Expand Down Expand Up @@ -268,50 +263,28 @@ def get_usd_balances(
exclude_spam: bool = False,
) -> List[BalanceWithFiat]:
"""
All this could be more optimal (e.g. batching requests), but as everything is cached
I think we should be alright
NOTE: PriceService was removed, this function return balances with price 0.
:param safe_address:
:param only_trusted: If True, return balance only for trusted tokens
:param exclude_spam: If True, exclude spam tokens
:return: List of BalanceWithFiat
"""
# TODO Use price service get_token_cached_usd_values
balances: List[Balance] = self.get_balances(
safe_address, only_trusted, exclude_spam
)
try:
eth_price = self.price_service.get_native_coin_usd_price()
except CannotGetPrice:
logger.warning("Cannot get network ether price", exc_info=True)
eth_price = 0
balances_with_usd = []
price_token_addresses = [balance.get_price_address() for balance in balances]
token_eth_values_with_timestamp = (
self.price_service.get_token_cached_eth_values(price_token_addresses)
)
for balance, token_eth_value_with_timestamp in zip(
balances, token_eth_values_with_timestamp
):
token_eth_value = token_eth_value_with_timestamp.eth_value
token_address = balance.token_address
if not token_address: # Ether
fiat_conversion = eth_price
fiat_balance = fiat_conversion * (balance.balance / 10**18)
else:
fiat_conversion = eth_price * token_eth_value
balance_with_decimals = balance.balance / 10**balance.token.decimals
fiat_balance = fiat_conversion * balance_with_decimals

for balance in balances:
balances_with_usd.append(
BalanceWithFiat(
balance.token_address,
balance.token,
balance.balance,
token_eth_value,
token_eth_value_with_timestamp.timestamp,
round(fiat_balance, 4),
round(fiat_conversion, 4),
0.0,
datetime.utcfromtimestamp(0),
0.0,
0.0,
FiatCode.USD.name,
)
)
Expand Down
118 changes: 42 additions & 76 deletions safe_transaction_service/history/tests/test_balance_service.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
from typing import Optional
from unittest import mock
from unittest.mock import MagicMock
import datetime

from django.test import TestCase
from django.utils import timezone

from eth_account import Account
from eth_typing import ChecksumAddress

from gnosis.eth.tests.ethereum_test_case import EthereumTestCaseMixin
from gnosis.eth.tests.utils import deploy_erc20

from safe_transaction_service.tokens.models import Token
from safe_transaction_service.tokens.services.price_service import PriceService
from safe_transaction_service.tokens.tests.factories import TokenFactory

from ..services import BalanceServiceProvider
Expand Down Expand Up @@ -41,18 +36,8 @@ def test_get_token_info(self):
self.assertEqual(token_info.symbol, token_db.symbol)
self.assertEqual(token_info.decimals, token_db.decimals)

@mock.patch.object(
PriceService, "get_token_eth_value", return_value=0.4, autospec=True
)
@mock.patch.object(
PriceService, "get_native_coin_usd_price", return_value=123.4, autospec=True
)
@mock.patch.object(timezone, "now", return_value=timezone.now())
def test_get_usd_balances(
self,
timezone_now_mock: MagicMock,
get_native_coin_usd_price_mock: MagicMock,
get_token_eth_value_mock: MagicMock,
):
balance_service = self.balance_service

Expand Down Expand Up @@ -85,16 +70,22 @@ def test_get_usd_balances(
balances,
[
BalanceWithFiat(
None, None, value, 1.0, timezone_now_mock.return_value, 0.0, 123.4
None,
None,
value,
0.0,
datetime.datetime.utcfromtimestamp(0),
0.0,
0.0,
),
BalanceWithFiat(
erc20.address,
token_info,
tokens_value,
0.4,
timezone_now_mock.return_value,
round(123.4 * 0.4 * (tokens_value / 1e18), 4),
round(123.4 * 0.4, 4),
0.0,
datetime.datetime.utcfromtimestamp(0),
0.0,
0.0,
),
],
)
Expand All @@ -104,7 +95,7 @@ def test_get_usd_balances(
balances,
[
BalanceWithFiat(
None, None, value, 1.0, timezone_now_mock.return_value, 0.0, 123.4
None, None, value, 0.0, datetime.datetime.utcfromtimestamp(0), 0, 0
),
],
)
Expand All @@ -115,16 +106,16 @@ def test_get_usd_balances(
balances,
[
BalanceWithFiat(
None, None, value, 1.0, timezone_now_mock.return_value, 0.0, 123.4
None, None, value, 0.0, datetime.datetime.utcfromtimestamp(0), 0, 0
),
BalanceWithFiat(
erc20.address,
token_info,
tokens_value,
0.4,
timezone_now_mock.return_value,
round(123.4 * 0.4 * (tokens_value / 1e18), 4),
round(123.4 * 0.4, 4),
0,
datetime.datetime.utcfromtimestamp(0),
0,
0,
),
],
)
Expand Down Expand Up @@ -167,57 +158,46 @@ def test_get_usd_balances(
None,
None,
value,
1.0,
timezone_now_mock.return_value,
0.0,
123.4,
datetime.datetime.utcfromtimestamp(0),
0.0,
0.0,
),
BalanceWithFiat(
erc20_3.address,
token_info_3,
tokens_value,
0.4,
timezone_now_mock.return_value,
round(123.4 * 0.4 * (tokens_value / 1e18), 4),
round(123.4 * 0.4, 4),
0.0,
datetime.datetime.utcfromtimestamp(0),
0.0,
0.0,
),
BalanceWithFiat(
erc20.address,
token_info,
tokens_value,
0.4,
timezone_now_mock.return_value,
round(123.4 * 0.4 * (tokens_value / 1e18), 4),
round(123.4 * 0.4, 4),
0.0,
datetime.datetime.utcfromtimestamp(0),
0.0,
0.0,
),
BalanceWithFiat(
erc20_2.address,
token_info_2,
tokens_value,
0.4,
timezone_now_mock.return_value,
round(123.4 * 0.4 * (tokens_value / 1e18), 4),
round(123.4 * 0.4, 4),
0.0,
datetime.datetime.utcfromtimestamp(0),
0.0,
0.0,
),
],
)

@mock.patch.object(
PriceService, "get_token_eth_value", return_value=0.4, autospec=True
)
@mock.patch.object(
PriceService, "get_native_coin_usd_price", return_value=123.4, autospec=True
)
@mock.patch.object(timezone, "now", return_value=timezone.now())
def test_get_usd_balances_copy_price(
self,
timezone_now_mock: MagicMock,
get_native_coin_usd_price_mock: MagicMock,
get_token_eth_value_mock: MagicMock,
):
def test_get_usd_balances_copy_price(self):
balance_service = self.balance_service
safe_address = SafeContractFactory().address
random_address = Account.create().address
timestamp_str = "1970-01-01T00:00:00Z"

balances = balance_service.get_usd_balances(safe_address)
self.assertEqual(len(balances), 1)
Expand All @@ -235,16 +215,7 @@ def test_get_usd_balances_copy_price(
)
ERC20TransferFactory(address=erc20.address, to=safe_address)

def get_token_eth_value(
self, token_address: ChecksumAddress
) -> Optional[float]:
if token_address == erc20.address:
return 0.4
elif token_address == random_address:
return 0.1

get_token_eth_value_mock.side_effect = get_token_eth_value
for expected_token_eth_value in (0.4, 0.1):
for expected_token_eth_value in (0, 0):
with self.subTest(expected_token_eth_value=expected_token_eth_value):
balances = balance_service.get_usd_balances(safe_address)
self.assertEqual(len(balances), 2)
Expand All @@ -255,24 +226,19 @@ def get_token_eth_value(
None,
None,
0,
1.0,
timezone_now_mock.return_value,
expected_token_eth_value,
datetime.datetime.utcfromtimestamp(0),
0.0,
0.0,
123.4,
),
BalanceWithFiat(
erc20.address,
balance_service.get_token_info(erc20.address),
tokens_value,
expected_token_eth_value,
timezone_now_mock.return_value,
round(
123.4
* expected_token_eth_value
* (tokens_value / 1e18),
4,
),
round(123.4 * expected_token_eth_value, 4),
datetime.datetime.utcfromtimestamp(0),
0.0,
0.0,
),
],
)
Expand Down
Loading

0 comments on commit 225cdc9

Please sign in to comment.