Skip to content
This repository was archived by the owner on Mar 18, 2026. It is now read-only.

Commit dc98514

Browse files
authored
Merge pull request #617 from aibtcdev/fix/safe-int-conversion
safe int conversion in lottery
2 parents bfec0e2 + 8284b0b commit dc98514

2 files changed

Lines changed: 17 additions & 72 deletions

File tree

‎app/services/integrations/webhooks/chainhook/handlers/action_proposal_handler.py‎

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,18 @@ def _sanitize_string(self, input_string: Optional[str]) -> Optional[str]:
405405

406406
return sanitized
407407

408+
def _to_safe_int(self, value: Optional[str]) -> int:
409+
"""Safely convert string to int, handling float strings via int(float()) with fallback to 0."""
410+
if value is None or value.strip() == "":
411+
return 0
412+
try:
413+
return int(float(value.strip()))
414+
except (ValueError, TypeError) as e:
415+
self.logger.warning(
416+
f"Failed to parse '{value}' as int: {e}, defaulting to 0"
417+
)
418+
return 0
419+
408420
def _get_agent_token_holders(self, dao_id: UUID) -> List[AgentWithWalletTokenDTO]:
409421
"""Get agents that hold tokens for the given DAO.
410422
@@ -447,13 +459,7 @@ def _conduct_quorum_lottery(
447459
Returns:
448460
LotterySelection: Complete lottery results with quorum tracking
449461
"""
450-
try:
451-
_ = int(proposal_liquid_tokens or "0")
452-
except ValueError as e:
453-
self.logger.warning(
454-
f"Invalid proposal_liquid_tokens '{proposal_liquid_tokens}': {e} - returning empty selection"
455-
)
456-
return LotterySelection()
462+
self._to_safe_int(proposal_liquid_tokens)
457463

458464
selection = LotterySelection()
459465

@@ -466,7 +472,7 @@ def _conduct_quorum_lottery(
466472
filtered_agents = [
467473
agent
468474
for agent in agents_with_tokens
469-
if int(agent.token_amount or "0") >= min_threshold
475+
if self._to_safe_int(agent.token_amount) >= min_threshold
470476
]
471477
total_filtered = len(filtered_agents)
472478
total_original = len(agents_with_tokens)
@@ -535,7 +541,7 @@ def _conduct_quorum_lottery(
535541
)
536542
selection.selected_wallets.append(wallet_dict)
537543

538-
selected_tokens += Decimal(selected_agent.token_amount)
544+
selected_tokens += Decimal(self._to_safe_int(selected_agent.token_amount))
539545

540546
self.logger.debug(
541547
f"Round {round_number}: Selected agent {selected_agent.agent_id} "
@@ -566,7 +572,7 @@ def _conduct_quorum_lottery(
566572
)
567573
selection.selected_wallets.append(wallet_dict)
568574

569-
selected_tokens += Decimal(selected_agent.token_amount)
575+
selected_tokens += Decimal(self._to_safe_int(selected_agent.token_amount))
570576

571577
# Update final totals
572578
selection.total_selected_tokens = str(selected_tokens)
@@ -586,7 +592,7 @@ def _perform_weighted_selection(
586592
self, remaining_agents: List[AgentWithWalletTokenDTO]
587593
) -> AgentWithWalletTokenDTO:
588594
"""Perform a single round of weighted random agent selection (assumes random is seeded)."""
589-
weights = [int(agent.token_amount or "0") for agent in remaining_agents]
595+
weights = [self._to_safe_int(agent.token_amount) for agent in remaining_agents]
590596
if not weights or all(w == 0 for w in weights):
591597
self.logger.warning("All remaining weights are zero, using equal weights")
592598
weights = [1] * len(remaining_agents)

‎app/services/integrations/webhooks/chainhook/handlers/lottery_utils.py‎

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -56,67 +56,6 @@ def calculate_total_eligible_tokens(
5656
logger.error(f"Error calculating total eligible tokens: {e}")
5757
return "0"
5858

59-
@staticmethod
60-
def is_quorum_achievable(
61-
liquid_tokens: str, total_eligible_tokens: str, quorum_percentage: float = 0.15
62-
) -> bool:
63-
"""Check if quorum is achievable with available tokens.
64-
65-
Args:
66-
liquid_tokens: Total liquid supply
67-
total_eligible_tokens: Total tokens held by eligible agents
68-
quorum_percentage: Required quorum percentage
69-
70-
Returns:
71-
True if quorum is achievable, False otherwise
72-
"""
73-
try:
74-
quorum_threshold = QuorumCalculator.calculate_quorum_threshold(
75-
liquid_tokens, quorum_percentage
76-
)
77-
return Decimal(total_eligible_tokens) >= Decimal(quorum_threshold)
78-
except (ValueError, TypeError) as e:
79-
logger.error(f"Error checking quorum achievability: {e}")
80-
return False
81-
82-
@staticmethod
83-
def calculate_selected_tokens_total(selected_wallets: List[Dict[str, str]]) -> str:
84-
"""Calculate total tokens from selected wallets.
85-
86-
Args:
87-
selected_wallets: List of {"wallet_id": str, "token_amount": str} dicts
88-
89-
Returns:
90-
Total selected tokens as string
91-
"""
92-
try:
93-
total = Decimal("0")
94-
for wallet in selected_wallets:
95-
total += Decimal(wallet.get("token_amount", "0"))
96-
return str(total)
97-
except (ValueError, TypeError) as e:
98-
logger.error(f"Error calculating selected tokens total: {e}")
99-
return "0"
100-
101-
@staticmethod
102-
def validate_quorum_achievement(
103-
selected_tokens_total: str, quorum_threshold: str
104-
) -> bool:
105-
"""Check if selected tokens meet the quorum threshold.
106-
107-
Args:
108-
selected_tokens_total: Total tokens from selected wallets
109-
quorum_threshold: Required threshold to meet quorum
110-
111-
Returns:
112-
True if quorum is achieved, False otherwise
113-
"""
114-
try:
115-
return Decimal(selected_tokens_total) >= Decimal(quorum_threshold)
116-
except (ValueError, TypeError) as e:
117-
logger.error(f"Error validating quorum achievement: {e}")
118-
return False
119-
12059

12160
class LotterySelection:
12261
"""Data class to hold lottery selection results."""

0 commit comments

Comments
 (0)