If you have some stake at Holozing, and tired about claiming your rewards, automation is your friend.
import json
import requests
import time
from beem import Hive
from beemgraphenebase.ecdsasig import sign_message
from beemgraphenebase.account import PrivateKey
from binascii import hexlify
from dotenv import load_dotenv
import os
import logging
load_dotenv()
# Set up logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class HolozingClient:
def __init__(self, username: str, posting_key: str):
self.username = username
self.posting_key = posting_key
self.jwt_token = None
self.hive = Hive(keys=[posting_key])
def check_pending_rewards(self) -> dict:
"""Check if there are any pending rewards before attempting to claim"""
url = f"https://api.holozing.com/rewards/pending?user={self.username}"
headers = {
'accept': 'application/json, text/plain, */*',
'origin': 'https://holozing.com',
'referer': 'https://holozing.com/'
}
try:
response = requests.get(url, headers=headers)
data = response.json()
total_rewards = (
float(data.get('delegation', '0')) +
float(data.get('stakeZing', '0')) +
float(data.get('holdingRewards', '0'))
)
logger.info(f"Rewards check for {self.username}:")
logger.info(f"Delegation: {data.get('delegation')} ZING")
logger.info(f"Stake: {data.get('stakeZing')} ZING")
logger.info(f"Holding: {data.get('holdingRewards')} ZING")
logger.info(f"Total: {total_rewards} ZING")
return {'total': total_rewards, 'data': data}
except Exception as e:
logger.error(f"Failed to check rewards: {str(e)}")
return {'total': 0, 'data': None}
def login(self) -> bool:
try:
login_result = self._login_to_holozing()
self.jwt_token = login_result.get('jwt')
return bool(self.jwt_token)
except Exception as e:
logger.error(f"Login failed: {str(e)}")
return False
def _login_to_holozing(self):
expiry = int(time.time()) + 86400
message = {
"username": self.username,
"type": "login",
"app": "holozing",
"expiry": expiry
}
message_str = json.dumps(message)
private_key = PrivateKey(self.posting_key)
signature_bytes = sign_message(message_str, private_key)
signature = hexlify(signature_bytes).decode('ascii')
login_url = "https://api.holozing.com/login/hive"
headers = {
"accept": "application/json, text/plain, */*",
"content-type": "application/json",
"origin": "https://holozing.com",
"referer": "https://holozing.com/"
}
payload = {
"success": True,
"error": None,
"result": signature,
"data": {
"type": "signBuffer",
"username": self.username,
"message": message_str,
"method": "Posting",
"rpc": None,
"title": "Login to HoloZing",
"key": "posting"
},
"message": "Message signed successfully.",
"request_id": 2
}
response = requests.post(login_url, json=payload, headers=headers)
return response.json()
def claim_rewards(self) -> bool:
"""
Claim rewards using the JWT token
"""
if not self.jwt_token:
logger.error(f"No JWT token available for {self.username}")
return False
url = "https://api.holozing.com/rewards/pending"
headers = {
"accept": "application/json, text/plain, */*",
"content-type": "application/json",
"authorization": f"Bearer {self.jwt_token}",
"origin": "https://holozing.com",
"referer": "https://holozing.com/",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
}
try:
response = requests.post(url, json={}, headers=headers)
if response.status_code == 200:
logger.info(f"Successfully claimed rewards for {self.username}")
return True
else:
logger.error(f"Failed to claim rewards for {self.username}. Status: {response.status_code}")
logger.error(f"Response: {response.text}")
return False
except Exception as e:
logger.error(f"Error claiming rewards for {self.username}: {str(e)}")
return False
def main():
username = "emrebeyler"
posting_key = os.getenv('HOLOZING_ACCOUNT_POSTING_KEY')
if not all([username, posting_key]):
logger.error("Missing credentials in environment variables")
return
client = HolozingClient(username, posting_key)
# First check if there are any rewards
rewards = client.check_pending_rewards()
if rewards['total'] <= 0:
logger.info("No rewards available to claim")
return
# Only proceed with login and claim if there are rewards
logger.info("Found claimable rewards. Proceeding with claim process...")
if client.login():
client.claim_rewards()
else:
logger.error("Failed to login for claiming")
if __name__ == "__main__":
main()
Required packages:
beem>=0.24.26
requests>=2.31.0
python-dotenv>=1.0.0
create .env file in the script, put your posting key as HOLOZING_POSTING_KEY=...
, edut username with your username, then just run the script. Basic knowledge about running python scripts and python environments are required.
P.S: Most of the code is written by Cursor AI Editor, can only get credits by giving it correct and clear directions. :) .
It's so good that I saw this post exactly after I did a manual claim haha. To be honest, unlike in the early days when the game was announced, I sometimes forget to claim rewards for days, so this will come in handy. Even if it does it once a day, it's enough 😂
Next days, when my new Raspi 5 16GB is arriving - i'll set up some DePin Projects and probably will take the chance to let a bunch of automation scripts running.
thanks for sharing!
Enjoy, a good use case for a RaspberryPI. :)