# Contract Address Details

### 0x2bb7F62c783A3AE88926C94B6c1DBc130cd82608

Contract Name
Treasury
Creator
0xafa414–714ba5 at 0x56eee8–87d446
Balance
0 MOVR
Tokens
Fetching tokens...
Transactions
431 Transactions
Transfers
510 Transfers
Gas Used
87,960,581
Last Balance Update
3132193
Contract name:
Treasury

Optimization enabled
true
Compiler version
v0.8.4+commit.c7e474f2

Optimization runs
200
EVM Version
default

Verified at
2022-01-14 15:49:53.632577Z

### Contract source code

``````// Sources flattened with hardhat v2.8.0 https://hardhat.org

// File @openzeppelin/contracts/utils/math/Math.sol@v4.4.1

// OpenZeppelin Contracts v4.4.1 (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}

/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}

/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}

/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a / b + (a % b == 0 ? 0 : 1);
}
}

// File @openzeppelin/contracts/token/ERC20/IERC20.sol@v4.4.1

// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);

/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);

/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) 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 `amount` 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 amount) external returns (bool);

/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
uint256 amount
) external returns (bool);

/**
* @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);
}

// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)

pragma solidity ^0.8.0;

/**
* @dev Collection of functions related to the address type
*/
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
*  - an externally-owned account
*  - a contract in construction
*  - an address where a contract will be created
*  - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.

uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}

/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
*/
function sendValue(address payable recipient, uint256 amount) internal {

(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}

/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}

/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}

/**
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}

/**
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");

(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}

/**
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}

/**
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");

(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}

/**
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}

/**
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");

(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}

/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly

assembly {
let returndata_size := mload(returndata)
}
} else {
revert(errorMessage);
}
}
}
}

// File @openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol@v4.4.1

// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {

function safeTransfer(
IERC20 token,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}

function safeTransferFrom(
IERC20 token,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}

/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
*/
function safeApprove(
IERC20 token,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
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,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}

function safeDecreaseAllowance(
IERC20 token,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}

/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.

bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}

// File @openzeppelin/contracts/security/ReentrancyGuard.sol@v4.4.1

// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.

// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;

uint256 private _status;

constructor() {
_status = _NOT_ENTERED;
}

/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

// Any calls to nonReentrant after this point will fail
_status = _ENTERED;

_;

// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}

// File @openzeppelin/contracts/utils/math/SafeMath.sol@v4.4.1

// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}

/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}

/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}

/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}

/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}

/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}

/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}

/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}

/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}

/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}

/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}

/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}

/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}

// File contracts/lib/Babylonian.sol

pragma solidity ^0.8.0;

library Babylonian {
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
// else z = 0
}
}

// File @openzeppelin/contracts/utils/Context.sol@v4.4.1

// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
* @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;
}
}

// File @openzeppelin/contracts/access/Ownable.sol@v4.4.1

// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

/**
* @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.
*
* By default, the owner account will be the one that deploys the contract. 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 {

event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}

/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}

/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}

/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
}

/**
* @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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_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);
}
}

// File contracts/owner/Operator.sol

pragma solidity ^0.8.0;

contract Operator is Context, Ownable {

event OperatorTransferred(address indexed previousOperator, address indexed newOperator);

constructor () {
_operator = _msgSender();
}

function operator() public view returns (address) {
return _operator;
}

modifier onlyOperator() {
require(_operator == msg.sender, "operator: caller is not the operator");
_;
}

function isOperator() public view returns (bool) {
return _msgSender() == _operator;
}

function transferOperator(address newOperator_) public onlyOwner {
_transferOperator(newOperator_);
}

function _transferOperator(address newOperator_) internal {
require(newOperator_ != address(0), "operator: zero address given for new operator");
_operator = newOperator_;
}
}

// File contracts/utils/ContractGuard.sol

pragma solidity ^0.8.0;

contract ContractGuard {
mapping(uint256 => mapping(address => bool)) private _status;

function checkSameOriginReentranted() internal view returns (bool) {
return _status[block.number][tx.origin];
}

function checkSameSenderReentranted() internal view returns (bool) {
return _status[block.number][msg.sender];
}

modifier onlyOneBlock() {
require(!checkSameOriginReentranted(), "ContractGuard: one block, one function");
require(!checkSameSenderReentranted(), "ContractGuard: one block, one function");

_;

_status[block.number][tx.origin] = true;
_status[block.number][msg.sender] = true;
}
}

// File contracts/interfaces/IBasisAsset.sol

pragma solidity ^0.8.0;

interface IBasisAsset {
function mint(address recipient, uint256 amount) external returns (bool);

function burn(uint256 amount) external;

function burnFrom(address from, uint256 amount) external;

function isOperator() external returns (bool);

function operator() external view returns (address);

function transferOperator(address newOperator_) external;
}

// File contracts/interfaces/IOracle.sol

pragma solidity ^0.8.0;

interface IOracle {
function update() external;

function consult(address _token, uint256 _amountIn) external view returns (uint144 amountOut);

function twap(address _token, uint256 _amountIn) external view returns (uint144 _amountOut);
}

// File contracts/interfaces/IMasonry.sol

pragma solidity ^0.8.0;

interface IMasonry {
function balanceOf(address _mason) external view returns (uint256);

function earned(address _mason) external view returns (uint256);

function canWithdraw(address _mason) external view returns (bool);

function canClaimReward(address _mason) external view returns (bool);

function epoch() external view returns (uint256);

function nextEpochPoint() external view returns (uint256);

function getAthenaPrice() external view returns (uint256);

function setOperator(address _operator) external;

function setLockUp(uint256 _withdrawLockupEpochs, uint256 _rewardLockupEpochs) external;

function stake(uint256 _amount) external;

function withdraw(uint256 _amount) external;

function exit() external;

function claimReward() external;

function allocateSeigniorage(uint256 _amount) external;

function governanceRecoverUnsupported(address _token, uint256 _amount, address _to) external;
}

// File contracts/Treasury.sol

pragma solidity ^0.8.0;

/*
_____   __  .__                              _____
/  _  \_/  |_|  |__   ____   ____ _____      /     \   ____   ____   ____ ___.__.
/  /_\  \   __\  |  \_/ __ \ /    \\__  \    /  \ /  \ /  _ \ /    \_/ __ <   |  |
/    |    \  | |   Y  \  ___/|   |  \/ __ \_ /    Y    (  <_> )   |  \  ___/\___  |
\____|__  /__| |___|  /\___  >___|  (____  / \____|__  /\____/|___|  /\___  > ____|
\/          \/     \/     \/     \/          \/            \/     \/\/

http://athena.money
*/
contract Treasury is ContractGuard {
using SafeERC20 for IERC20;
using SafeMath for uint256;

/* ========= CONSTANT VARIABLES ======== */

uint256 public constant PERIOD = 6 hours;

/* ========== STATE VARIABLES ========== */

// governance

// flags
bool public initialized = false;

// epoch
uint256 public startTime;
uint256 public epoch = 0;
uint256 public epochSupplyContractionLeft = 0;

// exclusions from total supply
address[] public excludedFromTotalSupply = [
//address(0xA7B16703470055881e7EE093e9b0bF537f29CD4d) // old AthenaRewardPool
];

// core components

// price
uint256 public athenaPriceOne;
uint256 public athenaPriceCeiling;

uint256 public seigniorageSaved;

uint256[] public supplyTiers;
uint256[] public maxExpansionTiers;

uint256 public maxSupplyExpansionPercent;
uint256 public bondDepletionFloorPercent;
uint256 public seigniorageExpansionFloorPercent;
uint256 public maxSupplyContractionPercent;
uint256 public maxDebtRatioPercent;

// 28 first epochs (1 week) with 4.5% expansion regardless of ATH price
uint256 public bootstrapEpochs;
uint256 public bootstrapSupplyExpansionPercent;

/* =================== Added variables =================== */
uint256 public previousEpochAthenaPrice;
uint256 public maxDiscountRate; // when purchasing bond
uint256 public maxPremiumRate; // when redeeming bond
uint256 public discountPercent;
uint256 public mintingFactorForPayingDebt; // print extra ATH during debt phase

uint256 public daoFundSharedPercent;

uint256 public devFundSharedPercent;

/* =================== Events =================== */

event Initialized(address indexed executor, uint256 at);
event BurnedBonds(address indexed from, uint256 bondAmount);
event RedeemedBonds(address indexed from, uint256 athenaAmount, uint256 bondAmount);
event BoughtBonds(address indexed from, uint256 athenaAmount, uint256 bondAmount);
event TreasuryFunded(uint256 timestamp, uint256 seigniorage);
event MasonryFunded(uint256 timestamp, uint256 seigniorage);
event DaoFundFunded(uint256 timestamp, uint256 seigniorage);
event DevFundFunded(uint256 timestamp, uint256 seigniorage);

/* =================== Modifier =================== */

modifier onlyOperator() {
require(operator == msg.sender, "Treasury: caller is not the operator");
_;
}

modifier checkCondition {
require(block.timestamp >= startTime, "Treasury: not started yet");

_;
}

modifier checkEpoch {
require(block.timestamp >= nextEpochPoint(), "Treasury: not opened yet");

_;

epochSupplyContractionLeft = (getAthenaPrice() > athenaPriceCeiling) ? 0 : getAthenaCirculatingSupply().mul(maxSupplyContractionPercent).div(10000);
}

modifier checkOperator {
require(
IBasisAsset(athena).operator() == address(this) &&
IBasisAsset(abond).operator() == address(this) &&
IBasisAsset(ashare).operator() == address(this) &&
"Treasury: need more permission"
);

_;
}

modifier notInitialized {
require(!initialized, "Treasury: already initialized");

_;
}

/* ========== VIEW FUNCTIONS ========== */

function isInitialized() public view returns (bool) {
return initialized;
}

// epoch
function nextEpochPoint() public view returns (uint256) {
}

// oracle
function getAthenaPrice() public view returns (uint256 athenaPrice) {
try IOracle(athenaOracle).consult(athena, 1e18) returns (uint144 price) {
return uint256(price);
} catch {
revert("Treasury: failed to consult ATH price from the oracle");
}
}

function getAthenaUpdatedPrice() public view returns (uint256 _athenaPrice) {
try IOracle(athenaOracle).twap(athena, 1e18) returns (uint144 price) {
return uint256(price);
} catch {
revert("Treasury: failed to consult ATH price from the oracle");
}
}

// budget
function getReserve() public view returns (uint256) {
return seigniorageSaved;
}

function getBurnableAthenaLeft() public view returns (uint256 _burnableAthenaLeft) {
uint256 _athenaPrice = getAthenaPrice();
if (_athenaPrice <= athenaPriceOne) {
uint256 _athenaSupply = getAthenaCirculatingSupply();
uint256 _bondMaxSupply = _athenaSupply.mul(maxDebtRatioPercent).div(10000);
uint256 _bondSupply = IERC20(abond).totalSupply();
if (_bondMaxSupply > _bondSupply) {
uint256 _maxMintableBond = _bondMaxSupply.sub(_bondSupply);
uint256 _maxBurnableAthena = _maxMintableBond.mul(_athenaPrice).div(1e18);
_burnableAthenaLeft = Math.min(epochSupplyContractionLeft, _maxBurnableAthena);
}
}
}

function getRedeemableBonds() public view returns (uint256 _redeemableBonds) {
uint256 _athenaPrice = getAthenaPrice();
if (_athenaPrice > athenaPriceCeiling) {
uint256 _totalAthena = IERC20(athena).balanceOf(address(this));
uint256 _rate = getBondPremiumRate();
if (_rate > 0) {
_redeemableBonds = _totalAthena.mul(1e18).div(_rate);
}
}
}

function getBondDiscountRate() public view returns (uint256 _rate) {
uint256 _athenaPrice = getAthenaPrice();
if (_athenaPrice <= athenaPriceOne) {
if (discountPercent == 0) {
// no discount
_rate = athenaPriceOne;
} else {
uint256 _bondAmount = athenaPriceOne.mul(1e18).div(_athenaPrice); // to burn 1 ATH
uint256 _discountAmount = _bondAmount.sub(athenaPriceOne).mul(discountPercent).div(10000);
if (maxDiscountRate > 0 && _rate > maxDiscountRate) {
_rate = maxDiscountRate;
}
}
}
}

function getBondPremiumRate() public view returns (uint256 _rate) {
uint256 _athenaPrice = getAthenaPrice();
if (_athenaPrice > athenaPriceCeiling) {
if (_athenaPrice >= _athenaPricePremiumThreshold) {
//Price > 1.10
if (maxPremiumRate > 0 && _rate > maxPremiumRate) {
}
} else {
// no premium bonus
_rate = athenaPriceOne;
}
}
}

/* ========== GOVERNANCE ========== */

function initialize(
uint256 _startTime
) public notInitialized {
athena = _athena;
abond = _abond;
ashare = _ashare;
athenaOracle = _athenaOracle;
masonry = _masonry;
startTime = _startTime;

athenaPriceOne = 10**18;
athenaPriceCeiling = athenaPriceOne.mul(101).div(100);

// Dynamic max expansion percent
supplyTiers = [0 ether, 500 ether, 1000 ether, 1500 ether, 2000 ether, 5000 ether, 10000 ether, 20000 ether, 50000 ether];
maxExpansionTiers = [450, 400, 350, 300, 250, 200, 150, 125, 100];

maxSupplyExpansionPercent = 400; // Upto 4.0% supply for expansion

bondDepletionFloorPercent = 10000; // 100% of Bond supply for depletion floor
seigniorageExpansionFloorPercent = 3500; // At least 35% of expansion reserved for masonry
maxSupplyContractionPercent = 300; // Upto 3.0% supply for contraction (to burn ATH and mint aBOND)
maxDebtRatioPercent = 3500; // Upto 35% supply of aBOND to purchase

// First 28 epochs with 4.5% expansion
bootstrapEpochs = 28;
bootstrapSupplyExpansionPercent = 450;

// set seigniorageSaved to it's balance

initialized = true;
operator = msg.sender;
emit Initialized(msg.sender, block.number);
}

function setOperator(address _operator) external onlyOperator {
operator = _operator;
}

function setMasonry(address _masonry) external onlyOperator {
masonry = _masonry;
}

function setAthenaOracle(address _athenaOracle) external onlyOperator {
athenaOracle = _athenaOracle;
}

function setAthenaPriceCeiling(uint256 _athenaPriceCeiling) external onlyOperator {
require(_athenaPriceCeiling >= athenaPriceOne && _athenaPriceCeiling <= athenaPriceOne.mul(120).div(100), "out of range"); // [\$1.0, \$1.2]
athenaPriceCeiling = _athenaPriceCeiling;
}

function setMaxSupplyExpansionPercents(uint256 _maxSupplyExpansionPercent) external onlyOperator {
require(_maxSupplyExpansionPercent >= 10 && _maxSupplyExpansionPercent <= 1000, "_maxSupplyExpansionPercent: out of range"); // [0.1%, 10%]
maxSupplyExpansionPercent = _maxSupplyExpansionPercent;
}

function setSupplyTiersEntry(uint8 _index, uint256 _value) external onlyOperator returns (bool) {
require(_index >= 0, "Index has to be higher than 0");
require(_index < 9, "Index has to be lower than count of tiers");
if (_index > 0) {
require(_value > supplyTiers[_index - 1]);
}
if (_index < 8) {
require(_value < supplyTiers[_index + 1]);
}
supplyTiers[_index] = _value;
return true;
}

function setMaxExpansionTiersEntry(uint8 _index, uint256 _value) external onlyOperator returns (bool) {
require(_index >= 0, "Index has to be higher than 0");
require(_index < 9, "Index has to be lower than count of tiers");
require(_value >= 10 && _value <= 1000, "_value: out of range"); // [0.1%, 10%]
maxExpansionTiers[_index] = _value;
return true;
}

function setBondDepletionFloorPercent(uint256 _bondDepletionFloorPercent) external onlyOperator {
require(_bondDepletionFloorPercent >= 500 && _bondDepletionFloorPercent <= 10000, "out of range"); // [5%, 100%]
bondDepletionFloorPercent = _bondDepletionFloorPercent;
}

function setMaxSupplyContractionPercent(uint256 _maxSupplyContractionPercent) external onlyOperator {
require(_maxSupplyContractionPercent >= 100 && _maxSupplyContractionPercent <= 1500, "out of range"); // [0.1%, 15%]
maxSupplyContractionPercent = _maxSupplyContractionPercent;
}

function setMaxDebtRatioPercent(uint256 _maxDebtRatioPercent) external onlyOperator {
require(_maxDebtRatioPercent >= 1000 && _maxDebtRatioPercent <= 10000, "out of range"); // [10%, 100%]
maxDebtRatioPercent = _maxDebtRatioPercent;
}

function setBootstrap(uint256 _bootstrapEpochs, uint256 _bootstrapSupplyExpansionPercent) external onlyOperator {
require(_bootstrapEpochs <= 120, "_bootstrapEpochs: out of range"); // <= 1 month
require(_bootstrapSupplyExpansionPercent >= 100 && _bootstrapSupplyExpansionPercent <= 1000, "_bootstrapSupplyExpansionPercent: out of range"); // [1%, 10%]
bootstrapEpochs = _bootstrapEpochs;
bootstrapSupplyExpansionPercent = _bootstrapSupplyExpansionPercent;
}

function setExtraFunds(
uint256 _daoFundSharedPercent,
uint256 _devFundSharedPercent
) external onlyOperator {
require(_daoFund != address(0), "zero");
require(_daoFundSharedPercent <= 3000, "out of range"); // <= 30%
require(_devFund != address(0), "zero");
require(_devFundSharedPercent <= 1000, "out of range"); // <= 10%
daoFund = _daoFund;
daoFundSharedPercent = _daoFundSharedPercent;
devFund = _devFund;
devFundSharedPercent = _devFundSharedPercent;
}

function setMaxDiscountRate(uint256 _maxDiscountRate) external onlyOperator {
maxDiscountRate = _maxDiscountRate;
}

}

function setDiscountPercent(uint256 _discountPercent) external onlyOperator {
require(_discountPercent <= 20000, "_discountPercent is over 200%");
discountPercent = _discountPercent;
}

require(_premiumThreshold <= 150, "_premiumThreshold is higher than 1.5");
}

require(_premiumPercent <= 20000, "_premiumPercent is over 200%");
}

function setMintingFactorForPayingDebt(uint256 _mintingFactorForPayingDebt) external onlyOperator {
require(_mintingFactorForPayingDebt >= 10000 && _mintingFactorForPayingDebt <= 20000, "_mintingFactorForPayingDebt: out of range"); // [100%, 200%]
mintingFactorForPayingDebt = _mintingFactorForPayingDebt;
}

/* ========== MUTABLE FUNCTIONS ========== */

function _updateAthenaPrice() internal {
try IOracle(athenaOracle).update() {} catch {}
}

function getAthenaCirculatingSupply() public view returns (uint256) {
IERC20 athenaErc20 = IERC20(athena);
uint256 totalSupply = athenaErc20.totalSupply();
uint256 balanceExcluded = 0;
for (uint8 entryId = 0; entryId < excludedFromTotalSupply.length; ++entryId) {
}
}

function buyBonds(uint256 _athenaAmount, uint256 targetPrice) external onlyOneBlock checkCondition checkOperator {
require(_athenaAmount > 0, "Treasury: cannot purchase bonds with zero amount");

uint256 athenaPrice = getAthenaPrice();
require(athenaPrice == targetPrice, "Treasury: ATH price moved");
require(
athenaPrice < athenaPriceOne, // price < \$1
"Treasury: athenaPrice not eligible for bond purchase"
);

require(_athenaAmount <= epochSupplyContractionLeft, "Treasury: not enough bond left to purchase");

uint256 _rate = getBondDiscountRate();
require(_rate > 0, "Treasury: invalid bond rate");

uint256 _bondAmount = _athenaAmount.mul(_rate).div(1e18);
uint256 athenaSupply = getAthenaCirculatingSupply();
uint256 newBondSupply = IERC20(abond).totalSupply().add(_bondAmount);
require(newBondSupply <= athenaSupply.mul(maxDebtRatioPercent).div(10000), "over max debt ratio");

IBasisAsset(athena).burnFrom(msg.sender, _athenaAmount);
IBasisAsset(abond).mint(msg.sender, _bondAmount);

epochSupplyContractionLeft = epochSupplyContractionLeft.sub(_athenaAmount);
_updateAthenaPrice();

emit BoughtBonds(msg.sender, _athenaAmount, _bondAmount);
}

function redeemBonds(uint256 _bondAmount, uint256 targetPrice) external onlyOneBlock checkCondition checkOperator {
require(_bondAmount > 0, "Treasury: cannot redeem bonds with zero amount");

uint256 athenaPrice = getAthenaPrice();
require(athenaPrice == targetPrice, "Treasury: ATH price moved");
require(
athenaPrice > athenaPriceCeiling, // price > \$1.01
"Treasury: athenaPrice not eligible for bond purchase"
);

uint256 _rate = getBondPremiumRate();
require(_rate > 0, "Treasury: invalid bond rate");

uint256 _athenaAmount = _bondAmount.mul(_rate).div(1e18);
require(IERC20(athena).balanceOf(address(this)) >= _athenaAmount, "Treasury: treasury has no more budget");

seigniorageSaved = seigniorageSaved.sub(Math.min(seigniorageSaved, _athenaAmount));

IBasisAsset(abond).burnFrom(msg.sender, _bondAmount);
IERC20(athena).safeTransfer(msg.sender, _athenaAmount);

_updateAthenaPrice();

emit RedeemedBonds(msg.sender, _athenaAmount, _bondAmount);
}

function _sendToMasonry(uint256 _amount) internal {

uint256 _daoFundSharedAmount = 0;
if (daoFundSharedPercent > 0) {
_daoFundSharedAmount = _amount.mul(daoFundSharedPercent).div(10000);
IERC20(athena).transfer(daoFund, _daoFundSharedAmount);
emit DaoFundFunded(block.timestamp, _daoFundSharedAmount);
}

uint256 _devFundSharedAmount = 0;
if (devFundSharedPercent > 0) {
_devFundSharedAmount = _amount.mul(devFundSharedPercent).div(10000);
IERC20(athena).transfer(devFund, _devFundSharedAmount);
emit DevFundFunded(block.timestamp, _devFundSharedAmount);
}

_amount = _amount.sub(_daoFundSharedAmount).sub(_devFundSharedAmount);

IERC20(athena).safeApprove(masonry, 0);
IERC20(athena).safeApprove(masonry, _amount);
IMasonry(masonry).allocateSeigniorage(_amount);
emit MasonryFunded(block.timestamp, _amount);
}

function _calculateMaxSupplyExpansionPercent(uint256 _athenaSupply) internal returns (uint256) {
for (uint8 tierId = 8; tierId >= 0; --tierId) {
if (_athenaSupply >= supplyTiers[tierId]) {
maxSupplyExpansionPercent = maxExpansionTiers[tierId];
break;
}
}
return maxSupplyExpansionPercent;
}

function allocateSeigniorage() external onlyOneBlock checkCondition checkEpoch checkOperator {
_updateAthenaPrice();
previousEpochAthenaPrice = getAthenaPrice();
uint256 athenaSupply = getAthenaCirculatingSupply().sub(seigniorageSaved);
if (epoch < bootstrapEpochs) {
// 28 first epochs with 4.5% expansion
_sendToMasonry(athenaSupply.mul(bootstrapSupplyExpansionPercent).div(10000));
} else {
if (previousEpochAthenaPrice > athenaPriceCeiling) {
// Expansion (\$ATH Price > 1 \$FTM): there is some seigniorage to be allocated
uint256 bondSupply = IERC20(abond).totalSupply();
uint256 _percentage = previousEpochAthenaPrice.sub(athenaPriceOne);
uint256 _savedForBond;
uint256 _savedForMasonry;
uint256 _mse = _calculateMaxSupplyExpansionPercent(athenaSupply).mul(1e14);
if (_percentage > _mse) {
_percentage = _mse;
}
if (seigniorageSaved >= bondSupply.mul(bondDepletionFloorPercent).div(10000)) {
// saved enough to pay debt, mint as usual rate
_savedForMasonry = athenaSupply.mul(_percentage).div(1e18);
} else {
// have not saved enough to pay debt, mint more
uint256 _seigniorage = athenaSupply.mul(_percentage).div(1e18);
_savedForMasonry = _seigniorage.mul(seigniorageExpansionFloorPercent).div(10000);
_savedForBond = _seigniorage.sub(_savedForMasonry);
if (mintingFactorForPayingDebt > 0) {
_savedForBond = _savedForBond.mul(mintingFactorForPayingDebt).div(10000);
}
}
if (_savedForMasonry > 0) {
_sendToMasonry(_savedForMasonry);
}
if (_savedForBond > 0) {
emit TreasuryFunded(block.timestamp, _savedForBond);
}
}
}
}

function governanceRecoverUnsupported(
IERC20 _token,
uint256 _amount,
) external onlyOperator {
// do not allow to drain core tokens
_token.safeTransfer(_to, _amount);
}

function masonrySetOperator(address _operator) external onlyOperator {
IMasonry(masonry).setOperator(_operator);
}

function masonrySetLockUp(uint256 _withdrawLockupEpochs, uint256 _rewardLockupEpochs) external onlyOperator {
IMasonry(masonry).setLockUp(_withdrawLockupEpochs, _rewardLockupEpochs);
}

function masonryAllocateSeigniorage(uint256 amount) external onlyOperator {
IMasonry(masonry).allocateSeigniorage(amount);
}

function masonryGovernanceRecoverUnsupported(
uint256 _amount,
) external onlyOperator {
IMasonry(masonry).governanceRecoverUnsupported(_token, _amount, _to);
}
}
``````

### Contract ABI

````[{"type":"event","name":"BoughtBonds","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"uint256","name":"athenaAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"bondAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BurnedBonds","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"uint256","name":"bondAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DaoFundFunded","inputs":[{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"seigniorage","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DevFundFunded","inputs":[{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"seigniorage","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"address","name":"executor","internalType":"address","indexed":true},{"type":"uint256","name":"at","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MasonryFunded","inputs":[{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"seigniorage","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RedeemedBonds","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"uint256","name":"athenaAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"bondAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TreasuryFunded","inputs":[{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"seigniorage","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"PERIOD","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"abond","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"allocateSeigniorage","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"ashare","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"athena","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"athenaOracle","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"athenaPriceCeiling","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"athenaPriceOne","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"bondDepletionFloorPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"bootstrapEpochs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"bootstrapSupplyExpansionPercent","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"buyBonds","inputs":[{"type":"uint256","name":"_athenaAmount","internalType":"uint256"},{"type":"uint256","name":"targetPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"daoFund","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"daoFundSharedPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"devFund","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"devFundSharedPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"discountPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"epoch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"epochSupplyContractionLeft","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"excludedFromTotalSupply","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAthenaCirculatingSupply","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"athenaPrice","internalType":"uint256"}],"name":"getAthenaPrice","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_athenaPrice","internalType":"uint256"}],"name":"getAthenaUpdatedPrice","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_rate","internalType":"uint256"}],"name":"getBondDiscountRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_rate","internalType":"uint256"}],"name":"getBondPremiumRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_burnableAthenaLeft","internalType":"uint256"}],"name":"getBurnableAthenaLeft","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_redeemableBonds","internalType":"uint256"}],"name":"getRedeemableBonds","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getReserve","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"governanceRecoverUnsupported","inputs":[{"type":"address","name":"_token","internalType":"contract IERC20"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"address","name":"_to","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_athena","internalType":"address"},{"type":"address","name":"_abond","internalType":"address"},{"type":"address","name":"_ashare","internalType":"address"},{"type":"address","name":"_athenaOracle","internalType":"address"},{"type":"address","name":"_masonry","internalType":"address"},{"type":"uint256","name":"_startTime","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"initialized","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isInitialized","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"masonry","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"masonryAllocateSeigniorage","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"masonryGovernanceRecoverUnsupported","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"address","name":"_to","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"masonrySetLockUp","inputs":[{"type":"uint256","name":"_withdrawLockupEpochs","internalType":"uint256"},{"type":"uint256","name":"_rewardLockupEpochs","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"masonrySetOperator","inputs":[{"type":"address","name":"_operator","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxDebtRatioPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxDiscountRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxExpansionTiers","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxPremiumRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxSupplyContractionPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxSupplyExpansionPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"mintingFactorForPayingDebt","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nextEpochPoint","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"operator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"premiumPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"premiumThreshold","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"previousEpochAthenaPrice","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"redeemBonds","inputs":[{"type":"uint256","name":"_bondAmount","internalType":"uint256"},{"type":"uint256","name":"targetPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"seigniorageExpansionFloorPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"seigniorageSaved","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAthenaOracle","inputs":[{"type":"address","name":"_athenaOracle","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAthenaPriceCeiling","inputs":[{"type":"uint256","name":"_athenaPriceCeiling","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBondDepletionFloorPercent","inputs":[{"type":"uint256","name":"_bondDepletionFloorPercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBootstrap","inputs":[{"type":"uint256","name":"_bootstrapEpochs","internalType":"uint256"},{"type":"uint256","name":"_bootstrapSupplyExpansionPercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDiscountPercent","inputs":[{"type":"uint256","name":"_discountPercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setExtraFunds","inputs":[{"type":"address","name":"_daoFund","internalType":"address"},{"type":"uint256","name":"_daoFundSharedPercent","internalType":"uint256"},{"type":"address","name":"_devFund","internalType":"address"},{"type":"uint256","name":"_devFundSharedPercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMasonry","inputs":[{"type":"address","name":"_masonry","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxDebtRatioPercent","inputs":[{"type":"uint256","name":"_maxDebtRatioPercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxDiscountRate","inputs":[{"type":"uint256","name":"_maxDiscountRate","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"setMaxExpansionTiersEntry","inputs":[{"type":"uint8","name":"_index","internalType":"uint8"},{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxPremiumRate","inputs":[{"type":"uint256","name":"_maxPremiumRate","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxSupplyContractionPercent","inputs":[{"type":"uint256","name":"_maxSupplyContractionPercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxSupplyExpansionPercents","inputs":[{"type":"uint256","name":"_maxSupplyExpansionPercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMintingFactorForPayingDebt","inputs":[{"type":"uint256","name":"_mintingFactorForPayingDebt","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOperator","inputs":[{"type":"address","name":"_operator","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPremiumPercent","inputs":[{"type":"uint256","name":"_premiumPercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPremiumThreshold","inputs":[{"type":"uint256","name":"_premiumThreshold","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"setSupplyTiersEntry","inputs":[{"type":"uint8","name":"_index","internalType":"uint8"},{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"startTime","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"supplyTiers","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]}]`
```

### Deployed ByteCode

``0x608060405234801561001057600080fd5b50600436106104285760003560e01c806381a7235f1161022b578063b8a878f911610130578063cecce38e116100b8578063da3ed41911610087578063da3ed41914610837578063e1e19f5d14610840578063e90b245414610853578063f14698de1461085c578063fcb6f0081461086557600080fd5b8063cecce38e146107f5578063d4b1494414610808578063d5d3b26c1461081b578063d98f24951461082e57600080fd5b8063c5967c26116100ff578063c5967c26146107c0578063c8412d02146107c8578063c86db2ad146107d1578063c8f987f3146107d9578063cc722c97146107e257600080fd5b8063b8a878f91461077e578063bcc81f1914610787578063be266d541461079a578063c48c4443146107ad57600080fd5b8063940e6064116101b357806399820025116101825780639982002514610729578063a0487eea1461073c578063a204452b1461074f578063b3ab15fb14610762578063b4d1d7951461077557600080fd5b8063940e6064146106dd578063951357d4146106f057806395b6ef0c1461070357806398b762a11461071657600080fd5b8063874106cc116101fa578063874106cc146106925780638c664db61461069b5780638d934f74146106ae578063900cf0cf146106c157806391bbfed5146106ca57600080fd5b806381a7235f1461065b57806381d11eaf1461066e5780638206784e1461067757806382cad8381461067f57600080fd5b8063499f3f19116103315780635a0fc79c116102b957806363f96cf41161028857806363f96cf41461061c57806372c054f91461062f578063734f70961461063757806378e979251461064a5780638166ee371461065357600080fd5b80635a0fc79c146105e55780635b756179146105ee5780635be25f67146105f657806362ac58e41461060957600080fd5b806355ebdeef1161030057806355ebdeef146105a5578063570ca735146105ae578063583863e9146105c1578063591663e1146105ca57806359bf5d39146105dd57600080fd5b8063499f3f191461055957806350d7ede21461056c57806354575af41461057f57806354f04a111461059257600080fd5b806322f832cd116103b4578063392e53cd11610383578063392e53cd146104f85780634008b2661461050a5780634013a08e1461051257806340af7ba51461051b5780634390d2a81461052e57600080fd5b806322f832cd146104d457806329ef1919146104dd5780632e9c7b65146104e65780633383a293146104ef57600080fd5b80630db7eb0b116103fb5780630db7eb0b14610479578063118ebbf914610481578063154ec2db14610494578063158ef93e146104a7578063227eb2bc146104cb57600080fd5b806303be7e761461042d57806304e5c7b1146104495780630b5bcec71461045e5780630cf6017514610471575b600080fd5b61043660215481565b6040519081526020015b60405180910390f35b61045c610457366004613d14565b61086e565b005b61045c61046c366004613d14565b61096a565b610436610a09565b610436610ab9565b61045c61048f366004613d44565b610b59565b61045c6104a2366004613d14565b611182565b6001546104bb90600160a01b900460ff1681565b6040519015158152602001610440565b610436600c5481565b61043660125481565b610436601a5481565b61043660195481565b610436600b5481565b600154600160a01b900460ff166104bb565b610436611203565b610436601d5481565b61045c610529366004613d14565b611316565b602054610541906001600160a01b031681565b6040516001600160a01b039091168152602001610440565b61045c610567366004613d14565b611397565b600754610541906001600160a01b031681565b61045c61058d366004613c45565b611438565b61045c6105a0366004613d44565b61154f565b610436601f5481565b600154610541906001600160a01b031681565b61043660175481565b61045c6105d8366004613d14565b611c69565b600d54610436565b610436600d5481565b61045c611cc8565b61045c610604366004613b95565b61233e565b61045c610617366004613b95565b61238a565b600954610541906001600160a01b031681565b610436612417565b61045c610645366004613d44565b6124dc565b61043660025481565b61043661256f565b61045c610669366004613d14565b6126e0565b61043660115481565b610436612757565b61054161068d366004613d14565b612859565b61043660165481565b61045c6106a9366004613d14565b612883565b601e54610541906001600160a01b031681565b61043660035481565b61045c6106d8366004613d44565b6128e2565b6104bb6106eb366004613d65565b6129de565b61045c6106fe366004613c45565b612b05565b61045c610711366004613bcd565b612ba2565b61045c610724366004613d14565b612e7b565b610436610737366004613d14565b612eaa565b61043661074a366004613d14565b612ecb565b61045c61075d366004613d14565b612edb565b61045c610770366004613b95565b612f0a565b61043661546081565b61043660185481565b61045c610795366004613c86565b612f56565b61045c6107a8366004613d14565b61307a565b600a54610541906001600160a01b031681565b6104366130d5565b610436601c5481565b6104366130ff565b610436601b5481565b600654610541906001600160a01b031681565b61045c610803366004613d14565b613141565b6104bb610816366004613d65565b61319f565b61045c610829366004613b95565b61326a565b61043660105481565b61043660145481565b600854610541906001600160a01b031681565b61043660135481565b61043660155481565b61043660045481565b6001546001600160a01b031633146108a15760405162461bcd60e51b815260040161089890613ef7565b60405180910390fd5b600c548110156109085760405162461bcd60e51b815260206004820152602c60248201527f5f7072656d69756d5468726573686f6c64206578636565647320617468656e6160448201526b50726963654365696c696e6760a01b6064820152608401610898565b60968111156109655760405162461bcd60e51b8152602060048201526024808201527f5f7072656d69756d5468726573686f6c6420697320686967686572207468616e60448201526320312e3560e01b6064820152608401610898565b601b55565b6001546001600160a01b031633146109945760405162461bcd60e51b815260040161089890613ef7565b600a81101580156109a757506103e88111155b610a045760405162461bcd60e51b815260206004820152602860248201527f5f6d6178537570706c79457870616e73696f6e50657263656e743a206f7574206044820152676f662072616e676560c01b6064820152608401610898565b601055565b600080610a14612757565b9050600b548111610ab557601a54610a2e575050600b5490565b6000610a5782610a51670de0b6b3a7640000600b546132b690919063ffffffff16565b906132c9565b90506000610a82612710610a51601a54610a7c600b54876132d590919063ffffffff16565b906132b6565b600b54909150610a9290826132e1565b93506000601854118015610aa7575060185484115b15610ab25760185493505b50505b5090565b600080610ac4612757565b9050600c54811115610ab5576000610aee6064610a51601b54600b546132b690919063ffffffff16565b9050808210610b4f576000610b1a612710610a51601c54610a7c600b54886132d590919063ffffffff16565b600b54909150610b2a90826132e1565b93506000601954118015610b3f575060195484115b15610ab257601954935050505090565b600b549250505090565b4360009081526020818152604080832032845290915290205460ff1615610b925760405162461bcd60e51b815260040161089890613f3b565b4360009081526020818152604080832033845290915290205460ff1615610bcb5760405162461bcd60e51b815260040161089890613f3b565b600254421015610bed5760405162461bcd60e51b815260040161089890613f81565b6006546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b158015610c3157600080fd5b505afa158015610c45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c699190613bb1565b6001600160a01b0316148015610d0157506007546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b158015610cbe57600080fd5b505afa158015610cd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf69190613bb1565b6001600160a01b0316145b8015610d8f57506008546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b158015610d4c57600080fd5b505afa158015610d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d849190613bb1565b6001600160a01b0316145b8015610e1d57506009546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b158015610dda57600080fd5b505afa158015610dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e129190613bb1565b6001600160a01b0316145b610e395760405162461bcd60e51b815260040161089890613e51565b60008211610ea05760405162461bcd60e51b815260206004820152602e60248201527f54726561737572793a2063616e6e6f742072656465656d20626f6e647320776960448201526d1d1a081e995c9bc8185b5bdd5b9d60921b6064820152608401610898565b6000610eaa612757565b9050818114610ef75760405162461bcd60e51b8152602060048201526019602482015278151c99585cdd5c9e4e88105512081c1c9a58d9481b5bdd9959603a1b6044820152606401610898565b600c548111610f185760405162461bcd60e51b815260040161089890613dfd565b6000610f22610ab9565b905060008111610f745760405162461bcd60e51b815260206004820152601b60248201527f54726561737572793a20696e76616c696420626f6e64207261746500000000006044820152606401610898565b6000610f8c670de0b6b3a7640000610a5187856132b6565b6006546040516370a0823160e01b815230600482015291925082916001600160a01b03909116906370a082319060240160206040518083038186803b158015610fd457600080fd5b505afa158015610fe8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100c9190613d2c565b10156110685760405162461bcd60e51b815260206004820152602560248201527f54726561737572793a20747265617375727920686173206e6f206d6f726520626044820152641d5919d95d60da1b6064820152608401610898565b611080611077600d54836132ed565b600d54906132d5565b600d5560075460405163079cc67960e41b81526001600160a01b03909116906379cc6790906110b59033908990600401613db1565b600060405180830381600087803b1580156110cf57600080fd5b505af11580156110e3573d6000803e3d6000fd5b50506006546110ff92506001600160a01b031690503383613303565b611107613359565b604080518281526020810187905233917f51e0d16595cabc591e64da08e45bb223577e5b9a39cd947b4ddc3472b2dd8878910160405180910390a25050436000908152602081815260408083203284529091528082208054600160ff1991821681179092553384529190922080549091169091179055505050565b6001546001600160a01b031633146111ac5760405162461bcd60e51b815260040161089890613ef7565b614e208111156111fe5760405162461bcd60e51b815260206004820152601d60248201527f5f646973636f756e7450657263656e74206973206f76657220323030250000006044820152606401610898565b601a55565b60008061120e612757565b9050600b548111610ab557600061122361256f565b90506000611242612710610a51601454856132b690919063ffffffff16565b90506000600760009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561129457600080fd5b505afa1580156112a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cc9190613d2c565b90508082111561130f5760006112e283836132d5565b905060006112fc670de0b6b3a7640000610a5184896132b6565b905061130a600454826132ed565b965050505b5050505090565b6001546001600160a01b031633146113405760405162461bcd60e51b815260040161089890613ef7565b614e208111156113925760405162461bcd60e51b815260206004820152601c60248201527f5f7072656d69756d50657263656e74206973206f7665722032303025000000006044820152606401610898565b601c55565b6001546001600160a01b031633146113c15760405162461bcd60e51b815260040161089890613ef7565b61271081101580156113d55750614e208111155b6114335760405162461bcd60e51b815260206004820152602960248201527f5f6d696e74696e67466163746f72466f72506179696e67446562743a206f7574604482015268206f662072616e676560b81b6064820152608401610898565b601d55565b6001546001600160a01b031633146114625760405162461bcd60e51b815260040161089890613ef7565b6006546001600160a01b03848116911614156114a95760405162461bcd60e51b8152602060048201526006602482015265617468656e6160d01b6044820152606401610898565b6007546001600160a01b03848116911614156114f05760405162461bcd60e51b815260040161089890602080825260049082015263189bdb9960e21b604082015260600190565b6008546001600160a01b03848116911614156115365760405162461bcd60e51b8152602060048201526005602482015264736861726560d81b6044820152606401610898565b61154a6001600160a01b0384168284613303565b505050565b4360009081526020818152604080832032845290915290205460ff16156115885760405162461bcd60e51b815260040161089890613f3b565b4360009081526020818152604080832033845290915290205460ff16156115c15760405162461bcd60e51b815260040161089890613f3b565b6002544210156115e35760405162461bcd60e51b815260040161089890613f81565b6006546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b15801561162757600080fd5b505afa15801561163b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165f9190613bb1565b6001600160a01b03161480156116f757506007546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b1580156116b457600080fd5b505afa1580156116c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ec9190613bb1565b6001600160a01b0316145b801561178557506008546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b15801561174257600080fd5b505afa158015611756573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177a9190613bb1565b6001600160a01b0316145b801561181357506009546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b1580156117d057600080fd5b505afa1580156117e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118089190613bb1565b6001600160a01b0316145b61182f5760405162461bcd60e51b815260040161089890613e51565b600082116118985760405162461bcd60e51b815260206004820152603060248201527f54726561737572793a2063616e6e6f7420707572636861736520626f6e64732060448201526f1dda5d1a081e995c9bc8185b5bdd5b9d60821b6064820152608401610898565b60006118a2612757565b90508181146118ef5760405162461bcd60e51b8152602060048201526019602482015278151c99585cdd5c9e4e88105512081c1c9a58d9481b5bdd9959603a1b6044820152606401610898565b600b5481106119105760405162461bcd60e51b815260040161089890613dfd565b6004548311156119755760405162461bcd60e51b815260206004820152602a60248201527f54726561737572793a206e6f7420656e6f75676820626f6e64206c65667420746044820152696f20707572636861736560b01b6064820152608401610898565b600061197f610a09565b9050600081116119d15760405162461bcd60e51b815260206004820152601b60248201527f54726561737572793a20696e76616c696420626f6e64207261746500000000006044820152606401610898565b60006119e9670de0b6b3a7640000610a5187856132b6565b905060006119f561256f565b90506000611a8983600760009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a4b57600080fd5b505afa158015611a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a839190613d2c565b906132e1565b9050611aa6612710610a51601454856132b690919063ffffffff16565b811115611aeb5760405162461bcd60e51b81526020600482015260136024820152726f766572206d6178206465627420726174696f60681b6044820152606401610898565b60065460405163079cc67960e41b81526001600160a01b03909116906379cc679090611b1d9033908b90600401613db1565b600060405180830381600087803b158015611b3757600080fd5b505af1158015611b4b573d6000803e3d6000fd5b50506007546040516340c10f1960e01b81526001600160a01b0390911692506340c10f199150611b819033908790600401613db1565b602060405180830381600087803b158015611b9b57600080fd5b505af1158015611baf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd39190613ccd565b50600454611be190886132d5565b600455611bec613359565b604080518881526020810185905233917f73017f1b70789e2e66759eeb3c7ec11f59e6eedb55d921cfaec5410dd42a4799910160405180910390a25050436000908152602081815260408083203284529091528082208054600160ff19918216811790925533845291909220805490911690911790555050505050565b6001546001600160a01b03163314611c935760405162461bcd60e51b815260040161089890613ef7565b6103e88110158015611ca757506127108111155b611cc35760405162461bcd60e51b815260040161089890613e88565b601455565b4360009081526020818152604080832032845290915290205460ff1615611d015760405162461bcd60e51b815260040161089890613f3b565b4360009081526020818152604080832033845290915290205460ff1615611d3a5760405162461bcd60e51b815260040161089890613f3b565b600254421015611d5c5760405162461bcd60e51b815260040161089890613f81565b611d646130d5565b421015611db35760405162461bcd60e51b815260206004820152601860248201527f54726561737572793a206e6f74206f70656e65642079657400000000000000006044820152606401610898565b6006546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b158015611df757600080fd5b505afa158015611e0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2f9190613bb1565b6001600160a01b0316148015611ec757506007546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b158015611e8457600080fd5b505afa158015611e98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebc9190613bb1565b6001600160a01b0316145b8015611f5557506008546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b158015611f1257600080fd5b505afa158015611f26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4a9190613bb1565b6001600160a01b0316145b8015611fe357506009546040805163570ca73560e01b8152905130926001600160a01b03169163570ca735916004808301926020929190829003018186803b158015611fa057600080fd5b505afa158015611fb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd89190613bb1565b6001600160a01b0316145b611fff5760405162461bcd60e51b815260040161089890613e51565b612007613359565b61200f612757565b601755600d5460009061202a9061202461256f565b906132d5565b905060155460035410156120605761205b612056612710610a51601654856132b690919063ffffffff16565b6133bd565b6122c2565b600c5460175411156122c257600754604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156120b157600080fd5b505afa1580156120c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e99190613d2c565b90506000612104600b546017546132d590919063ffffffff16565b9050600080600061211e655af3107a4000610a7c88613701565b90508084111561212c578093505b612147612710610a51601154886132b690919063ffffffff16565b600d541061216c57612165670de0b6b3a7640000610a5188876132b6565b91506121d8565b6000612184670de0b6b3a7640000610a5189886132b6565b90506121a1612710610a51601254846132b690919063ffffffff16565b92506121ad81846132d5565b601d54909450156121d6576121d3612710610a51601d54876132b690919063ffffffff16565b93505b505b81156121e7576121e7826133bd565b82156122bc57600d546121fa90846132e1565b600d556006546040516340c10f1960e01b81526001600160a01b03909116906340c10f199061222f9030908790600401613db1565b602060405180830381600087803b15801561224957600080fd5b505af115801561225d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122819190613ccd565b5060408051428152602081018590527ff705142bf09f04297640495ddf7c59b7fd6f51894c5aea9602d631cf05f0efc2910160405180910390a15b50505050505b506003546122d19060016132e1565b600355600c546122df612757565b116122fd576122f8612710610a51601354610a7c61256f565b612300565b60005b600455436000908152602081815260408083203284529091528082208054600160ff1991821681179092553384529190922080549091169091179055565b6001546001600160a01b031633146123685760405162461bcd60e51b815260040161089890613ef7565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031633146123b45760405162461bcd60e51b815260040161089890613ef7565b60095460405163b3ab15fb60e01b81526001600160a01b0383811660048301529091169063b3ab15fb906024015b600060405180830381600087803b1580156123fc57600080fd5b505af1158015612410573d6000803e3d6000fd5b5050505050565b600080612422612757565b9050600c54811115610ab5576006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561247257600080fd5b505afa158015612486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124aa9190613d2c565b905060006124b6610ab9565b90508015610ab2576124d481610a5184670de0b6b3a76400006132b6565b935050505090565b6001546001600160a01b031633146125065760405162461bcd60e51b815260040161089890613ef7565b600954604051632ffaaa0960e01b815260048101849052602481018390526001600160a01b0390911690632ffaaa0990604401600060405180830381600087803b15801561255357600080fd5b505af1158015612567573d6000803e3d6000fd5b505050505050565b600654604080516318160ddd60e01b815290516000926001600160a01b031691839183916318160ddd916004808301926020929190829003018186803b1580156125b857600080fd5b505afa1580156125cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125f09190613d2c565b90506000805b60055460ff821610156126d5576126c3846001600160a01b03166370a0823160058460ff168154811061263957634e487b7160e01b600052603260045260246000fd5b60009182526020909120015460405160e083901b6001600160e01b03191681526001600160a01b03909116600482015260240160206040518083038186803b15801561268457600080fd5b505afa158015612698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126bc9190613d2c565b83906132e1565b91506126ce816140bb565b90506125f6565b506124d482826132d5565b6001546001600160a01b0316331461270a5760405162461bcd60e51b815260040161089890613ef7565b600b54811015801561273657506127326064610a516078600b546132b690919063ffffffff16565b8111155b6127525760405162461bcd60e51b815260040161089890613e88565b600c55565b600a54600654604051633ddac95360e01b81526000926001600160a01b0390811692633ddac953926127999290911690670de0b6b3a764000090600401613db1565b60206040518083038186803b1580156127b157600080fd5b505afa9250505080156127e1575060408051601f3d908101601f191682019092526127de91810190613ced565b60015b61284b5760405162461bcd60e51b815260206004820152603560248201527f54726561737572793a206661696c656420746f20636f6e73756c74204154482060448201527470726963652066726f6d20746865206f7261636c6560581b6064820152608401610898565b6001600160901b0316919050565b6005818154811061286957600080fd5b6000918252602090912001546001600160a01b0316905081565b6001546001600160a01b031633146128ad5760405162461bcd60e51b815260040161089890613ef7565b6101f481101580156128c157506127108111155b6128dd5760405162461bcd60e51b815260040161089890613e88565b601155565b6001546001600160a01b0316331461290c5760405162461bcd60e51b815260040161089890613ef7565b607882111561295d5760405162461bcd60e51b815260206004820152601e60248201527f5f626f6f74737472617045706f6368733a206f7574206f662072616e676500006044820152606401610898565b6064811015801561297057506103e88111155b6129d35760405162461bcd60e51b815260206004820152602e60248201527f5f626f6f747374726170537570706c79457870616e73696f6e50657263656e7460448201526d3a206f7574206f662072616e676560901b6064820152608401610898565b601591909155601655565b6001546000906001600160a01b03163314612a0b5760405162461bcd60e51b815260040161089890613ef7565b60098360ff1610612a2e5760405162461bcd60e51b815260040161089890613eae565b60ff831615612a7b57600e612a4460018561404b565b60ff1681548110612a6557634e487b7160e01b600052603260045260246000fd5b90600052602060002001548211612a7b57600080fd5b60088360ff161015612acb57600e612a94846001613fd0565b60ff1681548110612ab557634e487b7160e01b600052603260045260246000fd5b90600052602060002001548210612acb57600080fd5b81600e8460ff1681548110612af057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015550600192915050565b6001546001600160a01b03163314612b2f5760405162461bcd60e51b815260040161089890613ef7565b600954604051631515d6bd60e21b81526001600160a01b038581166004830152602482018590528381166044830152909116906354575af490606401600060405180830381600087803b158015612b8557600080fd5b505af1158015612b99573d6000803e3d6000fd5b50505050505050565b600154600160a01b900460ff1615612bfc5760405162461bcd60e51b815260206004820152601d60248201527f54726561737572793a20616c726561647920696e697469616c697a65640000006044820152606401610898565b600680546001600160a01b03199081166001600160a01b0389811691909117909255600780548216888416179055600880548216878416179055600a80548216868416179055600980549091169184169190911790556002819055670de0b6b3a7640000600b819055612c7790606490610a519060656132b6565b600c55604080516101208101825260008152681b1ae4d6e2ef5000006020820152683635c9adc5dea0000091810191909152685150ae84a8cdf000006060820152686c6b935b8bbd400000608082015269010f0cf064dd5920000060a082015269021e19e0c9bab240000060c082015269043c33c193756480000060e0820152690a968163f0a57b400000610100820152612d1690600e906009613aea565b5060408051610120810182526101c28152610190602082015261015e9181019190915261012c606082015260fa608082015260c860a0820152609660c0820152607d60e08201526064610100820152612d7390600f906009613b3f565b50610190601055612710601155610dac601281905561012c601355601455606e601b55611b58601c9081556015556101c26016556006546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015612dea57600080fd5b505afa158015612dfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e229190613d2c565b600d55600180546001600160a81b03191633908117600160a01b179091556040514381527f25ff68dd81b34665b5ba7e553ee5511bf6812e12adb4a7e2c0d9e26b3099ce799060200160405180910390a2505050505050565b6001546001600160a01b03163314612ea55760405162461bcd60e51b815260040161089890613ef7565b601855565b600e8181548110612eba57600080fd5b600091825260209091200154905081565b600f8181548110612eba57600080fd5b6001546001600160a01b03163314612f055760405162461bcd60e51b815260040161089890613ef7565b601955565b6001546001600160a01b03163314612f345760405162461bcd60e51b815260040161089890613ef7565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b03163314612f805760405162461bcd60e51b815260040161089890613ef7565b6001600160a01b038416612fbf5760405162461bcd60e51b8152600401610898906020808252600490820152637a65726f60e01b604082015260600190565b610bb8831115612fe15760405162461bcd60e51b815260040161089890613e88565b6001600160a01b0382166130205760405162461bcd60e51b8152600401610898906020808252600490820152637a65726f60e01b604082015260600190565b6103e88111156130425760405162461bcd60e51b815260040161089890613e88565b601e80546001600160a01b03199081166001600160a01b0396871617909155601f939093556020805490931691909316179055602155565b6001546001600160a01b031633146130a45760405162461bcd60e51b815260040161089890613ef7565b6009546040516397ffe1d760e01b8152600481018390526001600160a01b03909116906397ffe1d7906024016123e2565b60006130fa6130f16154606003546132b690919063ffffffff16565b600254906132e1565b905090565b600a54600654604051630d01142560e31b81526000926001600160a01b0390811692636808a128926127999290911690670de0b6b3a764000090600401613db1565b6001546001600160a01b0316331461316b5760405162461bcd60e51b815260040161089890613ef7565b6064811015801561317e57506105dc8111155b61319a5760405162461bcd60e51b815260040161089890613e88565b601355565b6001546000906001600160a01b031633146131cc5760405162461bcd60e51b815260040161089890613ef7565b60098360ff16106131ef5760405162461bcd60e51b815260040161089890613eae565b600a821015801561320257506103e88211155b6132455760405162461bcd60e51b81526020600482015260146024820152735f76616c75653a206f7574206f662072616e676560601b6044820152606401610898565b81600f8460ff1681548110612af057634e487b7160e01b600052603260045260246000fd5b6001546001600160a01b031633146132945760405162461bcd60e51b815260040161089890613ef7565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b60006132c28284614015565b9392505050565b60006132c28284613ff5565b60006132c28284614034565b60006132c28284613fb8565b60008183106132fc57816132c2565b5090919050565b61154a8363a9059cbb60e01b8484604051602401613322929190613db1565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261378d565b600a60009054906101000a90046001600160a01b03166001600160a01b031663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156133a957600080fd5b505af19250505080156133ba575060015b50565b6006546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906133ef9030908590600401613db1565b602060405180830381600087803b15801561340957600080fd5b505af115801561341d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134419190613ccd565b50601f546000901561352d57613468612710610a51601f54856132b690919063ffffffff16565b600654601e5460405163a9059cbb60e01b81529293506001600160a01b039182169263a9059cbb926134a09216908590600401613db1565b602060405180830381600087803b1580156134ba57600080fd5b505af11580156134ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134f29190613ccd565b5060408051428152602081018390527fcb3f34aaa3445b461e6da5492dc89e5c257a59fa598131f3b6bbc97a3638e409910160405180910390a15b6021546000901561361857613553612710610a51602154866132b690919063ffffffff16565b60065460205460405163a9059cbb60e01b81529293506001600160a01b039182169263a9059cbb9261358b9216908590600401613db1565b602060405180830381600087803b1580156135a557600080fd5b505af11580156135b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135dd9190613ccd565b5060408051428152602081018390527fdc8b715b18523e58b7fd0da53259dfa91efd91df4a854d94b136e3333a3b9395910160405180910390a15b6136268161202485856132d5565b600954600654919450613647916001600160a01b039081169116600061385f565b600954600654613664916001600160a01b0391821691168561385f565b6009546040516397ffe1d760e01b8152600481018590526001600160a01b03909116906397ffe1d790602401600060405180830381600087803b1580156136aa57600080fd5b505af11580156136be573d6000803e3d6000fd5b505060408051428152602081018790527fa72fa2f263b243b0f0e1fec5f3d49d33de573d15929b6b730c6b8ab3838c1c4d935001905060405180910390a1505050565b600060085b600e8160ff168154811061372a57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154831061377357600f8160ff168154811061375f57634e487b7160e01b600052603260045260246000fd5b600091825260209091200154601055613783565b61377c8161409e565b9050613706565b5050601054919050565b60006137e2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139729092919063ffffffff16565b80519091501561154a57808060200190518101906138009190613ccd565b61154a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610898565b8015806138e85750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b1580156138ae57600080fd5b505afa1580156138c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138e69190613d2c565b155b6139535760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610898565b61154a8363095ea7b360e01b8484604051602401613322929190613db1565b60606139818484600085613989565b949350505050565b6060824710156139ea5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610898565b843b613a385760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610898565b600080866001600160a01b03168587604051613a549190613d95565b60006040518083038185875af1925050503d8060008114613a91576040519150601f19603f3d011682016040523d82523d6000602084013e613a96565b606091505b5091509150613aa6828286613ab1565b979650505050505050565b60608315613ac05750816132c2565b825115613ad05782518084602001fd5b8160405162461bcd60e51b81526004016108989190613dca565b828054828255906000526020600020908101928215613b33579160200282015b82811115613b33578251829069ffffffffffffffffffff16905591602001919060010190613b0a565b50610ab5929150613b80565b828054828255906000526020600020908101928215613b33579160200282015b82811115613b33578251829061ffff16905591602001919060010190613b5f565b5b80821115610ab55760008155600101613b81565b600060208284031215613ba6578081fd5b81356132c2816140f1565b600060208284031215613bc2578081fd5b81516132c2816140f1565b60008060008060008060c08789031215613be5578182fd5b8635613bf0816140f1565b95506020870135613c00816140f1565b94506040870135613c10816140f1565b93506060870135613c20816140f1565b92506080870135613c30816140f1565b8092505060a087013590509295509295509295565b600080600060608486031215613c59578283fd5b8335613c64816140f1565b9250602084013591506040840135613c7b816140f1565b809150509250925092565b60008060008060808587031215613c9b578384fd5b8435613ca6816140f1565b9350602085013592506040850135613cbd816140f1565b9396929550929360600135925050565b600060208284031215613cde578081fd5b815180151581146132c2578182fd5b600060208284031215613cfe578081fd5b81516001600160901b03811681146132c2578182fd5b600060208284031215613d25578081fd5b5035919050565b600060208284031215613d3d578081fd5b5051919050565b60008060408385031215613d56578182fd5b50508035926020909101359150565b60008060408385031215613d77578182fd5b823560ff81168114613d87578283fd5b946020939093013593505050565b60008251613da781846020870161406e565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020815260008251806020840152613de981604085016020870161406e565b601f01601f19169190910160400192915050565b60208082526034908201527f54726561737572793a20617468656e615072696365206e6f7420656c696769626040820152736c6520666f7220626f6e6420707572636861736560601b606082015260800190565b6020808252601e908201527f54726561737572793a206e656564206d6f7265207065726d697373696f6e0000604082015260600190565b6020808252600c908201526b6f7574206f662072616e676560a01b604082015260600190565b60208082526029908201527f496e6465782068617320746f206265206c6f776572207468616e20636f756e74604082015268206f6620746965727360b81b606082015260800190565b60208082526024908201527f54726561737572793a2063616c6c6572206973206e6f7420746865206f70657260408201526330ba37b960e11b606082015260800190565b60208082526026908201527f436f6e747261637447756172643a206f6e6520626c6f636b2c206f6e652066756040820152653731ba34b7b760d11b606082015260800190565b60208082526019908201527f54726561737572793a206e6f7420737461727465642079657400000000000000604082015260600190565b60008219821115613fcb57613fcb6140db565b500190565b600060ff821660ff84168060ff03821115613fed57613fed6140db565b019392505050565b60008261401057634e487b7160e01b81526012600452602481fd5b500490565b600081600019048311821515161561402f5761402f6140db565b500290565b600082821015614046576140466140db565b500390565b600060ff821660ff841680821015614065576140656140db565b90039392505050565b60005b83811015614089578181015183820152602001614071565b83811115614098576000848401525b50505050565b600060ff8216806140b1576140b16140db565b6000190192915050565b600060ff821660ff8114156140d2576140d26140db565b60010192915050565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b03811681146133ba57600080fdfea26469706673582212207b8b7d8f40dad85da0eb59c01cfa897bd7ae9b098b52b42f3cff43e40a54d40864736f6c63430008040033``