Vote Escrow NPM Token (Draft)

This document is a draft and likely to change.

The Vote Escrow Token is a governance mechanism conceptualized by Curve Finance that allows communities to stake their tokens for a defined duration, giving them the ability to participate in decision-making with their voting power. This encourages long-term commitment and discourages short-term speculation. The longer a user locks their tokens, the more significant their voting power becomes.

Neptune Mutual has taken inspiration from the innovative Vote Escrow Token concept pioneered by Curve Finance and developed its unique version, known as veNPM. The primary objective of veNPM is to facilitate community governance by empowering token holders to participate in the decision-making process, while also encouraging long-term commitment and discouraging short-term speculation.

While the underlying principles of veNPM share similarities with Curve Finance's VotingEscrow contract, the implementation is distinct. One of the key differences is the programming language used for the veNPM contract. While Curve Finance developed its VotingEscrow contract using Vyper, Neptune Mutual chose to use Solidity, the most widely adopted smart contract programming language in the Ethereum ecosystem. By doing so, veNPM becomes more accessible to a broader range of developers and the wider DeFi community.

Additionally, the veNPM contract is released under the Apache 2.0 license. This open-source license allows for the free use, modification, and distribution of the source code, encouraging developers to fork, explore, and enhance it. Consequently, this approach fosters a collaborative environment for innovation and enables the DeFi community to experiment with, adapt, and improve the veNPM contract as needed.

What is veNPM?#

The veNPM token is designed to incentivize long-term engagement and commitment within the Neptune Mutual community. The Vote Escrow NPM token is a non-standard implementation ERC20 token that allows locking NPM tokens for a minimum of 4 weeks and a maximum of 208 weeks. By locking their NPM tokens, users receive veNPM tokens and boosted voting power. The longer the lockup period, the greater the voting power, capped at 4x.

To receive veNPM tokens, users must "vote lock" their NPM tokens for a predefined duration. Once locked, veNPM tokens cannot be transferred, and the balance remains constant throughout the lockup period. However, the boosted voting power gradually decreases until it reaches 1x, equivalent to a freely floating NPM token in the market.

  • Non-transferable: veNPM tokens cannot be transferred between accounts.
  • Time-based Voting Power: The voting power granted by veNPM tokens depends on the duration of the lockup.
  • Incentivized Engagement: By locking NPM tokens, users gain access to boosted voting power, encouraging long-term commitment to the Neptune Mutual ecosystem.

Liquidity Gauge Pools#

The Liquidity Gauge Pools are essential components within the Neptune Mutual protocol, designed to encourage user participation and long-term commitment to the project. It achieves this by enabling users to deposit their liquidity provider (POD) tokens and stake them in exchange for rewards in the form of NPM tokens. This mechanism not only serves to incentivize users to add liquidity to the protocol but also to strengthen community governance by granting them veNPM voting power.

When users provide liquidity to the protocol, they receive POD LP tokens representing their share of the liquidity pool. These LP tokens can be deposited into the Liquidity Gauge Pool, allowing users to stake and earn rewards. The rewards are distributed in NPM tokens, which are the native tokens of the Neptune Mutual ecosystem. By staking LP tokens, users not only contribute to the stability and growth of the protocol but also stand to benefit from the platform's success through these rewards.

An essential aspect of the Liquidity Gauge Pool is the role of veNPM voting power in determining reward distribution. Users who hold veNPM tokens, which are obtained by locking NPM tokens for a specified period, possess voting power in the Neptune Mutual community governance. The longer the lock duration, the higher the veNPM voting power, up to a maximum of 4x. This boosted voting power directly impacts the proportion of rewards users receive from the Liquidity Gauge Pool, as those with higher voting power are entitled to a larger share of NPM rewards.

IVoteEscrowToken Interface Summary#

// Neptune Mutual Protocol (
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.12;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "../../util/interfaces/IThrowable.sol";

interface IVoteEscrowLocker {
  event VoteEscrowLock(address indexed accocunt, uint256 amount, uint256 durationInWeeks, uint256 previousUnlockAt, uint256 unlockAt, uint256 previousBalance, uint256 balance);
  event VoteEscrowUnlock(address indexed accocunt, uint256 amount, uint256 unlockAt, uint256 penalty);

  error InvalidVoteLockPeriodError(uint256 min, uint256 max);
  error InvalidVoteLockExtensionError(uint256 min, uint256 proposed);

interface IVoteEscrowToken is IThrowable, IERC20Upgradeable, IVoteEscrowLocker {
  function lock(uint256 amount, uint256 durationInWeeks) external;
  function unlock() external;
  function unlockPrematurely() external;

  function calculateBoost(uint256 durationInWeeks) external pure returns (uint256);
  function getVotingPower(address account) external view returns (uint256);

  error VoteEscrowUnlockError(uint256 unlocksAt);
  error VoteEscrowAlreadyUnlockedError();
  error VoteEscrowUnlockOffsetError(uint256 height);

The VoteEscrowToken is an upgradeable contract. Interacting with VoteEscrowToken is relatively straightforward and easy:

  • `lock(amount, durationInWeeks)` --> Lock NPM tokens and received veNPM
  • `unlock()` --> Fully unlock all NPM tokens
  • `unlockPrematurely()` --> Prematurely unlock all NPM tokens paying a penalty
  • `calculateBoost(durationInWeeks)` --> Calculates boost for specified duration
  • `getVotingPower(account)` --> Returns the voting power of an account

lock(uint256 amount, uint256 durationInWeeks)#

Before submitting a lock transaction, make sure that you approve the VoteEscrowToken contract to spend your NPM tokens.

Lock your desired number of NPM tokens in the VoteEscrowToken contract for the specified duration in weeks. Upon successful completion of this transaction, you will received equal units of NPM in veNPM tokens. Your veNPM token balances will not automatically decrease. You will need to redeem your veNPM tokens to get back the NPM tokens locked using the same wallet used to lock them in the future.

Be Careful

For most users, veNPM token is non-transferrable. However, some third party protocols can be added to a whitelist which enables them to transfer their veNPM tokens. If they lose veNPM tokens, they will not be able to unlock their NPM tokens.

You can keep calling the lock function with zero amount and specifying durationInWeeks to keep extending your lock to maintain maximum boost. You can only specify lock duration that results in maturity being postponed.


Before you submit an unlock transaction, make sure that you approve the VoteEscrowToken contract to spend your veNPM tokens.

Upon maturity of your vote escrow lock period, you can unlock your NPM tokens. If you do not unlock your NPM tokens, your voting power will remain at 1x boost. You can unlock and withdraw your NPM tokens whenever you want after maturity.

If you try to call the function unlock before maturity, the transaction will throw VoteEscrowUnlockError along with the unix timestamp on which your lock matures.


Before you submit an `unlockPrematurely` transaction, make sure that you approve the `VoteEscrowToken` contract to spend your veNPM tokens.

Please proceed with caution. If you wish to unlock your NPM tokens before maturity, you will incur a penalty of 25%. If you try to call the function unlockPrematurely() after your maturity, the transaction will throw `VoteEscrowAlreadyUnlockedError`.

calculateBoost(uint256 durationInWeeks)#

The `calculateBoost(durationInWeeks)` pure function is the basis of the implementation of boosted voting power. By calling this function from the backend or frontend UI and specifying the duration of the lock in weeks, the boost for the given duration can be calculated.

getVotingPower(address account)#

In order to check your voting power, you can call the function getVotingPower(account) passing your account address as the parameter.

Your voting power decreases over time. To maintain highest boost power, you can call the function lock with zero amount and specifying lock duration in weeks. The maximum boosted voting power one can receive is 4x.