Contract Name:
StakingWithOptionalReferral
Contract Source Code:
File 1 of 1 : StakingWithOptionalReferral
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title StakingWithOptionalReferral - A staking contract for SANIC tokens with optional referrals and compounding rewards.
/// @dev This contract includes the IERC20 interface inline to avoid external imports.
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract StakingWithOptionalReferral {
IERC20 public sanicToken; // Token to be staked
address public feeRecipient; // Address to receive fees
address public owner; // Contract owner
uint256 public dailyRewardRate = 8; // 8% daily rewards
uint256 public depositFee = 5; // 5% deposit fee
uint256 public referralFee = 12; // 12% referral bonus if a referrer is provided
struct User {
uint256 depositedAmount;
uint256 lastClaimTime;
}
mapping(address => User) public users;
mapping(address => address) public referrers; // Tracks referrers for users
event Deposit(
address indexed user,
uint256 amount,
uint256 netAmount,
address indexed referrer
);
event ClaimRewards(address indexed user, uint256 reward, uint256 fee);
event Compound(address indexed user, uint256 compoundedAmount);
event FeePaid(address indexed user, uint256 fee);
event ReferralBonusPaid(address indexed referrer, uint256 bonus);
event TokenUpdated(address indexed oldToken, address indexed newToken);
event FeeRecipientUpdated(address indexed oldRecipient, address indexed newRecipient);
modifier onlyOwner() {
require(msg.sender == owner, "Not authorized");
_;
}
constructor() {
sanicToken = IERC20(0x18b7566936e19FdFff08A1e20c301bc401985666); // Hardcoded SANIC token address
feeRecipient = 0x18b7566936e19FdFff08A1e20c301bc401985666; // Hardcoded fee recipient address
owner = msg.sender;
}
function deposit(uint256 _amount, address _referrer) external {
require(_amount > 0, "Deposit amount must be greater than zero");
// Check allowance
uint256 allowance = sanicToken.allowance(msg.sender, address(this));
require(allowance >= _amount, "Token allowance too low. Approve the contract first.");
// Check sender's balance
uint256 balance = sanicToken.balanceOf(msg.sender);
require(balance >= _amount, "Insufficient token balance for deposit.");
// Transfer tokens from sender to contract
bool success = sanicToken.transferFrom(msg.sender, address(this), _amount);
require(success, "Token transfer failed");
// Calculate deposit fee
uint256 fee = (_amount * depositFee) / 100;
uint256 netAmount = _amount - fee;
// Transfer fee to feeRecipient
success = sanicToken.transfer(feeRecipient, fee);
require(success, "Fee transfer failed");
// Handle optional referral bonus
if (_referrer != address(0) && _referrer != msg.sender) {
uint256 referralBonus = (_amount * referralFee) / 100;
success = sanicToken.transfer(_referrer, referralBonus);
require(success, "Referral bonus transfer failed");
referrers[msg.sender] = _referrer;
emit ReferralBonusPaid(_referrer, referralBonus);
}
// Update user's deposited amount and last claim time
User storage user = users[msg.sender];
user.depositedAmount += netAmount;
user.lastClaimTime = block.timestamp;
emit Deposit(msg.sender, _amount, netAmount, _referrer);
emit FeePaid(msg.sender, fee);
}
function claimRewards() external {
User storage user = users[msg.sender];
require(user.depositedAmount > 0, "No deposits found");
uint256 rewards = calculateRewards(msg.sender);
require(rewards > 0, "No rewards available");
// Calculate claim fee
uint256 fee = (rewards * depositFee) / 100; // Claim rewards fee
uint256 netRewards = rewards - fee;
// Update user's last claim time
user.lastClaimTime = block.timestamp;
// Transfer net rewards to user
bool success = sanicToken.transfer(msg.sender, netRewards);
require(success, "Reward transfer failed");
// Transfer fee to feeRecipient
success = sanicToken.transfer(feeRecipient, fee);
require(success, "Fee transfer failed");
emit ClaimRewards(msg.sender, netRewards, fee);
}
function compound() external {
User storage user = users[msg.sender];
require(user.depositedAmount > 0, "No deposits found");
uint256 rewards = calculateRewards(msg.sender);
require(rewards > 0, "No rewards available");
// Update user's last claim time
user.lastClaimTime = block.timestamp;
// Add rewards to deposited amount (compounding)
user.depositedAmount += rewards;
emit Compound(msg.sender, rewards);
}
function calculateRewards(address _user) public view returns (uint256) {
User memory user = users[_user];
uint256 elapsedTime = block.timestamp - user.lastClaimTime;
uint256 dailyRewards = (user.depositedAmount * dailyRewardRate) / 100;
return (dailyRewards * elapsedTime) / 1 days;
}
function updateToken(address _newToken) external onlyOwner {
require(_newToken != address(0), "Invalid token address");
address oldToken = address(sanicToken);
sanicToken = IERC20(_newToken);
emit TokenUpdated(oldToken, _newToken);
}
function updateFeeRecipient(address _newRecipient) external onlyOwner {
require(_newRecipient != address(0), "Invalid fee recipient address");
address oldRecipient = feeRecipient;
feeRecipient = _newRecipient;
emit FeeRecipientUpdated(oldRecipient, _newRecipient);
}
function getDepositedAmount(address _user) external view returns (uint256) {
return users[_user].depositedAmount;
}
function getPendingRewards(address _user) external view returns (uint256) {
return calculateRewards(_user);
}
}