Description:
Decentralized Finance (DeFi) protocol contract providing Staking functionality.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IVault {
function deposit() external payable;
function withdraw(uint256 amount, address to) external;
}
interface IReward {
function addReward(address user, uint256 amount) external;
}
contract Staking {
address public owner;
IVault public vault;
IReward public reward;
uint256 public constant MAX_STAKES_PER_USER = 100;
struct StakeInfo {
uint256 amount;
uint256 startTime;
uint256 lockupPeriod;
bool claimed;
}
mapping(address => StakeInfo[]) public stakes;
mapping(uint256 => uint256) public lockupRewardPercents;
// --- ReentrancyGuard
uint256 private _status;
modifier nonReentrant() {
require(_status != 2, "ReentrancyGuard: reentrant call");
_status = 2;
_;
_status = 1;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only owner");
_;
}
constructor() {
owner = msg.sender;
vault = IVault(0x40b5aF46D2833Be7Ee22Ff139Ec3CAe9B04D08DC);
reward = IReward(0x2795717F2D0e9325b79Fe1B7e22540A3e7dFA6E5);
lockupRewardPercents[15 days] = 5;
lockupRewardPercents[30 days] = 15;
lockupRewardPercents[60 days] = 35;
lockupRewardPercents[90 days] = 55;
lockupRewardPercents[180 days] = 115;
lockupRewardPercents[365 days] = 230;
_status = 1;
}
function stake(uint256 _lockupPeriod) external payable nonReentrant {
require(msg.value > 0, "Stake must be > 0");
require(lockupRewardPercents[_lockupPeriod] > 0, "Invalid lockup period");
require(stakes[msg.sender].length < MAX_STAKES_PER_USER, "Too many stakes");
stakes[msg.sender].push(
StakeInfo({
amount: msg.value,
startTime: block.timestamp,
lockupPeriod: _lockupPeriod,
claimed: false
})
);
vault.deposit{value: msg.value}();
}
function claimReward(uint256 index) external nonReentrant {
StakeInfo storage stakeData = stakes[msg.sender][index];
require(!stakeData.claimed, "Already claimed");
require(block.timestamp >= stakeData.startTime + stakeData.lockupPeriod, "Still locked");
uint256 rewardAmount = calculateReward(stakeData.amount, stakeData.lockupPeriod);
stakeData.claimed = true;
reward.addReward(msg.sender, rewardAmount);
}
function unstake(uint256 index) external nonReentrant {
StakeInfo storage stakeData = stakes[msg.sender][index];
require(block.timestamp >= stakeData.startTime + stakeData.lockupPeriod, "Still locked");
uint256 amount = stakeData.amount;
uint256 lastIndex = stakes[msg.sender].length - 1;
if (index != lastIndex) {
stakes[msg.sender][index] = stakes[msg.sender][lastIndex];
}
stakes[msg.sender].pop();
vault.withdraw(amount, msg.sender);
}
function calculateReward(uint256 amount, uint256 lockup) public view returns (uint256) {
uint256 percent = lockupRewardPercents[lockup];
return (amount * percent) / 100;
}
function getStakes(address user) external view returns (StakeInfo[] memory) {
return stakes[user];
}
function setLockupRewardPercent(uint256 period, uint256 percent) external onlyOwner {
lockupRewardPercents[period] = percent;
}
function setVault(address _vault) external onlyOwner {
require(_vault != address(0), "Invalid address");
vault = IVault(_vault);
}
function setReward(address _reward) external onlyOwner {
require(_reward != address(0), "Invalid address");
reward = IReward(_reward);
}
}
Submitted on: 2025-09-28 11:37:51
Comments
Log in to comment.
No comments yet.