eth-portfolio-temp 0.2.14__cp313-cp313-win_amd64.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.
- eth_portfolio/__init__.py +25 -0
- eth_portfolio/_argspec.cp313-win_amd64.pyd +0 -0
- eth_portfolio/_argspec.py +42 -0
- eth_portfolio/_cache.py +121 -0
- eth_portfolio/_config.cp313-win_amd64.pyd +0 -0
- eth_portfolio/_config.py +4 -0
- eth_portfolio/_db/__init__.py +0 -0
- eth_portfolio/_db/decorators.py +147 -0
- eth_portfolio/_db/entities.py +311 -0
- eth_portfolio/_db/utils.py +604 -0
- eth_portfolio/_decimal.py +156 -0
- eth_portfolio/_decorators.py +84 -0
- eth_portfolio/_exceptions.py +67 -0
- eth_portfolio/_ledgers/__init__.py +0 -0
- eth_portfolio/_ledgers/address.py +938 -0
- eth_portfolio/_ledgers/portfolio.py +327 -0
- eth_portfolio/_loaders/__init__.py +33 -0
- eth_portfolio/_loaders/_nonce.cp313-win_amd64.pyd +0 -0
- eth_portfolio/_loaders/_nonce.py +196 -0
- eth_portfolio/_loaders/balances.cp313-win_amd64.pyd +0 -0
- eth_portfolio/_loaders/balances.py +94 -0
- eth_portfolio/_loaders/token_transfer.py +217 -0
- eth_portfolio/_loaders/transaction.py +240 -0
- eth_portfolio/_loaders/utils.cp313-win_amd64.pyd +0 -0
- eth_portfolio/_loaders/utils.py +68 -0
- eth_portfolio/_shitcoins.cp313-win_amd64.pyd +0 -0
- eth_portfolio/_shitcoins.py +329 -0
- eth_portfolio/_stableish.cp313-win_amd64.pyd +0 -0
- eth_portfolio/_stableish.py +42 -0
- eth_portfolio/_submodules.py +73 -0
- eth_portfolio/_utils.py +225 -0
- eth_portfolio/_ydb/__init__.py +0 -0
- eth_portfolio/_ydb/token_transfers.py +145 -0
- eth_portfolio/address.py +397 -0
- eth_portfolio/buckets.py +194 -0
- eth_portfolio/constants.cp313-win_amd64.pyd +0 -0
- eth_portfolio/constants.py +82 -0
- eth_portfolio/portfolio.py +661 -0
- eth_portfolio/protocols/__init__.py +67 -0
- eth_portfolio/protocols/_base.py +108 -0
- eth_portfolio/protocols/convex.py +17 -0
- eth_portfolio/protocols/dsr.py +51 -0
- eth_portfolio/protocols/lending/README.md +6 -0
- eth_portfolio/protocols/lending/__init__.py +50 -0
- eth_portfolio/protocols/lending/_base.py +57 -0
- eth_portfolio/protocols/lending/compound.py +187 -0
- eth_portfolio/protocols/lending/liquity.py +110 -0
- eth_portfolio/protocols/lending/maker.py +104 -0
- eth_portfolio/protocols/lending/unit.py +46 -0
- eth_portfolio/protocols/liquity.py +16 -0
- eth_portfolio/py.typed +0 -0
- eth_portfolio/structs/__init__.py +43 -0
- eth_portfolio/structs/modified.py +69 -0
- eth_portfolio/structs/structs.py +637 -0
- eth_portfolio/typing/__init__.py +1447 -0
- eth_portfolio/typing/balance/single.py +176 -0
- eth_portfolio__mypyc.cp313-win_amd64.pyd +0 -0
- eth_portfolio_scripts/__init__.py +20 -0
- eth_portfolio_scripts/_args.py +26 -0
- eth_portfolio_scripts/_logging.py +15 -0
- eth_portfolio_scripts/_portfolio.py +194 -0
- eth_portfolio_scripts/_utils.py +106 -0
- eth_portfolio_scripts/balances.cp313-win_amd64.pyd +0 -0
- eth_portfolio_scripts/balances.py +52 -0
- eth_portfolio_scripts/docker/.grafana/dashboards/Portfolio/Balances.json +1962 -0
- eth_portfolio_scripts/docker/.grafana/dashboards/dashboards.yaml +10 -0
- eth_portfolio_scripts/docker/.grafana/datasources/datasources.yml +11 -0
- eth_portfolio_scripts/docker/__init__.cp313-win_amd64.pyd +0 -0
- eth_portfolio_scripts/docker/__init__.py +16 -0
- eth_portfolio_scripts/docker/check.cp313-win_amd64.pyd +0 -0
- eth_portfolio_scripts/docker/check.py +67 -0
- eth_portfolio_scripts/docker/docker-compose.yaml +61 -0
- eth_portfolio_scripts/docker/docker_compose.cp313-win_amd64.pyd +0 -0
- eth_portfolio_scripts/docker/docker_compose.py +81 -0
- eth_portfolio_scripts/main.py +119 -0
- eth_portfolio_scripts/py.typed +1 -0
- eth_portfolio_scripts/victoria/__init__.py +73 -0
- eth_portfolio_scripts/victoria/types.py +38 -0
- eth_portfolio_temp-0.2.14.dist-info/METADATA +26 -0
- eth_portfolio_temp-0.2.14.dist-info/RECORD +83 -0
- eth_portfolio_temp-0.2.14.dist-info/WHEEL +5 -0
- eth_portfolio_temp-0.2.14.dist-info/entry_points.txt +2 -0
- eth_portfolio_temp-0.2.14.dist-info/top_level.txt +3 -0
eth_portfolio/buckets.py
ADDED
|
@@ -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
|
|
Binary file
|
|
@@ -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())
|