eth-portfolio 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of eth-portfolio might be problematic. Click here for more details.

Files changed (47) hide show
  1. eth_portfolio/__init__.py +16 -0
  2. eth_portfolio/_argspec.py +42 -0
  3. eth_portfolio/_cache.py +116 -0
  4. eth_portfolio/_config.py +3 -0
  5. eth_portfolio/_db/__init__.py +0 -0
  6. eth_portfolio/_db/decorators.py +147 -0
  7. eth_portfolio/_db/entities.py +204 -0
  8. eth_portfolio/_db/utils.py +595 -0
  9. eth_portfolio/_decimal.py +122 -0
  10. eth_portfolio/_decorators.py +71 -0
  11. eth_portfolio/_exceptions.py +67 -0
  12. eth_portfolio/_ledgers/__init__.py +0 -0
  13. eth_portfolio/_ledgers/address.py +892 -0
  14. eth_portfolio/_ledgers/portfolio.py +327 -0
  15. eth_portfolio/_loaders/__init__.py +33 -0
  16. eth_portfolio/_loaders/balances.py +78 -0
  17. eth_portfolio/_loaders/token_transfer.py +214 -0
  18. eth_portfolio/_loaders/transaction.py +379 -0
  19. eth_portfolio/_loaders/utils.py +59 -0
  20. eth_portfolio/_shitcoins.py +212 -0
  21. eth_portfolio/_utils.py +286 -0
  22. eth_portfolio/_ydb/__init__.py +0 -0
  23. eth_portfolio/_ydb/token_transfers.py +136 -0
  24. eth_portfolio/address.py +382 -0
  25. eth_portfolio/buckets.py +181 -0
  26. eth_portfolio/constants.py +58 -0
  27. eth_portfolio/portfolio.py +629 -0
  28. eth_portfolio/protocols/__init__.py +66 -0
  29. eth_portfolio/protocols/_base.py +107 -0
  30. eth_portfolio/protocols/convex.py +17 -0
  31. eth_portfolio/protocols/dsr.py +31 -0
  32. eth_portfolio/protocols/lending/__init__.py +49 -0
  33. eth_portfolio/protocols/lending/_base.py +57 -0
  34. eth_portfolio/protocols/lending/compound.py +185 -0
  35. eth_portfolio/protocols/lending/liquity.py +110 -0
  36. eth_portfolio/protocols/lending/maker.py +105 -0
  37. eth_portfolio/protocols/lending/unit.py +47 -0
  38. eth_portfolio/protocols/liquity.py +16 -0
  39. eth_portfolio/py.typed +0 -0
  40. eth_portfolio/structs/__init__.py +43 -0
  41. eth_portfolio/structs/modified.py +69 -0
  42. eth_portfolio/structs/structs.py +637 -0
  43. eth_portfolio/typing.py +1460 -0
  44. eth_portfolio-1.1.0.dist-info/METADATA +174 -0
  45. eth_portfolio-1.1.0.dist-info/RECORD +47 -0
  46. eth_portfolio-1.1.0.dist-info/WHEEL +5 -0
  47. eth_portfolio-1.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,122 @@
1
+ import decimal
2
+ import logging
3
+ from typing import Union
4
+
5
+ from evmspec.data import Wei
6
+
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class Decimal(decimal.Decimal):
12
+ """
13
+ A subclass of :class:`decimal.Decimal` with additional functionality for JSON serialization.
14
+
15
+ This class extends the :class:`decimal.Decimal` class to provide an additional
16
+ method for JSON serialization. It also overrides arithmetic operations to ensure
17
+ that the result is of type :class:`Decimal`.
18
+
19
+ See Also:
20
+ - :class:`decimal.Decimal`
21
+ """
22
+
23
+ def jsonify(self) -> Union[str, int]:
24
+ """
25
+ Converts the :class:`Decimal` to a JSON-friendly format.
26
+
27
+ This method attempts to represent the :class:`Decimal` in the most compact form
28
+ possible for JSON serialization. It returns an integer if the :class:`Decimal`
29
+ is exactly equal to an integer, otherwise it returns a string in either
30
+ standard or scientific notation, depending on which is shorter.
31
+
32
+ If the integer representation is exactly equal to the :class:`Decimal`,
33
+ the integer is returned. Otherwise, the method returns the shorter of the
34
+ standard string representation or the scientific notation.
35
+
36
+ Examples:
37
+ >>> Decimal('123.4500').jsonify()
38
+ '123.45'
39
+ >>> Decimal('123000').jsonify()
40
+ 123000
41
+ >>> Decimal('0.000123').jsonify()
42
+ '1.23E-4'
43
+ >>> Decimal('1000000').jsonify()
44
+ 1000000
45
+ """
46
+ string = str(self)
47
+ integer = int(self)
48
+
49
+ if integer == self:
50
+ scientific_notation = "%E" % self
51
+ return (
52
+ integer
53
+ if len(str(integer)) <= len(scientific_notation) + 2
54
+ else scientific_notation
55
+ )
56
+
57
+ if "E" in string:
58
+ return string
59
+
60
+ scientific_notation = "%E" % self
61
+ while string[-1] == "0":
62
+ string = string[:-1]
63
+
64
+ if type(self)(scientific_notation) == self and len(scientific_notation) < len(string):
65
+ return scientific_notation
66
+
67
+ return string
68
+
69
+ def __add__(self, other):
70
+ return type(self)(super().__add__(other))
71
+
72
+ def __radd__(self, other):
73
+ return type(self)(super().__radd__(other))
74
+
75
+ def __sub__(self, other):
76
+ return type(self)(super().__sub__(other))
77
+
78
+ def __rsub__(self, other):
79
+ return type(self)(super().__rsub__(other))
80
+
81
+ def __mul__(self, other):
82
+ return type(self)(super().__mul__(other))
83
+
84
+ def __rmul__(self, other):
85
+ return type(self)(super().__rmul__(other))
86
+
87
+ def __truediv__(self, other):
88
+ return type(self)(super().__truediv__(other))
89
+
90
+ def __rtruediv__(self, other):
91
+ return type(self)(super().__rtruediv__(other))
92
+
93
+ def __floordiv__(self, other):
94
+ return type(self)(super().__floordiv__(other))
95
+
96
+ def __rfloordiv__(self, other):
97
+ return type(self)(super().__rfloordiv__(other))
98
+
99
+
100
+ class Gwei(Decimal):
101
+ """
102
+ A subclass of :class:`Decimal` representing Gwei values.
103
+
104
+ This class provides a property to convert Gwei to Wei.
105
+
106
+ See Also:
107
+ - :class:`Decimal`
108
+ - :class:`evmspec.data.Wei`
109
+ """
110
+
111
+ @property
112
+ def as_wei(self) -> Wei:
113
+ """
114
+ Converts the Gwei value to Wei.
115
+
116
+ This property multiplies the Gwei value by 10^9 to convert it to Wei.
117
+
118
+ Examples:
119
+ >>> Gwei('1').as_wei
120
+ Wei(1000000000)
121
+ """
122
+ return Wei(self * 10**9)
@@ -0,0 +1,71 @@
1
+ import asyncio
2
+ import functools
3
+ import inspect
4
+ import logging
5
+ from typing import Callable, Optional
6
+
7
+ from brownie import chain
8
+ from typing_extensions import Concatenate
9
+ from y.datatypes import Block
10
+
11
+ from eth_portfolio import _config
12
+ from eth_portfolio._utils import get_buffered_chain_height
13
+ from eth_portfolio.typing import _I, _P, _T
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ def set_end_block_if_none(
19
+ func: Callable[Concatenate[_I, Block, Block, _P], _T],
20
+ ) -> Callable[Concatenate[_I, Block, Optional[Block], _P], _T]:
21
+ """
22
+ Used to set `end_block` = `chain.height - _config.REORG_BUFFER` if `end_block` is None.
23
+ Only works with a class function that takes args (self, start_block, end_block, *args, **kwargs).
24
+ """
25
+ if inspect.isasyncgenfunction(func):
26
+
27
+ @functools.wraps(func)
28
+ async def wrap(
29
+ obj: _I,
30
+ start_block: Block,
31
+ end_block: Optional[Block],
32
+ *args: _P.args,
33
+ **kwargs: _P.kwargs,
34
+ ) -> _T:
35
+ if end_block is None:
36
+ end_block = await get_buffered_chain_height()
37
+ logger.debug("end_block not provided, using %s", end_block)
38
+ async for thing in func(obj, start_block, end_block, *args, **kwargs):
39
+ yield thing
40
+
41
+ elif asyncio.iscoroutinefunction(func):
42
+
43
+ @functools.wraps(func)
44
+ async def wrap(
45
+ obj: _I,
46
+ start_block: Block,
47
+ end_block: Block,
48
+ *args: _P.args,
49
+ **kwargs: _P.kwargs,
50
+ ) -> _T:
51
+ if end_block is None:
52
+ end_block = await get_buffered_chain_height()
53
+ logger.debug("end_block not provided, using %s", end_block)
54
+ return await func(obj, start_block, end_block, *args, **kwargs)
55
+
56
+ else:
57
+
58
+ @functools.wraps(func)
59
+ def wrap(
60
+ obj: _I,
61
+ start_block: Block,
62
+ end_block: Block,
63
+ *args: _P.args,
64
+ **kwargs: _P.kwargs,
65
+ ) -> _T:
66
+ if end_block is None:
67
+ end_block = chain.height - _config.REORG_BUFFER
68
+ logger.debug("end_block not provided, using %s", end_block)
69
+ return func(obj, start_block, end_block, *args, **kwargs)
70
+
71
+ return wrap
@@ -0,0 +1,67 @@
1
+ from asyncio import gather
2
+ from typing import TYPE_CHECKING
3
+
4
+ from y.datatypes import Block
5
+
6
+ if TYPE_CHECKING:
7
+ from eth_portfolio._ledgers.address import AddressLedgerBase
8
+
9
+
10
+ class BlockRangeIsCached(Exception):
11
+ """
12
+ Exception raised when a block range is already cached.
13
+
14
+ This exception indicates that the requested block range
15
+ has already been loaded into memory and does not need to be fetched again.
16
+
17
+ Examples:
18
+ >>> raise BlockRangeIsCached("Block range is already cached.")
19
+ """
20
+
21
+ pass
22
+
23
+
24
+ class BlockRangeOutOfBounds(Exception):
25
+ """
26
+ Exception raised when a block range is out of bounds.
27
+
28
+ This exception indicates that the requested block range
29
+ is outside the bounds of the cached data. It provides a method to
30
+ handle the loading of the remaining ledger entries that are out of bounds
31
+ by invoking the appropriate method in the associated ledger.
32
+
33
+ Args:
34
+ start_block: The starting block number of the out-of-bounds range.
35
+ end_block: The ending block number of the out-of-bounds range.
36
+ ledger: The ledger associated with the block range.
37
+
38
+ Examples:
39
+ >>> raise BlockRangeOutOfBounds(100, 200, ledger)
40
+
41
+ See Also:
42
+ - :class:`~eth_portfolio._ledgers.address.AddressLedgerBase`: The base class for address ledgers.
43
+ """
44
+
45
+ def __init__(self, start_block: Block, end_block: Block, ledger: "AddressLedgerBase") -> None:
46
+ self.ledger = ledger
47
+ self.start_block = start_block
48
+ self.end_block = end_block
49
+
50
+ async def load_remaining(self) -> None:
51
+ """
52
+ Asynchronously handles the loading of the remaining ledger entries that are out of bounds.
53
+
54
+ This method invokes the :meth:`~eth_portfolio._ledgers.address.AddressLedgerBase._load_new_objects`
55
+ method of the associated ledger to fetch the ledger entries for the blocks that are outside
56
+ the cached range, ensuring that the entire requested block range is covered.
57
+
58
+ Examples:
59
+ >>> await exception.load_remaining()
60
+
61
+ See Also:
62
+ - :meth:`~eth_portfolio._ledgers.address.AddressLedgerBase._load_new_objects`: Method to load new ledger entries.
63
+ """
64
+ return await gather(
65
+ self.ledger._load_new_objects(self.start_block, self.ledger.cached_thru - 1),
66
+ self.ledger._load_new_objects(self.ledger.cached_from + 1, self.end_block),
67
+ )
File without changes