Points System

Overview

The Curvance Points System is a core component of the protocol's voting escrow (veCVE) mechanism, providing the foundation for governance voting power and reward distribution. Rather than using raw locked token amounts, Curvance implements a "points" system to track user influence and manage the distribution of protocol rewards.

Technical Implementation

Points System Architecture

The points system consists of several interconnected mechanisms that track both individual and aggregate protocol state:

chainPoints: uint256  // Total points on the chain
userPoints: mapping(address => uint256)  // Points per user
chainUnlocksByEpoch: mapping(uint256 => uint256)  // Points unlocking in each epoch
userUnlocksByEpoch: mapping(address => mapping(uint256 => uint256))  // User points unlocking by epoch

Regular vs. Continuous Locks

Locks exist in two modes:

  • Regular Locks: Fixed-duration locks (1 year/26 epochs) with 1:1 point ratio

  • Continuous Locks: Auto-renewing locks with CONTINUOUS_LOCK_VALUE (max uint40) as unlockTime and a 2x point multiplier

Points Calculations

The continuous lock multiplier is defined as:

CL_POINT_MULTIPLIER = 2 // 200% of base points

Points calculation for continuous locks:

_getCLPoints(basePoints) => CL_POINT_MULTIPLIER * basePoints

Points State Machine

The points system's state evolves through these main operations:

  • Creating Locks: Adds points to user and chain totals

  • Extending Locks: Updates unlock schedule and potentially modifies points

  • Unlocking: Removes points when locks expire

  • Early Unlocking: Removes points with penalty

  • Changing Lock Mode: Toggles between regular and continuous lock

Internal functions managing this state:

_incrementPoints(address user, uint256 points)
_reducePoints(address user, uint256 points)
_incrementTokenUnlocks(address user, uint256 epoch, uint256 points)
_reduceTokenUnlocks(address user, uint256 epoch, uint256 points)
_updateUnlockDataToExtendedLock(address user, uint256 previousEpoch, uint256 epoch, uint256 previousPoints, uint256 points)
_updateDataToContinuousOn(address user, uint256 epoch, uint256 points, uint256 unlocks)
_updateDataFromEarlyUnlock(address user, uint256 points, uint256 unlockTime)

User-Facing Functions

createLock()

Creates a new voting escrow position by locking CVE tokens.

Function signature:

function createLock(
    uint256 amount,
    bool continuousLock,
    RewardsData calldata rewardsData,
    bytes calldata params,
    uint256 aux
) external nonReentrant
Parameter
Type
Description

amount

uint256

Amount of CVE tokens to lock

continuousLock

bool

Whether to enable continuous lock mode

rewardsData

RewardsData

Data structure for reward claiming

params

bytes

Additional parameters for rewards processing

aux

uint256

Auxiliary data

extendLock()

Extends an existing lock with additional tokens.

Function signature:

function extendLock(
    uint256 lockIndex,
    uint256 amount,
    RewardsData calldata rewardsData,
    bytes calldata params,
    uint256 aux
) external nonReentrant
Parameter
Type
Description

lockIndex

uint256

Index of the lock to extend

amount

uint256

Additional amount to lock

rewardsData

RewardsData

Data structure for reward claiming

params

bytes

Additional parameters for rewards processing

aux

uint256

Auxiliary data

updateLockMode()

Toggles a lock between regular and continuous lock modes.

Function signature:

function updateLockMode(
    uint256 lockIndex,
    bool continuousLock,
    RewardsData calldata rewardsData,
    bytes calldata params,
    uint256 aux
) external nonReentrant
Parameter
Type
Description

lockIndex

uint256

Index of the lock to update

continuousLock

bool

Whether to enable or disable continuous lock mode

rewardsData

RewardsData

Data structure for reward claiming

params

bytes

Additional parameters for rewards processing

aux

uint256

Auxiliary data

combineLocks()

Combines multiple locks into a single new lock.

Function signature:

function combineLocks(
    bool continuousLock,
    RewardsData calldata rewardsData,
    bytes calldata params,
    uint256 aux
) external nonReentrant
Parameter
Type
Description

continuousLock

bool

Whether the combined lock should be continuous

rewardsData

RewardsData

Data structure for reward claiming

params

bytes

Additional parameters for rewards processing

aux

uint256

Auxiliary data

unlock()

Unlocks tokens from an expired lock.

Function signature:

function unlock(
    uint256 lockIndex,
    RewardsData calldata rewardsData,
    bytes calldata params,
    uint256 aux
) external nonReentrant
Parameter
Type
Description

lockIndex

uint256

Index of the lock to unlock

rewardsData

RewardsData

Data structure for reward claiming

params

bytes

Additional parameters for rewards processing

aux

uint256

Auxiliary data

earlyUnlock()

Unlocks tokens before the lock expires, with a penalty.

Function signature:

function earlyUnlock(
    uint256 lockIndex,
    RewardsData calldata rewardsData,
    bytes calldata params,
    uint256 aux
) external nonReentrant
Parameter
Type
Description

lockIndex

uint256

Index of the lock to unlock early

rewardsData

RewardsData

Data structure for reward claiming

params

bytes

Additional parameters for rewards processing

aux

uint256

Auxiliary data

Querying Information

queryUserLocks()

Returns all locks for a specific user.

Function signature:

function queryUserLocks(address user) external view returns (uint256[] memory, uint256[] memory)
Parameter
Type
Description

user

address

Address of the user to query

Return Values:

Type
Description

uint256[] memory

Lock amounts

uint256[] memory

expiry dates or CONTINUOUS_LOCK_VALUE

getVotes()

Returns the voting power (points) of a user.

Function signature:

function getVotes(address user) external view returns (uint256)
Parameter
Type
Description

user

address

Address of the user to query

Return values:

Type
Description

uint256

Total voting power (points) of the user

Points Lifecycle

  1. Lock Creation:

  • Regular lock: +1 point per token, scheduled to unlock in 1 year

  • Continuous lock: +2 points per token, no scheduled unlock

  1. Lock Extension:

  • Updates unlock schedule

  • For continuous locks, increases points by 2x the additional amount

  • For regular locks, increases points by 1x the additional amount

  1. Lock Mode Update:

  • Regular → Continuous: Increases points by 1x the locked amount, removes scheduled unlock

  • Continuous → Regular: Decreases points by 1x the locked amount, adds scheduled unlock

  1. Unlock:

  • Removes points based on lock mode (1x for regular, 2x for continuous)

  • For regular locks, also updates the epoch unlock schedule

  1. Early Unlock:

  • Same point reduction as normal unlock

  • Applies penalty to returned tokens

Implementation Notes

  • The points system is synchronized with epochs to ensure rewards are correctly distributed

  • State-changing operations are restricted around epoch transitions (RESTRICTION_DURATION = 12 hours)

  • Multichain support allows locks to be transferred between chains

  • Continuous lock mode provides higher rewards but the same amount of locked tokens

Last updated