Automating Holozing reward claims

in #holozing6 hours ago (edited)

Screenshot 2025-01-12 at 21.10.43.png

That's me in HIVE universe

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. :) .

Sort:  

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. :)