编译器
0.8.19+commit.7dd6d404
文件 1 的 12:AccessControlBase.sol
import "@openzeppelin/contracts/utils/Context.sol";
import "../interfaces/core/IVaultAccessControlRegistry.sol";
pragma solidity 0.8.19;
contract AccessControlBase is Context {
IVaultAccessControlRegistry public immutable registry;
address public immutable timelockAddressImmutable;
constructor(address _vaultRegistry, address _timelock) {
registry = IVaultAccessControlRegistry(_vaultRegistry);
timelockAddressImmutable = _timelock;
}
modifier onlyGovernance() {
require(registry.isCallerGovernance(_msgSender()), "Forbidden: Only Governance");
_;
}
modifier onlyEmergency() {
require(registry.isCallerEmergency(_msgSender()), "Forbidden: Only Emergency");
_;
}
modifier onlySupport() {
require(registry.isCallerSupport(_msgSender()), "Forbidden: Only Support");
_;
}
modifier onlyTeam() {
require(registry.isCallerTeam(_msgSender()), "Forbidden: Only Team");
_;
}
modifier onlyProtocol() {
require(registry.isCallerProtocol(_msgSender()), "Forbidden: Only Protocol");
_;
}
modifier protocolNotPaused() {
require(!registry.isProtocolPaused(), "Forbidden: Protocol Paused");
_;
}
modifier onlyTimelockGovernance() {
address timelockActive_;
if (!registry.timelockActivated()) {
timelockActive_ = registry.governanceAddress();
} else {
timelockActive_ = timelockAddressImmutable;
}
require(_msgSender() == timelockActive_, "Forbidden: Only TimelockGovernance");
_;
}
}
文件 2 的 12:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 12:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 4 的 12:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, 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 from,
address to,
uint256 amount
) external returns (bool);
}
文件 5 的 12:ITokenManager.sol
pragma solidity 0.8.19;
interface ITokenManager {
function takeVestedWINR(address _from, uint256 _amount) external;
function takeWINR(address _from, uint256 _amount) external;
function sendVestedWINR(address _to, uint256 _amount) external;
function sendWINR(address _to, uint256 _amount) external;
function burnVestedWINR(uint256 _amount) external;
function burnWINR(uint256 _amount) external;
function mintWINR(address _to, uint256 _amount) external;
function sendWLP(address _to, uint256 _amount) external;
function mintOrTransferByPool(address _to, uint256 _amount) external;
function mintVestedWINR(address _input, uint256 _amount, address _recipient) external returns(uint256 _mintAmount);
function mintedByGames() external returns (uint256);
function MAX_MINT() external returns (uint256);
function share(uint256 amount) external;
}
文件 6 的 12:IVaultAccessControlRegistry.sol
import "@openzeppelin/contracts/access/IAccessControl.sol";
pragma solidity >=0.6.0 <0.9.0;
interface IVaultAccessControlRegistry is IAccessControl {
function timelockActivated() external view returns (bool);
function governanceAddress() external view returns (address);
function pauseProtocol() external;
function unpauseProtocol() external;
function isCallerGovernance(address _account) external view returns (bool);
function isCallerEmergency(address _account) external view returns (bool);
function isCallerProtocol(address _account) external view returns (bool);
function isCallerTeam(address _account) external view returns (bool);
function isCallerSupport(address _account) external view returns (bool);
function isProtocolPaused() external view returns (bool);
function changeGovernanceAddress(address _governanceAddress) external;
event DeadmanSwitchFlipped();
event GovernanceChange(address newGovernanceAddress);
}
文件 7 的 12:IWINR.sol
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWINR is IERC20 {
function mint(address account, uint256 amount) external returns (uint256, uint256);
function burn(uint256 amount) external;
function MAX_SUPPLY() external view returns (uint256);
}
文件 8 的 12:IWINRStaking.sol
pragma solidity 0.8.19;
interface IWINRStaking {
function share(uint256 amount) external;
function totalWeight() external view returns (uint256);
struct StakeDividend {
uint256 amount;
uint256 profitDebt;
uint256 weight;
uint128 depositTime;
}
struct StakeVesting {
uint256 amount;
uint256 weight;
uint256 vestingDuration;
uint256 profitDebt;
uint256 startTime;
uint256 accTokenFirstDay;
uint256 accTokenPerDay;
bool withdrawn;
bool cancelled;
}
struct Period {
uint256 duration;
uint256 minDuration;
uint256 claimDuration;
uint256 minPercent;
}
struct WeightMultipliers {
uint256 winr;
uint256 vWinr;
uint256 vWinrVesting;
}
event Donation(address indexed player, uint amount);
event Share(uint256 amount, uint256 totalWeight, uint256 totalStakedVWINR, uint256 totalStakedWINR);
event DepositVesting(
address indexed user,
uint256 index,
uint256 startTime,
uint256 endTime,
uint256 amount,
uint256 profitDebt,
bool isVested,
bool isVesting
);
event DepositDividend(
address indexed user,
uint256 amount,
uint256 profitDebt,
bool isVested
);
event Withdraw(
address indexed user,
uint256 withdrawTime,
uint256 index,
uint256 amount,
uint256 redeem,
uint256 vestedBurn
);
event WithdrawBatch(
address indexed user,
uint256 withdrawTime,
uint256[] indexes,
uint256 amount,
uint256 redeem,
uint256 vestedBurn
);
event Unstake(
address indexed user,
uint256 unstakeTime,
uint256 amount,
uint256 burnedAmount,
bool isVested
);
event Cancel(
address indexed user,
uint256 cancelTime,
uint256 index,
uint256 burnedAmount,
uint256 sentAmount
);
event ClaimVesting(address indexed user, uint256 reward, uint256 index);
event ClaimVestingBatch(address indexed user, uint256 reward, uint256[] indexes);
event ClaimDividend(address indexed user, uint256 reward, bool isVested);
event ClaimDividendBatch(address indexed user, uint256 reward);
event WeightMultipliersUpdate(WeightMultipliers _weightMultipliers);
event UnstakeBurnPercentageUpdate(uint256 _unstakeBurnPercentage);
}
文件 9 的 12:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 10 的 12:ReentrancyGuard.sol
pragma solidity >=0.8.0;
abstract contract ReentrancyGuard {
uint256 private locked = 1;
modifier nonReentrant() virtual {
require(locked == 1, "REENTRANCY");
locked = 2;
_;
locked = 1;
}
}
文件 11 的 12:WINRStaking.sol
pragma solidity 0.8.19;
import "./WINRVesting.sol";
contract WINRStaking is WINRVesting {
mapping(address => StakeDividend) public dividendWINRStakes;
mapping(address => StakeDividend) public dividendVestedWINRStakes;
constructor(
address _vaultRegistry,
address _timelock
) WINRVesting(_vaultRegistry, _timelock) {}
function dividendStakedAmount(
address _account,
bool _isVested
) external view returns (uint256) {
return
_isVested
? dividendVestedWINRStakes[_account].amount
: dividendWINRStakes[_account].amount;
}
function getDividendStake(
address _account,
bool _isVested
) external view returns (StakeDividend memory) {
return
_isVested
? dividendVestedWINRStakes[_account]
: dividendWINRStakes[_account];
}
function pendingDividendRewards(address _account) external view returns (uint256 pending_) {
pending_ += _pendingByDividendStake(dividendVestedWINRStakes[_account]);
pending_ += _pendingByDividendStake(dividendWINRStakes[_account]);
}
fallback() external payable {
emit Donation(msg.sender, msg.value);
}
receive() external payable {
emit Donation(msg.sender, msg.value);
}
function share(uint256 _amount) external override isAmountNonZero(_amount) onlyProtocol {
if (totalWeight > 0) {
totalProfit += _amount;
totalEarned += _amount;
accumProfitPerWeight += (_amount * PRECISION) / totalWeight;
emit Share(_amount, totalWeight, totalStakedVestedWINR, totalStakedWINR);
}
}
function claimDividend() external whenNotPaused nonReentrant {
_claimDividendBatch(msg.sender);
}
function pause() public onlyTeam {
_pause();
}
function unpause() public onlyTeam {
_unpause();
}
function withdrawDonations(address payable to, uint256 amount) external onlyGovernance {
require(address(this).balance >= amount, "Insufficient balance");
(bool sent, ) = to.call{value: amount}("");
require(sent, "Withdraw failed");
}
function updatePeriod(
uint256 duration,
uint256 minDuration,
uint256 claimDuration,
uint256 minPercent
) external onlyGovernance {
require(
duration >= minDuration,
"Duration must be greater than or equal to minimum duration"
);
require(
claimDuration <= duration,
"Claim duration must be less than or equal to duration"
);
period.duration = duration;
period.minDuration = minDuration;
period.claimDuration = claimDuration;
period.minPercent = minPercent;
}
function depositDividend(
uint256 _amount,
bool _isVested
) external isAmountNonZero(_amount) nonReentrant whenNotPaused {
address sender_ = msg.sender;
StakeDividend storage stake_;
if (_isVested) {
tokenManager.takeVestedWINR(sender_, _amount);
stake_ = dividendVestedWINRStakes[sender_];
totalStakedVestedWINR += _amount;
} else {
tokenManager.takeWINR(sender_, _amount);
stake_ = dividendWINRStakes[sender_];
totalStakedWINR += _amount;
}
if (stake_.amount > 0) {
_claimDividend(sender_, _isVested);
}
uint256 weight_ = _calculateWeight(stake_.amount + _amount, _isVested, false);
totalWeight += (weight_ - stake_.weight);
stake_.amount += _amount;
stake_.depositTime = uint128(block.timestamp);
stake_.weight = weight_;
stake_.profitDebt = _calcDebt(weight_);
emit DepositDividend(sender_, stake_.amount, stake_.profitDebt, _isVested);
}
function unstake(uint256 _amount, bool _isVested) external nonReentrant whenNotPaused {
address sender_ = msg.sender;
StakeDividend storage stake_ = _isVested
? dividendVestedWINRStakes[sender_]
: dividendWINRStakes[sender_];
require(stake_.amount >= _amount, "Insufficient stake amount");
ITokenManager tokenManager_ = tokenManager;
uint256 burnAmount_ = _computeBurnAmount(_amount);
uint256 sendAmount_ = _amount - burnAmount_;
uint256 unstakedWeight_;
_claimDividend(sender_, _isVested);
if (_isVested) {
tokenManager_.burnVestedWINR(burnAmount_);
tokenManager_.sendVestedWINR(sender_, sendAmount_);
unstakedWeight_ = _amount * weightMultipliers.vWinr;
totalStakedVestedWINR -= _amount;
} else {
tokenManager_.burnWINR(burnAmount_);
tokenManager_.sendWINR(sender_, sendAmount_);
unstakedWeight_ = _amount * weightMultipliers.winr;
totalStakedWINR -= _amount;
}
totalWeight -= unstakedWeight_;
stake_.amount -= _amount;
stake_.weight -= unstakedWeight_;
stake_.profitDebt = _calcDebt(stake_.weight);
emit Unstake(sender_, block.timestamp, sendAmount_, burnAmount_, _isVested);
}
function _claimDividend(
address _account,
bool _isVested
) internal returns (uint256 reward_) {
StakeDividend storage stake_ = _isVested
? dividendVestedWINRStakes[_account]
: dividendWINRStakes[_account];
reward_ = _pendingByDividendStake(stake_);
if (reward_ == 0) {
return 0;
}
tokenManager.sendWLP(_account, reward_);
stake_.profitDebt = _calcDebt(stake_.weight);
totalClaimed[_account] += reward_;
emit ClaimDividend(_account, reward_, _isVested);
}
function _claimDividendBatch(address _account) internal returns (uint256 reward_) {
StakeDividend storage stakeVWINR_ = dividendVestedWINRStakes[_account];
StakeDividend storage stakeWINR_ = dividendWINRStakes[_account];
reward_ = _pendingByDividendStake(stakeVWINR_);
reward_ += _pendingByDividendStake(stakeWINR_);
if (reward_ == 0) {
return 0;
}
tokenManager.sendWLP(_account, reward_);
stakeVWINR_.profitDebt = _calcDebt(stakeVWINR_.weight);
stakeWINR_.profitDebt = _calcDebt(stakeWINR_.weight);
totalClaimed[_account] += reward_;
emit ClaimDividendBatch(_account, reward_);
}
function _pendingByDividendStake(
StakeDividend memory _stake
) internal view returns (uint256 holderProfit_) {
holderProfit_ = ((_stake.weight * accumProfitPerWeight) / PRECISION);
if (holderProfit_ < _stake.profitDebt) {
return 0;
} else {
holderProfit_ -= _stake.profitDebt;
}
}
}
文件 12 的 12:WINRVesting.sol
pragma solidity 0.8.19;
import "solmate/src/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "../../core/AccessControlBase.sol";
import "../../interfaces/core/ITokenManager.sol";
import "../../interfaces/tokens/IWINR.sol";
import "../../interfaces/stakings/IWINRStaking.sol";
abstract contract WINRVesting is IWINRStaking, Pausable, ReentrancyGuard, AccessControlBase {
modifier isAmountNonZero(uint256 amount) {
require(amount > 0, "amount must be greater than zero");
_;
}
uint256 internal constant PRECISION = 1e18;
uint256 public totalProfit;
uint256 public totalWeight;
uint256 public totalStakedWINR;
uint256 public totalStakedVestedWINR;
uint256 public accumProfitPerWeight;
uint256 public unstakeBurnPercentage;
uint256 public totalEarned;
ITokenManager public tokenManager;
mapping(address => StakeVesting[]) public stakes;
mapping(address => uint256[]) public activeVestingIndexes;
mapping(address => uint256) public totalClaimed;
Period public period = Period(180 days, 15 days, 165, 5e17);
WeightMultipliers public weightMultipliers = WeightMultipliers(1, 2, 1);
constructor(
address _vaultRegistry,
address _timelock
) AccessControlBase(_vaultRegistry, _timelock) {
unstakeBurnPercentage = 5e15;
}
function pendingVestingRewards(address account) external view returns (uint256 pending) {
uint256[] memory activeIndexes = getActiveIndexes(account);
for (uint256 i = 0; i < activeIndexes.length; i++) {
StakeVesting memory stake = stakes[account][activeIndexes[i]];
pending += _pendingWLPOfStake(stake);
}
}
function pendingVestingByIndex(
address account,
uint256 index
) external view returns (uint256 pending) {
StakeVesting memory stake = stakes[account][index];
if(stake.withdrawn || stake.cancelled) return 0;
pending = _pendingWLPOfStake(stake);
}
function withdrawableTokens(
address _account,
uint256 _index
) external view returns (uint256 _withdrawable) {
StakeVesting memory _stake = stakes[_account][_index];
_withdrawable = _withdrawableByVesting(_stake);
if (_stake.startTime + _stake.vestingDuration > block.timestamp) {
_withdrawable = 0;
}
}
function getActiveIndexes(address staker) public view returns (uint[] memory indexes) {
indexes = activeVestingIndexes[staker];
}
function vestingStakedAmount(
address _account,
uint256[] calldata _indexes
) external view returns (uint256 _totalStaked) {
for (uint256 i = 0; i < _indexes.length; i++) {
StakeVesting memory _stake = stakes[_account][_indexes[i]];
_totalStaked += _stake.amount;
}
}
function globalData()
external
view
returns (uint256 _totalStakedVWINR, uint256 _totalStakedWINR, uint256 _totalEarned)
{
_totalStakedVWINR = totalStakedVestedWINR;
_totalStakedWINR = totalStakedWINR;
_totalEarned = totalEarned;
}
function getVestingStake(
address _account,
uint256 _index
) public view returns (StakeVesting memory _stake) {
_stake = stakes[_account][_index];
}
function getVestingStakeLength(address _account) external view returns (uint256 _length) {
_length = stakes[_account].length;
}
function _calcDebt(uint256 _weight) internal view returns (uint256 debt) {
debt = (_weight * accumProfitPerWeight) / PRECISION;
}
function _calculateWeight(
uint256 amount,
bool vested,
bool vesting
) internal view returns (uint256) {
return
!vested ? amount * weightMultipliers.winr : vesting
? amount * weightMultipliers.vWinrVesting
: amount * weightMultipliers.vWinr;
}
function _pendingWLPOfStake(StakeVesting memory stake) internal view returns (uint256) {
uint256 holderProfit = ((stake.weight * accumProfitPerWeight) / PRECISION);
return holderProfit < stake.profitDebt ? 0 : holderProfit - stake.profitDebt;
}
function _computeBurnAmount(uint256 amount) internal view returns (uint256 _burnAmount) {
_burnAmount = (amount * unstakeBurnPercentage) / PRECISION;
}
function _withdrawableByVesting(
StakeVesting memory stake
) internal view returns (uint256 withdrawable_) {
uint256 totalStakedDuration_ = (block.timestamp - stake.startTime) / 1 days;
uint256 _minDays = period.minDuration / 1 days;
if (totalStakedDuration_ < _minDays) {
return 0;
}
if (block.timestamp > stake.startTime + stake.vestingDuration) {
totalStakedDuration_ = stake.vestingDuration / 1 days;
}
withdrawable_ =
stake.accTokenFirstDay +
((stake.amount - stake.accTokenFirstDay) *
(totalStakedDuration_ - _minDays)) /
period.claimDuration;
}
function cancel(uint256 _index) external {
address sender_ = msg.sender;
StakeVesting memory stake;
(stake) = getVestingStake(sender_, _index);
require(!stake.withdrawn, "stake has withdrawn");
require(!stake.cancelled, "stake has cancelled");
_removeActiveIndex(sender_, _index);
uint256 amount_ = stake.amount;
uint256 burnAmount_ = _computeBurnAmount(amount_);
uint256 sendAmount_ = amount_ - burnAmount_;
totalStakedVestedWINR -= amount_;
totalWeight -= stake.weight;
uint256 reward_ = _pendingWLPOfStake(stake);
if(reward_ > 0) {
accumProfitPerWeight += (reward_ * PRECISION) / totalWeight;
stakes[sender_][_index].profitDebt += reward_;
}
stakes[sender_][_index].cancelled = true;
stakes[sender_][_index].amount = 0;
tokenManager.sendVestedWINR(sender_, sendAmount_);
tokenManager.burnVestedWINR(burnAmount_);
emit Cancel(sender_, block.timestamp, _index, burnAmount_, sendAmount_);
}
function setUnstakeBurnPercentage(uint256 _unstakeBurnPercentage) external onlyGovernance {
unstakeBurnPercentage = _unstakeBurnPercentage;
emit UnstakeBurnPercentageUpdate(_unstakeBurnPercentage);
}
function setTokenManager(ITokenManager _tokenManager) external onlyGovernance {
require(
address(_tokenManager) != address(0),
"token manager address can not be zero"
);
tokenManager = _tokenManager;
}
function depositVesting(
uint256 amount,
uint256 vestingDuration
) external isAmountNonZero(amount) nonReentrant whenNotPaused {
uint256 vestingDurationInSeconds = vestingDuration * 1 days;
require(
vestingDurationInSeconds >= period.minDuration &&
vestingDuration <= period.duration,
"duration must be in period"
);
address sender = msg.sender;
uint256 weight = _calculateWeight(amount, true, true);
uint256 profitDebt = _calcDebt(weight);
uint256 startTime = block.timestamp;
uint256 accTokenFirstDay = (amount * period.minPercent) / PRECISION;
uint256 accTokenPerDay = (amount - accTokenFirstDay) / period.claimDuration;
tokenManager.takeVestedWINR(sender, amount);
totalWeight += weight;
totalStakedVestedWINR += amount;
stakes[sender].push(
StakeVesting(
amount,
weight,
vestingDurationInSeconds,
profitDebt,
startTime,
accTokenFirstDay,
accTokenPerDay,
false,
false
)
);
uint256 _index = stakes[msg.sender].length - 1;
_addActiveIndex(msg.sender, _index);
emit DepositVesting(
sender,
_index,
startTime,
vestingDurationInSeconds,
amount,
profitDebt,
true,
true
);
}
function claimVesting(uint256[] calldata indexes) external whenNotPaused nonReentrant {
require(indexes.length > 0, "empty indexes");
_claim(indexes, true);
}
function withdrawVesting(uint256 _index) external whenNotPaused nonReentrant {
address sender_ = msg.sender;
StakeVesting storage stake_ = stakes[sender_][_index];
require(
block.timestamp >= stake_.startTime + stake_.vestingDuration,
"You can't withdraw the stake yet"
);
require(!stake_.withdrawn, "already withdrawn");
require(!stake_.cancelled, "stake cancelled");
uint256 redeemable_ = _withdrawableByVesting(stake_);
uint256 reward_ = _pendingWLPOfStake(stake_);
if (redeemable_ > 0) {
tokenManager.mintOrTransferByPool(sender_, redeemable_);
}
uint256 amountToBurn = stake_.amount - redeemable_;
if (amountToBurn > 0) {
tokenManager.mintWINR(address(tokenManager), amountToBurn);
tokenManager.burnWINR(amountToBurn);
}
tokenManager.burnVestedWINR(stake_.amount);
if (reward_ > 0) {
tokenManager.sendWLP(sender_, reward_);
stakes[sender_][_index].profitDebt += reward_;
totalProfit -= reward_;
totalClaimed[sender_] += reward_;
emit ClaimVesting(sender_, reward_, _index);
}
stake_.withdrawn = true;
_removeActiveIndex(sender_, _index);
totalWeight -= stake_.weight;
totalStakedVestedWINR -= stake_.amount;
emit Withdraw(
sender_,
block.timestamp,
_index,
stake_.weight,
stake_.weight,
stake_.amount
);
}
function withdrawVestingBatch(
uint256[] calldata indexes
) external whenNotPaused nonReentrant {
address sender = msg.sender;
uint256[4] memory _amounts;
for (uint256 i = 0; i < indexes.length; i++) {
uint256 index = indexes[i];
StakeVesting storage stake = stakes[sender][index];
require(
block.timestamp >= stake.startTime + stake.vestingDuration,
"You can't withdraw the stake yet"
);
require(!stake.withdrawn, "already withdrawn");
require(!stake.cancelled, "stake cancelled");
_amounts[0] += stake.weight;
_amounts[1] += _withdrawableByVesting(stake);
_amounts[2] += _pendingWLPOfStake(stake);
_amounts[3] += stake.amount;
stake.withdrawn = true;
_removeActiveIndex(sender, index);
}
if (_amounts[1] > 0) {
tokenManager.mintOrTransferByPool(sender, _amounts[1]);
}
uint256 amountToBurn = _amounts[3] - _amounts[1];
if (amountToBurn > 0) {
tokenManager.mintWINR(address(tokenManager), amountToBurn);
tokenManager.burnWINR(amountToBurn);
}
tokenManager.burnVestedWINR(_amounts[3]);
totalWeight -= _amounts[0];
totalStakedVestedWINR -= _amounts[3];
_claim(indexes, false);
emit WithdrawBatch(
sender,
block.timestamp,
indexes,
_amounts[1],
_amounts[1],
_amounts[3]
);
}
function _claim(uint256[] memory indexes, bool isClaim) internal {
address sender_ = msg.sender;
uint256 totalFee_;
for (uint256 i = 0; i < indexes.length; i++) {
uint256 index_ = indexes[i];
StakeVesting storage stake_ = stakes[sender_][index_];
if (isClaim) {
require(!stake_.withdrawn, "Stake has already been withdrawn");
}
require(!stake_.cancelled, "Stake has been cancelled");
uint256 fee_ = _pendingWLPOfStake(stake_);
stake_.profitDebt += fee_;
totalFee_ += fee_;
}
totalProfit -= totalFee_;
totalClaimed[sender_] += totalFee_;
if (totalFee_ > 0) {
tokenManager.sendWLP(sender_, totalFee_);
}
emit ClaimVestingBatch(sender_, totalFee_, indexes);
}
function _removeActiveIndex(address staker, uint index) internal {
uint[] storage indexes = activeVestingIndexes[staker];
uint length = indexes.length;
for (uint i = 0; i < length; i++) {
if (indexes[i] == index) {
indexes[i] = indexes[length - 1];
indexes.pop();
return;
}
}
}
function _addActiveIndex(address staker, uint256 index) internal {
uint[] storage indexes;
indexes = activeVestingIndexes[staker];
indexes.push(index);
}
function share(uint256 amount) external virtual override {}
}
{
"compilationTarget": {
"contracts/stakings/WINR-staking/WINRStaking.sol": "WINRStaking"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@ensdomains/=node_modules/@ensdomains/",
":@openzeppelin/=node_modules/@openzeppelin/",
":@uniswap/=node_modules/@uniswap/",
":base64-sol/=node_modules/base64-sol/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":eth-gas-reporter/=node_modules/eth-gas-reporter/",
":forge-std/=lib/forge-std/src/",
":hardhat/=node_modules/hardhat/",
":solmate/=node_modules/solmate/"
]
}
[{"inputs":[{"internalType":"address","name":"_vaultRegistry","type":"address"},{"internalType":"address","name":"_timelock","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"cancelTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sentAmount","type":"uint256"}],"name":"Cancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isVested","type":"bool"}],"name":"ClaimDividend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"ClaimDividendBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"ClaimVesting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"indexes","type":"uint256[]"}],"name":"ClaimVestingBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"profitDebt","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isVested","type":"bool"}],"name":"DepositDividend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"profitDebt","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isVested","type":"bool"},{"indexed":false,"internalType":"bool","name":"isVesting","type":"bool"}],"name":"DepositVesting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Donation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalWeight","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStakedVWINR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStakedWINR","type":"uint256"}],"name":"Share","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"unstakeTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnedAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isVested","type":"bool"}],"name":"Unstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_unstakeBurnPercentage","type":"uint256"}],"name":"UnstakeBurnPercentageUpdate","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"winr","type":"uint256"},{"internalType":"uint256","name":"vWinr","type":"uint256"},{"internalType":"uint256","name":"vWinrVesting","type":"uint256"}],"indexed":false,"internalType":"struct IWINRStaking.WeightMultipliers","name":"_weightMultipliers","type":"tuple"}],"name":"WeightMultipliersUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeem","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vestedBurn","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawTime","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeem","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vestedBurn","type":"uint256"}],"name":"WithdrawBatch","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"accumProfitPerWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"activeVestingIndexes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimDividend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"indexes","type":"uint256[]"}],"name":"claimVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_isVested","type":"bool"}],"name":"depositDividend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"vestingDuration","type":"uint256"}],"name":"depositVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_isVested","type":"bool"}],"name":"dividendStakedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"dividendVestedWINRStakes","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"profitDebt","type":"uint256"},{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"uint128","name":"depositTime","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"dividendWINRStakes","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"profitDebt","type":"uint256"},{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"uint128","name":"depositTime","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getActiveIndexes","outputs":[{"internalType":"uint256[]","name":"indexes","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_isVested","type":"bool"}],"name":"getDividendStake","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"profitDebt","type":"uint256"},{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"uint128","name":"depositTime","type":"uint128"}],"internalType":"struct IWINRStaking.StakeDividend","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getVestingStake","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"uint256","name":"vestingDuration","type":"uint256"},{"internalType":"uint256","name":"profitDebt","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"accTokenFirstDay","type":"uint256"},{"internalType":"uint256","name":"accTokenPerDay","type":"uint256"},{"internalType":"bool","name":"withdrawn","type":"bool"},{"internalType":"bool","name":"cancelled","type":"bool"}],"internalType":"struct IWINRStaking.StakeVesting","name":"_stake","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getVestingStakeLength","outputs":[{"internalType":"uint256","name":"_length","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalData","outputs":[{"internalType":"uint256","name":"_totalStakedVWINR","type":"uint256"},{"internalType":"uint256","name":"_totalStakedWINR","type":"uint256"},{"internalType":"uint256","name":"_totalEarned","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"pendingDividendRewards","outputs":[{"internalType":"uint256","name":"pending_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"pendingVestingByIndex","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"pendingVestingRewards","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"period","outputs":[{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"minDuration","type":"uint256"},{"internalType":"uint256","name":"claimDuration","type":"uint256"},{"internalType":"uint256","name":"minPercent","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract IVaultAccessControlRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ITokenManager","name":"_tokenManager","type":"address"}],"name":"setTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unstakeBurnPercentage","type":"uint256"}],"name":"setUnstakeBurnPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"share","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakes","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"uint256","name":"vestingDuration","type":"uint256"},{"internalType":"uint256","name":"profitDebt","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"accTokenFirstDay","type":"uint256"},{"internalType":"uint256","name":"accTokenPerDay","type":"uint256"},{"internalType":"bool","name":"withdrawn","type":"bool"},{"internalType":"bool","name":"cancelled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timelockAddressImmutable","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManager","outputs":[{"internalType":"contract ITokenManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalEarned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalProfit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStakedVestedWINR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStakedWINR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_isVested","type":"bool"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakeBurnPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"minDuration","type":"uint256"},{"internalType":"uint256","name":"claimDuration","type":"uint256"},{"internalType":"uint256","name":"minPercent","type":"uint256"}],"name":"updatePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256[]","name":"_indexes","type":"uint256[]"}],"name":"vestingStakedAmount","outputs":[{"internalType":"uint256","name":"_totalStaked","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weightMultipliers","outputs":[{"internalType":"uint256","name":"winr","type":"uint256"},{"internalType":"uint256","name":"vWinr","type":"uint256"},{"internalType":"uint256","name":"vWinrVesting","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawDonations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"withdrawVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"indexes","type":"uint256[]"}],"name":"withdrawVestingBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"withdrawableTokens","outputs":[{"internalType":"uint256","name":"_withdrawable","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]