eth-portfolio-temp 0.2.16__cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.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.
Files changed (83) hide show
  1. eth_portfolio/__init__.py +25 -0
  2. eth_portfolio/_argspec.cpython-312-i386-linux-gnu.so +0 -0
  3. eth_portfolio/_argspec.py +42 -0
  4. eth_portfolio/_cache.py +121 -0
  5. eth_portfolio/_config.cpython-312-i386-linux-gnu.so +0 -0
  6. eth_portfolio/_config.py +4 -0
  7. eth_portfolio/_db/__init__.py +0 -0
  8. eth_portfolio/_db/decorators.py +147 -0
  9. eth_portfolio/_db/entities.py +311 -0
  10. eth_portfolio/_db/utils.py +604 -0
  11. eth_portfolio/_decimal.py +156 -0
  12. eth_portfolio/_decorators.py +84 -0
  13. eth_portfolio/_exceptions.py +67 -0
  14. eth_portfolio/_ledgers/__init__.py +0 -0
  15. eth_portfolio/_ledgers/address.py +938 -0
  16. eth_portfolio/_ledgers/portfolio.py +327 -0
  17. eth_portfolio/_loaders/__init__.py +33 -0
  18. eth_portfolio/_loaders/_nonce.cpython-312-i386-linux-gnu.so +0 -0
  19. eth_portfolio/_loaders/_nonce.py +196 -0
  20. eth_portfolio/_loaders/balances.cpython-312-i386-linux-gnu.so +0 -0
  21. eth_portfolio/_loaders/balances.py +94 -0
  22. eth_portfolio/_loaders/token_transfer.py +217 -0
  23. eth_portfolio/_loaders/transaction.py +240 -0
  24. eth_portfolio/_loaders/utils.cpython-312-i386-linux-gnu.so +0 -0
  25. eth_portfolio/_loaders/utils.py +68 -0
  26. eth_portfolio/_shitcoins.cpython-312-i386-linux-gnu.so +0 -0
  27. eth_portfolio/_shitcoins.py +330 -0
  28. eth_portfolio/_stableish.cpython-312-i386-linux-gnu.so +0 -0
  29. eth_portfolio/_stableish.py +42 -0
  30. eth_portfolio/_submodules.py +73 -0
  31. eth_portfolio/_utils.py +225 -0
  32. eth_portfolio/_ydb/__init__.py +0 -0
  33. eth_portfolio/_ydb/token_transfers.py +145 -0
  34. eth_portfolio/address.py +397 -0
  35. eth_portfolio/buckets.py +194 -0
  36. eth_portfolio/constants.cpython-312-i386-linux-gnu.so +0 -0
  37. eth_portfolio/constants.py +82 -0
  38. eth_portfolio/portfolio.py +661 -0
  39. eth_portfolio/protocols/__init__.py +67 -0
  40. eth_portfolio/protocols/_base.py +108 -0
  41. eth_portfolio/protocols/convex.py +17 -0
  42. eth_portfolio/protocols/dsr.py +51 -0
  43. eth_portfolio/protocols/lending/README.md +6 -0
  44. eth_portfolio/protocols/lending/__init__.py +50 -0
  45. eth_portfolio/protocols/lending/_base.py +57 -0
  46. eth_portfolio/protocols/lending/compound.py +187 -0
  47. eth_portfolio/protocols/lending/liquity.py +110 -0
  48. eth_portfolio/protocols/lending/maker.py +104 -0
  49. eth_portfolio/protocols/lending/unit.py +46 -0
  50. eth_portfolio/protocols/liquity.py +16 -0
  51. eth_portfolio/py.typed +0 -0
  52. eth_portfolio/structs/__init__.py +43 -0
  53. eth_portfolio/structs/modified.py +69 -0
  54. eth_portfolio/structs/structs.py +637 -0
  55. eth_portfolio/typing/__init__.py +1447 -0
  56. eth_portfolio/typing/balance/single.py +176 -0
  57. eth_portfolio__mypyc.cpython-312-i386-linux-gnu.so +0 -0
  58. eth_portfolio_scripts/__init__.py +20 -0
  59. eth_portfolio_scripts/_args.py +26 -0
  60. eth_portfolio_scripts/_logging.py +15 -0
  61. eth_portfolio_scripts/_portfolio.py +194 -0
  62. eth_portfolio_scripts/_utils.py +106 -0
  63. eth_portfolio_scripts/balances.cpython-312-i386-linux-gnu.so +0 -0
  64. eth_portfolio_scripts/balances.py +52 -0
  65. eth_portfolio_scripts/docker/.grafana/dashboards/Portfolio/Balances.json +1962 -0
  66. eth_portfolio_scripts/docker/.grafana/dashboards/dashboards.yaml +10 -0
  67. eth_portfolio_scripts/docker/.grafana/datasources/datasources.yml +11 -0
  68. eth_portfolio_scripts/docker/__init__.cpython-312-i386-linux-gnu.so +0 -0
  69. eth_portfolio_scripts/docker/__init__.py +16 -0
  70. eth_portfolio_scripts/docker/check.cpython-312-i386-linux-gnu.so +0 -0
  71. eth_portfolio_scripts/docker/check.py +67 -0
  72. eth_portfolio_scripts/docker/docker-compose.yaml +61 -0
  73. eth_portfolio_scripts/docker/docker_compose.cpython-312-i386-linux-gnu.so +0 -0
  74. eth_portfolio_scripts/docker/docker_compose.py +96 -0
  75. eth_portfolio_scripts/main.py +119 -0
  76. eth_portfolio_scripts/py.typed +1 -0
  77. eth_portfolio_scripts/victoria/__init__.py +73 -0
  78. eth_portfolio_scripts/victoria/types.py +38 -0
  79. eth_portfolio_temp-0.2.16.dist-info/METADATA +26 -0
  80. eth_portfolio_temp-0.2.16.dist-info/RECORD +83 -0
  81. eth_portfolio_temp-0.2.16.dist-info/WHEEL +7 -0
  82. eth_portfolio_temp-0.2.16.dist-info/entry_points.txt +2 -0
  83. eth_portfolio_temp-0.2.16.dist-info/top_level.txt +3 -0
@@ -0,0 +1,194 @@
1
+ import logging
2
+ from typing import Any, Final, Optional, Set
3
+
4
+ from a_sync import igather
5
+ from eth_typing import ChecksumAddress
6
+ from faster_async_lru import alru_cache
7
+ from y.constants import CHAINID, STABLECOINS, WRAPPED_GAS_COIN
8
+ from y.convert import to_address
9
+ from y.datatypes import Address, AnyAddressType
10
+ from y.exceptions import ContractNotVerified
11
+ from y.prices.lending.aave import aave
12
+ from y.prices.lending.compound import CToken, compound
13
+ from y.prices.stable_swap.curve import curve
14
+ from y.prices.yearn import YearnInspiredVault, is_yearn_vault
15
+
16
+ from eth_portfolio.constants import BTC_LIKE, ETH_LIKE, INTL_STABLECOINS
17
+ from eth_portfolio._stableish import STABLEISH_COINS
18
+
19
+ logger: Final = logging.getLogger(__name__)
20
+ log_debug: Final = logger.debug
21
+
22
+ SORT_AS_STABLES: Final = STABLECOINS.keys() | STABLEISH_COINS[CHAINID]
23
+ OTHER_LONG_TERM_ASSETS: Final[Set[ChecksumAddress]] = {}.get(CHAINID, set()) # type: ignore [call-overload]
24
+
25
+
26
+ async def get_token_bucket(token: AnyAddressType) -> str:
27
+ """
28
+ Categorize a token into a specific bucket based on its type.
29
+
30
+ This function attempts to categorize a given token into predefined buckets
31
+ such as "Cash & cash equivalents", "ETH", "BTC", "Other long term assets",
32
+ or "Other short term assets". The categorization is based on the token's
33
+ characteristics and its presence in specific sets like :data:`ETH_LIKE`, :data:`BTC_LIKE`,
34
+ and :data:`OTHER_LONG_TERM_ASSETS`.
35
+
36
+ Args:
37
+ token: The address of the token to categorize.
38
+
39
+ Returns:
40
+ A string representing the bucket category of the token.
41
+
42
+ Raises:
43
+ ValueError: If the token's source has not been verified and the error message
44
+ does not match the expected pattern.
45
+
46
+ Example:
47
+ Categorize a stablecoin:
48
+
49
+ >>> await get_token_bucket("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")
50
+ 'Cash & cash equivalents'
51
+
52
+ Categorize an ETH-like token:
53
+
54
+ >>> await get_token_bucket("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE")
55
+ 'ETH'
56
+
57
+ See Also:
58
+ - :func:`_unwrap_token`
59
+ - :func:`_is_stable`
60
+ """
61
+ token_address = to_address(token)
62
+ try:
63
+ token_address = await _unwrap_token(token_address)
64
+ except ContractNotVerified as e:
65
+ return "Other short term assets"
66
+
67
+ if _is_stable(token_address):
68
+ return "Cash & cash equivalents"
69
+ if token_address in ETH_LIKE:
70
+ return "ETH"
71
+ if token_address in BTC_LIKE:
72
+ return "BTC"
73
+ if token_address in OTHER_LONG_TERM_ASSETS:
74
+ return "Other long term assets"
75
+ return "Other short term assets"
76
+
77
+
78
+ @alru_cache(maxsize=None)
79
+ async def _unwrap_token(token: Any) -> ChecksumAddress:
80
+ """
81
+ Recursively unwrap a token to its underlying asset.
82
+
83
+ This function attempts to unwrap a given token to its underlying asset by
84
+ checking if the token is a Yearn vault, a Curve pool, an Aave aToken, or a
85
+ Compound market. It recursively retrieves the underlying asset until it
86
+ reaches the base token.
87
+
88
+ Args:
89
+ token: The address of the token to unwrap.
90
+
91
+ Returns:
92
+ The address of the underlying asset.
93
+
94
+ Example:
95
+ Unwrap a Yearn vault token:
96
+
97
+ >>> await _unwrap_token("0x5f18C75AbDAe578b483E5F43f12a39cF75b973a9")
98
+ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
99
+
100
+ See Also:
101
+ - :func:`y.prices.yearn.is_yearn_vault`
102
+ - :class:`y.prices.yearn.YearnInspiredVault`
103
+ - :class:`y.prices.stable_swap.curve`
104
+ - :class:`y.prices.lending.aave`
105
+ - :class:`y.prices.lending.compound.CToken`
106
+ """
107
+ log_debug("unwrapping %s", token)
108
+ if str(token) in {"ETH", "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"}:
109
+ log_debug("returning eee address")
110
+ return token
111
+
112
+ if await is_yearn_vault(token, sync=False):
113
+ underlying = await YearnInspiredVault(token, asynchronous=True).underlying
114
+ log_debug("underlying: %s", underlying)
115
+ return await _unwrap_token(underlying)
116
+ if curve and (pool := await curve.get_pool(token)):
117
+ pool_tokens = set(await igather(map(_unwrap_token, await pool.coins)))
118
+ log_debug("pool_tokens: %s", pool_tokens)
119
+ if pool_bucket := _pool_bucket(pool_tokens):
120
+ log_debug("returning pool bucket: %s", pool_bucket)
121
+ return pool_bucket # type: ignore
122
+ if aave and await aave.is_atoken(token):
123
+ log_debug("atoken")
124
+ return str(await aave.underlying(token))
125
+ if compound and await compound.is_compound_market(token):
126
+ log_debug("unwrapping ctoken %s", token)
127
+ try:
128
+ return str(await CToken(token, asynchronous=True).underlying)
129
+ except AttributeError:
130
+ return WRAPPED_GAS_COIN
131
+ log_debug("returning: %s", token)
132
+ return token
133
+
134
+
135
+ def _pool_bucket(pool_tokens: set) -> Optional[str]:
136
+ """
137
+ Determine the bucket for a set of pool tokens.
138
+
139
+ This function checks if a set of pool tokens belongs to specific categories
140
+ such as BTC-like, ETH-like, or stablecoins, and returns the corresponding
141
+ bucket.
142
+
143
+ Args:
144
+ pool_tokens: A set of token addresses representing the pool tokens.
145
+
146
+ Returns:
147
+ A string representing the bucket category of the pool tokens, or None if
148
+ no specific category is found.
149
+
150
+ Example:
151
+ Determine the bucket for a BTC-like pool:
152
+
153
+ >>> _pool_bucket({"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"})
154
+ '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599'
155
+
156
+ See Also:
157
+ - :data:`BTC_LIKE`
158
+ - :data:`ETH_LIKE`
159
+ - :data:`STABLECOINS`
160
+ - :data:`INTL_STABLECOINS`
161
+ """
162
+ log_debug("Pool tokens: %s", pool_tokens)
163
+ if pool_tokens < BTC_LIKE:
164
+ return list(BTC_LIKE)[0]
165
+ if pool_tokens < ETH_LIKE:
166
+ return list(ETH_LIKE)[0]
167
+ if pool_tokens < SORT_AS_STABLES:
168
+ return list(SORT_AS_STABLES)[0]
169
+ return list(INTL_STABLECOINS)[0] if pool_tokens < INTL_STABLECOINS else None
170
+
171
+
172
+ def _is_stable(token: ChecksumAddress) -> bool:
173
+ """
174
+ Check if a token is a stablecoin or stable-ish coin.
175
+
176
+ This function checks if a given token is present in the :data:`STABLECOINS`,
177
+ :data:`INTL_STABLECOINS`, or :data:`STABLEISH_COINS` sets, indicating that it is
178
+ a stablecoin or considered stable by the wider market.
179
+
180
+ Args:
181
+ token: The address of the token to check.
182
+
183
+ Example:
184
+ Check if a token is a stablecoin or stable-ish coin:
185
+
186
+ >>> _is_stable("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")
187
+ True
188
+
189
+ See Also:
190
+ - :data:`STABLECOINS`
191
+ - :data:`INTL_STABLECOINS`
192
+ - :data:`STABLEISH_COINS`
193
+ """
194
+ return token in SORT_AS_STABLES or token in INTL_STABLECOINS
@@ -0,0 +1,82 @@
1
+ import os
2
+ from typing import Final
3
+
4
+ from brownie import chain
5
+ from y import Network, convert, weth
6
+
7
+ ERC20_TRANSFER_EVENT_HASH: Final = (
8
+ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
9
+ )
10
+ ERC677_TRANSFER_EVENT_HASH: Final = (
11
+ "0xe19260aff97b920c7df27010903aeb9c8d2be5d310a2c67824cf3f15396e4c16"
12
+ )
13
+
14
+ NUM_WALLETS: Final = int(os.environ.get("NUM_WALLETS", "10"))
15
+ ADDRESSES: Final = [
16
+ convert.to_address(address)
17
+ for address in {os.environ.get(f"PORTFOLIO_ADDRESS_{i}", None) for i in range(NUM_WALLETS)}
18
+ if address is not None
19
+ ]
20
+
21
+ TRANSFER_SIGS: Final = [ERC20_TRANSFER_EVENT_HASH, ERC677_TRANSFER_EVENT_HASH]
22
+
23
+ ETH_LIKE: Final = {
24
+ Network.Mainnet: {
25
+ "ETH",
26
+ weth.address,
27
+ "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
28
+ "0x5e74C9036fb86BD7eCdcb084a0673EFc32eA31cb", # seth
29
+ "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", # eth
30
+ "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", # steth
31
+ "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", # wstETH
32
+ "0x9559Aaa82d9649C7A7b220E7c461d2E74c9a3593", # reth
33
+ "0xE95A203B1a91a908F9B9CE46459d101078c2c3cb", # ankreth
34
+ "0x04C154b66CB340F3Ae24111CC767e0184Ed00Cc6", # pxETH
35
+ "0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3", # oETH
36
+ "0x0100546F2cD4C9D97f798fFC9755E47865FF7Ee6", # alETH
37
+ "0x1BED97CBC3c24A4fb5C069C6E311a967386131f7", # yETH
38
+ "0x24Ae2dA0f361AA4BE46b48EB19C91e02c5e4f27E", # mevETH
39
+ "0x5E8422345238F34275888049021821E8E08CAa1f", # frxETH
40
+ "0x821A278dFff762c76410264303F25bF42e195C0C", # pETH
41
+ "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704", # cbETH
42
+ "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", # weETH
43
+ "0x7C07F7aBe10CE8e33DC6C5aD68FE033085256A84", # icETH
44
+ },
45
+ }.get(chain.id, set())
46
+
47
+ BTC_LIKE: Final = {
48
+ Network.Mainnet: {
49
+ "0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D", # renbtc
50
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", # wbtc
51
+ "0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6", # sbtc
52
+ "0x8064d9Ae6cDf087b1bcd5BDf3531bD5d8C537a68", # obtc
53
+ "0x9BE89D2a4cd102D8Fecc6BF9dA793be995C22541", # bbtc
54
+ "0x0316EB71485b0Ab14103307bf65a021042c6d380", # hbtc
55
+ "0x5228a22e72ccC52d415EcFd199F99D0665E7733b", # pbtc
56
+ "0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa", # tbtc
57
+ "0x66eFF5221ca926636224650Fd3B9c497FF828F7D", # multiBTC
58
+ "0x657e8C867D8B37dCC18fA4Caead9C45EB088C642", # eBTC
59
+ },
60
+ }.get(chain.id, set())
61
+
62
+ INTL_STABLECOINS: Final = {
63
+ Network.Mainnet: {
64
+ "0xD71eCFF9342A5Ced620049e616c5035F1dB98620", # sEUR
65
+ "0xC581b735A1688071A1746c968e0798D642EDE491", # EURT
66
+ "0xdB25f211AB05b1c97D595516F45794528a807ad8", # EURS
67
+ "0x96E61422b6A9bA0e068B6c5ADd4fFaBC6a4aae27", # ibEUR
68
+ "0x9fcf418B971134625CdF38448B949C8640971671", # EURN
69
+ "0x39b8B6385416f4cA36a20319F70D28621895279D", # EURe
70
+ "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c", # EURC
71
+ "0x3F1B0278A9ee595635B61817630cC19DE792f506", # sAUD
72
+ "0xFAFdF0C4c1CB09d430Bf88c75D88BB46DAe09967", # ibAUD
73
+ "0x97fe22E7341a0Cd8Db6F6C021A24Dc8f4DAD855F", # sGBP
74
+ "0x69681f8fde45345C3870BCD5eaf4A05a60E7D227", # ibGBP
75
+ "0xF6b1C627e95BFc3c1b4c9B825a032Ff0fBf3e07d", # sJPY
76
+ "0x5555f75e3d5278082200Fb451D1b6bA946D8e13b", # ibJPY
77
+ "0x0F83287FF768D1c1e17a42F44d644D7F22e8ee1d", # sCHF
78
+ "0x1CC481cE2BD2EC7Bf67d1Be64d4878b16078F309", # ibCHF
79
+ "0x269895a3dF4D73b077Fc823dD6dA1B95f72Aaf9B", # sKRW
80
+ "0x95dFDC8161832e4fF7816aC4B6367CE201538253", # ibKRW
81
+ },
82
+ }.get(chain.id, set())