编译器
0.6.12+commit.27d51765
文件 1 的 11:Address.sol
pragma solidity ^0.6.2;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 11:AttoDecimal.sol
pragma solidity ^0.6.12;
import "./SafeMath.sol";
library AttoDecimal {
using SafeMath for uint256;
struct Instance {
uint256 mantissa;
}
uint256 internal constant BASE = 10;
uint256 internal constant EXPONENTIATION = 18;
uint256 internal constant ONE_MANTISSA = BASE**EXPONENTIATION;
uint256 internal constant ONE_TENTH_MANTISSA = ONE_MANTISSA / 10;
uint256 internal constant HALF_MANTISSA = ONE_MANTISSA / 2;
uint256 internal constant SQUARED_ONE_MANTISSA = ONE_MANTISSA * ONE_MANTISSA;
uint256 internal constant MAX_INTEGER = uint256(-1) / ONE_MANTISSA;
function maximum() internal pure returns (Instance memory) {
return Instance({mantissa: uint256(-1)});
}
function zero() internal pure returns (Instance memory) {
return Instance({mantissa: 0});
}
function one() internal pure returns (Instance memory) {
return Instance({mantissa: ONE_MANTISSA});
}
function convert(uint256 integer) internal pure returns (Instance memory) {
return Instance({mantissa: integer.mul(ONE_MANTISSA)});
}
function compare(Instance memory a, Instance memory b) internal pure returns (int8) {
if (a.mantissa < b.mantissa) return -1;
return int8(a.mantissa > b.mantissa ? 1 : 0);
}
function compare(Instance memory a, uint256 b) internal pure returns (int8) {
return compare(a, convert(b));
}
function add(Instance memory a, Instance memory b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa.add(b.mantissa)});
}
function add(Instance memory a, uint256 b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa.add(b.mul(ONE_MANTISSA))});
}
function sub(Instance memory a, Instance memory b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa.sub(b.mantissa)});
}
function sub(Instance memory a, uint256 b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa.sub(b.mul(ONE_MANTISSA))});
}
function sub(uint256 a, Instance memory b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mul(ONE_MANTISSA).sub(b.mantissa)});
}
function mul(Instance memory a, Instance memory b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa.mul(b.mantissa) / ONE_MANTISSA});
}
function mul(Instance memory a, uint256 b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa.mul(b)});
}
function div(Instance memory a, Instance memory b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa.mul(ONE_MANTISSA).div(b.mantissa)});
}
function div(Instance memory a, uint256 b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa.mul(ONE_MANTISSA).div(b)});
}
function div(uint256 a, Instance memory b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mul(SQUARED_ONE_MANTISSA).div(b.mantissa)});
}
function div(uint256 a, uint256 b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mul(ONE_MANTISSA).div(b)});
}
function idiv(Instance memory a, Instance memory b) internal pure returns (uint256) {
return a.mantissa.div(b.mantissa);
}
function idiv(Instance memory a, uint256 b) internal pure returns (uint256) {
return a.mantissa.div(b.mul(ONE_MANTISSA));
}
function idiv(uint256 a, Instance memory b) internal pure returns (uint256) {
return a.mul(ONE_MANTISSA).div(b.mantissa);
}
function mod(Instance memory a, Instance memory b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa.mod(b.mantissa)});
}
function mod(Instance memory a, uint256 b) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa.mod(b.mul(ONE_MANTISSA))});
}
function mod(uint256 a, Instance memory b) internal pure returns (Instance memory) {
if (a > MAX_INTEGER) return Instance({mantissa: a.mod(b.mantissa).mul(ONE_MANTISSA) % b.mantissa});
return Instance({mantissa: a.mul(ONE_MANTISSA).mod(b.mantissa)});
}
function floor(Instance memory a) internal pure returns (uint256) {
return a.mantissa / ONE_MANTISSA;
}
function ceil(Instance memory a) internal pure returns (uint256) {
return (a.mantissa / ONE_MANTISSA) + (a.mantissa % ONE_MANTISSA > 0 ? 1 : 0);
}
function round(Instance memory a) internal pure returns (uint256) {
return (a.mantissa / ONE_MANTISSA) + ((a.mantissa / ONE_TENTH_MANTISSA) % 10 >= 5 ? 1 : 0);
}
function eq(Instance memory a, Instance memory b) internal pure returns (bool) {
return a.mantissa == b.mantissa;
}
function eq(Instance memory a, uint256 b) internal pure returns (bool) {
if (b > MAX_INTEGER) return false;
return a.mantissa == b * ONE_MANTISSA;
}
function gt(Instance memory a, Instance memory b) internal pure returns (bool) {
return a.mantissa > b.mantissa;
}
function gt(Instance memory a, uint256 b) internal pure returns (bool) {
if (b > MAX_INTEGER) return false;
return a.mantissa > b * ONE_MANTISSA;
}
function gte(Instance memory a, Instance memory b) internal pure returns (bool) {
return a.mantissa >= b.mantissa;
}
function gte(Instance memory a, uint256 b) internal pure returns (bool) {
if (b > MAX_INTEGER) return false;
return a.mantissa >= b * ONE_MANTISSA;
}
function lt(Instance memory a, Instance memory b) internal pure returns (bool) {
return a.mantissa < b.mantissa;
}
function lt(Instance memory a, uint256 b) internal pure returns (bool) {
if (b > MAX_INTEGER) return true;
return a.mantissa < b * ONE_MANTISSA;
}
function lte(Instance memory a, Instance memory b) internal pure returns (bool) {
return a.mantissa <= b.mantissa;
}
function lte(Instance memory a, uint256 b) internal pure returns (bool) {
if (b > MAX_INTEGER) return true;
return a.mantissa <= b * ONE_MANTISSA;
}
function isInteger(Instance memory a) internal pure returns (bool) {
return a.mantissa % ONE_MANTISSA == 0;
}
function isPositive(Instance memory a) internal pure returns (bool) {
return a.mantissa > 0;
}
function isZero(Instance memory a) internal pure returns (bool) {
return a.mantissa == 0;
}
function sum(Instance[] memory array) internal pure returns (Instance memory result) {
uint256 length = array.length;
for (uint256 index = 0; index < length; index++) result = add(result, array[index]);
}
function toTuple(Instance memory a)
internal
pure
returns (
uint256 mantissa,
uint256 base,
uint256 exponentiation
)
{
return (a.mantissa, BASE, EXPONENTIATION);
}
}
文件 3 的 11:Context.sol
pragma solidity ^0.6.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 4 的 11:ERC20.sol
pragma solidity ^0.6.0;
import "./Context.sol";
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
using Address for address;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
constructor (string memory name, string memory symbol) public {
_name = name;
_symbol = symbol;
_decimals = 18;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, 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) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, 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 = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(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);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(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 _setupDecimals(uint8 decimals_) internal {
_decimals = decimals_;
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
文件 5 的 11:IERC20.sol
pragma solidity ^0.6.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, 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 sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 6 的 11:Math.sol
pragma solidity ^0.6.0;
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
文件 7 的 11:ReentrancyGuard.sol
pragma solidity ^0.6.0;
contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 8 的 11:SafeERC20.sol
pragma solidity ^0.6.0;
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 9 的 11:SafeMath.sol
pragma solidity ^0.6.0;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
文件 10 的 11:StakingPool.sol
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import "./Math.sol";
import "./SafeMath.sol";
import "./ERC20.sol";
import "./IERC20.sol";
import "./SafeERC20.sol";
import "./ReentrancyGuard.sol";
import "./AttoDecimal.sol";
import "./TwoStageOwnable.sol";
contract StakingPool is ERC20, ReentrancyGuard, TwoStageOwnable {
using SafeMath for uint256;
using SafeERC20 for IERC20;
using AttoDecimal for AttoDecimal.Instance;
struct Strategy {
uint256 endsAt;
uint256 perSecondReward;
uint256 startsAt;
}
struct Unstake {
uint256 amount;
uint256 applicableAt;
}
uint256 public constant MIN_STAKE_BALANCE = 10**18;
uint256 public claimingFeePercent;
uint256 public lastUpdatedAt;
uint256 private _feePool;
uint256 private _lockedRewards;
uint256 private _totalStaked;
uint256 private _totalUnstaked;
uint256 private _unstakingTime;
IERC20 private _stakingToken;
AttoDecimal.Instance private _defaultPrice;
AttoDecimal.Instance private _price;
Strategy private _currentStrategy;
Strategy private _nextStrategy;
mapping(address => Unstake) private _unstakes;
function getTimestamp() internal view virtual returns (uint256) {
return block.timestamp;
}
function feePool() public view returns (uint256) {
return _feePool;
}
function lockedRewards() public view returns (uint256) {
return _lockedRewards;
}
function totalStaked() public view returns (uint256) {
return _totalStaked;
}
function totalUnstaked() public view returns (uint256) {
return _totalUnstaked;
}
function stakingToken() public view returns (IERC20) {
return _stakingToken;
}
function unstakingTime() public view returns (uint256) {
return _unstakingTime;
}
function currentStrategy() public view returns (Strategy memory) {
return _currentStrategy;
}
function nextStrategy() public view returns (Strategy memory) {
return _nextStrategy;
}
function getUnstake(address account) public view returns (Unstake memory result) {
result = _unstakes[account];
}
function defaultPrice()
external
view
returns (
uint256 mantissa,
uint256 base,
uint256 exponentiation
)
{
return _defaultPrice.toTuple();
}
function getCurrentStrategyUnlockedRewards() public view returns (uint256 unlocked) {
unlocked = _getStrategyUnlockedRewards(_currentStrategy);
}
function getUnlockedRewards() public view returns (uint256 unlocked, bool currentStrategyEnded) {
unlocked = _getStrategyUnlockedRewards(_currentStrategy);
if (getTimestamp() >= _currentStrategy.endsAt) {
currentStrategyEnded = true;
if (_nextStrategy.endsAt != 0) unlocked = unlocked.add(_getStrategyUnlockedRewards(_nextStrategy));
}
}
function price()
public
view
returns (
uint256 mantissa,
uint256 base,
uint256 exponentiation
)
{
(uint256 unlocked, ) = getUnlockedRewards();
uint256 totalStaked_ = _totalStaked;
uint256 totalSupply_ = totalSupply();
AttoDecimal.Instance memory result = _defaultPrice;
if (totalSupply_ > 0) result = AttoDecimal.div(totalStaked_.add(unlocked), totalSupply_);
return result.toTuple();
}
function priceStored()
public
view
returns (
uint256 mantissa,
uint256 base,
uint256 exponentiation
)
{
return _price.toTuple();
}
function calculateUnstake(address account, uint256 amount)
public
view
returns (uint256 unstakedAmount, uint256 burnedAmount)
{
(uint256 mantissa_, , ) = price();
return _calculateUnstake(account, amount, AttoDecimal.Instance(mantissa_));
}
event Claimed(
address indexed account,
uint256 requestedAmount,
uint256 claimedAmount,
uint256 feeAmount,
uint256 burnedAmount
);
event ClaimingFeePercentUpdated(uint256 feePercent);
event CurrentStrategyUpdated(uint256 perSecondReward, uint256 startsAt, uint256 endsAt);
event FeeClaimed(address indexed receiver, uint256 amount);
event NextStrategyUpdated(uint256 perSecondReward, uint256 startsAt, uint256 endsAt);
event UnstakingTimeUpdated(uint256 unstakingTime);
event NextStrategyRemoved();
event PoolDecreased(uint256 amount);
event PoolIncreased(address indexed payer, uint256 amount);
event PriceUpdated(uint256 mantissa, uint256 base, uint256 exponentiation);
event RewardsUnlocked(uint256 amount);
event Staked(address indexed account, address indexed payer, uint256 stakedAmount, uint256 mintedAmount);
event Unstaked(address indexed account, uint256 requestedAmount, uint256 unstakedAmount, uint256 burnedAmount);
event UnstakingCanceled(address indexed account, uint256 amount);
event Withdrawed(address indexed account, uint256 amount);
constructor(
string memory syntheticTokenName,
string memory syntheticTokenSymbol,
IERC20 stakingToken_,
address owner_,
uint256 claimingFeePercent_,
uint256 perSecondReward_,
uint256 startsAt_,
uint256 duration_,
uint256 unstakingTime_,
uint256 defaultPriceMantissa
) public TwoStageOwnable(owner_) ERC20(syntheticTokenName, syntheticTokenSymbol) {
_defaultPrice = AttoDecimal.Instance(defaultPriceMantissa);
_stakingToken = stakingToken_;
_setClaimingFeePercent(claimingFeePercent_);
_validateStrategyParameters(perSecondReward_, startsAt_, duration_);
_setUnstakingTime(unstakingTime_);
_setCurrentStrategy(perSecondReward_, startsAt_, startsAt_.add(duration_));
lastUpdatedAt = getTimestamp();
_price = _defaultPrice;
}
function cancelUnstaking(uint256 amount) external onlyPositiveAmount(amount) returns (bool success) {
_update();
address caller = msg.sender;
Unstake storage unstake_ = _unstakes[caller];
uint256 unstakingAmount = unstake_.amount;
require(unstakingAmount >= amount, "Not enough unstaked balance");
uint256 stakedAmount = _price.mul(balanceOf(caller)).floor();
require(stakedAmount.add(amount) >= MIN_STAKE_BALANCE, "Stake balance lt min stake");
uint256 synthAmount = AttoDecimal.div(amount, _price).floor();
_mint(caller, synthAmount);
_totalStaked = _totalStaked.add(amount);
_totalUnstaked = _totalUnstaked.sub(amount);
unstake_.amount = unstakingAmount.sub(amount);
emit Staked(caller, address(0), amount, synthAmount);
emit UnstakingCanceled(caller, amount);
return true;
}
function claim(uint256 amount)
external
onlyPositiveAmount(amount)
returns (uint256 claimedAmount, uint256 burnedAmount)
{
_update();
address caller = msg.sender;
(claimedAmount, burnedAmount) = _calculateUnstake(caller, amount, _price);
uint256 fee = claimedAmount.mul(claimingFeePercent).div(100);
_burn(caller, burnedAmount);
_totalStaked = _totalStaked.sub(claimedAmount);
claimedAmount = claimedAmount.sub(fee);
_feePool = _feePool.add(fee);
emit Claimed(caller, amount, claimedAmount, fee, burnedAmount);
_stakingToken.safeTransfer(caller, claimedAmount);
}
function claimFees() external onlyOwner returns (uint256 amount) {
require(_feePool > 0, "No fees");
amount = _feePool;
_feePool = 0;
emit FeeClaimed(owner(), amount);
_stakingToken.safeTransfer(owner(), amount);
}
function createNewStrategy(
uint256 perSecondReward_,
uint256 startsAt_,
uint256 duration_
) public onlyOwner returns (bool success) {
_update();
_validateStrategyParameters(perSecondReward_, startsAt_, duration_);
uint256 endsAt = startsAt_.add(duration_);
Strategy memory strategy = Strategy({perSecondReward: perSecondReward_, startsAt: startsAt_, endsAt: endsAt});
if (_currentStrategy.startsAt > getTimestamp()) {
delete _nextStrategy;
emit NextStrategyRemoved();
_currentStrategy = strategy;
emit CurrentStrategyUpdated(perSecondReward_, startsAt_, endsAt);
} else {
emit NextStrategyUpdated(perSecondReward_, startsAt_, endsAt);
_nextStrategy = strategy;
if (_currentStrategy.endsAt > startsAt_) {
_currentStrategy.endsAt = startsAt_;
emit CurrentStrategyUpdated(_currentStrategy.perSecondReward, _currentStrategy.startsAt, startsAt_);
}
}
return true;
}
function decreasePool(uint256 amount) external onlyPositiveAmount(amount) onlyOwner returns (bool success) {
_update();
_lockedRewards = _lockedRewards.sub(amount, "Not enough locked rewards");
emit PoolDecreased(amount);
_stakingToken.safeTransfer(owner(), amount);
return true;
}
function increasePool(uint256 amount) external onlyPositiveAmount(amount) returns (bool success) {
_update();
address payer = msg.sender;
_lockedRewards = _lockedRewards.add(amount);
emit PoolIncreased(payer, amount);
_stakingToken.safeTransferFrom(payer, address(this), amount);
return true;
}
function setClaimingFeePercent(uint256 feePercent) external onlyOwner returns (bool success) {
_setClaimingFeePercent(feePercent);
return true;
}
function stake(uint256 amount) external onlyPositiveAmount(amount) returns (uint256 mintedAmount) {
address staker = msg.sender;
return _stake(staker, staker, amount);
}
function stakeForUser(address account, uint256 amount)
external
onlyPositiveAmount(amount)
returns (uint256 mintedAmount)
{
return _stake(account, msg.sender, amount);
}
function unstake(uint256 amount)
external
onlyPositiveAmount(amount)
returns (uint256 unstakedAmount, uint256 burnedAmount)
{
_update();
address caller = msg.sender;
(unstakedAmount, burnedAmount) = _calculateUnstake(caller, amount, _price);
_burn(caller, burnedAmount);
_totalStaked = _totalStaked.sub(unstakedAmount);
_totalUnstaked = _totalUnstaked.add(unstakedAmount);
Unstake storage unstake_ = _unstakes[caller];
unstake_.amount = unstake_.amount.add(unstakedAmount);
unstake_.applicableAt = getTimestamp().add(_unstakingTime);
emit Unstaked(caller, amount, unstakedAmount, burnedAmount);
}
function update() external returns (bool success) {
_update();
return true;
}
function withdraw() external returns (bool success) {
address caller = msg.sender;
Unstake storage unstake_ = _unstakes[caller];
uint256 amount = unstake_.amount;
require(amount > 0, "Not unstaked");
require(unstake_.applicableAt <= getTimestamp(), "Not released at");
delete _unstakes[caller];
_totalUnstaked = _totalUnstaked.sub(amount);
emit Withdrawed(caller, amount);
_stakingToken.safeTransfer(caller, amount);
return true;
}
function setUnstakingTime(uint256 unstakingTime_) external onlyOwner returns (bool success) {
_setUnstakingTime(unstakingTime_);
return true;
}
function _getStrategyUnlockedRewards(Strategy memory strategy_) internal view returns (uint256 unlocked) {
uint256 timestamp = getTimestamp();
if (timestamp < strategy_.startsAt || timestamp == lastUpdatedAt) {
return unlocked;
}
uint256 lastRewardedSecond = Math.max(lastUpdatedAt, strategy_.startsAt);
uint256 lastRewardableTimestamp = Math.min(timestamp, strategy_.endsAt);
if (lastRewardedSecond < lastRewardableTimestamp) {
uint256 timeDiff = lastRewardableTimestamp.sub(lastRewardedSecond);
unlocked = unlocked.add(timeDiff.mul(strategy_.perSecondReward));
}
}
function _calculateUnstake(
address account,
uint256 amount,
AttoDecimal.Instance memory price_
) internal view returns (uint256 unstakedAmount, uint256 burnedAmount) {
unstakedAmount = amount;
burnedAmount = AttoDecimal.div(amount, price_).ceil();
uint256 balance = balanceOf(account);
require(burnedAmount > 0, "Too small unstaking amount");
require(balance >= burnedAmount, "Not enough synthetic tokens");
uint256 remainingSyntheticBalance = balance.sub(burnedAmount);
uint256 remainingStake = _price.mul(remainingSyntheticBalance).floor();
if (remainingStake < 10**18) {
burnedAmount = balance;
unstakedAmount = unstakedAmount.add(remainingStake);
}
}
function _unlockRewardsAndStake() internal {
(uint256 unlocked, bool currentStrategyEnded) = getUnlockedRewards();
if (currentStrategyEnded) {
_currentStrategy = _nextStrategy;
emit NextStrategyRemoved();
if (_currentStrategy.endsAt != 0) {
emit CurrentStrategyUpdated(
_currentStrategy.perSecondReward,
_currentStrategy.startsAt,
_currentStrategy.endsAt
);
}
delete _nextStrategy;
}
unlocked = Math.min(unlocked, _lockedRewards);
if (unlocked > 0) {
emit RewardsUnlocked(unlocked);
_lockedRewards = _lockedRewards.sub(unlocked);
_totalStaked = _totalStaked.add(unlocked);
}
lastUpdatedAt = getTimestamp();
}
function _update() internal {
if (getTimestamp() <= lastUpdatedAt) return;
_unlockRewardsAndStake();
_updatePrice();
}
function _updatePrice() internal {
uint256 totalStaked_ = _totalStaked;
uint256 totalSupply_ = totalSupply();
if (totalSupply_ == 0) _price = _defaultPrice;
else _price = AttoDecimal.div(totalStaked_, totalSupply_);
emit PriceUpdated(_price.mantissa, AttoDecimal.BASE, AttoDecimal.EXPONENTIATION);
}
function _validateStrategyParameters(
uint256 perSecondReward,
uint256 startsAt,
uint256 duration
) internal view {
require(duration > 0, "Duration is zero");
require(startsAt >= getTimestamp(), "Starting timestamp lt current");
require(perSecondReward <= 188 * 10**18, "Per second reward overflow");
}
function _setClaimingFeePercent(uint256 feePercent) internal {
require(feePercent >= 0 && feePercent <= 100, "Invalid fee percent");
claimingFeePercent = feePercent;
emit ClaimingFeePercentUpdated(feePercent);
}
function _setUnstakingTime(uint256 unstakingTime_) internal {
_unstakingTime = unstakingTime_;
emit UnstakingTimeUpdated(unstakingTime_);
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal override {
_update();
string memory errorText = "Minimal stake balance should be more or equal to 1 token";
if (from != address(0)) {
uint256 fromNewBalance = _price.mul(balanceOf(from).sub(amount)).floor();
require(fromNewBalance >= MIN_STAKE_BALANCE || fromNewBalance == 0, errorText);
}
if (to != address(0)) {
require(_price.mul(balanceOf(to).add(amount)).floor() >= MIN_STAKE_BALANCE, errorText);
}
}
function _setCurrentStrategy(
uint256 perSecondReward_,
uint256 startsAt_,
uint256 endsAt_
) private {
_currentStrategy = Strategy({perSecondReward: perSecondReward_, startsAt: startsAt_, endsAt: endsAt_});
emit CurrentStrategyUpdated(perSecondReward_, startsAt_, endsAt_);
}
function _stake(
address staker,
address payer,
uint256 amount
) private returns (uint256 mintedAmount) {
_update();
mintedAmount = AttoDecimal.div(amount, _price).floor();
require(mintedAmount > 0, "Too small staking amount");
_mint(staker, mintedAmount);
_totalStaked = _totalStaked.add(amount);
emit Staked(staker, payer, amount, mintedAmount);
_stakingToken.safeTransferFrom(payer, address(this), amount);
}
modifier onlyPositiveAmount(uint256 amount) {
require(amount > 0, "Amount is not positive");
_;
}
}
文件 11 的 11:TwoStageOwnable.sol
pragma solidity ^0.6.12;
abstract contract TwoStageOwnable {
address private _nominatedOwner;
address private _owner;
function nominatedOwner() public view returns (address) {
return _nominatedOwner;
}
function owner() public view returns (address) {
return _owner;
}
event OwnerChanged(address indexed newOwner);
event OwnerNominated(address indexed nominatedOwner);
constructor(address owner_) internal {
require(owner_ != address(0), "Owner is zero");
_setOwner(owner_);
}
function acceptOwnership() external returns (bool success) {
require(msg.sender == _nominatedOwner, "Not nominated to ownership");
_setOwner(_nominatedOwner);
return true;
}
function nominateNewOwner(address owner_) external onlyOwner returns (bool success) {
_nominateNewOwner(owner_);
return true;
}
modifier onlyOwner {
require(msg.sender == _owner, "Not owner");
_;
}
function _nominateNewOwner(address owner_) internal {
if (_nominatedOwner == owner_) return;
require(_owner != owner_, "Already owner");
_nominatedOwner = owner_;
emit OwnerNominated(owner_);
}
function _setOwner(address newOwner) internal {
if (_owner == newOwner) return;
_owner = newOwner;
_nominatedOwner = address(0);
emit OwnerChanged(newOwner);
}
}
{
"compilationTarget": {
"StakingPool.sol": "StakingPool"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"syntheticTokenName","type":"string"},{"internalType":"string","name":"syntheticTokenSymbol","type":"string"},{"internalType":"contract IERC20","name":"stakingToken_","type":"address"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint256","name":"claimingFeePercent_","type":"uint256"},{"internalType":"uint256","name":"perSecondReward_","type":"uint256"},{"internalType":"uint256","name":"startsAt_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"},{"internalType":"uint256","name":"unstakingTime_","type":"uint256"},{"internalType":"uint256","name":"defaultPriceMantissa","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"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":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"requestedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnedAmount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feePercent","type":"uint256"}],"name":"ClaimingFeePercentUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"perSecondReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startsAt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endsAt","type":"uint256"}],"name":"CurrentStrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeClaimed","type":"event"},{"anonymous":false,"inputs":[],"name":"NextStrategyRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"perSecondReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startsAt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endsAt","type":"uint256"}],"name":"NextStrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nominatedOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PoolDecreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PoolIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"mantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"base","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exponentiation","type":"uint256"}],"name":"PriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintedAmount","type":"uint256"}],"name":"Staked","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":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"requestedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unstakedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnedAmount","type":"uint256"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UnstakingCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"unstakingTime","type":"uint256"}],"name":"UnstakingTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawed","type":"event"},{"inputs":[],"name":"MIN_STAKE_BALANCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"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":"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":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"calculateUnstake","outputs":[{"internalType":"uint256","name":"unstakedAmount","type":"uint256"},{"internalType":"uint256","name":"burnedAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"cancelUnstaking","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claim","outputs":[{"internalType":"uint256","name":"claimedAmount","type":"uint256"},{"internalType":"uint256","name":"burnedAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimFees","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimingFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perSecondReward_","type":"uint256"},{"internalType":"uint256","name":"startsAt_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"}],"name":"createNewStrategy","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentStrategy","outputs":[{"components":[{"internalType":"uint256","name":"endsAt","type":"uint256"},{"internalType":"uint256","name":"perSecondReward","type":"uint256"},{"internalType":"uint256","name":"startsAt","type":"uint256"}],"internalType":"struct StakingPool.Strategy","name":"","type":"tuple"}],"stateMutability":"view","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":"uint256","name":"amount","type":"uint256"}],"name":"decreasePool","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultPrice","outputs":[{"internalType":"uint256","name":"mantissa","type":"uint256"},{"internalType":"uint256","name":"base","type":"uint256"},{"internalType":"uint256","name":"exponentiation","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feePool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentStrategyUnlockedRewards","outputs":[{"internalType":"uint256","name":"unlocked","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnlockedRewards","outputs":[{"internalType":"uint256","name":"unlocked","type":"uint256"},{"internalType":"bool","name":"currentStrategyEnded","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getUnstake","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"applicableAt","type":"uint256"}],"internalType":"struct StakingPool.Unstake","name":"result","type":"tuple"}],"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":"uint256","name":"amount","type":"uint256"}],"name":"increasePool","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastUpdatedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockedRewards","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":"nextStrategy","outputs":[{"components":[{"internalType":"uint256","name":"endsAt","type":"uint256"},{"internalType":"uint256","name":"perSecondReward","type":"uint256"},{"internalType":"uint256","name":"startsAt","type":"uint256"}],"internalType":"struct StakingPool.Strategy","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"nominateNewOwner","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"mantissa","type":"uint256"},{"internalType":"uint256","name":"base","type":"uint256"},{"internalType":"uint256","name":"exponentiation","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceStored","outputs":[{"internalType":"uint256","name":"mantissa","type":"uint256"},{"internalType":"uint256","name":"base","type":"uint256"},{"internalType":"uint256","name":"exponentiation","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"feePercent","type":"uint256"}],"name":"setClaimingFeePercent","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"unstakingTime_","type":"uint256"}],"name":"setUnstakingTime","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[{"internalType":"uint256","name":"mintedAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stakeForUser","outputs":[{"internalType":"uint256","name":"mintedAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","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":"totalUnstaked","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":"uint256","name":"amount","type":"uint256"}],"name":"unstake","outputs":[{"internalType":"uint256","name":"unstakedAmount","type":"uint256"},{"internalType":"uint256","name":"burnedAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakingTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"update","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]