dao-treasury 0.0.10__cp310-cp310-win32.whl → 0.0.70__cp310-cp310-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. dao_treasury/.grafana/provisioning/dashboards/breakdowns/Expenses.json +551 -0
  2. dao_treasury/.grafana/provisioning/dashboards/breakdowns/Revenue.json +551 -0
  3. dao_treasury/.grafana/provisioning/dashboards/dashboards.yaml +7 -7
  4. dao_treasury/.grafana/provisioning/dashboards/streams/LlamaPay.json +220 -0
  5. dao_treasury/.grafana/provisioning/dashboards/summary/Monthly.json +153 -29
  6. dao_treasury/.grafana/provisioning/dashboards/transactions/Treasury Transactions.json +181 -29
  7. dao_treasury/.grafana/provisioning/dashboards/treasury/Cashflow (Including Unsorted).json +808 -0
  8. dao_treasury/.grafana/provisioning/dashboards/treasury/Cashflow.json +602 -0
  9. dao_treasury/.grafana/provisioning/dashboards/treasury/Current Treasury Assets.json +981 -0
  10. dao_treasury/.grafana/provisioning/dashboards/treasury/Historical Treasury Balances.json +2989 -0
  11. dao_treasury/.grafana/provisioning/dashboards/treasury/Operating Cashflow.json +478 -0
  12. dao_treasury/.grafana/provisioning/datasources/datasources.yaml +17 -0
  13. dao_treasury/ENVIRONMENT_VARIABLES.py +20 -0
  14. dao_treasury/__init__.py +36 -10
  15. dao_treasury/_docker.cp310-win32.pyd +0 -0
  16. dao_treasury/_docker.py +169 -37
  17. dao_treasury/_nicknames.cp310-win32.pyd +0 -0
  18. dao_treasury/_nicknames.py +32 -0
  19. dao_treasury/_wallet.cp310-win32.pyd +0 -0
  20. dao_treasury/_wallet.py +164 -12
  21. dao_treasury/constants.cp310-win32.pyd +0 -0
  22. dao_treasury/constants.py +39 -0
  23. dao_treasury/db.py +925 -150
  24. dao_treasury/docker-compose.yaml +6 -5
  25. dao_treasury/main.py +238 -28
  26. dao_treasury/sorting/__init__.cp310-win32.pyd +0 -0
  27. dao_treasury/sorting/__init__.py +219 -115
  28. dao_treasury/sorting/_matchers.cp310-win32.pyd +0 -0
  29. dao_treasury/sorting/_matchers.py +261 -17
  30. dao_treasury/sorting/_rules.cp310-win32.pyd +0 -0
  31. dao_treasury/sorting/_rules.py +166 -21
  32. dao_treasury/sorting/factory.cp310-win32.pyd +0 -0
  33. dao_treasury/sorting/factory.py +245 -37
  34. dao_treasury/sorting/rule.cp310-win32.pyd +0 -0
  35. dao_treasury/sorting/rule.py +228 -46
  36. dao_treasury/sorting/rules/__init__.cp310-win32.pyd +0 -0
  37. dao_treasury/sorting/rules/__init__.py +1 -0
  38. dao_treasury/sorting/rules/ignore/__init__.cp310-win32.pyd +0 -0
  39. dao_treasury/sorting/rules/ignore/__init__.py +1 -0
  40. dao_treasury/sorting/rules/ignore/llamapay.cp310-win32.pyd +0 -0
  41. dao_treasury/sorting/rules/ignore/llamapay.py +20 -0
  42. dao_treasury/streams/__init__.cp310-win32.pyd +0 -0
  43. dao_treasury/streams/__init__.py +0 -0
  44. dao_treasury/streams/llamapay.cp310-win32.pyd +0 -0
  45. dao_treasury/streams/llamapay.py +388 -0
  46. dao_treasury/treasury.py +118 -25
  47. dao_treasury/types.cp310-win32.pyd +0 -0
  48. dao_treasury/types.py +104 -7
  49. dao_treasury-0.0.70.dist-info/METADATA +134 -0
  50. dao_treasury-0.0.70.dist-info/RECORD +54 -0
  51. dao_treasury-0.0.70.dist-info/top_level.txt +2 -0
  52. dao_treasury__mypyc.cp310-win32.pyd +0 -0
  53. a743a720bbc4482d330e__mypyc.cp310-win32.pyd +0 -0
  54. dao_treasury/.grafana/provisioning/datasources/sqlite.yaml +0 -10
  55. dao_treasury-0.0.10.dist-info/METADATA +0 -36
  56. dao_treasury-0.0.10.dist-info/RECORD +0 -28
  57. dao_treasury-0.0.10.dist-info/top_level.txt +0 -2
  58. {dao_treasury-0.0.10.dist-info → dao_treasury-0.0.70.dist-info}/WHEEL +0 -0
@@ -1,74 +1,239 @@
1
- from typing import Any, Final, Generic, Optional, TypeVar, Union, final, overload
2
-
3
- from y import constants
1
+ from typing import Any, Final, Generic, Optional, Union, final, overload
4
2
 
3
+ from dao_treasury.constants import CHAINID
5
4
  from dao_treasury.sorting.rule import (
6
- CostOfRevenueSortRule,
7
- ExpenseSortRule,
8
- IgnoreSortRule,
9
- OtherExpenseSortRule,
10
- OtherIncomeSortRule,
11
- RevenueSortRule,
12
- )
13
- from dao_treasury.types import Networks, SortFunction, TxGroupName
14
-
15
-
16
- TRule = TypeVar(
17
- "TRule",
18
- RevenueSortRule,
19
5
  CostOfRevenueSortRule,
20
6
  ExpenseSortRule,
21
- OtherIncomeSortRule,
22
- OtherExpenseSortRule,
23
7
  IgnoreSortRule,
8
+ OtherExpenseSortRule,
9
+ OtherIncomeSortRule,
10
+ RevenueSortRule,
11
+ TRule,
24
12
  )
13
+ from dao_treasury.types import Networks, SortFunction, TxGroupName
14
+
25
15
 
16
+ def revenue(
17
+ txgroup: TxGroupName, networks: Networks = CHAINID
18
+ ) -> "SortRuleFactory[RevenueSortRule]":
19
+ """Create a factory to register revenue sort rules for a given transaction group.
26
20
 
27
- CHAINID: Final = constants.CHAINID
21
+ Args:
22
+ txgroup: Base name of the transaction group to categorize as revenue.
23
+ networks: Network ID or iterable of network IDs on which this rule applies.
28
24
 
25
+ See Also:
26
+ :func:`cost_of_revenue`
27
+ :class:`SortRuleFactory`
29
28
 
30
- def revenue(txgroup: TxGroupName, networks: Networks = CHAINID) -> "SortRuleFactory[RevenueSortRule]":
29
+ Examples:
30
+ >>> from dao_treasury.sorting.factory import revenue
31
+ >>> @revenue("Token Sales")
32
+ ... def match_sales(tx):
33
+ ... return tx.amount > 0 and tx.to_address is not None
34
+ """
31
35
  return SortRuleFactory(txgroup, networks, RevenueSortRule)
32
36
 
33
- def cost_of_revenue(txgroup: TxGroupName, networks: Networks = CHAINID) -> "SortRuleFactory[CostOfRevenueSortRule]":
37
+
38
+ def cost_of_revenue(
39
+ txgroup: TxGroupName, networks: Networks = CHAINID
40
+ ) -> "SortRuleFactory[CostOfRevenueSortRule]":
41
+ """Create a factory to register cost‐of‐revenue sort rules for a given transaction group.
42
+
43
+ Args:
44
+ txgroup: Base name of the transaction group to categorize as cost of revenue.
45
+ networks: Network ID or iterable of network IDs on which this rule applies.
46
+
47
+ See Also:
48
+ :func:`revenue`
49
+ :class:`SortRuleFactory`
50
+
51
+ Examples:
52
+ >>> from dao_treasury.sorting.factory import cost_of_revenue
53
+ >>> @cost_of_revenue("Manufacturing")
54
+ ... def match_manufacturing(tx):
55
+ ... return tx.from_address is not None and tx.amount_usd > 1000
56
+ """
34
57
  return SortRuleFactory(txgroup, networks, CostOfRevenueSortRule)
35
58
 
36
- def expense(txgroup: TxGroupName, networks: Networks = CHAINID) -> "SortRuleFactory[ExpenseSortRule]":
59
+
60
+ def expense(
61
+ txgroup: TxGroupName, networks: Networks = CHAINID
62
+ ) -> "SortRuleFactory[ExpenseSortRule]":
63
+ """Create a factory to register expense sort rules for a given transaction group.
64
+
65
+ Args:
66
+ txgroup: Base name of the transaction group to categorize as expense.
67
+ networks: Network ID or iterable of network IDs on which this rule applies.
68
+
69
+ See Also:
70
+ :func:`other_expense`
71
+ :class:`SortRuleFactory`
72
+
73
+ Examples:
74
+ >>> from dao_treasury.sorting.factory import expense
75
+ >>> @expense("Office Supplies")
76
+ ... def match_supplies(tx):
77
+ ... return tx.symbol == "USD" and tx.amount < 500
78
+ """
37
79
  return SortRuleFactory(txgroup, networks, ExpenseSortRule)
38
80
 
39
- def other_income(txgroup: TxGroupName, networks: Networks = CHAINID) -> "SortRuleFactory[OtherIncomeSortRule]":
81
+
82
+ def other_income(
83
+ txgroup: TxGroupName, networks: Networks = CHAINID
84
+ ) -> "SortRuleFactory[OtherIncomeSortRule]":
85
+ """Create a factory to register other‐income sort rules for a given transaction group.
86
+
87
+ Args:
88
+ txgroup: Base name of the transaction group to categorize as other income.
89
+ networks: Network ID or iterable of network IDs on which this rule applies.
90
+
91
+ See Also:
92
+ :func:`revenue`
93
+ :class:`SortRuleFactory`
94
+
95
+ Examples:
96
+ >>> from dao_treasury.sorting.factory import other_income
97
+ >>> @other_income("Interest")
98
+ ... def match_interest(tx):
99
+ ... return tx.token_address == SOME_TOKEN and tx.amount > 0
100
+ """
40
101
  return SortRuleFactory(txgroup, networks, OtherIncomeSortRule)
41
102
 
42
- def other_expense(txgroup: TxGroupName, networks: Networks = CHAINID) -> "SortRuleFactory[OtherExpenseSortRule]":
103
+
104
+ def other_expense(
105
+ txgroup: TxGroupName, networks: Networks = CHAINID
106
+ ) -> "SortRuleFactory[OtherExpenseSortRule]":
107
+ """Create a factory to register other‐expense sort rules for a given transaction group.
108
+
109
+ Args:
110
+ txgroup: Base name of the transaction group to categorize as other expense.
111
+ networks: Network ID or iterable of network IDs on which this rule applies.
112
+
113
+ See Also:
114
+ :func:`expense`
115
+ :class:`SortRuleFactory`
116
+
117
+ Examples:
118
+ >>> from dao_treasury.sorting.factory import other_expense
119
+ >>> @other_expense("Misc Fees")
120
+ ... def match_misc(tx):
121
+ ... return tx.amount_usd < 0 and tx.symbol == "ETH"
122
+ """
43
123
  return SortRuleFactory(txgroup, networks, OtherExpenseSortRule)
44
124
 
45
- def ignore(txgroup: TxGroupName, networks: Networks = CHAINID) -> "SortRuleFactory[IgnoreSortRule]":
125
+
126
+ def ignore(
127
+ txgroup: TxGroupName, networks: Networks = CHAINID
128
+ ) -> "SortRuleFactory[IgnoreSortRule]":
129
+ """Create a factory to register ignore sort rules for a given transaction group.
130
+
131
+ Args:
132
+ txgroup: Base name of the transaction group to categorize as ignored.
133
+ networks: Network ID or iterable of network IDs on which this rule applies.
134
+
135
+ See Also:
136
+ :class:`SortRuleFactory`
137
+
138
+ Examples:
139
+ >>> from dao_treasury.sorting.factory import ignore
140
+ >>> @ignore("Dust")
141
+ ... def match_dust(tx):
142
+ ... return abs(tx.value_usd) < 0.01
143
+ """
46
144
  return SortRuleFactory(txgroup, networks, IgnoreSortRule)
47
145
 
48
146
 
49
147
  @final
50
148
  class SortRuleFactory(Generic[TRule]):
149
+ """Builder for creating sort rule instances for a specific transaction group and network(s).
150
+
151
+ This factory supports two patterns:
152
+
153
+ 1. Decorating a function to register a dynamic matching rule.
154
+ 2. Calling :meth:`match` to supply static match attributes.
155
+
156
+ Use the convenience functions like :func:`revenue`, :func:`expense`, etc.,
157
+ to obtain an instance of this factory preconfigured with the appropriate rule type.
158
+
159
+ Examples:
160
+ >>> from dao_treasury.sorting.factory import revenue
161
+ >>> @revenue("Sales", networks=[1, 3])
162
+ ... def match_large_sales(tx):
163
+ ... return tx.value_usd > 1000
164
+ """
165
+
51
166
  def __init__(
52
167
  self,
53
- txgroup: TxGroupName,
168
+ txgroup: TxGroupName,
54
169
  networks: Networks,
55
- rule_type: TRule,
170
+ rule_type: TRule,
56
171
  ) -> None:
172
+ """Initialize the sort rule factory.
173
+
174
+ Args:
175
+ txgroup: Base name of the transaction group.
176
+ networks: Single network ID or iterable of network IDs where the rule applies.
177
+ rule_type: Sort rule class (e.g., RevenueSortRule) to instantiate.
178
+ """
57
179
  self.txgroup: Final = txgroup
58
- self.networks: Final = [networks] if isinstance(networks, int) else list(networks)
180
+ self.networks: Final = (
181
+ [networks] if isinstance(networks, int) else list(networks)
182
+ )
59
183
  self.rule_type: Final = rule_type
60
184
  self._rule: Optional[TRule] = None
185
+
61
186
  @overload
62
- def __call__(self, txgroup_name: TxGroupName, networks: Optional[Networks] = None) -> "SortRuleFactory":...
187
+ def __call__(
188
+ self, txgroup_name: TxGroupName, networks: Optional[Networks] = None
189
+ ) -> "SortRuleFactory":
190
+ """Configure a nested sub‐group.
191
+
192
+ Args:
193
+ txgroup_name: Sub‐group name.
194
+ networks: Optional network specification.
195
+ """
196
+
63
197
  @overload
64
- def __call__(self, func: SortFunction) -> SortFunction:...
198
+ def __call__(self, func: SortFunction) -> SortFunction:
199
+ """Register a matching function.
200
+
201
+ Args:
202
+ func: The custom matching function.
203
+ """
204
+
65
205
  def __call__( # type: ignore [misc]
66
- self,
206
+ self,
67
207
  func: Union[TxGroupName, SortFunction],
68
208
  networks: Optional[Networks] = None,
69
209
  ) -> Union["SortRuleFactory", SortFunction]:
210
+ """Configure a nested sub‐group or register a matching function.
211
+
212
+ Overloads:
213
+ * If `func` is a string, returns a new factory for `txgroup:func`.
214
+ * If `func` is callable, registers it as the match logic.
215
+
216
+ Args:
217
+ func: Sub‐group suffix (str) or a custom matching function.
218
+ networks: Optional networks override (only valid when `func` is str).
219
+
220
+ Raises:
221
+ RuntimeError: If `networks` is passed when `func` is callable.
222
+ ValueError: If `func` is neither str nor callable.
223
+
224
+ See Also:
225
+ :meth:`match`
226
+
227
+ Examples:
228
+ >>> fees = expense("Fees")
229
+ >>> @fees("Gas")
230
+ ... def match_gas(tx):
231
+ ... return tx.symbol == "ETH"
232
+ """
70
233
  if isinstance(func, str):
71
- return SortRuleFactory(f"{self.txgroup}:{func}", networks or self.networks, self.rule_type)
234
+ return SortRuleFactory(
235
+ f"{self.txgroup}:{func}", networks or self.networks, self.rule_type
236
+ )
72
237
  elif callable(func):
73
238
  if networks:
74
239
  raise RuntimeError("you can only pass networks if `func` is a string")
@@ -77,15 +242,58 @@ class SortRuleFactory(Generic[TRule]):
77
242
  self._rule = self.rule_type(txgroup=self.txgroup, func=func)
78
243
  return func
79
244
  raise ValueError(func)
245
+
80
246
  @property
81
247
  def rule(self) -> Optional[TRule]:
248
+ """Return the created sort rule instance, if any.
249
+
250
+ After decoration or a call to :meth:`match`, this property holds the
251
+ concrete :class:`~dao_treasury.types.SortRule` instance.
252
+
253
+ Examples:
254
+ >>> @other_income("Interest")
255
+ ... def match_i(tx):
256
+ ... return tx.value_usd > 100
257
+ """
82
258
  return self._rule
83
- def match(self, func: None = None, **match_values: Any) -> None: # TODO: give this proper kwargs
259
+
260
+ def match(
261
+ self, func: None = None, **match_values: Any
262
+ ) -> None: # TODO: give this proper kwargs
263
+ """Define static matching attributes for the sort rule.
264
+
265
+ Call this method with keyword matchers corresponding to rule attributes
266
+ (e.g., hash, from_address, symbol) to create a rule matching based on these values.
267
+
268
+ Args:
269
+ func: Must be None; a function match must use the decorator form.
270
+ **match_values: Attribute values for matching (e.g., hash="0x123", symbol="DAI").
271
+
272
+ Raises:
273
+ ValueError: If `func` is not None.
274
+ RuntimeError: If a matcher has already been set.
275
+
276
+ See Also:
277
+ :meth:`__call__`
278
+
279
+ Examples:
280
+ >>> ignore("Dust").match(symbol="WETH", from_address="0xAAA")
281
+ """
84
282
  if func is not None:
85
- raise ValueError(f"You cannot pass a func here, call {self} with the function as the sole arg instead")
86
- self.__check_locked()
87
- self._rule = self.rule_type(txgroup=self.txgroup, **match_values)
88
- self.locked = True
283
+ raise ValueError(
284
+ f"You cannot pass a func here, call {self} with the function as the sole arg instead"
285
+ )
286
+ # Only instantiate when we're on an allowed network
287
+ if CHAINID in self.networks:
288
+ self.__check_locked()
289
+ self._rule = self.rule_type(txgroup=self.txgroup, **match_values)
290
+ self.locked = True
291
+
89
292
  def __check_locked(self) -> None:
293
+ """Ensure that no matcher has already been registered.
294
+
295
+ Raises:
296
+ RuntimeError: If this factory already has a matcher assigned.
297
+ """
90
298
  if self._rule is not None:
91
299
  raise RuntimeError(f"{self} already has a matcher")