Address
0x46bcb4bb405cd0a3bafc549fce33cd9044a1a20bCurrent Holdings
$0.2531
TXs sent
not counted
First Active
2025-11-29
block 25,138,267
Last Active
292 days ago
block 25,150,707
Funded By
not identified
Net worth historyi
7 snapshots · to block 27,497,273coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
exact matchavstaking2solc 0.8.29+commit.ab55807cruntime exact · creation exact
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IERC20 {
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function transfer(address to, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
contract avstaking2 {
IERC20 public immutable stakingToken;
IERC20[] private _rewardTokens; // ← private = no auto getter
address public owner;
uint256 public constant DAILY_BP = 2500;
uint256 public constant BP_DIVISOR = 10000;
uint256 public constant SECONDS_PER_DAY = 86400;
uint256 public constant PRECISION = 1e24;
struct RewardPool {
uint256 rewardPerStakedToken;
uint256 lastUpdate;
uint256 leftoverRewards;
}
struct UserInfo {
uint256 staked;
uint256 rewardDebt;
uint256 pending;
}
uint256 public totalStaked;
mapping(uint256 => RewardPool) public rewardPools;
mapping(address => mapping(uint256 => UserInfo)) private users; // ← private = no auto getter
event Staked(address indexed user, uint256 amount);
event Unstaked(address indexed user, uint256 amount);
event Claimed(address indexed user, uint256 amount, IERC20 indexed token);
event RewardAdded(IERC20 indexed token, uint256 amount);
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
constructor() {
owner = msg.sender;
stakingToken = IERC20(0xA6E768f384F70cfDe30DbbdA37ccD84734718c7d); // AVRL
_addRewardToken(IERC20(0xA1077a294dDE1B09bB078844df40758a5D0f9a27)); // WPLS
}
function stake(uint256 amount) external {
require(amount > 0, "Zero");
for (uint256 i = 0; i < _rewardTokens.length; i++) _updateUser(msg.sender, i);
require(stakingToken.transferFrom(msg.sender, address(this), amount), "TF");
for (uint256 i = 0; i < _rewardTokens.length; i++) users[msg.sender][i].staked += amount;
totalStaked += amount;
emit Staked(msg.sender, amount);
}
function unstake(uint256 amount) external {
require(amount > 0, "Zero");
for (uint256 i = 0; i < _rewardTokens.length; i++) {
UserInfo storage info = users[msg.sender][i];
require(info.staked >= amount, "Low");
_updateUser(msg.sender, i);
info.staked -= amount;
}
totalStaked -= amount;
require(stakingToken.transfer(msg.sender, amount), "TF");
emit Unstaked(msg.sender, amount);
}
function claimAll() external {
for (uint256 i = 0; i < _rewardTokens.length; i++) {
_updateUser(msg.sender, i);
uint256 reward = users[msg.sender][i].pending;
if (reward > 0) {
users[msg.sender][i].pending = 0;
require(_rewardTokens[i].transfer(msg.sender, reward), "TF");
emit Claimed(msg.sender, reward, _rewardTokens[i]);
}
}
}
function _updateReward(uint256 i) internal {
RewardPool storage pool = rewardPools[i];
if (block.timestamp <= pool.lastUpdate || totalStaked == 0 || pool.leftoverRewards == 0) return;
uint256 elapsed = block.timestamp - pool.lastUpdate;
pool.lastUpdate = block.timestamp;
uint256 daily = (pool.leftoverRewards * DAILY_BP) / BP_DIVISOR;
uint256 reward = (daily * elapsed) / SECONDS_PER_DAY;
if (reward > pool.leftoverRewards) reward = pool.leftoverRewards;
pool.leftoverRewards -= reward;
pool.rewardPerStakedToken += (reward * PRECISION) / totalStaked;
}
function _updateUser(address user, uint256 i) internal {
_updateReward(i);
UserInfo storage info = users[user][i];
RewardPool storage pool = rewardPools[i];
uint256 acc = (info.staked * pool.rewardPerStakedToken) / PRECISION;
uint256 owed = acc - info.rewardDebt;
if (owed > 0) info.pending += owed;
info.rewardDebt = acc;
}
// Owner
function _addRewardToken(IERC20 token) internal {
for (uint256 i = 0; i < _rewardTokens.length; i++) require(_rewardTokens[i] != token, "Exists");
_rewardTokens.push(token);
rewardPools[_rewardTokens.length - 1].lastUpdate = block.timestamp;
}
function addRewardToken(IERC20 token) external onlyOwner { _addRewardToken(token); }
function depositRewards(IERC20 token, uint256 amount) external onlyOwner {
uint256 index = type(uint256).max;
for (uint256 i = 0; i < _rewardTokens.length; i++) {
if (_rewardTokens[i] == token) { index = i; break; }
}
require(index != type(uint256).max, "Not reward");
require(token.transferFrom(msg.sender, address(this), amount), "TF");
rewardPools[index].leftoverRewards += amount;
emit RewardAdded(token, amount);
}
// ==== VIEWS (manual getters — no clashes) ====
function getUserInfo(address user, uint256 index) external view returns (uint256 staked, uint256 rewardDebt, uint256 pending) {
UserInfo memory info = users[user][index];
return (info.staked, info.rewardDebt, info.pending);
}
function rewardTokenCount() external view returns (uint256) { return _rewardTokens.length; }
function rewardTokenAt(uint256 i) external view returns (address) { return address(_rewardTokens[i]); }
function apr(address tokenAddr) external view returns (uint256) {
for (uint256 i = 0; i < _rewardTokens.length; i++) {
if (address(_rewardTokens[i]) == tokenAddr && totalStaked > 0) {
uint256 daily = (rewardPools[i].leftoverRewards * DAILY_BP) / BP_DIVISOR;
return (daily * 365 * 1e18) / totalStaked;
}
}
return 0;
}
}