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,18 +1,18 @@
1
1
  networks:
2
2
  dao_treasury:
3
-
4
- volumes:
5
- grafana_data: {}
3
+ docker_eth_portfolio:
4
+ external: true
6
5
 
7
6
  services:
8
7
  grafana:
9
- image: grafana/grafana:10.2.0
8
+ image: grafana/grafana:12.2.1
10
9
  ports:
11
10
  - 127.0.0.1:${DAO_TREASURY_GRAFANA_PORT:-3004}:3000
12
11
  environment:
13
12
  - GF_SECURITY_ADMIN_USER=${GF_SECURITY_ADMIN_USER:-admin}
14
13
  - GF_SECURITY_ADMIN_PASSWORD=${GF_SECURITY_ADMIN_PASSWORD:-admin}
15
14
  - GF_AUTH_ANONYMOUS_ENABLED=true
15
+ - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
16
16
  - GF_DASHBOARDS_DEFAULT_HOME_DASHBOARD_PATH=/etc/grafana/provisioning/dashboards/summary/Monthly.json
17
17
  - GF_SERVER_ROOT_URL
18
18
  - GF_RENDERING_SERVER_URL=http://renderer:8091/render
@@ -21,10 +21,10 @@ services:
21
21
  - GF_INSTALL_PLUGINS=volkovlabs-variable-panel,frser-sqlite-datasource
22
22
  volumes:
23
23
  - ~/.dao-treasury/:/app/dao-treasury-data
24
- - grafana_data:/var/lib/grafana
25
24
  - ./.grafana/provisioning/:/etc/grafana/provisioning/
26
25
  networks:
27
26
  - dao_treasury
27
+ - docker_eth_portfolio
28
28
  restart: always
29
29
 
30
30
  renderer:
@@ -37,4 +37,5 @@ services:
37
37
  - HTTP_PORT=8091
38
38
  networks:
39
39
  - dao_treasury
40
+ - docker_eth_portfolio
40
41
  restart: always
dao_treasury/main.py CHANGED
@@ -1,3 +1,24 @@
1
+ """Command-line interface for exporting DAO treasury transactions.
2
+
3
+ This module parses command-line arguments, sets up environment variables for
4
+ Grafana and its renderer, and defines the entrypoint for a one-time export of
5
+ DAO treasury transactions. It populates the local SQLite database and starts
6
+ the required Docker services for Grafana dashboards. Transactions are fetched
7
+ via :class:`dao_treasury.Treasury`, sorted according to optional rules, and
8
+ inserted using the database routines (:func:`dao_treasury.db.TreasuryTx.insert`).
9
+
10
+ Example:
11
+ Running from the shell::
12
+
13
+ $ dao-treasury --network mainnet --sort-rules ./rules --wallet 0xABC123... \
14
+ --interval 6h --grafana-port 3000 --renderer-port 8091
15
+
16
+ See Also:
17
+ :func:`dao_treasury._docker.up`,
18
+ :func:`dao_treasury._docker.down`,
19
+ :class:`dao_treasury.Treasury`,
20
+ :func:`dao_treasury.db.TreasuryTx.insert`
21
+ """
1
22
 
2
23
  import argparse
3
24
  import asyncio
@@ -6,70 +27,259 @@ import os
6
27
  from pathlib import Path
7
28
 
8
29
  import brownie
30
+ import yaml
31
+ from a_sync import create_task
32
+ from dao_treasury._wallet import load_wallets_from_yaml
33
+ from eth_portfolio_scripts.balances import export_balances
9
34
  from eth_typing import BlockNumber
10
35
 
36
+ from dao_treasury.constants import CHAINID
37
+
11
38
 
12
39
  logger = logging.getLogger(__name__)
40
+
13
41
  logging.basicConfig(level=logging.INFO)
14
42
 
43
+
15
44
  parser = argparse.ArgumentParser(
16
- description="Runs the DAO Treasury Exporter until stopped",
45
+ description="Run a single DAO Treasury export and populate the database.",
17
46
  )
18
-
19
47
  parser.add_argument(
20
- '--network',
48
+ "--network",
21
49
  type=str,
22
- help='The brownie network identifier for the rpc you wish to use. default: mainnet',
23
- default='mainnet',
50
+ help="Brownie network identifier for the RPC to use. Default: mainnet",
51
+ default="mainnet",
52
+ )
53
+ parser.add_argument(
54
+ "--wallet",
55
+ type=str,
56
+ help=(
57
+ "DAO treasury wallet address(es) to include in the export. "
58
+ "Specify one or more addresses separated by spaces. "
59
+ "Check out https://bobthebuidler.github.io/dao-treasury/wallets.html for more info."
60
+ ),
61
+ nargs="+",
62
+ )
63
+ parser.add_argument(
64
+ "--wallets",
65
+ type=Path,
66
+ help=(
67
+ "Path to a YAML file mapping wallet addresses to advanced settings. "
68
+ "Each address is a key, with nested 'start' and/or 'end' mappings containing "
69
+ "either 'block' or 'timestamp'. "
70
+ "Check out https://bobthebuidler.github.io/dao-treasury/wallets.html for more info."
71
+ ),
72
+ default=None,
24
73
  )
25
74
  parser.add_argument(
26
75
  "--sort-rules",
27
76
  type=Path,
28
- help="The directory where your sort rules are defined. If not provided, transactions will be exported without sorting.",
77
+ help=(
78
+ "Directory containing sort rules definitions. "
79
+ "If omitted, transactions are exported without custom sorting. "
80
+ "Check out https://bobthebuidler.github.io/dao-treasury/sort_rules.html for more info."
81
+ ),
29
82
  default=None,
30
83
  )
31
- # TODO pass interval to the eth-portfolio portfolio exporter, but make the dashboard files more specific to dao treasury-ing
32
- #parser.add_argument(
33
- # '--interval',
34
- # type=str,
35
- # help='The time interval between datapoints. default: 1d',
36
- # default='1d',
37
- #)
38
84
  parser.add_argument(
39
- '--daemon',
85
+ "--nicknames",
86
+ type=Path,
87
+ help=(
88
+ "File containing sort address nicknames. "
89
+ "If omitted, transactions are exported without custom sorting. "
90
+ "See https://github.com/BobTheBuidler/yearn-treasury/blob/master/yearn_treasury/addresses.yaml for an example."
91
+ ),
92
+ default=None,
93
+ )
94
+ parser.add_argument(
95
+ "--interval",
96
+ type=str,
97
+ help="The time interval between datapoints. default: 1d",
98
+ default="1d",
99
+ )
100
+ parser.add_argument(
101
+ "--concurrency",
102
+ type=int,
103
+ help="The max number of historical blocks to export concurrently. default: 30",
104
+ default=30,
105
+ )
106
+ parser.add_argument(
107
+ "--daemon",
40
108
  action="store_true",
41
- help='TODO: If True, starts a daemon process instead of running in your terminal. Not currently supported.',
109
+ help="TODO: If True, run as a background daemon. Not currently supported.",
42
110
  )
43
111
  parser.add_argument(
44
- '--grafana-port',
112
+ "--grafana-port",
45
113
  type=int,
46
- help='The port that will be used by grafana',
114
+ help="Port for the DAO Treasury dashboard web interface. Default: 3000",
47
115
  default=3000,
48
116
  )
49
117
  parser.add_argument(
50
- '--renderer-port',
118
+ "--start-renderer",
119
+ action="store_true",
120
+ help="If set, the Grafana renderer container will be started for dashboard image export. By default, only the grafana container is started.",
121
+ )
122
+ parser.add_argument(
123
+ "--renderer-port",
51
124
  type=int,
52
- help='The port that will be used by grafana',
125
+ help="Port for the Grafana rendering service. Default: 8091",
53
126
  default=8091,
54
127
  )
128
+ parser.add_argument(
129
+ "--custom-bucket",
130
+ type=str,
131
+ action="append",
132
+ help=(
133
+ "Custom bucket mapping for a wallet address. "
134
+ "Specify as 'address:bucket_name'. "
135
+ "Can be used multiple times. Example: "
136
+ "--custom-bucket '0x123:My Bucket' --custom-bucket '0x456:Other Bucket'"
137
+ ),
138
+ default=None,
139
+ )
55
140
 
56
141
  args = parser.parse_args()
57
142
 
58
- os.environ['GF_PORT'] = str(args.grafana_port)
59
- os.environ['RENDERER_PORT'] = str(args.renderer_port)
143
+ os.environ["DAO_TREASURY_GRAFANA_PORT"] = str(args.grafana_port)
144
+ os.environ["DAO_TREASURY_RENDERER_PORT"] = str(args.renderer_port)
145
+
60
146
 
61
147
  # TODO: run forever arg
62
148
  def main() -> None:
63
- asyncio.run(export(args))
149
+ """Entrypoint for the `dao-treasury` console script.
150
+
151
+ This function invokes the export coroutine using the arguments parsed at import time.
152
+ It runs the asynchronous export to completion.
153
+
154
+ Example:
155
+ From the command line::
156
+
157
+ $ dao-treasury --network mainnet --sort-rules=./rules --wallet 0xABC123... 0xDEF456...
158
+
159
+ See Also:
160
+ :func:`export`
161
+ """
162
+ asyncio.get_event_loop().run_until_complete(export(args))
163
+
64
164
 
65
165
  async def export(args) -> None:
66
- from dao_treasury import _docker, Treasury
67
- # TODO pass interval to the eth-portfolio portfolio exporter, but make the dashboard files more specific to dao treasury-ing
68
- #interval = parse_timedelta(args.interval)
166
+ """Perform one-time export of treasury transactions and manage Docker services.
167
+
168
+ This coroutine creates a :class:`dao_treasury.Treasury` instance using the
169
+ provided wallets and sort rules, brings up the Grafana and renderer containers,
170
+ then concurrently exports balance snapshots and populates the transaction database
171
+ for blocks from 0 to the current chain height.
172
+
173
+ Args:
174
+ args: Parsed command-line arguments containing:
175
+ wallet: List of simple addresses or TreasuryWallet instances.
176
+ sort_rules: Directory of sorting rules.
177
+ interval: Time interval for balance snapshots.
178
+ daemon: Ignored flag.
179
+ grafana_port: Port for Grafana (sets DAO_TREASURY_GRAFANA_PORT).
180
+ renderer_port: Port for renderer (sets DAO_TREASURY_RENDERER_PORT).
181
+ start_renderer: If True, start renderer; otherwise, only start grafana.
182
+
183
+ Example:
184
+ In code::
185
+
186
+ await export(args) # where args come from parser.parse_args()
187
+
188
+ See Also:
189
+ :func:`dao_treasury._docker.up`,
190
+ :func:`dao_treasury._docker.down`,
191
+ :class:`dao_treasury.Treasury.populate_db`
192
+ """
193
+ import eth_portfolio_scripts.docker
194
+
195
+ from dao_treasury import _docker, constants, db, Treasury
196
+
197
+ wallets = getattr(args, "wallet", None)
198
+ wallets_advanced = getattr(args, "wallets", None)
199
+
200
+ # Ensure user does not supply both simple and advanced wallet inputs
201
+ if wallets and wallets_advanced:
202
+ parser.error("Cannot specify both --wallet and --wallets")
203
+
204
+ # Load advanced wallets from YAML if --wallets provided
205
+ if wallets_advanced:
206
+ wallets = load_wallets_from_yaml(wallets_advanced)
207
+
208
+ # Ensure at least one wallet source is provided
209
+ if not wallets:
210
+ parser.error("Must specify either --wallet or --wallets")
211
+
212
+ # TODO: remove this after refactoring eth-port a bit so we arent required to bring up the e-p dashboards
213
+ os.environ["GRAFANA_PORT"] = "3003"
214
+
215
+ # TODO but make the dashboard files more specific to dao treasury-ing
216
+
217
+ if args.nicknames:
218
+ parsed: dict = yaml.safe_load(args.nicknames.read_bytes())
219
+ active_network_config: dict = parsed.get(constants.CHAINID, {})
220
+ for nickname, addresses in active_network_config.items():
221
+ for address in addresses:
222
+ db.Address.set_nickname(address, nickname)
223
+
224
+ # Parse custom_buckets from --custom-bucket arguments
225
+ custom_buckets = None
226
+ if args.custom_bucket:
227
+ custom_buckets = {}
228
+ for item in args.custom_bucket:
229
+ if ":" not in item:
230
+ parser.error(
231
+ f"Invalid format for --custom-bucket: '{item}'. Must be 'address:bucket_name'."
232
+ )
233
+ address, bucket = item.split(":", 1)
234
+ address = address.strip()
235
+ bucket = bucket.strip()
236
+ if not address or not bucket:
237
+ parser.error(
238
+ f"Invalid format for --custom-bucket: '{item}'. Both address and bucket_name are required."
239
+ )
240
+ custom_buckets[address] = bucket
241
+
242
+ treasury = Treasury(
243
+ wallets, args.sort_rules, custom_buckets=custom_buckets, asynchronous=True
244
+ )
245
+
246
+ # Start only the requested containers
247
+ if args.start_renderer is True:
248
+ _docker.up()
249
+ else:
250
+ _docker.up("grafana")
251
+
252
+ # eth-portfolio needs this present
253
+ # TODO: we need to update eth-portfolio to honor wallet join and exit times
254
+ if not getattr(args, "wallet", None):
255
+ args.wallet = [
256
+ wallet.address
257
+ for wallet in wallets
258
+ if wallet.networks is None or CHAINID in wallet.networks
259
+ ]
260
+
261
+ # TODO: make this user configurable? would require some dynamic grafana dashboard files
262
+ args.label = "Treasury"
263
+
264
+ export_task = create_task(
265
+ asyncio.gather(
266
+ export_balances(args),
267
+ treasury.populate_db(BlockNumber(0), brownie.chain.height),
268
+ )
269
+ )
270
+
271
+ await asyncio.sleep(1)
272
+
273
+ # we don't need these containers since dao-treasury uses its own.
274
+ eth_portfolio_scripts.docker.stop("grafana")
275
+ eth_portfolio_scripts.docker.stop("renderer")
276
+
277
+ try:
278
+ await export_task
279
+ finally:
280
+ _docker.down()
69
281
 
70
- treasury = Treasury(args.wallet, args.sort_rules, asynchronous=True)
71
- await _docker.ensure_containers(treasury.populate_db)(BlockNumber(0), brownie.chain.height)
72
282
 
73
283
  if __name__ == "__main__":
74
- os.environ['BROWNIE_NETWORK_ID'] = args.network
284
+ os.environ["BROWNIE_NETWORK_ID"] = args.network
75
285
  brownie.project.run(__file__)