dao-treasury 0.0.29__cp312-cp312-musllinux_1_2_i686.whl → 0.0.31__cp312-cp312-musllinux_1_2_i686.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.
- 17ebe61b88bd37338d0a__mypyc.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/.grafana/provisioning/dashboards/dashboards.yaml +8 -0
- dao_treasury/.grafana/provisioning/dashboards/streams/LlamaPay.json +116 -0
- dao_treasury/.grafana/provisioning/dashboards/treasury/Cashflow.json +22 -22
- dao_treasury/_docker.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/_docker.py +23 -18
- dao_treasury/_nicknames.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/_wallet.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/constants.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/db.py +172 -16
- dao_treasury/docker-compose.yaml +1 -0
- dao_treasury/main.py +27 -3
- dao_treasury/sorting/__init__.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/sorting/__init__.py +1 -0
- dao_treasury/sorting/_matchers.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/sorting/_rules.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/sorting/factory.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/sorting/rule.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/sorting/rule.py +5 -0
- dao_treasury/sorting/rules/__init__.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/sorting/rules/__init__.py +1 -0
- dao_treasury/sorting/rules/ignore/__init__.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/sorting/rules/ignore/__init__.py +1 -0
- dao_treasury/sorting/rules/ignore/llamapay.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/sorting/rules/ignore/llamapay.py +20 -0
- dao_treasury/streams/__init__.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/streams/__init__.py +0 -0
- dao_treasury/streams/llamapay.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury/streams/llamapay.py +363 -0
- dao_treasury/treasury.py +25 -4
- dao_treasury/types.cpython-312-i386-linux-musl.so +0 -0
- {dao_treasury-0.0.29.dist-info → dao_treasury-0.0.31.dist-info}/METADATA +37 -5
- dao_treasury-0.0.31.dist-info/RECORD +49 -0
- dao_treasury-0.0.31.dist-info/top_level.txt +2 -0
- 8d7637a0eb7617042369__mypyc.cpython-312-i386-linux-musl.so +0 -0
- dao_treasury-0.0.29.dist-info/RECORD +0 -37
- dao_treasury-0.0.29.dist-info/top_level.txt +0 -2
- {dao_treasury-0.0.29.dist-info → dao_treasury-0.0.31.dist-info}/WHEEL +0 -0
dao_treasury/db.py
CHANGED
@@ -8,6 +8,7 @@ This module defines Pony ORM entities for:
|
|
8
8
|
- ERC-20 tokens and native coin placeholder (:class:`Token`)
|
9
9
|
- Hierarchical transaction grouping (:class:`TxGroup`)
|
10
10
|
- Treasury transaction records (:class:`TreasuryTx`)
|
11
|
+
- Streams and StreamedFunds for streaming payments
|
11
12
|
|
12
13
|
It also provides helper functions for inserting ledger entries,
|
13
14
|
resolving integrity conflicts, caching transaction receipts,
|
@@ -21,15 +22,16 @@ from functools import lru_cache
|
|
21
22
|
from logging import getLogger
|
22
23
|
from os import path
|
23
24
|
from pathlib import Path
|
24
|
-
from typing import TYPE_CHECKING, Dict, Final, Union, final
|
25
|
+
from typing import TYPE_CHECKING, Dict, Final, Tuple, Union, final
|
26
|
+
from datetime import date, datetime, time, timezone
|
25
27
|
|
26
|
-
from a_sync import AsyncThreadPoolExecutor
|
28
|
+
from a_sync import AsyncThreadPoolExecutor
|
27
29
|
from brownie import chain
|
28
30
|
from brownie.convert.datatypes import HexString
|
29
31
|
from brownie.exceptions import EventLookupError
|
30
32
|
from brownie.network.event import EventDict, _EventItem
|
31
33
|
from brownie.network.transaction import TransactionReceipt
|
32
|
-
from eth_typing import ChecksumAddress, HexAddress
|
34
|
+
from eth_typing import ChecksumAddress, HexAddress, HexStr
|
33
35
|
from eth_portfolio.structs import (
|
34
36
|
InternalTransfer,
|
35
37
|
LedgerEntry,
|
@@ -68,6 +70,7 @@ _INSERT_THREAD = AsyncThreadPoolExecutor(1)
|
|
68
70
|
_SORT_THREAD = AsyncThreadPoolExecutor(1)
|
69
71
|
_SORT_SEMAPHORE = Semaphore(50)
|
70
72
|
|
73
|
+
_UTC = timezone.utc
|
71
74
|
|
72
75
|
db = Database()
|
73
76
|
|
@@ -210,9 +213,10 @@ class Address(DbEntity):
|
|
210
213
|
|
211
214
|
treasury_tx_to = Set("TreasuryTx", reverse="to_address")
|
212
215
|
"""Inverse relation for transactions sent to this address."""
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
+
|
217
|
+
streams_from = Set("Stream", reverse="from_address")
|
218
|
+
streams_to = Set("Stream", reverse="to_address")
|
219
|
+
streams = Set("Stream", reverse="contract")
|
216
220
|
# vesting_escrows = Set("VestingEscrow", reverse="address")
|
217
221
|
# vests_received = Set("VestingEscrow", reverse="recipient")
|
218
222
|
# vests_funded = Set("VestingEscrow", reverse="funder")
|
@@ -226,6 +230,10 @@ class Address(DbEntity):
|
|
226
230
|
|
227
231
|
__hash__ = DbEntity.__hash__
|
228
232
|
|
233
|
+
@property
|
234
|
+
def contract(self) -> Contract:
|
235
|
+
return Contract(self.address)
|
236
|
+
|
229
237
|
@staticmethod
|
230
238
|
@lru_cache(maxsize=None)
|
231
239
|
def get_dbid(address: HexAddress) -> int:
|
@@ -380,7 +388,8 @@ class Token(DbEntity):
|
|
380
388
|
|
381
389
|
address = Required(Address, column="address_id")
|
382
390
|
"""Foreign key to the address record for this token contract."""
|
383
|
-
|
391
|
+
|
392
|
+
streams = Set("Stream", reverse="token")
|
384
393
|
# vesting_escrows = Set("VestingEscrow", reverse="token")
|
385
394
|
|
386
395
|
def __eq__(self, other: Union["Token", Address, ChecksumAddress]) -> bool: # type: ignore [override]
|
@@ -534,8 +543,10 @@ class TxGroup(DbEntity):
|
|
534
543
|
|
535
544
|
child_txgroups = Set("TxGroup", reverse="parent_txgroup")
|
536
545
|
"""Set of nested child groups."""
|
537
|
-
|
538
|
-
|
546
|
+
|
547
|
+
streams = Set("Stream", reverse="txgroup")
|
548
|
+
|
549
|
+
# TODO: implement this
|
539
550
|
# vesting_escrows = Set("VestingEscrow", reverse="txgroup")
|
540
551
|
|
541
552
|
@property
|
@@ -896,6 +907,151 @@ class TreasuryTx(DbEntity):
|
|
896
907
|
TreasuryTx[treasury_tx_dbid].txgroup = txgroup_dbid
|
897
908
|
|
898
909
|
|
910
|
+
_stream_metadata_cache: Final[Dict[HexStr, Tuple[ChecksumAddress, date]]] = {}
|
911
|
+
|
912
|
+
|
913
|
+
class Stream(DbEntity):
|
914
|
+
_table_ = "streams"
|
915
|
+
stream_id = PrimaryKey(str)
|
916
|
+
|
917
|
+
contract = Required("Address", reverse="streams")
|
918
|
+
start_block = Required(int)
|
919
|
+
end_block = Optional(int)
|
920
|
+
token = Required("Token", reverse="streams", index=True)
|
921
|
+
from_address = Required("Address", reverse="streams_from")
|
922
|
+
to_address = Required("Address", reverse="streams_to")
|
923
|
+
reason = Optional(str)
|
924
|
+
amount_per_second = Required(Decimal, 38, 1)
|
925
|
+
status = Required(str, default="Active")
|
926
|
+
txgroup = Optional("TxGroup", reverse="streams")
|
927
|
+
|
928
|
+
streamed_funds = Set("StreamedFunds")
|
929
|
+
|
930
|
+
scale = int(1e20)
|
931
|
+
|
932
|
+
@property
|
933
|
+
def is_alive(self) -> bool:
|
934
|
+
if self.end_block is None:
|
935
|
+
assert self.status in ["Active", "Paused"]
|
936
|
+
return self.status == "Active"
|
937
|
+
assert self.status == "Stopped"
|
938
|
+
return False
|
939
|
+
|
940
|
+
@property
|
941
|
+
def amount_per_minute(self) -> int:
|
942
|
+
return self.amount_per_second * 60
|
943
|
+
|
944
|
+
@property
|
945
|
+
def amount_per_hour(self) -> int:
|
946
|
+
return self.amount_per_minute * 60
|
947
|
+
|
948
|
+
@property
|
949
|
+
def amount_per_day(self) -> int:
|
950
|
+
return self.amount_per_hour * 24
|
951
|
+
|
952
|
+
@staticmethod
|
953
|
+
def check_closed(stream_id: HexStr) -> bool:
|
954
|
+
with db_session:
|
955
|
+
return any(sf.is_last_day for sf in Stream[stream_id].streamed_funds)
|
956
|
+
|
957
|
+
@staticmethod
|
958
|
+
def _get_start_and_end(stream_dbid: HexStr) -> Tuple[datetime, datetime]:
|
959
|
+
with db_session:
|
960
|
+
stream = Stream[stream_dbid]
|
961
|
+
start_date, end = stream.start_date, datetime.now(_UTC)
|
962
|
+
# convert start to datetime
|
963
|
+
start = datetime.combine(start_date, time(tzinfo=_UTC), tzinfo=_UTC)
|
964
|
+
if stream.end_block:
|
965
|
+
end = datetime.fromtimestamp(chain[stream.end_block].timestamp, tz=_UTC)
|
966
|
+
return start, end
|
967
|
+
|
968
|
+
def stop_stream(self, block: int) -> None:
|
969
|
+
self.end_block = block
|
970
|
+
self.status = "Stopped"
|
971
|
+
|
972
|
+
def pause(self) -> None:
|
973
|
+
self.status = "Paused"
|
974
|
+
|
975
|
+
@staticmethod
|
976
|
+
def _get_token_and_start_date(stream_id: HexStr) -> Tuple[ChecksumAddress, date]:
|
977
|
+
try:
|
978
|
+
return _stream_metadata_cache[stream_id]
|
979
|
+
except KeyError:
|
980
|
+
with db_session:
|
981
|
+
stream = Stream[stream_id]
|
982
|
+
token = stream.token.address.address
|
983
|
+
start_date = stream.start_date
|
984
|
+
_stream_metadata_cache[stream_id] = token, start_date
|
985
|
+
return token, start_date
|
986
|
+
|
987
|
+
@property
|
988
|
+
def stream_contract(self) -> Contract:
|
989
|
+
return Contract(self.contract.address)
|
990
|
+
|
991
|
+
@property
|
992
|
+
def start_date(self) -> date:
|
993
|
+
return datetime.fromtimestamp(chain[self.start_block].timestamp).date()
|
994
|
+
|
995
|
+
async def amount_withdrawable(self, block: int) -> int:
|
996
|
+
return await self.stream_contract.withdrawable.coroutine(
|
997
|
+
self.from_address.address,
|
998
|
+
self.to_address.address,
|
999
|
+
int(self.amount_per_second),
|
1000
|
+
block_identifier=block,
|
1001
|
+
)
|
1002
|
+
|
1003
|
+
def print(self) -> None:
|
1004
|
+
symbol = self.token.symbol
|
1005
|
+
print(f"{symbol} per second: {self.amount_per_second / self.scale}")
|
1006
|
+
print(f"{symbol} per day: {self.amount_per_day / self.scale}")
|
1007
|
+
|
1008
|
+
|
1009
|
+
class StreamedFunds(DbEntity):
|
1010
|
+
"""Each object represents one calendar day of tokens streamed for a particular stream."""
|
1011
|
+
|
1012
|
+
_table_ = "streamed_funds"
|
1013
|
+
|
1014
|
+
date = Required(date)
|
1015
|
+
stream = Required(Stream, reverse="streamed_funds")
|
1016
|
+
PrimaryKey(stream, date)
|
1017
|
+
|
1018
|
+
amount = Required(Decimal, 38, 18)
|
1019
|
+
price = Required(Decimal, 38, 18)
|
1020
|
+
value_usd = Required(Decimal, 38, 18)
|
1021
|
+
seconds_active = Required(int)
|
1022
|
+
is_last_day = Required(bool)
|
1023
|
+
|
1024
|
+
@db_session
|
1025
|
+
def get_entity(stream_id: str, date: datetime) -> "StreamedFunds":
|
1026
|
+
stream = Stream[stream_id]
|
1027
|
+
return StreamedFunds.get(date=date, stream=stream)
|
1028
|
+
|
1029
|
+
@classmethod
|
1030
|
+
@db_session
|
1031
|
+
def create_entity(
|
1032
|
+
cls,
|
1033
|
+
stream_id: str,
|
1034
|
+
date: datetime,
|
1035
|
+
price: Decimal,
|
1036
|
+
seconds_active: int,
|
1037
|
+
is_last_day: bool,
|
1038
|
+
) -> "StreamedFunds":
|
1039
|
+
stream = Stream[stream_id]
|
1040
|
+
amount_streamed_today = round(
|
1041
|
+
stream.amount_per_second * seconds_active / stream.scale, 18
|
1042
|
+
)
|
1043
|
+
entity = StreamedFunds(
|
1044
|
+
date=date,
|
1045
|
+
stream=stream,
|
1046
|
+
amount=amount_streamed_today,
|
1047
|
+
price=round(price, 18),
|
1048
|
+
value_usd=round(amount_streamed_today * price, 18),
|
1049
|
+
seconds_active=seconds_active,
|
1050
|
+
is_last_day=is_last_day,
|
1051
|
+
)
|
1052
|
+
return entity
|
1053
|
+
|
1054
|
+
|
899
1055
|
db.bind(
|
900
1056
|
provider="sqlite", # TODO: let user choose postgres with server connection params
|
901
1057
|
filename=str(SQLITE_DIR / "dao-treasury.sqlite"),
|
@@ -921,12 +1077,12 @@ def create_stream_ledger_view() -> None:
|
|
921
1077
|
Examples:
|
922
1078
|
>>> create_stream_ledger_view()
|
923
1079
|
"""
|
1080
|
+
db.execute("""DROP VIEW IF EXISTS stream_ledger;""")
|
924
1081
|
db.execute(
|
925
1082
|
"""
|
926
|
-
DROP VIEW IF EXISTS stream_ledger;
|
927
1083
|
create view stream_ledger as
|
928
1084
|
SELECT 'Mainnet' as chain_name,
|
929
|
-
cast(
|
1085
|
+
cast(strftime('%s', date || ' 00:00:00') as INTEGER) as timestamp,
|
930
1086
|
NULL as block,
|
931
1087
|
NULL as hash,
|
932
1088
|
NULL as log_index,
|
@@ -1007,7 +1163,7 @@ def create_general_ledger_view() -> None:
|
|
1007
1163
|
create VIEW general_ledger as
|
1008
1164
|
select *
|
1009
1165
|
from (
|
1010
|
-
SELECT treasury_tx_id, b.chain_name,
|
1166
|
+
SELECT treasury_tx_id, b.chain_name, a.timestamp, a.block, a.hash, a.log_index, c.symbol AS token, d.address AS "from", d.nickname as from_nickname, e.address AS "to", e.nickname as to_nickname, a.amount, a.price, a.value_usd, f.name AS txgroup, g.name AS parent_txgroup, f.txgroup_id
|
1011
1167
|
FROM treasury_txs a
|
1012
1168
|
LEFT JOIN chains b ON a.chain = b.chain_dbid
|
1013
1169
|
LEFT JOIN tokens c ON a.token_id = c.token_id
|
@@ -1015,9 +1171,9 @@ def create_general_ledger_view() -> None:
|
|
1015
1171
|
LEFT JOIN addresses e ON a."to" = e.address_id
|
1016
1172
|
LEFT JOIN txgroups f ON a.txgroup_id = f.txgroup_id
|
1017
1173
|
LEFT JOIN txgroups g ON f.parent_txgroup = g.txgroup_id
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1174
|
+
UNION
|
1175
|
+
SELECT -1, chain_name, timestamp, block, hash, log_index, token, "from", from_nickname, "to", to_nickname, amount, price, value_usd, txgroup, parent_txgroup, txgroup_id
|
1176
|
+
FROM stream_ledger
|
1021
1177
|
--UNION
|
1022
1178
|
--SELECT -1, *
|
1023
1179
|
--FROM vesting_ledger
|
@@ -1093,7 +1249,7 @@ def create_monthly_pnl_view() -> None:
|
|
1093
1249
|
|
1094
1250
|
|
1095
1251
|
with db_session:
|
1096
|
-
|
1252
|
+
create_stream_ledger_view()
|
1097
1253
|
# create_vesting_ledger_view()
|
1098
1254
|
create_general_ledger_view()
|
1099
1255
|
create_unsorted_txs_view()
|
dao_treasury/docker-compose.yaml
CHANGED
@@ -15,6 +15,7 @@ services:
|
|
15
15
|
- GF_SECURITY_ADMIN_USER=${GF_SECURITY_ADMIN_USER:-admin}
|
16
16
|
- GF_SECURITY_ADMIN_PASSWORD=${GF_SECURITY_ADMIN_PASSWORD:-admin}
|
17
17
|
- GF_AUTH_ANONYMOUS_ENABLED=true
|
18
|
+
- GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
|
18
19
|
- GF_DASHBOARDS_DEFAULT_HOME_DASHBOARD_PATH=/etc/grafana/provisioning/dashboards/summary/Monthly.json
|
19
20
|
- GF_SERVER_ROOT_URL
|
20
21
|
- GF_RENDERING_SERVER_URL=http://renderer:8091/render
|
dao_treasury/main.py
CHANGED
@@ -28,6 +28,7 @@ from pathlib import Path
|
|
28
28
|
|
29
29
|
import brownie
|
30
30
|
import yaml
|
31
|
+
from a_sync import create_task
|
31
32
|
from dao_treasury._wallet import load_wallets_from_yaml
|
32
33
|
from eth_portfolio_scripts.balances import export_balances
|
33
34
|
from eth_typing import BlockNumber
|
@@ -107,6 +108,11 @@ parser.add_argument(
|
|
107
108
|
help="Port for the DAO Treasury dashboard web interface. Default: 3000",
|
108
109
|
default=3000,
|
109
110
|
)
|
111
|
+
parser.add_argument(
|
112
|
+
"--start-renderer",
|
113
|
+
action="store_true",
|
114
|
+
help="If set, the Grafana renderer container will be started for dashboard image export. By default, only the grafana container is started.",
|
115
|
+
)
|
110
116
|
parser.add_argument(
|
111
117
|
"--renderer-port",
|
112
118
|
type=int,
|
@@ -154,6 +160,7 @@ async def export(args) -> None:
|
|
154
160
|
daemon: Ignored flag.
|
155
161
|
grafana_port: Port for Grafana (sets DAO_TREASURY_GRAFANA_PORT).
|
156
162
|
renderer_port: Port for renderer (sets DAO_TREASURY_RENDERER_PORT).
|
163
|
+
start_renderer: If True, start renderer; otherwise, only start grafana.
|
157
164
|
|
158
165
|
Example:
|
159
166
|
In code::
|
@@ -165,6 +172,8 @@ async def export(args) -> None:
|
|
165
172
|
:func:`dao_treasury._docker.down`,
|
166
173
|
:class:`dao_treasury.Treasury.populate_db`
|
167
174
|
"""
|
175
|
+
import eth_portfolio_scripts.docker
|
176
|
+
|
168
177
|
from dao_treasury import _docker, constants, db, Treasury
|
169
178
|
|
170
179
|
wallets = getattr(args, "wallet", None)
|
@@ -195,7 +204,12 @@ async def export(args) -> None:
|
|
195
204
|
db.Address.set_nickname(address, nickname)
|
196
205
|
|
197
206
|
treasury = Treasury(wallets, args.sort_rules, asynchronous=True)
|
198
|
-
|
207
|
+
|
208
|
+
# Start only the requested containers
|
209
|
+
if args.start_renderer is True:
|
210
|
+
_docker.up()
|
211
|
+
else:
|
212
|
+
_docker.up("grafana")
|
199
213
|
|
200
214
|
# eth-portfolio needs this present
|
201
215
|
# TODO: we need to update eth-portfolio to honor wallet join and exit times
|
@@ -209,11 +223,21 @@ async def export(args) -> None:
|
|
209
223
|
# TODO: make this user configurable? would require some dynamic grafana dashboard files
|
210
224
|
args.label = "Treasury"
|
211
225
|
|
212
|
-
|
213
|
-
|
226
|
+
export_task = create_task(
|
227
|
+
asyncio.gather(
|
214
228
|
export_balances(args),
|
215
229
|
treasury.populate_db(BlockNumber(0), brownie.chain.height),
|
216
230
|
)
|
231
|
+
)
|
232
|
+
|
233
|
+
await asyncio.sleep(1)
|
234
|
+
|
235
|
+
# we don't need these containers since dao-treasury uses its own.
|
236
|
+
eth_portfolio_scripts.docker.stop("grafana")
|
237
|
+
eth_portfolio_scripts.docker.stop("renderer")
|
238
|
+
|
239
|
+
try:
|
240
|
+
await export_task
|
217
241
|
finally:
|
218
242
|
_docker.down()
|
219
243
|
|
Binary file
|
dao_treasury/sorting/__init__.py
CHANGED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
dao_treasury/sorting/rule.py
CHANGED
@@ -31,6 +31,7 @@ See Also:
|
|
31
31
|
|
32
32
|
from collections import defaultdict
|
33
33
|
from dataclasses import dataclass
|
34
|
+
from logging import getLogger
|
34
35
|
from typing import (
|
35
36
|
TYPE_CHECKING,
|
36
37
|
DefaultDict,
|
@@ -53,6 +54,9 @@ if TYPE_CHECKING:
|
|
53
54
|
from dao_treasury.db import TreasuryTx
|
54
55
|
|
55
56
|
|
57
|
+
logger: Final = getLogger(__name__)
|
58
|
+
_log_debug: Final = logger.debug
|
59
|
+
|
56
60
|
SORT_RULES: DefaultDict[Type[SortRule], List[SortRule]] = defaultdict(list)
|
57
61
|
"""Mapping from sort rule classes to lists of instantiated rules, in creation order per class.
|
58
62
|
|
@@ -214,6 +218,7 @@ class _SortRule:
|
|
214
218
|
getattr(tx, matcher) == getattr(self, matcher) for matcher in matchers
|
215
219
|
)
|
216
220
|
|
221
|
+
_log_debug("checking %s for %s", tx, self.func)
|
217
222
|
match = self.func(tx) # type: ignore [misc]
|
218
223
|
return match if isinstance(match, bool) else await match
|
219
224
|
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
from dao_treasury.sorting.rules.ignore import *
|
@@ -0,0 +1 @@
|
|
1
|
+
from dao_treasury.sorting.rules.ignore.llamapay import *
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from dao_treasury import TreasuryTx
|
2
|
+
from dao_treasury.sorting.factory import ignore
|
3
|
+
from dao_treasury.streams import llamapay
|
4
|
+
|
5
|
+
|
6
|
+
@ignore("LlamaPay")
|
7
|
+
def is_llamapay_stream_replenishment(tx: TreasuryTx) -> bool:
|
8
|
+
if tx.to_address.address in llamapay.factories: # type: ignore [operator]
|
9
|
+
# We amortize these streams daily in the `llamapay` module, you'll sort each stream appropriately.
|
10
|
+
return True
|
11
|
+
|
12
|
+
# NOTE: not sure if we want this yet
|
13
|
+
# Puling unused funds back from vesting escrow / llamapay
|
14
|
+
# elif tx.from_address == "Contract: LlamaPay" and "StreamCancelled" in tx.events:
|
15
|
+
# if tx.amount > 0:
|
16
|
+
# tx.amount *= -1
|
17
|
+
# if tx.value_usd > 0:
|
18
|
+
# tx.value_usd *= -1
|
19
|
+
# return True
|
20
|
+
return False
|
Binary file
|
File without changes
|
Binary file
|