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

Commit add2df7

Browse files
committed
use default bribe platform from config, paladin integration adjusments
1 parent 887c614 commit add2df7

8 files changed

Lines changed: 60 additions & 208 deletions

File tree

fee_allocator/accounting/chains.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ def _init_alliance_pools(self) -> None:
249249
continue
250250

251251
tvl_threshold = thresholds.v2_min_tvl if protocol_version == 2 else thresholds.v3_min_tvl
252-
253-
if tvl_threshold == 0:
252+
253+
if tvl_threshold == 0 or pool.auto_include:
254254
self.alliance_pools.append(pool)
255255
logger.info(f"v{protocol_version} Alliance pool: {pool.pool_id} added as alliance pool")
256256
continue

fee_allocator/accounting/core_pools.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def __init__(self, data: PoolFeeData, chain: CorePoolChain):
9696

9797
self.voting_pool_override = self._get_voting_pool_override()
9898
self.market_override = self._get_market_override()
99-
99+
100100
self.original_earned_fee_share = Decimal(0)
101101
self.earned_fee_share_of_chain_usd = self._earned_fee_share_of_chain_usd()
102102
self.total_to_incentives_usd = self._total_to_incentives_usd()
@@ -138,10 +138,10 @@ def _get_partner_info(self):
138138
def _get_voting_pool_override(self):
139139
pool_override = self.chain.chains.pool_overrides.get(self.pool_id)
140140
return pool_override.voting_pool_override if pool_override else None
141-
142-
def _get_market_override(self) -> str:
141+
142+
def _get_market_override(self):
143143
pool_override = self.chain.chains.pool_overrides.get(self.pool_id)
144-
return pool_override.market_override if pool_override else "hh"
144+
return pool_override.market_override if pool_override else None
145145

146146

147147
def _earned_fee_share_of_chain_usd(self) -> Decimal:

fee_allocator/accounting/models.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111

1212
class PoolOverride(BaseModel):
1313
"""
14-
Represents pool-specific overrides for voting pool and market platforms.
14+
Represents pool-specific overrides for voting pool allocation and bribe platform.
1515
"""
16-
voting_pool_override: Optional[str] = None # "bal" or "aura"
17-
market_override: str = "hh" # "hh" (HiddenHand) or "paladin" (Paladin Quest)
16+
voting_pool_override: Optional[str] = None # "bal", "aura", or "split"
17+
market_override: Optional[str] = None # "stakedao" or "paladin" to override default routing
1818

1919

2020
class GlobalFeeConfig(BaseModel):
@@ -39,6 +39,10 @@ class GlobalFeeConfig(BaseModel):
3939
# Beets fee split (https://forum.balancer.fi/t/bip-800-deploy-balancer-v3-on-op-mainnet)
4040
beets_share_pct: Decimal
4141

42+
# Default bribe platforms (can be overridden per-pool via market_override)
43+
bal_bribe_platform: str = "hh"
44+
aura_bribe_platform: str = "hh"
45+
4246
@model_validator(mode="after")
4347
def set_dynamic_min_aura_incentive(self):
4448
self.min_aura_incentive = int(HiddenHand().get_min_aura_incentive())
@@ -54,6 +58,7 @@ class AlliancePool(BaseModel):
5458
partner: str
5559
eligibility_date: str
5660
active: bool
61+
auto_include: bool = False
5762

5863

5964
class AllianceMember(BaseModel):
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from .base import BribePlatform
2-
from .factory import BribePlatformFactory
2+
from .factory import get_platform
33
from .hiddenhand import HiddenHandPlatform
44
from .paladin import PaladinPlatform
55
from .stakedao import StakeDAOPlatform
66

77
__all__ = [
88
"BribePlatform",
9-
"BribePlatformFactory",
9+
"get_platform",
1010
"HiddenHandPlatform",
1111
"PaladinPlatform",
1212
"StakeDAOPlatform",
13-
]
13+
]
Lines changed: 20 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,26 @@
1-
from typing import Dict, Any, List
1+
from typing import Dict, Any
22
from .base import BribePlatform
33
from .hiddenhand import HiddenHandPlatform
44
from .paladin import PaladinPlatform
55
from .stakedao import StakeDAOPlatform
66

77

8-
class BribePlatformFactory:
9-
"""Factory for creating bribe platform instances based on configuration"""
10-
11-
_platforms = {
12-
"hh": HiddenHandPlatform,
13-
"paladin": PaladinPlatform,
14-
"stakedao": StakeDAOPlatform,
15-
}
16-
17-
@classmethod
18-
def register_platform(cls, config_key: str, platform_class: type):
19-
"""
20-
Register a new platform class
21-
22-
Args:
23-
config_key: The configuration key (e.g., 'hh', 'paladin', 'stakedao')
24-
platform_class: The platform class that implements BribePlatform
25-
"""
26-
cls._platforms[config_key] = platform_class
27-
28-
@classmethod
29-
def get_platform(cls, platform_name: str, book: Dict[str, str], run_config: Any) -> BribePlatform:
30-
"""
31-
Get platform instance based on platform name
32-
33-
Args:
34-
platform_name: Platform name ('hh', 'paladin', 'stakedao')
35-
book: Address book dictionary
36-
run_config: Run configuration object
37-
38-
Returns:
39-
BribePlatform instance
40-
41-
Raises:
42-
ValueError: If platform_name is not recognized
43-
"""
44-
if not platform_name or platform_name == "hh":
45-
return HiddenHandPlatform(book, run_config)
46-
47-
platform_class = cls._platforms.get(platform_name)
48-
if not platform_class:
49-
raise ValueError(f"Unknown platform: {platform_name}. Available: {list(cls._platforms.keys())}")
50-
51-
return platform_class(book, run_config)
52-
53-
@classmethod
54-
def get_supported_markets(cls, platform_name: str, book: Dict[str, str], run_config: Any) -> List[str]:
55-
"""
56-
Get list of supported markets for a platform
57-
58-
Args:
59-
platform_name: Platform name
60-
book: Address book dictionary
61-
run_config: Run configuration object
62-
63-
Returns:
64-
List of supported market names
65-
"""
66-
platform = cls.get_platform(platform_name, book, run_config)
67-
return platform.supported_markets
68-
8+
def get_platform(platform_name: str, book: Dict[str, str], run_config: Any) -> BribePlatform:
9+
"""
10+
Get platform instance based on platform name.
11+
12+
Args:
13+
platform_name: 'stakedao', 'paladin', or 'hh'
14+
book: Address book dictionary
15+
run_config: Run configuration object
16+
17+
Returns:
18+
BribePlatform instance
19+
"""
20+
if platform_name == "stakedao":
21+
return StakeDAOPlatform(book, run_config)
22+
elif platform_name == "paladin":
23+
return PaladinPlatform(book, run_config)
24+
elif platform_name == "hh":
25+
return HiddenHandPlatform(book, run_config)
26+
raise ValueError(f"Unknown platform: {platform_name}")
Lines changed: 12 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
from typing import Dict, Optional, Tuple, Any, List
22
import pandas as pd
3-
from web3 import Web3
43
from .base import BribePlatform
54
from bal_tools.safe_tx_builder import SafeContract
65
import json
76
from pathlib import Path
8-
from fee_allocator.logger import logger
97

108

119
class PaladinPlatform(BribePlatform):
@@ -60,64 +58,30 @@ def process_bribes(self, bribes_df: pd.DataFrame, builder: Any, usdc: Any) -> No
6058
fee_ratio = platform_fee_ratios[platform]
6159

6260
total_reward_amount = int(mantissa * 10000 / (10000 + fee_ratio))
63-
fee_amount = mantissa - total_reward_amount
61+
fee_amount = (total_reward_amount * fee_ratio) // 10000
62+
63+
reward_per_period = total_reward_amount // 2
64+
max_reward_per_vote = max(reward_per_period // 1000, 50)
65+
min_reward_per_vote = 50
6466

6567
quest_board.createRangedQuest(
6668
row["target"],
6769
self.usdc_address,
68-
True,
70+
"true",
6971
2,
70-
1,
71-
total_reward_amount,
72+
min_reward_per_vote,
73+
max_reward_per_vote,
7274
total_reward_amount,
7375
fee_amount,
7476
0,
7577
1,
76-
[]
78+
"[]"
7779
)
7880

7981

8082
def validate_gauge_requirements(self, gauge_address: str) -> Tuple[bool, Optional[str]]:
81-
"""Validate gauge has USDC as reward token with correct distributor"""
82-
try:
83-
base_dir = Path(__file__).parent.parent
84-
with open(f"{base_dir}/abi/gauge.json", "r") as f:
85-
gauge_abi = json.load(f)
86-
87-
w3 = self.run_config.mainnet.web3
88-
usdc = Web3.to_checksum_address(self.usdc_address)
89-
gauge = Web3.to_checksum_address(gauge_address)
90-
contract = w3.eth.contract(address=gauge, abi=gauge_abi)
91-
92-
try:
93-
usdc_found = usdc in [contract.functions.reward_tokens(i).call() for i in range(8)]
94-
except Exception:
95-
return False, "Gauge has incompatible implementation"
96-
97-
if not usdc_found:
98-
return False, f"USDC ({usdc}) not found in gauge reward tokens"
99-
100-
try:
101-
distributor = contract.functions.reward_data(usdc).call()[1]
102-
has_correct_distributor = (
103-
distributor.lower() == self.bal_quest_board.lower() or
104-
distributor.lower() == self.aura_quest_board.lower()
105-
)
106-
107-
if not has_correct_distributor:
108-
valid_distributors = [
109-
f"Balancer: {self.bal_quest_board}",
110-
f"Aura: {self.aura_quest_board}"
111-
]
112-
return False, f"Incorrect distributor. Valid: {', '.join(valid_distributors)}"
113-
114-
except Exception:
115-
return False, "Could not verify distributor"
116-
117-
return True, None
118-
119-
except Exception as e:
120-
return False, f"Validation error: {str(e)}"
83+
"""No validation needed for ROLLOVER close type"""
84+
return True, None
12185

12286
@property
12387
def platform_name(self) -> str:
@@ -129,41 +93,4 @@ def supported_markets(self) -> List[str]:
12993
return ["aura", "balancer"]
13094

13195
def get_platform_for_market(self, market: str, voting_pool_override: Optional[str]) -> str:
132-
return "paladin"
133-
134-
def check_all_gauge_requirements(self, pools: List[Any]) -> List[Dict]:
135-
"""Check all Paladin gauges for requirements and return issues"""
136-
gauges_with_issues = []
137-
138-
for pool in pools:
139-
if pool.market_override != "paladin":
140-
continue
141-
142-
valid, error_msg = self.validate_gauge_requirements(pool.gauge_address)
143-
if not valid:
144-
action_needed = []
145-
146-
# Determine which distributors are needed
147-
if pool.to_bal_incentives_usd > 0:
148-
action_needed.append(f"Balancer distributor ({self.bal_quest_board})")
149-
if pool.to_aura_incentives_usd > 0:
150-
action_needed.append(f"Aura distributor ({self.aura_quest_board})")
151-
152-
if action_needed:
153-
if "not found in gauge reward tokens" in error_msg:
154-
action_msg = f"Add USDC ({self.usdc_address}) as reward token and set {' and '.join(action_needed)}"
155-
elif "Incorrect distributor" in error_msg:
156-
action_msg = f"Set {' and '.join(action_needed)}"
157-
else:
158-
action_msg = error_msg
159-
160-
logger.warning(f"Paladin gauge {pool.gauge_address} missing requirements: {action_msg}")
161-
gauges_with_issues.append({
162-
"gauge": pool.gauge_address,
163-
"pool_id": pool.pool_id,
164-
"chain": pool.chain.name,
165-
"action": action_msg,
166-
"amount": float(pool.total_to_incentives_usd)
167-
})
168-
169-
return gauges_with_issues
96+
return "paladin"

fee_allocator/constants.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
FEE_CONSTANTS_URL = "https://raw.githubusercontent.com/BalancerMaxis/multisig-ops/main/config/protocol_fees_constants.json"
2-
ALLIANCE_CONFIG_URL = "https://raw.githubusercontent.com/BalancerMaxis/multisig-ops/main/config/alliance_fee_share.json"
1+
FEE_CONSTANTS_URL = "https://raw.githubusercontent.com/BalancerMaxis/multisig-ops/726104745a4b4bdfc1f93ce1c44a1754df31d87b/config/protocol_fees_constants.json"
2+
ALLIANCE_CONFIG_URL = "https://raw.githubusercontent.com/BalancerMaxis/multisig-ops/fe75ad42c2fca6702087165ec0ff77aea379085a/config/alliance_fee_share.json"
33
PARTNER_CONFIG_URL = "https://raw.githubusercontent.com/BalancerMaxis/multisig-ops/main/config/partner_fee_share.json"
44
EZKL_POOLS_URL = "https://raw.githubusercontent.com/BalancerMaxis/bal_addresses/main/outputs/ezkl_pools.json"
55
POOL_OVERRIDES_URL = "https://raw.githubusercontent.com/BalancerMaxis/multisig-ops/main/config/pool_incentives_overrides.json"

0 commit comments

Comments
 (0)