Skip to content

Commit

Permalink
Add POW Monitoring Discord Bot (#2)
Browse files Browse the repository at this point in the history
* Add POW Monitoring Discord Bot

* Change Arbiscan api key placement

* Add POW github action

* Refactor variable name for OSS
  • Loading branch information
Rodebrechtd authored Sep 25, 2024
1 parent ce59a78 commit 62189f2
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 18 deletions.
10 changes: 4 additions & 6 deletions .github/workflows/oss_issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ name: Get all community open issues
on:
schedule:
- cron: '0 16 * * 1,5'
jobs:

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Build the Docker image
- name: Build the Docker image and get all community open issues
env:
DISCORD_WEBHOOK: ${{ secrets.OSS_DISCORD_WEBHOOK }}
run: docker compose run --env DISCORD_WEBHOOK=$DISCORD_WEBHOOK --entrypoint "sh -c 'python3 oss_issues.py'" lilypad_assistant
OSS_DISCORD_WEBHOOK: ${{ secrets.OSS_DISCORD_WEBHOOK }}
run: docker compose run --env OSS_DISCORD_WEBHOOK=$OSS_DISCORD_WEBHOOK --entrypoint "sh -c 'python3 oss_issues.py'" lilypad_assistant
10 changes: 5 additions & 5 deletions .github/workflows/oss_leaderboard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ name: Generate Community Leaderboard
on:
schedule:
- cron: '0 16 * * 3,0'
jobs:

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Build the Docker image
- name: Build the Docker image and generate community leaderboard

env:
DISCORD_WEBHOOK: ${{ secrets.OSS_DISCORD_WEBHOOK }}
run: docker compose run --env DISCORD_WEBHOOK=$DISCORD_WEBHOOK --entrypoint "sh -c 'python3 oss_leaderboard.py'" lilypad_assistant
OSS_DISCORD_WEBHOOK: ${{ secrets.OSS_DISCORD_WEBHOOK }}
run: docker compose run --env OSS_DISCORD_WEBHOOK=$OSS_DISCORD_WEBHOOK --entrypoint "sh -c 'python3 oss_leaderboard.py'" lilypad_assistant
21 changes: 21 additions & 0 deletions .github/workflows/pow_monitoring.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: POW Monitoring

on:
schedule:
- cron: '5 * * * *' # Runs every 5 minutes past each hour

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build the Docker image and monitor POW address
env:
POW_DISCORD_WEBHOOK: ${{ secrets.POW_DISCORD_WEBHOOK }}
ARBISCAN_API_KEY: ${{ secrets.ARBISCAN_API_KEY }}
run: |
docker compose run \
--env POW_DISCORD_WEBHOOK=$POW_DISCORD_WEBHOOK \
--env ARBISCAN_API_KEY=$ARBISCAN_API_KEY \
--entrypoint "sh -c 'python3 pow_monitoring.py'" \
lilypad_assistant
6 changes: 3 additions & 3 deletions oss_issues.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import random
from utils.git import fetch_all_issues
from utils.discord import send_discord_message
from vars import DISCORD_WEBHOOK, GIT_API_URL
from vars import OSS_DISCORD_WEBHOOK, GIT_API_URL

# GitHub
params_open = {'state': 'open', 'per_page': 100, 'page': 1}
Expand Down Expand Up @@ -63,7 +63,7 @@ def process_open_issues():
"\n\n" +
format_issues(community_assigned_issues, "**Assigned**"))

send_discord_message(DISCORD_WEBHOOK, open_issues_message)
send_discord_message(OSS_DISCORD_WEBHOOK, open_issues_message)

# Process open issues
process_open_issues()
process_open_issues()
6 changes: 3 additions & 3 deletions oss_leaderboard.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections import defaultdict
from utils.git import fetch_all_issues
from utils.discord import send_discord_message
from vars import DISCORD_WEBHOOK, GIT_API_URL
from vars import OSS_DISCORD_WEBHOOK, GIT_API_URL

# GitHub
params_closed = {'state': 'closed', 'per_page': 100, 'page': 1}
Expand Down Expand Up @@ -71,6 +71,6 @@ def generate_leaderboard():
sorted_assignees = sorted(solved_issues_by_assignee.items(), key=lambda x: x[1], reverse=True)

leaderboard_message = format_leaderboard_with_progress(sorted_assignees)
send_discord_message(DISCORD_WEBHOOK, leaderboard_message)
send_discord_message(OSS_DISCORD_WEBHOOK, leaderboard_message)

generate_leaderboard()
generate_leaderboard()
108 changes: 108 additions & 0 deletions pow_monitoring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import requests
from datetime import datetime, timezone
from utils.discord import send_discord_message
from vars import (
POW_MONITORING_WEBHOOK,
LILYTEAM_DISCORD_ROLE,
LILYPAD_ADVOCATE_DISCORD_ROLE,
POW_CONTRACT_ADDRESS,
POW_CONTRACT_ADDRESS_URL,
ARBISCAN_API_KEY,
ARBISCAN_API_ENDPOINT
)

# Constants to set the warning and error thresholds for time since the last transaction
warning_threshold_minutes = 60 # Time in minutes to trigger a warning
error_threshold_minutes = 120 # Time in minutes to trigger an error

# Discord roles that will be tagged in the message
discord_roles = f"{LILYTEAM_DISCORD_ROLE}, {LILYPAD_ADVOCATE_DISCORD_ROLE}"

def get_latest_transaction_time():
"""
Fetch the latest transaction timestamp from the Etherscan API for the given contract address.
Returns the timestamp as a datetime object if successful, or None if an error occurs.
"""
# Parameters for querying the Etherscan API to get the list of transactions for a specific address
params = {
'module': 'account',
'action': 'txlist',
'address': POW_CONTRACT_ADDRESS, # Contract address for the Lilypad POW
'startblock': 0, # Start from the first block
'endblock': 99999999, # End at the latest block
'sort': 'desc', # Sort transactions by newest first
'apikey': ARBISCAN_API_KEY # API key for authenticating the request
}

# Make the request to Etherscan API
response = requests.get(ARBISCAN_API_ENDPOINT, params=params)

if response.status_code == 200: # Check if the API call was successful
data = response.json() # Parse the JSON response

# If status is '1' (success) and transactions are available
if data['status'] == '1' and len(data['result']) > 0:
latest_tx = data['result'][0] # Get the latest transaction (first one in the sorted list)
timestamp = int(latest_tx['timeStamp']) # Extract the timestamp from the transaction data
return datetime.fromtimestamp(timestamp, tz=timezone.utc) # Convert timestamp to datetime object
else:
print("No transactions found for this address.")
return None
else:
# Print an error message if the API request fails
print("Error fetching data from Etherscan.")
return None

def format_time_difference(seconds):
"""
Format the time difference in seconds into a more human-readable form (minutes and seconds).
"""
minutes = seconds // 60 # Convert total seconds to minutes
remaining_seconds = seconds % 60 # Get the remaining seconds after the minutes
return f"{int(minutes)} minutes and {int(remaining_seconds)} seconds" # Return formatted string

def monitor_transactions():
"""
Monitors the latest transaction time of the Lilypad POW contract.
Sends a Discord message if the time since the last transaction exceeds specified thresholds.
"""
# Get the timestamp of the latest transaction
latest_transaction_time = get_latest_transaction_time()

if latest_transaction_time is None: # Exit if there was an issue fetching the transaction
return

# Get the current time in UTC
current_time = datetime.now(timezone.utc)

# Calculate the difference between the current time and the time of the last transaction
time_diff = current_time - latest_transaction_time
total_seconds_since_last_tx = time_diff.total_seconds() # Get the difference in total seconds

# Info message to include with the alerts, contains the contract URL and Discord roles to tag
info_message = f"Lilypad POW Contract Address: {POW_CONTRACT_ADDRESS_URL} \n {discord_roles}"

# Check if the time since the last transaction exceeds the error threshold
if total_seconds_since_last_tx > error_threshold_minutes * 60:
error_message = f"**ERROR**: Last transaction was {format_time_difference(total_seconds_since_last_tx)} ago"
print(error_message) # Print error message
# Send an error alert to the specified Discord webhook
send_discord_message(POW_MONITORING_WEBHOOK, f"🔴 {error_message} \n {info_message}")

# Check if the time since the last transaction exceeds the warning threshold
elif total_seconds_since_last_tx > warning_threshold_minutes * 60:
warning_message = f"**WARNING**: Last transaction was {format_time_difference(total_seconds_since_last_tx)} ago"
print(warning_message) # Print warning message
# Send a warning alert to the specified Discord webhook
send_discord_message(POW_MONITORING_WEBHOOK, f"⚠️ {warning_message} \n {info_message}")

else:
# If the time since the last transaction is within acceptable limits
ok_message = f"**OK**: Last transaction was {format_time_difference(total_seconds_since_last_tx)} ago."
print(ok_message) # Print OK message
# Send an OK alert to the specified Discord webhook
send_discord_message(POW_MONITORING_WEBHOOK, f"🟢 {ok_message}")

# If this script is run directly, call the monitor_transactions function
if __name__ == "__main__":
monitor_transactions()
13 changes: 12 additions & 1 deletion vars.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,15 @@
GIT_API_URL = "https://api.github.com/repos/Lilypad-Tech/lilypad/issues"

# Discord webhook URL (you can set your actual webhook URL here)
DISCORD_WEBHOOK = os.getenv('DISCORD_WEBHOOK')
OSS_DISCORD_WEBHOOK = os.getenv('OSS_DISCORD_WEBHOOK')
POW_MONITORING_WEBHOOK = os.getenv('POW_DISCORD_WEBHOOK')

# Discord Roles
LILYTEAM_DISCORD_ROLE = "<@&1212902935969669140>"
LILYPAD_ADVOCATE_DISCORD_ROLE = "<@&1255696024161226783>"

# Arbiscan
ARBISCAN_API_KEY = os.getenv('ARBISCAN_API_KEY')
ARBISCAN_API_ENDPOINT = f'https://api-sepolia.arbiscan.io/api'
POW_CONTRACT_ADDRESS = "0x8b852ba45293d6dd51b10c57625c6c5f25adfb40"
POW_CONTRACT_ADDRESS_URL = f"https://sepolia.arbiscan.io/address/{POW_CONTRACT_ADDRESS}"

0 comments on commit 62189f2

Please sign in to comment.