Created
April 1, 2025 10:39
-
-
Save janklimo/14f2c4ed60127963936b26b4c8dd128e to your computer and use it in GitHub Desktop.
HL lucky draw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import pandas as pd | |
| import requests | |
| import numpy as np | |
| from typing import Dict, Tuple | |
| class LuckyDrawSelector: | |
| def __init__( | |
| self, | |
| ): | |
| self.comment_multiplier = 1.3 | |
| self.retweet_multiplier = 1.5 | |
| def get_staked_balance(self, wallet_address: str) -> float: | |
| api_url = "https://api.hyperliquid.xyz/info" | |
| payload = {"type": "delegations", "user": wallet_address} | |
| try: | |
| response = requests.post( | |
| api_url, headers={"Content-Type": "application/json"}, json=payload | |
| ) | |
| response.raise_for_status() | |
| data = response.json() | |
| # Find the delegation for PurrposefulNode | |
| target_validator = "0xf8efb4cb844a8458114994203d7b0bfe2422a288" | |
| for delegation in data: | |
| if delegation["validator"] == target_validator: | |
| return float(delegation["amount"]) | |
| return 0.0 | |
| except Exception as e: | |
| print(f"Error fetching staked balance for {wallet_address}: {e}") | |
| return 0.0 | |
| def calculate_score( | |
| self, staked_amount: float, has_comment: bool, has_retweet: bool | |
| ) -> float: | |
| # Quadratic voting principle: score is proportional to square root of staked amount | |
| # This gives smaller stakers more representation | |
| base_score = np.sqrt(staked_amount) | |
| # Apply social action multipliers | |
| if has_comment: | |
| base_score *= self.comment_multiplier | |
| if has_retweet: | |
| base_score *= self.retweet_multiplier | |
| return base_score | |
| def load_participant_data(self, file_path: str) -> pd.DataFrame: | |
| try: | |
| df = pd.read_csv(file_path) | |
| return df | |
| except Exception as e: | |
| raise Exception(f"Error loading participant data: {e}") | |
| def process_participants(self, participants_df: pd.DataFrame) -> pd.DataFrame: | |
| result_df = participants_df.copy() | |
| result_df["staked_amount"] = result_df["address"].apply(self.get_staked_balance) | |
| # Calculate scores using quadratic voting principle | |
| result_df["score"] = result_df.apply( | |
| lambda row: self.calculate_score( | |
| row["staked_amount"], row["commented"], row["retweeted"] | |
| ), | |
| axis=1, | |
| ) | |
| # Calculate win chances (normalized weights) | |
| valid_participants = result_df[result_df["score"] > 0] | |
| weights = valid_participants["score"].values | |
| normalized_weights = ( | |
| weights / pd.Series(weights).sum() | |
| ) # Normalize to probabilities | |
| # Create a chance column, default to 0 for participants with 0 score | |
| result_df["chance"] = 0.0 | |
| result_df.loc[valid_participants.index, "chance"] = normalized_weights | |
| return result_df | |
| def select_winner(self, scores_df: pd.DataFrame) -> str: | |
| valid_participants = scores_df[scores_df["score"] > 0] | |
| weights = valid_participants["score"].values | |
| weights = weights / pd.Series(weights).sum() # Normalize to probabilities | |
| # Select winner using weighted random choice | |
| winner_index = np.random.choice(valid_participants.index, size=1, p=weights)[0] | |
| winner_row = valid_participants.loc[winner_index] | |
| return winner_row["address"] | |
| def run_lucky_draw(self, file_path: str) -> Dict: | |
| # Load and process data | |
| participants_df = self.load_participant_data(file_path) | |
| processed_df = self.process_participants(participants_df) | |
| # Print statistics | |
| total_participants = len(processed_df) | |
| total_staked = processed_df["staked_amount"].sum() | |
| print(f"Total participants: {total_participants}") | |
| print(f"Total staked amount: {total_staked:.4f} HYPE") | |
| print(f"Average stake: {total_staked / total_participants:.4f} HYPE") | |
| # Print dataset with trimmed addresses | |
| print("\nParticipant Data:") | |
| display_df = processed_df.copy() | |
| display_df["address"] = display_df["address"].apply( | |
| lambda x: f"{x[:6]}...{x[-4:]}" | |
| ) | |
| # Format chance as percentage with 2 decimal places | |
| display_df["chance"] = (display_df["chance"] * 100).round(2).astype(str) + "%" | |
| print(display_df.to_string(index=False)) | |
| # Select winner | |
| winner_address = self.select_winner(processed_df) | |
| winner_data = ( | |
| processed_df[processed_df["address"] == winner_address].iloc[0].to_dict() | |
| ) | |
| return winner_data | |
| def main(): | |
| selector = LuckyDrawSelector() | |
| print(f"\n===== Running Lucky Draw =====") | |
| winner = selector.run_lucky_draw("data.csv") | |
| winner_address = winner["address"] | |
| formatted_address = f"{winner_address[:6]}...{winner_address[-4:]}" | |
| print( | |
| f"\nThe winner is {formatted_address} ({winner['username']}). Congratulations 🎉" | |
| ) | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment