Skip to content

split_lib

Pure BPS-splitting library used by EmissionRouter and GaugeWeightRouter. Not deployed@internal @pure helpers compile into each consumer.

Source: khomdev-veforge/src/split_lib.vy (Vyper 0.4.x)

Consumers: EmissionRouter.distribute · GaugeWeightRouter.poke (inline equivalent)

Implementation overview

  • No storage — all functions @internal @pure
  • proportional_split — normalize weights onto pool; last slot absorbs dust so sum equals pool exactly
  • weighted_distribution — like proportional but skips slices below min_slice; returns dust for caller to retain
flowchart TD
    W[weights + total_weight + pool] --> PS[proportional_split]
    W --> WD[weighted_distribution]
    PS --> ER[EmissionRouter distribute]
    WD --> ER

Constants

Name Value Role
MAX_BPS 10000 Denominator mirror

Internal functions

proportional_split

split_lib.proportional_split(weights, total_weight, pool) -> DynArray[uint256, 32]

Normalize per-item weights onto pool. Last slot absorbs floor-division dust so returned array sums to pool exactly.

Param Type Description
weights DynArray[uint256, 32] Per-item weights (any scale; ratio matters)
total_weight uint256 Sum of weights (caller-provided)
pool uint256 Total pie to distribute

Returns: DynArray[uint256, 32] — proportional shares; Σ == pool.

Access: @internal @pure — inlined in consumer.

Source (khomdev-veforge/src/split_lib.vy:29-79):

@internal
@pure
def proportional_split(weights: DynArray[uint256, 32], total_weight: uint256, pool: uint256) -> DynArray[uint256, 32]:
    if i == last:
        share = pool - running  # dust to last slot
    else:
        share = weights[i] * pool // total_weight

Example:

# EmissionRouter uses weighted_distribution instead when min_slice = num_epochs
shares = split_lib.proportional_split(weights, total, bal)

Cross-links: weighted_distribution

weighted_distribution

split_lib.weighted_distribution(weights, total_weight, pool, min_slice) -> (DynArray[uint256, 32], uint256)

Like proportional_split but items below min_slice get 0; skipped amount returned as dust.

Param Type Description
weights DynArray[uint256, 32] Per-item weights
total_weight uint256 Sum of weights
pool uint256 Total to distribute
min_slice uint256 Minimum viable slice (e.g. num_epochs)

Returns: (allocations, dust) — allocations same length as weights; sub-threshold entries are 0.

Access: @internal @pure — inlined in EmissionRouter.

Source (khomdev-veforge/src/split_lib.vy:82-131):

@internal
@pure
def weighted_distribution(weights, total_weight, pool, min_slice) -> (DynArray[uint256, 32], uint256):
    amount: uint256 = weights[i] * pool // total_weight
    if amount < min_slice:
        dust += amount
        result.append(0)
    else:
        result.append(amount)
    return (result, dust)

Note: EmissionRouter passes min_slice = num_epochs — gauges with indivisible slices are skipped; dust stays in router for next distribute.

Cross-links: EmissionRouter.distribute · proportional_split