yearn-treasury 0.1.6__cp312-cp312-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 (128) hide show
  1. yearn_treasury/__init__.py +20 -0
  2. yearn_treasury/_db.cp312-win32.pyd +0 -0
  3. yearn_treasury/_db.py +51 -0
  4. yearn_treasury/_ens.cp312-win32.pyd +0 -0
  5. yearn_treasury/_ens.py +31 -0
  6. yearn_treasury/_logging.cp312-win32.pyd +0 -0
  7. yearn_treasury/_logging.py +43 -0
  8. yearn_treasury/address_labels.yaml +39 -0
  9. yearn_treasury/budget/__init__.cp312-win32.pyd +0 -0
  10. yearn_treasury/budget/__init__.py +6 -0
  11. yearn_treasury/budget/_request.cp312-win32.pyd +0 -0
  12. yearn_treasury/budget/_request.py +44 -0
  13. yearn_treasury/budget/_requests.cp312-win32.pyd +0 -0
  14. yearn_treasury/budget/_requests.py +96 -0
  15. yearn_treasury/constants.py +92 -0
  16. yearn_treasury/main.py +176 -0
  17. yearn_treasury/py.typed +1 -0
  18. yearn_treasury/rules/__init__.py +20 -0
  19. yearn_treasury/rules/constants.cp312-win32.pyd +0 -0
  20. yearn_treasury/rules/constants.py +17 -0
  21. yearn_treasury/rules/cost_of_revenue/__init__.py +1 -0
  22. yearn_treasury/rules/cost_of_revenue/gas.cp312-win32.pyd +0 -0
  23. yearn_treasury/rules/cost_of_revenue/gas.py +66 -0
  24. yearn_treasury/rules/cost_of_revenue/match_on_hash.yaml +12 -0
  25. yearn_treasury/rules/expense/__init__.cp312-win32.pyd +0 -0
  26. yearn_treasury/rules/expense/__init__.py +4 -0
  27. yearn_treasury/rules/expense/general.cp312-win32.pyd +0 -0
  28. yearn_treasury/rules/expense/general.py +13 -0
  29. yearn_treasury/rules/expense/infrastructure.cp312-win32.pyd +0 -0
  30. yearn_treasury/rules/expense/infrastructure.py +47 -0
  31. yearn_treasury/rules/expense/match_on_hash.yaml +48 -0
  32. yearn_treasury/rules/expense/match_on_to_address.yaml +7 -0
  33. yearn_treasury/rules/expense/people.cp312-win32.pyd +0 -0
  34. yearn_treasury/rules/expense/people.py +84 -0
  35. yearn_treasury/rules/expense/security.cp312-win32.pyd +0 -0
  36. yearn_treasury/rules/expense/security.py +147 -0
  37. yearn_treasury/rules/ignore/__init__.py +8 -0
  38. yearn_treasury/rules/ignore/general.cp312-win32.pyd +0 -0
  39. yearn_treasury/rules/ignore/general.py +11 -0
  40. yearn_treasury/rules/ignore/maker.py +92 -0
  41. yearn_treasury/rules/ignore/passthru.py +310 -0
  42. yearn_treasury/rules/ignore/staking.py +102 -0
  43. yearn_treasury/rules/ignore/swaps/__init__.py +25 -0
  44. yearn_treasury/rules/ignore/swaps/_skip_tokens.py +9 -0
  45. yearn_treasury/rules/ignore/swaps/aave.py +69 -0
  46. yearn_treasury/rules/ignore/swaps/auctions.cp312-win32.pyd +0 -0
  47. yearn_treasury/rules/ignore/swaps/auctions.py +31 -0
  48. yearn_treasury/rules/ignore/swaps/compound.py +58 -0
  49. yearn_treasury/rules/ignore/swaps/conversion_factory.cp312-win32.pyd +0 -0
  50. yearn_treasury/rules/ignore/swaps/conversion_factory.py +21 -0
  51. yearn_treasury/rules/ignore/swaps/cowswap.py +87 -0
  52. yearn_treasury/rules/ignore/swaps/curve.py +176 -0
  53. yearn_treasury/rules/ignore/swaps/gearbox.cp312-win32.pyd +0 -0
  54. yearn_treasury/rules/ignore/swaps/gearbox.py +37 -0
  55. yearn_treasury/rules/ignore/swaps/iearn.cp312-win32.pyd +0 -0
  56. yearn_treasury/rules/ignore/swaps/iearn.py +43 -0
  57. yearn_treasury/rules/ignore/swaps/otc.cp312-win32.pyd +0 -0
  58. yearn_treasury/rules/ignore/swaps/otc.py +58 -0
  59. yearn_treasury/rules/ignore/swaps/pooltogether.cp312-win32.pyd +0 -0
  60. yearn_treasury/rules/ignore/swaps/pooltogether.py +23 -0
  61. yearn_treasury/rules/ignore/swaps/synthetix.cp312-win32.pyd +0 -0
  62. yearn_treasury/rules/ignore/swaps/synthetix.py +10 -0
  63. yearn_treasury/rules/ignore/swaps/uniswap.py +294 -0
  64. yearn_treasury/rules/ignore/swaps/unwrapper.cp312-win32.pyd +0 -0
  65. yearn_treasury/rules/ignore/swaps/unwrapper.py +17 -0
  66. yearn_treasury/rules/ignore/swaps/vaults.cp312-win32.pyd +0 -0
  67. yearn_treasury/rules/ignore/swaps/vaults.py +264 -0
  68. yearn_treasury/rules/ignore/swaps/woofy.cp312-win32.pyd +0 -0
  69. yearn_treasury/rules/ignore/swaps/woofy.py +80 -0
  70. yearn_treasury/rules/ignore/swaps/yfi.cp312-win32.pyd +0 -0
  71. yearn_treasury/rules/ignore/swaps/yfi.py +111 -0
  72. yearn_treasury/rules/ignore/swaps/yla.cp312-win32.pyd +0 -0
  73. yearn_treasury/rules/ignore/swaps/yla.py +28 -0
  74. yearn_treasury/rules/ignore/unit.cp312-win32.pyd +0 -0
  75. yearn_treasury/rules/ignore/unit.py +40 -0
  76. yearn_treasury/rules/ignore/weth.cp312-win32.pyd +0 -0
  77. yearn_treasury/rules/ignore/weth.py +48 -0
  78. yearn_treasury/rules/ignore/ygov.cp312-win32.pyd +0 -0
  79. yearn_treasury/rules/ignore/ygov.py +16 -0
  80. yearn_treasury/rules/other_expense/__init__.cp312-win32.pyd +0 -0
  81. yearn_treasury/rules/other_expense/__init__.py +7 -0
  82. yearn_treasury/rules/other_expense/boost.cp312-win32.pyd +0 -0
  83. yearn_treasury/rules/other_expense/boost.py +49 -0
  84. yearn_treasury/rules/other_expense/bugs.cp312-win32.pyd +0 -0
  85. yearn_treasury/rules/other_expense/bugs.py +81 -0
  86. yearn_treasury/rules/other_expense/donations.cp312-win32.pyd +0 -0
  87. yearn_treasury/rules/other_expense/donations.py +43 -0
  88. yearn_treasury/rules/other_expense/dyfi.cp312-win32.pyd +0 -0
  89. yearn_treasury/rules/other_expense/dyfi.py +29 -0
  90. yearn_treasury/rules/other_expense/events.cp312-win32.pyd +0 -0
  91. yearn_treasury/rules/other_expense/events.py +21 -0
  92. yearn_treasury/rules/other_expense/match_on_hash.yaml +43 -0
  93. yearn_treasury/rules/other_expense/match_on_to_address.yaml +8 -0
  94. yearn_treasury/rules/other_expense/misc.cp312-win32.pyd +0 -0
  95. yearn_treasury/rules/other_expense/misc.py +49 -0
  96. yearn_treasury/rules/other_expense/revshare.cp312-win32.pyd +0 -0
  97. yearn_treasury/rules/other_expense/revshare.py +20 -0
  98. yearn_treasury/rules/other_income/__init__.cp312-win32.pyd +0 -0
  99. yearn_treasury/rules/other_income/__init__.py +2 -0
  100. yearn_treasury/rules/other_income/airdrops.cp312-win32.pyd +0 -0
  101. yearn_treasury/rules/other_income/airdrops.py +30 -0
  102. yearn_treasury/rules/other_income/match_on_hash.yaml +21 -0
  103. yearn_treasury/rules/other_income/misc.cp312-win32.pyd +0 -0
  104. yearn_treasury/rules/other_income/misc.py +80 -0
  105. yearn_treasury/rules/revenue/__init__.py +6 -0
  106. yearn_treasury/rules/revenue/bribes.cp312-win32.pyd +0 -0
  107. yearn_treasury/rules/revenue/bribes.py +26 -0
  108. yearn_treasury/rules/revenue/farming.cp312-win32.pyd +0 -0
  109. yearn_treasury/rules/revenue/farming.py +56 -0
  110. yearn_treasury/rules/revenue/keepcoins.cp312-win32.pyd +0 -0
  111. yearn_treasury/rules/revenue/keepcoins.py +63 -0
  112. yearn_treasury/rules/revenue/match_on_hash.yaml +4 -0
  113. yearn_treasury/rules/revenue/seasolver.cp312-win32.pyd +0 -0
  114. yearn_treasury/rules/revenue/seasolver.py +23 -0
  115. yearn_treasury/rules/revenue/vaults.py +172 -0
  116. yearn_treasury/rules/revenue/yteams.cp312-win32.pyd +0 -0
  117. yearn_treasury/rules/revenue/yteams.py +17 -0
  118. yearn_treasury/shitcoins.py +144 -0
  119. yearn_treasury/vaults.cp312-win32.pyd +0 -0
  120. yearn_treasury/vaults.py +50 -0
  121. yearn_treasury/wallets.yaml +54 -0
  122. yearn_treasury/yteams.py +208 -0
  123. yearn_treasury-0.1.6.dist-info/METADATA +85 -0
  124. yearn_treasury-0.1.6.dist-info/RECORD +128 -0
  125. yearn_treasury-0.1.6.dist-info/WHEEL +5 -0
  126. yearn_treasury-0.1.6.dist-info/entry_points.txt +2 -0
  127. yearn_treasury-0.1.6.dist-info/top_level.txt +2 -0
  128. yearn_treasury__mypyc.cp312-win32.pyd +0 -0
@@ -0,0 +1,30 @@
1
+ from typing import Final
2
+
3
+ from dao_treasury import TreasuryTx, other_income
4
+ from y import Network
5
+
6
+
7
+ airdrop: Final = other_income("Airdrop")
8
+
9
+ _SAFE_AIRDROP_CONTRACTS: Final = (
10
+ "0xA0b937D5c8E32a80E3a8ed4227CD020221544ee6",
11
+ "0xC0fde70A65C7569Fe919bE57492228DEE8cDb585",
12
+ )
13
+
14
+
15
+ @airdrop("SAFE", Network.Mainnet)
16
+ def is_safe_airdrop(tx: TreasuryTx) -> bool:
17
+ return tx.symbol == "SAFE" and tx.from_address.address in _SAFE_AIRDROP_CONTRACTS # type: ignore [union-attr]
18
+
19
+
20
+ @airdrop("Other", Network.Mainnet)
21
+ def is_airdrop(tx: TreasuryTx) -> bool:
22
+ return tx.hash in {
23
+ "0x327684dab9e3ce61d125b36fe0b59cbfbc8aa5ac7a5b051125ab7cac3b93b90b",
24
+ "0x44f7d3b2030799ea45932baf6049528a059aabd6387f3128993d646d01c8e877", # TKX
25
+ "0xf2dbe58dffd3bc1476755e9f74e2ae07531579d0a3ea9e2aaac2ef902e080c2a", # TKX
26
+ "0x8079e9cae847da196dc5507561bc9d1434f765f05045bc1a82df735ec83bc6ec", # MTV
27
+ # NOTE: this one was rec'd elsewhere, dumped, and WETH sent to treasury
28
+ "0xc12ded505ea158717890e4ae6e7ab5eb5cb61edbc13dfd125dd0e6f9b1af9477", # Gnosis SAFE airdrop
29
+ "0x7c086a82b43b2f49db93b76a0698cf86a9c620b3bf924f0003175b04a17455ad", # PRISMA
30
+ }
@@ -0,0 +1,21 @@
1
+ 1:
2
+ YFI Mint:
3
+ - "0x21a3007a2547a9d6f1bceb44cb9292b36079fcccd8f36f7ec1ca066db261e153"
4
+ yvUSDN Shutdown:
5
+ # The USDN vault was shut down but the pool was so rekt they coulnd't even swap for want. Trace amounts of yield sent to yChad.
6
+ - "0x12b3687f4bfbc73c11dccbd61d18c3f785e6f0f91cb46280d7df08143162ceed"
7
+ Portals Fees:
8
+ - "0x7181e4956fde34580be7ebecc6b4b60ad06676b5bb88598a2d35706995bf1289"
9
+ - "0x3fd8a5995bfe7aa6bb4f502e4bd7e93f491c12f6a72f39644d2809a6eab8b57d"
10
+ Lido Grant:
11
+ - "0x2193a2e98487894a30fc1fc9b913ac7a59e14f47ab72b0b53a02aede7d919795"
12
+ - "0x64d9e139ac2b1738f4e3c1b1c2f979fc90544c9b9eed5cc8bcd960c73fc19ac8"
13
+ Tessaract Refund:
14
+ - "0xe1558686856dc43ca9797f9fd7113151e51fc69be35f36db3555b9cefd74399a"
15
+ Dust from Positive Slippage:
16
+ - "0x084d318cc42ea80c19e2c9c321f60b3d6d67274a38eb1c1a58cf0fe4093e9ef8"
17
+ Other:
18
+ # Some tokens showed up and nobody knew where they came from. Lucky Yearn.
19
+ - "0x5be236c49e5c5481fc9169dbdd5759cb1542d5d8fe047083ecf2403584468e1a"
20
+ - "0x6fde3ebcdd3e4e176d3138a976a2382fe15e71922d0b9740f04d0a7be3d4d30f"
21
+ - "0xbd2a33818b9e755c78c159de5863e2a153164f526d12cfacc773139841d1e594"
@@ -0,0 +1,80 @@
1
+ # mypy: disable-error-code="union-attr"
2
+ from decimal import Decimal
3
+ from typing import Final, Optional
4
+
5
+ from dao_treasury import TreasuryTx, other_income
6
+ from y import Contract, ContractNotVerified, ERC20, Network # type: ignore [attr-defined]
7
+
8
+ from yearn_treasury.rules.constants import ZERO_ADDRESS
9
+
10
+
11
+ _POINT_ONE: Final = Decimal("0.1")
12
+
13
+
14
+ @other_income("aToken Yield", Network.Mainnet)
15
+ def is_atoken_yield(tx: TreasuryTx) -> bool:
16
+ return (
17
+ tx.symbol in ("aLEND", "aLINK")
18
+ and tx.from_address.address == ZERO_ADDRESS
19
+ and tx.to_nickname in ("Yearn Treasury", "Yearn Treasury V1")
20
+ )
21
+
22
+
23
+ @other_income("RoboVault Thank You", Network.Fantom)
24
+ async def is_robovault_share(tx: TreasuryTx) -> bool:
25
+ """
26
+ After Yearn devs helped robovault with a vulnerability, robovault committed to sending Yearn a portion of their fees.
27
+ """
28
+ if not tx.symbol.startswith("rv") and tx.from_address.is_contract:
29
+ return False
30
+
31
+ try:
32
+ strat = await tx.from_address.contract_coro
33
+ except ContractNotVerified:
34
+ return False
35
+ else:
36
+ vault: Optional[Contract] = getattr(strat, "vault", None)
37
+
38
+ if vault is None:
39
+ return False
40
+
41
+ if await vault.coroutine(block_identifier=tx.block) == tx.token:
42
+ return True
43
+
44
+ return (
45
+ tx.from_nickname == "Contract: Strategy"
46
+ and tx.symbol == "rv3USDCc"
47
+ and await ERC20( # type: ignore [call-overload]
48
+ await vault.coroutine(block_identifier=tx.block),
49
+ asynchronous=True,
50
+ ).symbol
51
+ == "rv3USDCb"
52
+ )
53
+
54
+
55
+ @other_income("Cowswap Gas Reimbursement", Network.Mainnet)
56
+ def is_cowswap_gas_reimbursement(tx: TreasuryTx) -> bool:
57
+ return (
58
+ tx.symbol == "ETH"
59
+ and tx.from_nickname == "Cowswap Multisig"
60
+ and tx.to_nickname == "yMechs Multisig"
61
+ )
62
+
63
+
64
+ @other_income("USDS Referral Code", Network.Mainnet)
65
+ def is_usds_referral_code(tx: TreasuryTx) -> bool:
66
+ """Yearn earns some USDS for referring deposits to Maker"""
67
+ return (
68
+ tx.symbol == "USDS"
69
+ and tx.from_address.address == "0x3C5142F28567E6a0F172fd0BaaF1f2847f49D02F"
70
+ )
71
+
72
+
73
+ @other_income("yETH Application Fee", Network.Mainnet)
74
+ def is_yeth_application_fee(tx: TreasuryTx) -> bool:
75
+ return tx.symbol == "yETH" and tx.to_nickname == "Yearn Treasury" and tx.amount == _POINT_ONE
76
+
77
+
78
+ @other_income("yPRISMA Fees", Network.Mainnet)
79
+ def is_yprisma_fees(tx: TreasuryTx) -> bool:
80
+ return tx.symbol == "yvmkUSD-A" and tx.from_nickname == "Contract: YPrismaFeeDistributor"
@@ -0,0 +1,6 @@
1
+ from yearn_treasury.rules.revenue.bribes import *
2
+ from yearn_treasury.rules.revenue.farming import *
3
+ from yearn_treasury.rules.revenue.keepcoins import *
4
+ from yearn_treasury.rules.revenue.seasolver import *
5
+ from yearn_treasury.rules.revenue.vaults import *
6
+ from yearn_treasury.rules.revenue.yteams import *
@@ -0,0 +1,26 @@
1
+ from typing import Final
2
+
3
+ from dao_treasury import TreasuryTx, revenue
4
+
5
+
6
+ bribes: Final = revenue("Bribes")
7
+
8
+
9
+ @bribes("yCRV Bribes")
10
+ def is_ycrv_bribe(tx: TreasuryTx) -> bool:
11
+ return (
12
+ tx.from_nickname
13
+ in [
14
+ # OLD
15
+ "Contract: BribeSplitter",
16
+ # NEW
17
+ "Contract: YCRVSplitter",
18
+ # done manually during migration
19
+ ]
20
+ or tx.hash == "0x3c635388812bed82845c0df3531583399fdf736ccfb95837b362379766955f2d"
21
+ )
22
+
23
+
24
+ @bribes("yBribe Fees")
25
+ def is_ybribe_fees(tx: TreasuryTx) -> bool:
26
+ return False
@@ -0,0 +1,56 @@
1
+ from typing import Final
2
+
3
+ from dao_treasury import TreasuryTx, revenue
4
+ from y import Contract, Network
5
+
6
+ from yearn_treasury.rules.constants import ZERO_ADDRESS
7
+
8
+
9
+ farming: Final = revenue("Treasury Farming")
10
+
11
+
12
+ @farming("COMP Farming", Network.Mainnet)
13
+ async def is_comp_rewards(tx: TreasuryTx) -> bool:
14
+ return tx.symbol == "COMP" and await _is_generic_comp_rewards(tx)
15
+
16
+
17
+ @farming("SCREAM Farming", Network.Fantom)
18
+ async def is_scream_rewards(tx: TreasuryTx) -> bool:
19
+ return tx.symbol == "SCREAM" and await _is_generic_comp_rewards(tx)
20
+
21
+
22
+ @farming("SEX Farming", Network.Fantom)
23
+ def is_sex(tx: TreasuryTx) -> bool:
24
+ return tx.symbol == "SEX" and tx.from_address in (
25
+ ZERO_ADDRESS,
26
+ "0x7FcE87e203501C3a035CbBc5f0Ee72661976D6E1", # StakingRewards
27
+ )
28
+
29
+
30
+ @farming("SOLID Farming", Network.Fantom)
31
+ def is_solid(tx: TreasuryTx) -> bool:
32
+ return tx.symbol == "SOLID" and tx.from_address in (
33
+ "0x7FcE87e203501C3a035CbBc5f0Ee72661976D6E1", # StakingRewards
34
+ "0x26E1A0d851CF28E697870e1b7F053B605C8b060F", # LpDepositor
35
+ )
36
+
37
+
38
+ @farming("SOLIDsex Farming", Network.Fantom)
39
+ def is_solidsex(tx: TreasuryTx) -> bool:
40
+ return tx.symbol == "SOLIDsex" and tx.from_address in (
41
+ "0x7FcE87e203501C3a035CbBc5f0Ee72661976D6E1", # StakingRewards
42
+ "0xA5e76B97e12567bbA2e822aC68842097034C55e7", # FeeDistributor
43
+ )
44
+
45
+
46
+ async def _is_generic_comp_rewards(tx: TreasuryTx) -> bool:
47
+ for event in tx.get_events("DistributedSupplierComp"):
48
+ if (
49
+ tx.from_address == event.address
50
+ and "supplier" in event
51
+ and tx.to_address == event["supplier"]
52
+ ):
53
+ troller = await Contract.coroutine(event.address)
54
+ if hasattr(troller, "getCompAddress") and tx.token == await troller.getCompAddress:
55
+ return True
56
+ return False
@@ -0,0 +1,63 @@
1
+ # keepCOINS: excludes keepCRV as the CRV are locked forever.
2
+ from typing import Final, Tuple
3
+
4
+ from y import Network
5
+ from y.constants import CHAINID
6
+
7
+ from dao_treasury import TreasuryTx, revenue
8
+
9
+
10
+ keepcoins: Final = revenue("keepCOINS")
11
+
12
+ angle_strats_with_non_specific_names: Final[Tuple[str, ...]] = { # type: ignore [call-overload]
13
+ Network.Mainnet: (
14
+ "0x2CB390212b0e5091a3c0D0331669c1419165CF80",
15
+ "0x7C2b9DB2Ae5aCC6fAC2Fd6cE9b01A5EB4bDD1309",
16
+ ),
17
+ }.get(CHAINID, ())
18
+
19
+
20
+ @keepcoins("KeepANGLE")
21
+ def is_keep_angle(tx: TreasuryTx) -> bool:
22
+ return tx.symbol == "ANGLE" and (
23
+ tx.from_nickname == "Contract: StrategyAngleUSDC"
24
+ or tx.from_address in angle_strats_with_non_specific_names
25
+ )
26
+
27
+
28
+ @keepcoins("KeepBAL")
29
+ def is_keep_bal(tx: TreasuryTx) -> bool:
30
+ # This particular tx is pass-thru
31
+ if (
32
+ tx.symbol != "BAL"
33
+ or tx.hash == "0xf4677cce1a08ecd54272cdc1b23bc64693450f8bb5d6de59b8e58e288ec3b2a7"
34
+ ):
35
+ return False
36
+
37
+ return tx.from_nickname in [
38
+ "Contract: SSBv3 DAI staBAL3",
39
+ "Contract: SSBv3 USDC staBAL3",
40
+ "Contract: SSBv3 USDT staBAL3",
41
+ "Contract: SSBv3 WETH B-stETH-STABLE",
42
+ "Contract: SSBv3 WBTC staBAL3-BTC",
43
+ ] or tx.from_address in [
44
+ # Contract: Strategy (unhelpful name, we can use address though)
45
+ "0x960818b3F08dADca90b840298721FE7B419fBE12",
46
+ "0x074620e389B5715f7ba51Fc062D8fFaf973c7E02",
47
+ "0xB0F8b341951233BF08A5F15a838A1a85B016aEf9",
48
+ "0x034d775615d50D870D742caA1e539fC8d97955c2",
49
+ "0xe614f717b3e8273f38Ed7e0536DfBA60AD021c85",
50
+ ]
51
+
52
+
53
+ @keepcoins("KeepBEETS")
54
+ def is_keep_beets(tx: TreasuryTx) -> bool:
55
+ return (
56
+ tx.symbol == "BEETS"
57
+ and tx.hash != "0x1e997aa8c79ece76face8deb8fe7df4cea4f6a1ef7cd28501013ed30dfbe238f"
58
+ )
59
+
60
+
61
+ @keepcoins("KeepPOOL")
62
+ def is_keep_pool(tx: TreasuryTx) -> bool:
63
+ return tx.symbol == "POOL" and tx.from_nickname == "Contract: StrategyPoolTogether"
@@ -0,0 +1,4 @@
1
+ 1:
2
+ Dinobots:
3
+ - "0xf1ce47dc8a44fc37ffc580960f22bbe23896cf31bb0484f0cd5d23fc53c4d5fe"
4
+ - "0xa09e8ed14967023a672d332eb620204b20d63c574bc1b7575fc710cdfb794271"
@@ -0,0 +1,23 @@
1
+ from typing import Final
2
+ from dao_treasury import TreasuryTx, revenue
3
+ from y import Network
4
+
5
+
6
+ seasolver: Final = revenue("Seasolver", Network.Mainnet)
7
+
8
+
9
+ @seasolver("Positive Slippage")
10
+ def is_seasolver_slippage_revenue(tx: TreasuryTx) -> bool:
11
+ # TODO: check this earlier, probably in dao-treasury internals
12
+ # After may 1 2023 ymechs wallet separated from yearn treasury
13
+ return (
14
+ tx.block <= 17162286
15
+ and tx.from_nickname == "Contract: TradeHandler"
16
+ and tx.to_nickname == "yMechs Multisig"
17
+ )
18
+
19
+
20
+ @seasolver("CowSwap Incentives")
21
+ def is_cowswap_incentive(tx: TreasuryTx) -> bool:
22
+ """Incentives for swapping on CowSwap"""
23
+ return tx.symbol == "COW" and tx.from_address == "0xA03be496e67Ec29bC62F01a428683D7F9c204930"
@@ -0,0 +1,172 @@
1
+ from decimal import Decimal
2
+ from logging import getLogger
3
+ from typing import Final, Optional, cast
4
+
5
+ from dao_treasury import TreasuryTx, revenue
6
+ from eth_typing import ChecksumAddress
7
+ from faster_async_lru import alru_cache
8
+ from y import Contract, Network
9
+
10
+ from yearn_treasury.vaults import v1, v2
11
+
12
+
13
+ logger: Final = getLogger(__name__)
14
+
15
+ fees: Final = revenue("Fees")
16
+
17
+
18
+ # v1 helpers
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:
27
+ return (
28
+ symbol == "y3Crv"
29
+ and from_nickname.startswith("Contract: Strategy")
30
+ and from_nickname.endswith("3pool")
31
+ )
32
+
33
+
34
+ def _is_ypool(symbol: str, from_nickname: str) -> bool:
35
+ return (
36
+ symbol == "yyDAI+yUSDC+yUSDT+yTUSD"
37
+ and from_nickname.startswith("Contract: Strategy")
38
+ and from_nickname.endswith("ypool")
39
+ )
40
+
41
+
42
+ @alru_cache(maxsize=1000)
43
+ async def _get_rewards(controller: Contract, block: int) -> Optional[ChecksumAddress]:
44
+ try:
45
+ return await controller.rewards.coroutine(block_identifier=block) # type: ignore [no-any-return]
46
+ except ValueError as e:
47
+ if str(e) == "No data was returned - the call likely reverted":
48
+ return None
49
+ raise
50
+
51
+
52
+ @alru_cache(maxsize=None)
53
+ async def _get_controller(vault: Contract) -> Contract:
54
+ return await Contract.coroutine(await vault.controller) # type: ignore [return-value]
55
+
56
+
57
+ @fees("Vaults V1", Network.Mainnet)
58
+ async def is_v1_vault_fees(tx: TreasuryTx) -> bool:
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)
63
+
64
+ for vault, underlying in v1.items():
65
+ if token != underlying and not is_single_sided:
66
+ continue
67
+
68
+ controller = await _get_controller(vault)
69
+ rewards = await _get_rewards(controller, tx.block)
70
+ if tx.to_address != rewards:
71
+ logger.debug(
72
+ "to address %s doesnt match rewards address %s", tx.to_address.address, rewards
73
+ )
74
+ continue
75
+ strategy: ChecksumAddress = await controller.strategies.coroutine(
76
+ underlying, block_identifier=tx.block
77
+ )
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
+ )
86
+ return False
87
+
88
+
89
+ def is_inverse_fees_from_stash_contract(
90
+ from_address: ChecksumAddress, to_nickname: str | None
91
+ ) -> bool:
92
+ return (
93
+ from_address == "0xE376e8e8E3B0793CD61C6F1283bA18548b726C2e"
94
+ and to_nickname == "Token: Curve stETH Pool yVault"
95
+ )
96
+
97
+
98
+ @fees("Vaults V2")
99
+ async def is_v2_vault_fees(tx: TreasuryTx) -> bool:
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
108
+
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
113
+ return True
114
+
115
+ return False
116
+
117
+
118
+ @fees("Vaults V3")
119
+ def is_v3_vault_fees(tx: TreasuryTx) -> bool:
120
+ # TODO: fill me in too
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
@@ -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
+ ]
@@ -0,0 +1,144 @@
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
+
17
+ from y import Network, convert
18
+ from y.constants import CHAINID
19
+
20
+
21
+ _SHITCOINS: Final = {
22
+ Network.Mainnet: (
23
+ "0xC36442b4a4522E871399CD717aBDD847Ab11FE88", # UNI-V3 NFT, not shitcoin but not pricable
24
+ "0x0329b631464C43f4e8132df7B4ac29a2D89FFdC7",
25
+ "0xa191021599f60E2fDE1bc8c8d1a07e9BD663c4a9",
26
+ "0xD1E5b0FF1287aA9f9A268759062E4Ab08b9Dacbe", # .crypto domain NFT
27
+ "0x0B39Bb088f03b0baeA1AAC64AaEAb85E714c76e2",
28
+ "0x6cC759B8cE30e719511B6a897CfE449A19f64a92",
29
+ "0xD7aBCFd05a9ba3ACbc164624402fB2E95eC41be6",
30
+ "0xeaaa790591c646b0436f02f63e8Ca56209FEDE4E",
31
+ "0x1e988ba4692e52Bc50b375bcC8585b95c48AaD77",
32
+ "0xeF81c2C98cb9718003A89908e6bd1a5fA8A098A3",
33
+ "0x174Cd3359C6a4E6B64D2995Da4E2E4631379526E",
34
+ "0x1d41cf24dF81E3134319BC11c308c5589A486166",
35
+ "0x437a6B880d4b3Be9ed93BD66D6B7f872fc0f5b5E",
36
+ "0x53fFFB19BAcD44b82e204d036D579E86097E5D09",
37
+ "0x9694EED198C1b7aB81ADdaf36255Ea58acf13Fab",
38
+ "0x1AbBaC88B8F47D46a3d822eFA75F64A15C25966f",
39
+ "0x195EC13Ef52c30CEb4019A055e7938DAfAE21B6a",
40
+ "0xde32436e18c6946ED3559B925e3340Bf6D80B67A",
41
+ "0x2Fe158f89F32C9C5E6C7082487DBB26e42071512",
42
+ "0x9017201ae20f0940dB37723Cd704e80BcaA1347c",
43
+ "0x5C3509b1BeB81aC9621AEd482a77038Ef1fD1f5D",
44
+ "0x34D0f1Cb08D47dC1333657A0A84Df2462e806656",
45
+ "0x799dc7a6017BC623A4fef6828FA49b5661ed53fb",
46
+ "0xA00C7A61BcBb3F0ABCafACD149A3008A153b2DAb",
47
+ "0x11068577AE36897fFaB0024F010247B9129459E6",
48
+ "0x57b9d10157f66D8C00a815B5E289a152DeDBE7ed",
49
+ "0x01234567bac6fF94d7E4f0EE23119CF848F93245",
50
+ "0xe5868468Cb6Dd5d6D7056bd93f084816c6eF075f",
51
+ "0x0a24Bb4842c301276c65086B5d78D5C872993c72",
52
+ "0x63125c0d5Cd9071de9A1ac84c400982f41C697AE",
53
+ "0x4d22921215cF37e8d49e2Ac6d1F5e9672f63A7c6",
54
+ "0xe2549E429B78458fa60BC7B1b284d4411E1D5105",
55
+ "0xCfdD747d041397bcE08B0Fe6ebF7Ef65E9F46795",
56
+ "0x9745969171a38B40db05c506fe2DA2C36f317627",
57
+ "0x6051C1354Ccc51b4d561e43b02735DEaE64768B8",
58
+ "0xf0814d0E47F2390a8082C4a1BD819FDDe50f9bFc",
59
+ "0x2DBd330bC9B7f3A822a9173aB52172BdDDcAcE2A",
60
+ "0x1368452Bfb5Cd127971C8DE22C58fBE89D35A6BF", # JNTR/e
61
+ # just andre tinkering
62
+ "0x5cB5e2d7Ab9Fd32021dF8F1D3E5269bD437Ec3Bf",
63
+ # these arent shitcoins per se but we can't price them and dont expect to in the future, lets save cpu cycles
64
+ "0x9d45DAb69f1309F1F55A7280b1f6a2699ec918E8", # yFamily NFT <3
65
+ "0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85", # ENS
66
+ "0xD057B63f5E69CF1B929b356b579Cba08D7688048", # vCOW
67
+ "0x4c1317326fD8EFDeBdBE5e1cd052010D97723bd6", # deprecated yCRV
68
+ "0x8a0889d47f9Aa0Fac1cC718ba34E26b867437880", # deprecated st-yCRV
69
+ "0x55a290f08Bb4CAe8DcF1Ea5635A3FCfd4Da60456", # BITTO
70
+ "0x4770F3186225b1A6879983BD88C669CA55463886", # 69XMins
71
+ "0x05bAdF8A8e7fE5b43fae112108E26f2f663Bf1a2", # INUNOMICS
72
+ "0x3EF9181c9b96BAAafb3717A553E808Ccc72be37D", # MEMEPEPE
73
+ "0x5D22c8b4E3c90ca633e1377e6ca280a395fc61C0", # XMEME
74
+ "0x57f19E7e1A9066a741f59484481C4D2E9150e9E2", # MOCO
75
+ "0xb092D8E13Ba50963D57bEcB17a037728D883D02d", # BABYLABUBU
76
+ "0x4E51960bd33A6edA71a8B24A76311834BD98DD9f", # AICC
77
+ "0xB85485421d8a41C4648AB80bE1A725fA6b5Bc86d", # MEGA
78
+ "0x46D0Fb47b1e91130D53498EbeE7A968e7e6599f9", # Ghibli
79
+ "0x4FbB350052Bca5417566f188eB2EBCE5b19BC964", # GRG
80
+ "0x1f6DEb07E1a19bAfF90EC4075447eeF6eb96c0BA", # BABYMANYU
81
+ "0xD10EFABA11A51237fa120b15153DD432958bbDE3", # JIFFPOM
82
+ "0xCd9594cd25ED2a166362b6F76c523da08c4Ef2e5", # ESTHER
83
+ "0x16B907b5d1208Ae6086dE983a5EF45E7890eF272", # JUNFOX
84
+ "0xdE56173463d6461001B0891bC90DB224965f5762", # MAGNUS
85
+ "0x922824A5b3B3D5f4485fF52F4Ab7Cba5eA491874", # POSEIDON
86
+ "0x84F7D2f6FB447Bb11d3E7Ce64D83e1c02c2F3078", # VIRTUAL
87
+ "0x5C6Ed14E1017cf75C237A4A4b93Ce1D2f83EB002", # GRVT
88
+ "0xf76E6eFf109258fd5F52823d9F9feE7c90C97251", # wkeyDAO
89
+ "0x1BA4b447d0dF64DA64024e5Ec47dA94458C1e97f", # Hegic V8888 Options Token
90
+ # test token?
91
+ "0x372d5d02c6b4075bd58892f80300cA590e92d29E", # tOUSG
92
+ # dETH? don't think this is needed
93
+ "0x3d1E5Cf16077F349e999d6b21A4f646e83Cd90c5",
94
+ # ai shitcoin spam
95
+ "0xaf80B7dbeBbb5d9a4d33C453FcbF3d054DA53b25", # NODEPAY AI
96
+ "0xf960AbF9ccC883970BEa3E79f65027E27278e1A5", # ASK AI
97
+ "0xc136Eb8Abc892723aE87F355d12Cb721C4324D54", # Grok3
98
+ "0xc68bCEE3604F163f183Cf8B9a26E610E5961b037", # TESLA AI
99
+ "0xa65D56f8e074E773142205cD065FD0796B9aa483", # MASSIVE AI
100
+ "0x4e6c80aa486aF0ba20943Fbc067a5557DBcf5458", # SUNO AI
101
+ "0xC91223F844772dCdc2c6394585C8c30B3c1BE5C0", # SEND AI
102
+ "0x64b3336D1aDC6D3579e356760F53D3b018Cb11Bc", # ALC AI
103
+ "0x1495Ac869433698cCD2946c1e62D37bA766294A9", # NVIDIA AI PC
104
+ "0x8c0DF275c38092cd90Ae4d6147d8e619B3A24637", # COLLE AI
105
+ "0xe38f71fc2Ca5f5761cE21F39Fff2cE70662FA54c", # CHAINOPERA AI
106
+ "0xD2F89F59fBC7125b406e3F60A992DFa9FdB76524", # MISTRAL AI
107
+ "0xa0CCdBCeB5Da30F9d62F7A727F2B35C69dF08760", # CHUNK AI
108
+ "0x7CE31075d7450Aff4A9a82DdDF69D451B1e0C4E9", # DEEPSEEK AI
109
+ "0xf0f9C021AF9B6431FA59DAB75C8e6cB80c0dEa37", # TESLA AI
110
+ "0x635eeC65a7Ef10dCF96Bfe051D8A6e5960efe180", # KLING AI
111
+ "0xa3Efa0929569c15c20f89B591931899Fb05B4663", # GPT-5
112
+ "0x0A953979fdCfD82B08C77dB29705327BeC39ff13", # GROK4 AI
113
+ "0xc83377b9eE3CEe4Cc03CCd58AfdE1FB12864aEE3", # E AI
114
+ "0x927402ab67c0CDA3c187E9DFE34554AC581441f2", # SAITABIT
115
+ "0x691539810DF6e879A377C24CfEE130BBE92708d8", # NVIDIA AI
116
+ "0xdC82aC0A89197854cb2240FaBF7E7760a4fF4d9e", # NVIDIA
117
+ "0x5Fba8ea5A559CF5c99BA6dd884Ae17C1d621fE5B", # OSCAR AI
118
+ "0x57b055656460055192c8EAf616F90Ab76a32CC20", # Openx
119
+ # matt furry spam
120
+ "0x73228b3D33cC71cB721Fc62950577bE63bd9c8C9", # Maskman by Matt Furie
121
+ "0x7c28e66436C93BB9F657dDF2BA0eeeCf61369b92", # Bloodboy by Matt Furie
122
+ "0x70c5e1124569f17B1Be71E15833EaF1331f8727F", # Pac-hat by Matt Furie
123
+ "0xBd6555eC87C8A9a2280dCD6df45b9b074fC93Df2", # Bork by Matt Furie
124
+ # test token
125
+ "0x2F375Ce83EE85e505150d24E85A1742fd03cA593", # TEST
126
+ ),
127
+ }
128
+ """
129
+ Mapping of blockchain networks to tuples of token addresses that should be
130
+ ignored in Yearn Treasury analytics. These tokens are considered unpricable,
131
+ spam, or otherwise unwanted for reporting and analytics purposes.
132
+
133
+ Each tuple contains token contract addresses that will be excluded from
134
+ treasury calculations, reports, and dashboards for the corresponding network.
135
+ """
136
+
137
+
138
+ SHITCOINS: Final = {convert.to_address(shitcoin) for shitcoin in _SHITCOINS.get(CHAINID, ())} # type: ignore [call-overload]
139
+ """Set of checksummed token addresses to ignore for the current chain.
140
+
141
+ This set is derived from the _SHITCOINS mapping for the current CHAINID,
142
+ and is used to filter out unpricable, spam, or otherwise unwanted tokens
143
+ from all Yearn Treasury analytics and reporting.
144
+ """
Binary file