编译器
0.8.19+commit.7dd6d404
文件 1 的 5: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 的 5:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
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 _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 3 的 5:IERC20.sol
pragma solidity ^0.8.0;
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 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 4 的 5:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 5 的 5:Stake.sol
pragma solidity ^0.8.17;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
error NotOwner();
error BalanceLessThanAmount();
error StakingPeriodMismatch();
error ZeroAmount();
error ZeroAddress();
error StakingIdMismatch();
error StakeNotMature();
error StakeAlreadyMature();
error AlreadyClaimed();
error LengthMismatch();
error NonTransferable();
error StakeCompleted();
error NoRewardsToClaim();
contract Stake is ERC20 {
event OwnerUpdate(address indexed owner);
event Withdraw(address indexed tokenAddress, uint256 balance);
event AddInterestRate(uint8 period, uint96 rate);
event AddgStfxMultiplier(uint8 period, uint32 multiplier);
event UpdateBurnPercent(uint32 percent);
event UpdateBurnAddress(address indexed burnAddress);
event AddStake(
address indexed staker, uint256 stakeNumber, uint96 amount, uint96 expiryAmount, uint40 expiryTime, uint8 period
);
event Unstake(address indexed staker, uint256[] stakeNumber, uint96 totalTransferAmount, uint96 totalBurnAmount);
event Claim(
address indexed staker, uint256[] stakeNumber, uint96 amount, uint96 expiryAmount, uint96 transferAmount
);
event ClaimRewards(address indexed staker, uint256[] stakeNumber, uint96 totalRewards);
struct StakingInfo {
StakingPeriod period;
uint40 startTime;
uint40 expiryTime;
uint96 amount;
uint96 expiryAmount;
uint96 claimedAmount;
uint96 gStfxAmount;
bool isCompleted;
}
enum StakingPeriod {
MONTH,
QUARTER,
HALF,
YEAR,
TWO_YEAR
}
address public owner;
address public token;
uint32 public burnPercent;
address public burnAddress;
uint96 public totalStaked;
uint96 public burntToDate;
uint96 public rewardsToDate;
mapping(address => StakingInfo[]) public stakingInfo;
mapping(uint8 => uint96) public interestRate;
mapping(uint8 => uint32) public gStfxMultiplier;
constructor(address _token) ERC20("gSTFX", "gSTFX") {
owner = msg.sender;
token = _token;
burnPercent = 20000;
burnAddress = address(0x000000000000000000000000000000000000dEaD);
}
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwner();
_;
}
function getNumberOfStakes(address staker) public view returns (uint256) {
return stakingInfo[staker].length;
}
function getAllStakes(address staker) public view returns (StakingInfo[] memory) {
uint256 length = stakingInfo[staker].length;
StakingInfo[] memory allStakes = new StakingInfo[](length);
for (uint256 i = 0; i < length;) {
allStakes[i] = stakingInfo[staker][i];
unchecked {
++i;
}
}
return allStakes;
}
function getStakingInfo(address staker, uint256 n) public view returns (StakingInfo memory) {
return stakingInfo[staker][n];
}
function getIsStakeMature(address staker, uint256 n) public view returns (bool isMature) {
if (block.timestamp >= stakingInfo[staker][n].expiryTime) isMature = true;
}
function getStakeAmount(address staker, uint256[] memory n) public view returns (uint96 amount) {
if (n.length > getNumberOfStakes(staker)) revert LengthMismatch();
for (uint256 i = 0; i < n.length;) {
StakingInfo memory s = stakingInfo[staker][n[i]];
amount += s.amount;
unchecked {
++i;
}
}
}
function getExpiryAmount(address staker, uint256[] memory n) public view returns (uint96 expiryAmount) {
if (n.length > getNumberOfStakes(staker)) revert LengthMismatch();
for (uint256 i = 0; i < n.length;) {
StakingInfo memory s = stakingInfo[staker][n[i]];
expiryAmount += s.expiryAmount;
unchecked {
++i;
}
}
}
function getClaimedAmount(address staker, uint256[] memory n) public view returns (uint96 claimedAmount) {
if (n.length > getNumberOfStakes(staker)) revert LengthMismatch();
for (uint256 i = 0; i < n.length;) {
StakingInfo memory s = stakingInfo[staker][n[i]];
claimedAmount += s.claimedAmount;
unchecked {
++i;
}
}
}
function getAccruedRewards(address staker, uint256[] memory n) public view returns (uint96 claimableAmount) {
if (n.length > getNumberOfStakes(staker)) revert LengthMismatch();
for (uint256 i = 0; i < n.length;) {
StakingInfo memory s = stakingInfo[staker][n[i]];
if (s.isCompleted) {
claimableAmount += 0;
} else {
if (block.timestamp >= s.expiryTime) {
claimableAmount += uint96(s.expiryAmount - s.amount);
} else {
claimableAmount += uint96(
((s.expiryAmount - s.amount) * (block.timestamp - s.startTime)) / (s.expiryTime - s.startTime)
);
}
}
unchecked {
++i;
}
}
}
function getBurnAmount(address staker, uint256[] memory n) public view returns (uint96 burnAmount) {
if (n.length > getNumberOfStakes(staker)) revert LengthMismatch();
for (uint256 i = 0; i < n.length;) {
StakingInfo memory s = stakingInfo[staker][n[i]];
if ((block.timestamp >= s.expiryTime) || s.isCompleted) {
burnAmount += 0;
} else {
burnAmount += uint96(
(uint256(burnPercent) * s.amount * (s.expiryTime - block.timestamp))
/ (uint256(s.expiryTime - s.startTime) * 100000)
);
}
unchecked {
++i;
}
}
}
function getAccruedRewardsPerStake(address staker, uint256 n) public view returns (uint96 claimableAmount) {
StakingInfo memory s = stakingInfo[staker][n];
if (s.isCompleted) {
claimableAmount = 0;
} else {
if (block.timestamp >= s.expiryTime) {
claimableAmount = uint96(s.expiryAmount - s.amount);
} else {
claimableAmount = uint96(
((s.expiryAmount - s.amount) * (block.timestamp - s.startTime)) / (s.expiryTime - s.startTime)
);
}
}
}
function getBurnAmountPerStake(address staker, uint256 n) public view returns (uint96 burnAmount) {
StakingInfo memory s = stakingInfo[staker][n];
if ((block.timestamp >= s.expiryTime) || s.isCompleted) {
burnAmount = 0;
} else {
burnAmount = uint96(
(uint256(burnPercent) * s.amount * (s.expiryTime - block.timestamp))
/ (uint256(s.expiryTime - s.startTime) * 100000)
);
}
}
function getStats() public view returns (uint96, uint96, uint96) {
return (totalStaked, rewardsToDate, burntToDate);
}
function getStatsPerStaker(address staker)
public
view
returns (uint96 amount, uint96 expiryAmount, uint96 claimedAmount, uint96 accruedRewards)
{
uint256 length = getNumberOfStakes(staker);
for (uint256 i = 0; i < length;) {
StakingInfo memory s = stakingInfo[staker][i];
amount += s.amount;
expiryAmount += s.expiryAmount;
claimedAmount += s.claimedAmount;
accruedRewards += getAccruedRewardsPerStake(staker, i);
unchecked {
++i;
}
}
}
function getIdsForClaimRewards(address staker) public view returns (uint256[] memory n) {
uint256 length = getNumberOfStakes(staker);
for (uint256 i = 0; i < length;) {
StakingInfo memory s = stakingInfo[staker][i];
if (!s.isCompleted && (block.timestamp < s.expiryTime)) {
assembly {
let currentLength := mload(n)
mstore(n, add(currentLength, 1))
mstore(add(n, mul(add(currentLength, 1), 32)), i)
}
}
unchecked {
++i;
}
}
}
function setOwner(address newOwner) external onlyOwner {
if (newOwner == address(0)) revert ZeroAddress();
owner = newOwner;
emit OwnerUpdate(newOwner);
}
function addInterestRate(StakingPeriod period, uint96 rate) external onlyOwner {
if (rate < 1) revert ZeroAmount();
interestRate[uint8(period)] = rate;
emit AddInterestRate(uint8(period), rate);
}
function addgStfxMultiplier(StakingPeriod period, uint32 multiplier) external onlyOwner {
if (multiplier < 1) revert ZeroAmount();
gStfxMultiplier[uint8(period)] = multiplier;
emit AddgStfxMultiplier(uint8(period), multiplier);
}
function updateBurnPercent(uint32 percent) external onlyOwner {
if (percent < 1) revert ZeroAmount();
burnPercent = percent;
emit UpdateBurnPercent(percent);
}
function updateBurnAddress(address burn) external onlyOwner {
burnAddress = burn;
emit UpdateBurnAddress(burn);
}
function _setStakingPeriod(StakingPeriod period) internal view returns (uint40 expiryTime) {
if (period == StakingPeriod.MONTH) {
expiryTime = uint40(block.timestamp + 30 days);
} else if (period == StakingPeriod.QUARTER) {
expiryTime = uint40(block.timestamp + 90 days);
} else if (period == StakingPeriod.HALF) {
expiryTime = uint40(block.timestamp + 180 days);
} else if (period == StakingPeriod.YEAR) {
expiryTime = uint40(block.timestamp + 365 days);
} else if (period == StakingPeriod.TWO_YEAR) {
expiryTime = uint40(block.timestamp + 730 days);
} else {
revert StakingPeriodMismatch();
}
}
function _stake(uint96 amount, StakingPeriod period) internal view returns (StakingInfo memory s) {
s.startTime = uint40(block.timestamp);
s.amount = amount;
s.expiryAmount = uint96(((uint256(amount) * uint256(interestRate[uint8(period)])) / 100e18) + uint256(amount));
s.period = period;
s.expiryTime = _setStakingPeriod(period);
s.gStfxAmount = uint96((uint256(gStfxMultiplier[uint8(period)]) * uint256(s.amount)) / 1000);
}
function stake(uint96 amount, StakingPeriod period) external {
if (IERC20(token).balanceOf(msg.sender) < amount) revert BalanceLessThanAmount();
if (interestRate[uint8(period)] == 0) revert StakingPeriodMismatch();
StakingInfo memory s = _stake(amount, period);
stakingInfo[msg.sender].push(s);
totalStaked += amount;
uint256 length = stakingInfo[msg.sender].length;
_mint(msg.sender, s.gStfxAmount);
IERC20(token).transferFrom(msg.sender, address(this), amount);
emit AddStake(msg.sender, length - 1, amount, s.expiryAmount, s.expiryTime, uint8(period));
}
function restake(uint256 n, StakingPeriod period) external {
uint256 length = getNumberOfStakes(msg.sender);
if (n >= length) revert StakingIdMismatch();
StakingInfo memory s = getStakingInfo(msg.sender, n);
if (block.timestamp >= s.expiryTime) revert StakeAlreadyMature();
if (uint8(period) < uint8(s.period)) revert StakingPeriodMismatch();
uint96 stakedRewardTillNow = getAccruedRewardsPerStake(msg.sender, n);
StakingInfo memory sAfterRestake = _stake(s.amount + (stakedRewardTillNow - s.claimedAmount), period);
stakingInfo[msg.sender][n] = sAfterRestake;
totalStaked += stakedRewardTillNow - s.claimedAmount;
_mint(msg.sender, sAfterRestake.gStfxAmount - s.gStfxAmount);
emit AddStake(
msg.sender,
n,
sAfterRestake.amount,
sAfterRestake.expiryAmount,
sAfterRestake.expiryTime,
uint8(sAfterRestake.period)
);
}
function unstake(uint256[] memory n) external {
uint256 length = getNumberOfStakes(msg.sender);
if (n.length > length) revert LengthMismatch();
uint96 totalRewards;
uint96 totalTransferAmount;
uint96 totalBurnAmount;
uint96 gStfxToBurn;
for (uint256 i = 0; i < n.length;) {
if (n[i] >= length) revert StakingIdMismatch();
StakingInfo memory s = getStakingInfo(msg.sender, n[i]);
if (block.timestamp >= s.expiryTime) revert StakeAlreadyMature();
if (s.isCompleted) revert StakeCompleted();
uint96 accruedRewards = getAccruedRewardsPerStake(msg.sender, n[i]);
uint96 burnAmount = getBurnAmountPerStake(msg.sender, n[i]);
totalRewards += accruedRewards - s.claimedAmount;
totalTransferAmount += (s.amount - burnAmount) + (accruedRewards - s.claimedAmount);
totalBurnAmount += burnAmount;
gStfxToBurn += s.gStfxAmount;
stakingInfo[msg.sender][n[i]].claimedAmount = accruedRewards;
stakingInfo[msg.sender][n[i]].isCompleted = true;
unchecked {
++i;
}
}
rewardsToDate += totalRewards;
burntToDate += totalBurnAmount;
_burn(msg.sender, gStfxToBurn);
IERC20(token).transfer(msg.sender, totalTransferAmount);
IERC20(token).transfer(burnAddress, totalBurnAmount);
emit Unstake(msg.sender, n, totalTransferAmount, totalBurnAmount);
}
function claim(uint256[] memory n) external {
uint96 totalStakeAmount;
uint96 totalExpiryAmount;
uint96 transferAmount;
uint96 gStfxToBurn;
uint96 totalRewardsToDate;
uint256 length = getNumberOfStakes(msg.sender);
if (n.length > length) revert LengthMismatch();
for (uint256 i = 0; i < n.length;) {
if (n[i] >= length) revert StakingIdMismatch();
StakingInfo memory s = getStakingInfo(msg.sender, n[i]);
if (block.timestamp < s.expiryTime) revert StakeNotMature();
if (s.isCompleted) revert StakeCompleted();
totalStakeAmount += s.amount;
totalExpiryAmount += s.expiryAmount;
transferAmount += s.expiryAmount - s.claimedAmount;
totalRewardsToDate += s.expiryAmount - s.amount - s.claimedAmount;
gStfxToBurn += s.gStfxAmount;
stakingInfo[msg.sender][n[i]].claimedAmount = s.expiryAmount - s.amount;
stakingInfo[msg.sender][n[i]].isCompleted = true;
unchecked {
++i;
}
}
rewardsToDate += totalRewardsToDate;
_burn(msg.sender, gStfxToBurn);
IERC20(token).transfer(msg.sender, transferAmount);
emit Claim(msg.sender, n, totalStakeAmount, totalExpiryAmount, transferAmount);
}
function claimRewards(uint256[] memory n) external {
uint256 length = getNumberOfStakes(msg.sender);
if (n.length > length) revert LengthMismatch();
uint96 transferAmount;
for (uint256 i = 0; i < n.length;) {
if (n[i] >= length) revert StakingIdMismatch();
StakingInfo memory s = getStakingInfo(msg.sender, n[i]);
uint96 claimableAmount = getAccruedRewardsPerStake(msg.sender, n[i]);
if ((s.claimedAmount < claimableAmount) && !s.isCompleted) {
uint96 claimedAmountTillNow = s.claimedAmount;
transferAmount += claimableAmount - claimedAmountTillNow;
stakingInfo[msg.sender][n[i]].claimedAmount = claimableAmount;
}
unchecked {
++i;
}
}
if (transferAmount == 0) revert NoRewardsToClaim();
rewardsToDate += transferAmount;
IERC20(token).transfer(msg.sender, transferAmount);
emit ClaimRewards(msg.sender, n, transferAmount);
}
function withdraw(address tokenAddress) external onlyOwner {
uint256 balance = IERC20(tokenAddress).balanceOf(address(this));
IERC20(tokenAddress).transfer(owner, balance);
emit Withdraw(tokenAddress, balance);
}
function approve(address, uint256) public virtual override returns (bool) {
revert NonTransferable();
}
function transfer(address, uint256) public virtual override returns (bool) {
revert NonTransferable();
}
function transferFrom(address, address, uint256) public virtual override returns (bool) {
revert NonTransferable();
}
}
{
"compilationTarget": {
"src/Stake.sol": "Stake"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
":@openzeppelin/=lib/openzeppelin-contracts/",
":@synthetix/=src/interfaces/synthetix/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":solmate/=lib/solmate/src/"
]
}
[{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BalanceLessThanAmount","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"NoRewardsToClaim","type":"error"},{"inputs":[],"name":"NonTransferable","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"StakeAlreadyMature","type":"error"},{"inputs":[],"name":"StakeCompleted","type":"error"},{"inputs":[],"name":"StakeNotMature","type":"error"},{"inputs":[],"name":"StakingIdMismatch","type":"error"},{"inputs":[],"name":"StakingPeriodMismatch","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"period","type":"uint8"},{"indexed":false,"internalType":"uint96","name":"rate","type":"uint96"}],"name":"AddInterestRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakeNumber","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"expiryAmount","type":"uint96"},{"indexed":false,"internalType":"uint40","name":"expiryTime","type":"uint40"},{"indexed":false,"internalType":"uint8","name":"period","type":"uint8"}],"name":"AddStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"period","type":"uint8"},{"indexed":false,"internalType":"uint32","name":"multiplier","type":"uint32"}],"name":"AddgStfxMultiplier","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":"staker","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"stakeNumber","type":"uint256[]"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"expiryAmount","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"transferAmount","type":"uint96"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"stakeNumber","type":"uint256[]"},{"indexed":false,"internalType":"uint96","name":"totalRewards","type":"uint96"}],"name":"ClaimRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"OwnerUpdate","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":"staker","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"stakeNumber","type":"uint256[]"},{"indexed":false,"internalType":"uint96","name":"totalTransferAmount","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"totalBurnAmount","type":"uint96"}],"name":"Unstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"burnAddress","type":"address"}],"name":"UpdateBurnAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"percent","type":"uint32"}],"name":"UpdateBurnPercent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"enum Stake.StakingPeriod","name":"period","type":"uint8"},{"internalType":"uint96","name":"rate","type":"uint96"}],"name":"addInterestRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum Stake.StakingPeriod","name":"period","type":"uint8"},{"internalType":"uint32","name":"multiplier","type":"uint32"}],"name":"addgStfxMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"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":"","type":"address"},{"internalType":"uint256","name":"","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":"burnAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burnPercent","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burntToDate","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"n","type":"uint256[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"n","type":"uint256[]"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"gStfxMultiplier","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256[]","name":"n","type":"uint256[]"}],"name":"getAccruedRewards","outputs":[{"internalType":"uint96","name":"claimableAmount","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"n","type":"uint256"}],"name":"getAccruedRewardsPerStake","outputs":[{"internalType":"uint96","name":"claimableAmount","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getAllStakes","outputs":[{"components":[{"internalType":"enum Stake.StakingPeriod","name":"period","type":"uint8"},{"internalType":"uint40","name":"startTime","type":"uint40"},{"internalType":"uint40","name":"expiryTime","type":"uint40"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"uint96","name":"expiryAmount","type":"uint96"},{"internalType":"uint96","name":"claimedAmount","type":"uint96"},{"internalType":"uint96","name":"gStfxAmount","type":"uint96"},{"internalType":"bool","name":"isCompleted","type":"bool"}],"internalType":"struct Stake.StakingInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256[]","name":"n","type":"uint256[]"}],"name":"getBurnAmount","outputs":[{"internalType":"uint96","name":"burnAmount","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"n","type":"uint256"}],"name":"getBurnAmountPerStake","outputs":[{"internalType":"uint96","name":"burnAmount","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256[]","name":"n","type":"uint256[]"}],"name":"getClaimedAmount","outputs":[{"internalType":"uint96","name":"claimedAmount","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256[]","name":"n","type":"uint256[]"}],"name":"getExpiryAmount","outputs":[{"internalType":"uint96","name":"expiryAmount","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getIdsForClaimRewards","outputs":[{"internalType":"uint256[]","name":"n","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"n","type":"uint256"}],"name":"getIsStakeMature","outputs":[{"internalType":"bool","name":"isMature","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getNumberOfStakes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256[]","name":"n","type":"uint256[]"}],"name":"getStakeAmount","outputs":[{"internalType":"uint96","name":"amount","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"n","type":"uint256"}],"name":"getStakingInfo","outputs":[{"components":[{"internalType":"enum Stake.StakingPeriod","name":"period","type":"uint8"},{"internalType":"uint40","name":"startTime","type":"uint40"},{"internalType":"uint40","name":"expiryTime","type":"uint40"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"uint96","name":"expiryAmount","type":"uint96"},{"internalType":"uint96","name":"claimedAmount","type":"uint96"},{"internalType":"uint96","name":"gStfxAmount","type":"uint96"},{"internalType":"bool","name":"isCompleted","type":"bool"}],"internalType":"struct Stake.StakingInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStats","outputs":[{"internalType":"uint96","name":"","type":"uint96"},{"internalType":"uint96","name":"","type":"uint96"},{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getStatsPerStaker","outputs":[{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"uint96","name":"expiryAmount","type":"uint96"},{"internalType":"uint96","name":"claimedAmount","type":"uint96"},{"internalType":"uint96","name":"accruedRewards","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"interestRate","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"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":[{"internalType":"uint256","name":"n","type":"uint256"},{"internalType":"enum Stake.StakingPeriod","name":"period","type":"uint8"}],"name":"restake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsToDate","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"enum Stake.StakingPeriod","name":"period","type":"uint8"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakingInfo","outputs":[{"internalType":"enum Stake.StakingPeriod","name":"period","type":"uint8"},{"internalType":"uint40","name":"startTime","type":"uint40"},{"internalType":"uint40","name":"expiryTime","type":"uint40"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"uint96","name":"expiryAmount","type":"uint96"},{"internalType":"uint96","name":"claimedAmount","type":"uint96"},{"internalType":"uint96","name":"gStfxAmount","type":"uint96"},{"internalType":"bool","name":"isCompleted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"n","type":"uint256[]"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"burn","type":"address"}],"name":"updateBurnAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"percent","type":"uint32"}],"name":"updateBurnPercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]