Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Amortize streams #400

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions yearn/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

from yearn.networks import Network

YFI = {
Network.Mainnet: "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e",
}.get(chain.id, None)

WRAPPED_GAS_COIN = {
Network.Mainnet: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
Network.Fantom: "0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83",
Expand Down
306 changes: 281 additions & 25 deletions yearn/entities.py

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion yearn/middleware/middleware.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from http.client import NETWORK_AUTHENTICATION_REQUIRED
import logging

import eth_retry
Expand Down
1 change: 0 additions & 1 deletion yearn/treasury/accountant/expenses/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

if chain.id == Network.Mainnet:
team = expenses_txgroup.create_child("Team Payments", people.is_team_payment)
team.create_child("Replenish Streams", people.is_stream_replenishment)

expenses_txgroup.create_child("Coordinape", people.is_coordinape)
expenses_txgroup.create_child("The 0.03%", people.is_0_03_percent)
Expand Down
13 changes: 0 additions & 13 deletions yearn/treasury/accountant/expenses/people.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,6 @@ def is_team_payment(tx: TreasuryTx) -> bool:
if tx.hash == '0x91656eb3246a560498e808cbfb00af0518ec12f50effda42fc1496d0b0fb080a' and tx.log_index == 421:
return False

llamapay_hashes = [
"0xd268946b6937df798e965a98b3f9348f7fc8519a2df9ba124210e4ce6c3fecaf",
"0x9d8fc48fe2f552a424fa2e4fa35f2ddbe73eb9f1eae33bb3b7b27466b8dbb62f",
"0x7979a77ab8a30bc6cd12e1df92e5ba0478a8907caf6e100317b7968668d0d4a2",
"0x91656eb3246a560498e808cbfb00af0518ec12f50effda42fc1496d0b0fb080a",
"0x16c193b8891af35ec811ebe8416f25addc0c4ffe39e074b5820577f1d8be72ec",
]

zerox_splits_hashes = [
"0x38dbe0e943d978483439d4dec9e29f71fc4690e790261661ef3b2d179dee26b9"
]
Expand All @@ -51,8 +43,6 @@ def is_team_payment(tx: TreasuryTx) -> bool:
return True
elif tx in HashMatcher(disperse_app_hashes) and tx._from_nickname == 'Disperse.app':
return True
elif tx in HashMatcher(llamapay_hashes) and tx._to_nickname == "Contract: LlamaPay":
return True
elif tx in HashMatcher(zerox_splits_hashes) and tx._to_nickname == "Non-Verified Contract: 0x426eF4C1d57b4772BcBE23979f4bbb236c135e1C":
return True
return False
Expand Down Expand Up @@ -110,9 +100,6 @@ def is_other_grant(tx: TreasuryTx) -> bool:
return tx in HashMatcher(disperse_hashes)
return tx in HashMatcher(hashes)

def is_stream_replenishment(tx: TreasuryTx) -> bool:
pass

def is_0_03_percent(tx: TreasuryTx) -> bool:
return tx in HashMatcher([["0xe56521d79b0b87425e90c08ed3da5b4fa3329a40fe31597798806db07f68494e", Filter('_from_nickname', 'Disperse.app')]])

Expand Down
1 change: 1 addition & 0 deletions yearn/treasury/accountant/ignore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ def is_keep_crv(tx: TreasuryTx) -> bool:
ignore_txgroup.create_child("Transfer to yGov (Deprecated)", ygov.is_sent_to_ygov)
ignore_txgroup.create_child("Maker CDP Deposit", maker.is_yfi_cdp_deposit)
ignore_txgroup.create_child("Maker CDP Withdrawal", maker.is_yfi_cdp_withdrawal)
ignore_txgroup.create_child("Replenish Streams", general.is_stream_replenishment)
elif chain.id == Network.Fantom:
ignore_txgroup.create_child("OTCTrader", general.is_otc_trader)

Expand Down
3 changes: 3 additions & 0 deletions yearn/treasury/accountant/ignore/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ def is_weth(tx: TreasuryTx) -> bool:
if tx.from_address.address == constants.weth and tx.to_address and tx.to_address.address in treasury.addresses and tx.token.address.address == "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE":
return True

def is_stream_replenishment(tx: TreasuryTx) -> bool:
return tx._to_nickname == "Contract: LlamaPay"

def is_scam_airdrop(tx: TreasuryTx) -> bool:
hashes = {
Network.Mainnet: [
Expand Down
5 changes: 5 additions & 0 deletions yearn/treasury/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
from yearn.networks import Network
from yearn.prices.constants import weth

# The buyback contract
BUYER = {
Network.Mainnet: "0x6903223578806940bd3ff0C51f87aa43968424c8",
}.get(chain.id, None)

YFI_LIKE = {
Network.Mainnet: {
'0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e', # YFI
Expand Down
104 changes: 104 additions & 0 deletions yearn/treasury/streams.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@

from typing import List, Optional

from brownie import chain
from pony.orm import db_session, select
from yearn.constants import YCHAD_MULTISIG, YFI
from yearn.entities import Stream, Token, TxGroup
from yearn.events import decode_logs, get_logs_asap
from yearn.outputs.postgres.utils import cache_token
from yearn.treasury.constants import BUYER
from yearn.utils import contract

dai = "0x6B175474E89094C44Da98b954EedeAC495271d0F"

streams_dai = contract('0x60c7B0c5B3a4Dc8C690b074727a17fF7aA287Ff2')
streams_yfi = contract('0xf3764eC89B1ad20A31ed633b1466363FAc1741c4')

class YearnStreams:
def __init__(self):
assert chain.id == 1
self.stream_contracts = [streams_dai, streams_yfi]
self.skipped_events = ["PayerDeposit", "Withdraw"]
self.handled_events = ["StreamCreated", "StreamModified", "StreamPaused", "StreamCancelled"]
self.get_streams()

def __getitem__(self, key: str):
if isinstance(key, bytes):
key = key.hex()
return Stream[key]

def streams_for_recipient(self, recipient: str, at_block: Optional[int] = None) -> List[Stream]:
if at_block is None:
return list(select(s for s in Stream if s.to_address.address == recipient))
return list(select(s for s in Stream if s.to_address.address == recipient and (s.end_block is None or at_block <= s.end_block)))

def streams_for_token(self, token: Token, include_inactive: bool = False) -> List[Stream]:
if not isinstance(token, Token):
token = cache_token(token)
streams = list(select(s for s in Stream if s.token == token))
if include_inactive is False:
streams = [s for s in streams if s.is_alive]
return streams

def buyback_streams(self, include_inactive: bool = False) -> List[Stream]:
streams = self.streams_for_recipient(BUYER)
if include_inactive is False:
streams = [s for s in streams if s.is_alive]
return streams

@db_session
def dai_streams(self, include_inactive: bool = False) -> List[Stream]:
return self.streams_for_token(dai, include_inactive=include_inactive)

@db_session
def yfi_streams(self, include_inactive: bool = False) -> List[Stream]:
return self.streams_for_token(YFI, include_inactive=include_inactive)

@db_session
def streams(self, include_inactive: bool = False):
if include_inactive is True:
return list(select(s for s in Stream))
return list(select(s for s in Stream if s.is_alive))

@db_session
def get_streams(self):
for stream_contract in self.stream_contracts:
logs = decode_logs(get_logs_asap([stream_contract.address]))

for k in logs.keys():
if k not in self.handled_events and k not in self.skipped_events:
raise NotImplementedError(f"We need to build handling for {k} events.")

for log in logs['StreamCreated']:
from_address, *_ = log.values()
if from_address != YCHAD_MULTISIG:
continue
Stream.get_or_create_entity(log)

for log in logs['StreamModified']:
from_address, _, _, old_stream_id, *_ = log.values()
if from_address != YCHAD_MULTISIG:
continue
self[old_stream_id].stop_stream(log.block_number)
Stream.get_or_create_entity(log)

if 'StreamPaused' in logs:
for log in logs['StreamPaused']:
from_address, *_, stream_id = log.values()
if from_address != YCHAD_MULTISIG:
continue
self[stream_id].pause(log.block_number)

if 'StreamCancelled' in logs:
for log in logs['StreamCancelled']:
from_address, *_, stream_id = log.values()
if from_address != YCHAD_MULTISIG:
continue
self[stream_id].stop_stream(log.block_number)

team_payments_txgroup = TxGroup.get(name = "Team Payments")
for stream in self.yfi_streams(include_inactive=True):
for stream in self.streams_for_recipient(stream.to_address.address):
if stream.txgroup is None:
stream.txgroup = team_payments_txgroup