Skip to content

Commit

Permalink
Merge pull request #42 from BalancerMaxis/new-fee-model
Browse files Browse the repository at this point in the history
New fee model
  • Loading branch information
jalbrekt85 authored Feb 7, 2025
2 parents 9f69e08 + 5e13b57 commit 17ca147
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 61 deletions.
15 changes: 15 additions & 0 deletions fee_allocator/accounting/chains.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,18 @@ def total_earned_fees_usd_twap(self) -> Decimal:
return sum(
[pool_data.total_earned_fees_usd_twap for pool_data in self.pool_fee_data]
)

@property
def noncore_fees_collected(self) -> Decimal:
if not self.core_pools:
raise ValueError("core pools not set")
total_core_fees = sum(pool.total_earned_fees_usd_twap for pool in self.core_pools)
return max(self.fees_collected - total_core_fees, Decimal(0))

@property
def noncore_to_dao_usd(self) -> Decimal:
return self.noncore_fees_collected * self.chains.fee_config.noncore_dao_share_pct

@property
def noncore_to_vebal_usd(self) -> Decimal:
return self.noncore_fees_collected * self.chains.fee_config.noncore_vebal_share_pct
10 changes: 3 additions & 7 deletions fee_allocator/accounting/core_pools.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,7 @@ def _earned_fee_share_of_chain_usd(self) -> Decimal:
return self.total_earned_fees_usd_twap / self.chain.total_earned_fees_usd_twap

def _total_to_incentives_usd(self) -> Decimal:
to_distribute_to_incentives = self.chain.fees_collected * (
1
- self.chain.chains.fee_config.dao_share_pct
- self.chain.chains.fee_config.vebal_share_pct
)
to_distribute_to_incentives = self.chain.total_earned_fees_usd_twap * self.chain.chains.fee_config.vote_incentive_pct
return self.earned_fee_share_of_chain_usd * to_distribute_to_incentives

def _to_aura_incentives_usd(self) -> Decimal:
Expand All @@ -130,13 +126,13 @@ def _to_bal_incentives_usd(self) -> Decimal:
def _to_dao_usd(self) -> Decimal:
return (
self.earned_fee_share_of_chain_usd
* self.chain.fees_collected
* self.chain.total_earned_fees_usd_twap
* self.chain.chains.fee_config.dao_share_pct
)

def _to_vebal_usd(self) -> Decimal:
return (
self.earned_fee_share_of_chain_usd
* self.chain.fees_collected
* self.chain.total_earned_fees_usd_twap
* self.chain.chains.fee_config.vebal_share_pct
)
6 changes: 6 additions & 0 deletions fee_allocator/accounting/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@ class GlobalFeeConfig(BaseModel):
min_aura_incentive: int
min_existing_aura_incentive: int
min_vote_incentive_amount: int

# Core pool fee splits
vebal_share_pct: Decimal
dao_share_pct: Decimal
vote_incentive_pct: Decimal

# Non-core pool fee splits
noncore_vebal_share_pct: Decimal
noncore_dao_share_pct: Decimal


class RerouteConfig(BaseModel):
Expand Down
2 changes: 1 addition & 1 deletion fee_allocator/constants.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FEE_CONSTANTS_URL = "https://raw.githubusercontent.com/BalancerMaxis/multisig-ops/main/config/protocol_fees_constants.json"
FEE_CONSTANTS_URL = "https://raw.githubusercontent.com/BalancerMaxis/multisig-ops/f7e0425b59e474b01d2ede125053238460792630/config/protocol_fees_constants.json"
CORE_POOLS_URL = "https://raw.githubusercontent.com/BalancerMaxis/bal_addresses/main/outputs/core_pools.json"
REROUTE_CONFIG_URL = "https://raw.githubusercontent.com/BalancerMaxis/multisig-ops/main/config/core_pools_rerouting.json"
POOL_OVERRIDES_URL = "https://raw.githubusercontent.com/BalancerMaxis/multisig-ops/main/config/pool_incentives_overrides.json"
Expand Down
82 changes: 35 additions & 47 deletions fee_allocator/fee_allocator.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ def __init__(
)
self.book = AddrBook("mainnet").flatbook

def allocate(self):
"""
Allocates protocol fees to core pools and non-core pools according to BIP-734.
Core pools: 70% voting incentives, 12.5% veBAL, 17.5% DAO
Non-core pools: 82.5% veBAL, 17.5% DAO
"""
self.run_config.set_core_pool_chains_data()
self.run_config.set_aura_vebal_share()
self.run_config.set_initial_pool_allocation()
self.redistribute_fees()

def redistribute_fees(self):
"""
Expand Down Expand Up @@ -197,11 +207,12 @@ def generate_bribe_csv(
},
)

noncore_total_to_dao_usd = sum(chain.noncore_to_dao_usd for chain in self.run_config.all_chains)
output.append(
{
"target": "0x10A19e7eE7d7F8a52822f6817de8ea18204F2e4f", # DAO msig
"platform": "payment",
"amount": self.run_config.total_to_dao_usd,
"amount": self.run_config.total_to_dao_usd + noncore_total_to_dao_usd,
}
)

Expand All @@ -212,14 +223,6 @@ def generate_bribe_csv(
output_path = PROJECT_ROOT / output_path / f"bribes_{datetime_file_header}.csv"
output_path.parent.mkdir(exist_ok=True)

logger.info(f"Total fees collected: {self.run_config.total_fees_collected_usd}")
logger.info(
f"Total incentives allocated: {self.run_config.total_to_incentives_usd}"
)
logger.info(
f"delta {self.run_config.total_fees_collected_usd - self.run_config.total_to_incentives_usd}"
)

df.to_csv(
output_path,
index=False,
Expand Down Expand Up @@ -255,15 +258,6 @@ def generate_incentives_csv(

df = pd.DataFrame(output)

logger.info(f"Total fees collected: {self.run_config.total_fees_collected_usd}")
logger.info(
f"Total incentives allocated: {self.run_config.total_to_incentives_usd}"
)
logger.info(
f"delta {self.run_config.total_fees_collected_usd - self.run_config.total_to_incentives_usd}"
)


sorted_df = df.sort_values(by=["chain", "earned_fees"], ascending=False)
start_date = datetime.datetime.fromtimestamp(self.date_range[0]).date()
end_date = datetime.datetime.fromtimestamp(self.date_range[1]).date()
Expand Down Expand Up @@ -303,6 +297,7 @@ def generate_bribe_payload(
payment_df = df[df["platform"] == "payment"].iloc[0]

total_bribe_usdc = sum(bribe_df["amount"]) * 1e6
dao_fee_usdc = int(payment_df["amount"] * 1e6)

"""
bribe txs
Expand All @@ -323,13 +318,14 @@ def generate_bribe_payload(
"""
transfer txs
"""
usdc.transfer(payment_df["target"], int(payment_df["amount"] * 1e6))
usdc.transfer(payment_df["target"], dao_fee_usdc)

spent_usdc = int(total_bribe_usdc + (payment_df["amount"] * 1e6))
spent_usdc = int(total_bribe_usdc + dao_fee_usdc)
vebal_usdc_amount = int(
self.run_config.mainnet.web3.eth.contract(usdc.address, abi=get_abi("ERC20"))
.functions.balanceOf(builder.safe_address)
.call()
# self.run_config.mainnet.web3.eth.contract(usdc.address, abi=get_abi("ERC20"))
# .functions.balanceOf(builder.safe_address)
# .call()
401333231807
- spent_usdc
- 1
)
Expand Down Expand Up @@ -372,38 +368,35 @@ def recon(self) -> None:
4. Small delta between collected and distributed fees
"""
total_fees = self.run_config.total_fees_collected_usd
total_incentives = Decimal(0)
total_dao = Decimal(0)
total_vebal = Decimal(0)
total_aura = Decimal(0)
total_bal = Decimal(0)
total_dao = Decimal(0)
total_vebal = Decimal(0)
total_incentives = Decimal(0)

for chain in self.run_config.all_chains:
for pool in chain.core_pools:
assert pool.to_aura_incentives_usd >= 0, f"Negative Aura incentives: {pool.pool_id}"
assert pool.to_bal_incentives_usd >= 0, f"Negative BAL incentives: {pool.pool_id}"
assert pool.to_dao_usd >= 0, f"Negative DAO fees: {pool.pool_id}"
assert pool.to_vebal_usd >= 0, f"Negative veBAL fees: {pool.pool_id}"
assert pool.to_aura_incentives_usd >= 0, f"Negative aura incentives: {pool.to_aura_incentives_usd}"
assert pool.to_bal_incentives_usd >= 0, f"Negative bal incentives: {pool.to_bal_incentives_usd}"
assert pool.to_dao_usd >= 0, f"Negative dao share: {pool.to_dao_usd}"
assert pool.to_vebal_usd >= 0, f"Negative vebal share: {pool.to_vebal_usd}"

total_aura += pool.to_aura_incentives_usd
total_bal += pool.to_bal_incentives_usd
total_dao += pool.to_dao_usd
total_vebal += pool.to_vebal_usd

total_dao += chain.noncore_to_dao_usd
total_vebal += chain.noncore_to_vebal_usd

total_incentives = total_aura + total_bal + total_dao + total_vebal

delta = abs(total_fees - total_incentives)
assert delta < Decimal('0.15'), f"Large fee delta: {delta}"

total_pct = (
total_aura / total_incentives +
total_bal / total_incentives +
total_dao / total_incentives +
total_vebal / total_incentives
)
total_pct = (total_aura + total_bal + total_dao + total_vebal) / total_incentives

assert abs(1 - total_pct) < Decimal('0.0001'), f"Percentages don't sum to 1: {total_pct}"

aura_share = total_aura / (total_aura + total_bal)
# Only check Aura share against BAL for core pool incentives
core_pool_incentives = total_aura + total_bal
aura_share = total_aura / core_pool_incentives if core_pool_incentives > 0 else Decimal(0)
target_share = self.run_config.aura_vebal_share
assert abs(aura_share - target_share) < Decimal('0.05'), \
f"Aura share {aura_share} deviates from target {target_share}"
Expand Down Expand Up @@ -435,11 +428,6 @@ def recon(self) -> None:
else:
data = []

for entry in data:
if entry["periodStart"] == summary["periodStart"] and \
entry["periodEnd"] == summary["periodEnd"]:
return

data.append(summary)
with open(recon_file, "w") as f:
json.dump(data, f, indent=2)
8 changes: 2 additions & 6 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,8 @@ def main() -> None:
date_range = (ts_in_the_past, ts_now)

fee_allocator = FeeAllocator(input_fees, date_range)

fee_allocator.run_config.set_core_pool_chains_data()
fee_allocator.run_config.set_aura_vebal_share()
fee_allocator.run_config.set_initial_pool_allocation()

fee_allocator.redistribute_fees()

fee_allocator.allocate()
fee_allocator.recon()

fee_allocator.generate_incentives_csv()
Expand Down

0 comments on commit 17ca147

Please sign in to comment.