tinybot-eth 0.4.0__tar.gz → 0.6.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tinybot-eth
3
- Version: 0.4.0
3
+ Version: 0.6.0
4
4
  Summary: Minimal Python framework for building crypto bots
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -8,6 +8,7 @@ Requires-Dist: web3==7.14.1
8
8
  Requires-Dist: eth-abi==5.2.0
9
9
  Requires-Dist: eth-account==0.13.7
10
10
  Requires-Dist: python-telegram-bot==22.7
11
+ Requires-Dist: croniter==6.2.2
11
12
 
12
13
  # tinybot
13
14
 
@@ -34,6 +35,7 @@ bot = TinyBot(rpc_url, name="my bot")
34
35
 
35
36
  bot.listen(event="AuctionKicked", handler=on_kick, ...)
36
37
  bot.every(180, check_expired)
38
+ bot.cron("0 * * * *", hourly_check)
37
39
 
38
40
  await bot.run()
39
41
  ```
@@ -132,6 +134,19 @@ Handler signature: `async fn(bot)`
132
134
 
133
135
  ---
134
136
 
137
+ ### `bot.cron(expression, handler, name="", notify_errors=True) -> CronTask`
138
+
139
+ Register a cron-scheduled task. Uses standard cron expressions.
140
+
141
+ ```python
142
+ bot.cron("0 * * * *", notify_ending_soon) # every hour at :00
143
+ bot.cron("*/30 * * * *", check_something) # every 30 minutes
144
+ ```
145
+
146
+ Handler signature: `async fn(bot)`
147
+
148
+ ---
149
+
135
150
  ### `bot.get_listener(name) -> EventListener`
136
151
 
137
152
  Get a registered listener by name. Raises `ValueError` if not found.
@@ -178,14 +193,17 @@ tx_hash = bot.executor.execute(
178
193
  max_fee_gwei=100, # default: 100
179
194
  max_priority_fee_gwei=0, # default: 0
180
195
  simulate=True, # default: True — dry-run via eth_call before sending
196
+ wait=120, # default: 120 — seconds to wait for mining (0 = fire and forget)
181
197
  )
182
198
  ```
183
199
 
184
200
  - `executor.address` — signer address
185
201
  - `executor.balance` — signer ETH balance in wei
186
- - `executor.execute(call, ...)` — sign and broadcast a transaction, returns tx hash immediately (fire and forget)
202
+ - `executor.execute(call, ...)` — sign and broadcast a transaction, returns tx hash hex string
187
203
  - `gas_limit=0` (default) — auto-estimates gas with 1.5x buffer; pass a value to override
204
+ - `max_fee_gwei` / `max_priority_fee_gwei` — accept floats (e.g. `0.1`)
188
205
  - `simulate=True` (default) — runs `call.call()` first; reverts raise before the tx is sent
206
+ - `wait=120` (default) — wait up to N seconds for the tx to be mined; `0` for fire and forget
189
207
 
190
208
  ---
191
209
 
@@ -1,14 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: tinybot-eth
3
- Version: 0.4.0
4
- Summary: Minimal Python framework for building crypto bots
5
- Requires-Python: >=3.12
6
- Description-Content-Type: text/markdown
7
- Requires-Dist: web3==7.14.1
8
- Requires-Dist: eth-abi==5.2.0
9
- Requires-Dist: eth-account==0.13.7
10
- Requires-Dist: python-telegram-bot==22.7
11
-
12
1
  # tinybot
13
2
 
14
3
  Minimal Python framework for building crypto bots.
@@ -34,6 +23,7 @@ bot = TinyBot(rpc_url, name="my bot")
34
23
 
35
24
  bot.listen(event="AuctionKicked", handler=on_kick, ...)
36
25
  bot.every(180, check_expired)
26
+ bot.cron("0 * * * *", hourly_check)
37
27
 
38
28
  await bot.run()
39
29
  ```
@@ -132,6 +122,19 @@ Handler signature: `async fn(bot)`
132
122
 
133
123
  ---
134
124
 
125
+ ### `bot.cron(expression, handler, name="", notify_errors=True) -> CronTask`
126
+
127
+ Register a cron-scheduled task. Uses standard cron expressions.
128
+
129
+ ```python
130
+ bot.cron("0 * * * *", notify_ending_soon) # every hour at :00
131
+ bot.cron("*/30 * * * *", check_something) # every 30 minutes
132
+ ```
133
+
134
+ Handler signature: `async fn(bot)`
135
+
136
+ ---
137
+
135
138
  ### `bot.get_listener(name) -> EventListener`
136
139
 
137
140
  Get a registered listener by name. Raises `ValueError` if not found.
@@ -178,14 +181,17 @@ tx_hash = bot.executor.execute(
178
181
  max_fee_gwei=100, # default: 100
179
182
  max_priority_fee_gwei=0, # default: 0
180
183
  simulate=True, # default: True — dry-run via eth_call before sending
184
+ wait=120, # default: 120 — seconds to wait for mining (0 = fire and forget)
181
185
  )
182
186
  ```
183
187
 
184
188
  - `executor.address` — signer address
185
189
  - `executor.balance` — signer ETH balance in wei
186
- - `executor.execute(call, ...)` — sign and broadcast a transaction, returns tx hash immediately (fire and forget)
190
+ - `executor.execute(call, ...)` — sign and broadcast a transaction, returns tx hash hex string
187
191
  - `gas_limit=0` (default) — auto-estimates gas with 1.5x buffer; pass a value to override
192
+ - `max_fee_gwei` / `max_priority_fee_gwei` — accept floats (e.g. `0.1`)
188
193
  - `simulate=True` (default) — runs `call.call()` first; reverts raise before the tx is sent
194
+ - `wait=120` (default) — wait up to N seconds for the tx to be mined; `0` for fire and forget
189
195
 
190
196
  ---
191
197
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tinybot-eth"
3
- version = "0.4.0"
3
+ version = "0.6.0"
4
4
  description = "Minimal Python framework for building crypto bots"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -9,6 +9,7 @@ dependencies = [
9
9
  "eth-abi==5.2.0",
10
10
  "eth-account==0.13.7",
11
11
  "python-telegram-bot==22.7",
12
+ "croniter==6.2.2",
12
13
  ]
13
14
 
14
15
  [tool.setuptools.packages.find]
@@ -8,7 +8,9 @@ from web3 import Web3
8
8
  from tinybot.executor import Executor
9
9
  from tinybot.state import State
10
10
  from tinybot.tg import DEV_GROUP_CHAT_ID, notify_group_chat
11
- from tinybot.types import EventHandler, EventListener, PeriodicTask, TaskHandler
11
+ from croniter import croniter
12
+
13
+ from tinybot.types import CronTask, EventHandler, EventListener, PeriodicTask, TaskHandler
12
14
  from tinybot.utils import event_id, event_signature
13
15
 
14
16
 
@@ -20,6 +22,7 @@ class TinyBot:
20
22
  self.executor = Executor(self.w3, private_key) if private_key else None
21
23
  self._listeners: list[EventListener] = []
22
24
  self._tasks: list[PeriodicTask] = []
25
+ self._crons: list[tuple[CronTask, croniter]] = []
23
26
 
24
27
  # -------------------------------------------------------------------------
25
28
  # Registration
@@ -77,6 +80,26 @@ class TinyBot:
77
80
  self._tasks.append(task)
78
81
  return task
79
82
 
83
+ def cron(
84
+ self,
85
+ expression: str,
86
+ handler: TaskHandler,
87
+ name: str = "",
88
+ notify_errors: bool = True,
89
+ ) -> CronTask:
90
+ name = name or handler.__name__
91
+ if any(task.name == name for task, _ in self._crons):
92
+ raise ValueError(f"cron '{name}' already registered")
93
+ task = CronTask(
94
+ name=name,
95
+ expression=expression,
96
+ handler=handler,
97
+ notify_errors=notify_errors,
98
+ )
99
+ cron = croniter(expression, datetime.now())
100
+ self._crons.append((task, cron))
101
+ return task
102
+
80
103
  # -------------------------------------------------------------------------
81
104
  # Getters
82
105
  # -------------------------------------------------------------------------
@@ -149,7 +172,7 @@ class TinyBot:
149
172
  except Exception as e:
150
173
  await self._handle_error(e, listener.name, listener.notify_errors)
151
174
 
152
- async def _poll_task(self, task: PeriodicTask) -> None:
175
+ async def _poll_periodic(self, task: PeriodicTask) -> None:
153
176
  now = time.time()
154
177
  if now - task._last_run < task.interval:
155
178
  return
@@ -160,6 +183,16 @@ class TinyBot:
160
183
  except Exception as e:
161
184
  await self._handle_error(e, task.name, task.notify_errors)
162
185
 
186
+ async def _poll_cron(self, task: CronTask, cron: croniter) -> None:
187
+ now = datetime.now()
188
+ next_run = cron.get_current(datetime)
189
+ if now >= next_run:
190
+ try:
191
+ await task.handler(self)
192
+ except Exception as e:
193
+ await self._handle_error(e, task.name, task.notify_errors)
194
+ cron.get_next(datetime)
195
+
163
196
  # -------------------------------------------------------------------------
164
197
  # Run
165
198
  # -------------------------------------------------------------------------
@@ -175,5 +208,7 @@ class TinyBot:
175
208
  for listener in self._listeners:
176
209
  await self._poll_listener(listener)
177
210
  for task in self._tasks:
178
- await self._poll_task(task)
211
+ await self._poll_periodic(task)
212
+ for task, cron in self._crons:
213
+ await self._poll_cron(task, cron)
179
214
  await asyncio.sleep(tick)
@@ -20,10 +20,11 @@ class Executor:
20
20
  self,
21
21
  call,
22
22
  gas_limit: int = 0,
23
- max_fee_gwei: int = 100,
24
- max_priority_fee_gwei: int = 0,
23
+ max_fee_gwei: float = 100,
24
+ max_priority_fee_gwei: float = 0,
25
25
  value: int = 0,
26
26
  simulate: bool = True,
27
+ wait: int = 120,
27
28
  ) -> str:
28
29
  if simulate:
29
30
  call.call({"from": self._account.address, "value": value})
@@ -43,4 +44,6 @@ class Executor:
43
44
  )
44
45
  signed = self._w3.eth.account.sign_transaction(tx, self._account.key)
45
46
  tx_hash = self._w3.eth.send_raw_transaction(signed.raw_transaction)
47
+ if wait > 0:
48
+ self._w3.eth.wait_for_transaction_receipt(tx_hash, timeout=wait)
46
49
  return tx_hash.hex()
@@ -44,3 +44,11 @@ class PeriodicTask:
44
44
  handler: TaskHandler
45
45
  notify_errors: bool = True
46
46
  _last_run: float = 0
47
+
48
+
49
+ @dataclass
50
+ class CronTask:
51
+ name: str
52
+ expression: str
53
+ handler: TaskHandler
54
+ notify_errors: bool = True
@@ -1,3 +1,15 @@
1
+ Metadata-Version: 2.4
2
+ Name: tinybot-eth
3
+ Version: 0.6.0
4
+ Summary: Minimal Python framework for building crypto bots
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: web3==7.14.1
8
+ Requires-Dist: eth-abi==5.2.0
9
+ Requires-Dist: eth-account==0.13.7
10
+ Requires-Dist: python-telegram-bot==22.7
11
+ Requires-Dist: croniter==6.2.2
12
+
1
13
  # tinybot
2
14
 
3
15
  Minimal Python framework for building crypto bots.
@@ -23,6 +35,7 @@ bot = TinyBot(rpc_url, name="my bot")
23
35
 
24
36
  bot.listen(event="AuctionKicked", handler=on_kick, ...)
25
37
  bot.every(180, check_expired)
38
+ bot.cron("0 * * * *", hourly_check)
26
39
 
27
40
  await bot.run()
28
41
  ```
@@ -121,6 +134,19 @@ Handler signature: `async fn(bot)`
121
134
 
122
135
  ---
123
136
 
137
+ ### `bot.cron(expression, handler, name="", notify_errors=True) -> CronTask`
138
+
139
+ Register a cron-scheduled task. Uses standard cron expressions.
140
+
141
+ ```python
142
+ bot.cron("0 * * * *", notify_ending_soon) # every hour at :00
143
+ bot.cron("*/30 * * * *", check_something) # every 30 minutes
144
+ ```
145
+
146
+ Handler signature: `async fn(bot)`
147
+
148
+ ---
149
+
124
150
  ### `bot.get_listener(name) -> EventListener`
125
151
 
126
152
  Get a registered listener by name. Raises `ValueError` if not found.
@@ -167,14 +193,17 @@ tx_hash = bot.executor.execute(
167
193
  max_fee_gwei=100, # default: 100
168
194
  max_priority_fee_gwei=0, # default: 0
169
195
  simulate=True, # default: True — dry-run via eth_call before sending
196
+ wait=120, # default: 120 — seconds to wait for mining (0 = fire and forget)
170
197
  )
171
198
  ```
172
199
 
173
200
  - `executor.address` — signer address
174
201
  - `executor.balance` — signer ETH balance in wei
175
- - `executor.execute(call, ...)` — sign and broadcast a transaction, returns tx hash immediately (fire and forget)
202
+ - `executor.execute(call, ...)` — sign and broadcast a transaction, returns tx hash hex string
176
203
  - `gas_limit=0` (default) — auto-estimates gas with 1.5x buffer; pass a value to override
204
+ - `max_fee_gwei` / `max_priority_fee_gwei` — accept floats (e.g. `0.1`)
177
205
  - `simulate=True` (default) — runs `call.call()` first; reverts raise before the tx is sent
206
+ - `wait=120` (default) — wait up to N seconds for the tx to be mined; `0` for fire and forget
178
207
 
179
208
  ---
180
209
 
@@ -2,3 +2,4 @@ web3==7.14.1
2
2
  eth-abi==5.2.0
3
3
  eth-account==0.13.7
4
4
  python-telegram-bot==22.7
5
+ croniter==6.2.2
File without changes
File without changes