编译器
0.8.17+commit.8df45f5f
文件 1 的 11: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;
}
}
文件 2 的 11:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 3 的 11:NFTContractFunctions.sol
pragma solidity 0.8.17;
interface NFTContractFunctions {
function balanceOf(address owner) external view returns (uint256);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator)
external
view
returns (bool);
function approve(address to, uint256 tokenId) external;
}
文件 4 的 11:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 5 的 11: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());
}
}
文件 6 的 11:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
}
文件 7 的 11:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
文件 8 的 11:burnFunctions.sol
pragma solidity 0.8.17;
interface burnFunctions {
function burnKeys(uint256[] memory _keysToBeUsed, address _spender)
external;
}
文件 9 的 11:migratingSourceFunctions.sol
pragma solidity 0.8.17;
interface migratingSourceFunctions {
function getSingleStake(address _staker, uint256 index)
external
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256,
uint256
);
}
文件 10 的 11:stakeable.sol
pragma solidity 0.8.17;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./migratingSourceFunctions.sol";
contract Stakeable is ReentrancyGuard {
using SafeMath for uint256;
uint256 private initialTimestamp;
uint256 private _maxAllowancePerKey = 5000000000000000000;
uint256 private timePeriod;
uint256 private maxPositions = 4;
uint256 private MinStakeValueToClosePosition = 100000000000000000;
uint256 private MovePercentageBasisNumber = 50;
uint256 private minWithdraw = 100000000000000000;
address private StakingAccount;
bool private MoveFundsUponReceipt;
bool private partialWithdraw = true;
bool private lockdown = false;
bool private MovePercentageOfFundsUponReceipt = true;
bytes32 private constant ADMIN = keccak256(abi.encodePacked("ADMIN"));
bytes32 private constant EXEC = keccak256(abi.encodePacked("EXEC"));
bytes32 private constant CLAIM = keccak256(abi.encodePacked("CLAIM"));
Stakeholder[] internal stakeholders;
mapping(bytes32 => mapping(address => bool)) public roles;
mapping(address => uint256) internal stakes;
mapping(uint256 => poolGroup[]) private poolGroups;
event GrantRole(bytes32 indexed role, address indexed account);
event RevokeRole(bytes32 indexed role, address indexed account);
event Withdrawn(address indexed, uint256 amount, uint256 timestamp);
event Extended(
address user,
uint256 amount,
uint256 since,
uint256 reward,
uint256 timePeriod,
uint256 usedKeys
);
event Staked(
address indexed user,
uint256 amount,
uint256 index,
uint256 timestamp,
uint256 _plan,
uint256 timePeriod,
uint256 usedKeys
);
event Migrated(
address indexed user,
uint256 amount,
uint256 index,
uint256 timestamp,
uint256 _plan,
uint256 timePeriod,
uint256 usedKeys
);
struct Stake {
address user;
uint256 amount;
uint256 since;
uint256 percentage;
uint256 timePeriod;
uint256 reward;
uint256 usedKeys;
bool paused;
uint256 poolID;
}
struct Stakeholder {
address user;
Stake[] address_stakes;
}
struct poolGroup {
uint256 id;
bool active;
}
struct StakingSummary {
Stake[] stakes;
}
constructor() {
stakeholders.push();
}
function _addStakeholder(address staker) private returns (uint256) {
stakeholders.push();
uint256 userIndex = stakeholders.length - 1;
stakeholders[userIndex].user = staker;
stakes[staker] = userIndex;
return userIndex;
}
function _stake(
uint256 _amount,
uint256 _percentage,
uint256 _timePeriodInSeconds,
address _Sender,
uint256 usedKeys,
uint256 poolID
) internal {
require(poolGroups[poolID].length > 0, "No Pool");
require(StakingAccount != address(0), "Staking account not set.");
require(canStake(_Sender, _percentage), "Max open positions.");
if (MoveFundsUponReceipt) {
payable(StakingAccount).transfer(_amount);
}
if (MovePercentageOfFundsUponReceipt) {
payable(StakingAccount).transfer(
(_amount.mul(MovePercentageBasisNumber)).div(100)
);
}
uint256 index = stakes[_Sender];
uint256 timestamp = block.timestamp;
if (index == 0) {
index = _addStakeholder(_Sender);
}
initialTimestamp = block.timestamp;
timePeriod = initialTimestamp.add(_timePeriodInSeconds);
stakeholders[index].address_stakes.push(
Stake(
payable(_Sender),
_amount,
timestamp,
_percentage,
timePeriod,
0,
usedKeys,
false,
poolID
)
);
emit Staked(
_Sender,
_amount,
index,
timestamp,
_percentage,
timePeriod,
usedKeys
);
}
function _admin_stake(
uint256 _amount,
uint256 _percentage,
uint256 _timePeriodInSeconds,
address _Sender,
uint256 _startTime,
uint256 usedKeys,
uint256 rewards,
uint256 poolID
) internal {
require(canStake(_Sender, _percentage), "Max open positions.");
require(poolGroups[poolID].length > 0, "No Pool");
uint256 index = stakes[_Sender];
uint256 timestamp = _startTime;
if (index == 0) {
index = _addStakeholder(_Sender);
}
initialTimestamp = _startTime;
timePeriod = initialTimestamp.add(_timePeriodInSeconds);
stakeholders[index].address_stakes.push(
Stake(
payable(_Sender),
_amount,
timestamp,
_percentage,
timePeriod,
rewards,
usedKeys,
false,
poolID
)
);
emit Staked(
_Sender,
_amount,
index,
timestamp,
_percentage,
timePeriod,
usedKeys
);
}
function _migrateStake(
uint256 _amount,
uint256 _percentage,
uint256 _timePeriodInSeconds,
uint256 _startTime,
uint256 usedKeys,
uint256 _reward,
uint256 poolID
) internal {
require(poolGroups[poolID].length > 0, "No Pool");
require(canStake(msg.sender, _percentage), "Max open positions.");
uint256 index = stakes[msg.sender];
if (index == 0) {
index = _addStakeholder(msg.sender);
}
stakeholders[index].address_stakes.push(
Stake(
msg.sender,
_amount,
_startTime,
_percentage,
_timePeriodInSeconds,
_reward,
usedKeys,
false,
poolID
)
);
emit Migrated(
msg.sender,
_amount,
index,
_startTime,
_percentage,
_timePeriodInSeconds,
usedKeys
);
}
function calculateStakeReward(Stake memory _current_stake)
private
view
returns (uint256)
{
if (block.timestamp > _current_stake.timePeriod) {
return
(_current_stake.amount.mul(_current_stake.percentage)).div(100);
}
return 0;
}
function toggleStakeStatus(
address _staker,
bool _status,
uint256 index
) external onlyRole(EXEC) {
uint256 user_index = stakes[_staker];
require(user_index > 0, "Address not registered.");
Stake memory current_stake = stakeholders[user_index].address_stakes[
index
];
require(current_stake.amount > 0, "No active positions.");
stakeholders[user_index].address_stakes[index].paused = _status;
}
function _withdrawStake(uint256 index) internal {
require(lockdown == false, "Contract Locked.");
uint256 user_index = stakes[msg.sender];
require(user_index > 0, "Address not registered.");
require(index <= maxPositions - 1, "Index out of range.");
Stake memory current_stake = stakeholders[user_index].address_stakes[
index
];
require(
poolGroups[current_stake.poolID][0].active,
"Pool Temporary Suspended"
);
require(current_stake.amount > 0, "No active positions.");
require(
block.timestamp >= current_stake.timePeriod,
"Not matured yet."
);
uint256 reward = current_stake.reward.add(
calculateStakeReward(current_stake)
);
require(reward > 0, "Claim not ready.");
uint256 _amount = current_stake.amount.add(reward);
require(_amount >= minWithdraw, "Amount is less than minimum");
require(address(this).balance > _amount, "Not enough balance.");
delete stakeholders[user_index].address_stakes[index];
stakeholders[user_index].address_stakes[index] = stakeholders[
user_index
].address_stakes[stakeholders[user_index].address_stakes.length - 1];
stakeholders[user_index].address_stakes.pop();
payable(msg.sender).transfer(_amount);
emit Withdrawn(msg.sender, _amount, block.timestamp);
}
function _withdrawReturn(uint256 index) internal {
require(lockdown == false, "Contract Locked.");
uint256 user_index = stakes[msg.sender];
require(user_index > 0, "Address not registered.");
require(partialWithdraw, "Partial withdraw is not enabled.");
require(index <= maxPositions - 1, "Index out of range.");
Stake memory current_stake = stakeholders[user_index].address_stakes[
index
];
require(
poolGroups[current_stake.poolID][0].active,
"Pool Temporary Suspended"
);
require(current_stake.amount > 0, "No active positions.");
require(
block.timestamp >= current_stake.timePeriod,
"Not matured yet."
);
uint256 reward = current_stake.reward.add(
calculateStakeReward(current_stake)
);
require(reward > 0, "Claim not ready.");
uint256 _amount = reward;
require(_amount >= minWithdraw, "Amount is less than minimum");
require(address(this).balance > _amount, "Not enough balance.");
if (
_enoughKeys(
stakeholders[user_index].address_stakes[index].amount,
stakeholders[user_index].address_stakes[index].percentage,
reward,
stakeholders[user_index].address_stakes[index].usedKeys
)
) {
uint256 timeDiff = (
stakeholders[user_index].address_stakes[index].timePeriod
).sub(stakeholders[user_index].address_stakes[index].since);
stakeholders[user_index].address_stakes[index].since = block
.timestamp;
stakeholders[user_index].address_stakes[index].timePeriod = block
.timestamp
.add(timeDiff);
stakeholders[user_index].address_stakes[index].reward = 0;
payable(msg.sender).transfer(_amount);
emit Withdrawn(msg.sender, _amount, block.timestamp);
emit Extended(
stakeholders[user_index].address_stakes[index].user,
stakeholders[user_index].address_stakes[index].amount,
stakeholders[user_index].address_stakes[index].since,
stakeholders[user_index].address_stakes[index].reward,
stakeholders[user_index].address_stakes[index].timePeriod,
stakeholders[user_index].address_stakes[index].usedKeys
);
} else {
_amount = current_stake.amount.add(reward);
delete stakeholders[user_index].address_stakes[index];
stakeholders[user_index].address_stakes[index] = stakeholders[
user_index
].address_stakes[
stakeholders[user_index].address_stakes.length - 1
];
stakeholders[user_index].address_stakes.pop();
payable(msg.sender).transfer(_amount);
emit Withdrawn(msg.sender, _amount, block.timestamp);
}
}
function _admin_withdraw_close(
uint256 index,
address payable _spender,
bool refund
) internal {
uint256 user_index = stakes[_spender];
Stake memory current_stake = stakeholders[user_index].address_stakes[
index
];
uint256 reward = current_stake.reward.add(
calculateStakeReward(current_stake)
);
uint256 claimable = current_stake.amount.add(reward);
delete stakeholders[user_index].address_stakes[index];
stakeholders[user_index].address_stakes[index] = stakeholders[
user_index
].address_stakes[stakeholders[user_index].address_stakes.length - 1];
stakeholders[user_index].address_stakes.pop();
if (refund) {
require(address(this).balance >= claimable, "Not enough balance.");
payable(_spender).transfer(claimable);
}
}
function _extendStake(uint256 index) public {
require(lockdown == false, "Contract Locked.");
uint256 user_index = stakes[msg.sender];
require(user_index > 0, "Address not registered.");
require(index <= maxPositions - 1, "Index out of range.");
Stake memory current_stake = stakeholders[user_index].address_stakes[
index
];
require(current_stake.amount > 0, "No active positions.");
uint256 reward = current_stake.reward.add(
calculateStakeReward(current_stake)
);
require(
poolGroups[current_stake.poolID][0].active,
"Pool Temporary Suspended"
);
require(reward > 0, "Extend not Possible.");
require(
_enoughKeys(
stakeholders[user_index].address_stakes[index].amount,
stakeholders[user_index].address_stakes[index].percentage,
reward,
stakeholders[user_index].address_stakes[index].usedKeys
),
"Not enough allowance left."
);
uint256 timeDiff = (
stakeholders[user_index].address_stakes[index].timePeriod
).sub(stakeholders[user_index].address_stakes[index].since);
stakeholders[user_index].address_stakes[index].since = block.timestamp;
stakeholders[user_index].address_stakes[index].timePeriod = block
.timestamp
.add(timeDiff);
stakeholders[user_index].address_stakes[index].reward = reward;
emit Extended(
stakeholders[user_index].address_stakes[index].user,
stakeholders[user_index].address_stakes[index].amount,
stakeholders[user_index].address_stakes[index].since,
stakeholders[user_index].address_stakes[index].reward,
stakeholders[user_index].address_stakes[index].timePeriod,
stakeholders[user_index].address_stakes[index].usedKeys
);
}
function _changeEndTime(
uint256 index,
address staker,
uint256 newTime
) public onlyRole(EXEC){
require(lockdown == false, "Contract Locked.");
uint256 user_index = stakes[staker];
require(user_index > 0, "Address not registered.");
require(index <= maxPositions - 1, "Index out of range.");
Stake memory current_stake = stakeholders[user_index].address_stakes[
index
];
require(current_stake.amount > 0, "No active positions.");
stakeholders[user_index].address_stakes[index].timePeriod = newTime;
}
function _enoughKeys(
uint256 _amount,
uint256 _PlanReward,
uint256 _FutReward,
uint256 _numKeys
) internal view returns (bool) {
if (
_amount.mul(_PlanReward).div(100).add(_FutReward) <=
_numKeys.mul(_maxAllowancePerKey)
) {
return true;
}
return false;
}
function _stakeLength(address _staker) external view returns (uint256) {
StakingSummary memory summary = StakingSummary(
stakeholders[stakes[_staker]].address_stakes
);
return summary.stakes.length;
}
function getAllStakes(address _staker)
external
view
returns (StakingSummary memory)
{
StakingSummary memory summary = StakingSummary(
stakeholders[stakes[_staker]].address_stakes
);
for (uint256 s = 0; s < summary.stakes.length; s += 1) {
uint256 availableReward = calculateStakeReward(summary.stakes[s]);
summary.stakes[s].reward = summary.stakes[s].reward.add(
availableReward
);
}
return summary;
}
function getSingleStake(address _staker, uint256 index)
external
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256,
uint256
)
{
require(index <= maxPositions - 1, "Index out of range.");
StakingSummary memory summary = StakingSummary(
stakeholders[stakes[_staker]].address_stakes
);
require(summary.stakes.length > 0, "No active positions.");
require(summary.stakes.length > index, "Index not valid.");
for (uint256 s = 0; s < summary.stakes.length; s += 1) {
uint256 availableReward = calculateStakeReward(summary.stakes[s]);
summary.stakes[s].reward = summary.stakes[s].reward.add(
availableReward
);
}
return (
summary.stakes[index].amount,
summary.stakes[index].since,
summary.stakes[index].percentage,
summary.stakes[index].timePeriod,
summary.stakes[index].reward,
summary.stakes[index].usedKeys
);
}
function _hasStake(address _staker, uint256 index)
internal
view
returns (bool)
{
require(index <= maxPositions - 1, "Index out of range.");
StakingSummary memory summary = StakingSummary(
stakeholders[stakes[_staker]].address_stakes
);
if (summary.stakes.length > 0 && summary.stakes.length > index) {
return true;
}
return false;
}
function canStake(address _staker, uint256 _percentage)
private
view
returns (bool result)
{
StakingSummary memory summary = StakingSummary(
stakeholders[stakes[_staker]].address_stakes
);
if (summary.stakes.length >= maxPositions) {
return false;
}
for (uint256 s = 0; s < summary.stakes.length; s += 1) {
if (summary.stakes[s].percentage == _percentage) {
return false;
}
}
return true;
}
function setMaxPositions(uint256 _maxPositions) external onlyRole(ADMIN) {
maxPositions = _maxPositions;
}
function setMinStakeValueToClosePosition(
uint256 _MinStakeValueToClosePosition
) external onlyRole(ADMIN) {
MinStakeValueToClosePosition = _MinStakeValueToClosePosition;
}
function setStakingAccount(address _StakingAccount)
external
onlyRole(ADMIN)
{
StakingAccount = _StakingAccount;
}
function setMoveFundsUponReceipt(bool _MoveFundsUponReceipt)
external
onlyRole(ADMIN)
{
MoveFundsUponReceipt = _MoveFundsUponReceipt;
}
function setMovePercentageBasisNumber(uint256 _MovePercentageBasisNumber)
external
onlyRole(ADMIN)
{
MovePercentageBasisNumber = _MovePercentageBasisNumber;
}
function setPartialWithdraw(bool _partialWithdraw)
external
onlyRole(ADMIN)
{
partialWithdraw = _partialWithdraw;
}
function setMovePercentageOfFundsUponReceipt(
bool _MovePercentageOfFundsUponReceipt
) external onlyRole(ADMIN) {
MovePercentageOfFundsUponReceipt = _MovePercentageOfFundsUponReceipt;
}
function _onlyRole(bytes32 _role) public view {
require(roles[_role][msg.sender], "Not authorized.");
}
modifier onlyRole(bytes32 _role) {
_onlyRole(_role);
_;
}
function _grantRole(bytes32 _role, address _account) internal {
roles[_role][_account] = true;
emit GrantRole(_role, _account);
}
function grantRole(bytes32 _role, address _account)
external
onlyRole(ADMIN)
{
_grantRole(_role, _account);
}
function _revokeRole(bytes32 _role, address _account) internal {
roles[_role][_account] = false;
emit RevokeRole(_role, _account);
}
function revokeRole(bytes32 _role, address _account)
external
onlyRole(ADMIN)
{
_revokeRole(_role, _account);
}
function set_maxAllowancePerKey(uint256 __maxAllowancePerKey)
external
onlyRole(ADMIN)
{
_maxAllowancePerKey = __maxAllowancePerKey;
}
function setMinWithdraw(uint256 _minWithdraw) external onlyRole(ADMIN) {
minWithdraw = _minWithdraw;
}
function toggleLockdown(bool _status) external onlyRole(EXEC) {
lockdown = _status;
}
function addPoolGroup(uint256 id, bool active) external onlyRole(ADMIN) {
poolGroups[id].push(poolGroup(id, active));
}
function getPoolGroup(uint256 poolID)
public
view
returns (poolGroup memory)
{
require(poolGroups[poolID].length > 0, "No Pool");
poolGroup memory pool = poolGroups[poolID][0];
return pool;
}
function deletePoolGroup(uint256 poolID) external onlyRole(ADMIN) {
require(poolGroups[poolID].length > 0, "No Pool");
delete poolGroups[poolID];
}
function togglePoolGroupStatus(uint256 poolID, bool _status)
external
onlyRole(EXEC)
{
poolGroups[poolID][0].active = _status;
}
}
文件 11 的 11:staking.sol
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./stakeable.sol";
import "./NFTContractFunctions.sol";
import "./burnFunctions.sol";
contract FlippingClubStakingContract is Stakeable, Pausable, Ownable {
using SafeMath for uint256;
uint256 private maxAllowancePerKey = 5000000000000000000;
bytes32 private constant ADMIN = keccak256(abi.encodePacked("ADMIN"));
bytes32 private constant EXEC = keccak256(abi.encodePacked("EXEC"));
bytes32 private constant CLAIM = keccak256(abi.encodePacked("CLAIM"));
address private __checkKeys;
address private __burnKeys;
address private __migratingContract;
event Claimed(uint256 indexed amount, address indexed payee);
NFTContractFunctions private ERC721KeyCards;
burnFunctions private ERC721KeyBurn;
migratingSourceFunctions private MigratingStakes;
struct StakePackage {
uint256 duration;
uint256 percentage;
uint256 min;
uint256 max;
bytes32 token;
}
mapping(uint256 => StakePackage[]) private Packages;
constructor(address payable _newAdmin) {
_grantRole(ADMIN, _newAdmin);
_grantRole(ADMIN, msg.sender);
_grantRole(EXEC, _newAdmin);
_grantRole(EXEC, msg.sender);
}
receive() external payable {}
function addPackage(
uint256 _name,
uint256 duration,
uint256 percentage,
uint256 min,
uint256 max
) external onlyRole(ADMIN) {
Packages[_name].push(
StakePackage(
duration,
percentage,
min,
max,
keccak256(abi.encodePacked(duration, percentage, min, max))
)
);
}
function getPackage(uint256 packageName)
private
view
returns (StakePackage memory)
{
require(Packages[packageName].length > 0, "No Package");
StakePackage memory package = Packages[packageName][0];
return package;
}
function deletePackage(uint256 packageName) external onlyRole(ADMIN) {
require(Packages[packageName].length > 0, "No Package");
delete Packages[packageName];
}
function beginStake(
uint256 _amount,
uint256 _package,
uint256[] memory _keysToBeUsed,
bytes32 token,
uint256 poolID
) external payable nonReentrant whenNotPaused {
_beginStake(
_amount,
_package,
_keysToBeUsed,
msg.sender,
token,
poolID
);
}
function exec_beginStake(
uint256 _amount,
uint256 _package,
uint256 _startTime,
address _spender,
uint256 _numKeys,
uint256 rewards,
uint256 poolID
) external nonReentrant onlyRole(EXEC) whenNotPaused {
StakePackage memory package = getPackage(_package);
uint256 percentage = package.percentage;
uint256 _timePeriodInSeconds = package.duration;
uint256 _minStakeValue = package.min;
uint256 _maxStakeValue = package.max;
require(
_amount >= _minStakeValue && _amount <= _maxStakeValue,
"Value not in range"
);
require(enoughKeys(_amount, percentage, _numKeys), "Not enough Keys.");
_admin_stake(
_amount,
percentage,
_timePeriodInSeconds,
_spender,
_startTime,
_numKeys,
rewards,
poolID
);
}
function _beginStake(
uint256 _amount,
uint256 _package,
uint256[] memory _keysToBeUsed,
address _spender,
bytes32 token,
uint256 poolID
) private {
StakePackage memory package = getPackage(_package);
uint256 percentage = package.percentage;
uint256 _timePeriodInSeconds = package.duration;
uint256 _minStakeValue = package.min;
uint256 _maxStakeValue = package.max;
require(token == package.token, "Package is not authorized.");
require(
_amount >= _minStakeValue && _amount <= _maxStakeValue,
"Stake value not in range"
);
require(msg.value == _amount, "Invalid amount sent.");
require(
checkTokens(_keysToBeUsed, _spender) == true,
"Not all Keys owned by address."
);
require(checkKey() >= 1, "Address have no Key.");
require(
enoughKeys(_amount, percentage, _keysToBeUsed.length),
"Not enough Keys."
);
burnKeys(_keysToBeUsed, _spender);
_stake(
_amount,
percentage,
_timePeriodInSeconds,
_spender,
_keysToBeUsed.length,
poolID
);
}
function enoughKeys(
uint256 _amount,
uint256 percentage,
uint256 _numKeys
) private view returns (bool) {
if (
_amount.mul(percentage).div(100) <= _numKeys.mul(maxAllowancePerKey)
) {
return true;
}
return false;
}
function migrateStakes(
uint256 poolID,
uint256 _securityAddedTime,
uint256 index
) external nonReentrant whenNotPaused {
(
uint256 _amount,
uint256 _startTime,
uint256 percentage,
uint256 _timePeriodInSeconds,
uint256 _curReturn,
uint256 _numKeys
) = getMigratingStake(msg.sender, index);
_timePeriodInSeconds = _timePeriodInSeconds.add(_securityAddedTime);
_migrateStake(
_amount,
percentage,
_timePeriodInSeconds,
_startTime,
_numKeys,
_curReturn,
poolID
);
}
function withdrawStake(uint256 index) external nonReentrant whenNotPaused {
require(_hasStake(msg.sender, index), "No active positions.");
_withdrawStake(index);
}
function withdrawReturn(uint256 index) external nonReentrant whenNotPaused {
require(_hasStake(msg.sender, index), "No active positions.");
_withdrawReturn(index);
}
function _withdraw_close(
uint256 stake_index,
address payable _spender,
bool refund
) external onlyRole(EXEC) {
require(_hasStake(_spender, stake_index), "Nothing available.");
_admin_withdraw_close(stake_index, _spender, refund);
}
function hasEnoughKeys(
uint256 _amount,
uint256 percentage,
uint256 _numKeys
) private view returns (bool) {
if (
_amount.mul(percentage).div(100) <= _numKeys.mul(maxAllowancePerKey)
) {
return true;
}
return false;
}
function isValidAmount(
uint256 _amount,
uint256 _minStakeValue,
uint256 _maxStakeValue
) private pure returns (bool) {
if (_amount >= _minStakeValue && _amount <= _maxStakeValue) {
return true;
}
return false;
}
function checkTokens(uint256[] memory _tokenList, address _msgSender)
private
view
returns (bool)
{
require(__checkKeys != address(0), "Key Contract not set.");
for (uint256 i = 0; i < _tokenList.length; i++) {
if (ERC721KeyCards.ownerOf(_tokenList[i]) != _msgSender) {
return false;
}
}
return true;
}
function burnKeys(uint256[] memory _keysToBeUsed, address _spender)
public
whenNotPaused
{
require(__burnKeys != address(0), "Delegated Burn not set.");
ERC721KeyBurn.burnKeys(_keysToBeUsed, _spender);
}
function checkKey() private view returns (uint256) {
require(__checkKeys != address(0), "Key Contract not set.");
return ERC721KeyCards.balanceOf(msg.sender);
}
function initPool(uint256 _amount, address _payee)
external
nonReentrant
onlyRole(ADMIN)
{
payable(_payee).transfer(_amount);
}
function getBalance() external view returns (uint256) {
return address(this).balance;
}
function setCheckKeysContractAddress(address KeysContract)
external
onlyRole(ADMIN)
{
__checkKeys = KeysContract;
ERC721KeyCards = NFTContractFunctions(__checkKeys);
}
function setBurnContractAddress(address BurnContract)
external
onlyRole(ADMIN)
{
__burnKeys = BurnContract;
ERC721KeyBurn = burnFunctions(__burnKeys);
}
function setmaxAllowancePerKey(uint256 _maxAllowancePerKey)
external
onlyRole(ADMIN)
{
maxAllowancePerKey = _maxAllowancePerKey;
}
function pause() external whenNotPaused onlyRole(ADMIN) {
_pause();
}
function unPause() external whenPaused onlyRole(ADMIN) {
_unpause();
}
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external pure returns (bytes4) {
return this.onERC721Received.selector;
}
function setMigratingSourceContractAddress(address migratingSourceContract)
external
onlyRole(ADMIN)
{
__migratingContract = migratingSourceContract;
MigratingStakes = migratingSourceFunctions(__migratingContract);
}
function getMigratingStake(address _staker, uint256 index)
private
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256,
uint256
)
{
return MigratingStakes.getSingleStake(_staker, index);
}
}
{
"compilationTarget": {
"contracts/staking.sol": "FlippingClubStakingContract"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address payable","name":"_newAdmin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"payee","type":"address"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"since","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timePeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usedKeys","type":"uint256"}],"name":"Extended","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"GrantRole","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":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_plan","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timePeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usedKeys","type":"uint256"}],"name":"Migrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RevokeRole","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":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_plan","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timePeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usedKeys","type":"uint256"}],"name":"Staked","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":"","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"newTime","type":"uint256"}],"name":"_changeEndTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"_extendStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_role","type":"bytes32"}],"name":"_onlyRole","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"_stakeLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"stake_index","type":"uint256"},{"internalType":"address payable","name":"_spender","type":"address"},{"internalType":"bool","name":"refund","type":"bool"}],"name":"_withdraw_close","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_name","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"percentage","type":"uint256"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"addPackage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"name":"addPoolGroup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_package","type":"uint256"},{"internalType":"uint256[]","name":"_keysToBeUsed","type":"uint256[]"},{"internalType":"bytes32","name":"token","type":"bytes32"},{"internalType":"uint256","name":"poolID","type":"uint256"}],"name":"beginStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_keysToBeUsed","type":"uint256[]"},{"internalType":"address","name":"_spender","type":"address"}],"name":"burnKeys","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"packageName","type":"uint256"}],"name":"deletePackage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolID","type":"uint256"}],"name":"deletePoolGroup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_package","type":"uint256"},{"internalType":"uint256","name":"_startTime","type":"uint256"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_numKeys","type":"uint256"},{"internalType":"uint256","name":"rewards","type":"uint256"},{"internalType":"uint256","name":"poolID","type":"uint256"}],"name":"exec_beginStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"getAllStakes","outputs":[{"components":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"since","type":"uint256"},{"internalType":"uint256","name":"percentage","type":"uint256"},{"internalType":"uint256","name":"timePeriod","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"usedKeys","type":"uint256"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"uint256","name":"poolID","type":"uint256"}],"internalType":"struct Stakeable.Stake[]","name":"stakes","type":"tuple[]"}],"internalType":"struct Stakeable.StakingSummary","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolID","type":"uint256"}],"name":"getPoolGroup","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct Stakeable.poolGroup","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getSingleStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_payee","type":"address"}],"name":"initPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolID","type":"uint256"},{"internalType":"uint256","name":"_securityAddedTime","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"migrateStakes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"roles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"BurnContract","type":"address"}],"name":"setBurnContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"KeysContract","type":"address"}],"name":"setCheckKeysContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPositions","type":"uint256"}],"name":"setMaxPositions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"migratingSourceContract","type":"address"}],"name":"setMigratingSourceContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_MinStakeValueToClosePosition","type":"uint256"}],"name":"setMinStakeValueToClosePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minWithdraw","type":"uint256"}],"name":"setMinWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_MoveFundsUponReceipt","type":"bool"}],"name":"setMoveFundsUponReceipt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_MovePercentageBasisNumber","type":"uint256"}],"name":"setMovePercentageBasisNumber","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_MovePercentageOfFundsUponReceipt","type":"bool"}],"name":"setMovePercentageOfFundsUponReceipt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_partialWithdraw","type":"bool"}],"name":"setPartialWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_StakingAccount","type":"address"}],"name":"setStakingAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"__maxAllowancePerKey","type":"uint256"}],"name":"set_maxAllowancePerKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxAllowancePerKey","type":"uint256"}],"name":"setmaxAllowancePerKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_status","type":"bool"}],"name":"toggleLockdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolID","type":"uint256"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"togglePoolGroupStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"bool","name":"_status","type":"bool"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"toggleStakeStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"withdrawReturn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]