Launchpad Staking Contract


This contract is responsible for giving allocation for staking tokens over time.

Users stake to specific tracks, where stake weight accrues. Stake weight increases over time proportional to stake amount. For each passing block, a user's stake weight increases by their staked amount the previous block (times a scaling constant).

A sale contract will calculate a user's allocation as their stake weight divided by the total stake weight (from a particular track).


event AddTrack(string indexed name, address indexed token);
event DisableTrack(uint24 indexed trackId);
event ActiveRollOver(uint24 indexed trackId, address indexed user);
event BumpSaleCounter(uint24 indexed trackId, uint32 newCount);
event AddUserCheckpoint(uint24 indexed trackId, uint80 blockNumber);
event AddTrackCheckpoint(uint24 indexed trackId, uint80 blockNumber);
event Stake(uint24 indexed trackId, address indexed user, uint104 amount);
event Unstake(uint24 indexed trackId, address indexed user, uint104 amount);

Public variables


mapping(uint24 => mapping(uint24 => uint80))
    public trackFinishedSaleBlocks;

The number of checkpoints of a track.

(track, finished sale count) => block number


mapping(uint24 => mapping(address => mapping(uint24 => uint192)))
        public trackActiveRollOvers;

Stake weight each user actively rolls over for a given track and a finished sale count.

(track, user, finished sale count) => amount of stake weight


mapping(uint24 => mapping(uint24 => uint192))
        public trackTotalActiveRollOvers;

Total stake weight actively rolled over for a given track and a finished sale count.

(track, finished sale count) => total amount of stake weight


TrackInfo[] public tracks;

Array of track information indexed by track number.


mapping(uint24 => uint256) public numTrackStakers;

Number of unique stakers on a track.

(track) => staker count


mapping(uint24 => address[]) public trackStakers;

Array of unique stakers on track.

(track) => address array


mapping(uint24 => uint32) public trackCheckpointCounts;

The number of checkpoints of a track.

(track) => checkpoint count


mapping(uint24 => mapping(uint32 => TrackCheckpoint))
        public trackCheckpoints;

Track checkpoint mapping.

(track, checkpoint number) => TrackCheckpoint


mapping(uint24 => mapping(address => uint32))
    public userCheckpointCounts;

The number of checkpoints of a user for a track.

(track, user address) => checkpoint count


mapping(uint24 => mapping(address => mapping(uint32 => UserCheckpoint)))
        public userCheckpoints;

User checkpoint mapping.

(track, user address, checkpoint number) => UserCheckpoint



constructor() {}

The constructor takes no parameters.


function trackCount() external view returns (uint24)

Gets the number of tracks.


function addTrack(
    string calldata name,
    ERC20 stakeToken,
    uint24 _weightAccrualRate,
    uint64 _passiveRolloverRate,
    uint64 _activeRolloverRate,
    uint104 _maxTotalStake
) public onlyOwner

Adds a new track.

Note: Weight accrual rate is essentially a scaling constant for calculating stake weights. Mathematically, for each block that passes, a user's stake weight increases as follows:

previous block staked amount * weight accrual rate / 10**18

The main purpose of weight accrual rate is for scaling precision, making sure even small staked amounts don't accrue 0 weight every block. Since weight accrual rate is uint24 (and it cannot be set to 0), stake weight increase per block is limited to the following range:

  • Min: previous block staked amount / 10**18

  • Max: previous block staked amount * 10**6

This is limited enough to allow weight accrual rate to increase precision without a big risk of causing overflow in stake weight.


function bumpSaleCounter(uint24 trackId) public onlyOwner

Bumps a track's finished sale counter.


function disableTrack(uint24 trackId) public onlyOwner

Disables a track.


function activeRollOver(uint24 trackId) public

Perform active rollover.


function getUserStakeWeight(
    uint24 trackId,
    address user,
    uint80 blockNumber
) public view returns (uint104)

Gets a user's stake weight within a track at a particular block number.


function getTotalStakeWeight(uint24 trackId, uint80 blockNumber)
    returns (uint104)

Gets total stake weight within a track at a particular block number.


function stake(uint24 trackId, uint104 amount) external

Stakes on a track.


function unstake(uint24 trackId, uint104 amount) external

Unstakes from a track.

Other useful notes

Getting user's stake amount in a track

This can be obtained with the following steps:

  1. Get the number of checkpoints for the user checkpointCount = userCheckpointCounts[track ID][user address]

  2. Get the user's latest checkpoint:latestCheckpoint = userCheckpoints[track ID][user address][checkpointPount-1]

  3. Get the user's current staked amount via the staked field on the latest checkpoint.

Last updated