编译器
0.8.28+commit.7893614a
文件 1 的 5: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 的 5: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 的 5: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;
}
文件 4 的 5:SCMetagamePool.sol
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../Utils/SCPermissionedAccess.sol";
import "../../interfaces/IPermissionsManager.sol";
import "../../interfaces/ISCMetagamePool.sol";
contract SCMetagamePool is SCPermissionedAccess, ISCMetagamePool {
struct StakingData {
uint256 balance;
address msg_sender;
}
IERC20 public immutable token;
mapping(address => mapping(uint256 => StakingData)) _user_to_checkpoint_to_data;
mapping(address => uint256[]) _user_checkpoints;
mapping(address => mapping(address => uint256)) _user_to_approved_spend;
constructor(address permissions_, address token_) SCPermissionedAccess(permissions_) {
token = IERC20(token_);
}
function stake(uint256 amount_) external {
bool success = token.transferFrom(msg.sender, address(this), amount_);
if(!success) {
revert UnableToTransferTokens(msg.sender, amount_);
}
_stake(msg.sender, amount_);
}
function stakeFor(address staker_, uint256 amount_) external {
bool success = token.transferFrom(msg.sender, address(this), amount_);
if(!success) {
revert UnableToTransferTokens(msg.sender, amount_);
}
_stake(staker_, amount_);
}
function approve(address spender_, uint256 amount_) external {
_user_to_approved_spend[msg.sender][spender_] = amount_;
}
function spend(uint256 amount_, address staker_, address receiver_, string memory data_) external {
if(staker_ != msg.sender) {
uint256 approvedAmount = _user_to_approved_spend[staker_][msg.sender];
require(approvedAmount >= amount_, "Insufficient allowance");
_user_to_approved_spend[staker_][msg.sender] -= amount_;
}
uint256 _balance = _unstake(amount_, staker_, receiver_);
emit SpendFromStake(staker_, msg.sender, amount_, _balance, receiver_, data_);
}
function unstake(uint256 amount_) external {
uint256 _balance = _unstake(amount_, msg.sender, msg.sender);
emit Unstake(msg.sender, amount_, _balance);
}
function checkpoint_timestamps(address staker_) public view returns (uint256[] memory) {
return _user_checkpoints[staker_];
}
function checkpoint_timestamps_range(address staker_, uint256 start_, uint256 count_) public view returns (uint256[] memory _user_checkpoints_) {
uint256 totalCheckpoints = _user_checkpoints[staker_].length;
require(start_ < totalCheckpoints, "Start index out of bounds");
uint256 end = start_ + count_;
if (end > totalCheckpoints) {
end = totalCheckpoints;
}
_user_checkpoints_ = new uint256[](end - start_);
for (uint256 i = start_; i < end; i++) {
_user_checkpoints_[i - start_] = _user_checkpoints[staker_][i];
}
}
function checkpoints(address staker_, uint256[] memory checkpoint_timestamps_) public view returns (StakingData[] memory _data_) {
_data_ = new StakingData[](checkpoint_timestamps_.length);
uint256 len = checkpoint_timestamps_.length;
for(uint256 i = 0; i < len; i++) {
_data_[i] = _user_to_checkpoint_to_data[staker_][checkpoint_timestamps_[i]];
}
}
function _unstake(uint256 amount_, address staker_, address receiver_) internal returns (uint256) {
uint256[] storage _checkpoints = _user_checkpoints[staker_];
uint256 _balance = 0;
if(_checkpoints.length > 0) {
uint256 _last_ts = _checkpoints[_checkpoints.length-1];
_balance += _user_to_checkpoint_to_data[staker_][_last_ts].balance;
}
require(_balance >= amount_, "Insufficient balance");
_balance -= amount_;
bool success = token.transfer(receiver_, amount_);
if(!success) {
revert UnableToUnstakeTokens(staker_, amount_, token.balanceOf(address(this)));
}
uint256 _current_ts = block.timestamp;
_checkpoints.push(_current_ts);
StakingData memory newStakingData = StakingData({
balance: _balance,
msg_sender: msg.sender
});
_user_to_checkpoint_to_data[staker_][_current_ts] = newStakingData;
return _balance;
}
function _stake(address staker_, uint256 amount_) internal {
uint256[] storage _checkpoints = _user_checkpoints[staker_];
uint256 _balance = amount_;
if(_checkpoints.length > 0) {
uint256 _last_ts = _checkpoints[_checkpoints.length-1];
_balance += _user_to_checkpoint_to_data[staker_][_last_ts].balance;
}
uint256 _current_ts = block.timestamp;
_checkpoints.push(_current_ts);
StakingData memory newStakingData = StakingData({
balance: _balance,
msg_sender: msg.sender
});
_user_to_checkpoint_to_data[staker_][_current_ts] = newStakingData;
emit Stake(staker_, msg.sender, amount_, _balance);
}
}
文件 5 的 5: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);
}
}
{
"compilationTarget": {
"SuperChamps/contracts/Metagame/SCMetagamePool.sol": "SCMetagamePool"
},
"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"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UnableToTransferTokens","type":"error"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"total_staked_supply","type":"uint256"}],"name":"UnableToUnstakeTokens","type":"error"},{"inputs":[],"name":"UnexpectedBalance","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"address","name":"source","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"string","name":"data","type":"string"}],"name":"SpendFromStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"address","name":"source","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"Unstake","type":"event"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker_","type":"address"}],"name":"checkpoint_timestamps","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker_","type":"address"},{"internalType":"uint256","name":"start_","type":"uint256"},{"internalType":"uint256","name":"count_","type":"uint256"}],"name":"checkpoint_timestamps_range","outputs":[{"internalType":"uint256[]","name":"_user_checkpoints_","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker_","type":"address"},{"internalType":"uint256[]","name":"checkpoint_timestamps_","type":"uint256[]"}],"name":"checkpoints","outputs":[{"components":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"address","name":"msg_sender","type":"address"}],"internalType":"struct SCMetagamePool.StakingData[]","name":"_data_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permissions","outputs":[{"internalType":"contract IPermissionsManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"address","name":"staker_","type":"address"},{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"string","name":"data_","type":"string"}],"name":"spend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"stakeFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"}]