// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// Website: https://genesisdao.io/
// X: https://x.com/0xGenesisDAO
// Discord: https://discord.gg/genesisdao
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// &
// (&&&&&&&&&&&&&&&&&&&&&&&&&&&*
// &&&&&&&&&&&&&&&&&&&&&@,,@@@@&&&&&&&&&&&
// &&&&&&&&&&&&&&&&&&&&&,,,,,,,,,*@@@&&&&&&&&&&&&&
// &&&&&&&&&&&&&&&&&&&&,,,,,,,,,,,@@@@@@@&&&&&&&&&&&&&&&
// &&&&&&&&&&&&&&&&&@,,,,,,,,,,,@@@@@@@@@@&&&&&&&&&&&&&&&&&&&&
// &&&&&&&&&&&&&&@,,,,,,,,,,,*@@@@@@@@@@&&&&&&&&&@,,,,,#@@@@&&&&&&
// &&&&&&&&&&&&#,,,,,,,,,,,@@@@@@@@@@@&&&&&&&&&*,,,,,,,,,,,,@@@@&&&&&&
// &&&&&&&&&@..,,.,,,,,@@@@@@@@@@&&&&&&&&&&@,,,,,,,,,,,,,,,,,@@@@&&&&&&&
// #&&&&&&&&&&@..,,,,,%@@@@@@@@&&&&&&&&&@,,,,,,,,,,,,@@,,,,,,,,@@@@&&&&&&&&
// &&&&&&&&&&&&@..,,,,,&@@@@&&&&&&&&&..,,,,,,,,,,@@@@@@@@,,,,,,,@@@@&&&&&&&&&&
// &&&&&&&&&&&&&@..,,,,,&@@@@&&&&&&&&@..,,,,,@@@@@@@@@@@@@,,,,,,,@@@@&&&&&&&&&&*
// &&&&&&&&&&&&&@..,,,,,&@@@@&&&&&&&&@@@@@@@@@@@@@@&&&&&&@,,,,,,,@@@@&&&&&&&&&&&
// &&&&&&&&&&&&&&@..,,,,@@@@@@&&&&&&&&&&&&@@@@@@&&&&&&&&&&@@,,,,,,@@@@&&&&&&&&&&&&
// &&&&&&&&&&&&&&@@@@@@@@//*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@@@@@@@@@@@&&&&&&&&&&&&
// &&&&&&&&&&&&&&&@@@/**,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*@@@@@@@@@&&&&&&&&&&&&&
// &&&&&&&&&&&&&&&@.....,.,,@@@@@@@@@@@@@@@@@@@@@@@@@@&&%@@@@@@/*,,@@@@&&&&&&&&&&&&
// &&&&&&&&&&&&&&@....,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@/**,,,,@@@@&&&&&&&&&&&&
// &&&&&&&&&&&&&&@....,,,,@@@@&&&&&&&&&&&&&&&&&&&&&&&&&&&&@,,,,,,,@@@@&&&&&&&&&&&&
// &&&&&&&&&&&&&&@....,,,,@@@@&&&&&&&&&@,,,,,@@@@&&&&&&&&&@,,,,,,,@@@@&&&&&&&&&&&&
// &&&&&&&&&&&&&@....,,,,@@@@&&&&&,,,,,,,,,,,,@@@@&&&&&&&@,,,,,,,@@@@&&&&&&&&&&&
// &&&&&&&&&&&&&@....,,,,@@@@,,,,,,,,,,,,,,@@@@@@@&&&&&&&@,,,,,,,@@@@&&&&&&&&&&*
// &&&&&&&&&&&&@....,,,,,,,,,,,,,,,,,@@@@@@@@@@@&&&&&&&&,,,,,,,,@@@@&&&&&&&&&&
// /&&&&&&&&&&@....,,,,,,,,,,,@@@@@@@@@@@@&&&&&&&&@,,,,,,,,,,,,@@@@&&&&&&&&
// &&&&&&&&&@@....,,,,,@@@@@@@@@@@@&&&&&&&&&,,,,,,,,,,,,,@@@@@@@@&&&&&&&
// &&&&&&&&&@@@@@@@@@@@@@@@@&&&&&&&&&&@,,,,,,,,,,,,@@@@@@@@@@@&&&&&&&&
// &&&&&&&&&&@@@@@@@@&&&&&&&&&&@,,,,,,,,,,,,@@@@@@@@@@@&&&&&&&&&&&
// &&&&&&&&&&&&&&&&&&&&&&..,,,,,,,,,,(@@@@@@@@@@&&&&&&&&&&&&&&
// &&&&&&&&&&&&&&&&&@...,,,,,,@@@@@@@@@@&&&&&&&&&&&&&&&&
// &&&&&&&&&&&&&&@@@@@@@@@@@@@@@@&&&&&&&&&&&&&&&&&
// &&&&&&&&&&&&@@@@@@@@@&&&&&&&&&&&&&&&&&&
// *&&&&&&&&&&&&&&&&&&&&&&&&&&&
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IERC20MintableBurnable is IERC20 {
function mint(address account, uint256 amount) external;
function burn(uint256 amount) external;
}
contract GenesisAutoCompoundStaking is IERC20, Ownable {
uint256 private constant MAX_UINT256 = type(uint256).max;
uint256 private constant SCALE = 1e18;
uint256 private constant ONE_YEAR = 365 days;
uint256 private constant MAX_STAKE_TAX = 500; // 5%
uint256 private constant MAX_UNSTAKE_TAX = 1500; // 15%
uint256 private constant PERCENTAGE_BASE = 10000; // 100%
string public name = "Genesis Staking";
string public symbol = "sGEN";
uint8 public decimals = 18;
address public baseToken;
address public liquidityPool;
address public treasury;
uint256 public fixedAPR = 50 ether;
uint256 public dynamicAPRMinCap = 30 ether;
uint256 public dynamicAPRMaxCap = 70 ether;
uint256 public dynamicAPRConstant = 1 ether;
uint256 public rebaseInterval = 8 hours;
uint256 public stakeTax = 500;
uint256 public unstakeTax = 500;
uint256 public stakeStartTime;
uint256 public lastRebaseTime;
uint256 public totalGons;
uint256 public totalSupplyTokens;
uint256 public gonsPerFragment = 1e9;
uint256 public initialMaxSupply;
uint256 public maxSupply;
uint256 public maxGons;
uint256 public warmupPeriod;
mapping(address => uint256) private _gonBalances;
mapping(address => mapping(address => uint256)) private _allowances;
mapping(address => uint256) public stakeTimes;
event Mint(address indexed wallet, uint256 amount, uint256 gonsAdded, uint256 gonsPerFragment, uint256 newTotalSupply);
event Burn(address indexed wallet, uint256 amount, uint256 gonsRemoved, uint256 gonsPerFragment, uint256 newTotalSupply);
event Stake(address indexed user, uint256 amount, uint256 taxAmount, uint256 mintedTokens);
event Unstake(address indexed user, uint256 amount, uint256 taxAmount, uint256 returnedTokens);
event Rebase(
uint256 fixedAPR,
uint256 dynamicAPR,
uint256 rebaseAPR,
uint256 lastRebaseTime,
uint256 rebaseCount,
uint256 maxSupply,
uint256 supplyDelta,
uint256 gonsPerFragment,
uint256 currentSupply
);
event BaseTokenSet(address indexed baseToken);
event LiquidityPoolSet(address indexed liquidityPool);
event APRParamsSet(uint256 fixedAPR, uint256 dynamicAPRMinCap, uint256 dynamicAPRMaxCap, uint256 dynamicAPRConstant);
event RebaseIntervalSet(uint256 rebaseInterval);
event StakeTaxSet(uint256 stakeTax);
event UnstakeTaxSet(uint256 unstakeTax);
event StakeStartTimeSet(uint256 stakeStartTime);
event TreasurySet(address indexed treasury);
constructor(
address _baseToken,
address _liquidityPool,
address _treasury,
uint256 _stakeStartTime
) Ownable(msg.sender) {
baseToken = _baseToken;
liquidityPool = _liquidityPool;
treasury = _treasury;
stakeStartTime = _stakeStartTime;
maxSupply = IERC20MintableBurnable(baseToken).totalSupply() + 1 ether;
initialMaxSupply = maxSupply;
maxGons = MAX_UINT256 - (MAX_UINT256 % maxSupply);
gonsPerFragment = maxGons / maxSupply;
_mint(address(this), 1 ether);
warmupPeriod = 60;
emit BaseTokenSet(_baseToken);
emit LiquidityPoolSet(_liquidityPool);
emit TreasurySet(_treasury);
emit StakeStartTimeSet(_stakeStartTime);
}
function setBaseToken(address _baseToken) external onlyOwner {
baseToken = _baseToken;
emit BaseTokenSet(_baseToken);
}
function setLiquidityPool(address _liquidityPool) external onlyOwner {
liquidityPool = _liquidityPool;
emit LiquidityPoolSet(_liquidityPool);
}
function setAprParameters(
uint256 _fixedAPR,
uint256 _dynamicAPRMinCap,
uint256 _dynamicAPRMaxCap,
uint256 _dynamicAPRConstant
) external onlyOwner {
require(_dynamicAPRMinCap <= _dynamicAPRMaxCap, "Min cap higher than max cap");
fixedAPR = _fixedAPR;
dynamicAPRMinCap = _dynamicAPRMinCap;
dynamicAPRMaxCap = _dynamicAPRMaxCap;
dynamicAPRConstant = _dynamicAPRConstant;
emit APRParamsSet(_fixedAPR, _dynamicAPRMinCap, _dynamicAPRMaxCap, _dynamicAPRConstant);
}
function setRebaseInterval(uint256 _rebaseInterval) external onlyOwner {
rebaseInterval = _rebaseInterval;
emit RebaseIntervalSet(_rebaseInterval);
}
function setStakeTax(uint256 _stakeTax) external onlyOwner {
require(_stakeTax <= MAX_STAKE_TAX, "Stake tax too high");
stakeTax = _stakeTax;
emit StakeTaxSet(_stakeTax);
}
function setUnstakeTax(uint256 _unstakeTax) external onlyOwner {
require(_unstakeTax <= MAX_UNSTAKE_TAX, "Unstake tax too high");
unstakeTax = _unstakeTax;
emit UnstakeTaxSet(_unstakeTax);
}
function setTreasury(address _treasury) external onlyOwner {
treasury = _treasury;
emit TreasurySet(_treasury);
}
function setStakeStartTime(uint256 _stakeStartTime) external onlyOwner {
require(block.timestamp < stakeStartTime, "Staking already started");
stakeStartTime = _stakeStartTime;
emit StakeStartTimeSet(_stakeStartTime);
}
function setWarmupPeriod(uint256 _warmupPeriod) external onlyOwner {
require(_warmupPeriod > 0, "Warmup period too low");
require(_warmupPeriod <= 1 days, "Warmup period too high");
warmupPeriod = _warmupPeriod;
}
function _mint(address account, uint256 amount) internal {
require(account != address(0), "ERC20: mint to the zero address");
uint256 gonsToAdd = amount * gonsPerFragment;
totalGons += gonsToAdd;
totalSupplyTokens += amount;
_gonBalances[account] += gonsToAdd;
emit Mint(account, amount, gonsToAdd, gonsPerFragment, totalSupplyTokens);
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal {
require(account != address(0), "ERC20: burn from the zero address");
uint256 gonsToRemove = amount * gonsPerFragment;
totalGons -= gonsToRemove;
totalSupplyTokens -= amount;
_gonBalances[account] -= gonsToRemove;
emit Burn(account, amount, gonsToRemove, gonsPerFragment, totalSupplyTokens);
emit Transfer(account, address(0), amount);
}
function rebase() public {
if (block.timestamp < stakeStartTime) return;
uint256 timeToUse = lastRebaseTime > 0 ? lastRebaseTime : stakeStartTime;
uint256 rebaseCount = (block.timestamp - timeToUse) / rebaseInterval;
if (rebaseCount == 0) return;
uint256 fixedApr = getFixedAPR();
uint256 dynamicApr = getDynamicAPR();
uint256 finalApr = fixedApr + dynamicApr;
uint256 intervalsPerYear = ONE_YEAR / rebaseInterval;
uint256 intervalAPR = finalApr / intervalsPerYear;
uint256 supplyDelta = (maxSupply * intervalAPR) / SCALE / 100;
if (supplyDelta == 0) {
lastRebaseTime = timeToUse + rebaseInterval * rebaseCount;
return;
}
if (supplyDelta > maxSupply) {
supplyDelta = maxSupply;
}
maxSupply += supplyDelta;
gonsPerFragment = maxGons / maxSupply;
totalSupplyTokens = totalGons / gonsPerFragment;
lastRebaseTime = timeToUse + rebaseInterval * rebaseCount;
emit Rebase(
fixedApr,
dynamicApr,
intervalAPR,
timeToUse,
rebaseCount,
maxSupply,
supplyDelta,
gonsPerFragment,
totalSupplyTokens
);
}
function stake(uint256 amount) external {
rebase();
require(IERC20(baseToken).transferFrom(msg.sender, address(this), amount), "Transfer failed");
uint256 taxAmount = (amount * stakeTax) / PERCENTAGE_BASE;
uint256 netAmount = amount - taxAmount;
IERC20MintableBurnable(baseToken).burn(netAmount);
if (taxAmount > 0) {
IERC20(baseToken).transfer(treasury, taxAmount);
}
_mint(msg.sender, netAmount);
if (warmupPeriod > 0) {
stakeTimes[msg.sender] = block.timestamp;
}
emit Stake(msg.sender, amount, taxAmount, netAmount);
}
function unstake(uint256 amount) external {
require(block.timestamp - stakeTimes[msg.sender] >= warmupPeriod, "Warmup period not over");
rebase();
uint256 gonsToRemove = amount * gonsPerFragment;
require(_gonBalances[msg.sender] >= gonsToRemove, "Insufficient balance");
_burn(msg.sender, amount);
IERC20MintableBurnable(baseToken).mint(address(this), amount);
uint256 taxAmount = (amount * unstakeTax) / PERCENTAGE_BASE;
uint256 netAmount = amount - taxAmount;
IERC20(baseToken).transfer(msg.sender, netAmount);
if (taxAmount > 0) {
IERC20(baseToken).transfer(treasury, taxAmount);
}
emit Unstake(msg.sender, amount, taxAmount, netAmount);
}
function _transfer(address sender, address recipient, uint256 amount) internal {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
require(_gonBalances[sender] >= amount * gonsPerFragment, "ERC20: transfer amount exceeds balance");
require(sender == address(0) || recipient != address(this), "ERC20: transfer to staking contract");
rebase();
uint256 taxAmount = ((stakeTax + unstakeTax) * amount) / PERCENTAGE_BASE;
uint256 netAmount = amount - taxAmount;
uint256 gonsToTransfer = netAmount * gonsPerFragment;
uint256 gonsTaxAmount = taxAmount * gonsPerFragment;
_gonBalances[sender] -= (gonsToTransfer + gonsTaxAmount);
_gonBalances[recipient] += gonsToTransfer;
if (gonsTaxAmount > 0) {
_gonBalances[treasury] += gonsTaxAmount;
}
emit Transfer(sender, recipient, netAmount);
}
function getFixedAPR() public view returns (uint256) {
return fixedAPR;
}
function getDynamicAPR() public view returns (uint256) {
uint256 totalStaked = totalSupplyTokens;
uint256 lpBalance = IERC20(baseToken).balanceOf(liquidityPool);
if (lpBalance <= 0) {
revert("LP balance zero");
}
if (dynamicAPRConstant <= 0) {
revert("Dynamic APR constant zero");
}
uint256 ratio = (totalStaked * SCALE) / lpBalance;
if (ratio > 10 * SCALE) {
ratio = 10 * SCALE;
}
uint256 scaledRatio = (ratio * dynamicAPRConstant) / SCALE;
uint256 logInput = SCALE + scaledRatio;
uint256 logValue = log10(logInput);
uint256 apyValue = dynamicAPRMaxCap -
((dynamicAPRMaxCap - dynamicAPRMinCap) * logValue) /
log10(dynamicAPRConstant * 10);
if (apyValue < dynamicAPRMinCap) {
apyValue = dynamicAPRMinCap;
}
return apyValue;
}
function getFinalAPR() public view returns (uint256) {
return getFixedAPR() + getDynamicAPR();
}
function log10(uint256 x) internal view returns (uint256) {
if (x <= 0) {
revert("Log zero");
}
uint256 result = 0;
while (x >= 10 * SCALE) {
x /= 10;
result += SCALE;
}
for (uint8 i = 0; i < 18; ++i) {
x = (x * x) / SCALE;
if (x >= 10 * SCALE) {
x /= 10;
result += SCALE / (2 ** (i + 1));
}
}
return result;
}
function balanceOf(address account) public view override returns (uint256) {
return _gonBalances[account] / gonsPerFragment;
}
function totalSupply() public view override returns (uint256) {
return totalSupplyTokens;
}
function transfer(address recipient, uint256 amount) public override returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
function allowance(address owner, address spender) public view override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
uint256 currentAllowance = _allowances[sender][msg.sender];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
_transfer(sender, recipient, amount);
_approve(sender, msg.sender, currentAllowance - amount);
return true;
}
function _approve(address owner, address spender, uint256 amount) internal {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function timeTillNextRebase() public view returns (uint256) {
if (block.timestamp < stakeStartTime) {
return stakeStartTime - block.timestamp;
}
return rebaseInterval - ((block.timestamp - stakeStartTime) % rebaseInterval);
}
function totalTokensAtNextRebase() public view returns (uint256) {
uint256 fixedApr = getFixedAPR();
uint256 dynamicApr = getDynamicAPR();
uint256 finalApr = fixedApr + dynamicApr;
uint256 intervalsPerYear = ONE_YEAR / rebaseInterval;
uint256 intervalAPR = finalApr / intervalsPerYear;
uint256 supplyDelta = (totalSupplyTokens * intervalAPR) / SCALE / 100;
return supplyDelta;
}
function tokensForAddressAtNextRebase(address account) public view returns (uint256) {
uint256 supplyDelta = totalTokensAtNextRebase();
uint256 userBalance = balanceOf(account);
uint256 userShare = (userBalance * SCALE) / totalSupplyTokens;
return (supplyDelta * userShare) / SCALE / 100;
}
function tokensDeductedForUnstaking(uint256 amount) public view returns (uint256) {
uint256 taxAmount = (amount * unstakeTax) / PERCENTAGE_BASE;
return taxAmount;
}
function tokensDeductedForStaking(uint256 amount) public view returns (uint256) {
uint256 taxAmount = (amount * stakeTax) / PERCENTAGE_BASE;
return taxAmount;
}
function index() public view returns (uint256) {
return balanceOf(address(this));
}
function totalTokensRewarded() public view returns (uint256) {
return maxSupply - initialMaxSupply;
}
function emergencyWithdraw(address token, address to, uint256 amount) external onlyOwner {
require(token != address(this), "Cannot withdraw staking token");
IERC20(token).transfer(to, amount);
}
function emergencyEthWithdraw(address to, uint256 amount) external onlyOwner {
payable(to).transfer(amount);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(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 virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
{
"compilationTarget": {
"GenesisStaking.sol": "GenesisAutoCompoundStaking"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_baseToken","type":"address"},{"internalType":"address","name":"_liquidityPool","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"uint256","name":"_stakeStartTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fixedAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dynamicAPRMinCap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dynamicAPRMaxCap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dynamicAPRConstant","type":"uint256"}],"name":"APRParamsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"baseToken","type":"address"}],"name":"BaseTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gonsRemoved","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gonsPerFragment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalSupply","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidityPool","type":"address"}],"name":"LiquidityPoolSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gonsAdded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gonsPerFragment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalSupply","type":"uint256"}],"name":"Mint","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":"uint256","name":"fixedAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dynamicAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rebaseAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastRebaseTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rebaseCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supplyDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gonsPerFragment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentSupply","type":"uint256"}],"name":"Rebase","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rebaseInterval","type":"uint256"}],"name":"RebaseIntervalSet","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":"taxAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintedTokens","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"stakeStartTime","type":"uint256"}],"name":"StakeStartTimeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"stakeTax","type":"uint256"}],"name":"StakeTaxSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"treasury","type":"address"}],"name":"TreasurySet","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":"taxAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"returnedTokens","type":"uint256"}],"name":"Unstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"unstakeTax","type":"uint256"}],"name":"UnstakeTaxSet","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicAPRConstant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicAPRMaxCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicAPRMinCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emergencyEthWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fixedAPR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDynamicAPR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFinalAPR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFixedAPR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gonsPerFragment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"index","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialMaxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRebaseTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGons","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebaseInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fixedAPR","type":"uint256"},{"internalType":"uint256","name":"_dynamicAPRMinCap","type":"uint256"},{"internalType":"uint256","name":"_dynamicAPRMaxCap","type":"uint256"},{"internalType":"uint256","name":"_dynamicAPRConstant","type":"uint256"}],"name":"setAprParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_baseToken","type":"address"}],"name":"setBaseToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidityPool","type":"address"}],"name":"setLiquidityPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rebaseInterval","type":"uint256"}],"name":"setRebaseInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakeStartTime","type":"uint256"}],"name":"setStakeStartTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakeTax","type":"uint256"}],"name":"setStakeTax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unstakeTax","type":"uint256"}],"name":"setUnstakeTax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_warmupPeriod","type":"uint256"}],"name":"setWarmupPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakeTax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakeTimes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeTillNextRebase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"tokensDeductedForStaking","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"tokensDeductedForUnstaking","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"tokensForAddressAtNextRebase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalGons","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupplyTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensAtNextRebase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensRewarded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakeTax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"warmupPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]