ETH Price: $2,499.76 (-1.02%)

Contract

0x2a2273Dc6857bE5043b328eB3c1dC87680e830bB
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw By Posi...206229582024-08-27 22:37:594 days ago1724798279IN
0x2a2273Dc...680e830bB
0 ETH0.0032939510
Deposit To Posit...205916092024-08-23 13:30:478 days ago1724419847IN
0x2a2273Dc...680e830bB
0 ETH0.000526441.70241491
Withdraw By Posi...205915922024-08-23 13:27:238 days ago1724419643IN
0x2a2273Dc...680e830bB
0 ETH0.000508131.63977103
Withdraw By Posi...205816682024-08-22 4:09:359 days ago1724299775IN
0x2a2273Dc...680e830bB
0 ETH0.000362041.11478418
Deposit To Posit...205577912024-08-18 20:06:1113 days ago1724011571IN
0x2a2273Dc...680e830bB
0 ETH0.000432141.37609475
Withdraw By Posi...205577552024-08-18 19:58:5913 days ago1724011139IN
0x2a2273Dc...680e830bB
0 ETH0.000580621.64087826
Withdraw By Posi...205577142024-08-18 19:50:3513 days ago1724010635IN
0x2a2273Dc...680e830bB
0 ETH0.00036521.04792412
Withdraw By Posi...205577062024-08-18 19:48:5913 days ago1724010539IN
0x2a2273Dc...680e830bB
0 ETH0.00036851.11197338
Withdraw By Posi...205576792024-08-18 19:43:3513 days ago1724010215IN
0x2a2273Dc...680e830bB
0 ETH0.00038081.17255849
Withdraw By Posi...205576732024-08-18 19:42:2313 days ago1724010143IN
0x2a2273Dc...680e830bB
0 ETH0.00035011.07802373
Withdraw By Posi...205576672024-08-18 19:41:1113 days ago1724010071IN
0x2a2273Dc...680e830bB
0 ETH0.00035891.10513907
Withdraw By Posi...205576582024-08-18 19:39:2313 days ago1724009963IN
0x2a2273Dc...680e830bB
0 ETH0.000366371.12813445
Withdraw By Posi...205576492024-08-18 19:37:3513 days ago1724009855IN
0x2a2273Dc...680e830bB
0 ETH0.000334471.02986601
Withdraw By Posi...205576392024-08-18 19:35:3513 days ago1724009735IN
0x2a2273Dc...680e830bB
0 ETH0.000351721.14106732
Withdraw By Posi...205576332024-08-18 19:34:2313 days ago1724009663IN
0x2a2273Dc...680e830bB
0 ETH0.00037591.15748589
Deposit To Posit...204953132024-08-10 2:46:1121 days ago1723257971IN
0x2a2273Dc...680e830bB
0 ETH0.00043041.3918139
Withdraw By Posi...204952932024-08-10 2:42:1121 days ago1723257731IN
0x2a2273Dc...680e830bB
0 ETH0.000385641.24449181
Withdraw204796132024-08-07 22:13:5924 days ago1723068839IN
0x2a2273Dc...680e830bB
0 ETH0.000952392.85931265
Withdraw By Posi...204267282024-07-31 13:07:2331 days ago1722431243IN
0x2a2273Dc...680e830bB
0 ETH0.003394789.28503986
Deposit To Posit...203980422024-07-27 12:59:4735 days ago1722085187IN
0x2a2273Dc...680e830bB
0 ETH0.000607151.96338682
Withdraw By Posi...203980272024-07-27 12:56:4735 days ago1722085007IN
0x2a2273Dc...680e830bB
0 ETH0.000641852.07123297
Deposit To Posit...203086272024-07-15 1:28:3547 days ago1721006915IN
0x2a2273Dc...680e830bB
0 ETH0.001154053.73209683
Withdraw By Posi...203086072024-07-15 1:24:3547 days ago1721006675IN
0x2a2273Dc...680e830bB
0 ETH0.001282924.14006404
Deposit To Prope...202627362024-07-08 15:38:2354 days ago1720453103IN
0x2a2273Dc...680e830bB
0 ETH0.003506517.05724096
Deposit To Posit...201448402024-06-22 4:23:5970 days ago1719030239IN
0x2a2273Dc...680e830bB
0 ETH0.000742412.40079417
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Lockup

Compiler Version
v0.5.17+commit.d19bba13

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 22 : Lockup.sol
pragma solidity 0.5.17;

// prettier-ignore
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ISTokensManager} from "@devprotocol/i-s-tokens/contracts/interface/ISTokensManager.sol";
import "../common/libs/Decimals.sol";
import "../common/config/UsingConfig.sol";
import "../lockup/LockupStorage.sol";
import "../../interface/IDev.sol";
import "../../interface/IDevMinter.sol";
import "../../interface/IProperty.sol";
import "../../interface/IPolicy.sol";
import "../../interface/IAllocator.sol";
import "../../interface/ILockup.sol";
import "../../interface/IMetricsGroup.sol";

/**
 * A contract that manages the staking of DEV tokens and calculates rewards.
 * Staking and the following mechanism determines that reward calculation.
 *
 * Variables:
 * -`M`: Maximum mint amount per block determined by Allocator contract
 * -`B`: Number of blocks during staking
 * -`P`: Total number of staking locked up in a Property contract
 * -`S`: Total number of staking locked up in all Property contracts
 * -`U`: Number of staking per account locked up in a Property contract
 *
 * Formula:
 * Staking Rewards = M * B * (P / S) * (U / P)
 *
 * Note:
 * -`M`, `P` and `S` vary from block to block, and the variation cannot be predicted.
 * -`B` is added every time the Ethereum block is created.
 * - Only `U` and `B` are predictable variables.
 * - As `M`, `P` and `S` cannot be observed from a staker, the "cumulative sum" is often used to calculate ratio variation with history.
 * - Reward withdrawal always withdraws the total withdrawable amount.
 *
 * Scenario:
 * - Assume `M` is fixed at 500
 * - Alice stakes 100 DEV on Property-A (Alice's staking state on Property-A: `M`=500, `B`=0, `P`=100, `S`=100, `U`=100)
 * - After 10 blocks, Bob stakes 60 DEV on Property-B (Alice's staking state on Property-A: `M`=500, `B`=10, `P`=100, `S`=160, `U`=100)
 * - After 10 blocks, Carol stakes 40 DEV on Property-A (Alice's staking state on Property-A: `M`=500, `B`=20, `P`=140, `S`=200, `U`=100)
 * - After 10 blocks, Alice withdraws Property-A staking reward. The reward at this time is 5000 DEV (10 blocks * 500 DEV) + 3125 DEV (10 blocks * 62.5% * 500 DEV) + 2500 DEV (10 blocks * 50% * 500 DEV).
 */
contract Lockup is ILockup, UsingConfig, LockupStorage {
	using SafeMath for uint256;
	using Decimals for uint256;
	address public devMinter;
	address public sTokensManager;
	struct RewardPrices {
		uint256 reward;
		uint256 holders;
		uint256 interest;
		uint256 holdersCap;
	}
	event Lockedup(address _from, address _property, uint256 _value);
	event UpdateCap(uint256 _cap);

	/**
	 * Initialize the passed address as AddressConfig address and Devminter.
	 */
	constructor(
		address _config,
		address _devMinter,
		address _sTokensManager
	) public UsingConfig(_config) {
		devMinter = _devMinter;
		sTokensManager = _sTokensManager;
	}

	/**
	 * @dev Validates the passed Property has greater than 1 asset.
	 * @param _property property address
	 */
	modifier onlyAuthenticatedProperty(address _property) {
		require(
			IMetricsGroup(config().metricsGroup()).hasAssets(_property),
			"unable to stake to unauthenticated property"
		);
		_;
	}

	/**
	 * @dev Check if the owner of the token is a sender.
	 * @param _tokenId The ID of the staking position
	 */
	modifier onlyPositionOwner(uint256 _tokenId) {
		require(
			IERC721(sTokensManager).ownerOf(_tokenId) == msg.sender,
			"illegal sender"
		);
		_;
	}

	/**
	 * @dev deposit dev token to dev protocol and generate s-token
	 * @param _property target property address
	 * @param _amount staking value
	 * @return tokenId The ID of the created new staking position
	 */
	function depositToProperty(address _property, uint256 _amount)
		external
		returns (uint256)
	{
		return _implDepositToProperty(_property, _amount, "");
	}

	/**
	 * @dev deposit dev token to dev protocol and generate s-token
	 * @param _property target property address
	 * @param _amount staking value
	 * @param _payload additional bytes for s-token
	 * @return tokenId The ID of the created new staking position
	 */
	function depositToProperty(
		address _property,
		uint256 _amount,
		bytes32 _payload
	) external returns (uint256) {
		return _implDepositToProperty(_property, _amount, _payload);
	}

	function _implDepositToProperty(
		address _property,
		uint256 _amount,
		bytes32 _payload
	) private onlyAuthenticatedProperty(_property) returns (uint256) {
		/**
		 * Gets the latest cumulative sum of the interest price.
		 */
		(
			uint256 reward,
			uint256 holders,
			uint256 interest,
			uint256 holdersCap
		) = calculateCumulativeRewardPrices();
		/**
		 * Saves variables that should change due to the addition of staking.
		 */
		updateValues(
			true,
			_property,
			_amount,
			RewardPrices(reward, holders, interest, holdersCap)
		);
		/**
		 * transfer dev tokens
		 */
		require(
			IERC20(config().token()).transferFrom(
				msg.sender,
				_property,
				_amount
			),
			"dev transfer failed"
		);
		/**
		 * mint s tokens
		 */
		uint256 tokenId = ISTokensManager(sTokensManager).mint(
			msg.sender,
			_property,
			_amount,
			interest,
			_payload
		);
		emit Lockedup(msg.sender, _property, _amount);
		return tokenId;
	}

	/**
	 * @dev deposit dev token to dev protocol and update s-token status
	 * @param _tokenId s-token id
	 * @param _amount staking value
	 * @return bool On success, true will be returned
	 */
	function depositToPosition(uint256 _tokenId, uint256 _amount)
		external
		onlyPositionOwner(_tokenId)
		returns (bool)
	{
		/**
		 * Validates _amount is not 0.
		 */
		require(_amount != 0, "illegal deposit amount");
		ISTokensManager sTokenManagerInstance = ISTokensManager(sTokensManager);
		/**
		 * get position information
		 */
		(
			address property,
			uint256 amount,
			uint256 price,
			uint256 cumulativeReward,
			uint256 pendingReward
		) = sTokenManagerInstance.positions(_tokenId);
		/**
		 * Gets the withdrawable amount.
		 */
		(
			uint256 withdrawable,
			RewardPrices memory prices
		) = _calculateWithdrawableInterestAmount(
				property,
				amount,
				price,
				pendingReward
			);
		/**
		 * Saves variables that should change due to the addition of staking.
		 */
		updateValues(true, property, _amount, prices);
		/**
		 * transfer dev tokens
		 */
		require(
			IERC20(config().token()).transferFrom(
				msg.sender,
				property,
				_amount
			),
			"dev transfer failed"
		);
		/**
		 * update position information
		 */
		bool result = sTokenManagerInstance.update(
			_tokenId,
			amount.add(_amount),
			prices.interest,
			cumulativeReward.add(withdrawable),
			pendingReward.add(withdrawable)
		);
		require(result, "failed to update");
		/**
		 * generate events
		 */
		emit Lockedup(msg.sender, property, _amount);
		return true;
	}

	/**
	 * Adds staking.
	 * Only the Dev contract can execute this function.
	 */
	function lockup(
		address _from,
		address _property,
		uint256 _value
	) external onlyAuthenticatedProperty(_property) {
		/**
		 * Validates the sender is Dev contract.
		 */
		require(msg.sender == config().token(), "this is illegal address");

		/**
		 * Validates _value is not 0.
		 */
		require(_value != 0, "illegal lockup value");

		/**
		 * Since the reward per block that can be withdrawn will change with the addition of staking,
		 * saves the undrawn withdrawable reward before addition it.
		 */
		RewardPrices memory prices = updatePendingInterestWithdrawal(
			_property,
			_from
		);

		/**
		 * Saves variables that should change due to the addition of staking.
		 */
		updateValues4Legacy(true, _from, _property, _value, prices);

		emit Lockedup(_from, _property, _value);
	}

	/**
	 * Withdraw staking.(NFT)
	 * Releases staking, withdraw rewards, and transfer the staked and withdraw rewards amount to the sender.
	 */
	function withdrawByPosition(uint256 _tokenId, uint256 _amount)
		external
		onlyPositionOwner(_tokenId)
		returns (bool)
	{
		ISTokensManager sTokenManagerInstance = ISTokensManager(sTokensManager);
		/**
		 * get position information
		 */
		(
			address property,
			uint256 amount,
			uint256 price,
			uint256 cumulativeReward,
			uint256 pendingReward
		) = sTokenManagerInstance.positions(_tokenId);
		/**
		 * If the balance of the withdrawal request is bigger than the balance you are staking
		 */
		require(amount >= _amount, "insufficient tokens staked");
		/**
		 * Withdraws the staking reward
		 */
		(uint256 value, RewardPrices memory prices) = _withdrawInterest(
			property,
			amount,
			price,
			pendingReward
		);
		/**
		 * Transfer the staked amount to the sender.
		 */
		if (_amount != 0) {
			IProperty(property).withdraw(msg.sender, _amount);
		}
		/**
		 * Saves variables that should change due to the canceling staking..
		 */
		updateValues(false, property, _amount, prices);
		uint256 cumulative = cumulativeReward.add(value);
		/**
		 * update position information
		 */
		return
			sTokenManagerInstance.update(
				_tokenId,
				amount.sub(_amount),
				prices.interest,
				cumulative,
				0
			);
	}

	/**
	 * Withdraw staking.
	 * Releases staking, withdraw rewards, and transfer the staked and withdraw rewards amount to the sender.
	 */
	function withdraw(address _property, uint256 _amount) external {
		/**
		 * Validates the sender is staking to the target Property.
		 */
		require(
			hasValue(_property, msg.sender, _amount),
			"insufficient tokens staked"
		);

		/**
		 * Withdraws the staking reward
		 */
		RewardPrices memory prices = _withdrawInterest4Legacy(_property);

		/**
		 * Transfer the staked amount to the sender.
		 */
		if (_amount != 0) {
			IProperty(_property).withdraw(msg.sender, _amount);
		}

		/**
		 * Saves variables that should change due to the canceling staking..
		 */
		updateValues4Legacy(false, msg.sender, _property, _amount, prices);
	}

	/**
	 * get cap
	 */
	function cap() external view returns (uint256) {
		return getStorageCap();
	}

	/**
	 * set cap
	 */
	function updateCap(uint256 _cap) external {
		address setter = IPolicy(config().policy()).capSetter();
		require(setter == msg.sender, "illegal access");

		/**
		 * Updates cumulative amount of the holders reward cap
		 */
		(
			,
			uint256 holdersPrice,
			,
			uint256 cCap
		) = calculateCumulativeRewardPrices();

		// TODO: When this function is improved to be called on-chain, the source of `getStorageLastCumulativeHoldersPriceCap` can be rewritten to `getStorageLastCumulativeHoldersRewardPrice`.
		setStorageCumulativeHoldersRewardCap(cCap);
		setStorageLastCumulativeHoldersPriceCap(holdersPrice);
		setStorageCap(_cap);
		emit UpdateCap(_cap);
	}

	/**
	 * Returns the latest cap
	 */
	function _calculateLatestCap(uint256 _holdersPrice)
		private
		view
		returns (uint256)
	{
		uint256 cCap = getStorageCumulativeHoldersRewardCap();
		uint256 lastHoldersPrice = getStorageLastCumulativeHoldersPriceCap();
		uint256 additionalCap = _holdersPrice.sub(lastHoldersPrice).mul(
			getStorageCap()
		);
		return cCap.add(additionalCap);
	}

	/**
	 * Store staking states as a snapshot.
	 */
	function beforeStakesChanged(address _property, RewardPrices memory _prices)
		private
	{
		/**
		 * Gets latest cumulative holders reward for the passed Property.
		 */
		uint256 cHoldersReward = _calculateCumulativeHoldersRewardAmount(
			_prices.holders,
			_property
		);

		/**
		 * Sets `InitialCumulativeHoldersRewardCap`.
		 * Records this value only when the "first staking to the passed Property" is transacted.
		 */
		if (
			getStorageLastCumulativeHoldersRewardPricePerProperty(_property) ==
			0 &&
			getStorageInitialCumulativeHoldersRewardCap(_property) == 0 &&
			getStoragePropertyValue(_property) == 0
		) {
			setStorageInitialCumulativeHoldersRewardCap(
				_property,
				_prices.holdersCap
			);
		}

		/**
		 * Store each value.
		 */
		setStorageLastStakesChangedCumulativeReward(_prices.reward);
		setStorageLastCumulativeHoldersRewardPrice(_prices.holders);
		setStorageLastCumulativeInterestPrice(_prices.interest);
		setStorageLastCumulativeHoldersRewardAmountPerProperty(
			_property,
			cHoldersReward
		);
		setStorageLastCumulativeHoldersRewardPricePerProperty(
			_property,
			_prices.holders
		);
		setStorageCumulativeHoldersRewardCap(_prices.holdersCap);
		setStorageLastCumulativeHoldersPriceCap(_prices.holders);
	}

	/**
	 * Gets latest value of cumulative sum of the reward amount, cumulative sum of the holders reward per stake, and cumulative sum of the stakers reward per stake.
	 */
	function calculateCumulativeRewardPrices()
		public
		view
		returns (
			uint256 _reward,
			uint256 _holders,
			uint256 _interest,
			uint256 _holdersCap
		)
	{
		uint256 lastReward = getStorageLastStakesChangedCumulativeReward();
		uint256 lastHoldersPrice = getStorageLastCumulativeHoldersRewardPrice();
		uint256 lastInterestPrice = getStorageLastCumulativeInterestPrice();
		uint256 allStakes = getStorageAllValue();

		/**
		 * Gets latest cumulative sum of the reward amount.
		 */
		(uint256 reward, ) = dry();
		uint256 mReward = reward.mulBasis();

		/**
		 * Calculates reward unit price per staking.
		 * Later, the last cumulative sum of the reward amount is subtracted because to add the last recorded holder/staking reward.
		 */
		uint256 price = allStakes > 0
			? mReward.sub(lastReward).div(allStakes)
			: 0;

		/**
		 * Calculates the holders reward out of the total reward amount.
		 */
		uint256 holdersShare = IPolicy(config().policy()).holdersShare(
			price,
			allStakes
		);

		/**
		 * Calculates and returns each reward.
		 */
		uint256 holdersPrice = holdersShare.add(lastHoldersPrice);
		uint256 interestPrice = price.sub(holdersShare).add(lastInterestPrice);
		uint256 cCap = _calculateLatestCap(holdersPrice);
		return (mReward, holdersPrice, interestPrice, cCap);
	}

	/**
	 * Calculates cumulative sum of the holders reward per Property.
	 * To save computing resources, it receives the latest holder rewards from a caller.
	 */
	function _calculateCumulativeHoldersRewardAmount(
		uint256 _holdersPrice,
		address _property
	) private view returns (uint256) {
		(uint256 cHoldersReward, uint256 lastReward) = (
			getStorageLastCumulativeHoldersRewardAmountPerProperty(_property),
			getStorageLastCumulativeHoldersRewardPricePerProperty(_property)
		);

		/**
		 * `cHoldersReward` contains the calculation of `lastReward`, so subtract it here.
		 */
		uint256 additionalHoldersReward = _holdersPrice.sub(lastReward).mul(
			getStoragePropertyValue(_property)
		);

		/**
		 * Calculates and returns the cumulative sum of the holder reward by adds the last recorded holder reward and the latest holder reward.
		 */
		return cHoldersReward.add(additionalHoldersReward);
	}

	/**
	 * Calculates cumulative sum of the holders reward per Property.
	 * caution!!!this function is deprecated!!!
	 * use calculateRewardAmount
	 */
	function calculateCumulativeHoldersRewardAmount(address _property)
		external
		view
		returns (uint256)
	{
		(, uint256 holders, , ) = calculateCumulativeRewardPrices();
		return _calculateCumulativeHoldersRewardAmount(holders, _property);
	}

	/**
	 * Calculates holders reward and cap per Property.
	 */
	function calculateRewardAmount(address _property)
		external
		view
		returns (uint256, uint256)
	{
		(
			,
			uint256 holders,
			,
			uint256 holdersCap
		) = calculateCumulativeRewardPrices();
		uint256 initialCap = _getInitialCap(_property);

		/**
		 * Calculates the cap
		 */
		uint256 capValue = holdersCap.sub(initialCap);
		return (
			_calculateCumulativeHoldersRewardAmount(holders, _property),
			capValue
		);
	}

	function _getInitialCap(address _property) private view returns (uint256) {
		uint256 initialCap = getStorageInitialCumulativeHoldersRewardCap(
			_property
		);
		if (initialCap > 0) {
			return initialCap;
		}

		// Fallback when there is a data past staked.
		if (
			getStorageLastCumulativeHoldersRewardPricePerProperty(_property) >
			0 ||
			getStoragePropertyValue(_property) > 0
		) {
			return getStorageFallbackInitialCumulativeHoldersRewardCap();
		}
		return 0;
	}

	/**
	 * Updates cumulative sum of the maximum mint amount calculated by Allocator contract, the latest maximum mint amount per block,
	 * and the last recorded block number.
	 * The cumulative sum of the maximum mint amount is always added.
	 * By recording that value when the staker last stakes, the difference from the when the staker stakes can be calculated.
	 */
	function update() public {
		/**
		 * Gets the cumulative sum of the maximum mint amount and the maximum mint number per block.
		 */
		(uint256 _nextRewards, uint256 _amount) = dry();

		/**
		 * Records each value and the latest block number.
		 */
		setStorageCumulativeGlobalRewards(_nextRewards);
		setStorageLastSameRewardsAmountAndBlock(_amount, block.number);
	}

	/**
	 * Referring to the values recorded in each storage to returns the latest cumulative sum of the maximum mint amount and the latest maximum mint amount per block.
	 */
	function dry()
		private
		view
		returns (uint256 _nextRewards, uint256 _amount)
	{
		/**
		 * Gets the latest mint amount per block from Allocator contract.
		 */
		uint256 rewardsAmount = IAllocator(config().allocator())
			.calculateMaxRewardsPerBlock();

		/**
		 * Gets the maximum mint amount per block, and the last recorded block number from `LastSameRewardsAmountAndBlock` storage.
		 */
		(
			uint256 lastAmount,
			uint256 lastBlock
		) = getStorageLastSameRewardsAmountAndBlock();

		/**
		 * If the recorded maximum mint amount per block and the result of the Allocator contract are different,
		 * the result of the Allocator contract takes precedence as a maximum mint amount per block.
		 */
		uint256 lastMaxRewards = lastAmount == rewardsAmount
			? rewardsAmount
			: lastAmount;

		/**
		 * Calculates the difference between the latest block number and the last recorded block number.
		 */
		uint256 blocks = lastBlock > 0 ? block.number.sub(lastBlock) : 0;

		/**
		 * Adds the calculated new cumulative maximum mint amount to the recorded cumulative maximum mint amount.
		 */
		uint256 additionalRewards = lastMaxRewards.mul(blocks);
		uint256 nextRewards = getStorageCumulativeGlobalRewards().add(
			additionalRewards
		);

		/**
		 * Returns the latest theoretical cumulative sum of maximum mint amount and maximum mint amount per block.
		 */
		return (nextRewards, rewardsAmount);
	}

	/**
	 * Returns the staker reward as interest.
	 */
	function _calculateInterestAmount(uint256 _amount, uint256 _price)
		private
		view
		returns (
			uint256 amount_,
			uint256 interestPrice_,
			RewardPrices memory prices_
		)
	{
		/**
		 * Gets the latest cumulative sum of the interest price.
		 */
		(
			uint256 reward,
			uint256 holders,
			uint256 interest,
			uint256 holdersCap
		) = calculateCumulativeRewardPrices();

		/**
		 * Calculates and returns the latest withdrawable reward amount from the difference.
		 */
		uint256 result = interest >= _price
			? interest.sub(_price).mul(_amount).divBasis()
			: 0;
		return (
			result,
			interest,
			RewardPrices(reward, holders, interest, holdersCap)
		);
	}

	/**
	 * Returns the staker reward as interest.
	 */
	function _calculateInterestAmount4Legacy(address _property, address _user)
		private
		view
		returns (
			uint256 _amount,
			uint256 _interestPrice,
			RewardPrices memory _prices
		)
	{
		/**
		 * Get the amount the user is staking for the Property.
		 */
		uint256 lockedUpPerAccount = getStorageValue(_property, _user);

		/**
		 * Gets the cumulative sum of the interest price recorded the last time you withdrew.
		 */
		uint256 lastInterest = getStorageLastStakedInterestPrice(
			_property,
			_user
		);

		/**
		 * Gets the latest cumulative sum of the interest price.
		 */
		(
			uint256 reward,
			uint256 holders,
			uint256 interest,
			uint256 holdersCap
		) = calculateCumulativeRewardPrices();

		/**
		 * Calculates and returns the latest withdrawable reward amount from the difference.
		 */
		uint256 result = interest >= lastInterest
			? interest.sub(lastInterest).mul(lockedUpPerAccount).divBasis()
			: 0;
		return (
			result,
			interest,
			RewardPrices(reward, holders, interest, holdersCap)
		);
	}

	/**
	 * Returns the total rewards currently available for withdrawal. (For calling from inside the contract)
	 */
	function _calculateWithdrawableInterestAmount(
		address _property,
		uint256 _amount,
		uint256 _price,
		uint256 _pendingReward
	) private view returns (uint256 amount_, RewardPrices memory prices_) {
		/**
		 * If the passed Property has not authenticated, returns always 0.
		 */
		if (
			IMetricsGroup(config().metricsGroup()).hasAssets(_property) == false
		) {
			(
				uint256 reward,
				uint256 holders,
				uint256 interest,
				uint256 holdersCap
			) = calculateCumulativeRewardPrices();
			return (0, RewardPrices(reward, holders, interest, holdersCap));
		}

		/**
		 * Gets the latest withdrawal reward amount.
		 */
		(
			uint256 amount,
			,
			RewardPrices memory prices
		) = _calculateInterestAmount(_amount, _price);

		/**
		 * Returns the sum of all values.
		 */
		uint256 withdrawableAmount = amount.add(_pendingReward);
		return (withdrawableAmount, prices);
	}

	/**
	 * Returns the total rewards currently available for withdrawal. (For calling from inside the contract)
	 */
	function _calculateWithdrawableInterestAmount4Legacy(
		address _property,
		address _user
	) private view returns (uint256 _amount, RewardPrices memory _prices) {
		/**
		 * If the passed Property has not authenticated, returns always 0.
		 */
		if (
			IMetricsGroup(config().metricsGroup()).hasAssets(_property) == false
		) {
			(
				uint256 reward,
				uint256 holders,
				uint256 interest,
				uint256 holdersCap
			) = calculateCumulativeRewardPrices();
			return (0, RewardPrices(reward, holders, interest, holdersCap));
		}

		/**
		 * Gets the reward amount in saved without withdrawal.
		 */
		uint256 pending = getStoragePendingInterestWithdrawal(_property, _user);

		/**
		 * Gets the reward amount of before DIP4.
		 */
		uint256 legacy = __legacyWithdrawableInterestAmount(_property, _user);

		/**
		 * Gets the latest withdrawal reward amount.
		 */
		(
			uint256 amount,
			,
			RewardPrices memory prices
		) = _calculateInterestAmount4Legacy(_property, _user);

		/**
		 * Returns the sum of all values.
		 */
		uint256 withdrawableAmount = amount.add(pending).add(legacy);
		return (withdrawableAmount, prices);
	}

	/**
	 * Returns the total rewards currently available for withdrawal. (For calling from external of the contract)
	 */
	function calculateWithdrawableInterestAmount(
		address _property,
		address _user
	) external view returns (uint256) {
		(uint256 amount, ) = _calculateWithdrawableInterestAmount4Legacy(
			_property,
			_user
		);
		return amount;
	}

	/**
	 * Returns the total rewards currently available for withdrawal. (For calling from external of the contract)
	 */
	function calculateWithdrawableInterestAmountByPosition(uint256 _tokenId)
		external
		view
		returns (uint256)
	{
		ISTokensManager sTokenManagerInstance = ISTokensManager(sTokensManager);
		(
			address property,
			uint256 amount,
			uint256 price,
			,
			uint256 pendingReward
		) = sTokenManagerInstance.positions(_tokenId);
		(uint256 result, ) = _calculateWithdrawableInterestAmount(
			property,
			amount,
			price,
			pendingReward
		);
		return result;
	}

	/**
	 * Withdraws staking reward as an interest.
	 */
	function _withdrawInterest(
		address _property,
		uint256 _amount,
		uint256 _price,
		uint256 _pendingReward
	) private returns (uint256 value_, RewardPrices memory prices_) {
		/**
		 * Gets the withdrawable amount.
		 */
		(
			uint256 value,
			RewardPrices memory prices
		) = _calculateWithdrawableInterestAmount(
				_property,
				_amount,
				_price,
				_pendingReward
			);

		/**
		 * Mints the reward.
		 */
		require(
			IDevMinter(devMinter).mint(msg.sender, value),
			"dev mint failed"
		);

		/**
		 * Since the total supply of tokens has changed, updates the latest maximum mint amount.
		 */
		update();

		return (value, prices);
	}

	/**
	 * Withdraws staking reward as an interest.
	 */
	function _withdrawInterest4Legacy(address _property)
		private
		returns (RewardPrices memory _prices)
	{
		/**
		 * Gets the withdrawable amount.
		 */
		(
			uint256 value,
			RewardPrices memory prices
		) = _calculateWithdrawableInterestAmount4Legacy(_property, msg.sender);

		/**
		 * Sets the unwithdrawn reward amount to 0.
		 */
		setStoragePendingInterestWithdrawal(_property, msg.sender, 0);

		/**
		 * Updates the staking status to avoid double rewards.
		 */
		setStorageLastStakedInterestPrice(
			_property,
			msg.sender,
			prices.interest
		);
		__updateLegacyWithdrawableInterestAmount(_property, msg.sender);

		/**
		 * Mints the reward.
		 */
		require(
			IDevMinter(devMinter).mint(msg.sender, value),
			"dev mint failed"
		);

		/**
		 * Since the total supply of tokens has changed, updates the latest maximum mint amount.
		 */
		update();

		return prices;
	}

	/**
	 * Status updates with the addition or release of staking.
	 */
	function updateValues4Legacy(
		bool _addition,
		address _account,
		address _property,
		uint256 _value,
		RewardPrices memory _prices
	) private {
		/**
		 * Updates the staking status to avoid double rewards.
		 */
		setStorageLastStakedInterestPrice(
			_property,
			_account,
			_prices.interest
		);
		updateValues(_addition, _property, _value, _prices);
		/**
		 * Updates the staking value of property by user
		 */
		if (_addition) {
			addValue(_property, _account, _value);
		} else {
			subValue(_property, _account, _value);
		}
	}

	/**
	 * Status updates with the addition or release of staking.
	 */
	function updateValues(
		bool _addition,
		address _property,
		uint256 _value,
		RewardPrices memory _prices
	) private {
		beforeStakesChanged(_property, _prices);
		/**
		 * If added staking:
		 */
		if (_addition) {
			/**
			 * Updates the current staking amount of the protocol total.
			 */
			addAllValue(_value);

			/**
			 * Updates the current staking amount of the Property.
			 */
			addPropertyValue(_property, _value);
			/**
			 * If released staking:
			 */
		} else {
			/**
			 * Updates the current staking amount of the protocol total.
			 */
			subAllValue(_value);

			/**
			 * Updates the current staking amount of the Property.
			 */
			subPropertyValue(_property, _value);
		}

		/**
		 * Since each staking amount has changed, updates the latest maximum mint amount.
		 */
		update();
	}

	/**
	 * Returns the staking amount of the protocol total.
	 */
	function getAllValue() external view returns (uint256) {
		return getStorageAllValue();
	}

	/**
	 * Adds the staking amount of the protocol total.
	 */
	function addAllValue(uint256 _value) private {
		uint256 value = getStorageAllValue();
		value = value.add(_value);
		setStorageAllValue(value);
	}

	/**
	 * Subtracts the staking amount of the protocol total.
	 */
	function subAllValue(uint256 _value) private {
		uint256 value = getStorageAllValue();
		value = value.sub(_value);
		setStorageAllValue(value);
	}

	/**
	 * Returns the user's staking amount in the Property.
	 */
	function getValue(address _property, address _sender)
		external
		view
		returns (uint256)
	{
		return getStorageValue(_property, _sender);
	}

	/**
	 * Adds the user's staking amount in the Property.
	 */
	function addValue(
		address _property,
		address _sender,
		uint256 _value
	) private {
		uint256 value = getStorageValue(_property, _sender);
		value = value.add(_value);
		setStorageValue(_property, _sender, value);
	}

	/**
	 * Subtracts the user's staking amount in the Property.
	 */
	function subValue(
		address _property,
		address _sender,
		uint256 _value
	) private {
		uint256 value = getStorageValue(_property, _sender);
		value = value.sub(_value);
		setStorageValue(_property, _sender, value);
	}

	/**
	 * Returns whether the user is staking in the Property.
	 */
	function hasValue(
		address _property,
		address _sender,
		uint256 _amount
	) private view returns (bool) {
		uint256 value = getStorageValue(_property, _sender);
		return value >= _amount;
	}

	/**
	 * Returns the staking amount of the Property.
	 */
	function getPropertyValue(address _property)
		external
		view
		returns (uint256)
	{
		return getStoragePropertyValue(_property);
	}

	/**
	 * Adds the staking amount of the Property.
	 */
	function addPropertyValue(address _property, uint256 _value) private {
		uint256 value = getStoragePropertyValue(_property);
		value = value.add(_value);
		setStoragePropertyValue(_property, value);
	}

	/**
	 * Subtracts the staking amount of the Property.
	 */
	function subPropertyValue(address _property, uint256 _value) private {
		uint256 value = getStoragePropertyValue(_property);
		uint256 nextValue = value.sub(_value);
		setStoragePropertyValue(_property, nextValue);
	}

	/**
	 * Saves the latest reward amount as an undrawn amount.
	 */
	function updatePendingInterestWithdrawal(address _property, address _user)
		private
		returns (RewardPrices memory _prices)
	{
		/**
		 * Gets the latest reward amount.
		 */
		(
			uint256 withdrawableAmount,
			RewardPrices memory prices
		) = _calculateWithdrawableInterestAmount4Legacy(_property, _user);

		/**
		 * Saves the amount to `PendingInterestWithdrawal` storage.
		 */
		setStoragePendingInterestWithdrawal(
			_property,
			_user,
			withdrawableAmount
		);

		/**
		 * Updates the reward amount of before DIP4 to prevent further addition it.
		 */
		__updateLegacyWithdrawableInterestAmount(_property, _user);

		return prices;
	}

	/**
	 * Returns the reward amount of the calculation model before DIP4.
	 * It can be calculated by subtracting "the last cumulative sum of reward unit price" from
	 * "the current cumulative sum of reward unit price," and multiplying by the staking amount.
	 */
	function __legacyWithdrawableInterestAmount(
		address _property,
		address _user
	) private view returns (uint256) {
		uint256 _last = getStorageLastInterestPrice(_property, _user);
		uint256 price = getStorageInterestPrice(_property);
		uint256 priceGap = price.sub(_last);
		uint256 lockedUpValue = getStorageValue(_property, _user);
		uint256 value = priceGap.mul(lockedUpValue);
		return value.divBasis();
	}

	/**
	 * Updates and treats the reward of before DIP4 as already received.
	 */
	function __updateLegacyWithdrawableInterestAmount(
		address _property,
		address _user
	) private {
		uint256 interestPrice = getStorageInterestPrice(_property);
		if (getStorageLastInterestPrice(_property, _user) != interestPrice) {
			setStorageLastInterestPrice(_property, _user, interestPrice);
		}
	}

	function ___setFallbackInitialCumulativeHoldersRewardCap(uint256 _value)
		external
		onlyOwner
	{
		setStorageFallbackInitialCumulativeHoldersRewardCap(_value);
	}

	/**
	 * migration to nft
	 */
	function migrateToSTokens(address _property)
		external
		returns (uint256 tokenId_)
	{
		/**
		 * Get the amount the user is staking for the Property.
		 */
		uint256 amount = getStorageValue(_property, msg.sender);
		require(amount > 0, "not staked");
		/**
		 * Gets the cumulative sum of the interest price recorded the last time you withdrew.
		 */
		uint256 price = getStorageLastStakedInterestPrice(
			_property,
			msg.sender
		);
		/**
		 * Gets the reward amount in saved without withdrawal.
		 */
		uint256 pending = getStoragePendingInterestWithdrawal(
			_property,
			msg.sender
		);
		/**
		 * Sets the unwithdrawn reward amount to 0.
		 */
		setStoragePendingInterestWithdrawal(_property, msg.sender, 0);
		/**
		 * The amount of the user's investment in the property is set to zero.
		 */
		setStorageValue(_property, msg.sender, 0);
		ISTokensManager sTokenManagerInstance = ISTokensManager(sTokensManager);
		/**
		 * mint nft
		 */
		uint256 tokenId = sTokenManagerInstance.mint(
			msg.sender,
			_property,
			amount,
			price,
			""
		);
		/**
		 * update position information
		 */
		bool result = sTokenManagerInstance.update(
			tokenId,
			amount,
			price,
			0,
			pending
		);
		require(result, "failed to update");
		return tokenId;
	}
}

File 2 of 22 : LockupStorage.sol
pragma solidity 0.5.17;

import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import "../common/storage/UsingStorage.sol";

contract LockupStorage is UsingStorage {
	using SafeMath for uint256;

	uint256 private constant BASIS = 100000000000000000000000000000000;

	//AllValue
	function setStorageAllValue(uint256 _value) internal {
		bytes32 key = getStorageAllValueKey();
		eternalStorage().setUint(key, _value);
	}

	function getStorageAllValue() public view returns (uint256) {
		bytes32 key = getStorageAllValueKey();
		return eternalStorage().getUint(key);
	}

	function getStorageAllValueKey() private pure returns (bytes32) {
		return keccak256(abi.encodePacked("_allValue"));
	}

	//Value
	function setStorageValue(
		address _property,
		address _sender,
		uint256 _value
	) internal {
		bytes32 key = getStorageValueKey(_property, _sender);
		eternalStorage().setUint(key, _value);
	}

	function getStorageValue(address _property, address _sender)
		public
		view
		returns (uint256)
	{
		bytes32 key = getStorageValueKey(_property, _sender);
		return eternalStorage().getUint(key);
	}

	function getStorageValueKey(address _property, address _sender)
		private
		pure
		returns (bytes32)
	{
		return keccak256(abi.encodePacked("_value", _property, _sender));
	}

	//PropertyValue
	function setStoragePropertyValue(address _property, uint256 _value)
		internal
	{
		bytes32 key = getStoragePropertyValueKey(_property);
		eternalStorage().setUint(key, _value);
	}

	function getStoragePropertyValue(address _property)
		public
		view
		returns (uint256)
	{
		bytes32 key = getStoragePropertyValueKey(_property);
		return eternalStorage().getUint(key);
	}

	function getStoragePropertyValueKey(address _property)
		private
		pure
		returns (bytes32)
	{
		return keccak256(abi.encodePacked("_propertyValue", _property));
	}

	//InterestPrice
	function setStorageInterestPrice(address _property, uint256 _value)
		internal
	{
		// The previously used function
		// This function is only used in testing
		eternalStorage().setUint(getStorageInterestPriceKey(_property), _value);
	}

	function getStorageInterestPrice(address _property)
		public
		view
		returns (uint256)
	{
		return eternalStorage().getUint(getStorageInterestPriceKey(_property));
	}

	function getStorageInterestPriceKey(address _property)
		private
		pure
		returns (bytes32)
	{
		return keccak256(abi.encodePacked("_interestTotals", _property));
	}

	//LastInterestPrice
	function setStorageLastInterestPrice(
		address _property,
		address _user,
		uint256 _value
	) internal {
		eternalStorage().setUint(
			getStorageLastInterestPriceKey(_property, _user),
			_value
		);
	}

	function getStorageLastInterestPrice(address _property, address _user)
		public
		view
		returns (uint256)
	{
		return
			eternalStorage().getUint(
				getStorageLastInterestPriceKey(_property, _user)
			);
	}

	function getStorageLastInterestPriceKey(address _property, address _user)
		private
		pure
		returns (bytes32)
	{
		return
			keccak256(
				abi.encodePacked("_lastLastInterestPrice", _property, _user)
			);
	}

	//LastSameRewardsAmountAndBlock
	function setStorageLastSameRewardsAmountAndBlock(
		uint256 _amount,
		uint256 _block
	) internal {
		uint256 record = _amount.mul(BASIS).add(_block);
		eternalStorage().setUint(
			getStorageLastSameRewardsAmountAndBlockKey(),
			record
		);
	}

	function getStorageLastSameRewardsAmountAndBlock()
		public
		view
		returns (uint256 _amount, uint256 _block)
	{
		uint256 record = eternalStorage().getUint(
			getStorageLastSameRewardsAmountAndBlockKey()
		);
		uint256 amount = record.div(BASIS);
		uint256 blockNumber = record.sub(amount.mul(BASIS));
		return (amount, blockNumber);
	}

	function getStorageLastSameRewardsAmountAndBlockKey()
		private
		pure
		returns (bytes32)
	{
		return keccak256(abi.encodePacked("_LastSameRewardsAmountAndBlock"));
	}

	//CumulativeGlobalRewards
	function setStorageCumulativeGlobalRewards(uint256 _value) internal {
		eternalStorage().setUint(
			getStorageCumulativeGlobalRewardsKey(),
			_value
		);
	}

	function getStorageCumulativeGlobalRewards() public view returns (uint256) {
		return eternalStorage().getUint(getStorageCumulativeGlobalRewardsKey());
	}

	function getStorageCumulativeGlobalRewardsKey()
		private
		pure
		returns (bytes32)
	{
		return keccak256(abi.encodePacked("_cumulativeGlobalRewards"));
	}

	//PendingWithdrawal
	function setStoragePendingInterestWithdrawal(
		address _property,
		address _user,
		uint256 _value
	) internal {
		eternalStorage().setUint(
			getStoragePendingInterestWithdrawalKey(_property, _user),
			_value
		);
	}

	function getStoragePendingInterestWithdrawal(
		address _property,
		address _user
	) public view returns (uint256) {
		return
			eternalStorage().getUint(
				getStoragePendingInterestWithdrawalKey(_property, _user)
			);
	}

	function getStoragePendingInterestWithdrawalKey(
		address _property,
		address _user
	) private pure returns (bytes32) {
		return
			keccak256(
				abi.encodePacked("_pendingInterestWithdrawal", _property, _user)
			);
	}

	//DIP4GenesisBlock
	function setStorageDIP4GenesisBlock(uint256 _block) internal {
		eternalStorage().setUint(getStorageDIP4GenesisBlockKey(), _block);
	}

	function getStorageDIP4GenesisBlock() public view returns (uint256) {
		return eternalStorage().getUint(getStorageDIP4GenesisBlockKey());
	}

	function getStorageDIP4GenesisBlockKey() private pure returns (bytes32) {
		return keccak256(abi.encodePacked("_dip4GenesisBlock"));
	}

	//lastStakedInterestPrice
	function setStorageLastStakedInterestPrice(
		address _property,
		address _user,
		uint256 _value
	) internal {
		eternalStorage().setUint(
			getStorageLastStakedInterestPriceKey(_property, _user),
			_value
		);
	}

	function getStorageLastStakedInterestPrice(address _property, address _user)
		public
		view
		returns (uint256)
	{
		return
			eternalStorage().getUint(
				getStorageLastStakedInterestPriceKey(_property, _user)
			);
	}

	function getStorageLastStakedInterestPriceKey(
		address _property,
		address _user
	) private pure returns (bytes32) {
		return
			keccak256(
				abi.encodePacked("_lastStakedInterestPrice", _property, _user)
			);
	}

	//lastStakesChangedCumulativeReward
	function setStorageLastStakesChangedCumulativeReward(uint256 _value)
		internal
	{
		eternalStorage().setUint(
			getStorageLastStakesChangedCumulativeRewardKey(),
			_value
		);
	}

	function getStorageLastStakesChangedCumulativeReward()
		public
		view
		returns (uint256)
	{
		return
			eternalStorage().getUint(
				getStorageLastStakesChangedCumulativeRewardKey()
			);
	}

	function getStorageLastStakesChangedCumulativeRewardKey()
		private
		pure
		returns (bytes32)
	{
		return
			keccak256(abi.encodePacked("_lastStakesChangedCumulativeReward"));
	}

	//LastCumulativeHoldersRewardPrice
	function setStorageLastCumulativeHoldersRewardPrice(uint256 _holders)
		internal
	{
		eternalStorage().setUint(
			getStorageLastCumulativeHoldersRewardPriceKey(),
			_holders
		);
	}

	function getStorageLastCumulativeHoldersRewardPrice()
		public
		view
		returns (uint256)
	{
		return
			eternalStorage().getUint(
				getStorageLastCumulativeHoldersRewardPriceKey()
			);
	}

	function getStorageLastCumulativeHoldersRewardPriceKey()
		private
		pure
		returns (bytes32)
	{
		return keccak256(abi.encodePacked("0lastCumulativeHoldersRewardPrice"));
	}

	//LastCumulativeInterestPrice
	function setStorageLastCumulativeInterestPrice(uint256 _interest) internal {
		eternalStorage().setUint(
			getStorageLastCumulativeInterestPriceKey(),
			_interest
		);
	}

	function getStorageLastCumulativeInterestPrice()
		public
		view
		returns (uint256)
	{
		return
			eternalStorage().getUint(
				getStorageLastCumulativeInterestPriceKey()
			);
	}

	function getStorageLastCumulativeInterestPriceKey()
		private
		pure
		returns (bytes32)
	{
		return keccak256(abi.encodePacked("0lastCumulativeInterestPrice"));
	}

	//LastCumulativeHoldersRewardAmountPerProperty
	function setStorageLastCumulativeHoldersRewardAmountPerProperty(
		address _property,
		uint256 _value
	) internal {
		eternalStorage().setUint(
			getStorageLastCumulativeHoldersRewardAmountPerPropertyKey(
				_property
			),
			_value
		);
	}

	function getStorageLastCumulativeHoldersRewardAmountPerProperty(
		address _property
	) public view returns (uint256) {
		return
			eternalStorage().getUint(
				getStorageLastCumulativeHoldersRewardAmountPerPropertyKey(
					_property
				)
			);
	}

	function getStorageLastCumulativeHoldersRewardAmountPerPropertyKey(
		address _property
	) private pure returns (bytes32) {
		return
			keccak256(
				abi.encodePacked(
					"0lastCumulativeHoldersRewardAmountPerProperty",
					_property
				)
			);
	}

	//LastCumulativeHoldersRewardPricePerProperty
	function setStorageLastCumulativeHoldersRewardPricePerProperty(
		address _property,
		uint256 _price
	) internal {
		eternalStorage().setUint(
			getStorageLastCumulativeHoldersRewardPricePerPropertyKey(_property),
			_price
		);
	}

	function getStorageLastCumulativeHoldersRewardPricePerProperty(
		address _property
	) public view returns (uint256) {
		return
			eternalStorage().getUint(
				getStorageLastCumulativeHoldersRewardPricePerPropertyKey(
					_property
				)
			);
	}

	function getStorageLastCumulativeHoldersRewardPricePerPropertyKey(
		address _property
	) private pure returns (bytes32) {
		return
			keccak256(
				abi.encodePacked(
					"0lastCumulativeHoldersRewardPricePerProperty",
					_property
				)
			);
	}

	//cap
	function setStorageCap(uint256 _cap) internal {
		eternalStorage().setUint(getStorageCapKey(), _cap);
	}

	function getStorageCap() public view returns (uint256) {
		return eternalStorage().getUint(getStorageCapKey());
	}

	function getStorageCapKey() private pure returns (bytes32) {
		return keccak256(abi.encodePacked("_cap"));
	}

	//CumulativeHoldersRewardCap
	function setStorageCumulativeHoldersRewardCap(uint256 _value) internal {
		eternalStorage().setUint(
			getStorageCumulativeHoldersRewardCapKey(),
			_value
		);
	}

	function getStorageCumulativeHoldersRewardCap()
		public
		view
		returns (uint256)
	{
		return
			eternalStorage().getUint(getStorageCumulativeHoldersRewardCapKey());
	}

	function getStorageCumulativeHoldersRewardCapKey()
		private
		pure
		returns (bytes32)
	{
		return keccak256(abi.encodePacked("_cumulativeHoldersRewardCap"));
	}

	//LastCumulativeHoldersPriceCap
	function setStorageLastCumulativeHoldersPriceCap(uint256 _value) internal {
		eternalStorage().setUint(
			getStorageLastCumulativeHoldersPriceCapKey(),
			_value
		);
	}

	function getStorageLastCumulativeHoldersPriceCap()
		public
		view
		returns (uint256)
	{
		return
			eternalStorage().getUint(
				getStorageLastCumulativeHoldersPriceCapKey()
			);
	}

	function getStorageLastCumulativeHoldersPriceCapKey()
		private
		pure
		returns (bytes32)
	{
		return keccak256(abi.encodePacked("_lastCumulativeHoldersPriceCap"));
	}

	//InitialCumulativeHoldersRewardCap
	function setStorageInitialCumulativeHoldersRewardCap(
		address _property,
		uint256 _value
	) internal {
		eternalStorage().setUint(
			getStorageInitialCumulativeHoldersRewardCapKey(_property),
			_value
		);
	}

	function getStorageInitialCumulativeHoldersRewardCap(address _property)
		public
		view
		returns (uint256)
	{
		return
			eternalStorage().getUint(
				getStorageInitialCumulativeHoldersRewardCapKey(_property)
			);
	}

	function getStorageInitialCumulativeHoldersRewardCapKey(address _property)
		private
		pure
		returns (bytes32)
	{
		return
			keccak256(
				abi.encodePacked(
					"_initialCumulativeHoldersRewardCap",
					_property
				)
			);
	}

	//FallbackInitialCumulativeHoldersRewardCap
	function setStorageFallbackInitialCumulativeHoldersRewardCap(uint256 _value)
		internal
	{
		eternalStorage().setUint(
			getStorageFallbackInitialCumulativeHoldersRewardCapKey(),
			_value
		);
	}

	function getStorageFallbackInitialCumulativeHoldersRewardCap()
		public
		view
		returns (uint256)
	{
		return
			eternalStorage().getUint(
				getStorageFallbackInitialCumulativeHoldersRewardCapKey()
			);
	}

	function getStorageFallbackInitialCumulativeHoldersRewardCapKey()
		private
		pure
		returns (bytes32)
	{
		return
			keccak256(
				abi.encodePacked("_fallbackInitialCumulativeHoldersRewardCap")
			);
	}
}

File 3 of 22 : UsingStorage.sol
pragma solidity 0.5.17;

import "../../../interface/IUsingStorage.sol";
import {Ownable} from "@openzeppelin/contracts/ownership/Ownable.sol";
import "./EternalStorage.sol";

/**
 * Module for contrast handling EternalStorage.
 */
contract UsingStorage is Ownable, IUsingStorage {
	address private _storage;

	/**
	 * Modifier to verify that EternalStorage is set.
	 */
	modifier hasStorage() {
		require(_storage != address(0), "storage is not set");
		_;
	}

	/**
	 * Returns the set EternalStorage instance.
	 */
	function eternalStorage()
		internal
		view
		hasStorage
		returns (EternalStorage)
	{
		return EternalStorage(_storage);
	}

	/**
	 * Returns the set EternalStorage address.
	 */
	function getStorageAddress() external view hasStorage returns (address) {
		return _storage;
	}

	/**
	 * Create a new EternalStorage contract.
	 * This function call will fail if the EternalStorage contract is already set.
	 * Also, only the owner can execute it.
	 */
	function createStorage() external onlyOwner {
		require(_storage == address(0), "storage is set");
		EternalStorage tmp = new EternalStorage();
		_storage = address(tmp);
	}

	/**
	 * Assigns the EternalStorage contract that has already been created.
	 * Only the owner can execute this function.
	 */
	function setStorage(address _storageAddress) external onlyOwner {
		_storage = _storageAddress;
	}

	/**
	 * Delegates the owner of the current EternalStorage contract.
	 * Only the owner can execute this function.
	 */
	function changeOwner(address newOwner) external onlyOwner {
		EternalStorage(_storage).changeOwner(newOwner);
	}
}

File 4 of 22 : EternalStorage.sol
pragma solidity 0.5.17;

/**
 * Module for persisting states.
 * Stores a map for `uint256`, `string`, `address`, `bytes32`, `bool`, and `int256` type with `bytes32` type as a key.
 */
contract EternalStorage {
	address private currentOwner = msg.sender;

	mapping(bytes32 => uint256) private uIntStorage;
	mapping(bytes32 => string) private stringStorage;
	mapping(bytes32 => address) private addressStorage;
	mapping(bytes32 => bytes32) private bytesStorage;
	mapping(bytes32 => bool) private boolStorage;
	mapping(bytes32 => int256) private intStorage;

	/**
	 * Modifiers to validate that only the owner can execute.
	 */
	modifier onlyCurrentOwner() {
		require(msg.sender == currentOwner, "not current owner");
		_;
	}

	/**
	 * Transfer the owner.
	 * Only the owner can execute this function.
	 */
	function changeOwner(address _newOwner) external {
		require(msg.sender == currentOwner, "not current owner");
		currentOwner = _newOwner;
	}

	// *** Getter Methods ***

	/**
	 * Returns the value of the `uint256` type that mapped to the given key.
	 */
	function getUint(bytes32 _key) external view returns (uint256) {
		return uIntStorage[_key];
	}

	/**
	 * Returns the value of the `string` type that mapped to the given key.
	 */
	function getString(bytes32 _key) external view returns (string memory) {
		return stringStorage[_key];
	}

	/**
	 * Returns the value of the `address` type that mapped to the given key.
	 */
	function getAddress(bytes32 _key) external view returns (address) {
		return addressStorage[_key];
	}

	/**
	 * Returns the value of the `bytes32` type that mapped to the given key.
	 */
	function getBytes(bytes32 _key) external view returns (bytes32) {
		return bytesStorage[_key];
	}

	/**
	 * Returns the value of the `bool` type that mapped to the given key.
	 */
	function getBool(bytes32 _key) external view returns (bool) {
		return boolStorage[_key];
	}

	/**
	 * Returns the value of the `int256` type that mapped to the given key.
	 */
	function getInt(bytes32 _key) external view returns (int256) {
		return intStorage[_key];
	}

	// *** Setter Methods ***

	/**
	 * Maps a value of `uint256` type to a given key.
	 * Only the owner can execute this function.
	 */
	function setUint(bytes32 _key, uint256 _value) external onlyCurrentOwner {
		uIntStorage[_key] = _value;
	}

	/**
	 * Maps a value of `string` type to a given key.
	 * Only the owner can execute this function.
	 */
	function setString(bytes32 _key, string calldata _value)
		external
		onlyCurrentOwner
	{
		stringStorage[_key] = _value;
	}

	/**
	 * Maps a value of `address` type to a given key.
	 * Only the owner can execute this function.
	 */
	function setAddress(bytes32 _key, address _value)
		external
		onlyCurrentOwner
	{
		addressStorage[_key] = _value;
	}

	/**
	 * Maps a value of `bytes32` type to a given key.
	 * Only the owner can execute this function.
	 */
	function setBytes(bytes32 _key, bytes32 _value) external onlyCurrentOwner {
		bytesStorage[_key] = _value;
	}

	/**
	 * Maps a value of `bool` type to a given key.
	 * Only the owner can execute this function.
	 */
	function setBool(bytes32 _key, bool _value) external onlyCurrentOwner {
		boolStorage[_key] = _value;
	}

	/**
	 * Maps a value of `int256` type to a given key.
	 * Only the owner can execute this function.
	 */
	function setInt(bytes32 _key, int256 _value) external onlyCurrentOwner {
		intStorage[_key] = _value;
	}

	// *** Delete Methods ***

	/**
	 * Deletes the value of the `uint256` type that mapped to the given key.
	 * Only the owner can execute this function.
	 */
	function deleteUint(bytes32 _key) external onlyCurrentOwner {
		delete uIntStorage[_key];
	}

	/**
	 * Deletes the value of the `string` type that mapped to the given key.
	 * Only the owner can execute this function.
	 */
	function deleteString(bytes32 _key) external onlyCurrentOwner {
		delete stringStorage[_key];
	}

	/**
	 * Deletes the value of the `address` type that mapped to the given key.
	 * Only the owner can execute this function.
	 */
	function deleteAddress(bytes32 _key) external onlyCurrentOwner {
		delete addressStorage[_key];
	}

	/**
	 * Deletes the value of the `bytes32` type that mapped to the given key.
	 * Only the owner can execute this function.
	 */
	function deleteBytes(bytes32 _key) external onlyCurrentOwner {
		delete bytesStorage[_key];
	}

	/**
	 * Deletes the value of the `bool` type that mapped to the given key.
	 * Only the owner can execute this function.
	 */
	function deleteBool(bytes32 _key) external onlyCurrentOwner {
		delete boolStorage[_key];
	}

	/**
	 * Deletes the value of the `int256` type that mapped to the given key.
	 * Only the owner can execute this function.
	 */
	function deleteInt(bytes32 _key) external onlyCurrentOwner {
		delete intStorage[_key];
	}
}

File 5 of 22 : Decimals.sol
pragma solidity 0.5.17;

import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";

/**
 * Library for emulating calculations involving decimals.
 */
library Decimals {
	using SafeMath for uint256;
	uint120 private constant BASIS_VAKUE = 1000000000000000000;

	/**
	 * @dev Returns the ratio of the first argument to the second argument.
	 * @param _a Numerator.
	 * @param _b Fraction.
	 * @return Calculated ratio.
	 */
	function outOf(uint256 _a, uint256 _b)
		internal
		pure
		returns (uint256 result)
	{
		if (_a == 0) {
			return 0;
		}
		uint256 a = _a.mul(BASIS_VAKUE);
		if (a < _b) {
			return 0;
		}
		return (a.div(_b));
	}

	/**
	 * @dev Returns multiplied the number by 10^18.
	 * @param _a Numerical value to be multiplied.
	 * @return Multiplied value.
	 */
	function mulBasis(uint256 _a) internal pure returns (uint256) {
		return _a.mul(BASIS_VAKUE);
	}

	/**
	 * @dev Returns divisioned the number by 10^18.
	 * This function can use it to restore the number of digits in the result of `outOf`.
	 * @param _a Numerical value to be divisioned.
	 * @return Divisioned value.
	 */
	function divBasis(uint256 _a) internal pure returns (uint256) {
		return _a.div(BASIS_VAKUE);
	}
}

File 6 of 22 : UsingConfig.sol
pragma solidity 0.5.17;

import "../../../interface/IAddressConfig.sol";

/**
 * Module for using AddressConfig contracts.
 */
contract UsingConfig {
	address private _config;

	/**
	 * Initialize the argument as AddressConfig address.
	 */
	constructor(address _addressConfig) public {
		_config = _addressConfig;
	}

	/**
	 * Returns the latest AddressConfig instance.
	 */
	function config() internal view returns (IAddressConfig) {
		return IAddressConfig(_config);
	}

	/**
	 * Returns the latest AddressConfig address.
	 */
	function configAddress() external view returns (address) {
		return _config;
	}
}

File 7 of 22 : IUsingStorage.sol
// SPDX-License-Identifier: MPL-2.0
pragma solidity >=0.5.17;

interface IUsingStorage {
	function getStorageAddress() external view returns (address);

	function createStorage() external;

	function setStorage(address _storageAddress) external;

	function changeOwner(address newOwner) external;
}

File 8 of 22 : IProperty.sol
// SPDX-License-Identifier: MPL-2.0
pragma solidity >=0.5.17;

interface IProperty {
	function author() external view returns (address);

	function changeAuthor(address _nextAuthor) external;

	function changeName(string calldata _name) external;

	function changeSymbol(string calldata _symbol) external;

	function withdraw(address _sender, uint256 _value) external;
}

File 9 of 22 : IPolicy.sol
// SPDX-License-Identifier: MPL-2.0
pragma solidity >=0.5.17;

interface IPolicy {
	function rewards(uint256 _lockups, uint256 _assets)
		external
		view
		returns (uint256);

	function holdersShare(uint256 _amount, uint256 _lockups)
		external
		view
		returns (uint256);

	function authenticationFee(uint256 _assets, uint256 _propertyAssets)
		external
		view
		returns (uint256);

	function marketVotingBlocks() external view returns (uint256);

	function policyVotingBlocks() external view returns (uint256);

	function shareOfTreasury(uint256 _supply) external view returns (uint256);

	function treasury() external view returns (address);

	function capSetter() external view returns (address);
}

File 10 of 22 : IMetricsGroup.sol
// SPDX-License-Identifier: MPL-2.0
pragma solidity >=0.5.17;

interface IMetricsGroup {
	function addGroup(address _addr) external;

	function removeGroup(address _addr) external;

	function isGroup(address _addr) external view returns (bool);

	function totalIssuedMetrics() external view returns (uint256);

	function hasAssets(address _property) external view returns (bool);

	function getMetricsCountPerProperty(address _property)
		external
		view
		returns (uint256);

	function totalAuthenticatedProperties() external view returns (uint256);
}

File 11 of 22 : ILockup.sol
// SPDX-License-Identifier: MPL-2.0
pragma solidity >=0.5.17;

interface ILockup {
	function depositToProperty(address _property, uint256 _amount)
		external
		returns (uint256);

	function depositToProperty(
		address _property,
		uint256 _amount,
		bytes32 _data
	) external returns (uint256);

	function depositToPosition(uint256 _tokenId, uint256 _amount)
		external
		returns (bool);

	function lockup(
		address _from,
		address _property,
		uint256 _value
	) external;

	function update() external;

	function withdraw(address _property, uint256 _amount) external;

	function withdrawByPosition(uint256 _tokenId, uint256 _amount)
		external
		returns (bool);

	function calculateCumulativeRewardPrices()
		external
		view
		returns (
			uint256 _reward,
			uint256 _holders,
			uint256 _interest,
			uint256 _holdersCap
		);

	function calculateRewardAmount(address _property)
		external
		view
		returns (uint256, uint256);

	/**
	 * caution!!!this function is deprecated!!!
	 * use calculateRewardAmount
	 */
	function calculateCumulativeHoldersRewardAmount(address _property)
		external
		view
		returns (uint256);

	function getPropertyValue(address _property)
		external
		view
		returns (uint256);

	function getAllValue() external view returns (uint256);

	function getValue(address _property, address _sender)
		external
		view
		returns (uint256);

	function calculateWithdrawableInterestAmount(
		address _property,
		address _user
	) external view returns (uint256);

	function calculateWithdrawableInterestAmountByPosition(uint256 _tokenId)
		external
		view
		returns (uint256);

	function cap() external view returns (uint256);

	function updateCap(uint256 _cap) external;

	function devMinter() external view returns (address);

	function sTokensManager() external view returns (address);

	function migrateToSTokens(address _property) external returns (uint256);
}

File 12 of 22 : IDevMinter.sol
// SPDX-License-Identifier: MPL-2.0
pragma solidity >=0.5.17;

interface IDevMinter {
	function mint(address account, uint256 amount) external returns (bool);

	function renounceMinter() external;
}

File 13 of 22 : IDev.sol
// SPDX-License-Identifier: MPL-2.0
pragma solidity >=0.5.17;

interface IDev {
	function deposit(address _to, uint256 _amount) external returns (bool);

	function depositFrom(
		address _from,
		address _to,
		uint256 _amount
	) external returns (bool);

	function fee(address _from, uint256 _amount) external returns (bool);
}

File 14 of 22 : IAllocator.sol
// SPDX-License-Identifier: MPL-2.0
pragma solidity >=0.5.17;

interface IAllocator {
	function beforeBalanceChange(
		address _property,
		address _from,
		address _to
	) external;

	function calculateMaxRewardsPerBlock() external view returns (uint256);
}

File 15 of 22 : IAddressConfig.sol
// SPDX-License-Identifier: MPL-2.0
pragma solidity >=0.5.17;

interface IAddressConfig {
	function token() external view returns (address);

	function allocator() external view returns (address);

	function allocatorStorage() external view returns (address);

	function withdraw() external view returns (address);

	function withdrawStorage() external view returns (address);

	function marketFactory() external view returns (address);

	function marketGroup() external view returns (address);

	function propertyFactory() external view returns (address);

	function propertyGroup() external view returns (address);

	function metricsGroup() external view returns (address);

	function metricsFactory() external view returns (address);

	function policy() external view returns (address);

	function policyFactory() external view returns (address);

	function policySet() external view returns (address);

	function policyGroup() external view returns (address);

	function lockup() external view returns (address);

	function lockupStorage() external view returns (address);

	function voteTimes() external view returns (address);

	function voteTimesStorage() external view returns (address);

	function voteCounter() external view returns (address);

	function voteCounterStorage() external view returns (address);

	function setAllocator(address _addr) external;

	function setAllocatorStorage(address _addr) external;

	function setWithdraw(address _addr) external;

	function setWithdrawStorage(address _addr) external;

	function setMarketFactory(address _addr) external;

	function setMarketGroup(address _addr) external;

	function setPropertyFactory(address _addr) external;

	function setPropertyGroup(address _addr) external;

	function setMetricsFactory(address _addr) external;

	function setMetricsGroup(address _addr) external;

	function setPolicyFactory(address _addr) external;

	function setPolicyGroup(address _addr) external;

	function setPolicySet(address _addr) external;

	function setPolicy(address _addr) external;

	function setToken(address _addr) external;

	function setLockup(address _addr) external;

	function setLockupStorage(address _addr) external;

	function setVoteTimes(address _addr) external;

	function setVoteTimesStorage(address _addr) external;

	function setVoteCounter(address _addr) external;

	function setVoteCounterStorage(address _addr) external;
}

File 16 of 22 : IERC721.sol
pragma solidity ^0.5.0;

import "../../introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
contract IERC721 is IERC165 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of NFTs in `owner`'s account.
     */
    function balanceOf(address owner) public view returns (uint256 balance);

    /**
     * @dev Returns the owner of the NFT specified by `tokenId`.
     */
    function ownerOf(uint256 tokenId) public view returns (address owner);

    /**
     * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
     * another (`to`).
     *
     *
     *
     * Requirements:
     * - `from`, `to` cannot be zero.
     * - `tokenId` must be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this
     * NFT by either {approve} or {setApprovalForAll}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public;
    /**
     * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
     * another (`to`).
     *
     * Requirements:
     * - If the caller is not `from`, it must be approved to move this NFT by
     * either {approve} or {setApprovalForAll}.
     */
    function transferFrom(address from, address to, uint256 tokenId) public;
    function approve(address to, uint256 tokenId) public;
    function getApproved(uint256 tokenId) public view returns (address operator);

    function setApprovalForAll(address operator, bool _approved) public;
    function isApprovedForAll(address owner, address operator) public view returns (bool);


    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
}

File 17 of 22 : IERC20.sol
pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */
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(address sender, address recipient, 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);
}

File 18 of 22 : Ownable.sol
pragma solidity ^0.5.0;

import "../GSN/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * 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.
 */
contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

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

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 19 of 22 : SafeMath.sol
pragma solidity ^0.5.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @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) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @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 sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

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

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts 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 mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message 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.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 20 of 22 : IERC165.sol
pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 21 of 22 : Context.sol
pragma solidity ^0.5.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 GSN 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.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 22 of 22 : ISTokensManager.sol
// SPDX-License-Identifier: MPL-2.0
pragma solidity >=0.5.17;

interface ISTokensManager {
	/*
	 * @dev The event fired when a token is minted.
	 * @param tokenId The ID of the created new staking position
	 * @param owner The address of the owner of the new staking position
	 * @param property The address of the Property as the staking destination
	 * @param amount The amount of the new staking position
	 * @param price The latest unit price of the cumulative staking reward
	 */
	event Minted(
		uint256 tokenId,
		address owner,
		address property,
		uint256 amount,
		uint256 price
	);

	/*
	 * @dev The event fired when a token is updated.
	 * @param tokenId The ID of the staking position
	 * @param amount The new staking amount
	 * @param price The latest unit price of the cumulative staking reward
	 * This value equals the 3rd return value of the Lockup.calculateCumulativeRewardPrices
	 * @param cumulativeReward The cumulative withdrawn reward amount
	 * @param pendingReward The pending withdrawal reward amount amount
	 */
	event Updated(
		uint256 tokenId,
		uint256 amount,
		uint256 price,
		uint256 cumulativeReward,
		uint256 pendingReward
	);

	/*
	 * @dev The event fired when toke uri freezed.
	 * @param tokenId The ID of the freezed token uri
	 * @param freezingUser user of freezed token uri
	 */
	event Freezed(uint256 tokenId, address freezingUser);

	/*
	 * @dev Creates the new staking position for the caller.
	 * Mint must be called from the Lockup contract.
	 * @param _owner The address of the owner of the new staking position
	 * @param _property The address of the Property as the staking destination
	 * @param _amount The amount of the new staking position
	 * @param _price The latest unit price of the cumulative staking reward
	 * @param _payload The payload for token
	 * @return uint256 The ID of the created new staking position
	 */
	function mint(
		address _owner,
		address _property,
		uint256 _amount,
		uint256 _price,
		bytes32 _payload
	) external returns (uint256);

	/*
	 * @dev Updates the existing staking position.
	 * Update must be called from the Lockup contract.
	 * @param _tokenId The ID of the staking position
	 * @param _amount The new staking amount
	 * @param _price The latest unit price of the cumulative staking reward
	 * This value equals the 3rd return value of the Lockup.calculateCumulativeRewardPrices
	 * @param _cumulativeReward The cumulative withdrawn reward amount
	 * @param _pendingReward The pending withdrawal reward amount amount
	 * @return bool On success, true will be returned
	 */
	function update(
		uint256 _tokenId,
		uint256 _amount,
		uint256 _price,
		uint256 _cumulativeReward,
		uint256 _pendingReward
	) external returns (bool);

	/*
	 * @dev set token uri information
	 * @param _tokenId The ID of the staking position
	 * @param _data set data
	 */
	function setTokenURIImage(uint256 _tokenId, string calldata _data) external;

	/*
	 * @dev set token uri descriptor
	 * @param _property property address
	 * @param _descriptor descriptor address
	 */
	function setTokenURIDescriptor(address _property, address _descriptor)
		external;

	/*
	 * @dev freeze token uri data
	 * @param _tokenId The ID of the staking position
	 */
	function freezeTokenURI(uint256 _tokenId) external;

	/*
	 * @dev Gets the existing staking position.
	 * @param _tokenId The ID of the staking position
	 * @return address The address of the Property as the staking destination
	 * @return uint256 The amount of the new staking position
	 * @return uint256 The latest unit price of the cumulative staking reward
	 * @return uint256 The cumulative withdrawn reward amount
	 * @return uint256 The pending withdrawal reward amount amount
	 */
	function positions(uint256 _tokenId)
		external
		view
		returns (
			address,
			uint256,
			uint256,
			uint256,
			uint256
		);

	/*
	 * @dev Get the freezed status.
	 * @param _tokenId The ID of the staking position
	 * @return bool If freezed, return true
	 */
	function isFreezed(uint256 _tokenId) external view returns (bool);

	/*
	 * @dev Gets the reward status of the staking position.
	 * @param _tokenId The ID of the staking position
	 * @return uint256 The reward amount of adding the cumulative withdrawn amount
	 to the withdrawable amount
	 * @return uint256 The cumulative withdrawn reward amount
	 * @return uint256 The withdrawable reward amount
	 */
	function rewards(uint256 _tokenId)
		external
		view
		returns (
			uint256,
			uint256,
			uint256
		);

	/*
	 * @dev get token ids by property
	 * @param _property property address
	 * @return uint256[] token id list
	 */
	function positionsOfProperty(address _property)
		external
		view
		returns (uint256[] memory);

	/*
	 * @dev get token ids by owner
	 * @param _owner owner address
	 * @return uint256[] token id list
	 */
	function positionsOfOwner(address _owner)
		external
		view
		returns (uint256[] memory);

	/*
	 * @dev get descriptor address
	 * @param _property property address
	 * @return address descriptor address
	 */
	function descriptorOf(address _property) external view returns (address);

	/*
	 * @dev get the payload
	 * @param _tokenId token id
	 * @return bytes32 stored payload
	 */
	function payloadOf(uint256 _tokenId) external view returns (bytes32);

	/*
	 * @dev get current token id
	 * @return uint256 current token id
	 */
	function currentIndex() external view returns (uint256);
}

Settings
{
  "remappings": [],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_config","type":"address"},{"internalType":"address","name":"_devMinter","type":"address"},{"internalType":"address","name":"_sTokensManager","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"address","name":"_property","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Lockedup","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_cap","type":"uint256"}],"name":"UpdateCap","type":"event"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"___setFallbackInitialCumulativeHoldersRewardCap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"}],"name":"calculateCumulativeHoldersRewardAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"calculateCumulativeRewardPrices","outputs":[{"internalType":"uint256","name":"_reward","type":"uint256"},{"internalType":"uint256","name":"_holders","type":"uint256"},{"internalType":"uint256","name":"_interest","type":"uint256"},{"internalType":"uint256","name":"_holdersCap","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"}],"name":"calculateRewardAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"calculateWithdrawableInterestAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"calculateWithdrawableInterestAmountByPosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"changeOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"configAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"createStorage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositToPosition","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_property","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositToProperty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_property","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_payload","type":"bytes32"}],"name":"depositToProperty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"devMinter","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAllValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"}],"name":"getPropertyValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageAllValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageCumulativeGlobalRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageCumulativeHoldersRewardCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageDIP4GenesisBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageFallbackInitialCumulativeHoldersRewardCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"}],"name":"getStorageInitialCumulativeHoldersRewardCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"}],"name":"getStorageInterestPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageLastCumulativeHoldersPriceCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"}],"name":"getStorageLastCumulativeHoldersRewardAmountPerProperty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageLastCumulativeHoldersRewardPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"}],"name":"getStorageLastCumulativeHoldersRewardPricePerProperty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageLastCumulativeInterestPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getStorageLastInterestPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageLastSameRewardsAmountAndBlock","outputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_block","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getStorageLastStakedInterestPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageLastStakesChangedCumulativeReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"getStoragePendingInterestWithdrawal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"}],"name":"getStoragePropertyValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"},{"internalType":"address","name":"_sender","type":"address"}],"name":"getStorageValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_property","type":"address"},{"internalType":"address","name":"_sender","type":"address"}],"name":"getValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_property","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"lockup","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_property","type":"address"}],"name":"migrateToSTokens","outputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"sTokensManager","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_storageAddress","type":"address"}],"name":"setStorage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"update","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_cap","type":"uint256"}],"name":"updateCap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_property","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawByPosition","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b5060405162004f3638038062004f36833981810160405260608110156200003757600080fd5b5080516020820151604090920151600080546001600160a01b0319166001600160a01b0384161781559192916200006d620000ee565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600380546001600160a01b039384166001600160a01b0319918216179091556004805492909316911617905550620000f2565b3390565b614e3480620001026000396000f3fe608060405234801561001057600080fd5b50600436106102d65760003560e01c806395490d6c11610182578063e78468f0116100e9578063f1a03dd0116100a2578063f578b1c11161007c578063f578b1c1146107eb578063f9c514e4146107f3578063fb971d0114610821578063fd1ac3d814610829576102d6565b8063f1a03dd014610791578063f2fde38b14610799578063f3fef3a3146107bf576102d6565b8063e78468f0146106c4578063edaf329f146106f6578063eea1061714610717578063eebf29361461071f578063ef39f11f14610745578063ef5680961461076b576102d6565b8063c311c5361161013b578063c311c53614610648578063c7ab3a2214610650578063c91dcd8114610676578063d07a30751461067e578063d6c3187114610686578063e35e8cf11461068e576102d6565b806395490d6c1461057b578063a2e62045146105a9578063a6f9dae1146105b1578063a7d68896146105d7578063a92cd330146105f4578063af61a9c51461061a576102d6565b80636576db28116102415780638017333d116101fa5780638da5cb5b116101d45780638da5cb5b1461053d5780638f32d59b146105455780639137c1a71461054d57806394ab898c14610573576102d6565b80638017333d1461050757806381136f5a1461050f57806387407e4c14610535576102d6565b80636576db28146104725780636afa639c14610495578063714d6958146104c3578063715018a6146104cb5780637654f7ab146104d35780637d24d4fa146104db576102d6565b8063523f91b611610293578063523f91b61461039457806355fac3be146103ba578063603da01d146103e857806360cec3701461041657806360e8da7c1461041e578063628a0d051461043b576102d6565b8063076ae477146102db5780630c0d4a0b146103135780630c71c3e814610332578063270d33bc1461033a578063355274ea14610368578063393a4d3414610370575b600080fd5b610301600480360360208110156102f157600080fd5b50356001600160a01b031661084f565b60408051918252519081900360200190f35b6103306004803603602081101561032957600080fd5b50356108d8565b005b61030161092b565b6103016004803603604081101561035057600080fd5b506001600160a01b03813581169160200135166109b0565b610301610a3b565b610378610a4a565b604080516001600160a01b039092168252519081900360200190f35b610301600480360360208110156103aa57600080fd5b50356001600160a01b0316610aaf565b610301600480360360408110156103d057600080fd5b506001600160a01b0381358116916020013516610ad0565b610301600480360360408110156103fe57600080fd5b506001600160a01b0381358116916020013516610ae3565b610301610b05565b6103016004803603602081101561043457600080fd5b5035610b25565b61045e6004803603604081101561045157600080fd5b5080359060200135610bdf565b604080519115158252519081900360200190f35b61045e6004803603604081101561048857600080fd5b5080359060200135610f07565b610301600480360360408110156104ab57600080fd5b506001600160a01b038135811691602001351661138a565b6103016113ac565b6103306113cc565b61030161145d565b610301600480360360408110156104f157600080fd5b506001600160a01b038135169060200135611467565b610301611475565b6103016004803603602081101561052557600080fd5b50356001600160a01b0316611495565b610301611521565b6103786115ab565b61045e6115ba565b6103306004803603602081101561056357600080fd5b50356001600160a01b03166115e0565b610378611649565b6103016004803603604081101561059157600080fd5b506001600160a01b0381358116916020013516611658565b6103306116e6565b610330600480360360208110156105c757600080fd5b50356001600160a01b031661170c565b610330600480360360208110156105ed57600080fd5b50356117bc565b6103016004803603602081101561060a57600080fd5b50356001600160a01b031661194d565b61062261196e565b604080519485526020850193909352838301919091526060830152519081900360800190f35b610301611b36565b6103016004803603602081101561066657600080fd5b50356001600160a01b0316611b56565b610378611b77565b610301611b86565b610378611ba6565b610330600480360360608110156106a457600080fd5b506001600160a01b03813581169160208101359091169060400135611bb5565b610301600480360360608110156106da57600080fd5b506001600160a01b038135169060208101359060400135611e57565b6106fe611e6c565b6040805192835260208301919091528051918290030190f35b610301611f4f565b6103016004803603602081101561073557600080fd5b50356001600160a01b0316611f6f565b6106fe6004803603602081101561075b57600080fd5b50356001600160a01b0316611f89565b6103016004803603602081101561078157600080fd5b50356001600160a01b0316611fd4565b6103016121d6565b610330600480360360208110156107af57600080fd5b50356001600160a01b03166121f6565b610330600480360360408110156107d557600080fd5b506001600160a01b038135169060200135612246565b610301612335565b6103016004803603604081101561080957600080fd5b506001600160a01b0381358116916020013516612355565b61033061236b565b6103016004803603602081101561083f57600080fd5b50356001600160a01b031661244f565b6000610859610a4a565b6001600160a01b031663bd02d0f56108708461245a565b6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156108a457600080fd5b505afa1580156108b8573d6000803e3d6000fd5b505050506040513d60208110156108ce57600080fd5b505190505b919050565b6108e06115ba565b61091f576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b610928816124aa565b50565b6000610935610a4a565b6001600160a01b031663bd02d0f561094b612506565b6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561097f57600080fd5b505afa158015610993573d6000803e3d6000fd5b505050506040513d60208110156109a957600080fd5b5051905090565b60006109ba610a4a565b6001600160a01b031663bd02d0f56109d28585612537565b6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610a0657600080fd5b505afa158015610a1a573d6000803e3d6000fd5b505050506040513d6020811015610a3057600080fd5b505190505b92915050565b6000610a45612335565b905090565b6002546000906001600160a01b0316610a9f576040805162461bcd60e51b81526020600482015260126024820152711cdd1bdc9859d9481a5cc81b9bdd081cd95d60721b604482015290519081900360640190fd5b506002546001600160a01b031690565b6000610ab9610a4a565b6001600160a01b031663bd02d0f5610870846125a0565b6000610adc8383611658565b9392505050565b6000610aed610a4a565b6001600160a01b031663bd02d0f56109d285856125ef565b6000610b0f610a4a565b6001600160a01b031663bd02d0f561094b612652565b600480546040805163133f757160e31b8152928301849052516000926001600160a01b0390921691839182918291829186916399fbab889160248082019260a092909190829003018186803b158015610b7d57600080fd5b505afa158015610b91573d6000803e3d6000fd5b505050506040513d60a0811015610ba757600080fd5b50805160208201516040830151608090930151919650945090925090506000610bd28585858561268e565b5098975050505050505050565b60048054604080516331a9108f60e11b815292830185905251600092859233926001600160a01b0390911691636352211e916024808301926020929190829003018186803b158015610c3057600080fd5b505afa158015610c44573d6000803e3d6000fd5b505050506040513d6020811015610c5a57600080fd5b50516001600160a01b031614610ca8576040805162461bcd60e51b815260206004820152600e60248201526d34b63632b3b0b61039b2b73232b960911b604482015290519081900360640190fd5b600480546040805163133f757160e31b8152928301879052516001600160a01b0390911691600091829182918291829187916399fbab889160248083019260a0929190829003018186803b158015610cff57600080fd5b505afa158015610d13573d6000803e3d6000fd5b505050506040513d60a0811015610d2957600080fd5b5080516020820151604083015160608401516080909401519298509096509450909250905088841015610da3576040805162461bcd60e51b815260206004820152601a60248201527f696e73756666696369656e7420746f6b656e73207374616b6564000000000000604482015290519081900360640190fd5b6000610dad614026565b610db9878787866127f9565b915091508a600014610e2c576040805163f3fef3a360e01b8152336004820152602481018d905290516001600160a01b0389169163f3fef3a391604480830192600092919082900301818387803b158015610e1357600080fd5b505af1158015610e27573d6000803e3d6000fd5b505050505b610e396000888d846128f5565b6000610e4b858463ffffffff61293e16565b9050886001600160a01b03166386904ccf8e610e708f8b61299890919063ffffffff16565b85604001518560006040518663ffffffff1660e01b81526004018086815260200185815260200184815260200183815260200182815260200195505050505050602060405180830381600087803b158015610eca57600080fd5b505af1158015610ede573d6000803e3d6000fd5b505050506040513d6020811015610ef457600080fd5b50519d9c50505050505050505050505050565b60048054604080516331a9108f60e11b815292830185905251600092859233926001600160a01b0390911691636352211e916024808301926020929190829003018186803b158015610f5857600080fd5b505afa158015610f6c573d6000803e3d6000fd5b505050506040513d6020811015610f8257600080fd5b50516001600160a01b031614610fd0576040805162461bcd60e51b815260206004820152600e60248201526d34b63632b3b0b61039b2b73232b960911b604482015290519081900360640190fd5b8261101b576040805162461bcd60e51b81526020600482015260166024820152751a5b1b1959d85b0819195c1bdcda5d08185b5bdd5b9d60521b604482015290519081900360640190fd5b600480546040805163133f757160e31b8152928301879052516001600160a01b0390911691600091829182918291829187916399fbab889160248083019260a0929190829003018186803b15801561107257600080fd5b505afa158015611086573d6000803e3d6000fd5b505050506040513d60a081101561109c57600080fd5b5080516020820151604083015160608401516080909401519298509096509450909250905060006110cb614026565b6110d78787878661268e565b915091506110e86001888d846128f5565b6110f0611ba6565b6001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561112857600080fd5b505afa15801561113c573d6000803e3d6000fd5b505050506040513d602081101561115257600080fd5b5051604080516323b872dd60e01b81523360048201526001600160a01b038a81166024830152604482018f9052915191909216916323b872dd9160648083019260209291908290030181600087803b1580156111ad57600080fd5b505af11580156111c1573d6000803e3d6000fd5b505050506040513d60208110156111d757600080fd5b5051611220576040805162461bcd60e51b815260206004820152601360248201527219195d881d1c985b9cd9995c8819985a5b1959606a1b604482015290519081900360640190fd5b6000886001600160a01b03166386904ccf8e6112458f8b61293e90919063ffffffff16565b604086015161125a8a8963ffffffff61293e16565b61126a8a8a63ffffffff61293e16565b6040518663ffffffff1660e01b81526004018086815260200185815260200184815260200183815260200182815260200195505050505050602060405180830381600087803b1580156112bc57600080fd5b505af11580156112d0573d6000803e3d6000fd5b505050506040513d60208110156112e657600080fd5b505190508061132f576040805162461bcd60e51b815260206004820152601060248201526f6661696c656420746f2075706461746560801b604482015290519081900360640190fd5b604080513381526001600160a01b038a1660208201528082018e905290517f71601c75cd9722fdbd6d57dbb30980d4a4bd6169ba3d456dc18b7f878629d7bf9181900360600190a15060019c9b505050505050505050505050565b6000611394610a4a565b6001600160a01b031663bd02d0f56109d285856129da565b60006113b6610a4a565b6001600160a01b031663bd02d0f561094b612a3c565b6113d46115ba565b611413576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b6000610a45611521565b6000610adc83836000612a84565b600061147f610a4a565b6001600160a01b031663bd02d0f561094b612e14565b6000806114a183612e5c565b90506114ab610a4a565b6001600160a01b031663bd02d0f5826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156114ee57600080fd5b505afa158015611502573d6000803e3d6000fd5b505050506040513d602081101561151857600080fd5b50519392505050565b60008061152c612eaa565b9050611536610a4a565b6001600160a01b031663bd02d0f5826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561157957600080fd5b505afa15801561158d573d6000803e3d6000fd5b505050506040513d60208110156115a357600080fd5b505191505090565b6001546001600160a01b031690565b6001546000906001600160a01b03166115d1612ede565b6001600160a01b031614905090565b6115e86115ba565b611627576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6003546001600160a01b031681565b6000806116658484612ee2565b905061166f610a4a565b6001600160a01b031663bd02d0f5826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156116b257600080fd5b505afa1580156116c6573d6000803e3d6000fd5b505050506040513d60208110156116dc57600080fd5b5051949350505050565b6000806116f1612f34565b915091506116fe8261308a565b61170881436130a8565b5050565b6117146115ba565b611753576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b6002546040805163a6f9dae160e01b81526001600160a01b0384811660048301529151919092169163a6f9dae191602480830192600092919082900301818387803b1580156117a157600080fd5b505af11580156117b5573d6000803e3d6000fd5b5050505050565b60006117c6611ba6565b6001600160a01b0316630505c8c96040518163ffffffff1660e01b815260040160206040518083038186803b1580156117fe57600080fd5b505afa158015611812573d6000803e3d6000fd5b505050506040513d602081101561182857600080fd5b505160408051632cfab26560e21b815290516001600160a01b039092169163b3eac99491600480820192602092909190829003018186803b15801561186c57600080fd5b505afa158015611880573d6000803e3d6000fd5b505050506040513d602081101561189657600080fd5b505190506001600160a01b03811633146118e8576040805162461bcd60e51b815260206004820152600e60248201526d696c6c6567616c2061636365737360901b604482015290519081900360640190fd5b6000806118f361196e565b93505092505061190281613147565b61190b82613165565b61191484613183565b6040805185815290517f3b499d333a6661bd0059d289a2b6f94c0031fa04fa48949544552fcc2021c0bc9181900360200190a150505050565b6000611957610a4a565b6001600160a01b031663bd02d0f5610870846131a1565b600080600080600061197e61092b565b9050600061198a611b36565b905060006119966113ac565b905060006119a2611521565b905060006119ae612f34565b50905060006119bc826131f1565b905060008084116119ce5760006119ee565b6119ee846119e2848a63ffffffff61299816565b9063ffffffff61320b16565b905060006119fa611ba6565b6001600160a01b0316630505c8c96040518163ffffffff1660e01b815260040160206040518083038186803b158015611a3257600080fd5b505afa158015611a46573d6000803e3d6000fd5b505050506040513d6020811015611a5c57600080fd5b505160408051631759a88560e31b8152600481018590526024810188905290516001600160a01b039092169163bacd442891604480820192602092909190829003018186803b158015611aae57600080fd5b505afa158015611ac2573d6000803e3d6000fd5b505050506040513d6020811015611ad857600080fd5b505190506000611aee828963ffffffff61293e16565b90506000611b1288611b06868663ffffffff61299816565b9063ffffffff61293e16565b90506000611b1f8361324d565b959f929e50909c50939a5098505050505050505050565b6000611b40610a4a565b6001600160a01b031663bd02d0f561094b6132aa565b6000611b60610a4a565b6001600160a01b031663bd02d0f5610870846132db565b6004546001600160a01b031681565b6000611b90610a4a565b6001600160a01b031663bd02d0f561094b61332b565b6000546001600160a01b031690565b81611bbe611ba6565b6001600160a01b031663628f043d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611bf657600080fd5b505afa158015611c0a573d6000803e3d6000fd5b505050506040513d6020811015611c2057600080fd5b505160408051638b234cb160e01b81526001600160a01b03848116600483015291519190921691638b234cb1916024808301926020929190829003018186803b158015611c6c57600080fd5b505afa158015611c80573d6000803e3d6000fd5b505050506040513d6020811015611c9657600080fd5b5051611cd35760405162461bcd60e51b815260040180806020018281038252602b815260200180614dd5602b913960400191505060405180910390fd5b611cdb611ba6565b6001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d1357600080fd5b505afa158015611d27573d6000803e3d6000fd5b505050506040513d6020811015611d3d57600080fd5b50516001600160a01b03163314611d9b576040805162461bcd60e51b815260206004820152601760248201527f7468697320697320696c6c6567616c2061646472657373000000000000000000604482015290519081900360640190fd5b81611de4576040805162461bcd60e51b8152602060048201526014602482015273696c6c6567616c206c6f636b75702076616c756560601b604482015290519081900360640190fd5b611dec614026565b611df68486613373565b9050611e066001868686856133a8565b604080516001600160a01b0380881682528616602082015280820185905290517f71601c75cd9722fdbd6d57dbb30980d4a4bd6169ba3d456dc18b7f878629d7bf9181900360600190a15050505050565b6000611e64848484612a84565b949350505050565b6000806000611e79610a4a565b6001600160a01b031663bd02d0f5611e8f6133e4565b6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611ec357600080fd5b505afa158015611ed7573d6000803e3d6000fd5b505050506040513d6020811015611eed57600080fd5b505190506000611f11826d04ee2d6d415b85acef810000000063ffffffff61320b16565b90506000611f43611f36836d04ee2d6d415b85acef810000000063ffffffff61342c16565b849063ffffffff61299816565b91945090925050509091565b6000611f59610a4a565b6001600160a01b031663bd02d0f561094b613485565b600080611f7a61196e565b5050915050610adc81846134cd565b600080600080611f9761196e565b9350509250506000611fa886613522565b90506000611fbc838363ffffffff61299816565b9050611fc884886134cd565b95509350505050915091565b600080611fe18333611658565b905060008111612025576040805162461bcd60e51b815260206004820152600a6024820152691b9bdd081cdd185ad95960b21b604482015290519081900360640190fd5b60006120318433610ae3565b9050600061203f85336109b0565b905061204d8533600061357a565b6120598533600061359a565b60048054604080516320d7b32760e01b815233938101939093526001600160a01b0388811660248501526044840187905260648401869052905191169160009183916320d7b3279160a480830192602092919082900301818787803b1580156120c157600080fd5b505af11580156120d5573d6000803e3d6000fd5b505050506040513d60208110156120eb57600080fd5b5051604080516386904ccf60e01b815260048101839052602481018890526044810187905260006064820181905260848201879052915192935090916001600160a01b038516916386904ccf9160a480830192602092919082900301818787803b15801561215857600080fd5b505af115801561216c573d6000803e3d6000fd5b505050506040513d602081101561218257600080fd5b50519050806121cb576040805162461bcd60e51b815260206004820152601060248201526f6661696c656420746f2075706461746560801b604482015290519081900360640190fd5b509695505050505050565b60006121e0610a4a565b6001600160a01b031663bd02d0f561094b61361b565b6121fe6115ba565b61223d576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b6109288161364c565b6122518233836136ed565b6122a2576040805162461bcd60e51b815260206004820152601a60248201527f696e73756666696369656e7420746f6b656e73207374616b6564000000000000604482015290519081900360640190fd5b6122aa614026565b6122b383613706565b90508115612322576040805163f3fef3a360e01b81523360048201526024810184905290516001600160a01b0385169163f3fef3a391604480830192600092919082900301818387803b15801561230957600080fd5b505af115801561231d573d6000803e3d6000fd5b505050505b6123306000338585856133a8565b505050565b600061233f610a4a565b6001600160a01b031663bd02d0f561094b613816565b6000806123628484613845565b50949350505050565b6123736115ba565b6123b2576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b6002546001600160a01b031615612401576040805162461bcd60e51b815260206004820152600e60248201526d1cdd1bdc9859d9481a5cc81cd95d60921b604482015290519081900360640190fd5b600060405161240f9061404e565b604051809103906000f08015801561242b573d6000803e3d6000fd5b50600280546001600160a01b0319166001600160a01b039290921691909117905550565b6000610a3582611495565b6000816040516020018080614c86602d9139602d01826001600160a01b03166001600160a01b031660601b8152601401915050604051602081830303815290604052805190602001209050919050565b6124b2610a4a565b6001600160a01b031663e2a4853a6124c861361b565b836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b1580156117a157600080fd5b60006040516020018080614cfa60229139602201905060405160208183030381529060405280519060200120905090565b604080517f5f70656e64696e67496e7465726573745769746864726177616c0000000000006020808301919091526001600160601b0319606086811b8216603a85015285901b16604e830152825160428184030181526062909201909252805191012092915050565b604080516e5f696e746572657374546f74616c7360881b60208083019190915260609390931b6001600160601b031916602f820152815180820360230181526043909101909152805191012090565b604080517f5f6c6173745374616b6564496e746572657374507269636500000000000000006020808301919091526001600160601b0319606095861b8116603884015293851b909316604c82015281518082038301815293019052815191012090565b60408051705f6469703447656e65736973426c6f636b60781b602080830191909152825180830360110181526031909201909252805191012090565b6000612698614026565b6126a0611ba6565b6001600160a01b031663628f043d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156126d857600080fd5b505afa1580156126ec573d6000803e3d6000fd5b505050506040513d602081101561270257600080fd5b505160408051638b234cb160e01b81526001600160a01b03898116600483015291519190921691638b234cb1916024808301926020929190829003018186803b15801561274e57600080fd5b505afa158015612762573d6000803e3d6000fd5b505050506040513d602081101561277857600080fd5b50516127ba5760008060008061278c61196e565b6040805160808101825294855260208501939093529183015260608201526000965094506127f09350505050565b60006127c4614026565b6127ce87876139d0565b925050915060006127e8868461293e90919063ffffffff16565b945090925050505b94509492505050565b6000612803614026565b600061280d614026565b6128198888888861268e565b600354604080516340c10f1960e01b81523360048201526024810185905290519395509193506001600160a01b0316916340c10f19916044808201926020929091908290030181600087803b15801561287157600080fd5b505af1158015612885573d6000803e3d6000fd5b505050506040513d602081101561289b57600080fd5b50516128e0576040805162461bcd60e51b815260206004820152600f60248201526e19195d881b5a5b9d0819985a5b1959608a1b604482015290519081900360640190fd5b6128e86116e6565b9097909650945050505050565b6128ff8382613a4d565b831561291d5761290e82613af7565b6129188383613b1e565b612930565b61292682613b47565b6129308383613b63565b6129386116e6565b50505050565b600082820183811015610adc576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000610adc83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613b8e565b60408051755f6c6173744c617374496e746572657374507269636560501b6020808301919091526001600160601b0319606086811b8216603685015285901b16604a8301528251603e818403018152605e909201909252805191012092915050565b604080517f306c61737443756d756c6174697665496e7465726573745072696365000000006020808301919091528251808303601c018152603c909201909252805191012090565b600083612a8f611ba6565b6001600160a01b031663628f043d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ac757600080fd5b505afa158015612adb573d6000803e3d6000fd5b505050506040513d6020811015612af157600080fd5b505160408051638b234cb160e01b81526001600160a01b03848116600483015291519190921691638b234cb1916024808301926020929190829003018186803b158015612b3d57600080fd5b505afa158015612b51573d6000803e3d6000fd5b505050506040513d6020811015612b6757600080fd5b5051612ba45760405162461bcd60e51b815260040180806020018281038252602b815260200180614dd5602b913960400191505060405180910390fd5b600080600080612bb261196e565b9350935093509350612be760018a8a6040518060800160405280898152602001888152602001878152602001868152506128f5565b612bef611ba6565b6001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c2757600080fd5b505afa158015612c3b573d6000803e3d6000fd5b505050506040513d6020811015612c5157600080fd5b5051604080516323b872dd60e01b81523360048201526001600160a01b038c81166024830152604482018c9052915191909216916323b872dd9160648083019260209291908290030181600087803b158015612cac57600080fd5b505af1158015612cc0573d6000803e3d6000fd5b505050506040513d6020811015612cd657600080fd5b5051612d1f576040805162461bcd60e51b815260206004820152601360248201527219195d881d1c985b9cd9995c8819985a5b1959606a1b604482015290519081900360640190fd5b60048054604080516320d7b32760e01b815233938101939093526001600160a01b038c81166024850152604484018c905260648401869052608484018b9052905160009391909216916320d7b3279160a48082019260209290919082900301818787803b158015612d8f57600080fd5b505af1158015612da3573d6000803e3d6000fd5b505050506040513d6020811015612db957600080fd5b5051604080513381526001600160a01b038d1660208201528082018c905290519192507f71601c75cd9722fdbd6d57dbb30980d4a4bd6169ba3d456dc18b7f878629d7bf919081900360600190a19998505050505050505050565b604080517f5f63756d756c6174697665476c6f62616c526577617264730000000000000000602080830191909152825180830360180181526038909201909252805191012090565b604080516d5f70726f706572747956616c756560901b60208083019190915260609390931b6001600160601b031916602e820152815180820360220181526042909101909152805191012090565b60408051685f616c6c56616c756560b81b602080830191909152825180830360090181526029909201909252805191012090565b3390565b60408051655f76616c756560d01b6020808301919091526001600160601b0319606086811b8216602685015285901b16603a8301528251602e818403018152604e909201909252805191012092915050565b6000806000612f41611ba6565b6001600160a01b031663aa5dcecc6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7957600080fd5b505afa158015612f8d573d6000803e3d6000fd5b505050506040513d6020811015612fa357600080fd5b505160408051633aa5460b60e01b815290516001600160a01b0390921691633aa5460b91600480820192602092909190829003018186803b158015612fe757600080fd5b505afa158015612ffb573d6000803e3d6000fd5b505050506040513d602081101561301157600080fd5b50519050600080613020611e6c565b9150915060008383146130335782613035565b835b90506000808311613047576000613057565b613057438463ffffffff61299816565b9050600061306b838363ffffffff61342c16565b9050600061307b82611b06611475565b98509596505050505050509091565b613092610a4a565b6001600160a01b031663e2a4853a6124c8612e14565b60006130cc82611b06856d04ee2d6d415b85acef810000000063ffffffff61342c16565b90506130d6610a4a565b6001600160a01b031663e2a4853a6130ec6133e4565b836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b15801561312a57600080fd5b505af115801561313e573d6000803e3d6000fd5b50505050505050565b61314f610a4a565b6001600160a01b031663e2a4853a6124c861332b565b61316d610a4a565b6001600160a01b031663e2a4853a6124c8613485565b61318b610a4a565b6001600160a01b031663e2a4853a6124c8613816565b6000816040516020018080614d8960229139602201826001600160a01b03166001600160a01b031660601b8152601401915050604051602081830303815290604052805190602001209050919050565b6000610a3582670de0b6b3a764000063ffffffff61342c16565b6000610adc83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613c25565b600080613258611b86565b90506000613264611f4f565b9050600061328f613273612335565b613283878563ffffffff61299816565b9063ffffffff61342c16565b90506132a1838263ffffffff61293e16565b95945050505050565b60006040516020018080614cd960219139602101905060405160208183030381529060405280519060200120905090565b6000816040516020018080614d1c602c9139602c01826001600160a01b03166001600160a01b031660601b8152601401915050604051602081830303815290604052805190602001209050919050565b604080517f5f63756d756c6174697665486f6c6465727352657761726443617000000000006020808301919091528251808303601b018152603b909201909252805191012090565b61337b614026565b6000613385614026565b61338f8585613845565b9150915061339e85858461357a565b611e648585613c8a565b6133b783858360400151613cb2565b6133c3858484846128f5565b84156133d9576133d4838584613cd2565b6117b5565b6117b5838584613cfd565b604080517f5f4c61737453616d6552657761726473416d6f756e74416e64426c6f636b00006020808301919091528251808303601e018152603e909201909252805191012090565b60008261343b57506000610a35565b8282028284828161344857fe5b0414610adc5760405162461bcd60e51b8152600401808060200182810382526021815260200180614d486021913960400191505060405180910390fd5b604080517f5f6c61737443756d756c6174697665486f6c64657273507269636543617000006020808301919091528251808303601e018152603e909201909252805191012090565b60008060006134db8461084f565b6134e485611b56565b9150915060006135066134f686611495565b613283888563ffffffff61299816565b9050613518838263ffffffff61293e16565b9695505050505050565b60008061352e8361194d565b9050801561353d5790506108d3565b600061354884611b56565b118061355c5750600061355a84611495565b115b15613571576135696121d6565b9150506108d3565b50600092915050565b613582610a4a565b6001600160a01b031663e2a4853a6130ec8585612537565b60006135a68484612ee2565b90506135b0610a4a565b6001600160a01b031663e2a4853a82846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b1580156135fd57600080fd5b505af1158015613611573d6000803e3d6000fd5b5050505050505050565b60006040516020018080614dab602a9139602a01905060405160208183030381529060405280519060200120905090565b6001600160a01b0381166136915760405162461bcd60e51b8152600401808060200182810382526026815260200180614cb36026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000806136fa8585611658565b90921115949350505050565b61370e614026565b6000613718614026565b6137228433613845565b915091506137328433600061357a565b61374184338360400151613cb2565b61374b8433613c8a565b600354604080516340c10f1960e01b81523360048201526024810185905290516001600160a01b03909216916340c10f19916044808201926020929091908290030181600087803b15801561379f57600080fd5b505af11580156137b3573d6000803e3d6000fd5b505050506040513d60208110156137c957600080fd5b505161380e576040805162461bcd60e51b815260206004820152600f60248201526e19195d881b5a5b9d0819985a5b1959608a1b604482015290519081900360640190fd5b610adc6116e6565b604080516305f6361760e41b602080830191909152825180830360040181526024909201909252805191012090565b600061384f614026565b613857611ba6565b6001600160a01b031663628f043d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561388f57600080fd5b505afa1580156138a3573d6000803e3d6000fd5b505050506040513d60208110156138b957600080fd5b505160408051638b234cb160e01b81526001600160a01b03878116600483015291519190921691638b234cb1916024808301926020929190829003018186803b15801561390557600080fd5b505afa158015613919573d6000803e3d6000fd5b505050506040513d602081101561392f57600080fd5b50516139715760008060008061394361196e565b6040805160808101825294855260208501939093529183015260608201526000965094506139c99350505050565b600061397d85856109b0565b9050600061398b8686613d1b565b90506000613997614026565b6139a18888613d82565b925050915060006139bf84611b06878661293e90919063ffffffff16565b9650909450505050505b9250929050565b6000806139db614026565b6000806000806139e961196e565b9350935093509350600088831015613a02576000613a1e565b613a1e613a198b613283868d63ffffffff61299816565b613e18565b604080516080810182529687526020870195909552938501839052506060840152909450925090509250925092565b6000613a5d8260200151846134cd565b9050613a6883611b56565b158015613a7b5750613a798361194d565b155b8015613a8d5750613a8b83611495565b155b15613aa057613aa0838360600151613e32565b8151613aab90613eab565b613ab88260200151613ec9565b613ac58260400151613ee7565b613acf8382613f05565b613add838360200151613f24565b613aea8260600151613147565b6123308260200151613165565b6000613b01611521565b9050613b13818363ffffffff61293e16565b905061170881613f43565b6000613b2983611495565b9050613b3b818363ffffffff61293e16565b90506123308382613fa4565b6000613b51611521565b9050613b13818363ffffffff61299816565b6000613b6e83611495565b90506000613b82828463ffffffff61299816565b90506129388482613fa4565b60008184841115613c1d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613be2578181015183820152602001613bca565b50505050905090810190601f168015613c0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008183613c745760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613be2578181015183820152602001613bca565b506000838581613c8057fe5b0495945050505050565b6000613c9583610aaf565b905080613ca2848461138a565b1461233057612330838383614006565b613cba610a4a565b6001600160a01b031663e2a4853a6130ec85856125ef565b6000613cde8484611658565b9050613cf0818363ffffffff61293e16565b905061293884848361359a565b6000613d098484611658565b9050613cf0818363ffffffff61299816565b600080613d28848461138a565b90506000613d3585610aaf565b90506000613d49828463ffffffff61299816565b90506000613d578787611658565b90506000613d6b838363ffffffff61342c16565b9050613d7681613e18565b98975050505050505050565b600080613d8d614026565b6000613d998686611658565b90506000613da78787610ae3565b9050600080600080613db761196e565b9350935093509350600085831015613dd0576000613de7565b613de7613a1988613283868a63ffffffff61299816565b6040805160808101825296875260208701959095529385018390525060608401529096509450925050509250925092565b6000610a3582670de0b6b3a764000063ffffffff61320b16565b613e3a610a4a565b6001600160a01b031663e2a4853a613e51846131a1565b836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015613e8f57600080fd5b505af1158015613ea3573d6000803e3d6000fd5b505050505050565b613eb3610a4a565b6001600160a01b031663e2a4853a6124c8612506565b613ed1610a4a565b6001600160a01b031663e2a4853a6124c86132aa565b613eef610a4a565b6001600160a01b031663e2a4853a6124c8612a3c565b613f0d610a4a565b6001600160a01b031663e2a4853a613e518461245a565b613f2c610a4a565b6001600160a01b031663e2a4853a613e51846132db565b6000613f4d612eaa565b9050613f57610a4a565b6001600160a01b031663e2a4853a82846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015613e8f57600080fd5b6000613faf83612e5c565b9050613fb9610a4a565b6001600160a01b031663e2a4853a82846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b15801561312a57600080fd5b61400e610a4a565b6001600160a01b031663e2a4853a6130ec85856129da565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b610c2a8061405c8339019056fe6080604052600080546001600160a01b0319163317905534801561002257600080fd5b50610bf8806100326000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c8063a6f9dae1116100ad578063d5d2c56011610071578063d5d2c560146103f5578063dc97d96214610418578063e2a4853a14610435578063e2b202bf14610458578063f6bb3cc41461047557610121565b8063a6f9dae114610332578063abfdcced14610358578063bd02d0f51461037d578063c031a180146103ac578063ca446dd9146103c957610121565b8063616b59f6116100f4578063616b59f6146101be5780636e899550146101db5780637ae1cfca146102525780638c16009514610283578063986e791a146102a057610121565b80630e14a3761461012657806321f8a721146101455780632c62ff2d1461017e5780633e49bed01461019b575b600080fd5b6101436004803603602081101561013c57600080fd5b5035610492565b005b6101626004803603602081101561015b57600080fd5b50356104fd565b604080516001600160a01b039092168252519081900360200190f35b6101436004803603602081101561019457600080fd5b5035610518565b610143600480360360408110156101b157600080fd5b508035906020013561057d565b610143600480360360208110156101d457600080fd5b50356105dc565b610143600480360360408110156101f157600080fd5b8135919081019060408101602082013564010000000081111561021357600080fd5b82018360208201111561022557600080fd5b8035906020019184600183028401116401000000008311171561024757600080fd5b50909250905061063a565b61026f6004803603602081101561026857600080fd5b50356106a6565b604080519115158252519081900360200190f35b6101436004803603602081101561029957600080fd5b50356106bb565b6102bd600480360360208110156102b657600080fd5b5035610719565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102f75781810151838201526020016102df565b50505050905090810190601f1680156103245780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101436004803603602081101561034857600080fd5b50356001600160a01b03166107b8565b6101436004803603604081101561036e57600080fd5b50803590602001351515610827565b61039a6004803603602081101561039357600080fd5b5035610894565b60408051918252519081900360200190f35b61039a600480360360208110156103c257600080fd5b50356108a6565b610143600480360360408110156103df57600080fd5b50803590602001356001600160a01b03166108b8565b6101436004803603604081101561040b57600080fd5b5080359060200135610933565b61039a6004803603602081101561042e57600080fd5b5035610992565b6101436004803603604081101561044b57600080fd5b50803590602001356109a4565b6101436004803603602081101561046e57600080fd5b5035610a03565b6101436004803603602081101561048b57600080fd5b5035610a61565b6000546001600160a01b031633146104df576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600090815260036020526040902080546001600160a01b0319169055565b6000908152600360205260409020546001600160a01b031690565b6000546001600160a01b03163314610565576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b6000908152600560205260409020805460ff19169055565b6000546001600160a01b031633146105ca576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b60009182526006602052604090912055565b6000546001600160a01b03163314610629576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600090815260046020526040812055565b6000546001600160a01b03163314610687576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b60008381526002602052604090206106a0908383610ac8565b50505050565b60009081526005602052604090205460ff1690565b6000546001600160a01b03163314610708576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600090815260066020526040812055565b600081815260026020818152604092839020805484516001821615610100026000190190911693909304601f810183900483028401830190945283835260609390918301828280156107ac5780601f10610781576101008083540402835291602001916107ac565b820191906000526020600020905b81548152906001019060200180831161078f57829003601f168201915b50505050509050919050565b6000546001600160a01b03163314610805576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610874576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600091825260056020526040909120805460ff1916911515919091179055565b60009081526001602052604090205490565b60009081526004602052604090205490565b6000546001600160a01b03163314610905576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b60009182526003602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b6000546001600160a01b03163314610980576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b60009182526004602052604090912055565b60009081526006602052604090205490565b6000546001600160a01b031633146109f1576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b60009182526001602052604090912055565b6000546001600160a01b03163314610a50576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600090815260016020526040812055565b6000546001600160a01b03163314610aae576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b6000818152600260205260408120610ac591610b46565b50565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610b095782800160ff19823516178555610b36565b82800160010185558215610b36579182015b82811115610b36578235825591602001919060010190610b1b565b50610b42929150610b86565b5090565b50805460018160011615610100020316600290046000825580601f10610b6c5750610ac5565b601f016020900490600052602060002090810190610ac591905b610ba091905b80821115610b425760008155600101610b8c565b9056fe6e6f742063757272656e74206f776e6572000000000000000000000000000000a265627a7a723158209c0dc6304ed22c7d92cc360e2d87ee5a1b86eed066d6e22f0e7f1913d0c1658364736f6c63430005110032306c61737443756d756c6174697665486f6c64657273526577617264416d6f756e7450657250726f70657274794f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373306c61737443756d756c6174697665486f6c6465727352657761726450726963655f6c6173745374616b65734368616e67656443756d756c6174697665526577617264306c61737443756d756c6174697665486f6c64657273526577617264507269636550657250726f7065727479536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725f696e697469616c43756d756c6174697665486f6c646572735265776172644361705f66616c6c6261636b496e697469616c43756d756c6174697665486f6c64657273526577617264436170756e61626c6520746f207374616b6520746f20756e61757468656e746963617465642070726f7065727479a265627a7a72315820758134f3c0e01748dc3c48c5c4e20479f4f773857f3881e2ed813d29f61b419564736f6c634300051100320000000000000000000000001d415aa39d647834786eb9b5a333a50e9935b7960000000000000000000000004596dae6955693c50522f1b06bdbf7b93ceb547900000000000000000000000050489ff5f879a44c87bba85287729d663b18ced5

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102d65760003560e01c806395490d6c11610182578063e78468f0116100e9578063f1a03dd0116100a2578063f578b1c11161007c578063f578b1c1146107eb578063f9c514e4146107f3578063fb971d0114610821578063fd1ac3d814610829576102d6565b8063f1a03dd014610791578063f2fde38b14610799578063f3fef3a3146107bf576102d6565b8063e78468f0146106c4578063edaf329f146106f6578063eea1061714610717578063eebf29361461071f578063ef39f11f14610745578063ef5680961461076b576102d6565b8063c311c5361161013b578063c311c53614610648578063c7ab3a2214610650578063c91dcd8114610676578063d07a30751461067e578063d6c3187114610686578063e35e8cf11461068e576102d6565b806395490d6c1461057b578063a2e62045146105a9578063a6f9dae1146105b1578063a7d68896146105d7578063a92cd330146105f4578063af61a9c51461061a576102d6565b80636576db28116102415780638017333d116101fa5780638da5cb5b116101d45780638da5cb5b1461053d5780638f32d59b146105455780639137c1a71461054d57806394ab898c14610573576102d6565b80638017333d1461050757806381136f5a1461050f57806387407e4c14610535576102d6565b80636576db28146104725780636afa639c14610495578063714d6958146104c3578063715018a6146104cb5780637654f7ab146104d35780637d24d4fa146104db576102d6565b8063523f91b611610293578063523f91b61461039457806355fac3be146103ba578063603da01d146103e857806360cec3701461041657806360e8da7c1461041e578063628a0d051461043b576102d6565b8063076ae477146102db5780630c0d4a0b146103135780630c71c3e814610332578063270d33bc1461033a578063355274ea14610368578063393a4d3414610370575b600080fd5b610301600480360360208110156102f157600080fd5b50356001600160a01b031661084f565b60408051918252519081900360200190f35b6103306004803603602081101561032957600080fd5b50356108d8565b005b61030161092b565b6103016004803603604081101561035057600080fd5b506001600160a01b03813581169160200135166109b0565b610301610a3b565b610378610a4a565b604080516001600160a01b039092168252519081900360200190f35b610301600480360360208110156103aa57600080fd5b50356001600160a01b0316610aaf565b610301600480360360408110156103d057600080fd5b506001600160a01b0381358116916020013516610ad0565b610301600480360360408110156103fe57600080fd5b506001600160a01b0381358116916020013516610ae3565b610301610b05565b6103016004803603602081101561043457600080fd5b5035610b25565b61045e6004803603604081101561045157600080fd5b5080359060200135610bdf565b604080519115158252519081900360200190f35b61045e6004803603604081101561048857600080fd5b5080359060200135610f07565b610301600480360360408110156104ab57600080fd5b506001600160a01b038135811691602001351661138a565b6103016113ac565b6103306113cc565b61030161145d565b610301600480360360408110156104f157600080fd5b506001600160a01b038135169060200135611467565b610301611475565b6103016004803603602081101561052557600080fd5b50356001600160a01b0316611495565b610301611521565b6103786115ab565b61045e6115ba565b6103306004803603602081101561056357600080fd5b50356001600160a01b03166115e0565b610378611649565b6103016004803603604081101561059157600080fd5b506001600160a01b0381358116916020013516611658565b6103306116e6565b610330600480360360208110156105c757600080fd5b50356001600160a01b031661170c565b610330600480360360208110156105ed57600080fd5b50356117bc565b6103016004803603602081101561060a57600080fd5b50356001600160a01b031661194d565b61062261196e565b604080519485526020850193909352838301919091526060830152519081900360800190f35b610301611b36565b6103016004803603602081101561066657600080fd5b50356001600160a01b0316611b56565b610378611b77565b610301611b86565b610378611ba6565b610330600480360360608110156106a457600080fd5b506001600160a01b03813581169160208101359091169060400135611bb5565b610301600480360360608110156106da57600080fd5b506001600160a01b038135169060208101359060400135611e57565b6106fe611e6c565b6040805192835260208301919091528051918290030190f35b610301611f4f565b6103016004803603602081101561073557600080fd5b50356001600160a01b0316611f6f565b6106fe6004803603602081101561075b57600080fd5b50356001600160a01b0316611f89565b6103016004803603602081101561078157600080fd5b50356001600160a01b0316611fd4565b6103016121d6565b610330600480360360208110156107af57600080fd5b50356001600160a01b03166121f6565b610330600480360360408110156107d557600080fd5b506001600160a01b038135169060200135612246565b610301612335565b6103016004803603604081101561080957600080fd5b506001600160a01b0381358116916020013516612355565b61033061236b565b6103016004803603602081101561083f57600080fd5b50356001600160a01b031661244f565b6000610859610a4a565b6001600160a01b031663bd02d0f56108708461245a565b6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156108a457600080fd5b505afa1580156108b8573d6000803e3d6000fd5b505050506040513d60208110156108ce57600080fd5b505190505b919050565b6108e06115ba565b61091f576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b610928816124aa565b50565b6000610935610a4a565b6001600160a01b031663bd02d0f561094b612506565b6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561097f57600080fd5b505afa158015610993573d6000803e3d6000fd5b505050506040513d60208110156109a957600080fd5b5051905090565b60006109ba610a4a565b6001600160a01b031663bd02d0f56109d28585612537565b6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610a0657600080fd5b505afa158015610a1a573d6000803e3d6000fd5b505050506040513d6020811015610a3057600080fd5b505190505b92915050565b6000610a45612335565b905090565b6002546000906001600160a01b0316610a9f576040805162461bcd60e51b81526020600482015260126024820152711cdd1bdc9859d9481a5cc81b9bdd081cd95d60721b604482015290519081900360640190fd5b506002546001600160a01b031690565b6000610ab9610a4a565b6001600160a01b031663bd02d0f5610870846125a0565b6000610adc8383611658565b9392505050565b6000610aed610a4a565b6001600160a01b031663bd02d0f56109d285856125ef565b6000610b0f610a4a565b6001600160a01b031663bd02d0f561094b612652565b600480546040805163133f757160e31b8152928301849052516000926001600160a01b0390921691839182918291829186916399fbab889160248082019260a092909190829003018186803b158015610b7d57600080fd5b505afa158015610b91573d6000803e3d6000fd5b505050506040513d60a0811015610ba757600080fd5b50805160208201516040830151608090930151919650945090925090506000610bd28585858561268e565b5098975050505050505050565b60048054604080516331a9108f60e11b815292830185905251600092859233926001600160a01b0390911691636352211e916024808301926020929190829003018186803b158015610c3057600080fd5b505afa158015610c44573d6000803e3d6000fd5b505050506040513d6020811015610c5a57600080fd5b50516001600160a01b031614610ca8576040805162461bcd60e51b815260206004820152600e60248201526d34b63632b3b0b61039b2b73232b960911b604482015290519081900360640190fd5b600480546040805163133f757160e31b8152928301879052516001600160a01b0390911691600091829182918291829187916399fbab889160248083019260a0929190829003018186803b158015610cff57600080fd5b505afa158015610d13573d6000803e3d6000fd5b505050506040513d60a0811015610d2957600080fd5b5080516020820151604083015160608401516080909401519298509096509450909250905088841015610da3576040805162461bcd60e51b815260206004820152601a60248201527f696e73756666696369656e7420746f6b656e73207374616b6564000000000000604482015290519081900360640190fd5b6000610dad614026565b610db9878787866127f9565b915091508a600014610e2c576040805163f3fef3a360e01b8152336004820152602481018d905290516001600160a01b0389169163f3fef3a391604480830192600092919082900301818387803b158015610e1357600080fd5b505af1158015610e27573d6000803e3d6000fd5b505050505b610e396000888d846128f5565b6000610e4b858463ffffffff61293e16565b9050886001600160a01b03166386904ccf8e610e708f8b61299890919063ffffffff16565b85604001518560006040518663ffffffff1660e01b81526004018086815260200185815260200184815260200183815260200182815260200195505050505050602060405180830381600087803b158015610eca57600080fd5b505af1158015610ede573d6000803e3d6000fd5b505050506040513d6020811015610ef457600080fd5b50519d9c50505050505050505050505050565b60048054604080516331a9108f60e11b815292830185905251600092859233926001600160a01b0390911691636352211e916024808301926020929190829003018186803b158015610f5857600080fd5b505afa158015610f6c573d6000803e3d6000fd5b505050506040513d6020811015610f8257600080fd5b50516001600160a01b031614610fd0576040805162461bcd60e51b815260206004820152600e60248201526d34b63632b3b0b61039b2b73232b960911b604482015290519081900360640190fd5b8261101b576040805162461bcd60e51b81526020600482015260166024820152751a5b1b1959d85b0819195c1bdcda5d08185b5bdd5b9d60521b604482015290519081900360640190fd5b600480546040805163133f757160e31b8152928301879052516001600160a01b0390911691600091829182918291829187916399fbab889160248083019260a0929190829003018186803b15801561107257600080fd5b505afa158015611086573d6000803e3d6000fd5b505050506040513d60a081101561109c57600080fd5b5080516020820151604083015160608401516080909401519298509096509450909250905060006110cb614026565b6110d78787878661268e565b915091506110e86001888d846128f5565b6110f0611ba6565b6001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561112857600080fd5b505afa15801561113c573d6000803e3d6000fd5b505050506040513d602081101561115257600080fd5b5051604080516323b872dd60e01b81523360048201526001600160a01b038a81166024830152604482018f9052915191909216916323b872dd9160648083019260209291908290030181600087803b1580156111ad57600080fd5b505af11580156111c1573d6000803e3d6000fd5b505050506040513d60208110156111d757600080fd5b5051611220576040805162461bcd60e51b815260206004820152601360248201527219195d881d1c985b9cd9995c8819985a5b1959606a1b604482015290519081900360640190fd5b6000886001600160a01b03166386904ccf8e6112458f8b61293e90919063ffffffff16565b604086015161125a8a8963ffffffff61293e16565b61126a8a8a63ffffffff61293e16565b6040518663ffffffff1660e01b81526004018086815260200185815260200184815260200183815260200182815260200195505050505050602060405180830381600087803b1580156112bc57600080fd5b505af11580156112d0573d6000803e3d6000fd5b505050506040513d60208110156112e657600080fd5b505190508061132f576040805162461bcd60e51b815260206004820152601060248201526f6661696c656420746f2075706461746560801b604482015290519081900360640190fd5b604080513381526001600160a01b038a1660208201528082018e905290517f71601c75cd9722fdbd6d57dbb30980d4a4bd6169ba3d456dc18b7f878629d7bf9181900360600190a15060019c9b505050505050505050505050565b6000611394610a4a565b6001600160a01b031663bd02d0f56109d285856129da565b60006113b6610a4a565b6001600160a01b031663bd02d0f561094b612a3c565b6113d46115ba565b611413576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b6000610a45611521565b6000610adc83836000612a84565b600061147f610a4a565b6001600160a01b031663bd02d0f561094b612e14565b6000806114a183612e5c565b90506114ab610a4a565b6001600160a01b031663bd02d0f5826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156114ee57600080fd5b505afa158015611502573d6000803e3d6000fd5b505050506040513d602081101561151857600080fd5b50519392505050565b60008061152c612eaa565b9050611536610a4a565b6001600160a01b031663bd02d0f5826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561157957600080fd5b505afa15801561158d573d6000803e3d6000fd5b505050506040513d60208110156115a357600080fd5b505191505090565b6001546001600160a01b031690565b6001546000906001600160a01b03166115d1612ede565b6001600160a01b031614905090565b6115e86115ba565b611627576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6003546001600160a01b031681565b6000806116658484612ee2565b905061166f610a4a565b6001600160a01b031663bd02d0f5826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156116b257600080fd5b505afa1580156116c6573d6000803e3d6000fd5b505050506040513d60208110156116dc57600080fd5b5051949350505050565b6000806116f1612f34565b915091506116fe8261308a565b61170881436130a8565b5050565b6117146115ba565b611753576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b6002546040805163a6f9dae160e01b81526001600160a01b0384811660048301529151919092169163a6f9dae191602480830192600092919082900301818387803b1580156117a157600080fd5b505af11580156117b5573d6000803e3d6000fd5b5050505050565b60006117c6611ba6565b6001600160a01b0316630505c8c96040518163ffffffff1660e01b815260040160206040518083038186803b1580156117fe57600080fd5b505afa158015611812573d6000803e3d6000fd5b505050506040513d602081101561182857600080fd5b505160408051632cfab26560e21b815290516001600160a01b039092169163b3eac99491600480820192602092909190829003018186803b15801561186c57600080fd5b505afa158015611880573d6000803e3d6000fd5b505050506040513d602081101561189657600080fd5b505190506001600160a01b03811633146118e8576040805162461bcd60e51b815260206004820152600e60248201526d696c6c6567616c2061636365737360901b604482015290519081900360640190fd5b6000806118f361196e565b93505092505061190281613147565b61190b82613165565b61191484613183565b6040805185815290517f3b499d333a6661bd0059d289a2b6f94c0031fa04fa48949544552fcc2021c0bc9181900360200190a150505050565b6000611957610a4a565b6001600160a01b031663bd02d0f5610870846131a1565b600080600080600061197e61092b565b9050600061198a611b36565b905060006119966113ac565b905060006119a2611521565b905060006119ae612f34565b50905060006119bc826131f1565b905060008084116119ce5760006119ee565b6119ee846119e2848a63ffffffff61299816565b9063ffffffff61320b16565b905060006119fa611ba6565b6001600160a01b0316630505c8c96040518163ffffffff1660e01b815260040160206040518083038186803b158015611a3257600080fd5b505afa158015611a46573d6000803e3d6000fd5b505050506040513d6020811015611a5c57600080fd5b505160408051631759a88560e31b8152600481018590526024810188905290516001600160a01b039092169163bacd442891604480820192602092909190829003018186803b158015611aae57600080fd5b505afa158015611ac2573d6000803e3d6000fd5b505050506040513d6020811015611ad857600080fd5b505190506000611aee828963ffffffff61293e16565b90506000611b1288611b06868663ffffffff61299816565b9063ffffffff61293e16565b90506000611b1f8361324d565b959f929e50909c50939a5098505050505050505050565b6000611b40610a4a565b6001600160a01b031663bd02d0f561094b6132aa565b6000611b60610a4a565b6001600160a01b031663bd02d0f5610870846132db565b6004546001600160a01b031681565b6000611b90610a4a565b6001600160a01b031663bd02d0f561094b61332b565b6000546001600160a01b031690565b81611bbe611ba6565b6001600160a01b031663628f043d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611bf657600080fd5b505afa158015611c0a573d6000803e3d6000fd5b505050506040513d6020811015611c2057600080fd5b505160408051638b234cb160e01b81526001600160a01b03848116600483015291519190921691638b234cb1916024808301926020929190829003018186803b158015611c6c57600080fd5b505afa158015611c80573d6000803e3d6000fd5b505050506040513d6020811015611c9657600080fd5b5051611cd35760405162461bcd60e51b815260040180806020018281038252602b815260200180614dd5602b913960400191505060405180910390fd5b611cdb611ba6565b6001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d1357600080fd5b505afa158015611d27573d6000803e3d6000fd5b505050506040513d6020811015611d3d57600080fd5b50516001600160a01b03163314611d9b576040805162461bcd60e51b815260206004820152601760248201527f7468697320697320696c6c6567616c2061646472657373000000000000000000604482015290519081900360640190fd5b81611de4576040805162461bcd60e51b8152602060048201526014602482015273696c6c6567616c206c6f636b75702076616c756560601b604482015290519081900360640190fd5b611dec614026565b611df68486613373565b9050611e066001868686856133a8565b604080516001600160a01b0380881682528616602082015280820185905290517f71601c75cd9722fdbd6d57dbb30980d4a4bd6169ba3d456dc18b7f878629d7bf9181900360600190a15050505050565b6000611e64848484612a84565b949350505050565b6000806000611e79610a4a565b6001600160a01b031663bd02d0f5611e8f6133e4565b6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611ec357600080fd5b505afa158015611ed7573d6000803e3d6000fd5b505050506040513d6020811015611eed57600080fd5b505190506000611f11826d04ee2d6d415b85acef810000000063ffffffff61320b16565b90506000611f43611f36836d04ee2d6d415b85acef810000000063ffffffff61342c16565b849063ffffffff61299816565b91945090925050509091565b6000611f59610a4a565b6001600160a01b031663bd02d0f561094b613485565b600080611f7a61196e565b5050915050610adc81846134cd565b600080600080611f9761196e565b9350509250506000611fa886613522565b90506000611fbc838363ffffffff61299816565b9050611fc884886134cd565b95509350505050915091565b600080611fe18333611658565b905060008111612025576040805162461bcd60e51b815260206004820152600a6024820152691b9bdd081cdd185ad95960b21b604482015290519081900360640190fd5b60006120318433610ae3565b9050600061203f85336109b0565b905061204d8533600061357a565b6120598533600061359a565b60048054604080516320d7b32760e01b815233938101939093526001600160a01b0388811660248501526044840187905260648401869052905191169160009183916320d7b3279160a480830192602092919082900301818787803b1580156120c157600080fd5b505af11580156120d5573d6000803e3d6000fd5b505050506040513d60208110156120eb57600080fd5b5051604080516386904ccf60e01b815260048101839052602481018890526044810187905260006064820181905260848201879052915192935090916001600160a01b038516916386904ccf9160a480830192602092919082900301818787803b15801561215857600080fd5b505af115801561216c573d6000803e3d6000fd5b505050506040513d602081101561218257600080fd5b50519050806121cb576040805162461bcd60e51b815260206004820152601060248201526f6661696c656420746f2075706461746560801b604482015290519081900360640190fd5b509695505050505050565b60006121e0610a4a565b6001600160a01b031663bd02d0f561094b61361b565b6121fe6115ba565b61223d576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b6109288161364c565b6122518233836136ed565b6122a2576040805162461bcd60e51b815260206004820152601a60248201527f696e73756666696369656e7420746f6b656e73207374616b6564000000000000604482015290519081900360640190fd5b6122aa614026565b6122b383613706565b90508115612322576040805163f3fef3a360e01b81523360048201526024810184905290516001600160a01b0385169163f3fef3a391604480830192600092919082900301818387803b15801561230957600080fd5b505af115801561231d573d6000803e3d6000fd5b505050505b6123306000338585856133a8565b505050565b600061233f610a4a565b6001600160a01b031663bd02d0f561094b613816565b6000806123628484613845565b50949350505050565b6123736115ba565b6123b2576040805162461bcd60e51b81526020600482018190526024820152600080516020614d69833981519152604482015290519081900360640190fd5b6002546001600160a01b031615612401576040805162461bcd60e51b815260206004820152600e60248201526d1cdd1bdc9859d9481a5cc81cd95d60921b604482015290519081900360640190fd5b600060405161240f9061404e565b604051809103906000f08015801561242b573d6000803e3d6000fd5b50600280546001600160a01b0319166001600160a01b039290921691909117905550565b6000610a3582611495565b6000816040516020018080614c86602d9139602d01826001600160a01b03166001600160a01b031660601b8152601401915050604051602081830303815290604052805190602001209050919050565b6124b2610a4a565b6001600160a01b031663e2a4853a6124c861361b565b836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b1580156117a157600080fd5b60006040516020018080614cfa60229139602201905060405160208183030381529060405280519060200120905090565b604080517f5f70656e64696e67496e7465726573745769746864726177616c0000000000006020808301919091526001600160601b0319606086811b8216603a85015285901b16604e830152825160428184030181526062909201909252805191012092915050565b604080516e5f696e746572657374546f74616c7360881b60208083019190915260609390931b6001600160601b031916602f820152815180820360230181526043909101909152805191012090565b604080517f5f6c6173745374616b6564496e746572657374507269636500000000000000006020808301919091526001600160601b0319606095861b8116603884015293851b909316604c82015281518082038301815293019052815191012090565b60408051705f6469703447656e65736973426c6f636b60781b602080830191909152825180830360110181526031909201909252805191012090565b6000612698614026565b6126a0611ba6565b6001600160a01b031663628f043d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156126d857600080fd5b505afa1580156126ec573d6000803e3d6000fd5b505050506040513d602081101561270257600080fd5b505160408051638b234cb160e01b81526001600160a01b03898116600483015291519190921691638b234cb1916024808301926020929190829003018186803b15801561274e57600080fd5b505afa158015612762573d6000803e3d6000fd5b505050506040513d602081101561277857600080fd5b50516127ba5760008060008061278c61196e565b6040805160808101825294855260208501939093529183015260608201526000965094506127f09350505050565b60006127c4614026565b6127ce87876139d0565b925050915060006127e8868461293e90919063ffffffff16565b945090925050505b94509492505050565b6000612803614026565b600061280d614026565b6128198888888861268e565b600354604080516340c10f1960e01b81523360048201526024810185905290519395509193506001600160a01b0316916340c10f19916044808201926020929091908290030181600087803b15801561287157600080fd5b505af1158015612885573d6000803e3d6000fd5b505050506040513d602081101561289b57600080fd5b50516128e0576040805162461bcd60e51b815260206004820152600f60248201526e19195d881b5a5b9d0819985a5b1959608a1b604482015290519081900360640190fd5b6128e86116e6565b9097909650945050505050565b6128ff8382613a4d565b831561291d5761290e82613af7565b6129188383613b1e565b612930565b61292682613b47565b6129308383613b63565b6129386116e6565b50505050565b600082820183811015610adc576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000610adc83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613b8e565b60408051755f6c6173744c617374496e746572657374507269636560501b6020808301919091526001600160601b0319606086811b8216603685015285901b16604a8301528251603e818403018152605e909201909252805191012092915050565b604080517f306c61737443756d756c6174697665496e7465726573745072696365000000006020808301919091528251808303601c018152603c909201909252805191012090565b600083612a8f611ba6565b6001600160a01b031663628f043d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ac757600080fd5b505afa158015612adb573d6000803e3d6000fd5b505050506040513d6020811015612af157600080fd5b505160408051638b234cb160e01b81526001600160a01b03848116600483015291519190921691638b234cb1916024808301926020929190829003018186803b158015612b3d57600080fd5b505afa158015612b51573d6000803e3d6000fd5b505050506040513d6020811015612b6757600080fd5b5051612ba45760405162461bcd60e51b815260040180806020018281038252602b815260200180614dd5602b913960400191505060405180910390fd5b600080600080612bb261196e565b9350935093509350612be760018a8a6040518060800160405280898152602001888152602001878152602001868152506128f5565b612bef611ba6565b6001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c2757600080fd5b505afa158015612c3b573d6000803e3d6000fd5b505050506040513d6020811015612c5157600080fd5b5051604080516323b872dd60e01b81523360048201526001600160a01b038c81166024830152604482018c9052915191909216916323b872dd9160648083019260209291908290030181600087803b158015612cac57600080fd5b505af1158015612cc0573d6000803e3d6000fd5b505050506040513d6020811015612cd657600080fd5b5051612d1f576040805162461bcd60e51b815260206004820152601360248201527219195d881d1c985b9cd9995c8819985a5b1959606a1b604482015290519081900360640190fd5b60048054604080516320d7b32760e01b815233938101939093526001600160a01b038c81166024850152604484018c905260648401869052608484018b9052905160009391909216916320d7b3279160a48082019260209290919082900301818787803b158015612d8f57600080fd5b505af1158015612da3573d6000803e3d6000fd5b505050506040513d6020811015612db957600080fd5b5051604080513381526001600160a01b038d1660208201528082018c905290519192507f71601c75cd9722fdbd6d57dbb30980d4a4bd6169ba3d456dc18b7f878629d7bf919081900360600190a19998505050505050505050565b604080517f5f63756d756c6174697665476c6f62616c526577617264730000000000000000602080830191909152825180830360180181526038909201909252805191012090565b604080516d5f70726f706572747956616c756560901b60208083019190915260609390931b6001600160601b031916602e820152815180820360220181526042909101909152805191012090565b60408051685f616c6c56616c756560b81b602080830191909152825180830360090181526029909201909252805191012090565b3390565b60408051655f76616c756560d01b6020808301919091526001600160601b0319606086811b8216602685015285901b16603a8301528251602e818403018152604e909201909252805191012092915050565b6000806000612f41611ba6565b6001600160a01b031663aa5dcecc6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7957600080fd5b505afa158015612f8d573d6000803e3d6000fd5b505050506040513d6020811015612fa357600080fd5b505160408051633aa5460b60e01b815290516001600160a01b0390921691633aa5460b91600480820192602092909190829003018186803b158015612fe757600080fd5b505afa158015612ffb573d6000803e3d6000fd5b505050506040513d602081101561301157600080fd5b50519050600080613020611e6c565b9150915060008383146130335782613035565b835b90506000808311613047576000613057565b613057438463ffffffff61299816565b9050600061306b838363ffffffff61342c16565b9050600061307b82611b06611475565b98509596505050505050509091565b613092610a4a565b6001600160a01b031663e2a4853a6124c8612e14565b60006130cc82611b06856d04ee2d6d415b85acef810000000063ffffffff61342c16565b90506130d6610a4a565b6001600160a01b031663e2a4853a6130ec6133e4565b836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b15801561312a57600080fd5b505af115801561313e573d6000803e3d6000fd5b50505050505050565b61314f610a4a565b6001600160a01b031663e2a4853a6124c861332b565b61316d610a4a565b6001600160a01b031663e2a4853a6124c8613485565b61318b610a4a565b6001600160a01b031663e2a4853a6124c8613816565b6000816040516020018080614d8960229139602201826001600160a01b03166001600160a01b031660601b8152601401915050604051602081830303815290604052805190602001209050919050565b6000610a3582670de0b6b3a764000063ffffffff61342c16565b6000610adc83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613c25565b600080613258611b86565b90506000613264611f4f565b9050600061328f613273612335565b613283878563ffffffff61299816565b9063ffffffff61342c16565b90506132a1838263ffffffff61293e16565b95945050505050565b60006040516020018080614cd960219139602101905060405160208183030381529060405280519060200120905090565b6000816040516020018080614d1c602c9139602c01826001600160a01b03166001600160a01b031660601b8152601401915050604051602081830303815290604052805190602001209050919050565b604080517f5f63756d756c6174697665486f6c6465727352657761726443617000000000006020808301919091528251808303601b018152603b909201909252805191012090565b61337b614026565b6000613385614026565b61338f8585613845565b9150915061339e85858461357a565b611e648585613c8a565b6133b783858360400151613cb2565b6133c3858484846128f5565b84156133d9576133d4838584613cd2565b6117b5565b6117b5838584613cfd565b604080517f5f4c61737453616d6552657761726473416d6f756e74416e64426c6f636b00006020808301919091528251808303601e018152603e909201909252805191012090565b60008261343b57506000610a35565b8282028284828161344857fe5b0414610adc5760405162461bcd60e51b8152600401808060200182810382526021815260200180614d486021913960400191505060405180910390fd5b604080517f5f6c61737443756d756c6174697665486f6c64657273507269636543617000006020808301919091528251808303601e018152603e909201909252805191012090565b60008060006134db8461084f565b6134e485611b56565b9150915060006135066134f686611495565b613283888563ffffffff61299816565b9050613518838263ffffffff61293e16565b9695505050505050565b60008061352e8361194d565b9050801561353d5790506108d3565b600061354884611b56565b118061355c5750600061355a84611495565b115b15613571576135696121d6565b9150506108d3565b50600092915050565b613582610a4a565b6001600160a01b031663e2a4853a6130ec8585612537565b60006135a68484612ee2565b90506135b0610a4a565b6001600160a01b031663e2a4853a82846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b1580156135fd57600080fd5b505af1158015613611573d6000803e3d6000fd5b5050505050505050565b60006040516020018080614dab602a9139602a01905060405160208183030381529060405280519060200120905090565b6001600160a01b0381166136915760405162461bcd60e51b8152600401808060200182810382526026815260200180614cb36026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000806136fa8585611658565b90921115949350505050565b61370e614026565b6000613718614026565b6137228433613845565b915091506137328433600061357a565b61374184338360400151613cb2565b61374b8433613c8a565b600354604080516340c10f1960e01b81523360048201526024810185905290516001600160a01b03909216916340c10f19916044808201926020929091908290030181600087803b15801561379f57600080fd5b505af11580156137b3573d6000803e3d6000fd5b505050506040513d60208110156137c957600080fd5b505161380e576040805162461bcd60e51b815260206004820152600f60248201526e19195d881b5a5b9d0819985a5b1959608a1b604482015290519081900360640190fd5b610adc6116e6565b604080516305f6361760e41b602080830191909152825180830360040181526024909201909252805191012090565b600061384f614026565b613857611ba6565b6001600160a01b031663628f043d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561388f57600080fd5b505afa1580156138a3573d6000803e3d6000fd5b505050506040513d60208110156138b957600080fd5b505160408051638b234cb160e01b81526001600160a01b03878116600483015291519190921691638b234cb1916024808301926020929190829003018186803b15801561390557600080fd5b505afa158015613919573d6000803e3d6000fd5b505050506040513d602081101561392f57600080fd5b50516139715760008060008061394361196e565b6040805160808101825294855260208501939093529183015260608201526000965094506139c99350505050565b600061397d85856109b0565b9050600061398b8686613d1b565b90506000613997614026565b6139a18888613d82565b925050915060006139bf84611b06878661293e90919063ffffffff16565b9650909450505050505b9250929050565b6000806139db614026565b6000806000806139e961196e565b9350935093509350600088831015613a02576000613a1e565b613a1e613a198b613283868d63ffffffff61299816565b613e18565b604080516080810182529687526020870195909552938501839052506060840152909450925090509250925092565b6000613a5d8260200151846134cd565b9050613a6883611b56565b158015613a7b5750613a798361194d565b155b8015613a8d5750613a8b83611495565b155b15613aa057613aa0838360600151613e32565b8151613aab90613eab565b613ab88260200151613ec9565b613ac58260400151613ee7565b613acf8382613f05565b613add838360200151613f24565b613aea8260600151613147565b6123308260200151613165565b6000613b01611521565b9050613b13818363ffffffff61293e16565b905061170881613f43565b6000613b2983611495565b9050613b3b818363ffffffff61293e16565b90506123308382613fa4565b6000613b51611521565b9050613b13818363ffffffff61299816565b6000613b6e83611495565b90506000613b82828463ffffffff61299816565b90506129388482613fa4565b60008184841115613c1d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613be2578181015183820152602001613bca565b50505050905090810190601f168015613c0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008183613c745760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613be2578181015183820152602001613bca565b506000838581613c8057fe5b0495945050505050565b6000613c9583610aaf565b905080613ca2848461138a565b1461233057612330838383614006565b613cba610a4a565b6001600160a01b031663e2a4853a6130ec85856125ef565b6000613cde8484611658565b9050613cf0818363ffffffff61293e16565b905061293884848361359a565b6000613d098484611658565b9050613cf0818363ffffffff61299816565b600080613d28848461138a565b90506000613d3585610aaf565b90506000613d49828463ffffffff61299816565b90506000613d578787611658565b90506000613d6b838363ffffffff61342c16565b9050613d7681613e18565b98975050505050505050565b600080613d8d614026565b6000613d998686611658565b90506000613da78787610ae3565b9050600080600080613db761196e565b9350935093509350600085831015613dd0576000613de7565b613de7613a1988613283868a63ffffffff61299816565b6040805160808101825296875260208701959095529385018390525060608401529096509450925050509250925092565b6000610a3582670de0b6b3a764000063ffffffff61320b16565b613e3a610a4a565b6001600160a01b031663e2a4853a613e51846131a1565b836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015613e8f57600080fd5b505af1158015613ea3573d6000803e3d6000fd5b505050505050565b613eb3610a4a565b6001600160a01b031663e2a4853a6124c8612506565b613ed1610a4a565b6001600160a01b031663e2a4853a6124c86132aa565b613eef610a4a565b6001600160a01b031663e2a4853a6124c8612a3c565b613f0d610a4a565b6001600160a01b031663e2a4853a613e518461245a565b613f2c610a4a565b6001600160a01b031663e2a4853a613e51846132db565b6000613f4d612eaa565b9050613f57610a4a565b6001600160a01b031663e2a4853a82846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015613e8f57600080fd5b6000613faf83612e5c565b9050613fb9610a4a565b6001600160a01b031663e2a4853a82846040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b15801561312a57600080fd5b61400e610a4a565b6001600160a01b031663e2a4853a6130ec85856129da565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b610c2a8061405c8339019056fe6080604052600080546001600160a01b0319163317905534801561002257600080fd5b50610bf8806100326000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c8063a6f9dae1116100ad578063d5d2c56011610071578063d5d2c560146103f5578063dc97d96214610418578063e2a4853a14610435578063e2b202bf14610458578063f6bb3cc41461047557610121565b8063a6f9dae114610332578063abfdcced14610358578063bd02d0f51461037d578063c031a180146103ac578063ca446dd9146103c957610121565b8063616b59f6116100f4578063616b59f6146101be5780636e899550146101db5780637ae1cfca146102525780638c16009514610283578063986e791a146102a057610121565b80630e14a3761461012657806321f8a721146101455780632c62ff2d1461017e5780633e49bed01461019b575b600080fd5b6101436004803603602081101561013c57600080fd5b5035610492565b005b6101626004803603602081101561015b57600080fd5b50356104fd565b604080516001600160a01b039092168252519081900360200190f35b6101436004803603602081101561019457600080fd5b5035610518565b610143600480360360408110156101b157600080fd5b508035906020013561057d565b610143600480360360208110156101d457600080fd5b50356105dc565b610143600480360360408110156101f157600080fd5b8135919081019060408101602082013564010000000081111561021357600080fd5b82018360208201111561022557600080fd5b8035906020019184600183028401116401000000008311171561024757600080fd5b50909250905061063a565b61026f6004803603602081101561026857600080fd5b50356106a6565b604080519115158252519081900360200190f35b6101436004803603602081101561029957600080fd5b50356106bb565b6102bd600480360360208110156102b657600080fd5b5035610719565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102f75781810151838201526020016102df565b50505050905090810190601f1680156103245780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101436004803603602081101561034857600080fd5b50356001600160a01b03166107b8565b6101436004803603604081101561036e57600080fd5b50803590602001351515610827565b61039a6004803603602081101561039357600080fd5b5035610894565b60408051918252519081900360200190f35b61039a600480360360208110156103c257600080fd5b50356108a6565b610143600480360360408110156103df57600080fd5b50803590602001356001600160a01b03166108b8565b6101436004803603604081101561040b57600080fd5b5080359060200135610933565b61039a6004803603602081101561042e57600080fd5b5035610992565b6101436004803603604081101561044b57600080fd5b50803590602001356109a4565b6101436004803603602081101561046e57600080fd5b5035610a03565b6101436004803603602081101561048b57600080fd5b5035610a61565b6000546001600160a01b031633146104df576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600090815260036020526040902080546001600160a01b0319169055565b6000908152600360205260409020546001600160a01b031690565b6000546001600160a01b03163314610565576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b6000908152600560205260409020805460ff19169055565b6000546001600160a01b031633146105ca576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b60009182526006602052604090912055565b6000546001600160a01b03163314610629576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600090815260046020526040812055565b6000546001600160a01b03163314610687576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b60008381526002602052604090206106a0908383610ac8565b50505050565b60009081526005602052604090205460ff1690565b6000546001600160a01b03163314610708576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600090815260066020526040812055565b600081815260026020818152604092839020805484516001821615610100026000190190911693909304601f810183900483028401830190945283835260609390918301828280156107ac5780601f10610781576101008083540402835291602001916107ac565b820191906000526020600020905b81548152906001019060200180831161078f57829003601f168201915b50505050509050919050565b6000546001600160a01b03163314610805576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610874576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600091825260056020526040909120805460ff1916911515919091179055565b60009081526001602052604090205490565b60009081526004602052604090205490565b6000546001600160a01b03163314610905576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b60009182526003602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b6000546001600160a01b03163314610980576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b60009182526004602052604090912055565b60009081526006602052604090205490565b6000546001600160a01b031633146109f1576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b60009182526001602052604090912055565b6000546001600160a01b03163314610a50576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b600090815260016020526040812055565b6000546001600160a01b03163314610aae576040805162461bcd60e51b81526020600482015260116024820152600080516020610ba4833981519152604482015290519081900360640190fd5b6000818152600260205260408120610ac591610b46565b50565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610b095782800160ff19823516178555610b36565b82800160010185558215610b36579182015b82811115610b36578235825591602001919060010190610b1b565b50610b42929150610b86565b5090565b50805460018160011615610100020316600290046000825580601f10610b6c5750610ac5565b601f016020900490600052602060002090810190610ac591905b610ba091905b80821115610b425760008155600101610b8c565b9056fe6e6f742063757272656e74206f776e6572000000000000000000000000000000a265627a7a723158209c0dc6304ed22c7d92cc360e2d87ee5a1b86eed066d6e22f0e7f1913d0c1658364736f6c63430005110032306c61737443756d756c6174697665486f6c64657273526577617264416d6f756e7450657250726f70657274794f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373306c61737443756d756c6174697665486f6c6465727352657761726450726963655f6c6173745374616b65734368616e67656443756d756c6174697665526577617264306c61737443756d756c6174697665486f6c64657273526577617264507269636550657250726f7065727479536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725f696e697469616c43756d756c6174697665486f6c646572735265776172644361705f66616c6c6261636b496e697469616c43756d756c6174697665486f6c64657273526577617264436170756e61626c6520746f207374616b6520746f20756e61757468656e746963617465642070726f7065727479a265627a7a72315820758134f3c0e01748dc3c48c5c4e20479f4f773857f3881e2ed813d29f61b419564736f6c63430005110032

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000001d415aa39d647834786eb9b5a333a50e9935b7960000000000000000000000004596dae6955693c50522f1b06bdbf7b93ceb547900000000000000000000000050489ff5f879a44c87bba85287729d663b18ced5

-----Decoded View---------------
Arg [0] : _config (address): 0x1D415aa39D647834786EB9B5a333A50e9935b796
Arg [1] : _devMinter (address): 0x4596DaE6955693C50522F1b06bDBf7b93cEB5479
Arg [2] : _sTokensManager (address): 0x50489Ff5f879A44C87bBA85287729D663b18CeD5

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000001d415aa39d647834786eb9b5a333a50e9935b796
Arg [1] : 0000000000000000000000004596dae6955693c50522f1b06bdbf7b93ceb5479
Arg [2] : 00000000000000000000000050489ff5f879a44c87bba85287729d663b18ced5


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.