// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract Context {
// Empty internal constructor, to prevent people from mistakenly deploying
// an instance of this contract, which should be used via inheritance.
constructor() {}
function _msgSender() internal view returns (address) {
return msg.sender;
}
function _msgData() internal view returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(_owner == _msgSender(), 'Ownable: caller is not the owner');
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), 'Ownable: new owner is the zero address');
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
contract JUMPBonusPool is Ownable {
uint256 public bonusCircleTime;
uint256 public delayTime = 30;
uint256 public mintLimit;
mapping(address=>bool) public bonusClaimed;
uint256 public tickId;
uint256 public startTime;
uint256 private endBonusTimestamp;
uint256 public totalBonus;
bool public mintLimitFlag = false;
mapping(address => bool) public callerMap;
address[5] public bonusUsers;
uint256 public index;
address public marketMakerAddr = 0xFE49c3D7b7EF988233FAddeD69f7B624A392E017;
event AddTick(uint256 tickId,address user,uint256 amountETH);
event Claim(address sender,uint256 totalBonus);
event SetCaller(address sender,address addr,bool active);
modifier onlyCaller() {
require(isCaller(msg.sender), "Not caller");
_;
}
constructor(uint256 _startTime) {
startTime = _startTime;
bonusCircleTime = 96 hours;
mintLimit = 101287e17;
endBonusTimestamp = startTime + bonusCircleTime;
}
function addTick(address user,uint256 mintTotal) public payable onlyCaller {
require(block.timestamp >= startTime,'Not start');
uint256 amountETH = msg.value;
require(mintTotal <= mintLimit,'Exceed bonusLimit');
tickId++;
totalBonus += amountETH;
//add delay time
endBonusTimestamp = endBonusTimestamp + delayTime;
if (endBonusTimestamp - block.timestamp > bonusCircleTime) {
endBonusTimestamp = block.timestamp + bonusCircleTime;
}
if(index == 5){
index =0;
}
bonusUsers[index] = user;
index++;
if(mintTotal == mintLimit ){
startCycleETH();//start Refund ETH
endBonusTimestamp = block.timestamp;
mintLimitFlag = true;
}
emit AddTick(tickId,user,amountETH);
}
function startCycleETH() internal{
uint256 ethBalance = address(this).balance;
if(ethBalance > 0){
(bool success, ) = marketMakerAddr.call{value: ethBalance}("");
require(success, "Fail to claim bonus");
}
}
function claimETH() public {
require(block.timestamp > endBonusTimestamp,'Pool Not end');
require(!bonusClaimed[msg.sender] && !mintLimitFlag,'Bonus claimed');
bool isWinnerFlag = isWinner(msg.sender);
require(isWinnerFlag, 'RebirthETHBonusPool: not winner');
uint256 bonus = getWinnerBonus(msg.sender);
bonusClaimed[msg.sender] = true;
(bool success, ) = msg.sender.call{value: bonus}("");
require(success, "Fail to claim bonus");
emit Claim(msg.sender,bonus);
}
function isWinner(address user) public view returns (bool) {
if (block.timestamp <= endBonusTimestamp || mintLimitFlag) {
return false;
}
address[] memory winners = getWinners();
uint winnerNum = winners.length;
for(uint256 i = 0;i < winnerNum;i++ ){
if(winners[i] == user){
return true;
}
}
return false;
}
function getWinnerBonus(address user) public view returns(uint256 bonus){
if (block.timestamp <= endBonusTimestamp) {
return 0;
}
address[] memory winners = getWinners();
uint256 winnerNum = winners.length;
uint256 averageBonus = totalBonus / winnerNum;
for(uint256 i = 0;i < winnerNum;i++ ){
if(winners[i] == user){
bonus += averageBonus;
}
}
}
function getWinners() public view returns (address[] memory winners) {
if (block.timestamp <= endBonusTimestamp) {
return winners;
}
winners = new address[](5);
uint256 cnt = 0;
for(uint256 i = 0;i < 5;i++ ){
if(bonusUsers[i] != address(0)){
winners[cnt] = bonusUsers[i];
cnt++;
}
}
// Downsize the array to fit.
assembly {
mstore(winners, cnt)
}
return winners;
}
function getEndBonusTime() public view returns(uint256){
return endBonusTimestamp;
}
function getCurrBlockAndTime() public view returns(uint256 blockNum,uint256 blockTime){
blockNum = block.number;
blockTime = block.timestamp;
}
function setCaller(address addr, bool active) public onlyOwner {
callerMap[addr] = active;
emit SetCaller(msg.sender,addr,active);
}
function isCaller(address addr) public view returns (bool) {
return callerMap[addr];
}
receive() external payable {}
}
{
"compilationTarget": {
"contracts/JUMP/JUMPBonusPool.sol": "JUMPBonusPool"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"uint256","name":"_startTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tickId","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountETH","type":"uint256"}],"name":"AddTick","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalBonus","type":"uint256"}],"name":"Claim","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":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"SetCaller","type":"event"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"mintTotal","type":"uint256"}],"name":"addTick","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"bonusCircleTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bonusClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"bonusUsers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"callerMap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delayTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrBlockAndTime","outputs":[{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"blockTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEndBonusTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getWinnerBonus","outputs":[{"internalType":"uint256","name":"bonus","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWinners","outputs":[{"internalType":"address[]","name":"winners","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"index","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isCaller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isWinner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketMakerAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintLimitFlag","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"active","type":"bool"}],"name":"setCaller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tickId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]