yearn-treasury 0.0.8__cp310-cp310-win_amd64.whl → 0.0.48__cp310-cp310-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.
Potentially problematic release.
This version of yearn-treasury might be problematic. Click here for more details.
- yearn_treasury/__init__.py +16 -0
- yearn_treasury/_db.cp310-win_amd64.pyd +0 -0
- yearn_treasury/_db.py +41 -0
- yearn_treasury/_ens.cp310-win_amd64.pyd +0 -0
- yearn_treasury/_ens.py +14 -0
- yearn_treasury/_logging.cp310-win_amd64.pyd +0 -0
- yearn_treasury/_logging.py +43 -0
- yearn_treasury/address_labels.yaml +39 -0
- yearn_treasury/budget/__init__.cp310-win_amd64.pyd +0 -0
- yearn_treasury/budget/__init__.py +2 -2
- yearn_treasury/budget/_request.cp310-win_amd64.pyd +0 -0
- yearn_treasury/budget/_request.py +8 -0
- yearn_treasury/budget/_requests.cp310-win_amd64.pyd +0 -0
- yearn_treasury/budget/_requests.py +45 -14
- yearn_treasury/constants.py +34 -6
- yearn_treasury/main.py +77 -43
- yearn_treasury/rules/__init__.py +17 -0
- yearn_treasury/rules/constants.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/constants.py +1 -1
- yearn_treasury/rules/cost_of_revenue/gas.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/cost_of_revenue/gas.py +10 -3
- yearn_treasury/rules/expense/__init__.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/expense/general.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/expense/infrastructure.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/expense/infrastructure.py +31 -1
- yearn_treasury/rules/expense/people.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/expense/people.py +43 -0
- yearn_treasury/rules/expense/security.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/expense/security.py +51 -27
- yearn_treasury/rules/ignore/__init__.py +8 -6
- yearn_treasury/rules/ignore/general.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/general.py +3 -2
- yearn_treasury/rules/ignore/maker.py +48 -64
- yearn_treasury/rules/ignore/passthru.py +310 -0
- yearn_treasury/rules/ignore/staking.py +23 -18
- yearn_treasury/rules/ignore/swaps/__init__.py +18 -5
- yearn_treasury/rules/ignore/swaps/aave.py +39 -19
- yearn_treasury/rules/ignore/swaps/auctions.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/auctions.py +31 -0
- yearn_treasury/rules/ignore/swaps/compound.py +38 -36
- yearn_treasury/rules/ignore/swaps/conversion_factory.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/conversion_factory.py +21 -0
- yearn_treasury/rules/ignore/swaps/cowswap.py +87 -0
- yearn_treasury/rules/ignore/swaps/curve.py +170 -0
- yearn_treasury/rules/ignore/swaps/gearbox.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/gearbox.py +37 -0
- yearn_treasury/rules/ignore/swaps/iearn.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/iearn.py +43 -0
- yearn_treasury/rules/ignore/swaps/otc.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/otc.py +58 -0
- yearn_treasury/rules/ignore/swaps/pooltogether.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/pooltogether.py +23 -0
- yearn_treasury/rules/ignore/swaps/synthetix.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/synthetix.py +10 -0
- yearn_treasury/rules/ignore/swaps/uniswap.py +222 -169
- yearn_treasury/rules/ignore/swaps/unwrapper.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/unwrapper.py +17 -0
- yearn_treasury/rules/ignore/swaps/vaults.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/vaults.py +264 -0
- yearn_treasury/rules/ignore/swaps/woofy.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/woofy.py +80 -0
- yearn_treasury/rules/ignore/swaps/yfi.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/yfi.py +111 -0
- yearn_treasury/rules/ignore/swaps/yla.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/yla.py +28 -0
- yearn_treasury/rules/ignore/unit.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/unit.py +40 -0
- yearn_treasury/rules/ignore/weth.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/weth.py +12 -4
- yearn_treasury/rules/ignore/ygov.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_expense/__init__.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_expense/__init__.py +7 -0
- yearn_treasury/rules/other_expense/boost.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_expense/boost.py +49 -0
- yearn_treasury/rules/other_expense/bugs.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_expense/bugs.py +81 -0
- yearn_treasury/rules/other_expense/donations.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_expense/donations.py +43 -0
- yearn_treasury/rules/other_expense/dyfi.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_expense/dyfi.py +29 -0
- yearn_treasury/rules/other_expense/events.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_expense/events.py +21 -0
- yearn_treasury/rules/other_expense/match_on_to_address.yaml +3 -2
- yearn_treasury/rules/other_expense/misc.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_expense/misc.py +49 -0
- yearn_treasury/rules/other_expense/revshare.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_expense/revshare.py +20 -0
- yearn_treasury/rules/other_income/__init__.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_income/__init__.py +2 -77
- yearn_treasury/rules/other_income/airdrops.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_income/airdrops.py +30 -0
- yearn_treasury/rules/other_income/match_on_hash.yaml +2 -0
- yearn_treasury/rules/other_income/misc.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/other_income/misc.py +80 -0
- yearn_treasury/rules/revenue/__init__.py +5 -0
- yearn_treasury/rules/revenue/bribes.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/revenue/farming.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/revenue/farming.py +56 -0
- yearn_treasury/rules/revenue/keepcoins.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/revenue/seasolver.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/revenue/seasolver.py +7 -1
- yearn_treasury/rules/revenue/vaults.py +97 -34
- yearn_treasury/rules/revenue/yteams.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/revenue/yteams.py +17 -0
- yearn_treasury/shitcoins.py +93 -2
- yearn_treasury/vaults.cp310-win_amd64.pyd +0 -0
- yearn_treasury/vaults.py +30 -22
- yearn_treasury/wallets.yaml +54 -0
- yearn_treasury/yteams.py +208 -0
- yearn_treasury-0.0.48.dist-info/METADATA +86 -0
- yearn_treasury-0.0.48.dist-info/RECORD +128 -0
- yearn_treasury-0.0.48.dist-info/top_level.txt +2 -0
- yearn_treasury__mypyc.cp310-win_amd64.pyd +0 -0
- f79b89f5f6693162015b__mypyc.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/__init__.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/maker.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/staking.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/__init__.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/_skip_tokens.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/aave.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/compound.cp310-win_amd64.pyd +0 -0
- yearn_treasury/rules/ignore/swaps/uniswap.cp310-win_amd64.pyd +0 -0
- yearn_treasury-0.0.8.dist-info/METADATA +0 -69
- yearn_treasury-0.0.8.dist-info/RECORD +0 -76
- yearn_treasury-0.0.8.dist-info/top_level.txt +0 -2
- {yearn_treasury-0.0.8.dist-info → yearn_treasury-0.0.48.dist-info}/WHEEL +0 -0
- {yearn_treasury-0.0.8.dist-info → yearn_treasury-0.0.48.dist-info}/entry_points.txt +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
1
2
|
from logging import getLogger
|
|
2
|
-
from typing import Final, Optional
|
|
3
|
+
from typing import Final, Optional, cast
|
|
3
4
|
|
|
4
|
-
from async_lru import alru_cache
|
|
5
5
|
from dao_treasury import TreasuryTx, revenue
|
|
6
6
|
from eth_typing import ChecksumAddress
|
|
7
|
+
from faster_async_lru import alru_cache
|
|
7
8
|
from y import Contract, Network
|
|
8
9
|
|
|
9
10
|
from yearn_treasury.vaults import v1, v2
|
|
@@ -15,18 +16,25 @@ fees: Final = revenue("Fees")
|
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
# v1 helpers
|
|
18
|
-
def
|
|
19
|
+
def _is_single_sided(tx: TreasuryTx) -> bool:
|
|
20
|
+
"""Fees from single-sided strategies are not denominated in `vault.token`."""
|
|
21
|
+
symbol = tx.symbol
|
|
22
|
+
from_nickname = tx.from_nickname
|
|
23
|
+
return _is_y3crv(symbol, from_nickname) or _is_ypool(symbol, from_nickname)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _is_y3crv(symbol: str, from_nickname: str) -> bool:
|
|
19
27
|
return (
|
|
20
|
-
|
|
21
|
-
and
|
|
28
|
+
symbol == "y3Crv"
|
|
29
|
+
and from_nickname.startswith("Contract: Strategy")
|
|
22
30
|
and from_nickname.endswith("3pool")
|
|
23
31
|
)
|
|
24
32
|
|
|
25
33
|
|
|
26
|
-
def _is_ypool(
|
|
34
|
+
def _is_ypool(symbol: str, from_nickname: str) -> bool:
|
|
27
35
|
return (
|
|
28
|
-
|
|
29
|
-
and
|
|
36
|
+
symbol == "yyDAI+yUSDC+yUSDT+yTUSD"
|
|
37
|
+
and from_nickname.startswith("Contract: Strategy")
|
|
30
38
|
and from_nickname.endswith("ypool")
|
|
31
39
|
)
|
|
32
40
|
|
|
@@ -48,11 +56,13 @@ async def _get_controller(vault: Contract) -> Contract:
|
|
|
48
56
|
|
|
49
57
|
@fees("Vaults V1", Network.Mainnet)
|
|
50
58
|
async def is_v1_vault_fees(tx: TreasuryTx) -> bool:
|
|
51
|
-
token = tx.
|
|
59
|
+
token = tx.token_address
|
|
60
|
+
|
|
61
|
+
# Fees from single-sided strategies are not denominated in `vault.token` but everything else is
|
|
62
|
+
is_single_sided = _is_single_sided(tx)
|
|
52
63
|
|
|
53
64
|
for vault, underlying in v1.items():
|
|
54
|
-
|
|
55
|
-
if token != underlying and not _is_y3crv(tx) and not _is_ypool(tx):
|
|
65
|
+
if token != underlying and not is_single_sided:
|
|
56
66
|
continue
|
|
57
67
|
|
|
58
68
|
controller = await _get_controller(vault)
|
|
@@ -65,39 +75,41 @@ async def is_v1_vault_fees(tx: TreasuryTx) -> bool:
|
|
|
65
75
|
strategy: ChecksumAddress = await controller.strategies.coroutine(
|
|
66
76
|
underlying, block_identifier=tx.block
|
|
67
77
|
)
|
|
68
|
-
if tx.from_address
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return True
|
|
78
|
+
if tx.from_address == strategy:
|
|
79
|
+
return True
|
|
80
|
+
logger.debug(
|
|
81
|
+
"from address %s doesnt match strategy %s set on controller %s",
|
|
82
|
+
tx.from_address.address,
|
|
83
|
+
strategy,
|
|
84
|
+
controller,
|
|
85
|
+
)
|
|
77
86
|
return False
|
|
78
87
|
|
|
79
88
|
|
|
80
|
-
def is_inverse_fees_from_stash_contract(
|
|
89
|
+
def is_inverse_fees_from_stash_contract(
|
|
90
|
+
from_address: ChecksumAddress, to_nickname: str | None
|
|
91
|
+
) -> bool:
|
|
81
92
|
return (
|
|
82
|
-
|
|
83
|
-
and
|
|
93
|
+
from_address == "0xE376e8e8E3B0793CD61C6F1283bA18548b726C2e"
|
|
94
|
+
and to_nickname == "Token: Curve stETH Pool yVault"
|
|
84
95
|
)
|
|
85
96
|
|
|
86
97
|
|
|
87
|
-
# TODO: add Network param to SortRule
|
|
88
98
|
@fees("Vaults V2")
|
|
89
99
|
async def is_v2_vault_fees(tx: TreasuryTx) -> bool:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
)
|
|
96
|
-
|
|
100
|
+
token = tx.token_address
|
|
101
|
+
from_address = cast(ChecksumAddress, tx.from_address.address)
|
|
102
|
+
if (
|
|
103
|
+
from_address == token
|
|
104
|
+
and (vault := v2.get(from_address))
|
|
105
|
+
and tx.to_address == await vault.rewards.coroutine(block_identifier=tx.block)
|
|
106
|
+
):
|
|
107
|
+
return True
|
|
97
108
|
|
|
98
|
-
if is_inverse_fees_from_stash_contract(tx):
|
|
99
|
-
|
|
100
|
-
|
|
109
|
+
if is_inverse_fees_from_stash_contract(from_address, tx.to_nickname):
|
|
110
|
+
value_usd = cast(Decimal, tx.value_usd)
|
|
111
|
+
if value_usd > 0:
|
|
112
|
+
tx.value_usd = -value_usd
|
|
101
113
|
return True
|
|
102
114
|
|
|
103
115
|
return False
|
|
@@ -107,3 +119,54 @@ async def is_v2_vault_fees(tx: TreasuryTx) -> bool:
|
|
|
107
119
|
def is_v3_vault_fees(tx: TreasuryTx) -> bool:
|
|
108
120
|
# TODO: fill me in too
|
|
109
121
|
return False
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@fees("YearnFed", Network.Mainnet)
|
|
125
|
+
def is_yearn_fed_fees(tx: TreasuryTx) -> bool:
|
|
126
|
+
symbol = tx.symbol
|
|
127
|
+
from_address = tx.from_address
|
|
128
|
+
# New version
|
|
129
|
+
if (
|
|
130
|
+
symbol in ["yvCurve-DOLA-U", "CRV"]
|
|
131
|
+
and from_address == "0x64e4fC597C70B26102464B7F70B1F00C77352910"
|
|
132
|
+
):
|
|
133
|
+
return True
|
|
134
|
+
# Old versions
|
|
135
|
+
if symbol in ["yvCurve-DOLA-U", "yveCRV-DAO"] and from_address in [
|
|
136
|
+
"0x09F61718474e2FFB884f438275C0405E3D3559d3",
|
|
137
|
+
"0x7928becDda70755B9ABD5eE7c7D5E267F1412042",
|
|
138
|
+
]:
|
|
139
|
+
return True
|
|
140
|
+
if (
|
|
141
|
+
symbol == "INV"
|
|
142
|
+
and tx.from_nickname == "Inverse Treasury"
|
|
143
|
+
and tx.to_nickname == "ySwap Multisig"
|
|
144
|
+
):
|
|
145
|
+
return True
|
|
146
|
+
if (
|
|
147
|
+
from_address == "0x9D5Df30F475CEA915b1ed4C0CCa59255C897b61B"
|
|
148
|
+
and tx.to_nickname == "ySwap Multisig"
|
|
149
|
+
):
|
|
150
|
+
return True
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@fees("DOLAFRAXBP", Network.Mainnet)
|
|
155
|
+
def is_dolafraxbp_fees(tx: TreasuryTx) -> bool:
|
|
156
|
+
return (
|
|
157
|
+
tx.from_nickname == "Contract: StrategyConvexFraxBpRewardsClonable"
|
|
158
|
+
and tx.to_nickname == "Yearn yChad Multisig"
|
|
159
|
+
and tx.symbol == "yvCurve-DOLA-FRAXBP-U"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@fees("TempleDAO Private Vault", Network.Mainnet)
|
|
164
|
+
def is_temple(tx: TreasuryTx) -> bool:
|
|
165
|
+
if tx.to_nickname in ["Yearn Treasury", "Yearn yChad Multisig"]: # fees have been sent to both
|
|
166
|
+
from_nickname = tx.from_nickname
|
|
167
|
+
symbol = tx.symbol
|
|
168
|
+
if from_nickname == "Contract: StrategyConvexCrvCvxPairsClonable" and symbol == "CRV":
|
|
169
|
+
return True
|
|
170
|
+
elif from_nickname == "Contract: Splitter" and symbol in ["yveCRV-DAO", "CRV"]:
|
|
171
|
+
return True
|
|
172
|
+
return False
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Final
|
|
2
|
+
|
|
3
|
+
from dao_treasury import TreasuryTx, revenue
|
|
4
|
+
from y import Network
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
OXSPLIT_CONTRACT: Final = "0x2ed6c4B5dA6378c7897AC67Ba9e43102Feb694EE"
|
|
8
|
+
SPLITS_WAREHOUSE_CONTRACT: Final = "0x8fb66F38cF86A3d5e8768f8F1754A24A6c661Fb8"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@revenue("yTeam Rev Share", Network.Mainnet)
|
|
12
|
+
def is_yteam_rev_share(tx: TreasuryTx) -> bool:
|
|
13
|
+
return tx.from_address in [OXSPLIT_CONTRACT, SPLITS_WAREHOUSE_CONTRACT] or tx.hash in [
|
|
14
|
+
# These predate the split implementation and must be accounted for separately
|
|
15
|
+
# yAudit
|
|
16
|
+
"0x6e4f4405bd0970d42a48795a5219c14c763705f6ea9879affea652438758c065",
|
|
17
|
+
]
|
yearn_treasury/shitcoins.py
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
List of "shitcoins" (but like, actual shit shitcoins) to ignore in all
|
|
3
|
+
Yearn Treasury analytics.
|
|
4
|
+
|
|
5
|
+
This module defines, for each blockchain network, a set of token addresses
|
|
6
|
+
known to be unpricable, considered as spam, or otherwise unwanted for
|
|
7
|
+
reporting and analytics. These tokens are passed in to :mod:`eth-portfolio`,
|
|
8
|
+
which contains the logic that prevents these shitcoins from being included in
|
|
9
|
+
any Yearn Treasury outputs.
|
|
10
|
+
|
|
11
|
+
Since these tokens do nothing but add noise to the outputs, transactions
|
|
12
|
+
involving them are excluded from treasury calculations, reports, and dashboards.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from typing import Final
|
|
16
|
+
|
|
1
17
|
from y import Network, convert
|
|
2
18
|
from y.constants import CHAINID
|
|
3
19
|
|
|
4
20
|
|
|
5
|
-
_SHITCOINS = {
|
|
21
|
+
_SHITCOINS: Final = {
|
|
6
22
|
Network.Mainnet: (
|
|
7
23
|
"0xC36442b4a4522E871399CD717aBDD847Ab11FE88", # UNI-V3 NFT, not shitcoin but not pricable
|
|
8
24
|
"0x0329b631464C43f4e8132df7B4ac29a2D89FFdC7",
|
|
@@ -34,18 +50,93 @@ _SHITCOINS = {
|
|
|
34
50
|
"0xe5868468Cb6Dd5d6D7056bd93f084816c6eF075f",
|
|
35
51
|
"0x0a24Bb4842c301276c65086B5d78D5C872993c72",
|
|
36
52
|
"0x63125c0d5Cd9071de9A1ac84c400982f41C697AE",
|
|
53
|
+
"0x4d22921215cF37e8d49e2Ac6d1F5e9672f63A7c6",
|
|
54
|
+
"0xe2549E429B78458fa60BC7B1b284d4411E1D5105",
|
|
55
|
+
"0xCfdD747d041397bcE08B0Fe6ebF7Ef65E9F46795",
|
|
56
|
+
"0x9745969171a38B40db05c506fe2DA2C36f317627",
|
|
57
|
+
"0x6051C1354Ccc51b4d561e43b02735DEaE64768B8",
|
|
58
|
+
"0xf0814d0E47F2390a8082C4a1BD819FDDe50f9bFc",
|
|
59
|
+
"0x2DBd330bC9B7f3A822a9173aB52172BdDDcAcE2A",
|
|
60
|
+
# just andre tinkering
|
|
61
|
+
"0x5cB5e2d7Ab9Fd32021dF8F1D3E5269bD437Ec3Bf",
|
|
37
62
|
# these arent shitcoins per se but we can't price them and dont expect to in the future, lets save cpu cycles
|
|
38
63
|
"0x9d45DAb69f1309F1F55A7280b1f6a2699ec918E8", # yFamily NFT <3
|
|
39
64
|
"0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85", # ENS
|
|
40
65
|
"0xD057B63f5E69CF1B929b356b579Cba08D7688048", # vCOW
|
|
41
66
|
"0x4c1317326fD8EFDeBdBE5e1cd052010D97723bd6", # deprecated yCRV
|
|
42
67
|
"0x8a0889d47f9Aa0Fac1cC718ba34E26b867437880", # deprecated st-yCRV
|
|
68
|
+
"0x55a290f08Bb4CAe8DcF1Ea5635A3FCfd4Da60456", # BITTO
|
|
69
|
+
"0x4770F3186225b1A6879983BD88C669CA55463886", # 69XMins
|
|
70
|
+
"0x05bAdF8A8e7fE5b43fae112108E26f2f663Bf1a2", # INUNOMICS
|
|
71
|
+
"0x3EF9181c9b96BAAafb3717A553E808Ccc72be37D", # MEMEPEPE
|
|
72
|
+
"0x5D22c8b4E3c90ca633e1377e6ca280a395fc61C0", # XMEME
|
|
73
|
+
"0x57f19E7e1A9066a741f59484481C4D2E9150e9E2", # MOCO
|
|
74
|
+
"0xb092D8E13Ba50963D57bEcB17a037728D883D02d", # BABYLABUBU
|
|
75
|
+
"0x4E51960bd33A6edA71a8B24A76311834BD98DD9f", # AICC
|
|
76
|
+
"0xB85485421d8a41C4648AB80bE1A725fA6b5Bc86d", # MEGA
|
|
77
|
+
"0x46D0Fb47b1e91130D53498EbeE7A968e7e6599f9", # Ghibli
|
|
78
|
+
"0x4FbB350052Bca5417566f188eB2EBCE5b19BC964", # GRG
|
|
79
|
+
"0x1f6DEb07E1a19bAfF90EC4075447eeF6eb96c0BA", # BABYMANYU
|
|
80
|
+
"0xD10EFABA11A51237fa120b15153DD432958bbDE3", # JIFFPOM
|
|
81
|
+
"0xCd9594cd25ED2a166362b6F76c523da08c4Ef2e5", # ESTHER
|
|
82
|
+
"0x16B907b5d1208Ae6086dE983a5EF45E7890eF272", # JUNFOX
|
|
83
|
+
"0xdE56173463d6461001B0891bC90DB224965f5762", # MAGNUS
|
|
84
|
+
"0x922824A5b3B3D5f4485fF52F4Ab7Cba5eA491874", # POSEIDON
|
|
85
|
+
"0x84F7D2f6FB447Bb11d3E7Ce64D83e1c02c2F3078", # VIRTUAL
|
|
86
|
+
"0x5C6Ed14E1017cf75C237A4A4b93Ce1D2f83EB002", # GRVT
|
|
87
|
+
"0xf76E6eFf109258fd5F52823d9F9feE7c90C97251", # wkeyDAO
|
|
43
88
|
# test token?
|
|
44
89
|
"0x372d5d02c6b4075bd58892f80300cA590e92d29E", # tOUSG
|
|
45
90
|
# dETH? don't think this is needed
|
|
46
91
|
"0x3d1E5Cf16077F349e999d6b21A4f646e83Cd90c5",
|
|
92
|
+
# ai shitcoin spam
|
|
93
|
+
"0xaf80B7dbeBbb5d9a4d33C453FcbF3d054DA53b25", # NODEPAY AI
|
|
94
|
+
"0xf960AbF9ccC883970BEa3E79f65027E27278e1A5", # ASK AI
|
|
95
|
+
"0xc136Eb8Abc892723aE87F355d12Cb721C4324D54", # Grok3
|
|
96
|
+
"0xc68bCEE3604F163f183Cf8B9a26E610E5961b037", # TESLA AI
|
|
97
|
+
"0xa65D56f8e074E773142205cD065FD0796B9aa483", # MASSIVE AI
|
|
98
|
+
"0x4e6c80aa486aF0ba20943Fbc067a5557DBcf5458", # SUNO AI
|
|
99
|
+
"0xC91223F844772dCdc2c6394585C8c30B3c1BE5C0", # SEND AI
|
|
100
|
+
"0x64b3336D1aDC6D3579e356760F53D3b018Cb11Bc", # ALC AI
|
|
101
|
+
"0x1495Ac869433698cCD2946c1e62D37bA766294A9", # NVIDIA AI PC
|
|
102
|
+
"0x8c0DF275c38092cd90Ae4d6147d8e619B3A24637", # COLLE AI
|
|
103
|
+
"0xe38f71fc2Ca5f5761cE21F39Fff2cE70662FA54c", # CHAINOPERA AI
|
|
104
|
+
"0xD2F89F59fBC7125b406e3F60A992DFa9FdB76524", # MISTRAL AI
|
|
105
|
+
"0xa0CCdBCeB5Da30F9d62F7A727F2B35C69dF08760", # CHUNK AI
|
|
106
|
+
"0x7CE31075d7450Aff4A9a82DdDF69D451B1e0C4E9", # DEEPSEEK AI
|
|
107
|
+
"0xf0f9C021AF9B6431FA59DAB75C8e6cB80c0dEa37", # TESLA AI
|
|
108
|
+
"0x635eeC65a7Ef10dCF96Bfe051D8A6e5960efe180", # KLING AI
|
|
109
|
+
"0xa3Efa0929569c15c20f89B591931899Fb05B4663", # GPT-5
|
|
110
|
+
"0x0A953979fdCfD82B08C77dB29705327BeC39ff13", # GROK4 AI
|
|
111
|
+
"0xc83377b9eE3CEe4Cc03CCd58AfdE1FB12864aEE3", # E AI
|
|
112
|
+
"0x927402ab67c0CDA3c187E9DFE34554AC581441f2", # SAITABIT
|
|
113
|
+
"0x691539810DF6e879A377C24CfEE130BBE92708d8", # NVIDIA AI
|
|
114
|
+
"0xdC82aC0A89197854cb2240FaBF7E7760a4fF4d9e", # NVIDIA
|
|
115
|
+
"0x5Fba8ea5A559CF5c99BA6dd884Ae17C1d621fE5B", # OSCAR AI
|
|
116
|
+
"0x57b055656460055192c8EAf616F90Ab76a32CC20", # Openx
|
|
117
|
+
# matt furry spam
|
|
118
|
+
"0x73228b3D33cC71cB721Fc62950577bE63bd9c8C9", # Maskman by Matt Furie
|
|
119
|
+
"0x7c28e66436C93BB9F657dDF2BA0eeeCf61369b92", # Bloodboy by Matt Furie
|
|
120
|
+
"0x70c5e1124569f17B1Be71E15833EaF1331f8727F", # Pac-hat by Matt Furie
|
|
121
|
+
"0xBd6555eC87C8A9a2280dCD6df45b9b074fC93Df2", # Bork by Matt Furie
|
|
122
|
+
# test token
|
|
123
|
+
"0x2F375Ce83EE85e505150d24E85A1742fd03cA593", # TEST
|
|
47
124
|
),
|
|
48
125
|
}
|
|
126
|
+
"""
|
|
127
|
+
Mapping of blockchain networks to tuples of token addresses that should be
|
|
128
|
+
ignored in Yearn Treasury analytics. These tokens are considered unpricable,
|
|
129
|
+
spam, or otherwise unwanted for reporting and analytics purposes.
|
|
130
|
+
|
|
131
|
+
Each tuple contains token contract addresses that will be excluded from
|
|
132
|
+
treasury calculations, reports, and dashboards for the corresponding network.
|
|
133
|
+
"""
|
|
134
|
+
|
|
49
135
|
|
|
136
|
+
SHITCOINS: Final = {convert.to_address(shitcoin) for shitcoin in _SHITCOINS.get(CHAINID, ())} # type: ignore [call-overload]
|
|
137
|
+
"""Set of checksummed token addresses to ignore for the current chain.
|
|
50
138
|
|
|
51
|
-
|
|
139
|
+
This set is derived from the _SHITCOINS mapping for the current CHAINID,
|
|
140
|
+
and is used to filter out unpricable, spam, or otherwise unwanted tokens
|
|
141
|
+
from all Yearn Treasury analytics and reporting.
|
|
142
|
+
"""
|
|
Binary file
|
yearn_treasury/vaults.py
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
|
+
Vault discovery and tracking utilities for Yearn Treasury.
|
|
3
|
+
|
|
4
|
+
This module discovers Yearn vault contracts and maps them to their
|
|
5
|
+
underlying assets using Yearn's on-chain registry contracts. It
|
|
6
|
+
provides dictionaries for v1 and v2 vaults, supporting transaction
|
|
7
|
+
classification, analytics, and reporting across the Yearn Treasury
|
|
8
|
+
system.
|
|
9
|
+
|
|
10
|
+
Key Responsibilities:
|
|
11
|
+
- Discover and map all v1 and v2 vault contracts to underlying assets at startup.
|
|
12
|
+
- Provide lookup tables for use in vault deposit/withdrawal sort rules.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from typing import Dict, Final
|
|
2
16
|
|
|
3
17
|
from brownie import chain
|
|
4
18
|
from eth_typing import ChecksumAddress
|
|
@@ -7,36 +21,30 @@ from y import Contract, Events, Network
|
|
|
7
21
|
from yearn_treasury._ens import resolver, topics
|
|
8
22
|
|
|
9
23
|
|
|
24
|
+
v1: Final[Dict[Contract, ChecksumAddress]] = {}
|
|
25
|
+
"""Vault contract -> underlying address"""
|
|
26
|
+
|
|
27
|
+
v2: Final[Dict[ChecksumAddress, Contract]] = {}
|
|
28
|
+
"""Vault address -> vault contract"""
|
|
29
|
+
|
|
30
|
+
|
|
10
31
|
if chain.id == Network.Mainnet:
|
|
11
32
|
_v1_addresses_provider = Contract("0x9be19Ee7Bc4099D62737a7255f5c227fBcd6dB93")
|
|
12
33
|
_addresses_generator_v1_vaults = Contract(
|
|
13
34
|
_v1_addresses_provider.addressById("ADDRESSES_GENERATOR_V1_VAULTS")
|
|
14
35
|
)
|
|
15
36
|
|
|
16
|
-
|
|
17
|
-
vault
|
|
18
|
-
for vault in map(Contract, _addresses_generator_v1_vaults.assetsAddresses())
|
|
19
|
-
}
|
|
37
|
+
for vault in map(Contract, _addresses_generator_v1_vaults.assetsAddresses()):
|
|
38
|
+
v1[vault] = vault.token()
|
|
20
39
|
|
|
21
40
|
now = chain.height
|
|
22
41
|
|
|
42
|
+
# TODO: make resolve_ens util in eth-port and refactor this out
|
|
23
43
|
v2_registries = [
|
|
24
|
-
|
|
25
|
-
for event in Events( # type: ignore [attr-defined]
|
|
26
|
-
addresses=resolver, topics=topics
|
|
27
|
-
).events(now)
|
|
28
|
-
]
|
|
29
|
-
|
|
30
|
-
v2: List[Contract] = [
|
|
31
|
-
Contract(vault)
|
|
32
|
-
for vault in {
|
|
33
|
-
event["vault"]
|
|
34
|
-
for event in Events(addresses=list(map(str, v2_registries))).events(now)
|
|
35
|
-
if event.name == "NewVault"
|
|
36
|
-
}
|
|
44
|
+
event["newAddress"].hex() for event in Events(addresses=resolver, topics=topics).events(now)
|
|
37
45
|
]
|
|
38
46
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
for event in Events(addresses=list(map(str, v2_registries))).events(now):
|
|
48
|
+
if event.name == "NewVault":
|
|
49
|
+
vault_address = event["vault"]
|
|
50
|
+
v2[vault_address] = Contract(vault_address)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Treasury
|
|
2
|
+
"0x93A62dA5a14C80f265DAbC077fCEE437B1a0Efde":
|
|
3
|
+
networks:
|
|
4
|
+
- 1
|
|
5
|
+
"0x89716Ad7EDC3be3B35695789C475F3e7A3Deb12a":
|
|
6
|
+
networks:
|
|
7
|
+
- 250
|
|
8
|
+
|
|
9
|
+
# yChad
|
|
10
|
+
"0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52":
|
|
11
|
+
networks:
|
|
12
|
+
- 1
|
|
13
|
+
"0xC0E2830724C946a6748dDFE09753613cd38f6767":
|
|
14
|
+
networks:
|
|
15
|
+
- 250
|
|
16
|
+
|
|
17
|
+
# Yearn Treasury V1
|
|
18
|
+
"0xb99a40fcE04cb740EB79fC04976CA15aF69AaaaE":
|
|
19
|
+
networks:
|
|
20
|
+
- 1
|
|
21
|
+
|
|
22
|
+
# Yearn KP3R Wallet
|
|
23
|
+
"0x5f0845101857d2A91627478e302357860b1598a1":
|
|
24
|
+
|
|
25
|
+
# ySwap Multisig
|
|
26
|
+
"0x7d2aB9CA511EBD6F03971Fb417d3492aA82513f0":
|
|
27
|
+
|
|
28
|
+
# yMechs Multisig
|
|
29
|
+
"0x2C01B4AD51a67E2d8F02208F54dF9aC4c0B778B6":
|
|
30
|
+
end:
|
|
31
|
+
block:
|
|
32
|
+
1: 17162286
|
|
33
|
+
|
|
34
|
+
# Fee Reimbursement Stash
|
|
35
|
+
"0xE376e8e8E3B0793CD61C6F1283bA18548b726C2e":
|
|
36
|
+
|
|
37
|
+
# New token dumping wallet
|
|
38
|
+
"0xC001d00d425Fa92C4F840baA8f1e0c27c4297a0B":
|
|
39
|
+
|
|
40
|
+
# veFarming wallet
|
|
41
|
+
"0x4fc1b14cD213e7B6212145Ba4f180C3d53d1A11e":
|
|
42
|
+
|
|
43
|
+
### yRoboTreasury Wallets ###
|
|
44
|
+
# https://github.com/yearn/yRoboTreasury/blob/master/deployment.json
|
|
45
|
+
|
|
46
|
+
# Treasury
|
|
47
|
+
"0xEf77cc176c748d291EfB6CdC982c5744fC7211c8":
|
|
48
|
+
networks:
|
|
49
|
+
- 1
|
|
50
|
+
|
|
51
|
+
# Stables reserve
|
|
52
|
+
"0x278374fFb10B7D16E7633444c13e6E565EA57c28":
|
|
53
|
+
networks:
|
|
54
|
+
- 1
|
yearn_treasury/yteams.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# This is a loose copy of an old script and will not likely be refactored into something pretty
|
|
2
|
+
import os
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
from decimal import Decimal
|
|
5
|
+
from functools import lru_cache
|
|
6
|
+
from logging import getLogger
|
|
7
|
+
from typing import Any, Dict, Final, List, Set, Tuple
|
|
8
|
+
|
|
9
|
+
import a_sync
|
|
10
|
+
from brownie import chain
|
|
11
|
+
from eth_portfolio.structs import TokenTransfer
|
|
12
|
+
from eth_portfolio._ydb.token_transfers import InboundTokenTransfers
|
|
13
|
+
from pandas import DataFrame, MultiIndex
|
|
14
|
+
from y import Contract, Network, get_block_at_timestamp
|
|
15
|
+
from y.exceptions import ContractNotVerified
|
|
16
|
+
|
|
17
|
+
from yearn_treasury.constants import ZERO_ADDRESS
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
DATA_FOLDER: Final = os.path.join(".", "data")
|
|
21
|
+
OUTPUT_FILE: Final = os.path.join(DATA_FOLDER, f"teams_revenue_{chain.id}.csv")
|
|
22
|
+
NUMBER_OF_MONTHS_TO_INCLUDE_IN_REPORT: Final = 36
|
|
23
|
+
|
|
24
|
+
if not os.path.exists(DATA_FOLDER):
|
|
25
|
+
os.makedirs(DATA_FOLDER)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# TODO: maybe move this into constants for reuse
|
|
29
|
+
yteams_addresses = {
|
|
30
|
+
Network.Mainnet: {
|
|
31
|
+
"v3": {
|
|
32
|
+
"ms": "0x33333333D5eFb92f19a5F94a43456b3cec2797AE",
|
|
33
|
+
"splits": {"0x2A12CAA2c13Af03c117D836CA3811a5Ca946133B": 12.5},
|
|
34
|
+
},
|
|
35
|
+
"dinobots": {
|
|
36
|
+
"ms": "0x2C01B4AD51a67E2d8F02208F54dF9aC4c0B778B6",
|
|
37
|
+
"splits": {"0xC4f238633A85A854C4702d2c66264771D1fa7904": 17.5},
|
|
38
|
+
},
|
|
39
|
+
"ylockers": {
|
|
40
|
+
"ms": "0x4444AAAACDBa5580282365e25b16309Bd770ce4a",
|
|
41
|
+
"splits": {
|
|
42
|
+
"0xac580302548FCCBBf00020de20C3A8AA516821AD": 2.5,
|
|
43
|
+
"0x794f80E899c772de9E326eC83cCfD8D94e208B49": 6.25,
|
|
44
|
+
"0x5FF0f87b05806ce89967638CA727Af8309d92A89": 12.5,
|
|
45
|
+
"0x5A7575368797695BefD785f546C6b8B7e9D37f8c": 15.625,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
# "ylockers others": {"ms": "0x4444AAAACDBa5580282365e25b16309Bd770ce4a","splits":{"0x5FF0f87b05806ce89967638CA727Af8309d92A89":12.5, "0x5A7575368797695BefD785f546C6b8B7e9D37f8c":15.625}},
|
|
49
|
+
"yaudit": {
|
|
50
|
+
"ms": "0x8973B848775a87a0D5bcf262C555859b87E6F7dA",
|
|
51
|
+
"splits": {
|
|
52
|
+
"0xd7A1DBe236A38528D54317415a530b2326068373": 35,
|
|
53
|
+
"0xF104F38592287e25868BD8C3dcCCa1a311916f88": 35,
|
|
54
|
+
"0x1a9D272C3b7fE427639702A332D51348213B0bC1": 20,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
"yeth": {
|
|
58
|
+
"ms": "0xeEEEEeeeEe274C3CCe13f77C85d8eBd9F7fd4479",
|
|
59
|
+
"splits": {"0x14EFe6390C6758E3fE4379A14e3B329274b1b072": 25},
|
|
60
|
+
},
|
|
61
|
+
"yfarm": {
|
|
62
|
+
"ms": "0x55157997cb324a374cCd7c40914ff879Fd9D515C",
|
|
63
|
+
"splits": {"0x0B3cCe59E038373F6008D9266B6D6eB4d21689b1": 50},
|
|
64
|
+
},
|
|
65
|
+
"sms": {
|
|
66
|
+
"ms": "0x16388463d60FFE0661Cf7F1f31a7D658aC790ff7",
|
|
67
|
+
"splits": {"0xd6748776CF06a80EbE36cd83D325B31bb916bf54": 25},
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
}[Network(chain.id)]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
logger: Final = getLogger(__name__)
|
|
74
|
+
|
|
75
|
+
_not_verified: Final[Set[str]] = set()
|
|
76
|
+
_warned: Final[Set[TokenTransfer]] = set()
|
|
77
|
+
|
|
78
|
+
_known_tokens_without_prices: Final = frozenset({"SAFE", "vCOW"})
|
|
79
|
+
"""When there is a PriceError for these tokens, no logs will be emitted."""
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@lru_cache(maxsize=None)
|
|
83
|
+
def transfers_for(wallet: str) -> InboundTokenTransfers:
|
|
84
|
+
return InboundTokenTransfers(wallet, 0, load_prices=True) # type: ignore [arg-type]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
async def calculate_teams_revenue_expenses() -> None:
|
|
88
|
+
logger.info("Starting process to calculate teams revenues and expenses")
|
|
89
|
+
timestamps = get_timestamps_for_report()
|
|
90
|
+
|
|
91
|
+
async def get_coros_for_timestamp(dt: datetime) -> Dict[str, Dict[str, Decimal]]:
|
|
92
|
+
return await a_sync.gather(
|
|
93
|
+
{
|
|
94
|
+
label: total(label, wallet_info, dt)
|
|
95
|
+
for label, wallet_info in yteams_addresses.items()
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
all_data = await a_sync.gather({dt: get_coros_for_timestamp(dt) for dt in timestamps})
|
|
100
|
+
|
|
101
|
+
result = {
|
|
102
|
+
(dt, teams, movement): values
|
|
103
|
+
for dt, data in all_data.items()
|
|
104
|
+
for teams, info in data.items()
|
|
105
|
+
for movement, values in info.items()
|
|
106
|
+
}
|
|
107
|
+
df = DataFrame.from_dict(result, orient="index")
|
|
108
|
+
print("------------")
|
|
109
|
+
# print(df.index)
|
|
110
|
+
# print(df.head(10))
|
|
111
|
+
df.index = MultiIndex.from_tuples(df.index)
|
|
112
|
+
print("********")
|
|
113
|
+
# print(df.index)
|
|
114
|
+
df.reset_index(inplace=True)
|
|
115
|
+
df.columns = ["datetime", "team", "label", "value"]
|
|
116
|
+
df.to_csv(OUTPUT_FILE)
|
|
117
|
+
logger.info(
|
|
118
|
+
f"Finished processing yteams calculations and saved file to {os.path.abspath(OUTPUT_FILE)}"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def get_timestamps_for_report() -> List[datetime]:
|
|
123
|
+
now = datetime.now(tz=timezone.utc)
|
|
124
|
+
prev_month_end = datetime(
|
|
125
|
+
year=now.year,
|
|
126
|
+
month=now.month,
|
|
127
|
+
day=1,
|
|
128
|
+
hour=0,
|
|
129
|
+
minute=0,
|
|
130
|
+
second=0,
|
|
131
|
+
microsecond=0,
|
|
132
|
+
tzinfo=timezone.utc,
|
|
133
|
+
) - timedelta(microseconds=1)
|
|
134
|
+
datetimes = []
|
|
135
|
+
print("Exporting report for timestamps:")
|
|
136
|
+
for _ in range(NUMBER_OF_MONTHS_TO_INCLUDE_IN_REPORT):
|
|
137
|
+
print(f" - {prev_month_end}")
|
|
138
|
+
datetimes.append(prev_month_end)
|
|
139
|
+
prev_month_end -= timedelta(days=prev_month_end.day)
|
|
140
|
+
return datetimes
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
async def total(label: str, wallet_info: Dict[str, Any], timestamp: datetime) -> Dict[str, Decimal]:
|
|
144
|
+
rev = await sum_revenue_transfers.sum(wallet_info["splits"].items(), timestamp=timestamp)
|
|
145
|
+
grants = await sum_grants_received(wallet_info["ms"], timestamp)
|
|
146
|
+
if rev > 10_000_000:
|
|
147
|
+
raise ValueError(rev)
|
|
148
|
+
if grants > 10_000_000:
|
|
149
|
+
raise ValueError(grants)
|
|
150
|
+
net = rev - grants
|
|
151
|
+
if label == "yaudit":
|
|
152
|
+
logger.info("--- %s thru %s ---", label, timestamp)
|
|
153
|
+
logger.info("inbound %s", rev)
|
|
154
|
+
logger.info("grants -%s", grants)
|
|
155
|
+
logger.info("net %s", net)
|
|
156
|
+
return {"revenue": rev, "grants": grants, "total": net}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@a_sync.a_sync(default="async")
|
|
160
|
+
async def sum_revenue_transfers(params: Tuple[str, Decimal], timestamp: datetime) -> Decimal:
|
|
161
|
+
wallet, rev_share = params
|
|
162
|
+
block = await get_block_at_timestamp(timestamp)
|
|
163
|
+
total = Decimal(0)
|
|
164
|
+
async for transfer in transfers_for(wallet).yield_thru_block(block):
|
|
165
|
+
transfer = await transfer
|
|
166
|
+
if transfer is None:
|
|
167
|
+
# failed to decode, probably shitcoin
|
|
168
|
+
continue
|
|
169
|
+
if not transfer.value:
|
|
170
|
+
# zero value transfer
|
|
171
|
+
continue
|
|
172
|
+
if transfer.price:
|
|
173
|
+
total += transfer.value * transfer.price
|
|
174
|
+
elif transfer not in _warned and transfer.token not in _known_tokens_without_prices:
|
|
175
|
+
logger.warning(f"BAD: {transfer}")
|
|
176
|
+
_warned.add(transfer)
|
|
177
|
+
return round(total * Decimal((100 - rev_share) / 100), 8)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
async def sum_grants_received(wallet: str, timestamp: datetime) -> Decimal:
|
|
181
|
+
grants = Decimal(0)
|
|
182
|
+
block = await get_block_at_timestamp(timestamp)
|
|
183
|
+
async for transfer in transfers_for(wallet).yield_thru_block(block):
|
|
184
|
+
transfer = await transfer
|
|
185
|
+
if transfer is None:
|
|
186
|
+
# failed to decode, probably shitcoin
|
|
187
|
+
continue
|
|
188
|
+
if not transfer.value:
|
|
189
|
+
# zero value transfer
|
|
190
|
+
continue
|
|
191
|
+
if transfer.price:
|
|
192
|
+
if transfer.from_address != ZERO_ADDRESS:
|
|
193
|
+
try:
|
|
194
|
+
contract = await Contract.coroutine(transfer.from_address)
|
|
195
|
+
if (
|
|
196
|
+
hasattr(contract, "recipient") and await contract.recipient == wallet
|
|
197
|
+
) or transfer.from_address == "0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52":
|
|
198
|
+
grants += transfer.value * transfer.price
|
|
199
|
+
except ContractNotVerified as e:
|
|
200
|
+
if str(e) not in _not_verified:
|
|
201
|
+
_not_verified.add(str(e))
|
|
202
|
+
logger.debug(f"{e.__class__.__name__}: {e}")
|
|
203
|
+
except Exception as e:
|
|
204
|
+
logger.warning(f"{e.__class__.__name__}: {e}")
|
|
205
|
+
elif transfer not in _warned and transfer.token not in _known_tokens_without_prices:
|
|
206
|
+
logger.warning(f"BAD: {transfer}")
|
|
207
|
+
_warned.add(transfer)
|
|
208
|
+
return round(grants, 8)
|