Built on Uniswap V3 Staker
Expanded by Revert Finance
Special thanks to Uniswap and Revert Finance for creating the foundational liquidity incentives infrastructure.
This repository contains the deployment configuration and scripts for Neverland's Uniswap V3 Staker, a liquidity incentives protocol on Monad. The codebase extends Uniswap's canonical staking contract and Revert Finance's enhancements with custom deployment tooling, network support, and operational infrastructure specific to Neverland's requirements.
- Key Features
- Requirements
- Getting Started
- Deployment
- Common Operations
- Contract Verification
- Project Structure
- Incentive Configuration
- License and Attribution
- Monad Native: Built for Monad's parallel execution environment
- Enhanced Deployment: Complete Hardhat-based deployment system with artifact management
- Network Integration: Native support for Monad testnet and mainnet
- Flexible Configuration: Customizable incentive parameters (lead time, duration, lockups)
- Extendable Epochs: Refundee can extend incentives in rolling windows (each extension is bounded by
maxIncentiveDuration, but total lifetime can exceed the original duration) - Production Ready: Comprehensive testing and verification infrastructure
- Neverland Specific: Optimized for Neverland's DUST/MON liquidity incentives with perpetual extensions, lockups, and harvest‑while‑staked flows
- Proportional Rewards: Time-weighted liquidity rewards based on position size and duration
- Vesting Support: Configurable vesting periods for locked incentives (per position, enforced on harvest)
- Lockup Periods: Optional lockup periods preventing early unstaking while allowing harvesting
- Rolling Extensions: Incentives can be extended multiple times; each extension respects
maxIncentiveDurationfrom the extension moment but the overall program can continue indefinitely - Harvest-While-Staked: LPs can harvest rewards without exiting once vesting is satisfied
- Multi-Incentive Staking: Single positions can participate in multiple concurrent incentives
- Per-stake vesting memory: Once a stake satisfies vesting, subsequent harvests/unstakes on that stake do not reapply vesting unless the position is unstaked and restaked
- Locked reward sweep: Refundee can collect vesting penalties (
totalRewardLocked) mid-program; unclaimed rewards stay in the contract - Permissionless: Anyone can create liquidity incentives
- ERC20 Agnostic: Support for any reward token (with security considerations)
- Vesting semantics: Vesting is time-in-range based. Once a stake vests, future harvests/unstakes skip vesting until the stake is exited and re-entered.
- Refundee powers: After
endTime, refundee can force-unstake positions (lockup bypass). At any time, refundee can sweeptotalRewardLocked(forfeited rewards);totalRewardUnclaimedis untouched. - Lockup grace: A 1-hour grace window after staking allows the owner to unstake even if lockup is set (to correct misconfigured/out-of-range positions). After that, lockup applies until expiry.
- Timing helper:
getStakeTimingexposes grace/lockup endpoints, time-in-range accrued, vesting remaining, and vesting status for frontends. - Extensions: Extending changes the forward reward rate depending on how much reward is added vs. how much time is added; past accruals are unaffected.
- ERC20 Rewards: Designed for standard ERC20 reward tokens only.
- Node.js >= 16
- Private key or mnemonic for deployment account
- RPC access to Monad networks
- Block explorer API keys (Optional, for verification)
-
Install dependencies:
yarn install -
Compile contracts before running any other command:
yarn compile
-
Copy the
.env.exampleto.env:cp .env.example .env
-
Configure your
.envfile:# Etherscan API key for contract verification ETHERSCAN_API_KEY=your_etherscan_api_key_here # Private key for contract deployment PRIVATE_KEY=your_private_key_here # Monad Mainnet RPC URL MONAD_RPC_URL=your_monad_mainnet_rpc_url # Uniswap V3 Factory addresses UNISWAP_V3_FACTORY_MONAD=0x... UNISWAP_V3_POSITION_MANAGER_MONAD=0x... UNISWAP_V3_FACTORY_MONAD_TESTNET=0x... UNISWAP_V3_POSITION_MANAGER_MONAD_TESTNET=0x...
# Full deployment with verification
npx hardhat deploy --network monad-testnet --verify
# Deploy without verification
npx hardhat deploy --network monad-testnet# Deploy to mainnet
npx hardhat deploy --network monad --verifyOverride default incentive configuration:
# Custom lead time and duration
npx hardhat deploy --network monad-testnet \
--maxIncentiveStartLeadTime 2419200 \
--maxIncentiveDuration 2592000 \
--verify# Check deployment artifacts
cat deployments-monad-testnet.json
cat deployments/monad-testnet/UniswapV3Staker.jsonAfter deployment, incentives can be created using the deployed contract:
// Example: Create DUST/MON incentive with lockup period
const incentiveKey = {
rewardToken: USDC_ADDRESS,
pool: DUST_MON_POOL_ADDRESS,
startTime: Math.floor(Date.now() / 1000) + 86400, // Tomorrow
endTime: Math.floor(Date.now() / 1000) + 86400 * 7, // 7 days
vestingPeriod: 86400 * 3, // 3 days vesting (full rewards after 3 days in range)
lockupPeriod: 86400 * 2, // 2 days lockup (cannot unstake for 2 days)
refundee: treasuryAddress,
};
await staker.createIncentive(incentiveKey, rewardAmount);// Approve NFT transfer
await positionManager.approve(stakerAddress, tokenId);
// Stake position
await positionManager.safeTransferFrom(
userAddress,
stakerAddress,
tokenId,
ethers.utils.defaultAbiCoder.encode(["tuple(...)"], [incentiveKey])
);Contracts are automatically verified during deployment when using the --verify flag.
├── contracts/ # Uniswap V3 Staker contract and interfaces
├── scripts/ # Deployment and utility scripts
│ ├── deploy.ts # Main deployment script with artifact generation
│ └── deploy-config.ts # Network-specific configuration
├── test/ # Test suites and fixtures
├── docs/ # Documentation and design specifications
│ ├── Design.md # Core contract design and mechanics
│ └── Neverland.md # Neverland-specific deployment and configuration
├── deployments/ # Deployment artifacts per network
├── hardhat.config.ts # Hardhat configuration
├── package.json # Project dependencies and scripts
└── README.md # This file
Note:
maxIncentiveDurationlimits how far into the future each extension may push the end time. Refundee can extend again after that window elapses, so total lifetime can exceed 28 days.
Each incentive is defined by an IncentiveKey with the following parameters:
- Reward Token: ERC20 token used for rewards
- Pool: Uniswap V3 pool address for the incentive
- Start Time: When the incentive becomes active
- End Time: When the incentive expires
- Vesting Period: Time required in-range for full rewards (0 = immediate)
- Lockup Period: Time before unstaking is allowed (0 = no lockup)
- Refundee: Address that can refund unused rewards
- Start Time: Must be now or in the future, max 28 days ahead
- Duration: End time - start time ≤ 28 days
- Vesting: Must be ≤ incentive duration
- Lockup: Must be ≤ incentive duration and either 0 or greater than the 1-hour grace window
- Reward: Must be > 0
- Refundee: Must be valid address
- Vesting is enforced per stake: a position must spend at least
vestingPeriodseconds in range since its last harvest before it can harvest again. - If a user unstakes before vesting completes, the contract keeps the original behavior (partial rewards, remainder locked for refundee).
- Harvesting after vesting completes resets the per-stake timer; users who want frequent harvests should set
vestingPeriod = 0(instant vesting).
Neverland uses lockup periods and rolling extensions to stabilize liquidity:
- During Lockup: Users can harvest rewards but cannot unstake positions
- After Lockup: Normal unstaking behavior (subject to vesting penalties if applicable)
- Independent of Vesting: Lockup controls unstaking, vesting controls reward harvesting
- Refundee Override: Incentive creators can always unstake after incentive end, regardless of lockup
- Post-Expiry Enforcement: Lockup timers continue to apply even if the incentive has ended; owners must satisfy the full lockup duration, while refunders can unstake immediately after the program ends (for clean-up scenarios).
- On-Chain Data:
incentives(incentiveId)now returns(totalRewardUnclaimed, totalRewardLocked, totalSecondsClaimedX128, numberOfStakes, endTime, vestingPeriod, lockupPeriod).
- Added optional
lockupPeriodparameter to prevent early unstaking - Added support for incentives extension by
extLockupPeriod - Lockup periods work independently from vesting periods
- Users can harvest rewards during lockup but cannot unstake
| Network | Status | Address |
|---|---|---|
| Monad | Production | 0x... |
| Monad Testnet | Testnet | 0x... |
The main change compared to v1.0.2 is the addition of a new configuration value called vestingPeriod, which defines the minimal time a staked position needs to be in range to receive the full reward.
| Network | Status | Address |
|---|---|---|
| Polygon | Production | 0x8c696deF6Db3104DF72F7843730784460795659a |
| Network | Status | Address |
|---|---|---|
| Mainnet | Production | 0xe34139463bA50bD61336E0c446Bd8C0867c6fE65 |
| Rinkeby | Testnet | 0xe34139463bA50bD61336E0c446Bd8C0867c6fE65 |
| Kovan | Testnet | 0xe34139463bA50bD61336E0c446Bd8C0867c6fE65 |
| Ropsten | Testnet | 0xe34139463bA50bD61336E0c446Bd8C0867c6fE65 |
| Goerli | Testnet | 0xe34139463bA50bD61336E0c446Bd8C0867c6fE65 |
| Arbitrum Rinkeby | Testnet | 0xe34139463bA50bD61336E0c446Bd8C0867c6fE65 |
| Arbitrum One | Production | 0xe34139463bA50bD61336E0c446Bd8C0867c6fE65 |
| Optimism | Production | 0xe34139463bA50bD61336E0c446Bd8C0867c6fE65 |
| Optimism Kovan | Testnet | 0xe34139463bA50bD61336E0c446Bd8C0867c6fE65 |
DEPRECATED: For historical verification purposes only, the staker at tag v1.0.0 was deployed at the address: 0x1f98407aaB862CdDeF78Ed252D6f557aA5b0f00d
Uniswap V3 Staker is part of the Uniswap protocol, licensed under GPL-2.0-or-later.
Revert Finance Expansion extends the core functionality with the vestingPeriod.
Neverland Enhancement adds the lockupPeriod feature for enhanced incentive design flexibility and extLockupPeriod for incentives extension, while harvestRewards is created to allow users to harvest rewards during lockup periods without unstaking.
This repository builds on:
- Uniswap V3 Staker: Core staking mechanics and reward distribution
- Revert Finance: Enhanced reward distribution with vesting period
- Neverland: Lockup periods for controlled unstaking, incentives extension and rewards claiming during lockup periods without unstaking.
For Uniswap governance and licensing questions, visit Uniswap Governance.
With respect and gratitude to the Uniswap and Revert Finance communities 💜