eth-portfolio-temp 0.0.35.dev0__cp310-cp310-win32.whl → 0.2.17__cp310-cp310-win32.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 (46) hide show
  1. eth_portfolio/_argspec.cp310-win32.pyd +0 -0
  2. eth_portfolio/_cache.py +2 -2
  3. eth_portfolio/_config.cp310-win32.pyd +0 -0
  4. eth_portfolio/_db/utils.py +7 -9
  5. eth_portfolio/_decimal.py +11 -10
  6. eth_portfolio/_ledgers/address.py +1 -1
  7. eth_portfolio/_loaders/_nonce.cp310-win32.pyd +0 -0
  8. eth_portfolio/_loaders/_nonce.py +4 -4
  9. eth_portfolio/_loaders/balances.cp310-win32.pyd +0 -0
  10. eth_portfolio/_loaders/token_transfer.py +1 -1
  11. eth_portfolio/_loaders/transaction.py +1 -1
  12. eth_portfolio/_loaders/utils.cp310-win32.pyd +0 -0
  13. eth_portfolio/_loaders/utils.py +1 -1
  14. eth_portfolio/_shitcoins.cp310-win32.pyd +0 -0
  15. eth_portfolio/_shitcoins.py +54 -0
  16. eth_portfolio/_stableish.cp310-win32.pyd +0 -0
  17. eth_portfolio/_utils.py +12 -10
  18. eth_portfolio/_ydb/token_transfers.py +32 -23
  19. eth_portfolio/address.py +2 -1
  20. eth_portfolio/buckets.py +3 -3
  21. eth_portfolio/constants.cp310-win32.pyd +0 -0
  22. eth_portfolio/portfolio.py +1 -1
  23. eth_portfolio/protocols/lending/liquity.py +1 -1
  24. eth_portfolio/protocols/lending/maker.py +13 -14
  25. eth_portfolio/structs/structs.py +2 -2
  26. eth_portfolio/typing/__init__.py +6 -6
  27. eth_portfolio__mypyc.cp310-win32.pyd +0 -0
  28. eth_portfolio_scripts/_portfolio.py +54 -41
  29. eth_portfolio_scripts/_utils.py +20 -6
  30. eth_portfolio_scripts/balances.cp310-win32.pyd +0 -0
  31. eth_portfolio_scripts/balances.py +7 -4
  32. eth_portfolio_scripts/docker/__init__.cp310-win32.pyd +0 -0
  33. eth_portfolio_scripts/docker/check.cp310-win32.pyd +0 -0
  34. eth_portfolio_scripts/docker/check.py +28 -17
  35. eth_portfolio_scripts/docker/docker-compose.yaml +2 -2
  36. eth_portfolio_scripts/docker/docker_compose.cp310-win32.pyd +0 -0
  37. eth_portfolio_scripts/docker/docker_compose.py +38 -18
  38. eth_portfolio_scripts/main.py +6 -0
  39. eth_portfolio_scripts/victoria/__init__.py +3 -0
  40. {eth_portfolio_temp-0.0.35.dev0.dist-info → eth_portfolio_temp-0.2.17.dist-info}/METADATA +8 -7
  41. eth_portfolio_temp-0.2.17.dist-info/RECORD +83 -0
  42. {eth_portfolio_temp-0.0.35.dev0.dist-info → eth_portfolio_temp-0.2.17.dist-info}/top_level.txt +1 -1
  43. 295eace8438df6ec133b__mypyc.cp310-win32.pyd +0 -0
  44. eth_portfolio_temp-0.0.35.dev0.dist-info/RECORD +0 -83
  45. {eth_portfolio_temp-0.0.35.dev0.dist-info → eth_portfolio_temp-0.2.17.dist-info}/WHEEL +0 -0
  46. {eth_portfolio_temp-0.0.35.dev0.dist-info → eth_portfolio_temp-0.2.17.dist-info}/entry_points.txt +0 -0
Binary file
eth_portfolio/_cache.py CHANGED
@@ -30,7 +30,7 @@ def cache_to_disk(fn: Callable[P, T]) -> Callable[P, T]:
30
30
  cache_path_for_fn = f"{BASE_PATH}{fn.__module__.replace('.', '/')}/{name}"
31
31
  logger = getLogger(f"eth_portfolio.cache_to_disk.{name}")
32
32
 
33
- def get_cache_file_path(args, kwargs):
33
+ def get_cache_file_path(args: tuple[Any, ...], kwargs: dict[str, Any]) -> str:
34
34
  # Create a unique filename based on the function arguments
35
35
  key = md5(dumps((args, sorted(kwargs.items())))).hexdigest()
36
36
  return join(cache_path_for_fn, f"{key}.json")
@@ -46,7 +46,7 @@ def cache_to_disk(fn: Callable[P, T]) -> Callable[P, T]:
46
46
 
47
47
  queue: PriorityQueue = PriorityQueue()
48
48
 
49
- async def cache_deco_worker_coro(func) -> NoReturn:
49
+ async def cache_deco_worker_coro(func: Callable[..., Any]) -> NoReturn:
50
50
  try:
51
51
  while True:
52
52
  _, fut, cache_path, args, kwargs = await queue.get()
Binary file
@@ -7,8 +7,7 @@ import evmspec
7
7
  import y._db.common
8
8
  import y._db.config as config
9
9
  from a_sync import PruningThreadPoolExecutor, a_sync
10
- from brownie import chain
11
- from eth_typing import ChecksumAddress
10
+ from eth_typing import ChecksumAddress, HexAddress
12
11
  from evmspec.data import _decode_hook
13
12
  from logging import getLogger
14
13
  from msgspec import ValidationError, json
@@ -32,7 +31,6 @@ from eth_portfolio._db.decorators import break_locks, requery_objs_on_diff_tx_er
32
31
  from eth_portfolio._db.entities import (
33
32
  AddressExtended,
34
33
  BlockExtended,
35
- ContractExtended,
36
34
  TokenExtended,
37
35
  )
38
36
  from eth_portfolio._decimal import Decimal
@@ -42,7 +40,7 @@ from eth_portfolio.typing import _P, _T, Fn
42
40
  logger = getLogger(__name__)
43
41
 
44
42
 
45
- def __bind():
43
+ def __bind() -> None:
46
44
  try:
47
45
  db.bind(**config.connection_settings)
48
46
  except BindingError as e:
@@ -176,7 +174,7 @@ def ensure_block(block: int) -> None:
176
174
  # )
177
175
 
178
176
 
179
- def is_token(address) -> bool:
177
+ def is_token(address: ChecksumAddress) -> bool:
180
178
  if address == EEE_ADDRESS:
181
179
  return False
182
180
  # with suppress(NonStandardERC20):
@@ -188,16 +186,16 @@ def is_token(address) -> bool:
188
186
  return get_event_loop().run_until_complete(_is_token(address))
189
187
 
190
188
 
191
- async def _is_token(address) -> bool:
189
+ async def _is_token(address: HexAddress) -> bool:
192
190
  # just breaking a weird lock, dont mind me
193
- if retval := await get_event_loop().run_in_executor(process, __is_token, address):
191
+ if retval := await get_event_loop().run_in_executor(process, __is_token, address): # type: ignore [name-defined]
194
192
  logger.debug("%s is token")
195
193
  else:
196
194
  logger.debug("%s is not token")
197
195
  return retval
198
196
 
199
197
 
200
- def __is_token(address) -> bool:
198
+ def __is_token(address: HexAddress) -> bool:
201
199
  with suppress(NonStandardERC20):
202
200
  erc = ERC20(address, asynchronous=True)
203
201
  if all(
@@ -322,7 +320,7 @@ async def get_transaction(sender: ChecksumAddress, nonce: int) -> Optional[Trans
322
320
  _decoded = 0
323
321
 
324
322
 
325
- async def _yield_to_loop():
323
+ async def _yield_to_loop() -> None:
326
324
  """dont let the event loop get congested, let your rpc begin work asap"""
327
325
  global _decoded
328
326
  _decoded += 1
eth_portfolio/_decimal.py CHANGED
@@ -3,6 +3,7 @@ import logging
3
3
  from typing import Union
4
4
 
5
5
  from evmspec.data import Wei
6
+ from typing_extensions import Self
6
7
 
7
8
 
8
9
  logger = logging.getLogger(__name__)
@@ -69,61 +70,61 @@ class Decimal(decimal.Decimal):
69
70
 
70
71
  return string
71
72
 
72
- def __add__(self, other):
73
+ def __add__(self, other) -> Self:
73
74
  try:
74
75
  return type(self)(super().__add__(other))
75
76
  except TypeError as e:
76
77
  raise TypeError(str(e), other) from e.__cause__
77
78
 
78
- def __radd__(self, other):
79
+ def __radd__(self, other) -> Self:
79
80
  try:
80
81
  return type(self)(super().__radd__(other))
81
82
  except TypeError as e:
82
83
  raise TypeError(str(e), other) from e.__cause__
83
84
 
84
- def __sub__(self, other):
85
+ def __sub__(self, other) -> Self:
85
86
  try:
86
87
  return type(self)(super().__sub__(other))
87
88
  except TypeError as e:
88
89
  raise TypeError(str(e), other) from e.__cause__
89
90
 
90
- def __rsub__(self, other):
91
+ def __rsub__(self, other) -> Self:
91
92
  try:
92
93
  return type(self)(super().__rsub__(other))
93
94
  except TypeError as e:
94
95
  raise TypeError(str(e), other) from e.__cause__
95
96
 
96
- def __mul__(self, other):
97
+ def __mul__(self, other) -> Self:
97
98
  try:
98
99
  return type(self)(super().__mul__(other))
99
100
  except TypeError as e:
100
101
  raise TypeError(str(e), other) from e.__cause__
101
102
 
102
- def __rmul__(self, other):
103
+ def __rmul__(self, other) -> Self:
103
104
  try:
104
105
  return type(self)(super().__rmul__(other))
105
106
  except TypeError as e:
106
107
  raise TypeError(str(e), other) from e.__cause__
107
108
 
108
- def __truediv__(self, other):
109
+ def __truediv__(self, other) -> Self:
109
110
  try:
110
111
  return type(self)(super().__truediv__(other))
111
112
  except TypeError as e:
112
113
  raise TypeError(str(e), other) from e.__cause__
113
114
 
114
- def __rtruediv__(self, other):
115
+ def __rtruediv__(self, other) -> Self:
115
116
  try:
116
117
  return type(self)(super().__rtruediv__(other))
117
118
  except TypeError as e:
118
119
  raise TypeError(str(e), other) from e.__cause__
119
120
 
120
- def __floordiv__(self, other):
121
+ def __floordiv__(self, other) -> Self:
121
122
  try:
122
123
  return type(self)(super().__floordiv__(other))
123
124
  except TypeError as e:
124
125
  raise TypeError(str(e), other) from e.__cause__
125
126
 
126
- def __rfloordiv__(self, other):
127
+ def __rfloordiv__(self, other) -> Self:
127
128
  try:
128
129
  return type(self)(super().__rfloordiv__(other))
129
130
  except TypeError as e:
@@ -37,13 +37,13 @@ import dank_mids
37
37
  import eth_retry
38
38
  from a_sync.asyncio import sleep0 as yield_to_loop
39
39
  from aiohttp import ClientResponseError
40
- from async_lru import alru_cache
41
40
  from brownie import chain
42
41
  from dank_mids.eth import TraceFilterParams
43
42
  from eth_typing import BlockNumber, ChecksumAddress
44
43
  from evmspec import FilterTrace
45
44
  from evmspec.structs.receipt import Status
46
45
  from evmspec.structs.trace import call, reward
46
+ from faster_async_lru import alru_cache
47
47
  from typing_extensions import Unpack
48
48
  from pandas import DataFrame # type: ignore
49
49
  from tqdm import tqdm
@@ -2,7 +2,7 @@ import asyncio
2
2
  import logging
3
3
  from collections import defaultdict
4
4
  from time import time
5
- from typing import ClassVar, DefaultDict, Dict, Final, Tuple, final
5
+ from typing import ClassVar, DefaultDict, Dict, Final, Optional, Tuple, final
6
6
 
7
7
  import a_sync
8
8
  import dank_mids
@@ -145,7 +145,7 @@ async def _get_area(
145
145
  return lo, hi
146
146
 
147
147
 
148
- def _update_nonces(address: ChecksumAddress, nonce: Nonce, block: BlockNumber):
148
+ def _update_nonces(address: ChecksumAddress, nonce: Nonce, block: BlockNumber) -> None:
149
149
  # if you are searching for `nonce` and you verified it occurs AT or ABOVE `block` call this fn.
150
150
  if block > nonces[address][nonce]:
151
151
  nonces[address][nonce] = block
@@ -178,13 +178,13 @@ def _get_num_chunks(range_size: int) -> int:
178
178
 
179
179
  @final
180
180
  class BlockCache:
181
- block: ClassVar = 0
181
+ block: ClassVar[BlockNumber] = 0
182
182
  updated_at: ClassVar = 0.0
183
183
  lock: Final = asyncio.Lock()
184
184
  ttl: Final = 5.0
185
185
 
186
186
 
187
- async def get_block_number():
187
+ async def get_block_number() -> BlockNumber:
188
188
  if now() - BlockCache.updated_at < BlockCache.ttl:
189
189
  return BlockCache.block
190
190
  async with BlockCache.lock:
@@ -7,10 +7,10 @@ from logging import getLogger
7
7
  from typing import Final, Optional, Set
8
8
 
9
9
  from a_sync import create_task, gather
10
- from async_lru import alru_cache
11
10
  from dank_mids import BlockSemaphore
12
11
  from eth_typing import ChecksumAddress
13
12
  from evmspec.data import TransactionIndex
13
+ from faster_async_lru import alru_cache
14
14
  from msgspec import Struct, ValidationError
15
15
  from msgspec.json import decode
16
16
  from pony.orm import TransactionIntegrityError, UnexpectedError
@@ -15,9 +15,9 @@ import eth_retry
15
15
  import evmspec
16
16
  import msgspec
17
17
  from a_sync import SmartProcessingQueue
18
- from async_lru import alru_cache
19
18
  from eth_typing import ChecksumAddress
20
19
  from evmspec import data
20
+ from faster_async_lru import alru_cache
21
21
  from pony.orm import TransactionIntegrityError
22
22
  from y import get_price
23
23
  from y._decorators import stuck_coro_debugger
@@ -4,8 +4,8 @@ import dank_mids
4
4
  import eth_retry
5
5
  import msgspec
6
6
  from a_sync import SmartProcessingQueue
7
- from async_lru import alru_cache
8
7
  from eth_typing import HexStr
8
+ from faster_async_lru import alru_cache
9
9
  from y._decorators import stuck_coro_debugger
10
10
 
11
11
 
Binary file
@@ -20,6 +20,7 @@ shitcoins: Final = {
20
20
  "0xBFA9180729f1c549334080005Ca37093593fB7Aa",
21
21
  "0x643695D282f6BA237afe27FFE0Acd89a86b50d3e",
22
22
  # Tagged as spam on Etherscan
23
+ "0x3B809ABd5a7597F8d1cf7dEB2747A1e1580C1488",
23
24
  "0xCfB0Ef3e179427316FBD7F0D0296F173762BeEE0",
24
25
  "0xfAFe8a7c0A9b3807CC1df0DEB0BA0B5a5fb7A872",
25
26
  "0xdf66B9727553fB9Bfa417699CB8F60425d62d1E3",
@@ -67,6 +68,12 @@ shitcoins: Final = {
67
68
  "0x635701CC5fE41FE8AbD02aa74Beb02e3540E9BB2",
68
69
  "0xF709642622729feafC8bf0934679706df49d8A30",
69
70
  # Tagged as phishing on Etherscan
71
+ "0x4AeDC0B9Acdf5BE1d312Ace7c2df425C2f56F9C3",
72
+ "0xd16A07Ac860c95F3E225b3A847F81C267b3f929d",
73
+ "0x211c1eB92D74cbdA58bA82116502fD02dd8F319E",
74
+ "0x6ef7D6682086Ad4936D2bC141cD94b2c43476FeD",
75
+ "0x0C98216a20f8e19C1483cf8B307A5E9ce758428D",
76
+ "0x6426b6C2A9108Fa815bcccA3a3232301E1895742",
70
77
  "0x0bF377fb3b5F1dD601e693B8fAF6b0bD249f37D3",
71
78
  "0xBf5fB1563ef58ba41325454ca61Cc3D62bd40744",
72
79
  "0x54fd62228C6e1234fd5Fded28555CA963Dcf6d26",
@@ -90,6 +97,22 @@ shitcoins: Final = {
90
97
  "0x0e1CD6d2715432e4DBedFE969b0Eb2867FF61d5b",
91
98
  "0x9aE357521153FB07bE6F5792CE7a49752638fbb7",
92
99
  # Generally looks like shit
100
+ "0x5e43e50A3cB43Fb71eD2500bC847E8d25b8335f9",
101
+ "0xE8ED1fca5af1c7dd46A3D5bbDFf7e99749D9e0aa",
102
+ "0x00d0F0250364C431376cC64AADd3aa13c6A8998D",
103
+ "0x256099A072ea5fd35eC134758440413095967109",
104
+ "0xe975ACEb3b61a88A355B066D9cCC910CAb8b4853",
105
+ "0x59fF00f75b49089385377c7f7D905E193c9eb5e2",
106
+ "0x99304A346F8FD562336Fd3485301c02cEbE4F0ae",
107
+ "0x74b1C36268B5dC659aEEA588cb1683E96DaaB71a",
108
+ "0x92BF340B2c67be6911095675f744F9a3aD22d8F0",
109
+ "0xa635305B4a6A1E4A55Eb6A6B54a8D2a55e914F6f",
110
+ "0xC76f77Bff99Ec269050Ca929F4d37B00f012c65F",
111
+ "0x56BcBef8f5Ca4Fc224fE58187c66EA34d3A1ef4a",
112
+ "0xdc6050Ec75Bc4692333A1C301eB799e348d0b77e",
113
+ "0x0542e502cec25bD51b4f3461f4F704807FA1A6D8",
114
+ "0xc01e807Cc73469e9983B614A96847BC01332447d",
115
+ "0x87D38d662A4aae29BB60057e71AFf923C7523DC3",
93
116
  "0xDFC01a7956C0d151ae197274B974fA7527EbAFB9",
94
117
  "0xE256CF1C7caEff4383DabafEe6Dd53910F97213D",
95
118
  "0x7CD6143B8781dC7e0667e50DB02Eb6539799722F",
@@ -163,7 +186,32 @@ shitcoins: Final = {
163
186
  "0xc6a76f7ad66d0e6Ccd1AaAd6e7568c9bd55Dce62",
164
187
  "0xB4d4334eB5a251cbE5cC7Afb0Ba26119aCE62281",
165
188
  "0xE5c5AE39B98eFd9D3c9E0F2a5457D98fFA4b0b46",
189
+ # Generally looks like shit (symbol ERC20)
190
+ "0x2adA6e459089292264133d8D7c85f6907423E444",
191
+ "0x356F680eE21c8CeFfA460c38D20A137F3D07D9af",
192
+ "0x683eAca6CD17383FA93e95f17e7DE443666160eB",
193
+ "0x7452cc6Bd1FA968dd1672FF447f3D7ff1ce210A8",
194
+ "0x773F67800a6d79C0198E8Ac798658f80cb346083",
195
+ "0xaE977D03F5A3999c762eb42a203c436dFF3Df03C",
196
+ "0xbD67D76edFD88719efD7669583258209015B0aB5",
197
+ "0xd814cd86ed2e85156d9Cf3A9319261259458f50c",
198
+ "0xd0E6420b900dE49113B3404b437ee153Bf220B36",
199
+ "0xf1D1C6ea9166bcF97A099A1388E1663933bB2E48",
200
+ "0xF8B49aEC3E356f911f86F58Ff9204242d4b0e6A5",
201
+ "0xe37be01D1337E77aCB0b4293DDb4D410D80010a7",
202
+ "0x7EeAcC32C81e4D78E9705fBf0b977f5A858Bf0F3",
203
+ "0x90133FF815ade1977EA2f1454dBC1d309EAA33f6",
204
+ "0x82ff6D346E424025B1F07e4C8D6527806e50fCA5",
205
+ "0x7C2bc9F685e1f78e42d236Ff819D89DDA864359d",
206
+ "0x3ea463dD031A384DB68d6fD2f37574248E7ffCfE",
207
+ "0x241b047e810c70AB2bB5C567391E0888c4791cbe",
208
+ "0x47D1b57e5B542808eeEd0C509583Fa12d023f05e",
209
+ "0x8a33B3e6f5C0049Cff6dEca0564F5fbDa0eBe9f9",
210
+ "0x84b2e82Ef534e8bE05276DBf4F9e5474fBeD5E59",
211
+ "0x022b5fE59fc45a29d58a7e45a2567b69b649d623",
212
+ "0x178d20220c22008cc1886d2E689cAeE4A5c3239b",
166
213
  # Tagged as well known address scam on Etherscan
214
+ "0x59bed83a385571ffac0FC15A43f0f6f72e66Dccb",
167
215
  "0x2Ec109a0ceFEC70661a242a8B54cae8f45630397",
168
216
  "0x11d666B9C8fa057774324a9bFe6B53eB8d23079f",
169
217
  "0x0598BEf845934d83463cEaDd8C86F0801e2Ee058",
@@ -211,6 +259,7 @@ shitcoins: Final = {
211
259
  "0xAba86342C3f57E002F47F6eb38099A577312F2e8",
212
260
  "0x94C4bfDD351A2EeA9d57e602C2a24d6Fe823Fd1a",
213
261
  "0xAfF006725DeeAF5BF6750A6C7c98D9e70cB189a4",
262
+ "0x54c4D37aD550f9776CE2021df245d98B4Bb5Cb5E",
214
263
  # fake USDC
215
264
  "0x98a7800EB17e1A0e2b2A4b69e83c58F4535F2180",
216
265
  "0xdC5BCA9992191c900D7A7F5b8e1b3e4161d1aa51",
@@ -218,6 +267,8 @@ shitcoins: Final = {
218
267
  "0xbADbe6619c0563c60E62C7409681440a80391a27",
219
268
  "0x89D3Ac7C32Aa14bEE6Fa90E041241dc4eEbbDFB3",
220
269
  "0x640c6fdAfbDaC9bfCe79943890fdc98f8d39bE3e",
270
+ "0xA04a3a553548090a7b81D2de75B8a08Ee45860e1",
271
+ "0x1b8F28C0d410456FE04b8f421d00d6654F66AbB6",
221
272
  # fake DAI
222
273
  "0xf84f908E78f9295b53883AD9ACa38F86d513f03F",
223
274
  "0x20Dd160716b0387220Eea7B9951bDb51B3728DC4",
@@ -227,6 +278,9 @@ shitcoins: Final = {
227
278
  "0x9257Cf49802E00048A30a6429e9c4d86210F4253",
228
279
  "0x6b1b80b4b3228060EA21C292a3b9c576691Ca6cC",
229
280
  "0xfCDFf724385Dcb47f2E62f7F2E383a7822Ed9718",
281
+ "0x94a2a4d842F522Dac0E793f2f9Ad08058997D06d",
282
+ "0xb44D28295E3D7C898C087A1cB209A444DeD5E4c1",
283
+ "0xFf3A7EE33203F5d3C69C309B5425b0E3fEfB736B",
230
284
  # fake ETH
231
285
  "0x225795bb6D20773a4A34c682Ae8457D00C80F955",
232
286
  "0x25741E94782d3EaA7fb0A02D78256bf065AEC3B9",
Binary file
eth_portfolio/_utils.py CHANGED
@@ -18,10 +18,10 @@ from typing import (
18
18
 
19
19
  import dank_mids
20
20
  from a_sync import ASyncGenericBase, ASyncIterable, ASyncIterator, as_yielded
21
- from async_lru import alru_cache
22
21
  from brownie import chain
23
22
  from brownie.exceptions import ContractNotFound
24
- from eth_abi.exceptions import InsufficientDataBytes
23
+ from faster_async_lru import alru_cache
24
+ from faster_eth_abi.exceptions import InsufficientDataBytes
25
25
  from eth_typing import ChecksumAddress
26
26
  from pandas import DataFrame # type: ignore
27
27
  from y import ERC20, Contract, Network
@@ -47,10 +47,15 @@ if TYPE_CHECKING:
47
47
 
48
48
  logger: Final = logging.getLogger(__name__)
49
49
 
50
- NON_STANDARD_ERC721: Final = {
50
+ NON_STANDARD_ERC721: Final[List[ChecksumAddress]] = {
51
51
  Network.Mainnet: ["0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB"], # CryptoPunks
52
52
  }.get(CHAINID, [])
53
53
 
54
+ SUPPRESS_ERROR_LOGS: Final[List[ChecksumAddress]] = {
55
+ # put tokens here when you don't expect them to price successfully and do not want to see the associated error logs
56
+ }.get(CHAINID, [])
57
+ """Put tokens here when you don't expect them to price successfully and do not want to see the associated error logs."""
58
+
54
59
 
55
60
  async def get_buffered_chain_height() -> int:
56
61
  """Returns an int equal to the current height of the chain minus `_config.REORG_BUFFER`."""
@@ -74,10 +79,6 @@ class Decimal(_decimal.Decimal):
74
79
 
75
80
  # TODO i forget why I had this lol, should I delete?
76
81
 
77
- def __init__(self, v) -> None:
78
- # assert not isinstance(v, _decimal.Decimal)
79
- super().__init__()
80
-
81
82
 
82
83
  async def _describe_err(token: AddressOrContract, block: Optional[Block]) -> str:
83
84
  """
@@ -132,9 +133,10 @@ async def _get_price(token: AddressOrContract, block: Optional[int] = None) -> _
132
133
  # Can't get symbol for handling like other excs
133
134
  logger.warning(f"NonStandardERC20 while fetching price for {token}")
134
135
  elif isinstance(e.exception, PriceError):
135
- logger.warning(
136
- f"PriceError while fetching price for {await _describe_err(token, block)}"
137
- )
136
+ if token not in SUPPRESS_ERROR_LOGS:
137
+ logger.warning(
138
+ f"PriceError while fetching price for {await _describe_err(token, block)}"
139
+ )
138
140
  else:
139
141
  logger.warning(f"{e} while fetching price for {await _describe_err(token, block)}")
140
142
  logger.warning(e, exc_info=True)
@@ -1,15 +1,16 @@
1
1
  from abc import abstractmethod
2
2
  from asyncio import Task, create_task, sleep
3
3
  from logging import DEBUG, getLogger
4
- from typing import AsyncIterator, List
4
+ from typing import Any, AsyncIterator, Final, List
5
5
 
6
6
  import dank_mids
7
7
  import evmspec
8
8
  import y._db.log
9
9
  from a_sync import ASyncIterable, ASyncIterator, as_yielded
10
10
  from brownie import chain
11
+ from eth_typing import BlockNumber, ChecksumAddress
12
+ from faster_eth_abi import encode
11
13
  from faster_eth_utils import encode_hex
12
- from y.datatypes import Address
13
14
  from y.utils.events import ProcessedEvents
14
15
 
15
16
  from eth_portfolio._loaders import load_token_transfer
@@ -18,19 +19,13 @@ from eth_portfolio.constants import TRANSFER_SIGS
18
19
  from eth_portfolio.structs import TokenTransfer
19
20
 
20
21
 
21
- try:
22
- # this is only available in 4.0.0+
23
- from eth_abi import encode
22
+ logger: Final = getLogger(__name__)
23
+ _logger_is_enabled_for: Final = logger.isEnabledFor
24
+ _logger_log: Final = logger._log
24
25
 
25
- encode_address = lambda address: encode_hex(encode(["address"], [str(address)]))
26
- except ImportError:
27
- from eth_abi import encode_single
28
26
 
29
- encode_address = lambda address: encode_hex(encode_single("address", str(address)))
30
-
31
- logger = getLogger(__name__)
32
- _logger_is_enabled_for = logger.isEnabledFor
33
- _logger_log = logger._log
27
+ def encode_address(address: Any) -> bytes:
28
+ return encode_hex(encode(["address"], [str(address)]))
34
29
 
35
30
 
36
31
  class _TokenTransfers(ProcessedEvents["Task[TokenTransfer]"]):
@@ -38,9 +33,14 @@ class _TokenTransfers(ProcessedEvents["Task[TokenTransfer]"]):
38
33
 
39
34
  __slots__ = "address", "_load_prices"
40
35
 
41
- def __init__(self, address: Address, from_block: int, load_prices: bool = False):
42
- self.address = address
43
- self._load_prices = load_prices
36
+ def __init__(
37
+ self,
38
+ address: ChecksumAddress,
39
+ from_block: BlockNumber,
40
+ load_prices: bool = False,
41
+ ) -> None:
42
+ self.address: Final = address
43
+ self._load_prices: Final = load_prices
44
44
  super().__init__(topics=self._topics, from_block=from_block)
45
45
 
46
46
  def __repr__(self) -> str:
@@ -51,7 +51,7 @@ class _TokenTransfers(ProcessedEvents["Task[TokenTransfer]"]):
51
51
  def _topics(self) -> List: ...
52
52
 
53
53
  @ASyncIterator.wrap # type: ignore [call-overload]
54
- async def yield_thru_block(self, block) -> AsyncIterator["Task[TokenTransfer]"]:
54
+ async def yield_thru_block(self, block: BlockNumber) -> AsyncIterator["Task[TokenTransfer]"]:
55
55
  if not _logger_is_enabled_for(DEBUG):
56
56
  async for task in self._objects_thru(block=block):
57
57
  yield task
@@ -119,18 +119,27 @@ class TokenTransfers(ASyncIterable[TokenTransfer]):
119
119
  NOTE: These do not come back in chronologcal order.
120
120
  """
121
121
 
122
- def __init__(self, address: Address, from_block: int, load_prices: bool = False):
123
- self.transfers_in = InboundTokenTransfers(address, from_block, load_prices=load_prices)
124
- self.transfers_out = OutboundTokenTransfers(address, from_block, load_prices=load_prices)
122
+ def __init__(
123
+ self,
124
+ address: ChecksumAddress,
125
+ from_block: BlockNumber,
126
+ load_prices: bool = False,
127
+ ) -> None:
128
+ self.transfers_in: Final = InboundTokenTransfers(
129
+ address, from_block, load_prices=load_prices
130
+ )
131
+ self.transfers_out: Final = OutboundTokenTransfers(
132
+ address, from_block, load_prices=load_prices
133
+ )
125
134
 
126
- async def __aiter__(self):
135
+ async def __aiter__(self) -> AsyncIterator["Task[TokenTransfer]"]:
127
136
  async for transfer in self.__yield_thru_block(await dank_mids.eth.block_number):
128
137
  yield transfer
129
138
 
130
- def yield_thru_block(self, block: int) -> ASyncIterator["Task[TokenTransfer]"]:
139
+ def yield_thru_block(self, block: BlockNumber) -> ASyncIterator["Task[TokenTransfer]"]:
131
140
  return ASyncIterator(self.__yield_thru_block(block))
132
141
 
133
- def __yield_thru_block(self, block: int) -> AsyncIterator["Task[TokenTransfer]"]:
142
+ def __yield_thru_block(self, block: BlockNumber) -> AsyncIterator["Task[TokenTransfer]"]:
134
143
  return as_yielded(
135
144
  self.transfers_in.yield_thru_block(block), self.transfers_out.yield_thru_block(block)
136
145
  )
eth_portfolio/address.py CHANGED
@@ -23,6 +23,7 @@ import dank_mids
23
23
  import eth_retry
24
24
  import y
25
25
  from a_sync.exceptions import MappingIsEmptyError
26
+ from eth_typing import BlockNumber
26
27
  from y import convert
27
28
  from y._decorators import stuck_coro_debugger
28
29
  from y.datatypes import Address, Block
@@ -312,7 +313,7 @@ class PortfolioAddress(_LedgeredBase[AddressLedgerBase]):
312
313
  return Balance(token=y.EEE_ADDRESS, block=block)
313
314
 
314
315
  @stuck_coro_debugger
315
- async def token_balances(self, block) -> TokenBalances:
316
+ async def token_balances(self, block: BlockNumber) -> TokenBalances:
316
317
  """
317
318
  Retrieves the balances for all tokens in the wallet at a given block.
318
319
 
eth_portfolio/buckets.py CHANGED
@@ -1,9 +1,9 @@
1
1
  import logging
2
- from typing import Final, Optional, Set
2
+ from typing import Any, Final, Optional, Set
3
3
 
4
4
  from a_sync import igather
5
- from async_lru import alru_cache
6
5
  from eth_typing import ChecksumAddress
6
+ from faster_async_lru import alru_cache
7
7
  from y.constants import CHAINID, STABLECOINS, WRAPPED_GAS_COIN
8
8
  from y.convert import to_address
9
9
  from y.datatypes import Address, AnyAddressType
@@ -76,7 +76,7 @@ async def get_token_bucket(token: AnyAddressType) -> str:
76
76
 
77
77
 
78
78
  @alru_cache(maxsize=None)
79
- async def _unwrap_token(token) -> ChecksumAddress:
79
+ async def _unwrap_token(token: Any) -> ChecksumAddress:
80
80
  """
81
81
  Recursively unwrap a token to its underlying asset.
82
82
 
Binary file
@@ -37,7 +37,7 @@ from eth_portfolio.typing import Addresses, PortfolioBalances
37
37
  logger = logging.getLogger(__name__)
38
38
 
39
39
 
40
- class PortfolioWallets(Iterable[PortfolioAddress], Dict[Address, PortfolioAddress]): # type: ignore [misc]
40
+ class PortfolioWallets(Iterable[PortfolioAddress], Dict[Address, PortfolioAddress]): # type: ignore [metaclass]
41
41
  """
42
42
  A container that holds all :class:`~eth_portfolio.address.PortfolioAddress` objects for a specific :class:`~eth_portfolio.Portfolio`.
43
43
 
@@ -1,6 +1,6 @@
1
1
  from typing import Optional
2
2
 
3
- from async_lru import alru_cache
3
+ from faster_async_lru import alru_cache
4
4
  from y import Contract, Network, get_price
5
5
  from y._decorators import stuck_coro_debugger
6
6
  from y.constants import EEE_ADDRESS
@@ -1,10 +1,12 @@
1
1
  from asyncio import gather
2
- from typing import List, Optional
2
+ from typing import Final, List, Optional
3
3
 
4
4
  from a_sync import igather
5
- from async_lru import alru_cache
5
+ from brownie import ZERO_ADDRESS
6
6
  from dank_mids.exceptions import Revert
7
7
  from eth_typing import HexStr
8
+ from faster_async_lru import alru_cache
9
+ from faster_eth_abi import encode
8
10
  from y import Contract, Network, contract_creation_block_async, get_price
9
11
  from y._decorators import stuck_coro_debugger
10
12
  from y.constants import dai
@@ -14,18 +16,15 @@ from eth_portfolio._utils import Decimal
14
16
  from eth_portfolio.protocols.lending._base import LendingProtocolWithLockedCollateral
15
17
  from eth_portfolio.typing import Balance, TokenBalances
16
18
 
17
- try:
18
- # this is only available in 4.0.0+
19
- from eth_abi import encode
20
19
 
21
- encode_bytes = lambda bytestring: encode(["bytes32"], [bytestring])
22
- except ImportError:
23
- from eth_abi import encode_single
20
+ yfi: Final = "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e"
21
+ dai: Contract
22
+ _1e18: Final = Decimal(10**18)
23
+ _1e45: Final = Decimal(10**45)
24
24
 
25
- encode_bytes = lambda bytestring: encode_single("bytes32", bytestring)
26
25
 
27
- yfi = "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e"
28
- dai: Contract
26
+ def encode_bytes(bytestring: str) -> bytes:
27
+ return encode(["bytes32"], [bytestring])
29
28
 
30
29
 
31
30
  class Maker(LendingProtocolWithLockedCollateral):
@@ -50,8 +49,8 @@ class Maker(LendingProtocolWithLockedCollateral):
50
49
 
51
50
  balances: TokenBalances = TokenBalances(block=block)
52
51
  for token, data in zip(gems, ink_data):
53
- if ink := data.dict()["ink"]:
54
- balance = ink / Decimal(10**18)
52
+ if token != ZERO_ADDRESS and (ink := data.dict()["ink"]):
53
+ balance = ink / _1e18
55
54
  value = round(balance * Decimal(await get_price(token, block, sync=False)), 18)
56
55
  balances[token] = Balance(balance, value, token=token, block=block)
57
56
  return balances
@@ -75,7 +74,7 @@ class Maker(LendingProtocolWithLockedCollateral):
75
74
  for urns, ilk_info in data:
76
75
  art = urns.dict()["art"]
77
76
  rate = ilk_info.dict()["rate"]
78
- debt = art * rate / Decimal(1e45)
77
+ debt = art * rate / _1e45
79
78
  balances[dai.address] += Balance(debt, debt, token=dai, block=block)
80
79
  return balances
81
80