feat(voting): optimize rewards from current incentives - #27
Draft
WilliamPyke wants to merge 2 commits into
Draft
Conversation
✅ Deploy Preview for matchb0x ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for matchboxdeveloper ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
matchbox | ad8a01c | Jul 30 2026, 04:10 AM |
Maximizing pro-rata incentive capture under a fixed vote budget equalizes marginal returns across gauges, which has an exact solution. We were approximating it with a 10,000-step greedy walk wrapped in a heuristic search over candidate gauge subsets, which cost ~170ms of blocked main thread per click and still landed up to 1.74% below the optimum. Solving the water-fill directly is exact, runs in under a millisecond, and makes the gauge cap unnecessary: concentration now falls out of the math, since a diluting vote stops paying before the candidate list runs out. Two modelling fixes come with it. A gauge nobody has voted for yet looked like free money -- one basis point captured the whole pool -- so projections were wildly optimistic and ballots filled with dust. Competing weight is now floored at one basis point of the voter's own power, the finest vote a ballot can express. Separately, the annualized return truncated its principal to micro-USD before dividing, reporting no APY at all for small positions. Basis points are assigned by largest remainder so the ballot always totals exactly 100%. The old greedy also never terminated early, dumping thousands of leftover basis points on whichever gauge won a tie-break once every marginal return had reached zero. The panel collapses to a single Optimize button that writes straight to the ballot. The max-gauge input, the per-gauge exclusions, and the preview-then-apply two-step were all surfacing knobs on an approximation that no longer exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Why
Gauge voters currently have to compare incentive pools and dilution manually. This gives them a current-epoch recommendation designed to increase external incentive rewards per veMEZO or veBTC without silently changing their ballot.
User impact
Users can preview an optimized allocation, exclude gauges, adjust the maximum number of gauges, and explicitly apply the result. The same allocation is used for every eligible selected NFT, and prior replaceable votes are included in the projection.
Validation
pnpm --filter @repo/webapp lintpnpm --filter @repo/webapp typecheckpnpm --filter @repo/webapp testpnpm --filter @repo/webapp buildpnpm typecheckNotes
Workspace-wide lint still reports an unrelated existing line-ending formatting issue in
apps/developer-platform/src/styles/globals.css; webapp lint passes.