编译器
0.8.28+commit.7893614a
文件 1 的 7:IERC20.sol
pragma solidity ^0.8.20;
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 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 2 的 7:IPermissionsManager.sol
pragma solidity ^0.8.24;
interface IPermissionsManager{
enum Role {
ANY,
GLOBAL_ADMIN,
MINT_ADMIN,
TRANSFER_ADMIN,
SYSTEMS_ADMIN,
EXT1,
EXT2,
EXT3,
EXT4,
EXT5,
EXT6,
EXT7,
EXT8,
EXT9,
EXT10
}
function hasRole(Role role_, address account_) external view returns(bool);
function addRole(Role role_, address account_) external;
function removeRole(Role role_, address account_) external;
}
文件 3 的 7:ISCAccessPass.sol
pragma solidity ^0.8.24;
interface ISCAccessPass {
function isPassHolder(address addr_) external view returns (bool);
function isVerified(address addr_) external view returns (bool);
function getLevel(address addr_) external view returns (uint256);
function getLevel(uint256 id_) external view returns (uint256);
}
文件 4 的 7:ISCMetagamePool.sol
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface ISCMetagamePool{
event Stake(address staker, address source, uint256 amount, uint256 balance);
event Unstake(address staker, uint256 amount, uint256 balance);
event SpendFromStake(address staker, address source, uint256 amount, uint256 balance, address receiver, string data);
error UnableToTransferTokens(address staker, uint256 amount);
error UnableToUnstakeTokens(address staker, uint256 amount, uint256 total_staked_supply);
error UnexpectedBalance();
function stake(uint256 amount_) external;
function stakeFor(address staker_, uint256 amount_) external;
function approve(address spender_, uint256 amount_) external;
function spend(uint256 amount_, address staker_, address receiver_, string memory data_) external;
function unstake(uint256 amount_) external;
}
文件 5 的 7:ISCSeasonRewards.sol
pragma solidity ^0.8.24;
interface ISCSeasonRewards {
struct Season {
uint256 id;
uint256 start_time;
uint256 end_time;
uint256 reward_amount;
uint256 remaining_reward_amount;
uint256 claim_end_time;
}
function startSeason(
uint256 start_time_
) external returns(Season memory);
function endSeason(
uint256 id_
) external;
function finalize(
uint256 id_,
uint256 reward_amount_,
uint256 claim_duration
) external;
function reportRewards(
uint256 season_id_,
address[] calldata players_,
uint256[] calldata rewards_
) external;
function claimReward(
uint256 season_id_
) external;
function getClaimableReward(
uint256 season_id_
) external view returns(uint256);
function revokeUnclaimedReward(
uint256 id_
) external;
}
文件 6 的 7:SCPermissionedAccess.sol
pragma solidity ^0.8.24;
import "../../interfaces/IPermissionsManager.sol";
contract SCPermissionedAccess {
IPermissionsManager public immutable permissions;
modifier isGlobalAdmin() {
require(permissions.hasRole(IPermissionsManager.Role.GLOBAL_ADMIN, msg.sender), "Not a Global Admin");
_;
}
modifier isSystemsAdmin() {
require(permissions.hasRole(IPermissionsManager.Role.SYSTEMS_ADMIN, msg.sender), "Not a Systems Admin");
_;
}
constructor(address _permissions){
permissions = IPermissionsManager(_permissions);
}
}
文件 7 的 7:SCSeasonRewards.sol
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../Utils/SCPermissionedAccess.sol";
import "../../interfaces/IPermissionsManager.sol";
import "../../interfaces/ISCSeasonRewards.sol";
import "../../interfaces/ISCAccessPass.sol";
import "../../interfaces/ISCMetagamePool.sol";
contract SCSeasonRewards is ISCSeasonRewards, SCPermissionedAccess{
IERC20 immutable token;
address treasury;
ISCAccessPass public access_pass;
ISCMetagamePool public staking_pool;
ISCSeasonRewards.Season[] public seasons;
mapping(uint256 => mapping(address => uint256)) public season_rewards;
mapping(uint256 => mapping(address => uint256)) public claimed_rewards;
mapping(bytes => bool) private consumed_signatures;
mapping(address => uint256) public player_last_signature_timestamp;
event TreasurySet(address treasury);
event StakedRewards(address staker, uint256 rewards);
constructor(
address permissions_,
address token_,
address treasury_,
address access_pass_,
address staking_pool_)
SCPermissionedAccess(permissions_)
{
token = IERC20(token_);
treasury = treasury_;
access_pass = ISCAccessPass(access_pass_);
staking_pool = ISCMetagamePool(staking_pool_);
}
function setTreasury(address treasury_) external isGlobalAdmin {
treasury = treasury_;
emit TreasurySet(treasury_);
}
function startSeason(
uint256 start_time_
) external isSystemsAdmin returns(ISCSeasonRewards.Season memory season_)
{
require(start_time_ > 0, "CANNOT START AT 0");
season_.start_time = start_time_;
season_.end_time = type(uint256).max;
season_.id = uint32(seasons.length);
seasons.push(season_);
}
function isSeasonActive(
Season memory season_,
uint256 timestamp_
) public pure returns(bool _active)
{
_active = season_.end_time >= timestamp_ && timestamp_ > season_.start_time;
}
function isSeasonFinalized(
Season memory season_
) public pure returns(bool _finalized)
{
_finalized = season_.claim_end_time > 0;
}
function isSeasonEnded(
Season memory season_,
uint256 timestamp_
) public pure returns(bool _ended)
{
_ended = season_.end_time < timestamp_;
}
function isSeasonClaimingActive(
Season memory season_,
uint256 timestamp_
) public pure returns(bool _active)
{
_active = isSeasonFinalized(season_) && season_.claim_end_time >= timestamp_;
}
function isSeasonClaimingEnded(
Season memory season_,
uint256 timestamp_
) public pure returns(bool _ended)
{
_ended = isSeasonFinalized(season_) && season_.claim_end_time < timestamp_;
}
function endSeason(
uint256 id_
) external isSystemsAdmin
{
Season storage _season = seasons[id_];
require(_season.start_time > 0, "SEASON NOT FOUND");
require(isSeasonActive(_season, block.timestamp), "SEASON NOT ACTIVE");
_season.end_time = block.timestamp;
}
function revokeUnclaimedReward(
uint256 id_
) external isSystemsAdmin
{
Season storage _season = seasons[id_];
uint256 _remaining_reward_amount = _season.remaining_reward_amount;
require(_season.start_time > 0, "SEASON NOT FOUND");
require(isSeasonClaimingEnded(_season, block.timestamp), "SEASON_CLAIM_NOT_ENDED");
require(_remaining_reward_amount > 0, "ZERO_REMAINING_AMOUNT");
bool transfer_success = token.transfer(treasury, _remaining_reward_amount);
require(transfer_success, "FAILED TRANSFER");
_season.remaining_reward_amount -= uint128(_remaining_reward_amount);
}
function finalize(
uint256 id_,
uint256 reward_amount_,
uint256 claim_duration_
) external isSystemsAdmin
{
Season storage _season = seasons[id_];
require(_season.start_time > 0, "SEASON NOT FOUND");
require(isSeasonEnded(_season, block.timestamp), "SEASON_NOT_ENDED");
require(!isSeasonFinalized(_season), "SEASON_FINALIZED");
require(reward_amount_ == _season.reward_amount, "REWARD AMOUNT DOESN'T MATCH");
require(claim_duration_ >= 7 days && claim_duration_ < 1000 days, "CLAIM DURATION OUT OF BOUNDS");
bool transfer_success = token.transferFrom(treasury, address(this), reward_amount_);
require(transfer_success, "FAILED TRANSFER");
_season.remaining_reward_amount = reward_amount_;
_season.claim_end_time = block.timestamp + claim_duration_;
}
function reportRewards(
uint256 season_id_,
address[] calldata players_,
uint256[] calldata rewards_
) external isSystemsAdmin
{
require(players_.length == rewards_.length, "ARRAYS MISMATCH");
Season storage _season = seasons[season_id_];
require(_season.start_time > 0, "SEASON NOT FOUND");
require(!isSeasonFinalized(_season), "SEASON FINALIZED");
uint256 _increase = 0;
uint256 _decrease = 0;
for (uint256 i = 0; i < players_.length; i++) {
_increase += rewards_[i];
_decrease += season_rewards[season_id_][players_[i]];
season_rewards[season_id_][players_[i]] = rewards_[i];
}
_season.reward_amount += _increase;
_season.reward_amount -= _decrease;
}
function _preClaim(
uint256 season_id_
) internal
returns (uint256)
{
require(claimed_rewards[season_id_][msg.sender] == 0, "REWARD CLAIMED");
Season storage _season = seasons[season_id_];
require(isSeasonClaimingActive(_season, block.timestamp), "SEASON_CLAIM_ENDED");
uint256 _reward = season_rewards[season_id_][msg.sender];
require(_reward > 0, "MUST HAVE A NON ZERO REWARD");
_season.remaining_reward_amount -= _reward;
claimed_rewards[season_id_][msg.sender] = _reward;
return _reward;
}
function claimReward(
uint256 season_id_
) external
{
uint256 _reward = _preClaim(season_id_);
bool transfer_success = token.transfer(msg.sender, _reward);
require(transfer_success, "FAILED TRANSFER");
}
function stakeReward(
uint256 season_id_
) external
{
uint256 _reward = _preClaim(season_id_);
token.approve(address(staking_pool), _reward);
staking_pool.stakeFor(msg.sender, _reward);
emit StakedRewards(msg.sender, _reward);
}
function getClaimableReward(
uint256 season_id_
) public view returns(uint256 _reward)
{
_reward = season_rewards[season_id_][msg.sender] - claimed_rewards[season_id_][msg.sender];
Season storage _season = seasons[season_id_];
if( !isSeasonClaimingActive(_season, block.timestamp) )
{
_reward = 0;
}
}
function recoverERC20(address tokenAddress_, uint256 tokenAmount_) external isGlobalAdmin {
IERC20(tokenAddress_).transfer(msg.sender, tokenAmount_);
}
}
{
"compilationTarget": {
"SuperChamps/contracts/Seasons/SCSeasonRewards.sol": "SCSeasonRewards"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 20
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"permissions_","type":"address"},{"internalType":"address","name":"token_","type":"address"},{"internalType":"address","name":"treasury_","type":"address"},{"internalType":"address","name":"access_pass_","type":"address"},{"internalType":"address","name":"staking_pool_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"StakedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"treasury","type":"address"}],"name":"TreasurySet","type":"event"},{"inputs":[],"name":"access_pass","outputs":[{"internalType":"contract ISCAccessPass","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"season_id_","type":"uint256"}],"name":"claimReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"claimed_rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"endSeason","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"uint256","name":"reward_amount_","type":"uint256"},{"internalType":"uint256","name":"claim_duration_","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"season_id_","type":"uint256"}],"name":"getClaimableReward","outputs":[{"internalType":"uint256","name":"_reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"start_time","type":"uint256"},{"internalType":"uint256","name":"end_time","type":"uint256"},{"internalType":"uint256","name":"reward_amount","type":"uint256"},{"internalType":"uint256","name":"remaining_reward_amount","type":"uint256"},{"internalType":"uint256","name":"claim_end_time","type":"uint256"}],"internalType":"struct ISCSeasonRewards.Season","name":"season_","type":"tuple"},{"internalType":"uint256","name":"timestamp_","type":"uint256"}],"name":"isSeasonActive","outputs":[{"internalType":"bool","name":"_active","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"start_time","type":"uint256"},{"internalType":"uint256","name":"end_time","type":"uint256"},{"internalType":"uint256","name":"reward_amount","type":"uint256"},{"internalType":"uint256","name":"remaining_reward_amount","type":"uint256"},{"internalType":"uint256","name":"claim_end_time","type":"uint256"}],"internalType":"struct ISCSeasonRewards.Season","name":"season_","type":"tuple"},{"internalType":"uint256","name":"timestamp_","type":"uint256"}],"name":"isSeasonClaimingActive","outputs":[{"internalType":"bool","name":"_active","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"start_time","type":"uint256"},{"internalType":"uint256","name":"end_time","type":"uint256"},{"internalType":"uint256","name":"reward_amount","type":"uint256"},{"internalType":"uint256","name":"remaining_reward_amount","type":"uint256"},{"internalType":"uint256","name":"claim_end_time","type":"uint256"}],"internalType":"struct ISCSeasonRewards.Season","name":"season_","type":"tuple"},{"internalType":"uint256","name":"timestamp_","type":"uint256"}],"name":"isSeasonClaimingEnded","outputs":[{"internalType":"bool","name":"_ended","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"start_time","type":"uint256"},{"internalType":"uint256","name":"end_time","type":"uint256"},{"internalType":"uint256","name":"reward_amount","type":"uint256"},{"internalType":"uint256","name":"remaining_reward_amount","type":"uint256"},{"internalType":"uint256","name":"claim_end_time","type":"uint256"}],"internalType":"struct ISCSeasonRewards.Season","name":"season_","type":"tuple"},{"internalType":"uint256","name":"timestamp_","type":"uint256"}],"name":"isSeasonEnded","outputs":[{"internalType":"bool","name":"_ended","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"start_time","type":"uint256"},{"internalType":"uint256","name":"end_time","type":"uint256"},{"internalType":"uint256","name":"reward_amount","type":"uint256"},{"internalType":"uint256","name":"remaining_reward_amount","type":"uint256"},{"internalType":"uint256","name":"claim_end_time","type":"uint256"}],"internalType":"struct ISCSeasonRewards.Season","name":"season_","type":"tuple"}],"name":"isSeasonFinalized","outputs":[{"internalType":"bool","name":"_finalized","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"permissions","outputs":[{"internalType":"contract IPermissionsManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"player_last_signature_timestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress_","type":"address"},{"internalType":"uint256","name":"tokenAmount_","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"season_id_","type":"uint256"},{"internalType":"address[]","name":"players_","type":"address[]"},{"internalType":"uint256[]","name":"rewards_","type":"uint256[]"}],"name":"reportRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"revokeUnclaimedReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"season_rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"seasons","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"start_time","type":"uint256"},{"internalType":"uint256","name":"end_time","type":"uint256"},{"internalType":"uint256","name":"reward_amount","type":"uint256"},{"internalType":"uint256","name":"remaining_reward_amount","type":"uint256"},{"internalType":"uint256","name":"claim_end_time","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"treasury_","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"season_id_","type":"uint256"}],"name":"stakeReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"staking_pool","outputs":[{"internalType":"contract ISCMetagamePool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start_time_","type":"uint256"}],"name":"startSeason","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"start_time","type":"uint256"},{"internalType":"uint256","name":"end_time","type":"uint256"},{"internalType":"uint256","name":"reward_amount","type":"uint256"},{"internalType":"uint256","name":"remaining_reward_amount","type":"uint256"},{"internalType":"uint256","name":"claim_end_time","type":"uint256"}],"internalType":"struct ISCSeasonRewards.Season","name":"season_","type":"tuple"}],"stateMutability":"nonpayable","type":"function"}]