veTOWN for Lending & Borrowing
TownSquare is introducing a vote-escrow (ve) incentives system that directs emissions to two activities in each lending market:
Lenders (deposits) — incentivize TVL on the supply side.
Borrowers (debt outstanding / activity) — incentivize healthy demand.
The design mirrors ve(3,3) stacks (Velodrome/Aerodrome) and classic veCRV (Curve) so that engineering can fork and retrofit minimal code: keep VotingEscrow, Voter, Minter, RewardsDistributor, Bribe, and replace LP pool gauges with SupplyGauge and BorrowGauge per asset.
High-Level Concepts
veToken (NFT lock): Users lock the protocol token for a duration to receive vote power that decays to zero at unlock.
Epochs: Fixed windows (default 7 days) where votes are snapshotted and emissions are streamed to gauges.
Gauges: Reward contracts that stream emissions to participants according to balances:
SupplyGauge[asset]→ pays lenders by scaled supply balance (aToken-like).BorrowGauge[asset]→ pays borrowers by scaled debt balance (variableDebt-like).
Voter: Aggregates epoch votes from ve holders and assigns each gauge a % of the weekly emission.
Bribes / Voting Rewards (optional): Per-gauge reward channels paying ve voters who supported that gauge in the epoch.
Rewards Distributor (ve rebase): Optional “locker rebase” stream to ve lockers (separate from gauge emissions).
Market Registry: Whitelists which markets have gauges and sets risk params (caps, utilization floors).
Emission Policy: Config for weekly budget, decay, and optional side multipliers (e.g., borrow 1.2×).
Roles
User: Locks tokens for ve; supplies/borrows assets; votes each epoch; claims rewards.
Protocol Gov/Multisig: Lists markets; sets caps/allowlists; updates emission policy.
Partners: Can add bribes to steer votes (with allowlisted tokens).
Keepers (optional): Trigger epoch rollovers / batch distributions if not auto-pulled by claims.
User Flows
Lock → Vote → Earn
Lock: User locks token → receives
veNFT(id, power).Vote: User allocates vote weights across any combination of
SupplyGauge[asset]andBorrowGauge[asset].Epoch Start: Votes snapshot →
Votercomputes per-gauge weight share.Stream:
MintermintsE_epoch→ routes toVoter→ each gauge receivesE_gand streams linearly over the epoch.Accrual:
Lenders accrue in
SupplyGaugeby scaled aToken balance.Borrowers accrue in
BorrowGaugeby scaled debt balance.
Claim: Users call
claim()on gauges (andgetReward()on bribe contracts if they voted).
Supply/Borrow Balance Change
When a user supplies/withdraws or borrows/repays, the respective scaled balance changes. The gauge updates the user’s accrual using a cumulative reward index.
Economics & Formulas
Epoch Allocation
Let
E_epochbe emissions for the epoch.Let
w_gbe the vote weight for gaugeg.Gauge share:
Optional side multiplier (policy overlay):
Then renormalize to keep the epoch budget constant:
Streaming Rate
rate_g = E_g / epochSecondsGauges stream linearly over the epoch (no compounding inside the epoch).
Per-User Accrual (Index Model)
For each gauge:
Maintain
indexanduserIndex[user].On time progress
dt:On user interaction:
Scaled balances come from your interest-bearing tokens:
Supply side:
aToken.scaledBalanceOf(user)Borrow side:
variableDebtToken.scaledBalanceOf(user)
Optional “Boost” for Lockers Who Use the Market
Effective balance cap (Curve-style idea, optional):
Keep
capmodest (e.g., 2.5×) to avoid runaway concentration.
Contracts & Responsibilities
VotingEscrow (veNFT)
Core:
createLock(amount, unlockTime),increaseAmount,increaseUnlockTime,balanceOfNFT(tokenId, t),merge/split (optional).Voting Slope/Decay: Time-weighted decay to enforce long-term alignment.
Events:
LockCreated,LockIncreased,LockExtended,Withdrawn.
Voter
Register Gauges:
addGauge(gauge, type)wheretype ∈ {SUPPLY, BORROW}.Vote:
vote(tokenId, gauges[], weights[])(can be re-cast each epoch).Distribute: On epoch start, computes each gauge’s
E_g(with policy multipliers) and callsnotifyRewardAmounton gauges.Voting Rewards: Tracks who voted for which gauges for bribe/fee claims.
Guards: Max % per gauge/asset; gauge kill/suspend; per-epoch vote limits.
Minter
Emission Budget: Holds the epoch schedule and decay.
Mint & Route: At epoch rollover, mints
E_epoch, sends toVoter, optional % toRewardsDistributor(ve rebase).
RewardsDistributor (optional)
ve Rebase: Streams a portion of emissions (or protocol fees) to ve lockers proportionally to ve balances.
Bribe / FeesVotingReward (optional but recommended)
Per-Gauge Vaults: Accept allowlisted reward tokens.
Eligibility: Only ve voters who voted for this gauge in the epoch can claim.
Use: Partners can fund these to steer votes without protocol code changes.
SupplyGauge[asset] / BorrowGauge[asset]
Stake Model: No explicit staking; the “stake” is the user’s scaled balance read from the market tokens.
Hooks:
Option A (hook-based): Market tokens call
onBalanceChange(user, delta)on mint/burn/transfer.Option B (lazy): Settle on user actions + periodic keeper tick.
Core Methods:
notifyRewardAmount(amount)— set epoch stream.claim(user)— pull user’s accrued rewards.earned(user)— view function.
Admin:
setRewardToken,setBribeAddress,setMarketOracle(if needed),pause.
MarketRegistry
Lists markets eligible for gauges with risk flags.
Params per market:
utilizationFloor,maxEmissionPct,sideCaps,isActive.
EmissionPolicy
Global knobs:
epochLength,baseWeeklyEmission,decayBps,supplyMultiplier,borrowMultiplier,sinkGauge(if zero-vote fallback).
Security & Risk Controls
Gauge Whitelist: Only protocol-approved markets get gauges.
Bribe Token Allowlist: Prevent malicious token griefing.
Caps:
Per-gauge max share of weekly emissions.
Per-asset aggregate cap across its two gauges.
Utilization Floor: Optionally require
U ≥ U_minto accept votes for a gauge (avoid wasting emissions on dead markets).Kill-Switch: Ability to pause individual gauges and bribe vaults.
Reentrancy & Accounting: Guard
claim()andnotifyRewardAmount(); use pull-based transfers.
Parameters (suggested defaults, all configurable)
epochLength: 7 daysdecayBps: 100 bps per epoch (example)supplyMultiplier: 1.0 (neutral)borrowMultiplier: 1.0–1.2 (policy lever)maxEmissionPctPerGauge: 15%maxEmissionPctPerAsset: 25% (supply+borrow combined)utilizationFloor: 10–20% (if enabled)bribeTokensAllowlist: curated list (stablecoins + blue-chips)
Last updated