Skip to content

Commit b2f1d57

Browse files
authored
feat(safe): halve API calls and rotate keys
2 parents 7a1ce9f + 639a23d commit b2f1d57

3 files changed

Lines changed: 17 additions & 23 deletions

File tree

.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ AAVE_ALERT_THRESHOLD=0.95
3636
AAVE_CRITICAL_THRESHOLD=0.98
3737
AAVE_ENABLE_NOTIFICATIONS=true
3838

39-
# Safe
39+
# Safe (two keys rotated to stay within API rate limits)
4040
SAFE_API_KEY=your-api-key
41+
SAFE_API_KEY_2=your-second-api-key
4142

4243
# Tenderly (for transaction simulation)
4344
TENDERLY_API_KEY=your-tenderly-api-key

.github/workflows/_run-monitoring.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ env:
121121
COINGECKO_API_KEY: ${{ secrets.COINGECKO_API_KEY }}
122122
TENDERLY_API_KEY: ${{ secrets.TENDERLY_API_KEY }}
123123
SAFE_API_KEY: ${{ secrets.SAFE_API_KEY }}
124+
SAFE_API_KEY_2: ${{ secrets.SAFE_API_KEY_2 }}
124125
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
125126
LLM_MODEL: ${{ secrets.LLM_MODEL }}
126127
LLM_PROVIDER: ${{ secrets.LLM_PROVIDER }}

safe/main.py

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import itertools
12
import os
23
import time
34

@@ -21,6 +22,12 @@
2122
provider_url_mainnet = os.getenv("PROVIDER_URL_MAINNET")
2223
provider_url_arb = os.getenv("PROVIDER_URL_ARBITRUM")
2324

25+
# Round-robin iterator over available Safe API keys.
26+
_api_keys: list[str] = [k for k in [os.getenv("SAFE_API_KEY"), os.getenv("SAFE_API_KEY_2")] if k]
27+
if not _api_keys:
28+
raise ValueError("At least one SAFE_API_KEY must be set.")
29+
_api_key_cycle = itertools.cycle(_api_keys)
30+
2431
safe_address_network_prefix = {
2532
"mainnet": "eth",
2633
"arbitrum-main": "arb1",
@@ -188,9 +195,7 @@ def get_safe_transactions(
188195
if executed is not None:
189196
params["executed"] = str(executed).lower()
190197

191-
api_key = os.getenv("SAFE_API_KEY")
192-
if not api_key:
193-
raise ValueError("SAFE_API_KEY environment variable not set.")
198+
api_key = next(_api_key_cycle)
194199

195200
headers = {
196201
"Authorization": f"Bearer {api_key}",
@@ -230,36 +235,23 @@ def get_safe_transactions(
230235
return []
231236

232237

233-
def get_last_executed_nonce(safe_address: str, network_name: str) -> int:
234-
executed_txs = get_safe_transactions(safe_address, network_name, executed=True, limit=1)
235-
if executed_txs:
236-
return int(executed_txs[0]["nonce"])
237-
return -1 # Return -1 if no executed transactions found
238-
239-
240-
def get_pending_transactions_after_last_executed(safe_address: str, network_name: str) -> list[dict]:
241-
last_executed_nonce = get_last_executed_nonce(safe_address, network_name)
238+
def get_pending_transactions(safe_address: str, network_name: str) -> list[dict]:
239+
"""Fetch pending transactions with nonce higher than the last cached nonce."""
240+
last_cached_nonce = get_last_executed_nonce_from_file(safe_address)
242241
pending_txs = get_safe_transactions(safe_address, network_name, executed=False)
243-
244-
if pending_txs:
245-
return [tx for tx in pending_txs if int(tx["nonce"]) > last_executed_nonce]
246-
return []
242+
return [tx for tx in pending_txs if int(tx["nonce"]) > last_cached_nonce]
247243

248244

249245
def get_safe_url(safe_address: str, network_name: str) -> str:
250246
return f"{SAFE_WEBSITE_URL}{safe_address_network_prefix[network_name]}:{safe_address}"
251247

252248

253249
def check_for_pending_transactions(safe_address: str, network_name: str, protocol: str) -> None:
254-
pending_transactions = get_pending_transactions_after_last_executed(safe_address, network_name)
250+
pending_transactions = get_pending_transactions(safe_address, network_name)
255251

256252
if pending_transactions:
257253
for tx in pending_transactions:
258254
nonce = int(tx["nonce"])
259-
# skip tx if the nonce is already processed
260-
if nonce <= get_last_executed_nonce_from_file(safe_address):
261-
logger.info("Skipping tx with nonce %s as it is already processed.", nonce)
262-
continue
263255

264256
target_contract = tx["to"]
265257

@@ -355,7 +347,7 @@ def main():
355347
logger.info("Running for %s on %s", safe[0], safe[1])
356348
last_api_call_time, request_counter = check_api_limit(last_api_call_time, request_counter)
357349
run_for_network(safe[1], safe[2], safe[0])
358-
request_counter += 2
350+
request_counter += 1
359351

360352

361353
if __name__ == "__main__":

0 commit comments

Comments
 (0)