ERC-20
DeFi
Overview
Max Total Supply
511,234,744,896.537433298437672978 HLX
Holders
385 (0.00%)
Market
Price
$0.00 @ 0.000000 ETH (+6.93%)
Onchain Market Cap
$628,818.74
Circulating Supply Market Cap
$0.00
Other Info
Token Contract (WITH 18 Decimals)
Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
HELIOS
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 0 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/interfaces/IERC165.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../interfaces/IHlxOnBurn.sol"; import "../interfaces/ITITANX.sol"; import "../interfaces/ITitanOnBurn.sol"; import "../interfaces/IBuynBurn.sol"; import "../libs/calcFunctions.sol"; import "./GlobalInfo.sol"; import "./MintInfo.sol"; import "./StakeInfo.sol"; import "./BurnInfo.sol"; import "./OwnerInfo.sol"; //custom errors error Helios_InvalidAmount(); error Helios_InsufficientBalance(); error Helios_NotSupportedContract(); error Helios_InsufficientProtocolFees(); error Helios_FailedToSendAmount(); error Helios_NotAllowed(); error Helios_NoCycleRewardToClaim(); error Helios_NoSharesExist(); error Helios_EmptyUndistributeFees(); error Helios_InvalidBurnRewardPercent(); error Helios_MaxedWalletMints(); error Helios_LPTokensHasMinted(); error Helios_InvalidAddress(); error Helios_InsufficientBurnAllowance(); error Helios_OnlyBuyAndBurn(); error Helios_OnlyWhiteListedProjects(); /** @title Helios */ contract HELIOS is ERC20, ReentrancyGuard, GlobalInfo, MintInfo, StakeInfo, BurnInfo, OwnerInfo, IERC165, ITitanOnBurn { /** Storage Variables*/ /** @dev stores genesis wallet address */ address private s_genesisAddress; /** @dev stores Investment address */ address private s_investmentAddress; /** @dev stores buy and burn contract address */ address private s_buyAndBurnAddress; /** @dev stores treasury contract address */ address private s_treasuryAddress; /** @dev stores TITANX contract address */ address private s_titanxAddress; /** @dev tracks collected protocol fees until it is distributed */ uint256 private s_undistributedTitanX; /** @dev tracks collected protocol fees until it is distributed */ uint256 private s_undistributedETH; /** @dev stores total Titanx burned by Users */ uint256 private s_totalTitanBurned; // /** @dev tracks burn reward from distributeTitanX() until payout is triggered */ // uint88 private s_cycleBurnReward; /** @dev tracks if initial LP tokens has minted or not */ InitialLPMinted private s_initialLPMinted; // /** @dev trigger to turn on burn pool reward */ // BurnPoolEnabled private s_burnPoolEnabled; /** @dev tracks user + project burn mints allowance */ mapping(address => mapping(address => uint256)) private s_allowanceBurnMints; /** @dev tracks projects whiteListed to stake on hlx */ mapping(address => bool) private s_whiteList; /** @dev tracks user + project burn stakes allowance */ mapping(address => mapping(address => uint256)) private s_allowanceBurnStakes; struct MintParams { uint256 mintPower; uint256 numOfDays; uint256 titanToBurn; uint256 gMintPower; uint256 currentHRank; uint256 mintCost; } event ProtocolFeeRecevied( address indexed user, uint256 indexed day, uint256 indexed amount ); event TitanXDistributed(address indexed caller, uint256 indexed amount); event CyclePayoutTriggered( address indexed caller, uint256 indexed cycleNo, uint256 indexed reward // uint256 burnReward ); event RewardClaimed( address indexed user, uint256 indexed reward, uint256 indexed ethReward ); event ApproveBurnStakes( address indexed user, address indexed project, uint256 indexed amount ); event ApproveBurnMints( address indexed user, address indexed project, uint256 indexed amount ); constructor( address genesisAddress, address buyAndBurnAddress, address titanxAddress, address treasuryAddress, address investmentAddress ) ERC20("HELIOS", "HLX") { if (genesisAddress == address(0)) revert Helios_InvalidAddress(); if (buyAndBurnAddress == address(0)) revert Helios_InvalidAddress(); if (titanxAddress == address(0)) revert Helios_InvalidAddress(); if (treasuryAddress == address(0)) revert Helios_InvalidAddress(); s_genesisAddress = genesisAddress; s_investmentAddress = investmentAddress; s_buyAndBurnAddress = buyAndBurnAddress; s_titanxAddress = titanxAddress; s_treasuryAddress = treasuryAddress; } modifier onlyBuyAndBurn() { if (_msgSender() != s_buyAndBurnAddress) revert Helios_OnlyBuyAndBurn(); _; } function supportsInterface( bytes4 interfaceId ) external pure override returns (bool) { return interfaceId == INTERFACE_ID_ERC165 || interfaceId == INTERFACE_ID_ITITANONBURN; } function onBurn(address, uint256 amount) external override { require(msg.sender == s_titanxAddress, "Only TitanX"); s_totalTitanBurned += amount; } /**** Mint Functions *****/ /** @notice create a new mint * @param mintPower 1 - 100,000 * @param numOfDays mint length of 1 - 250 */ function startMint( uint256 mintPower, uint256 numOfDays, uint256 titanToBurn ) external payable nonReentrant dailyUpdate { if (getUserLatestMintId(_msgSender()) + 1 > MAX_MINT_PER_WALLET) revert Helios_MaxedWalletMints(); if (titanToBurn > 0) _burnTitanX(titanToBurn); MintParams memory params = MintParams({ mintPower: mintPower, numOfDays: numOfDays, titanToBurn: titanToBurn, gMintPower: getGlobalMintPower() + mintPower, currentHRank: getGlobalHRank() + 1, mintCost: getMintCost(mintPower, getCurrentMintCost()) }); uint256 gMinting = getTotalMinting() + _startMint( _msgSender(), params.mintPower, params.numOfDays, getCurrentMintableHlx(), getCurrentMintPowerBonus(), getCurrentEAABonus(), getUserBurnAmplifierBonus(_msgSender()), params.gMintPower, params.currentHRank, params.mintCost, params.titanToBurn ); _updateMintStats(params.currentHRank, params.gMintPower, gMinting); _protocolFees(mintPower); } /** @notice claim a matured mint * @param id mint id */ function claimMint(uint256 id) external dailyUpdate nonReentrant { _mintReward(_claimMint(_msgSender(), id, MintAction.CLAIM)); } /**** Stake Functions *****/ /** @notice start a new stake * @param amount Helios amount * @param numOfDays stake length * @param titanToBurn amount of titanX tokens to burn to get reward */ function startStake( uint256 amount, uint256 numOfDays, uint256 titanToBurn ) external dailyUpdate nonReentrant { if (balanceOf(_msgSender()) < amount) revert Helios_InsufficientBalance(); if (msg.sender != tx.origin) { // check if it's whitelisted require(s_whiteList[msg.sender], "Contract not whitelisted."); } if (titanToBurn > 0) _burnTitanX(titanToBurn); _burn(_msgSender(), amount); _initFirstSharesCycleIndex( _msgSender(), _startStake( _msgSender(), amount, numOfDays, getCurrentShareRate(), getCurrentContractDay(), getGlobalPayoutTriggered(), titanToBurn, titanToBurn > 0 ? IBuynBurn(s_buyAndBurnAddress).getCurrentTitanPrice() : 0 ) ); } /** @notice end a stake * @param id stake id */ function endStake(uint256 id) external dailyUpdate nonReentrant { _mint( _msgSender(), _endStake( _msgSender(), id, getCurrentContractDay(), StakeAction.END, StakeAction.END_OWN, getGlobalPayoutTriggered() ) ); } /** @notice end a stake for others * @param user wallet address * @param id stake id */ function endStakeForOthers( address user, uint256 id ) external dailyUpdate nonReentrant { _mint( user, _endStake( user, id, getCurrentContractDay(), StakeAction.END, StakeAction.END_OTHER, getGlobalPayoutTriggered() ) ); } /** @notice distribute the collected protocol fees into different pools/payouts * automatically send the incentive fee to caller, buyAndBurnFunds to BuyAndBurn contract, and genesis wallet */ function distributeTitanX() external dailyUpdate nonReentrant { ( uint256 incentiveFee, uint256 buyAndBurnFunds, uint256 treasuryReward, uint256 genesisWallet ) = _distributeTitanX(); _sendFunds( incentiveFee, buyAndBurnFunds, treasuryReward, genesisWallet ); } /** @notice trigger cylce payouts for day 22, 69, 420 * As long as the cycle has met its maturiy day (eg. Cycle22 is day 22), payout can be triggered in any day onwards */ function triggerPayouts() external dailyUpdate nonReentrant { uint256 globalActiveShares = getGlobalShares() - getGlobalExpiredShares(); if (globalActiveShares < 1) revert Helios_NoSharesExist(); uint256 incentiveFee; uint256 buyAndBurnFunds; uint256 genesisWallet; uint256 treasuryReward; if (s_undistributedTitanX != 0) ( incentiveFee, buyAndBurnFunds, treasuryReward, genesisWallet ) = _distributeTitanX(); uint256 currentContractDay = getCurrentContractDay(); PayoutTriggered isTriggered = PayoutTriggered.NO; _triggerCyclePayout(DAY22, globalActiveShares, currentContractDay) == PayoutTriggered.YES && isTriggered == PayoutTriggered.NO ? isTriggered = PayoutTriggered.YES : isTriggered; _triggerCyclePayout(DAY69, globalActiveShares, currentContractDay) == PayoutTriggered.YES && isTriggered == PayoutTriggered.NO ? isTriggered = PayoutTriggered.YES : isTriggered; _triggerCyclePayout(DAY420, globalActiveShares, currentContractDay) == PayoutTriggered.YES && isTriggered == PayoutTriggered.NO ? isTriggered = PayoutTriggered.YES : isTriggered; if (isTriggered == PayoutTriggered.YES) { if (getGlobalPayoutTriggered() == PayoutTriggered.NO) _setGlobalPayoutTriggered(); } if (incentiveFee != 0) _sendFunds( incentiveFee, buyAndBurnFunds, treasuryReward, genesisWallet ); } /** @notice claim all user available TitanX/ETH payouts in one call */ function claimUserAvailablePayouts() external dailyUpdate nonReentrant { uint256 totalTitanXReward = 0; uint256 totalEthReward = 0; (uint256 reward, uint256 ethReward) = _claimCyclePayout(DAY22); totalTitanXReward += reward; totalEthReward += ethReward; (reward, ethReward) = _claimCyclePayout(DAY69); totalTitanXReward += reward; totalEthReward += ethReward; (reward, ethReward) = _claimCyclePayout(DAY420); totalTitanXReward += reward; totalEthReward += ethReward; if (totalTitanXReward == 0 && totalEthReward == 0) revert Helios_NoCycleRewardToClaim(); if (totalTitanXReward > 0) { _sendTitanX(_msgSender(), totalTitanXReward); } if (totalEthReward > 0) { _sendViaCall(payable(_msgSender()), totalEthReward); } emit RewardClaimed(_msgSender(), totalTitanXReward, totalEthReward); } /** @notice Set BuyAndBurn Contract Address - able to change to new contract that supports UniswapV4+ * Only owner can call this function * @param contractAddress BuyAndBurn contract address */ function setBuyAndBurnContractAddress( address contractAddress ) external onlyOwner { if (contractAddress == address(0)) revert Helios_InvalidAddress(); s_buyAndBurnAddress = contractAddress; } /** @notice adds address to whitelist * Only owner can call this function * @param contractAddress project contract address * @param permit bool True to allow */ function whiteList( address contractAddress, bool permit ) external onlyOwner { if (contractAddress == address(0)) revert Helios_InvalidAddress(); s_whiteList[contractAddress] = permit; } /** @notice Set Treasury Contract Address - able to change to new contract that supports UniswapV4+ * Only owner can call this function * @param contractAddress Treasury contract address */ function setTreasuryContractAddress( address contractAddress ) external onlyOwner { if (contractAddress == address(0)) revert Helios_InvalidAddress(); s_treasuryAddress = contractAddress; } /** @notice Set TitanX Contract Address - able to change to new contract that supports UniswapV4+ * Only owner can call this function * @param contractAddress TitanX contract address */ function setTitanXContractAddress( address contractAddress ) external onlyOwner { if (contractAddress == address(0)) revert Helios_InvalidAddress(); s_titanxAddress = contractAddress; } /** @notice Set to new genesis wallet. Only genesis wallet can call this function * @param newAddress new genesis wallet address */ function setNewGenesisAddress(address newAddress) external { if (_msgSender() != s_genesisAddress) revert Helios_NotAllowed(); if (newAddress == address(0)) revert Helios_InvalidAddress(); s_genesisAddress = newAddress; } /** @notice Set to new Investment Address. * @param newAddress new Investment address */ function setNewInvestmentAddress(address newAddress) external { if (_msgSender() != s_investmentAddress) revert Helios_NotAllowed(); if (newAddress == address(0)) revert Helios_InvalidAddress(); s_investmentAddress = newAddress; } /** @notice mint initial LP tokens. Only BuyAndBurn contract set by genesis wallet can call this function */ function mintLPTokens() external { if (_msgSender() != s_buyAndBurnAddress) revert Helios_NotAllowed(); if (s_initialLPMinted == InitialLPMinted.YES) revert Helios_LPTokensHasMinted(); s_initialLPMinted = InitialLPMinted.YES; _mint(s_buyAndBurnAddress, INITAL_LP_TOKENS); } /** @notice burn all BuyAndBurn contract Helios */ function burnLPTokens() external dailyUpdate onlyBuyAndBurn { _burn(s_buyAndBurnAddress, balanceOf(s_buyAndBurnAddress)); } //private functions /** @dev mint reward to user and 1% to genesis wallet * @param reward helios amount */ function _mintReward(uint256 reward) private { _mint(_msgSender(), reward); _mint(s_investmentAddress, (reward * 100) / PERCENT_BPS); } /** @dev burns given amount of titanX with giving reward to caller and genesis Wallet * @param titanAmount amount titanX to burn */ function _burnTitanX(uint256 titanAmount) private { ITITANX(TITANX).burnTokensToPayAddress( _msgSender(), titanAmount, BURN_REWARD_PERCENT_EACH, BURN_REWARD_PERCENT_EACH, s_genesisAddress ); } /** @dev send TitanX to respective parties * @param incentiveFee fees for caller to run distributeTitanX() * @param buyAndBurnFunds funds for buy and burn * @param genesisWalletFunds funds for genesis wallet */ function _sendFunds( uint256 incentiveFee, uint256 buyAndBurnFunds, uint256 treasuryReward, uint256 genesisWalletFunds ) private { _sendTitanX(_msgSender(), incentiveFee); _sendTitanX(s_genesisAddress, genesisWalletFunds); _sendTitanX(s_buyAndBurnAddress, buyAndBurnFunds); _sendTitanX(s_treasuryAddress, treasuryReward); } /** @dev calculation to distribute collected protocol fees into different pools/parties */ function _distributeTitanX() private returns ( uint256 incentiveFee, uint256 buyAndBurnFunds, uint256 treasuryReward, uint256 genesisWallet ) { uint256 accumulatedFees = s_undistributedTitanX; if (accumulatedFees == 0) revert Helios_EmptyUndistributeFees(); s_undistributedTitanX = 0; emit TitanXDistributed(_msgSender(), accumulatedFees); incentiveFee = (accumulatedFees * INCENTIVE_FEE_PERCENT) / INCENTIVE_FEE_PERCENT_BASE; accumulatedFees -= incentiveFee; buyAndBurnFunds = (accumulatedFees * getBuynBurnPercentage()) / PERCENT_BPS; treasuryReward = (accumulatedFees * getTreasuryPercentage()) / PERCENT_BPS; genesisWallet = (accumulatedFees * PERCENT_TO_GENESIS) / PERCENT_BPS; uint256 cycleRewardPool = accumulatedFees - buyAndBurnFunds - treasuryReward - genesisWallet; //cycle payout if (cycleRewardPool != 0) { uint256 cycle22Reward = (cycleRewardPool * CYCLE_22_PERCENT) / PERCENT_BPS; uint256 cycle69Reward = (cycleRewardPool * CYCLE_69_PERCENT) / PERCENT_BPS; _setCyclePayoutPool(DAY22, cycle22Reward); _setCyclePayoutPool(DAY69, cycle69Reward); _setCyclePayoutPool( DAY420, cycleRewardPool - cycle22Reward - cycle69Reward ); } uint256 ethForDistribution = s_undistributedETH; //cycle ETH payout if (ethForDistribution != 0) { s_undistributedETH = 0; uint256 ethCycle22Reward = (ethForDistribution * CYCLE_22_PERCENT) / PERCENT_BPS; uint256 ethCycle69Reward = (ethForDistribution * CYCLE_69_PERCENT) / PERCENT_BPS; _setETHCyclePayoutPool(DAY22, ethCycle22Reward); _setETHCyclePayoutPool(DAY69, ethCycle69Reward); _setETHCyclePayoutPool( DAY420, ethForDistribution - ethCycle22Reward - ethCycle69Reward ); } } /** @dev calcualte required protocol fees, and return the balance (if any) * @param mintPower mint power 1-100,000 */ function _protocolFees(uint256 mintPower) private { uint256 protocolFee; protocolFee = getMintCost(mintPower, getCurrentMintCost()); // Transfer Titanx From user to contract IERC20(s_titanxAddress).transferFrom( _msgSender(), address(this), protocolFee ); s_undistributedTitanX += protocolFee; emit ProtocolFeeRecevied( _msgSender(), getCurrentContractDay(), protocolFee ); } /** @dev calculate payouts for each cycle day tracked by cycle index * @param cycleNo cylce day 22, 69, 420 * @param currentContractDay current contract day * @return triggered is payout triggered succesfully */ function _triggerCyclePayout( uint256 cycleNo, uint256 globalActiveShares, uint256 currentContractDay ) private returns (PayoutTriggered triggered) { //check against cylce payout maturity day if (currentContractDay < getNextCyclePayoutDay(cycleNo)) return PayoutTriggered.NO; //update the next cycle payout day regardless of payout triggered succesfully or not _setNextCyclePayoutDay(cycleNo); uint256 reward = getCyclePayoutPool(cycleNo); uint256 ethReward = getETHCyclePayoutPool(cycleNo); if (reward == 0 && ethReward == 0) return PayoutTriggered.NO; //calculate cycle reward per share and get new cycle Index _calculateCycleRewardPerShare( cycleNo, reward, ethReward, globalActiveShares ); emit CyclePayoutTriggered(_msgSender(), cycleNo, reward); return PayoutTriggered.YES; } /** @dev calculate user reward with specified cycle day and claim type (shares) and update user's last claim cycle index * @param cycleNo cycle day 22, 69, 420 */ function _claimCyclePayout( uint256 cycleNo ) private returns (uint256, uint256) { ( uint256 reward, uint256 ethRewards, uint256 userClaimCycleIndex, uint256 userClaimSharesIndex ) = calculateUserCycleReward(_msgSender(), cycleNo); _updateUserClaimIndexes( _msgSender(), cycleNo, userClaimCycleIndex, userClaimSharesIndex ); return (reward, ethRewards); } /** @dev burn liquid Helios through other project. * called by other contracts for proof of burn 2.0 with up to 8% for both builder fee and user rebate * @param user user address * @param amount liquid helios amount * @param userRebatePercentage percentage for user rebate in liquid helios (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid helios (0 - 8) * @param rewardPaybackAddress builder can opt to receive fee in another address */ function _burnLiquidHlx( address user, uint256 amount, uint256 userRebatePercentage, uint256 rewardPaybackPercentage, address rewardPaybackAddress ) private { if (amount == 0) revert Helios_InvalidAmount(); if (balanceOf(user) < amount) revert Helios_InsufficientBalance(); _spendAllowance(user, _msgSender(), amount); _burnbefore(userRebatePercentage, rewardPaybackPercentage); _burn(user, amount); _burnAfter( user, amount, userRebatePercentage, rewardPaybackPercentage, rewardPaybackAddress, BurnSource.LIQUID ); } /** @dev burn stake through other project. * called by other contracts for proof of burn 2.0 with up to 8% for both builder fee and user rebate * @param user user address * @param id stake id * @param userRebatePercentage percentage for user rebate in liquid helios (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid helios (0 - 8) * @param rewardPaybackAddress builder can opt to receive fee in another address */ function _burnStake( address user, uint256 id, uint256 userRebatePercentage, uint256 rewardPaybackPercentage, address rewardPaybackAddress ) private { _spendBurnStakeAllowance(user); _burnbefore(userRebatePercentage, rewardPaybackPercentage); _burnAfter( user, _endStake( user, id, getCurrentContractDay(), StakeAction.BURN, StakeAction.END_OWN, getGlobalPayoutTriggered() ), userRebatePercentage, rewardPaybackPercentage, rewardPaybackAddress, BurnSource.STAKE ); } /** @dev burn mint through other project. * called by other contracts for proof of burn 2.0 * burn mint has no builder reward and no user rebate * @param user user address * @param id mint id */ function _burnMint(address user, uint256 id) private { _spendBurnMintAllowance(user); _burnbefore(0, 0); uint256 amount = _claimMint(user, id, MintAction.BURN); _mint(s_genesisAddress, (amount * 800) / PERCENT_BPS); _burnAfter(user, amount, 0, 0, _msgSender(), BurnSource.MINT); } /** @dev perform checks before burning starts. * check reward percentage and check if called by supported contract * @param userRebatePercentage percentage for user rebate * @param rewardPaybackPercentage percentage for builder fee */ function _burnbefore( uint256 userRebatePercentage, uint256 rewardPaybackPercentage ) private view { if ( rewardPaybackPercentage + userRebatePercentage > MAX_BURN_REWARD_PERCENT ) revert Helios_InvalidBurnRewardPercent(); //Only supported contracts is allowed to call this function if ( !IERC165(_msgSender()).supportsInterface( IERC165.supportsInterface.selector ) || !IERC165(_msgSender()).supportsInterface( type(IHlxOnBurn).interfaceId ) ) revert Helios_NotSupportedContract(); } /** @dev update burn stats and mint reward to builder or user if applicable * @param user user address * @param amount helios amount burned * @param userRebatePercentage percentage for user rebate in liquid helios (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid helios (0 - 8) * @param rewardPaybackAddress builder can opt to receive fee in another address * @param source liquid/mint/stake */ function _burnAfter( address user, uint256 amount, uint256 userRebatePercentage, uint256 rewardPaybackPercentage, address rewardPaybackAddress, BurnSource source ) private { _updateBurnAmount(user, _msgSender(), amount, source); uint256 devFee; uint256 userRebate; if (rewardPaybackPercentage != 0) devFee = (amount * rewardPaybackPercentage * PERCENT_BPS) / (100 * PERCENT_BPS); if (userRebatePercentage != 0) userRebate = (amount * userRebatePercentage * PERCENT_BPS) / (100 * PERCENT_BPS); if (devFee != 0) _mint(rewardPaybackAddress, devFee); if (userRebate != 0) _mint(user, userRebate); IHlxOnBurn(_msgSender()).onBurn(user, amount); } /** @dev Recommended method to transfer Tokens * @param to receiving address. * @param amount in wei. */ function _sendTitanX(address to, uint256 amount) private { if (to == address(0)) revert Helios_InvalidAddress(); IERC20(s_titanxAddress).transfer(to, amount); } /** @dev Recommended method to use to send native coins. * @param to receiving address. * @param amount in wei. */ function _sendViaCall(address payable to, uint256 amount) private { if (to == address(0)) revert Helios_InvalidAddress(); (bool sent, ) = to.call{value: amount}(""); if (!sent) revert Helios_FailedToSendAmount(); } /** @dev reduce user's allowance for caller (spender/project) by 1 (burn 1 stake at a time) * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * @param user user address */ function _spendBurnStakeAllowance(address user) private { uint256 currentAllowance = allowanceBurnStakes(user, _msgSender()); if (currentAllowance != type(uint256).max) { if (currentAllowance == 0) revert Helios_InsufficientBurnAllowance(); --s_allowanceBurnStakes[user][_msgSender()]; } } /** @dev reduce user's allowance for caller (spender/project) by 1 (burn 1 mint at a time) * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * @param user user address */ function _spendBurnMintAllowance(address user) private { uint256 currentAllowance = allowanceBurnMints(user, _msgSender()); if (currentAllowance != type(uint256).max) { if (currentAllowance == 0) revert Helios_InsufficientBurnAllowance(); --s_allowanceBurnMints[user][_msgSender()]; } } //Views /** @dev calculate user payout reward with specified cycle day and claim type (shares/burn). * it loops through all the unclaimed cylce index until the latest cycle index * @param user user address * @param cycleNo cycle day 7, 25, 69, 183, 420 * @return rewards calculated reward * @return ethRewards calculated reward * @return userClaimCycleIndex last claim cycle index * @return userClaimSharesIndex last claim shares index */ function calculateUserCycleReward( address user, uint256 cycleNo ) public view returns ( uint256 rewards, uint256 ethRewards, uint256 userClaimCycleIndex, uint256 userClaimSharesIndex ) { uint256 cycleMaxIndex = getCurrentCycleIndex(cycleNo); (userClaimCycleIndex, userClaimSharesIndex) = getUserLastClaimIndex( user, cycleNo ); uint256 sharesMaxIndex = getUserLatestShareIndex(user); for (uint256 i = userClaimCycleIndex; i <= cycleMaxIndex; i++) { (uint256 payoutPerShare, uint256 payoutDay) = getPayoutPerShare( cycleNo, i ); (uint256 ethPayoutPerShare, ) = getETHPayoutPerShare(cycleNo, i); uint256 shares; (shares, userClaimSharesIndex) = _getSharesAndUpdateIndex( user, userClaimSharesIndex, sharesMaxIndex, payoutDay ); if (payoutPerShare != 0 && shares != 0) { //reward has 18 decimals scaling, so here divide by 1e18 rewards += (shares * payoutPerShare) / SCALING_FACTOR_1e18; } if (ethPayoutPerShare != 0 && shares != 0) { ethRewards += (shares * ethPayoutPerShare) / SCALING_FACTOR_1e18; } userClaimCycleIndex = i + 1; } } function _getSharesAndUpdateIndex( address user, uint256 userClaimSharesIndex, uint256 sharesMaxIndex, uint256 payoutDay ) private view returns (uint256 shares, uint256) { //loop shares indexes to find the last updated shares before/same triggered payout day for (uint256 j = userClaimSharesIndex; j <= sharesMaxIndex; j++) { if (getUserActiveSharesDay(user, j) <= payoutDay) shares = getUserActiveShares(user, j); else break; userClaimSharesIndex = j; } return (shares, userClaimSharesIndex); } /** @notice get contract ETH balance * @return balance eth balance */ function getBalance() public view returns (uint256) { return address(this).balance; } /** @notice get genesis Wallet Address * @return address */ function getGenesisAddress() public view returns (address) { return s_genesisAddress; } /** @notice get Investment Address * @return address */ function getInvestmentAddress() public view returns (address) { return s_investmentAddress; } /** @notice check if address is whitelisted * @return bool */ function isWhiteListed(address contractAddress) public view returns (bool) { return s_whiteList[contractAddress]; } /** @notice get total TitanX burned by user using this contract * @return total titan burned */ function getTotalTitanXBurned() public view returns (uint256) { return s_totalTitanBurned; } /** @notice get contract TitanX balance * @return balance TitanX balance */ function getTitanXBalance() public view returns (uint256) { return IERC20(s_titanxAddress).balanceOf(address(this)); } /** @notice get contract Hlx balance * @return balance Hlx balance */ function getHlxBalance() public view returns (uint256) { return balanceOf(address(this)); } /** @notice get undistributed TitanX balance * @return amount titanX amount */ function getUndistributedTitanX() public view returns (uint256) { return s_undistributedTitanX; } /** @notice get undistributed ETH balance * @return amount ETH */ function getUndistributedETH() public view returns (uint256) { return s_undistributedETH; } /** @notice get estimated Hlx at end of miner * @return amount of hlx */ function getMintableHlx( uint256 mintPower, uint256 numOfDays, uint256 titanToBurn, address user ) public view returns (uint256) { uint256 mintCost = getMintCost(mintPower, getCurrentMintCost()); uint256 percentage = _calculateBonusPercentage(titanToBurn, mintCost); return calculateMintReward( mintPower, numOfDays, getCurrentMintableHlx(), getCurrentEAABonus(), getUserBurnAmplifierBonus(user), percentage ); } /** @notice get estimated shares */ function estimateShares( uint256 amount, uint256 numOfDays ) public view returns (uint256 sharesWithBonus, uint256 sharesWithoutBonus) { uint256 shareRate = getCurrentShareRate(); sharesWithBonus = calculateShares(amount, numOfDays, shareRate); sharesWithoutBonus = amount / (shareRate / SCALING_FACTOR_1e18); } /** @notice calculate share bonus * @return shareBonus calculated shares bonus in 11 decimals */ function getShareBonus(uint256 noOfDays) public pure returns (uint256) { return calculateShareBonus(noOfDays); } /** @notice get user TitanX payout for all cycles * @param user user address * @return reward total reward */ function getUserTitanXClaimableTotal( address user ) public view returns (uint256 reward) { uint256 _reward; (_reward, , , ) = calculateUserCycleReward(user, DAY22); reward += _reward; (_reward, , , ) = calculateUserCycleReward(user, DAY69); reward += _reward; (_reward, , , ) = calculateUserCycleReward(user, DAY420); reward += _reward; } /** @notice get user ETH payout for all cycles * @param user user address * @return reward total reward */ function getUserETHClaimableTotal( address user ) public view returns (uint256 reward) { uint256 _reward; (, _reward, , ) = calculateUserCycleReward(user, DAY22); reward += _reward; (, _reward, , ) = calculateUserCycleReward(user, DAY69); reward += _reward; (, _reward, , ) = calculateUserCycleReward(user, DAY420); reward += _reward; } /** @notice get total penalties from mint and stake * @return amount total penalties */ function getTotalPenalties() public view returns (uint256) { return getTotalMintPenalty() + getTotalStakePenalty(); } /** @notice returns user's burn stakes allowance of a project * @param user user address * @param spender project address */ function allowanceBurnStakes( address user, address spender ) public view returns (uint256) { return s_allowanceBurnStakes[user][spender]; } /** @notice returns user's burn mints allowance of a project * @param user user address * @param spender project address */ function allowanceBurnMints( address user, address spender ) public view returns (uint256) { return s_allowanceBurnMints[user][spender]; } /** @notice Burn Helios tokens and creates Proof-Of-Burn record to be used by connected DeFi and fee is paid to specified address * @param user user address * @param amount helios amount * @param userRebatePercentage percentage for user rebate in liquid helios (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid helios (0 - 8) * @param rewardPaybackAddress builder can opt to receive fee in another address */ function burnTokensToPayAddress( address user, uint256 amount, uint256 userRebatePercentage, uint256 rewardPaybackPercentage, address rewardPaybackAddress ) public dailyUpdate nonReentrant { _burnLiquidHlx( user, amount, userRebatePercentage, rewardPaybackPercentage, rewardPaybackAddress ); } /** @notice Burn Hlx tokens and creates Proof-Of-Burn record to be used by connected DeFi and fee is paid to specified address * @param user user address * @param amount helios amount * @param userRebatePercentage percentage for user rebate in liquid helios (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid helios (0 - 8) */ function burnTokens( address user, uint256 amount, uint256 userRebatePercentage, uint256 rewardPaybackPercentage ) public dailyUpdate nonReentrant { _burnLiquidHlx( user, amount, userRebatePercentage, rewardPaybackPercentage, _msgSender() ); } /** @notice receive eth */ receive() external payable { if (msg.value > 0) { s_undistributedETH += msg.value; } } /** @notice allows user to burn liquid helios directly from contract * @param amount helios amount */ function userBurnTokens(uint256 amount) public dailyUpdate nonReentrant { if (amount == 0) revert Helios_InvalidAmount(); if (balanceOf(_msgSender()) < amount) revert Helios_InsufficientBalance(); _burn(_msgSender(), amount); _updateBurnAmount(_msgSender(), address(0), amount, BurnSource.LIQUID); } /** @notice Burn stake and creates Proof-Of-Burn record to be used by connected DeFi and fee is paid to specified address * @param user user address * @param id stake id * @param userRebatePercentage percentage for user rebate in liquid helios (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid helios (0 - 8) * @param rewardPaybackAddress builder can opt to receive fee in another address */ function burnStakeToPayAddress( address user, uint256 id, uint256 userRebatePercentage, uint256 rewardPaybackPercentage, address rewardPaybackAddress ) public dailyUpdate nonReentrant { _burnStake( user, id, userRebatePercentage, rewardPaybackPercentage, rewardPaybackAddress ); } /** @notice Burn stake and creates Proof-Of-Burn record to be used by connected DeFi and fee is paid to project contract address * @param user user address * @param id stake id * @param userRebatePercentage percentage for user rebate in liquid helios (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid helios (0 - 8) */ function burnStake( address user, uint256 id, uint256 userRebatePercentage, uint256 rewardPaybackPercentage ) public dailyUpdate nonReentrant { _burnStake( user, id, userRebatePercentage, rewardPaybackPercentage, _msgSender() ); } /** @notice allows user to burn stake directly from contract * @param id stake id */ function userBurnStake(uint256 id) public dailyUpdate nonReentrant { _updateBurnAmount( _msgSender(), address(0), _endStake( _msgSender(), id, getCurrentContractDay(), StakeAction.BURN, StakeAction.END_OWN, getGlobalPayoutTriggered() ), BurnSource.STAKE ); } /** @notice Burn mint and creates Proof-Of-Burn record to be used by connected DeFi. * Burn mint has no project reward or user rebate * @param user user address * @param id mint id */ function burnMint( address user, uint256 id ) public dailyUpdate nonReentrant { _burnMint(user, id); } /** @notice allows user to burn mint directly from contract * @param id mint id */ function userBurnMint(uint256 id) public dailyUpdate nonReentrant { _updateBurnAmount( _msgSender(), address(0), _claimMint(_msgSender(), id, MintAction.BURN), BurnSource.MINT ); } /** @notice Sets `amount` as the allowance of `spender` over the caller's (user) mints. * @param spender contract address * @param amount allowance amount */ function approveBurnMints( address spender, uint256 amount ) public returns (bool) { if (spender == address(0)) revert Helios_InvalidAddress(); s_allowanceBurnMints[_msgSender()][spender] = amount; emit ApproveBurnMints(_msgSender(), spender, amount); return true; } /** @notice Sets `amount` as the allowance of `spender` over the caller's (user) stakes. * @param spender contract address * @param amount allowance amount */ function approveBurnStakes( address spender, uint256 amount ) public returns (bool) { if (spender == address(0)) revert Helios_InvalidAddress(); s_allowanceBurnStakes[_msgSender()][spender] = amount; emit ApproveBurnStakes(_msgSender(), spender, amount); return true; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the 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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.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); }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "../libs/constant.sol"; import "../libs/enum.sol"; /** * @title BurnInfo * @dev this contract is meant to be inherited into main contract * @notice It has the variables and functions specifically for tracking burn amount and reward */ abstract contract BurnInfo { //Variables //track the total helios burn amount uint256 private s_totalHlxBurned; //mappings //track wallet address -> total helios burn amount mapping(address => uint256) private s_userBurnAmount; //track contract/project address -> total helios burn amount mapping(address => uint256) private s_project_BurnAmount; //track contract/project address, wallet address -> total helios burn amount mapping(address => mapping(address => uint256)) private s_projectUser_BurnAmount; //events /** @dev log user burn helios event * project can be address(0) if user burns helios directly from helios contract * burnPoolCycleIndex is the cycle 28 index, which reuse the same index as Day 28 cycle index * helioSource 0=Liquid, 1=Mint, 2=Stake */ event HlxBurned( address indexed user, address indexed project, uint256 amount, BurnSource helioSource ); //functions /** @dev update the burn amount in each 28-cylce for user and project (if any) * @param user wallet address * @param project contract address * @param amount helios amount burned */ function _updateBurnAmount( address user, address project, uint256 amount, BurnSource source ) internal { s_userBurnAmount[user] += amount; s_totalHlxBurned += amount; if (project != address(0)) { s_project_BurnAmount[project] += amount; s_projectUser_BurnAmount[project][user] += amount; } emit HlxBurned(user, project, amount, source); } /** @dev returned value is in 18 decimals, need to divide it by 1e18 and 100 (percentage) when using this value for reward calculation * The burn amplifier percentage is applied to all future mints. Capped at MAX_BURN_AMP_PERCENT (8%) * @param user wallet address * @return percentage returns percentage value in 18 decimals */ function getUserBurnAmplifierBonus( address user ) public view returns (uint256) { uint256 userBurnTotal = getUserBurnTotal(user); if (userBurnTotal == 0) return 0; if (userBurnTotal >= MAX_BURN_AMP_BASE) return MAX_BURN_AMP_PERCENT; return (MAX_BURN_AMP_PERCENT * userBurnTotal) / MAX_BURN_AMP_BASE; } //views /** @notice return total burned helios amount from all users burn or projects burn * @return totalBurnAmount returns entire burned helios */ function getTotalBurnTotal() public view returns (uint256) { return s_totalHlxBurned; } /** @notice return user address total burned helios * @return userBurnAmount returns user address total burned helios */ function getUserBurnTotal(address user) public view returns (uint256) { return s_userBurnAmount[user]; } /** @notice return project address total burned helios amount * @return projectTotalBurnAmount returns project total burned helios */ function getProjectBurnTotal( address contractAddress ) public view returns (uint256) { return s_project_BurnAmount[contractAddress]; } /** @notice return user address total burned helios amount via a project address * @param contractAddress project address * @param user user address * @return projectUserTotalBurnAmount returns user address total burned helios via a project address */ function getProjectUserBurnTotal( address contractAddress, address user ) public view returns (uint256) { return s_projectUser_BurnAmount[contractAddress][user]; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "../libs/enum.sol"; import "../libs/constant.sol"; abstract contract GlobalInfo { //Variables //deployed timestamp uint256 private immutable i_genesisTs; /** @dev track current contract day */ uint256 private s_currentContractDay; /** @dev shareRate starts 420 ether and increases capped at 1500 ether */ uint256 private s_currentshareRate; /** @dev mintCost starts 420m ether increases and capped at 2B ether, uin256 has enough size */ uint256 private s_currentMintCost; /** @dev mintableHlx starts 4.2m ether decreases and capped at 420 ether, uint96 has enough size */ uint256 private s_currentMintableHlx; /** @dev mintPowerBonus starts 350_000_000 and decreases capped at 35_000 */ uint256 private s_currentMintPowerBonus; /** @dev EAABonus starts 10_000_000 and decreases to 0 */ uint256 private s_currentEAABonus; /** @dev 7 day update for percentages */ uint256 private s_nextSevenDayUpdate; /** @dev Percentage Share to BuynBurn */ uint256 private s_percentBuynBurn; /** @dev Percentage to Treasury*/ uint256 private s_percentTreasury; /** @dev track if any of the cycle day 22, 69, 420 has payout triggered succesfully * this is used in end stake where either the shares change should be tracked in current/next payout cycle */ PayoutTriggered private s_isGlobalPayoutTriggered; /** @dev track payouts based on every cycle day 22, 69, 420 when distributeTitanX() is called */ mapping(uint256 => uint256) private s_cyclePayouts; /** @dev track payouts based on every cycle day 22, 69, 420 when distributeETH() is called */ mapping(uint256 => uint256) private s_ethCyclePayouts; /** @dev track payout index for each cycle day, increased by 1 when triggerPayouts() is called succesfully * eg. curent index is 2, s_cyclePayoutIndex[DAY22] = 2 */ mapping(uint256 => uint256) private s_cyclePayoutIndex; /** @dev track payout info (day and payout per share) for each cycle day * eg. s_cyclePayoutIndex is 2, * s_CyclePayoutPerShare[DAY22][2].day = 22 * s_CyclePayoutPerShare[DAY22][2].payoutPerShare = 0.1 */ mapping(uint256 => mapping(uint256 => CycleRewardPerShare)) private s_cyclePayoutPerShare; /** @dev track payout info (day and payout per share) for each cycle day * eg. s_cyclePayoutIndex is 2, * s_ETHCyclePayoutPerShare[DAY22][2].day = 7 * s_ETHCyclePayoutPerShare[DAY22][2].payoutPerShare = 0.1 */ mapping(uint256 => mapping(uint256 => CycleRewardPerShare)) private s_ethCyclePayoutPerShare; /** @dev track user last payout reward claim index for cycleIndex and sharesIndex * so calculation would start from next index instead of the first index * [address][DAY22].cycleIndex = 1 * [address][DAY22].sharesIndex = 2 * cycleIndex is the last stop in s_cyclePayoutPerShare * sharesIndex is the last stop in s_addressIdToActiveShares */ mapping(address => mapping(uint256 => UserCycleClaimIndex)) private s_addressCycleToLastClaimIndex; /** @dev track when is the next cycle payout day for each cycle day * eg. s_nextCyclePayoutDay[DAY22] = 22 * s_nextCyclePayoutDay[DAY69] = 69 */ mapping(uint256 => uint256) s_nextCyclePayoutDay; //structs struct CycleRewardPerShare { uint256 day; uint256 payoutPerShare; } struct UserCycleClaimIndex { uint256 cycleIndex; uint256 sharesIndex; } //event event GlobalDailyUpdateStats( uint256 indexed day, uint256 indexed mintCost, uint256 mintableHlx, uint256 mintPowerBonus, uint256 EAABonus ); /** @dev Update variables in terms of day, modifier is used in all external/public functions (exclude view) * Every interaction to the contract would run this function to update variables */ modifier dailyUpdate() { _dailyUpdate(); _; } constructor() { i_genesisTs = block.timestamp; s_currentContractDay = 1; s_currentMintCost = START_MAX_MINT_COST; s_currentMintableHlx = START_MAX_MINTABLE_PER_DAY; s_currentshareRate = START_SHARE_RATE; s_currentMintPowerBonus = START_MINTPOWER_INCREASE_BONUS; s_currentEAABonus = EAA_START; s_nextCyclePayoutDay[DAY22] = DAY22; s_nextCyclePayoutDay[DAY69] = DAY69; s_nextCyclePayoutDay[DAY420] = DAY420; s_nextSevenDayUpdate = 7; s_percentBuynBurn = 60_00; s_percentTreasury = 10_00; } /** @dev calculate and update variables daily and reset triggers flag */ function _dailyUpdate() private { uint256 currentContractDay = s_currentContractDay; uint256 currentBlockDay = ((block.timestamp - i_genesisTs) / 1 days) + 1; if (currentBlockDay > currentContractDay) { //get last day info ready for calculation uint256 newMintCost = s_currentMintCost; uint256 newMintableHlx = s_currentMintableHlx; uint256 newMintPowerBonus = s_currentMintPowerBonus; uint256 newEAABonus = s_currentEAABonus; uint256 dayDifference = currentBlockDay - currentContractDay; /** Reason for a for loop to update Mint supply * Ideally, user interaction happens daily, so Mint supply is synced in every day * (cylceDifference = 1) * However, if there's no interaction for more than 1 day, then * Mint supply isn't updated correctly due to cylceDifference > 1 day * Eg. 2 days of no interaction, then interaction happens in 3rd day. * It's incorrect to only decrease the Mint supply one time as now it's in 3rd day. * And if this happens, there will be no tracked data for the skipped days as not needed */ for (uint256 i; i < dayDifference; i++) { newMintCost = (newMintCost * DAILY_MINT_COST_INCREASE_STEP) / PERCENT_BPS; newMintableHlx = (newMintableHlx * DAILY_SUPPLY_MINTABLE_REDUCTION) / PERCENT_BPS; newMintPowerBonus = (newMintPowerBonus * DAILY_MINTPOWER_INCREASE_BONUS_REDUCTION) / PERCENT_BPS; if (newMintCost > CAPPED_MAX_MINT_COST) { newMintCost = CAPPED_MAX_MINT_COST; } if ( currentContractDay >= s_nextSevenDayUpdate && s_percentBuynBurn != PERCENT_TO_BUY_AND_BURN_FINAL && s_percentTreasury != PERCENT_TO_TREASURY_FINAL ) { s_percentBuynBurn -= PERCENT_CHANGE; s_percentTreasury += PERCENT_CHANGE; s_nextSevenDayUpdate += 7; } if (newMintableHlx < CAPPED_MIN_DAILY_HLX_MINTABLE) { newMintableHlx = CAPPED_MIN_DAILY_HLX_MINTABLE; } if (newMintPowerBonus < CAPPED_MIN_MINTPOWER_BONUS) { newMintPowerBonus = CAPPED_MIN_MINTPOWER_BONUS; } if (currentBlockDay <= MAX_BONUS_DAY) { newEAABonus -= EAA_BONUSE_FIXED_REDUCTION_PER_DAY; } else { newEAABonus = EAA_END; } emit GlobalDailyUpdateStats( ++currentContractDay, newMintCost, newMintableHlx, newMintPowerBonus, newEAABonus ); } s_currentMintCost = newMintCost; s_currentMintableHlx = newMintableHlx; s_currentMintPowerBonus = newMintPowerBonus; s_currentEAABonus = newEAABonus; s_currentContractDay = currentBlockDay; s_isGlobalPayoutTriggered = PayoutTriggered.NO; } } /** @dev first created shares will start from the last payout index + 1 (next cycle payout) * as first shares will always disqualified from past payouts * reduce gas cost needed to loop from first index * @param user user address * @param isFirstShares flag to only initialize when address is fresh wallet */ function _initFirstSharesCycleIndex( address user, uint256 isFirstShares ) internal { if (isFirstShares == 1) { if (s_cyclePayoutIndex[DAY22] != 0) { s_addressCycleToLastClaimIndex[user][DAY22].cycleIndex = s_cyclePayoutIndex[DAY22] + 1; s_addressCycleToLastClaimIndex[user][DAY69].cycleIndex = s_cyclePayoutIndex[DAY69] + 1; s_addressCycleToLastClaimIndex[user][DAY420] .cycleIndex = uint96(s_cyclePayoutIndex[DAY420] + 1); } } } /** @dev first created shares will start from the last payout index + 1 (next cycle payout) * as first shares will always disqualified from past payouts * reduce gas cost needed to loop from first index * @param cycleNo cylce day 22, 69, 420 * @param reward total accumulated reward in cycle day 22, 69, 420 * @param globalActiveShares global active shares * @return index return latest current cycleIndex */ function _calculateCycleRewardPerShare( uint256 cycleNo, uint256 reward, uint256 ethReward, uint256 globalActiveShares ) internal returns (uint256 index) { s_cyclePayouts[cycleNo] = 0; s_ethCyclePayouts[cycleNo] = 0; index = ++s_cyclePayoutIndex[cycleNo]; //add 18 decimals to reward for better precision in calculation s_cyclePayoutPerShare[cycleNo][index].payoutPerShare = (reward * SCALING_FACTOR_1e18) / globalActiveShares; s_cyclePayoutPerShare[cycleNo][index].day = getCurrentContractDay(); s_ethCyclePayoutPerShare[cycleNo][index].payoutPerShare = (ethReward * SCALING_FACTOR_1e18) / globalActiveShares; s_ethCyclePayoutPerShare[cycleNo][index].day = getCurrentContractDay(); } /** @dev update with the last index where a user has claimed the payout reward * @param user user address * @param cycleNo cylce day 22, 69, 420 * @param userClaimCycleIndex last claimed cycle index * @param userClaimSharesIndex last claimed shares index */ function _updateUserClaimIndexes( address user, uint256 cycleNo, uint256 userClaimCycleIndex, uint256 userClaimSharesIndex ) internal { if ( userClaimCycleIndex != s_addressCycleToLastClaimIndex[user][cycleNo].cycleIndex ) s_addressCycleToLastClaimIndex[user][cycleNo] .cycleIndex = userClaimCycleIndex; if ( userClaimSharesIndex != s_addressCycleToLastClaimIndex[user][cycleNo].sharesIndex ) s_addressCycleToLastClaimIndex[user][cycleNo] .sharesIndex = userClaimSharesIndex; } /** @dev set to YES when any of the cycle days payout is triggered * reset to NO in new contract day */ function _setGlobalPayoutTriggered() internal { s_isGlobalPayoutTriggered = PayoutTriggered.YES; } /** @dev add reward into cycle day 22, 69, 420 pool * @param cycleNo cycle day 22, 69, 420 * @param reward reward from distributeETH() */ function _setCyclePayoutPool(uint256 cycleNo, uint256 reward) internal { s_cyclePayouts[cycleNo] += reward; } /** @dev add ETH reward into cycle day 22, 69, 420 pool * @param cycleNo cycle day 22, 69, 420 * @param ethReward reward */ function _setETHCyclePayoutPool( uint256 cycleNo, uint256 ethReward ) internal { s_ethCyclePayouts[cycleNo] += ethReward; } /** @dev calculate and update the next payout day for specified cycleNo * the formula will update the payout day based on current contract day * this is to make sure the value is correct when for some reason has skipped more than one cycle payout * @param cycleNo cycle day 22, 69, 420 */ function _setNextCyclePayoutDay(uint256 cycleNo) internal { uint256 maturityDay = s_nextCyclePayoutDay[cycleNo]; uint256 currentContractDay = s_currentContractDay; if (currentContractDay >= maturityDay) { s_nextCyclePayoutDay[cycleNo] += cycleNo * (((currentContractDay - maturityDay) / cycleNo) + 1); } } //Public functions /** @notice allow anyone to sync dailyUpdate manually */ function manualDailyUpdate() public dailyUpdate {} /** Views */ /** @notice Returns current block timestamp * @return currentBlockTs current block timestamp */ function getCurrentBlockTimeStamp() public view returns (uint256) { return block.timestamp; } /** @notice Returns current contract day * @return currentContractDay current contract day */ function getCurrentContractDay() public view returns (uint256) { return s_currentContractDay; } /** @notice Returns current Treasury Percentage * @return percentTreasury current day */ function getTreasuryPercentage() public view returns (uint256) { return s_percentTreasury; } /** @notice Returns current BuynBurn Percentage * @return percentBuynBurn current day */ function getBuynBurnPercentage() public view returns (uint256) { return s_percentBuynBurn; } /** @notice Returns current mint cost * @return currentMintCost current block timestamp */ function getCurrentMintCost() public view returns (uint256) { return s_currentMintCost; } /** @notice Returns current share rate * @return currentShareRate current share rate */ function getCurrentShareRate() public view returns (uint256) { return s_currentshareRate; } /** @notice Returns current mintable Helios * @return currentMintableHlx current mintable Helios */ function getCurrentMintableHlx() public view returns (uint256) { return s_currentMintableHlx; } /** @notice Returns current mint power bonus * @return currentMintPowerBonus current mint power bonus */ function getCurrentMintPowerBonus() public view returns (uint256) { return s_currentMintPowerBonus; } /** @notice Returns current contract EAA bonus * @return currentEAABonus current EAA bonus */ function getCurrentEAABonus() public view returns (uint256) { return s_currentEAABonus; } /** @notice Returns current cycle index for the specified cycle day * @param cycleNo cycle day 22, 69, 420 * @return currentCycleIndex current cycle index to track the payouts */ function getCurrentCycleIndex( uint256 cycleNo ) public view returns (uint256) { return s_cyclePayoutIndex[cycleNo]; } /** @notice Returns whether payout is triggered successfully in any cylce day * @return isTriggered 0 or 1, 0= No, 1=Yes */ function getGlobalPayoutTriggered() public view returns (PayoutTriggered) { return s_isGlobalPayoutTriggered; } /** @notice Returns the distributed pool reward for the specified cycle day * @param cycleNo cycle day 22, 69, 420 * @return currentPayoutPool current accumulated payout pool */ function getCyclePayoutPool(uint256 cycleNo) public view returns (uint256) { return s_cyclePayouts[cycleNo]; } /** @notice Returns the distributed ETH pool reward for the specified cycle day * @param cycleNo cycle day 22, 69, 420 * @return currentPayoutPool current accumulated payout pool */ function getETHCyclePayoutPool( uint256 cycleNo ) public view returns (uint256) { return s_ethCyclePayouts[cycleNo]; } /** @notice Returns the calculated payout per share and contract day for the specified cycle day and index * @param cycleNo cycle day 22, 69, 420 * @param index cycle index * @return payoutPerShare calculated payout per share * @return triggeredDay the day when payout was triggered to perform calculation */ function getPayoutPerShare( uint256 cycleNo, uint256 index ) public view returns (uint256, uint256) { return ( s_cyclePayoutPerShare[cycleNo][index].payoutPerShare, s_cyclePayoutPerShare[cycleNo][index].day ); } /** @notice Returns the calculated ETH payout per share and contract day for the specified cycle day and index * @param cycleNo cycle day 22, 69, 420 * @param index cycle index * @return payoutPerShare calculated payout per share * @return triggeredDay the day when payout was triggered to perform calculation */ function getETHPayoutPerShare( uint256 cycleNo, uint256 index ) public view returns (uint256, uint256) { return ( s_ethCyclePayoutPerShare[cycleNo][index].payoutPerShare, s_ethCyclePayoutPerShare[cycleNo][index].day ); } /** @notice Returns user's last claimed shares payout indexes for the specified cycle day * @param user user address * @param cycleNo cycle day 22, 69, 420 * @return cycleIndex cycle index * @return sharesIndex shares index */ function getUserLastClaimIndex( address user, uint256 cycleNo ) public view returns (uint256 cycleIndex, uint256 sharesIndex) { return ( s_addressCycleToLastClaimIndex[user][cycleNo].cycleIndex, s_addressCycleToLastClaimIndex[user][cycleNo].sharesIndex ); } /** @notice Returns contract deployment block timestamp * @return genesisTs deployed timestamp */ function genesisTs() public view returns (uint256) { return i_genesisTs; } /** @notice Returns next payout day for the specified cycle day * @param cycleNo cycle day 22, 69, 420 * @return nextPayoutDay next payout day */ function getNextCyclePayoutDay( uint256 cycleNo ) public view returns (uint256) { return s_nextCyclePayoutDay[cycleNo]; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "../libs/calcFunctions.sol"; //custom errors error Helios_InvalidMintLength(); error Helios_InvalidMintPower(); error Helios_NoMintExists(); error Helios_MintHasClaimed(); error Helios_MintNotMature(); error Helios_MintHasBurned(); abstract contract MintInfo { //variables /** @dev track global hRank */ uint256 private s_globalHRank; /** @dev track total mint claimed */ uint256 private s_globalMintClaim; /** @dev track total mint burned */ uint256 private s_globalMintBurn; /** @dev track total helios minting */ uint256 private s_globalHlxMinting; /** @dev track total helios penalty */ uint256 private s_globalHlxMintPenalty; /** @dev track global mint power */ uint256 private s_globalMintPower; //mappings /** @dev track address => mintId */ mapping(address => uint256) private s_addressMId; /** @dev track address, mintId => hRank info (gHrank, gMintPower) */ mapping(address => mapping(uint256 => HRankInfo)) private s_addressMIdToHRankInfo; /** @dev track global hRank => mintInfo*/ mapping(uint256 => UserMintInfo) private s_hRankToMintInfo; //structs struct UserMintInfo { uint256 mintPower; uint16 numOfDays; uint256 mintableHlx; uint48 mintStartTs; uint48 maturityTs; uint256 mintPowerBonus; uint256 EAABonus; uint256 mintedHlx; uint256 mintCost; uint256 penalty; uint256 titanBurned; MintStatus status; } struct HRankInfo { uint256 hRank; uint256 gMintPower; } struct UserMint { uint256 mId; uint256 hRank; uint256 gMintPower; UserMintInfo mintInfo; } //events event MintStarted( address indexed user, uint256 indexed hRank, uint256 indexed gMintpower, UserMintInfo userMintInfo ); event MintClaimed( address indexed user, uint256 indexed hRank, uint256 rewardMinted, uint256 indexed penalty, uint256 mintPenalty ); //functions /** @dev create a new mint * @param user user address * @param mintPower mint power * @param numOfDays mint lenght * @param mintableHlx mintable helios * @param mintPowerBonus mint power bonus * @param EAABonus EAA bonus * @param burnAmpBonus burn amplifier bonus * @param gMintPower global mint power * @param currentHRank current global hRank * @param mintCost actual mint cost paid for a mint * @param titanAmount titan Burned amount */ function _startMint( address user, uint256 mintPower, uint256 numOfDays, uint256 mintableHlx, uint256 mintPowerBonus, uint256 EAABonus, uint256 burnAmpBonus, uint256 gMintPower, uint256 currentHRank, uint256 mintCost, uint256 titanAmount ) internal returns (uint256 mintable) { if (numOfDays == 0 || numOfDays > MAX_MINT_LENGTH) revert Helios_InvalidMintLength(); if (mintPower == 0 || mintPower > MAX_MINT_POWER_CAP) revert Helios_InvalidMintPower(); uint256 percentage = 0; if (titanAmount > 0) { percentage = _calculateBonusPercentage(titanAmount, mintCost); } //calculate mint reward up front with the provided params mintable = calculateMintReward( mintPower, numOfDays, mintableHlx, EAABonus, burnAmpBonus, percentage ); _storeMintInfo( user, mintPower, numOfDays, mintable, mintPowerBonus, EAABonus, currentHRank, gMintPower, mintCost, titanAmount ); } function _calculateBonusPercentage( uint256 titanAmount, uint256 mintCost ) internal pure returns (uint256) { uint256 percentage = (titanAmount * 10000) / mintCost; return percentage; } function _storeMintInfo( address user, uint256 mintPower, uint256 numOfDays, uint256 mintable, uint256 mintPowerBonus, uint256 EAABonus, uint256 currentHRank, uint256 gMintPower, uint256 mintCost, uint256 titanAmount ) private { //store variables into mint info UserMintInfo memory userMintInfo = UserMintInfo({ mintPower: mintPower, numOfDays: uint16(numOfDays), mintableHlx: mintable, mintPowerBonus: mintPowerBonus, EAABonus: EAABonus, mintStartTs: uint48(block.timestamp), maturityTs: uint48(block.timestamp + (numOfDays * SECONDS_IN_DAY)), mintedHlx: 0, mintCost: mintCost, penalty: 0, titanBurned: titanAmount, status: MintStatus.ACTIVE }); /** s_addressMId[user] tracks mintId for each addrress * s_addressMIdToHRankInfo[user][id] tracks current mint hRank and gPowerMint * s_hRankToMintInfo[currentHRank] stores mint info */ uint256 id = ++s_addressMId[user]; s_addressMIdToHRankInfo[user][id].hRank = currentHRank; s_addressMIdToHRankInfo[user][id].gMintPower = gMintPower; s_hRankToMintInfo[currentHRank] = userMintInfo; emit MintStarted(user, currentHRank, gMintPower, userMintInfo); } /** @dev update variables * @param currentHRank current hRank * @param gMintPower current global mint power * @param gMinting current global minting */ function _updateMintStats( uint256 currentHRank, uint256 gMintPower, uint256 gMinting ) internal { s_globalHRank = currentHRank; s_globalMintPower = gMintPower; s_globalHlxMinting = gMinting; } /** @dev calculate reward for claim mint or burn mint. * Claim mint has maturity check while burn mint would bypass maturity check. * @param user user address * @param id mint id * @param action claim mint or burn mint * @return reward calculated final reward after all bonuses and penalty (if any) */ function _claimMint( address user, uint256 id, MintAction action ) internal returns (uint256 reward) { uint256 hRank = s_addressMIdToHRankInfo[user][id].hRank; uint256 gMintPower = s_addressMIdToHRankInfo[user][id].gMintPower; if (hRank == 0) revert Helios_NoMintExists(); UserMintInfo memory mint = s_hRankToMintInfo[hRank]; if (mint.status == MintStatus.CLAIMED) revert Helios_MintHasClaimed(); if (mint.status == MintStatus.BURNED) revert Helios_MintHasBurned(); //Only check maturity for claim mint action, burn mint bypass this check if (mint.maturityTs > block.timestamp && action == MintAction.CLAIM) revert Helios_MintNotMature(); s_globalHlxMinting -= mint.mintableHlx; reward = _calculateClaimReward(user, hRank, gMintPower, mint, action); } /** @dev calculate final reward with bonuses and penalty (if any) * @param user user address * @param hRank mint's hRank * @param gMintPower mint's gMintPower * @param userMintInfo mint's info * @param action claim mint or burn mint * @return reward calculated final reward after all bonuses and penalty (if any) */ function _calculateClaimReward( address user, uint256 hRank, uint256 gMintPower, UserMintInfo memory userMintInfo, MintAction action ) private returns (uint256 reward) { if (action == MintAction.CLAIM) s_hRankToMintInfo[hRank].status = MintStatus.CLAIMED; if (action == MintAction.BURN) s_hRankToMintInfo[hRank].status = MintStatus.BURNED; uint256 penaltyAmount; uint256 penalty; uint256 bonus; //only calculate penalty when current block timestamp > maturity timestamp if (block.timestamp > userMintInfo.maturityTs) { penalty = calculateClaimMintPenalty( block.timestamp - userMintInfo.maturityTs ); } //Only Claim action has mintPower bonus if (action == MintAction.CLAIM) { bonus = calculateMintPowerBonus( userMintInfo.mintPowerBonus, userMintInfo.mintPower, gMintPower, s_globalMintPower ); } //mintPowerBonus has scaling factor of 1e7, so divide by 1e7 reward = uint256(userMintInfo.mintableHlx) + (bonus / SCALING_FACTOR_1e7); penaltyAmount = (reward * penalty) / 100; reward -= penaltyAmount; if (action == MintAction.CLAIM) ++s_globalMintClaim; if (action == MintAction.BURN) ++s_globalMintBurn; if (penaltyAmount != 0) s_globalHlxMintPenalty += penaltyAmount; //only stored minted amount for claim mint if (action == MintAction.CLAIM) { s_hRankToMintInfo[hRank].mintedHlx = reward; s_hRankToMintInfo[hRank].penalty = penaltyAmount; } emit MintClaimed(user, hRank, reward, penalty, penaltyAmount); } //views /** @notice Returns the latest Mint Id of an address * @param user address * @return mId latest mint id */ function getUserLatestMintId(address user) public view returns (uint256) { return s_addressMId[user]; } /** * @dev Estimates the reward for a specific mint operation for a user, including any applicable bonuses and subtracting penalties for late claims. * This function calculates an estimate of the total reward a user can expect from a mint at the time of its maturity, based on the current state. * * @param user The address of the user who initiated the mint operation. * @param mintId The unique identifier of the mint operation for which the reward is being estimated. */ function estimateMintReward( address user, uint256 mintId ) public view returns (uint256 baseReward) { uint256 hRank = s_addressMIdToHRankInfo[user][mintId].hRank; uint256 gMintPower = s_addressMIdToHRankInfo[user][mintId].gMintPower; if (hRank == 0) revert Helios_NoMintExists(); UserMintInfo memory mint = s_hRankToMintInfo[hRank]; // Base mintable HLX baseReward = mint.mintableHlx; // Calculate additional rewards here. uint256 bonus = calculateMintPowerBonus( mint.mintPowerBonus, mint.mintPower, gMintPower, s_globalMintPower ); baseReward += baseReward + (bonus / SCALING_FACTOR_1e7); //hypothetical bonus } /** @notice Returns mint info of an address + mint id * @param user address * @param id mint id * @return mintInfo user mint info */ function getUserMintInfo( address user, uint256 id ) public view returns (UserMintInfo memory mintInfo) { return s_hRankToMintInfo[s_addressMIdToHRankInfo[user][id].hRank]; } /** @notice Return all mints info of an address * @param user address * @return mintInfos all mints info of an address including mint id, hRank and gMintPower */ function getUserMints( address user ) public view returns (UserMint[] memory mintInfos) { uint256 count = s_addressMId[user]; mintInfos = new UserMint[](count); for (uint256 i = 1; i <= count; i++) { mintInfos[i - 1] = UserMint({ mId: i, hRank: s_addressMIdToHRankInfo[user][i].hRank, gMintPower: s_addressMIdToHRankInfo[user][i].gMintPower, mintInfo: getUserMintInfo(user, i) }); } } /** @notice Return total mints burned * @return totalMintBurned total mints burned */ function getTotalMintBurn() public view returns (uint256) { return s_globalMintBurn; } /** @notice Return current gobal hRank * @return globalHRank global hRank */ function getGlobalHRank() public view returns (uint256) { return s_globalHRank; } /** @notice Return current gobal mint power * @return globalMintPower global mint power */ function getGlobalMintPower() public view returns (uint256) { return s_globalMintPower; } /** @notice Return total mints claimed * @return totalMintClaimed total mints claimed */ function getTotalMintClaim() public view returns (uint256) { return s_globalMintClaim; } /** @notice Return total active mints (exluded claimed and burned mints) * @return totalActiveMints total active mints */ function getTotalActiveMints() public view returns (uint256) { return s_globalHRank - s_globalMintClaim - s_globalMintBurn; } /** @notice Return total minting helios * @return totalMinting total minting helios */ function getTotalMinting() public view returns (uint256) { return s_globalHlxMinting; } /** @notice Return total helios penalty * @return totalHlxPenalty total helios penalty */ function getTotalMintPenalty() public view returns (uint256) { return s_globalHlxMintPenalty; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "@openzeppelin/contracts/utils/Context.sol"; error Helios_NotOnwer(); abstract contract OwnerInfo is Context { address private s_owner; /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { s_owner = _msgSender(); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (s_owner != _msgSender()) revert Helios_NotOnwer(); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { _setOwner(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 { _setOwner(newOwner); } function _setOwner(address newOwner) private { s_owner = newOwner; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "../libs/calcFunctions.sol"; //custom errors error Helios_InvalidStakeLength(); error Helios_RequireOneMinimumShare(); error Helios_ExceedMaxAmountPerStake(); error Helios_NoStakeExists(); error Helios_StakeHasEnded(); error Helios_StakeNotMatured(); error Helios_StakeHasBurned(); error Helios_MaxedWalletStakes(); abstract contract StakeInfo { //Variables /** @dev track global stake Id */ uint256 private s_globalStakeId; /** @dev track global shares */ uint256 private s_globalShares; /** @dev track global expired shares */ uint256 private s_globalExpiredShares; /** @dev track global staked Helios */ uint256 private s_globalHlxStaked; /** @dev track global end stake penalty */ uint256 private s_globalStakePenalty; /** @dev track global ended stake */ uint256 private s_globalStakeEnd; /** @dev track global burned stake */ uint256 private s_globalStakeBurn; //mappings /** @dev track address => stakeId */ mapping(address => uint256) private s_addressSId; /** @dev track address, stakeId => global stake Id */ mapping(address => mapping(uint256 => uint256)) private s_addressSIdToGlobalStakeId; /** @dev track global stake Id => stake info */ mapping(uint256 => UserStakeInfo) private s_globalStakeIdToStakeInfo; /** @dev track address => shares Index */ mapping(address => uint256) private s_userSharesIndex; /** @dev track user total active shares by user shares index * s_addressIdToActiveShares[user][index] = UserActiveShares (contract day, total user active shares) * works like a snapshot or log when user shares has changed (increase/decrease) */ mapping(address => mapping(uint256 => UserActiveShares)) private s_addressIdToActiveShares; //structs struct UserStakeInfo { uint256 hlxAmount; uint256 shares; uint16 numOfDays; uint48 stakeStartTs; uint48 maturityTs; uint256 titanBurned; StakeStatus status; } struct UserStake { uint256 sId; uint256 globalStakeId; UserStakeInfo stakeInfo; } struct UserActiveShares { uint256 day; uint256 activeShares; } //events event StakeStarted( address indexed user, uint256 indexed globalStakeId, uint256 numOfDays, UserStakeInfo userStakeInfo ); event StakeEnded( address indexed user, uint256 indexed globalStakeId, uint256 hlxAmount, uint256 indexed penalty, uint256 penaltyAmount ); //functions /** @dev create a new stake * @param user user address * @param amount helios amount * @param numOfDays stake lenght * @param shareRate current share rate * @param day current contract day * @param isPayoutTriggered has global payout triggered * @param titanAmount titan amount burned * @param titanPrice titan price against hlx * @return isFirstShares first created shares or not */ function _startStake( address user, uint256 amount, uint256 numOfDays, uint256 shareRate, uint256 day, PayoutTriggered isPayoutTriggered, uint256 titanAmount, uint256 titanPrice ) internal returns (uint256 isFirstShares) { uint256 sId = ++s_addressSId[user]; if (sId > MAX_STAKE_PER_WALLET) revert Helios_MaxedWalletStakes(); if (numOfDays < MIN_STAKE_LENGTH || numOfDays > MAX_STAKE_LENGTH) revert Helios_InvalidStakeLength(); //calculate shares uint256 shares = calculateShares(amount, numOfDays, shareRate); if (shares / SCALING_FACTOR_1e18 < 1) revert Helios_RequireOneMinimumShare(); if (titanAmount > 0) { uint256 percentage = calculateBonusPercentage( titanAmount, titanPrice, amount ); if (percentage > BURN_STAKE_AMP) percentage = BURN_STAKE_AMP; shares = shares + ((shares * percentage) / PERCENT_BASE); } _storeUserStakesInfo(sId, user, amount, numOfDays, shares, titanAmount); //update shares changes isFirstShares = _updateSharesStats( user, shares, amount, day, isPayoutTriggered, StakeAction.START ); } /** * @dev Calculates the bonus percentage based on the amount of Titan tokens burned. * @param titanAmount The amount of Titan tokens burned by the user. * @param titanPrice The price of Titan tokens relative to Helios. * @param amountStaked The amount of Helios staked by the user. * @return The bonus percentage, scaled to maintain precision. * * This function calculates the value of the burned Titan tokens in terms of the staked Helios tokens. * It then computes the bonus percentage based on this value. The result is scaled to account for * Solidity's lack of support for floating-point arithmetic. */ function calculateBonusPercentage( uint256 titanAmount, uint256 titanPrice, uint256 amountStaked ) internal pure returns (uint256) { uint256 titanValueInHlx = (amountStaked * titanPrice) / SCALING_FACTOR_1e18; uint256 percentage = (titanAmount * PERCENT_BASE) / titanValueInHlx; return percentage; } /** * @dev Records stake information for a user. * @param sId Unique identifier for the stake. * @param user Address of the user staking the tokens. * @param amount Amount of tokens staked. * @param numOfDays Duration of the stake in days. * @param shares Number of shares allocated for the stake. */ function _storeUserStakesInfo( uint256 sId, address user, uint256 amount, uint256 numOfDays, uint256 shares, uint256 titanAmount ) private { uint256 currentGStakeId = ++s_globalStakeId; uint256 maturityTs; maturityTs = block.timestamp + (numOfDays * SECONDS_IN_DAY); UserStakeInfo memory userStakeInfo = UserStakeInfo({ hlxAmount: amount, shares: shares, numOfDays: uint16(numOfDays), stakeStartTs: uint48(block.timestamp), maturityTs: uint48(maturityTs), status: StakeStatus.ACTIVE, titanBurned: titanAmount }); /** s_addressSId[user] tracks stake Id for each address * s_addressSIdToGlobalStakeId[user][id] tracks stack id to global stake Id * s_globalStakeIdToStakeInfo[currentGStakeId] stores stake info */ s_addressSIdToGlobalStakeId[user][sId] = currentGStakeId; s_globalStakeIdToStakeInfo[currentGStakeId] = userStakeInfo; emit StakeStarted(user, currentGStakeId, numOfDays, userStakeInfo); } /** @dev end stake and calculate pinciple with penalties (if any) or burn stake * @param user user address * @param id stake Id * @param day current contract day * @param action end stake or burn stake * @param payOther is end stake for others * @param isPayoutTriggered has global payout triggered * @return helios helios principle */ function _endStake( address user, uint256 id, uint256 day, StakeAction action, StakeAction payOther, PayoutTriggered isPayoutTriggered ) internal returns (uint256 helios) { uint256 globalStakeId = s_addressSIdToGlobalStakeId[user][id]; if (globalStakeId == 0) revert Helios_NoStakeExists(); UserStakeInfo memory userStakeInfo = s_globalStakeIdToStakeInfo[ globalStakeId ]; if (userStakeInfo.status == StakeStatus.ENDED) revert Helios_StakeHasEnded(); if (userStakeInfo.status == StakeStatus.BURNED) revert Helios_StakeHasBurned(); //end stake for others requires matured stake to prevent EES for others if ( payOther == StakeAction.END_OTHER && block.timestamp < userStakeInfo.maturityTs ) revert Helios_StakeNotMatured(); //update shares changes uint256 shares = userStakeInfo.shares; _updateSharesStats( user, shares, userStakeInfo.hlxAmount, day, isPayoutTriggered, action ); if (action == StakeAction.END) { ++s_globalStakeEnd; s_globalStakeIdToStakeInfo[globalStakeId].status = StakeStatus .ENDED; } else if (action == StakeAction.BURN) { ++s_globalStakeBurn; s_globalStakeIdToStakeInfo[globalStakeId].status = StakeStatus .BURNED; } helios = _calculatePrinciple( user, globalStakeId, userStakeInfo, action ); } /** @dev update shares changes to track when user shares has changed, this affect the payout calculation * @param user user address * @param shares shares * @param amount helios amount * @param day current contract day * @param isPayoutTriggered has global payout triggered * @param action start stake or end stake * @return isFirstShares first created shares or not */ function _updateSharesStats( address user, uint256 shares, uint256 amount, uint256 day, PayoutTriggered isPayoutTriggered, StakeAction action ) private returns (uint256 isFirstShares) { //Get previous active shares to calculate new shares change uint256 index = s_userSharesIndex[user]; uint256 previousShares = s_addressIdToActiveShares[user][index] .activeShares; if (action == StakeAction.START) { //return 1 if this is a new wallet address //this is used to initialize last claim index to the latest cycle index if (index == 0) isFirstShares = 1; s_addressIdToActiveShares[user][++index].activeShares = previousShares + shares; s_globalShares += shares; s_globalHlxStaked += amount; } else { s_addressIdToActiveShares[user][++index].activeShares = previousShares - shares; s_globalExpiredShares += shares; s_globalHlxStaked -= amount; } //If global payout hasn't triggered, use current contract day to eligible for payout //If global payout has triggered, then start with next contract day as it's no longer eligible to claim latest payout s_addressIdToActiveShares[user][index].day = isPayoutTriggered == PayoutTriggered.NO ? day : day + 1; s_userSharesIndex[user] = index; } /** @dev calculate stake principle and apply penalty (if any) * @param user user address * @param globalStakeId global stake Id * @param userStakeInfo stake info * @param action end stake or burn stake * @return principle calculated principle after penalty (if any) */ function _calculatePrinciple( address user, uint256 globalStakeId, UserStakeInfo memory userStakeInfo, StakeAction action ) internal returns (uint256 principle) { uint256 hlxAmount = userStakeInfo.hlxAmount; //penalty is in percentage uint256 penalty = calculateEndStakePenalty( userStakeInfo.stakeStartTs, userStakeInfo.maturityTs, block.timestamp, action ); uint256 penaltyAmount; penaltyAmount = (hlxAmount * penalty) / 100; principle = hlxAmount - penaltyAmount; s_globalStakePenalty += penaltyAmount; emit StakeEnded(user, globalStakeId, principle, penalty, penaltyAmount); } //Views /** @notice get global shares * @return globalShares global shares */ function getGlobalShares() public view returns (uint256) { return s_globalShares; } /** @notice get global expired shares * @return globalExpiredShares global expired shares */ function getGlobalExpiredShares() public view returns (uint256) { return s_globalExpiredShares; } /** @notice get global active shares * @return globalActiveShares global active shares */ function getGlobalActiveShares() public view returns (uint256) { return s_globalShares - s_globalExpiredShares; } /** @notice get total helios staked * @return totalHlxStaked total helios staked */ function getTotalHlxStaked() public view returns (uint256) { return s_globalHlxStaked; } /** @notice get global stake id * @return globalStakeId global stake id */ function getGlobalStakeId() public view returns (uint256) { return s_globalStakeId; } /** @notice get global active stakes * @return globalActiveStakes global active stakes */ function getGlobalActiveStakes() public view returns (uint256) { return s_globalStakeId - getTotalStakeEnd(); } /** @notice get total stake ended * @return totalStakeEnded total stake ended */ function getTotalStakeEnd() public view returns (uint256) { return s_globalStakeEnd; } /** @notice get total stake burned * @return totalStakeBurned total stake burned */ function getTotalStakeBurn() public view returns (uint256) { return s_globalStakeBurn; } /** @notice get total end stake penalty * @return totalEndStakePenalty total end stake penalty */ function getTotalStakePenalty() public view returns (uint256) { return s_globalStakePenalty; } /** @notice get user latest shares index * @return latestSharesIndex latest shares index */ function getUserLatestShareIndex( address user ) public view returns (uint256) { return s_userSharesIndex[user]; } /** @notice get user current active shares * @return currentActiveShares current active shares */ function getUserCurrentActiveShares( address user ) public view returns (uint256) { return s_addressIdToActiveShares[user][getUserLatestShareIndex(user)] .activeShares; } /** @notice get user active shares at sharesIndex * @return activeShares active shares at sharesIndex */ function getUserActiveShares( address user, uint256 sharesIndex ) internal view returns (uint256) { return s_addressIdToActiveShares[user][sharesIndex].activeShares; } /** @notice get user active shares contract day at sharesIndex * @return activeSharesDay active shares contract day at sharesIndex */ function getUserActiveSharesDay( address user, uint256 sharesIndex ) internal view returns (uint256) { return s_addressIdToActiveShares[user][sharesIndex].day; } /** @notice get stake info with stake id * @return stakeInfo stake info */ function getUserStakeInfo( address user, uint256 id ) public view returns (UserStakeInfo memory) { return s_globalStakeIdToStakeInfo[s_addressSIdToGlobalStakeId[user][id]]; } /** @notice get all stake info of an address * @return stakeInfos all stake info of an address */ function getUserStakes( address user ) public view returns (UserStake[] memory) { uint256 count = s_addressSId[user]; UserStake[] memory stakes = new UserStake[](count); for (uint256 i = 1; i <= count; i++) { stakes[i - 1] = UserStake({ sId: i, globalStakeId: s_addressSIdToGlobalStakeId[user][i], stakeInfo: getUserStakeInfo(user, i) }); } return stakes; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; interface IBuynBurn { function getCurrentTitanPrice() external view returns (uint256); }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; interface IHlxOnBurn { function onBurn(address user, uint256 amount) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; interface ITitanOnBurn { function onBurn(address user, uint256 amount) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; interface ITITANX { // Enum for stake status enum StakeStatus { ACTIVE, ENDED, BURNED } // Struct for user stake information struct UserStakeInfo { uint152 titanAmount; uint128 shares; uint16 numOfDays; uint48 stakeStartTs; uint48 maturityTs; StakeStatus status; } struct UserStake { uint256 sId; uint256 globalStakeId; UserStakeInfo stakeInfo; } function balanceOf(address account) external view returns (uint256); function getBalance() external; function mintLPTokens() external; function burnLPTokens() external; function startStake(uint256 amount, uint256 numOfDays) external; function endStake(uint256 id) external; function claimUserAvailableETHPayouts() external; function burnTokensToPayAddress( address user, uint256 amount, uint256 userRebatePercentage, uint256 rewardPaybackPercentage, address rewardPaybackAddress ) external; /** @notice get stake info with stake id * @return stakeInfo stake info */ function getUserStakeInfo( address user, uint256 id ) external view returns (UserStakeInfo memory); /** * @notice Calculates the total ETH claimable by a user for all cycles. * @dev This function sums up the rewards from various cycles based on user shares. * @param user The address of the user for whom to calculate the claimable ETH. * @return reward The total ETH reward claimable by the user. */ function getUserETHClaimableTotal( address user ) external view returns (uint256 reward); /** * @notice Get all stake info of a given user address. * @param user The address of the user to query stake information for. * @return An array of UserStake structs containing all stake info for the given address. */ function getUserStakes( address user ) external view returns (UserStake[] memory); /** * @notice Trigger cycle payouts for days 8, 28, 90, 369, 888, including the burn reward cycle 28. * Payouts can be triggered on or after the maturity day of each cycle (e.g., Cycle8 on day 8). */ function triggerPayouts() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "./constant.sol"; import "./enum.sol"; /** @notice get mint cost * @param mintPower mint power (1 - 100) * @param mintCost cost of mint * @return mintCost total mint cost */ function getMintCost( uint256 mintPower, uint256 mintCost ) pure returns (uint256) { return (mintCost * mintPower) / MAX_MINT_POWER_CAP; } //MintInfo /** @notice the formula to calculate mint reward at create new mint * @param mintPower mint power 1 - 100,000 * @param numOfDays mint length 1 - 250 * @param mintableHlx current contract day mintable helios * @param EAABonus current contract day EAA Bonus * @param burnAmpBonus user burn amplifier bonus from getUserBurnAmplifierBonus(user) * @return reward base helios amount */ function calculateMintReward( uint256 mintPower, uint256 numOfDays, uint256 mintableHlx, uint256 EAABonus, uint256 burnAmpBonus, uint256 percentageBonus ) pure returns (uint256 reward) { uint256 baseReward = (mintableHlx * mintPower * numOfDays); if (numOfDays != 1) baseReward -= (baseReward * MINT_DAILY_REDUCTION * (numOfDays - 1)) / PERCENT_BPS; reward = baseReward; if (EAABonus != 0) { //EAA Bonus has 1e6 scaling, so here divide by 1e6 reward += ((baseReward * EAABonus) / 100 / SCALING_FACTOR_1e6); } if (burnAmpBonus != 0) { //burnAmpBonus has 1e18 scaling reward += (baseReward * burnAmpBonus) / 100 / SCALING_FACTOR_1e18; } // Apply the percentage bonus if (percentageBonus != 0) { percentageBonus = percentageBonus > BURN_MINT_AMP ? BURN_MINT_AMP : percentageBonus; // Convert the bonus to a percentage (1000 represents 10%, so divide by 10000) uint256 additionalReward = (reward * percentageBonus) / 10000; reward += additionalReward; } reward /= MAX_MINT_POWER_CAP; } /** @notice the formula to calculate bonus reward * heavily influenced by the difference between current global mint power and user mint's global mint power * @param mintPowerBonus mint power bonus from mintinfo * @param mintPower mint power 1 - 100,000 from mintinfo * @param gMintPower global mint power from mintinfo * @param globalMintPower current global mint power * @return bonus bonus amount in helios */ function calculateMintPowerBonus( uint256 mintPowerBonus, uint256 mintPower, uint256 gMintPower, uint256 globalMintPower ) pure returns (uint256 bonus) { if (globalMintPower <= gMintPower) return 0; bonus = (((mintPowerBonus * mintPower * (globalMintPower - gMintPower)) * SCALING_FACTOR_1e18) / MAX_MINT_POWER_CAP); } /** @notice Return max mint length * @return maxMintLength max mint length */ function getMaxMintDays() pure returns (uint256) { return MAX_MINT_LENGTH; } /** @notice Return max mints per wallet * @return maxMintPerWallet max mints per wallet */ function getMaxMintsPerWallet() pure returns (uint256) { return MAX_MINT_PER_WALLET; } /** * @dev Return penalty percentage based on number of days late after the grace period of 7 days * @param secsLate seconds late (block timestamp - maturity timestamp) * @return penalty penalty in percentage */ function calculateClaimMintPenalty(uint256 secsLate) pure returns (uint256 penalty) { if (secsLate <= CLAIM_MINT_GRACE_PERIOD * SECONDS_IN_DAY) return 0; if (secsLate <= (CLAIM_MINT_GRACE_PERIOD + 1) * SECONDS_IN_DAY) return 1; if (secsLate <= (CLAIM_MINT_GRACE_PERIOD + 2) * SECONDS_IN_DAY) return 3; if (secsLate <= (CLAIM_MINT_GRACE_PERIOD + 3) * SECONDS_IN_DAY) return 8; if (secsLate <= (CLAIM_MINT_GRACE_PERIOD + 4) * SECONDS_IN_DAY) return 17; if (secsLate <= (CLAIM_MINT_GRACE_PERIOD + 5) * SECONDS_IN_DAY) return 35; if (secsLate <= (CLAIM_MINT_GRACE_PERIOD + 6) * SECONDS_IN_DAY) return 72; return 99; } //StakeInfo error Helios_AtLeastHalfMaturity(); /** @notice get max stake length * @return maxStakeLength max stake length */ function getMaxStakeLength() pure returns (uint256) { return MAX_STAKE_LENGTH; } /** @notice calculate shares and shares bonus * @param amount helios amount * @param noOfDays stake length * @param shareRate current contract share rate * @return shares calculated shares in 18 decimals */ function calculateShares( uint256 amount, uint256 noOfDays, uint256 shareRate ) pure returns (uint256) { uint256 shares = amount; shares += (shares * calculateShareBonus(noOfDays)) / SCALING_FACTOR_1e11; shares /= (shareRate / SCALING_FACTOR_1e18); return shares; } /** @notice calculate share bonus * @param noOfDays stake length * @return shareBonus calculated shares bonus in 11 decimals */ function calculateShareBonus(uint256 noOfDays) pure returns (uint256 shareBonus) { if (noOfDays <= MIN_STAKE_LENGTH) { return SCALING_FACTOR_1e6; // no bonus } uint256 effectiveDays = noOfDays - MIN_STAKE_LENGTH; uint256 cappedEffectiveDays = effectiveDays <= (LPB_MAX_DAYS - MIN_STAKE_LENGTH) ? effectiveDays : (LPB_MAX_DAYS - MIN_STAKE_LENGTH); shareBonus = ((cappedEffectiveDays * SCALING_FACTOR_1e11) / LPB_PER_PERCENT); return shareBonus; } /** @notice calculate end stake penalty * @param stakeStartTs start stake timestamp * @param maturityTs maturity timestamp * @param currentBlockTs current block timestamp * @param action end stake or burn stake * @return penalty penalty in percentage */ function calculateEndStakePenalty( uint256 stakeStartTs, uint256 maturityTs, uint256 currentBlockTs, StakeAction action ) view returns (uint256) { //Matured, then calculate and return penalty if (currentBlockTs >= maturityTs) { uint256 lateSec = currentBlockTs - maturityTs; uint256 gracePeriodSec = END_STAKE_GRACE_PERIOD * SECONDS_IN_DAY; if (lateSec <= gracePeriodSec) return 0; return max((min((lateSec - gracePeriodSec), 1) / SECONDS_IN_DAY) + 1, 99); } //burn stake is excluded from penalty //if not matured and action is burn stake then return 0 if (action == StakeAction.BURN) return 0; //Emergency End Stake //Not allow to EES below 50% maturity if (block.timestamp < stakeStartTs + (maturityTs - stakeStartTs) / 2) revert Helios_AtLeastHalfMaturity(); //50% penalty for EES before maturity timestamp return 50; } //a - input to check against b //b - minimum number function min(uint256 a, uint256 b) pure returns (uint256) { if (a > b) return a; return b; } //a - input to check against b //b - maximum number function max(uint256 a, uint256 b) pure returns (uint256) { if (a > b) return b; return a; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "../interfaces/ITitanOnBurn.sol"; // ===================== common ========================================== uint256 constant SECONDS_IN_DAY = 86400; uint256 constant SCALING_FACTOR_1e3 = 1e3; uint256 constant SCALING_FACTOR_1e6 = 1e6; uint256 constant SCALING_FACTOR_1e7 = 1e7; uint256 constant SCALING_FACTOR_1e11 = 1e11; uint256 constant SCALING_FACTOR_1e18 = 1e18; // ===================== Helios ========================================== uint256 constant PERCENT_TO_BUY_AND_BURN_FINAL = 0; uint256 constant PERCENT_TO_CYCLE_PAYOUTS = 28_00; uint256 constant PERCENT_TO_TREASURY_FINAL = 70_00; uint256 constant PERCENT_CHANGE = 50; uint256 constant PERCENT_TO_GENESIS = 2_00; uint256 constant INCENTIVE_FEE_PERCENT = 3_000; //0.3% uint256 constant INCENTIVE_FEE_PERCENT_BASE = 1_000_000; uint256 constant INITAL_LP_TOKENS = 1_600_000_000 ether; // ===================== globalInfo ========================================== //Helios Supply Variables uint256 constant START_MAX_MINTABLE_PER_DAY = 4_200_000_000 ether; uint256 constant CAPPED_MIN_DAILY_HLX_MINTABLE = 420_000 ether; uint256 constant DAILY_SUPPLY_MINTABLE_REDUCTION = 99_65; //10% - 0% linear for 69 days //EAA Variables uint256 constant EAA_START = 10 * SCALING_FACTOR_1e6; uint256 constant EAA_BONUSE_FIXED_REDUCTION_PER_DAY = 144_927; uint256 constant EAA_END = 0; uint256 constant MAX_BONUS_DAY = 69; //Mint Cost Variables uint256 constant START_MAX_MINT_COST = 420_000_000_000 ether; uint256 constant CAPPED_MAX_MINT_COST = 2_000_000_000_000 ether; uint256 constant DAILY_MINT_COST_INCREASE_STEP = 100_10;//0.1% // 1000 to 0.1 HLX -0.35% Daily //mintPower Bonus Variables uint256 constant START_MINTPOWER_INCREASE_BONUS = 10_000 * SCALING_FACTOR_1e7; //starts at 10_000 with 1e7 scaling factor uint256 constant CAPPED_MIN_MINTPOWER_BONUS = 10_000 * SCALING_FACTOR_1e3; //capped min of 0.1 * 1e7 = 10_000 * 1e3 uint256 constant DAILY_MINTPOWER_INCREASE_BONUS_REDUCTION = 99_65; //Share Rate Variables uint256 constant START_SHARE_RATE = 420 ether; //Cycle Variables uint256 constant DAY22 = 22; uint256 constant DAY69 = 69; uint256 constant DAY420 = 420; uint256 constant CYCLE_22_PERCENT = 35_00; uint256 constant CYCLE_69_PERCENT = 30_00; uint256 constant CYCLE_420_PERCENT = 35_00; uint256 constant PERCENT_BPS = 100_00; // ===================== mintInfo ========================================== uint256 constant MAX_MINT_POWER_CAP = 100_000; uint256 constant MAX_MINT_LENGTH = 250; uint256 constant CLAIM_MINT_GRACE_PERIOD = 7; uint256 constant MAX_MINT_PER_WALLET = 1000; uint256 constant MAX_BURN_AMP_BASE = 80 * 1e9 * 1 ether; uint256 constant MAX_BURN_AMP_PERCENT = 8 ether; uint256 constant MINT_DAILY_REDUCTION = 11; // ===================== stakeInfo ========================================== uint256 constant MAX_STAKE_PER_WALLET = 1000; uint256 constant MIN_STAKE_LENGTH = 30; uint256 constant MAX_STAKE_LENGTH = 830; uint256 constant END_STAKE_GRACE_PERIOD = 7; // 0%-200% linear 1-830 days /* Stake Longer Pays Better bonus */ uint256 constant LPB_MAX_DAYS = 830; uint256 constant LPB_PER_PERCENT = 400; //20% /* Burn Stake Amplifier */ uint256 constant BURN_STAKE_AMP = 2000; //10% /* Burn Mint Amplifier */ uint256 constant BURN_MINT_AMP = 1000; // ===================== burnInfo ========================================== uint256 constant MAX_BURN_REWARD_PERCENT = 8; // ===================== Treasury ========================================== uint256 constant PERCENT_TO_STAKERS = 10_00; uint256 constant PERCENT_TO_BUYANDBURNHELIOS = 70_00; uint16 constant STAKE_DURATION = 3500; uint24 constant POOLFEE1PERCENT = 10000; //1% Fee uint160 constant MIN_SQRT_RATIO = 4295128739; uint160 constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342; address constant TITANX = 0xF19308F923582A6f7c465e5CE7a9Dc1BEC6665B1; address constant UNISWAPV3FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984; address constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address constant TITANX_WETH_POOL = 0xc45A81BC23A64eA556ab4CdF08A86B61cdcEEA8b; address constant NONFUNGIBLEPOSITIONMANAGER = 0xC36442b4a4522E871399CD717aBDD847Ab11FE88; uint8 constant BURN_REWARD_PERCENT_EACH = 4; uint256 constant TREASURY_INCENTIVE_FEE_PERCENT = 1000; uint256 constant INCENTIVE_FEE_CAP_ETH = 0.1 ether; uint256 constant PERCENT_BASE = 10_000; /* bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 constant INTERFACE_ID_ERC165 = 0x01ffc9a7; // ERC-165 Interface ID for ITitanOnBurn bytes4 constant INTERFACE_ID_ITITANONBURN = type(ITitanOnBurn).interfaceId;
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; enum MintAction { CLAIM, BURN } enum MintStatus { ACTIVE, CLAIMED, BURNED } enum StakeAction { START, END, BURN, END_OWN, END_OTHER } enum StakeStatus { ACTIVE, ENDED, BURNED } enum PayoutTriggered { NO, YES } enum InitialLPMinted { NO, YES } enum PayoutClaim { SHARES, BURN } enum BurnSource { LIQUID, MINT, STAKE } enum BurnPoolEnabled { FALSE, TRUE }
{ "optimizer": { "enabled": true, "runs": 0 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"genesisAddress","type":"address"},{"internalType":"address","name":"buyAndBurnAddress","type":"address"},{"internalType":"address","name":"titanxAddress","type":"address"},{"internalType":"address","name":"treasuryAddress","type":"address"},{"internalType":"address","name":"investmentAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Helios_AtLeastHalfMaturity","type":"error"},{"inputs":[],"name":"Helios_EmptyUndistributeFees","type":"error"},{"inputs":[],"name":"Helios_FailedToSendAmount","type":"error"},{"inputs":[],"name":"Helios_InsufficientBalance","type":"error"},{"inputs":[],"name":"Helios_InsufficientBurnAllowance","type":"error"},{"inputs":[],"name":"Helios_InvalidAddress","type":"error"},{"inputs":[],"name":"Helios_InvalidAmount","type":"error"},{"inputs":[],"name":"Helios_InvalidBurnRewardPercent","type":"error"},{"inputs":[],"name":"Helios_InvalidMintLength","type":"error"},{"inputs":[],"name":"Helios_InvalidMintPower","type":"error"},{"inputs":[],"name":"Helios_InvalidStakeLength","type":"error"},{"inputs":[],"name":"Helios_LPTokensHasMinted","type":"error"},{"inputs":[],"name":"Helios_MaxedWalletMints","type":"error"},{"inputs":[],"name":"Helios_MaxedWalletStakes","type":"error"},{"inputs":[],"name":"Helios_MintHasBurned","type":"error"},{"inputs":[],"name":"Helios_MintHasClaimed","type":"error"},{"inputs":[],"name":"Helios_MintNotMature","type":"error"},{"inputs":[],"name":"Helios_NoCycleRewardToClaim","type":"error"},{"inputs":[],"name":"Helios_NoMintExists","type":"error"},{"inputs":[],"name":"Helios_NoSharesExist","type":"error"},{"inputs":[],"name":"Helios_NoStakeExists","type":"error"},{"inputs":[],"name":"Helios_NotAllowed","type":"error"},{"inputs":[],"name":"Helios_NotOnwer","type":"error"},{"inputs":[],"name":"Helios_NotSupportedContract","type":"error"},{"inputs":[],"name":"Helios_OnlyBuyAndBurn","type":"error"},{"inputs":[],"name":"Helios_RequireOneMinimumShare","type":"error"},{"inputs":[],"name":"Helios_StakeHasBurned","type":"error"},{"inputs":[],"name":"Helios_StakeHasEnded","type":"error"},{"inputs":[],"name":"Helios_StakeNotMatured","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"project","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ApproveBurnMints","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"project","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ApproveBurnStakes","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"uint256","name":"cycleNo","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"CyclePayoutTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"day","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"mintCost","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintableHlx","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintPowerBonus","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"EAABonus","type":"uint256"}],"name":"GlobalDailyUpdateStats","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"project","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"enum BurnSource","name":"helioSource","type":"uint8"}],"name":"HlxBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"hRank","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardMinted","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"penalty","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintPenalty","type":"uint256"}],"name":"MintClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"hRank","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"gMintpower","type":"uint256"},{"components":[{"internalType":"uint256","name":"mintPower","type":"uint256"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint256","name":"mintableHlx","type":"uint256"},{"internalType":"uint48","name":"mintStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"internalType":"uint256","name":"mintPowerBonus","type":"uint256"},{"internalType":"uint256","name":"EAABonus","type":"uint256"},{"internalType":"uint256","name":"mintedHlx","type":"uint256"},{"internalType":"uint256","name":"mintCost","type":"uint256"},{"internalType":"uint256","name":"penalty","type":"uint256"},{"internalType":"uint256","name":"titanBurned","type":"uint256"},{"internalType":"enum MintStatus","name":"status","type":"uint8"}],"indexed":false,"internalType":"struct MintInfo.UserMintInfo","name":"userMintInfo","type":"tuple"}],"name":"MintStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"day","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ProtocolFeeRecevied","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"ethReward","type":"uint256"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"globalStakeId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"hlxAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"penalty","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penaltyAmount","type":"uint256"}],"name":"StakeEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"globalStakeId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numOfDays","type":"uint256"},{"components":[{"internalType":"uint256","name":"hlxAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint48","name":"stakeStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"internalType":"uint256","name":"titanBurned","type":"uint256"},{"internalType":"enum StakeStatus","name":"status","type":"uint8"}],"indexed":false,"internalType":"struct StakeInfo.UserStakeInfo","name":"userStakeInfo","type":"tuple"}],"name":"StakeStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TitanXDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowanceBurnMints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowanceBurnStakes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approveBurnMints","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approveBurnStakes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burnLPTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"burnMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"userRebatePercentage","type":"uint256"},{"internalType":"uint256","name":"rewardPaybackPercentage","type":"uint256"}],"name":"burnStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"userRebatePercentage","type":"uint256"},{"internalType":"uint256","name":"rewardPaybackPercentage","type":"uint256"},{"internalType":"address","name":"rewardPaybackAddress","type":"address"}],"name":"burnStakeToPayAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"userRebatePercentage","type":"uint256"},{"internalType":"uint256","name":"rewardPaybackPercentage","type":"uint256"}],"name":"burnTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"userRebatePercentage","type":"uint256"},{"internalType":"uint256","name":"rewardPaybackPercentage","type":"uint256"},{"internalType":"address","name":"rewardPaybackAddress","type":"address"}],"name":"burnTokensToPayAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"cycleNo","type":"uint256"}],"name":"calculateUserCycleReward","outputs":[{"internalType":"uint256","name":"rewards","type":"uint256"},{"internalType":"uint256","name":"ethRewards","type":"uint256"},{"internalType":"uint256","name":"userClaimCycleIndex","type":"uint256"},{"internalType":"uint256","name":"userClaimSharesIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"claimMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimUserAvailablePayouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"distributeTitanX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"endStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"endStakeForOthers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"mintId","type":"uint256"}],"name":"estimateMintReward","outputs":[{"internalType":"uint256","name":"baseReward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"numOfDays","type":"uint256"}],"name":"estimateShares","outputs":[{"internalType":"uint256","name":"sharesWithBonus","type":"uint256"},{"internalType":"uint256","name":"sharesWithoutBonus","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisTs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBuynBurnPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockTimeStamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentContractDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cycleNo","type":"uint256"}],"name":"getCurrentCycleIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentEAABonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentMintCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentMintPowerBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentMintableHlx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentShareRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cycleNo","type":"uint256"}],"name":"getCyclePayoutPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cycleNo","type":"uint256"}],"name":"getETHCyclePayoutPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cycleNo","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getETHPayoutPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGenesisAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalActiveShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalActiveStakes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalExpiredShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalHRank","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalMintPower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalPayoutTriggered","outputs":[{"internalType":"enum PayoutTriggered","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalStakeId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHlxBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInvestmentAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintPower","type":"uint256"},{"internalType":"uint256","name":"numOfDays","type":"uint256"},{"internalType":"uint256","name":"titanToBurn","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"getMintableHlx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cycleNo","type":"uint256"}],"name":"getNextCyclePayoutDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cycleNo","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getPayoutPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"getProjectBurnTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"getProjectUserBurnTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"noOfDays","type":"uint256"}],"name":"getShareBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTitanXBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalActiveMints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalBurnTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalHlxStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalMintBurn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalMintClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalMintPenalty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalMinting","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalPenalties","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalStakeBurn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalStakeEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalStakePenalty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalTitanXBurned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTreasuryPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUndistributedETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUndistributedTitanX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserBurnAmplifierBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserBurnTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserCurrentActiveShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserETHClaimableTotal","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"cycleNo","type":"uint256"}],"name":"getUserLastClaimIndex","outputs":[{"internalType":"uint256","name":"cycleIndex","type":"uint256"},{"internalType":"uint256","name":"sharesIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserLatestMintId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserLatestShareIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUserMintInfo","outputs":[{"components":[{"internalType":"uint256","name":"mintPower","type":"uint256"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint256","name":"mintableHlx","type":"uint256"},{"internalType":"uint48","name":"mintStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"internalType":"uint256","name":"mintPowerBonus","type":"uint256"},{"internalType":"uint256","name":"EAABonus","type":"uint256"},{"internalType":"uint256","name":"mintedHlx","type":"uint256"},{"internalType":"uint256","name":"mintCost","type":"uint256"},{"internalType":"uint256","name":"penalty","type":"uint256"},{"internalType":"uint256","name":"titanBurned","type":"uint256"},{"internalType":"enum MintStatus","name":"status","type":"uint8"}],"internalType":"struct MintInfo.UserMintInfo","name":"mintInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserMints","outputs":[{"components":[{"internalType":"uint256","name":"mId","type":"uint256"},{"internalType":"uint256","name":"hRank","type":"uint256"},{"internalType":"uint256","name":"gMintPower","type":"uint256"},{"components":[{"internalType":"uint256","name":"mintPower","type":"uint256"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint256","name":"mintableHlx","type":"uint256"},{"internalType":"uint48","name":"mintStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"internalType":"uint256","name":"mintPowerBonus","type":"uint256"},{"internalType":"uint256","name":"EAABonus","type":"uint256"},{"internalType":"uint256","name":"mintedHlx","type":"uint256"},{"internalType":"uint256","name":"mintCost","type":"uint256"},{"internalType":"uint256","name":"penalty","type":"uint256"},{"internalType":"uint256","name":"titanBurned","type":"uint256"},{"internalType":"enum MintStatus","name":"status","type":"uint8"}],"internalType":"struct MintInfo.UserMintInfo","name":"mintInfo","type":"tuple"}],"internalType":"struct MintInfo.UserMint[]","name":"mintInfos","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUserStakeInfo","outputs":[{"components":[{"internalType":"uint256","name":"hlxAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint48","name":"stakeStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"internalType":"uint256","name":"titanBurned","type":"uint256"},{"internalType":"enum StakeStatus","name":"status","type":"uint8"}],"internalType":"struct StakeInfo.UserStakeInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserStakes","outputs":[{"components":[{"internalType":"uint256","name":"sId","type":"uint256"},{"internalType":"uint256","name":"globalStakeId","type":"uint256"},{"components":[{"internalType":"uint256","name":"hlxAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint48","name":"stakeStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"internalType":"uint256","name":"titanBurned","type":"uint256"},{"internalType":"enum StakeStatus","name":"status","type":"uint8"}],"internalType":"struct StakeInfo.UserStakeInfo","name":"stakeInfo","type":"tuple"}],"internalType":"struct StakeInfo.UserStake[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserTitanXClaimableTotal","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"isWhiteListed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manualDailyUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintLPTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"onBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"setBuyAndBurnContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"setNewGenesisAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"setNewInvestmentAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"setTitanXContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"setTreasuryContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintPower","type":"uint256"},{"internalType":"uint256","name":"numOfDays","type":"uint256"},{"internalType":"uint256","name":"titanToBurn","type":"uint256"}],"name":"startMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"numOfDays","type":"uint256"},{"internalType":"uint256","name":"titanToBurn","type":"uint256"}],"name":"startStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"triggerPayouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"userBurnMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"userBurnStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"userBurnTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bool","name":"permit","type":"bool"}],"name":"whiteList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a06040523480156200001157600080fd5b50604051620061a9380380620061a9833981016040819052620000349162000366565b6040518060400160405280600681526020016548454c494f5360d01b8152506040518060400160405280600381526020016209098b60eb1b815250816003908051906020019062000087929190620002a3565b5080516200009d906004906020840190620002a3565b50506001600581905542608052600655506c054d17db76321263eca00000006008556b0d92289838d21a99680000006009556816c4abbebea0100000600755620000ed62989680612710620003d6565b600a9081556200010290620f424090620003d6565b600b55601660208190527f6891b01528b646d3d0e273b7a56a751ccd9937f93c4f054a2a00404bb4fe64625560457f2320e82a07edbcb031d1b2e6236451ad287a5f528e6a2589351912cfedc3c5a3556101a460008190527f7e7449794f742b661d735866176c1d5a6b7b35ed500c377d57d70547609fa0ab556007600c55611770600d556103e8600e55603080546001600160a01b031916331790556001600160a01b038516620001c7576040516329d6af1160e01b815260040160405180910390fd5b6001600160a01b038416620001ef576040516329d6af1160e01b815260040160405180910390fd5b6001600160a01b03831662000217576040516329d6af1160e01b815260040160405180910390fd5b6001600160a01b0382166200023f576040516329d6af1160e01b815260040160405180910390fd5b603180546001600160a01b03199081166001600160a01b039788161790915560328054821692871692909217909155603380548216948616949094179093556035805484169285169290921790915560348054909216921691909117905562000441565b828054620002b19062000404565b90600052602060002090601f016020900481019282620002d5576000855562000320565b82601f10620002f057805160ff191683800117855562000320565b8280016001018555821562000320579182015b828111156200032057825182559160200191906001019062000303565b506200032e92915062000332565b5090565b5b808211156200032e576000815560010162000333565b80516001600160a01b03811681146200036157600080fd5b919050565b600080600080600060a086880312156200037f57600080fd5b6200038a8662000349565b94506200039a6020870162000349565b9350620003aa6040870162000349565b9250620003ba6060870162000349565b9150620003ca6080870162000349565b90509295509295909350565b6000816000190483118215151615620003ff57634e487b7160e01b600052601160045260246000fd5b500290565b600181811c908216806200041957607f821691505b602082108114156200043b57634e487b7160e01b600052602260045260246000fd5b50919050565b608051615d45620004646000396000818161108a0152612bcd0152615d456000f3fe6080604052600436106104ae5760003560e01c8062281d14146104d8578062ae5faa146104fc57806301ffc9a71461052957806306fdde0314610559578063095ea7b31461057b5780630cbe28d61461059b57806310cc8ee7146105bb57806312065fe0146105db5780631371bb40146105ee57806313aad5101461063457806318160ddd146106495780631ae409c01461065e578063216630b4146106735780632277d1bd14610688578063236393851461069d57806323b5675f146106b257806323b872dd146106c757806324f33a5b146106e7578063276b5c1a146106fc57806329b70d7a146107115780632d02347a146107475780632f77195114610774578063300284f214610789578063313ce567146107a957806333f3fd78146107c557806337c4f8c4146107e5578063392e353d14610805578063395093511461083a578063398015271461085a5780633a9693e11461087a5780633c34267f1461089a5780633d05012d146108ba578063403b285b146108cf57806341d6831a146108f657806345a1b92c1461090b578063462a8c2f1461092b5780634cf2d48f146109585780634df833af14610978578063510f8b9c1461098d578063544a6c59146109ad57806354f5d028146109f3578063566d0be314610a085780635742744114610a285780635a3c8b7d14610a485780635c1c5cb314610a5d5780635c3ef13014610a725780636272683314610ab8578063682d2d1114610acd578063692b6fdc14610aed5780636c52876b14610b1a5780636f60963314610b2f5780636f9170f614610b4457806370a0823114610b7d57806370c9b00214610b9d578063715018a614610bbd5780637629052d14610bd25780637789281e14610bf257806377a5426914610c075780637b763a2c14610c275780637d6b325314610c475780637ec26dca14610c67578063800bb26914610c7c578063842e298114610c91578063856a73da14610cbe578063880a083614610cde57806389de416514610cf35780638b13cdae14610d1357806392c1df5414610d335780639332812414610d485780639474782014610d6857806395d89b4114610d7d57806396d9720814610d925780639a5a6cd914610db25780639ed9922014610dd2578063a2573e5b14610df2578063a457c2d714610e10578063a76222af14610e30578063a9059cbb14610e45578063af4fb76314610e65578063af835b8a14610e7a578063b0977f6914610ea7578063b0aebfbc14610ebc578063b8fac78914610edc578063b984c94614610ef1578063baf20eef14610f06578063bb88603c14610f26578063c081f4c014610f3b578063c50312ad14610f50578063d16baeb914610f86578063d6f8688f14610fa6578063d819e19814610fe6578063d9af94af14611013578063dd62ed3e14611026578063dff96e9a14611046578063e33a3c941461105b578063e3af6d0a1461107b578063e3d3227d146110ae578063e8052174146110c3578063efe17023146110e3578063f2fde38b14611103578063f63ec50e14611123578063f80b0cfb14611138578063faa94d3b1461114d578063fac940f41461116d578063fbf9529d14611180578063fe9497a614611195578063ffb75cab146111b557600080fd5b366104d35734156104d15734603760008282546104cb919061561f565b90915550505b005b600080fd5b3480156104e457600080fd5b50600b545b6040519081526020015b60405180910390f35b34801561050857600080fd5b5061051c610517366004615653565b6111e2565b6040516104f39190615704565b34801561053557600080fd5b50610549610544366004615712565b6112b0565b60405190151581526020016104f3565b34801561056557600080fd5b5061056e6112e6565b6040516104f3919061573c565b34801561058757600080fd5b50610549610596366004615653565b611378565b3480156105a757600080fd5b506104d16105b6366004615791565b611390565b3480156105c757600080fd5b506104d16105d63660046157aa565b6113d9565b3480156105e757600080fd5b50476104e9565b3480156105fa57600080fd5b506104e96106093660046157d6565b6001600160a01b039182166000908152602f6020908152604080832093909416825291909152205490565b34801561064057600080fd5b506104d161154e565b34801561065557600080fd5b506002546104e9565b34801561066a57600080fd5b506006546104e9565b34801561067f57600080fd5b50601a546104e9565b34801561069457600080fd5b506104d1611558565b3480156106a957600080fd5b506104e961172d565b3480156106be57600080fd5b50600d546104e9565b3480156106d357600080fd5b506105496106e2366004615809565b611751565b3480156106f357600080fd5b50600e546104e9565b34801561070857600080fd5b506026546104e9565b34801561071d57600080fd5b506104e961072c366004615845565b6001600160a01b03166000908152602e602052604090205490565b34801561075357600080fd5b506104e9610762366004615791565b60009081526016602052604090205490565b34801561078057600080fd5b506019546104e9565b34801561079557600080fd5b506105496107a4366004615653565b611777565b3480156107b557600080fd5b50604051601281526020016104f3565b3480156107d157600080fd5b506104d16107e0366004615860565b6117f8565b3480156107f157600080fd5b506104d1610800366004615791565b611826565b34801561081157600080fd5b506108256108203660046158b0565b61184f565b604080519283526020830191909152016104f3565b34801561084657600080fd5b50610549610855366004615653565b611873565b34801561086657600080fd5b506104e96108753660046158d2565b611895565b34801561088657600080fd5b506104d1610895366004615845565b6118e7565b3480156108a657600080fd5b506104d16108b5366004615791565b611964565b3480156108c657600080fd5b506037546104e9565b3480156108db57600080fd5b506032546001600160a01b03165b6040516104f39190615911565b34801561090257600080fd5b506036546104e9565b34801561091757600080fd5b506104d1610926366004615653565b6119d3565b34801561093757600080fd5b506104e9610946366004615791565b60009081526010602052604090205490565b34801561096457600080fd5b506104d1610973366004615845565b611a36565b34801561098457600080fd5b506038546104e9565b34801561099957600080fd5b506104e96109a8366004615845565b611a87565b3480156109b957600080fd5b506104e96109c83660046157d6565b6001600160a01b039182166000908152603a6020908152604080832093909416825291909152205490565b3480156109ff57600080fd5b50602c546104e9565b348015610a1457600080fd5b506104d1610a23366004615791565b611aef565b348015610a3457600080fd5b50610825610a433660046158b0565b611b2a565b348015610a5457600080fd5b506009546104e9565b348015610a6957600080fd5b506104d1611b6d565b348015610a7e57600080fd5b506104e9610a8d3660046157d6565b6001600160a01b039182166000908152603c6020908152604080832093909416825291909152205490565b348015610ac457600080fd5b506104d1611bad565b348015610ad957600080fd5b506104e9610ae8366004615653565b611cc1565b348015610af957600080fd5b506104e9610b08366004615791565b60009081526011602052604090205490565b348015610b2657600080fd5b506104e9611e2a565b348015610b3b57600080fd5b506008546104e9565b348015610b5057600080fd5b50610549610b5f366004615845565b6001600160a01b03166000908152603b602052604090205460ff1690565b348015610b8957600080fd5b506104e9610b98366004615845565b611e42565b348015610ba957600080fd5b50610825610bb83660046158b0565b611e5d565b348015610bc957600080fd5b506104d1611e81565b348015610bde57600080fd5b506104d1610bed366004615845565b611e93565b348015610bfe57600080fd5b506022546104e9565b348015610c1357600080fd5b506104d1610c22366004615860565b611ee4565b348015610c3357600080fd5b506104d1610c42366004615653565b611f01565b348015610c5357600080fd5b506104d1610c62366004615845565b611f29565b348015610c7357600080fd5b506017546104e9565b348015610c8857600080fd5b506104e9611f7a565b348015610c9d57600080fd5b50610cb1610cac366004615845565b611f92565b6040516104f39190615925565b348015610cca57600080fd5b50610549610cd9366004615653565b612091565b348015610cea57600080fd5b506021546104e9565b348015610cff57600080fd5b50610825610d0e366004615653565b612112565b348015610d1f57600080fd5b506104e9610d2e366004615791565b612142565b348015610d3f57600080fd5b50601c546104e9565b348015610d5457600080fd5b50600f5460ff166040516104f39190615989565b348015610d7457600080fd5b506104e961214d565b348015610d8957600080fd5b5061056e612158565b348015610d9e57600080fd5b506104d1610dad3660046159a3565b612167565b348015610dbe57600080fd5b506104e9610dcd366004615845565b612194565b348015610dde57600080fd5b506104d1610ded3660046159a3565b6121cf565b348015610dfe57600080fd5b506031546001600160a01b03166108e9565b348015610e1c57600080fd5b50610549610e2b366004615653565b6121ec565b348015610e3c57600080fd5b506104e9612272565b348015610e5157600080fd5b50610549610e60366004615653565b6122e4565b348015610e7157600080fd5b506104e96122f2565b348015610e8657600080fd5b506104e9610e95366004615791565b60009081526012602052604090205490565b348015610eb357600080fd5b506023546104e9565b348015610ec857600080fd5b506104d1610ed7366004615845565b612304565b348015610ee857600080fd5b506025546104e9565b348015610efd57600080fd5b506020546104e9565b348015610f1257600080fd5b506104d1610f21366004615791565b612381565b348015610f3257600080fd5b506104d16123a5565b348015610f4757600080fd5b506024546104e9565b348015610f5c57600080fd5b506104e9610f6b366004615845565b6001600160a01b03166000908152601d602052604090205490565b348015610f9257600080fd5b506104d1610fa13660046159ea565b6123ff565b348015610fb257600080fd5b50610fc6610fc1366004615653565b612459565b6040805194855260208501939093529183015260608201526080016104f3565b348015610ff257600080fd5b50611006611001366004615653565b61257a565b6040516104f39190615adb565b34801561101f57600080fd5b50426104e9565b34801561103257600080fd5b506104e96110413660046157d6565b61265f565b34801561105257600080fd5b50601b546104e9565b34801561106757600080fd5b506104e9611076366004615845565b61268a565b34801561108757600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006104e9565b3480156110ba57600080fd5b506104d16126e9565b3480156110cf57600080fd5b506104e96110de366004615845565b612783565b3480156110ef57600080fd5b506104d16110fe366004615653565b61279e565b34801561110f57600080fd5b506104d161111e366004615845565b6127d0565b34801561112f57600080fd5b50600a546104e9565b34801561114457600080fd5b506018546104e9565b34801561115957600080fd5b506104e9611168366004615845565b6127e1565b6104d161117b3660046157aa565b6127fc565b34801561118c57600080fd5b506007546104e9565b3480156111a157600080fd5b506104e96111b0366004615845565b61292b565b3480156111c157600080fd5b506111d56111d0366004615845565b61298a565b6040516104f39190615aea565b6111ea615503565b6001600160a01b038316600090815260286020908152604080832085845282528083205483526029825291829020825160e0810184528154815260018201549281019290925260028082015461ffff81169484019490945265ffffffffffff62010000850481166060850152600160401b9094049093166080830152600381015460a083015260048101549192909160c084019160ff909116908111156112935761129361567d565b60028111156112a4576112a461567d565b90525090505b92915050565b60006001600160e01b031982166301ffc9a760e01b14806112aa57506001600160e01b031982166311686e4b60e21b1492915050565b6060600380546112f590615b4e565b80601f016020809104026020016040519081016040528092919081815260200182805461132190615b4e565b801561136e5780601f106113435761010080835404028352916020019161136e565b820191906000526020600020905b81548152906001019060200180831161135157829003601f168201915b5050505050905090565b600033611386818585612a9b565b5060019392505050565b611398612bbf565b6113a0612e0d565b6113cc336113c733846113b260065490565b600160036113c2600f5460ff1690565b612e67565b6130c9565b6113d66001600555565b50565b6113e1612bbf565b6113e9612e0d565b826113f333611e42565b101561141257604051631d78718160e01b815260040160405180910390fd5b33321461147957336000908152603b602052604090205460ff166114795760405162461bcd60e51b815260206004820152601960248201527821b7b73a3930b1ba103737ba103bb434ba32b634b9ba32b21760391b60448201526064015b60405180910390fd5b80156114885761148881613176565b6114923384613207565b61153f3361153a3386866114a560075490565b600654600f5460ff168960008b116114be576000613327565b603360009054906101000a90046001600160a01b03166001600160a01b031663665f8efb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611511573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115359190615b83565b613327565b61345e565b6115496001600555565b505050565b611556612bbf565b565b611560612bbf565b611568612e0d565b600061157360225490565b6021546115809190615b9c565b905060018110156115a45760405163df8afe1960e01b815260040160405180910390fd5b6000806000806036546000146115c8576115bc61359b565b92965090945090925090505b60006115d360065490565b9050600060016115e5601689856137a9565b60018111156115f6576115f661567d565b148015611614575060008160018111156116125761161261567d565b145b61161e5780611623565b506001805b506001611632604589856137a9565b60018111156116435761164361567d565b1480156116615750600081600181111561165f5761165f61567d565b145b61166b5780611670565b506001805b5060016116806101a489856137a9565b60018111156116915761169161567d565b1480156116af575060008160018111156116ad576116ad61567d565b145b6116b957806116be565b506001805b5060018160018111156116d3576116d361567d565b141561170a576000600f5460ff1660018111156116f2576116f261567d565b141561170a5761170a600f805460ff19166001179055565b851561171c5761171c8686858761384f565b505050505050506115566001600555565b60006019546018546017546117429190615b9c565b61174c9190615b9c565b905090565b60003361175f85828561389a565b61176a85858561390e565b60019150505b9392505050565b60006001600160a01b0383166117a0576040516329d6af1160e01b815260040160405180910390fd5b336000818152603a602090815260408083206001600160a01b038816808552925280832086905551859391927ff8e109bcddf5e12132b7cd8a8517d97498f50c7ac595874d6f513243098b079891a450600192915050565b611800612bbf565b611808612e0d565b6118158585858585613aa0565b61181f6001600555565b5050505050565b61182e612bbf565b611836612e0d565b6113cc33600061184833856001613b15565b6001613d13565b60009182526014602090815260408084209284529190529020600181015490549091565b600033611386818585611886838361265f565b611890919061561f565b612a9b565b6000806118aa866118a560085490565b613e25565b905060006118b88583613e35565b90506118da87876118c860095490565b600b546118d489611a87565b86613e4f565b925050505b949350505050565b6031546001600160a01b0316336001600160a01b03161461191b576040516339e2f41f60e21b815260040160405180910390fd5b6001600160a01b038116611942576040516329d6af1160e01b815260040160405180910390fd5b603180546001600160a01b0319166001600160a01b0392909216919091179055565b61196c612bbf565b611974612e0d565b8061199257604051630aa71b7760e41b815260040160405180910390fd5b8061199c33611e42565b10156119bb57604051631d78718160e01b815260040160405180910390fd5b6119c53382613207565b6113cc336000836000613d13565b6035546001600160a01b03163314611a1b5760405162461bcd60e51b815260206004820152600b60248201526a09edcd8f240a8d2e8c2dcb60ab1b6044820152606401611470565b8060386000828254611a2d919061561f565b90915550505050565b611a3e613f7e565b6001600160a01b038116611a65576040516329d6af1160e01b815260040160405180910390fd5b603480546001600160a01b0319166001600160a01b0392909216919091179055565b600080611a9383612783565b905080611aa35750600092915050565b680204fce5e3e2502611601f1b8110611ac65750676f05b59d3b20000092915050565b680204fce5e3e2502611601f1b611ae582676f05b59d3b200000615bb3565b6117709190615bd2565b611af7612bbf565b611aff612e0d565b6113cc336000611b233385611b1360065490565b600260036113c2600f5460ff1690565b6002613d13565b6000806000611b3860075490565b9050611b45858583613fa9565b9250611b59670de0b6b3a764000082615bd2565b611b639086615bd2565b9150509250929050565b611b75612bbf565b611b7d612e0d565b600080600080611b8b61359b565b9350935093509350611b9f8484848461384f565b505050506115566001600555565b611bb5612bbf565b611bbd612e0d565b600080600080611bcd6016614000565b9092509050611bdc828561561f565b9350611be8818461561f565b9250611bf46045614000565b9092509050611c03828561561f565b9350611c0f818461561f565b9250611c1c6101a4614000565b9092509050611c2b828561561f565b9350611c37818461561f565b925083158015611c45575082155b15611c63576040516354d2b34960e01b815260040160405180910390fd5b8315611c7457611c74335b85614037565b8215611c8457611c8433846140d3565b6040518390859033907ff01da32686223933d8a18a391060918c7f11a3648639edd87ae013e2e273174390600090a4505050506115566001600555565b6001600160a01b0382166000908152601e602090815260408083208484529091528120805460019091015481611d0a57604051637a2e11eb60e01b815260040160405180910390fd5b6000828152601f6020908152604080832081516101808101835281548152600182015461ffff169381019390935260028082015492840192909252600381015465ffffffffffff8082166060860152600160301b909104166080840152600481015460a0840152600581015460c0840152600681015460e0840152600781015461010084015260088101546101208401526009810154610140840152600a810154909161016084019160ff1690811115611dc657611dc661567d565b6002811115611dd757611dd761567d565b815250509050806040015193506000611dfc8260a00151836000015185601c5461416e565b9050611e0b6298968082615bd2565b611e15908661561f565b611e1f908661561f565b979650505050505050565b6000611e3560245490565b601b5461174c919061561f565b6001600160a01b031660009081526020819052604090205490565b60009182526013602090815260408084209284529190529020600181015490549091565b611e89613f7e565b61155660006141be565b611e9b613f7e565b6001600160a01b038116611ec2576040516329d6af1160e01b815260040160405180910390fd5b603580546001600160a01b0319166001600160a01b0392909216919091179055565b611eec612bbf565b611ef4612e0d565b61181585858585856141e0565b611f09612bbf565b611f11612e0d565b611f1b828261420f565b611f256001600555565b5050565b611f31613f7e565b6001600160a01b038116611f58576040516329d6af1160e01b815260040160405180910390fd5b603380546001600160a01b0319166001600160a01b0392909216919091179055565b6000611f8560255490565b60205461174c9190615b9c565b6001600160a01b038116600090815260276020526040812054606091816001600160401b03811115611fc657611fc6615bf4565b604051908082528060200260200182016040528015611fff57816020015b611fec615540565b815260200190600190039081611fe45790505b50905060015b82811161208957604080516060810182528281526001600160a01b038716600090815260286020908152838220858352815290839020549082015290810161204d87846111e2565b90528261205b600184615b9c565b8151811061206b5761206b615c0a565b6020026020010181905250808061208190615c20565b915050612005565b509392505050565b60006001600160a01b0383166120ba576040516329d6af1160e01b815260040160405180910390fd5b336000818152603c602090815260408083206001600160a01b038816808552925280832086905551859391927fd508e6bf29a4128e58df993e4fe1db1d926db54e85247bc919df2c52eb78212591a450600192915050565b6001600160a01b039190911660009081526015602090815260408083209383529290522080546001909101549091565b60006112aa8261426d565b600061174c30611e42565b6060600480546112f590615b4e565b61216f612bbf565b612177612e0d565b61218484848484336141e0565b61218e6001600555565b50505050565b6001600160a01b0381166000908152602b60205260408120816121b6846127e1565b8152602001908152602001600020600101549050919050565b6121d7612bbf565b6121df612e0d565b6121848484848433613aa0565b600033816121fa828661265f565b90508381101561225a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401611470565b6122678286868403612a9b565b506001949350505050565b6035546040516370a0823160e01b81526000916001600160a01b0316906370a08231906122a3903090600401615911565b602060405180830381865afa1580156122c0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174c9190615b83565b60003361138681858561390e565b600060225460215461174c9190615b9c565b6032546001600160a01b0316336001600160a01b031614612338576040516339e2f41f60e21b815260040160405180910390fd5b6001600160a01b03811661235f576040516329d6af1160e01b815260040160405180910390fd5b603280546001600160a01b0319166001600160a01b0392909216919091179055565b612389612bbf565b612391612e0d565b6113cc6123a033836000613b15565b6142ce565b6123ad612bbf565b6033546001600160a01b0316336001600160a01b0316146123e157604051630eb3f67960e21b815260040160405180910390fd5b603354611556906001600160a01b03166123fa81611e42565b613207565b612407613f7e565b6001600160a01b03821661242e576040516329d6af1160e01b815260040160405180910390fd5b6001600160a01b03919091166000908152603b60205260409020805460ff1916911515919091179055565b60008060008060006124778660009081526012602052604090205490565b90506124838787612112565b90935091506000612493886127e1565b9050835b82811161256e576000806124ab8a84611e5d565b9150915060006124bb8b8561184f565b50905060006124cc8d8988866142f6565b9850905083158015906124de57508015155b1561250d57670de0b6b3a76400006124f68583615bb3565b6125009190615bd2565b61250a908c61561f565b9a505b811580159061251b57508015155b1561254a57670de0b6b3a76400006125338383615bb3565b61253d9190615bd2565b612547908b61561f565b99505b61255585600161561f565b985050505050808061256690615c20565b915050612497565b50505092959194509250565b612582615561565b6001600160a01b0383166000908152601e602090815260408083208584528252808320548352601f82529182902082516101808101845281548152600182015461ffff169281019290925260028082015493830193909352600381015465ffffffffffff8082166060850152600160301b909104166080830152600481015460a0830152600581015460c0830152600681015460e0830152600781015461010083015260088101546101208301526009810154610140830152600a8101549192909161016084019160ff909116908111156112935761129361567d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080612698836016612459565b509092506126aa91508290508361561f565b91506126b7836045612459565b509092506126c991508290508361561f565b91506126d7836101a4612459565b5090925061177091508290508361561f565b6033546001600160a01b0316336001600160a01b03161461271d576040516339e2f41f60e21b815260040160405180910390fd5b600160395460ff1660018111156127365761273661567d565b141561275557604051633ee45dcb60e21b815260040160405180910390fd5b6039805460ff19166001179055603354611556906001600160a01b03166714adf4b7320334b9601e1b6130c9565b6001600160a01b03166000908152602d602052604090205490565b6127a6612bbf565b6127ae612e0d565b611f1b826113c784846127c060065490565b600160046113c2600f5460ff1690565b6127d8613f7e565b6113d6816141be565b6001600160a01b03166000908152602a602052604090205490565b612804612e0d565b61280c612bbf565b6103e861281833610f6b565b61282390600161561f565b1115612842576040516334da899760e11b815260040160405180910390fd5b80156128515761285181613176565b60006040518060c001604052808581526020018481526020018381526020018561287a601c5490565b612884919061561f565b815260200161289260175490565b61289d90600161561f565b81526020016128af866118a560085490565b9052905060006128eb3383516020850151600954600a54600b546128d233611a87565b89606001518a608001518b60a001518c6040015161437f565b601a546128f8919061561f565b90506129168260800151836060015183601792909255601c55601a55565b61291f85614420565b50506115496001600555565b600080612939836016612459565b5091925061294b91508290508361561f565b9150612958836045612459565b5091925061296a91508290508361561f565b9150612978836101a4612459565b5091925061177091508290508361561f565b6001600160a01b0381166000908152601d6020526040902054606090806001600160401b038111156129be576129be615bf4565b6040519080825280602002602001820160405280156129f757816020015b6129e46155e1565b8152602001906001900390816129dc5790505b50915060015b818111612a9457604080516080810182528281526001600160a01b0386166000908152601e6020908152838220858352808252848320805483860152928690529052600101549181019190915260608101612a58868461257a565b905283612a66600184615b9c565b81518110612a7657612a76615c0a565b60200260200101819052508080612a8c90615c20565b9150506129fd565b5050919050565b6001600160a01b038316612afd5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401611470565b6001600160a01b038216612b5e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401611470565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600654600062015180612bf27f000000000000000000000000000000000000000000000000000000000000000042615b9c565b612bfc9190615bd2565b612c0790600161561f565b905081811115611f2557600854600954600a54600b546000612c298787615b9c565b905060005b81811015612de957612710612c4561271a88615bb3565b612c4f9190615bd2565b9550612710612c606126ed87615bb3565b612c6a9190615bd2565b9450612710612c7b6126ed86615bb3565b612c859190615bd2565b935068327cb2734119d3b7a9601f1b861115612cab5768327cb2734119d3b7a9601f1b95505b600c548810158015612cbe5750600d5415155b8015612cce5750611b58600e5414155b15612d20576032600d6000828254612ce69190615b9c565b925050819055506032600e6000828254612d00919061561f565b925050819055506007600c6000828254612d1a919061561f565b90915550505b6958f03ee118a13e800000851015612d40576958f03ee118a13e80000094505b612d4e6103e8612710615bb3565b841015612d6657612d636103e8612710615bb3565b93505b60458711612d8257612d7b6202361f84615b9c565b9250612d87565b600092505b85612d9189615c20565b604080518881526020810188905290810186905290995089907f1b4cf4ae62850d5107d63ca4895b7d62305df42148813646f7f4a76638a9618a9060600160405180910390a380612de181615c20565b915050612c2e565b5050600893909355600991909155600a55600b5560065550600f805460ff19169055565b60026005541415612e605760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611470565b6002600555565b6001600160a01b038616600090815260286020908152604080832088845290915281205480612ea95760405163de9d71e560e01b815260040160405180910390fd5b6000818152602960209081526040808320815160e0810183528154815260018201549381019390935260028082015461ffff81169385019390935265ffffffffffff62010000840481166060860152600160401b9093049092166080840152600381015460a08401526004810154909160c084019160ff1690811115612f3157612f3161567d565b6002811115612f4257612f4261567d565b905250905060018160c001516002811115612f5f57612f5f61567d565b1415612f7e5760405163081b599f60e41b815260040160405180910390fd5b60028160c001516002811115612f9657612f9661567d565b1415612fb55760405163c3fb2f4760e01b815260040160405180910390fd5b6004856004811115612fc957612fc961567d565b148015612fe15750806080015165ffffffffffff1642105b15612fff57604051639d2f92f560e01b815260040160405180910390fd5b60208101518151613016908b9083908b898c614508565b50600187600481111561302b5761302b61567d565b14156130655760256000815461304090615c20565b909155506000838152602960205260409020600401805460ff191660011790556130af565b60028760048111156130795761307961567d565b14156130af5760266000815461308e90615c20565b909155506000838152602960205260409020600401805460ff191660021790555b6130bb8a84848a6146b3565b9a9950505050505050505050565b6001600160a01b03821661311f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401611470565b8060026000828254613131919061561f565b90915550506001600160a01b03821660008181526020818152604080832080548601905551848152600080516020615cf0833981519152910160405180910390a35050565b73f19308f923582a6f7c465e5ce7a9dc1bec6665b16333f3fd783360315460405160e084901b6001600160e01b03191681526001600160a01b03928316600480830191909152602482018790526044820181905260648201529116608482015260a401600060405180830381600087803b1580156131f357600080fd5b505af115801561181f573d6000803e3d6000fd5b6001600160a01b0382166132675760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401611470565b6001600160a01b038216600090815260208190526040902054818110156132db5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401611470565b6001600160a01b038316600081815260208181526040808320868603905560028054879003905551858152919291600080516020615cf0833981519152910160405180910390a3505050565b6001600160a01b03881660009081526027602052604081208054829190829061334f90615c20565b918290555090506103e88111156133795760405163174a8f9960e21b815260040160405180910390fd5b601e881080613389575061033e88115b156133a75760405163d1b1ca9d60e01b815260040160405180910390fd5b60006133b48a8a8a613fa9565b905060016133ca670de0b6b3a764000083615bd2565b10156133e95760405163082aaa8760e41b815260040160405180910390fd5b84156134325760006133fc86868d614775565b90506107d081111561340d57506107d05b61271061341a8284615bb3565b6134249190615bd2565b61342e908361561f565b9150505b613440828c8c8c858a6147ba565b61344f8b828c8a8a6000614508565b9b9a5050505050505050505050565b8060011415611f255760166000526012602052600080516020615cd08339815191525415611f255760166000526012602052600080516020615cd0833981519152546134ab90600161561f565b6001600160a01b038316600090815260156020908152604080832060168452825282209290925560459052601290527f2438ba9a9fcd62a1364c4e295291b48be211763142dce8144a28ac91969f666f5461350790600161561f565b6001600160a01b03831660009081526015602090815260408083206045845282528220929092556101a49052601290527fb7ff304c5ab3d0f93c4868e4aee66ebe077d23da2da94c4b2280ba2f567bd0225461356490600161561f565b6001600160a01b03831660009081526015602090815260408083206101a4845290915290206001600160601b039190911690555050565b6000806000806000603654905080600014156135ca57604051630b0daf9d60e21b815260040160405180910390fd5b60006036819055604051829133917f97934fea6c25f21bceb486fba06c291987ec0bc4e293ea7b328285bdb07a180f9190a3620f424061360c610bb883615bb3565b6136169190615bd2565b94506136228582615b9c565b9050612710613630600d5490565b61363a9083615bb3565b6136449190615bd2565b9350612710613652600e5490565b61365c9083615bb3565b6136669190615bd2565b925061271061367660c883615bb3565b6136809190615bd2565b9150600082846136908785615b9c565b61369a9190615b9c565b6136a49190615b9c565b9050801561371f5760006127106136bd610dac84615bb3565b6136c79190615bd2565b905060006127106136da610bb885615bb3565b6136e49190615bd2565b90506136f1601683614971565b6136fc604582614971565b61371c6101a48261370d8587615b9c565b6137179190615b9c565b614971565b50505b60375480156137a0576000603781905561271061373e610dac84615bb3565b6137489190615bd2565b9050600061271061375b610bb885615bb3565b6137659190615bd2565b905061377260168361498f565b61377d60458261498f565b61379d6101a48261378e8587615b9c565b6137989190615b9c565b61498f565b50505b50505090919293565b6000838152601660205260408120548210156137c757506000611770565b6137d0846149ad565b600084815260106020908152604080832054601190925290912054811580156137f7575080155b1561380757600092505050611770565b61381386838388614a18565b506040518290879033907f973833b060ae272a085ff5b17b764e39ddac6a5612bdc9337f586dc7efee604990600090a450600195945050505050565b61385833611c6e565b60315461386e906001600160a01b031682614037565b603354613884906001600160a01b031684614037565b60345461218e906001600160a01b031683614037565b60006138a6848461265f565b9050600019811461218e57818110156139015760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401611470565b61218e8484848403612a9b565b6001600160a01b0383166139725760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401611470565b6001600160a01b0382166139d45760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401611470565b6001600160a01b03831660009081526020819052604090205481811015613a4c5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401611470565b6001600160a01b0384811660008181526020818152604080832087870390559387168083529184902080548701905592518581529092600080516020615cf0833981519152910160405180910390a361218e565b83613abe57604051630aa71b7760e41b815260040160405180910390fd5b83613ac886611e42565b1015613ae757604051631d78718160e01b815260040160405180910390fd5b613af285338661389a565b613afc8383614ae1565b613b068585613207565b61181f85858585856000614c01565b6001600160a01b0383166000908152601e602090815260408083208584529091528120805460019091015481613b5e57604051637a2e11eb60e01b815260040160405180910390fd5b6000828152601f6020908152604080832081516101808101835281548152600182015461ffff169381019390935260028082015492840192909252600381015465ffffffffffff8082166060860152600160301b909104166080840152600481015460a0840152600581015460c0840152600681015460e0840152600781015461010084015260088101546101208401526009810154610140840152600a810154909161016084019160ff1690811115613c1a57613c1a61567d565b6002811115613c2b57613c2b61567d565b905250905060018161016001516002811115613c4957613c4961567d565b1415613c68576040516339f4887960e21b815260040160405180910390fd5b60028161016001516002811115613c8157613c8161567d565b1415613ca0576040516323acf12560e01b815260040160405180910390fd5b42816080015165ffffffffffff16118015613ccc57506000856001811115613cca57613cca61567d565b145b15613cea57604051636971be5760e11b815260040160405180910390fd5b8060400151601a6000828254613d009190615b9c565b90915550611e1f90508784848489614cff565b6001600160a01b0384166000908152602d602052604081208054849290613d3b90849061561f565b9250508190555081602c6000828254613d54919061561f565b90915550506001600160a01b03831615613dd2576001600160a01b0383166000908152602e602052604081208054849290613d9090849061561f565b90915550506001600160a01b038084166000908152602f6020908152604080832093881683529290529081208054849290613dcc90849061561f565b90915550505b826001600160a01b0316846001600160a01b03167fdf82885dedaf240ee119dba88f242ab92b4bff124f1c029d077cad9a57fb97c68484604051613e17929190615c3b565b60405180910390a350505050565b6000620186a0611ae58484615bb3565b60008082613e4585612710615bb3565b6118df9190615bd2565b60008086613e5d8988615bb3565b613e679190615bb3565b905086600114613eab57612710613e7f600189615b9c565b613e8a600b84615bb3565b613e949190615bb3565b613e9e9190615bd2565b613ea89082615b9c565b90505b9050808415613ee557620f42406064613ec48784615bb3565b613ece9190615bd2565b613ed89190615bd2565b613ee2908361561f565b91505b8315613f2157670de0b6b3a76400006064613f008684615bb3565b613f0a9190615bd2565b613f149190615bd2565b613f1e908361561f565b91505b8215613f65576103e88311613f365782613f3a565b6103e85b92506000612710613f4b8585615bb3565b613f559190615bd2565b9050613f61818461561f565b9250505b613f72620186a083615bd2565b98975050505050505050565b6030546001600160a01b0316331461155657604051635e8a044f60e01b815260040160405180910390fd5b60008364174876e800613fbb8561426d565b613fc59083615bb3565b613fcf9190615bd2565b613fd9908261561f565b9050613fed670de0b6b3a764000084615bd2565b613ff79082615bd2565b95945050505050565b600080808080806140113388612459565b935093509350935061402b6140233390565b888484614f29565b50919590945092505050565b6001600160a01b03821661405e576040516329d6af1160e01b815260040160405180910390fd5b60355460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906140909085908590600401615c58565b6020604051808303816000875af11580156140af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115499190615c71565b6001600160a01b0382166140fa576040516329d6af1160e01b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614147576040519150601f19603f3d011682016040523d82523d6000602084013e61414c565b606091505b505090508061154957604051633ad7296360e11b815260040160405180910390fd5b600082821161417f575060006118df565b620186a0670de0b6b3a76400006141968585615b9c565b6141a08789615bb3565b6141aa9190615bb3565b6141b49190615bb3565b613ff79190615bd2565b603080546001600160a01b0319166001600160a01b0392909216919091179055565b6141e985614fd6565b6141f38383614ae1565b61181f856142058787611b1360065490565b8585856002614c01565b6142188261505b565b614223600080614ae1565b600061423183836001613b15565b60315490915061425d906001600160a01b031661271061425384610320615bb3565b6113c79190615bd2565b6115498382600080336001614c01565b6000601e82116142815750620f4240919050565b600061428e601e84615b9c565b9050600061429f601e61033e615b9c565b8211156142b8576142b3601e61033e615b9c565b6142ba565b815b9050610190613e4564174876e80083615bb3565b6142d833826130c9565b6032546113d6906001600160a01b0316612710614253846064615bb3565b600080845b848111614374576001600160a01b0387166000908152602b60209081526040808320848452909152902054841061435a576001600160a01b0387166000908152602b60209081526040808320848452909152902060010154925061435f565b614374565b9450848061436c81615c20565b9150506142fb565b509095939450505050565b600089158061438e575060fa8a115b156143ac576040516332c13ef760e01b815260040160405180910390fd5b8a15806143bb5750620186a08b115b156143d9576040516304c7176560e31b815260040160405180910390fd5b600082156143ee576143eb8385613e35565b90505b6143fc8c8c8c8b8b86613e4f565b91506144108d8d8d858d8d8b8d8c8c6150af565b509b9a5050505050505050505050565b600061442f826118a560085490565b6035549091506001600160a01b03166323b872dd336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018490526064016020604051808303816000875af1158015614497573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144bb9190615c71565b5080603660008282546144ce919061561f565b909155505060065460405182919033907fd833e83f161e4ddfb1306cdf11a374a0a23393f008f9394b85999b988c232e3690600090a45050565b6001600160a01b0386166000908152602a6020908152604080832054602b83528184208185529092528220600101548284600481111561454a5761454a61567d565b14156145d4578161455a57600192505b614564888261561f565b6001600160a01b038a166000908152602b602052604081209061458685615c20565b94508481526020019081526020016000206001018190555087602160008282546145b0919061561f565b9250508190555086602360008282546145c9919061561f565b909155506146499050565b6145de8882615b9c565b6001600160a01b038a166000908152602b602052604081209061460085615c20565b945084815260200190815260200160002060010181905550876022600082825461462a919061561f565b9250508190555086602360008282546146439190615b9c565b90915550505b600085600181111561465d5761465d61567d565b146146725761466d86600161561f565b614674565b855b6001600160a01b039099166000818152602b6020908152604080832086845282528083209c909c55918152602a90915298909820559695505050505050565b6000808360000151905060006146e3856060015165ffffffffffff16866080015165ffffffffffff1642876152d6565b9050600060646146f38385615bb3565b6146fd9190615bd2565b90506147098184615b9c565b9350806024600082825461471d919061561f565b90915550506040805185815260208101839052839189916001600160a01b038c16917f971d9ff3287b3ba75194105e7281e55c93b0a89cad9915664bb3fd9211f8d5f1910160405180910390a4505050949350505050565b600080670de0b6b3a764000061478b8585615bb3565b6147959190615bd2565b90506000816147a661271088615bb3565b6147b09190615bd2565b9695505050505050565b60006020600081546147cb90615c20565b9182905550905060006147e16201518086615bb3565b6147eb904261561f565b905060006040518060e001604052808881526020018681526020018761ffff1681526020014265ffffffffffff1681526020018365ffffffffffff168152602001858152602001600060028111156148455761484561567d565b90526001600160a01b03891660009081526028602090815260408083208d845282528083208790558683526029825291829020835181559083015160018083019190915591830151600280830180546060870151608088015161ffff9095166001600160401b0319909216919091176201000065ffffffffffff928316021765ffffffffffff60401b1916600160401b91909416029290921790915560a0840151600383015560c0840151600483018054959650869593949193909260ff199091169190849081111561491a5761491a61567d565b021790555090505082886001600160a01b03167f04e1761ddc1451be2b9abb20d50c7e317778879612685874154566bbb4acafc7888460405161495e929190615c8e565b60405180910390a3505050505050505050565b60008281526010602052604081208054839290611a2d90849061561f565b60008281526011602052604081208054839290611a2d90849061561f565b60008181526016602052604090205460065481811061154957826149d18383615b9c565b6149db9190615bd2565b6149e690600161561f565b6149f09084615bb3565b60008481526016602052604081208054909190614a0e90849061561f565b9091555050505050565b6000848152601060209081526040808320839055601182528083208390556012909152812080548290614a4a90615c20565b9182905550905081614a64670de0b6b3a764000086615bb3565b614a6e9190615bd2565b600086815260136020908152604080832085845290915290206001810191909155600654905581614aa7670de0b6b3a764000085615bb3565b614ab19190615bd2565b60009586526014602090815260408088208489529091529095206001810195909555600654909455509192915050565b6008614aed838361561f565b1115614b0c57604051632902579f60e01b815260040160405180910390fd5b6040516301ffc9a760e01b80825233916301ffc9a791614b2e91600401615ca3565b602060405180830381865afa158015614b4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b6f9190615c71565b1580614be357506040516301ffc9a760e01b815233906301ffc9a790614ba0906311686e4b60e21b90600401615ca3565b602060405180830381865afa158015614bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614be19190615c71565b155b15611f255760405163d03681f360e01b815260040160405180910390fd5b614c0d86338784613d13565b6000808415614c4757614c236127106064615bb3565b612710614c30878a615bb3565b614c3a9190615bb3565b614c449190615bd2565b91505b8515614c7e57614c5a6127106064615bb3565b612710614c67888a615bb3565b614c719190615bb3565b614c7b9190615bd2565b90505b8115614c8e57614c8e84836130c9565b8015614c9e57614c9e88826130c9565b6040516311686e4b60e21b815233906345a1b92c90614cc3908b908b90600401615c58565b600060405180830381600087803b158015614cdd57600080fd5b505af1158015614cf1573d6000803e3d6000fd5b505050505050505050505050565b600080826001811115614d1457614d1461567d565b1415614d37576000858152601f60205260409020600a01805460ff191660011790555b6001826001811115614d4b57614d4b61567d565b1415614d6e576000858152601f60205260409020600a01805460ff191660021790555b6000806000856080015165ffffffffffff16421115614daa57614da7866080015165ffffffffffff1642614da29190615b9c565b6153be565b91505b6000856001811115614dbe57614dbe61567d565b1415614ddd57614dda8660a00151876000015189601c5461416e565b90505b614dea6298968082615bd2565b8660400151614df9919061561f565b93506064614e078386615bb3565b614e119190615bd2565b9250614e1d8385615b9c565b93506000856001811115614e3357614e3361567d565b1415614e4d57601860008154614e4890615c20565b909155505b6001856001811115614e6157614e6161567d565b1415614e7b57601960008154614e7690615c20565b909155505b8215614e995782601b6000828254614e93919061561f565b90915550505b6000856001811115614ead57614ead61567d565b1415614ecf576000888152601f60205260409020600681018590556008018390555b81888a6001600160a01b03167fbd866a3fbf35e201f790e87581b1afbb3165e879df5d35313a4875a70b9f3b368787604051614f15929190918252602082015260400190565b60405180910390a450505095945050505050565b6001600160a01b03841660009081526015602090815260408083208684529091529020548214614f7a576001600160a01b038416600090815260156020908152604080832086845290915290208290555b6001600160a01b0384166000908152601560209081526040808320868452909152902060010154811461218e576001600160a01b0384166000908152601560209081526040808320868452909152902060010181905550505050565b6000614fe28233610a8d565b90506000198114611f25578061500b57604051632048203360e01b815260040160405180910390fd5b6001600160a01b0382166000908152603c6020526040812090335b6001600160a01b03166001600160a01b031681526020019081526020016000206000815461505390615cb8565b909155505050565b600061506782336109c8565b90506000198114611f25578061509057604051632048203360e01b815260040160405180910390fd5b6001600160a01b0382166000908152603a602052604081209033615026565b60006040518061018001604052808b81526020018a61ffff1681526020018981526020014265ffffffffffff168152602001620151808b6150f09190615bb3565b6150fa904261561f565b65ffffffffffff1681526020018881526020018781526020016000815260200184815260200160008152602001838152602001600060028111156151405761514061567d565b90526001600160a01b038c166000908152601d6020526040812080549293509091829061516c90615c20565b91829055506001600160a01b038d166000908152601e6020908152604080832084845282528083208a815560019081018a90558a8452601f8352928190208651815591860151828401805461ffff90921661ffff199092169190911790558501516002808301919091556060860151600383018054608089015165ffffffffffff908116600160301b026001600160601b031990921693169290921791909117905560a0860151600483015560c0860151600583015560e08601516006830155610100860151600783015561012086015160088301556101408601516009830155610160860151600a83018054959650879593949193909260ff199091169190849081111561527d5761527d61567d565b021790555090505084868d6001600160a01b03167f2b2d6cbbd64131cfb538b30ae4a9dc516d6fe02b65e223719e216846f0118a95856040516152c09190615adb565b60405180910390a4505050505050505050505050565b60008383106153515760006152eb8585615b9c565b905060006152fd620151806007615bb3565b9050808211615311576000925050506118df565b6153486201518061532c6153258486615b9c565b60016154d4565b6153369190615bd2565b61534190600161561f565b60636154eb565b925050506118df565b60028260048111156153655761536561567d565b1415615373575060006118df565b600261537f8686615b9c565b6153899190615bd2565b615393908661561f565b4210156153b3576040516354d335b760e11b815260040160405180910390fd5b506032949350505050565b60006153ce620151806007615bb3565b82116153dc57506000919050565b620151806153ec6007600161561f565b6153f69190615bb3565b821161540457506001919050565b620151806154146007600261561f565b61541e9190615bb3565b821161542c57506003919050565b6201518061543c6007600361561f565b6154469190615bb3565b821161545457506008919050565b620151806154646007600461561f565b61546e9190615bb3565b821161547c57506011919050565b6201518061548c6007600561561f565b6154969190615bb3565b82116154a457506023919050565b620151806154b46007600661561f565b6154be9190615bb3565b82116154cc57506048919050565b506063919050565b6000818311156154e55750816112aa565b50919050565b6000818311156154fc5750806112aa565b5090919050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a081018290529060c08201905b905290565b6040518060600160405280600081526020016000815260200161553b615503565b60405180610180016040528060008152602001600061ffff16815260200160008152602001600065ffffffffffff168152602001600065ffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000600281111561553b5761553b61567d565b604051806080016040528060008152602001600081526020016000815260200161553b615561565b634e487b7160e01b600052601160045260246000fd5b6000821982111561563257615632615609565b500190565b80356001600160a01b038116811461564e57600080fd5b919050565b6000806040838503121561566657600080fd5b61566f83615637565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b600381106113d6576113d661567d565b805182526020810151602083015261ffff6040820151166040830152606081015165ffffffffffff8082166060850152806080840151166080850152505060a081015160a083015260c08101516156f981615693565b8060c0840152505050565b60e081016112aa82846156a3565b60006020828403121561572457600080fd5b81356001600160e01b03198116811461177057600080fd5b600060208083528351808285015260005b818110156157695785810183015185820160400152820161574d565b8181111561577b576000604083870101525b50601f01601f1916929092016040019392505050565b6000602082840312156157a357600080fd5b5035919050565b6000806000606084860312156157bf57600080fd5b505081359360208301359350604090920135919050565b600080604083850312156157e957600080fd5b6157f283615637565b915061580060208401615637565b90509250929050565b60008060006060848603121561581e57600080fd5b61582784615637565b925061583560208501615637565b9150604084013590509250925092565b60006020828403121561585757600080fd5b61177082615637565b600080600080600060a0868803121561587857600080fd5b61588186615637565b94506020860135935060408601359250606086013591506158a460808701615637565b90509295509295909350565b600080604083850312156158c357600080fd5b50508035926020909101359150565b600080600080608085870312156158e857600080fd5b84359350602085013592506040850135915061590660608601615637565b905092959194509250565b6001600160a01b0391909116815260200190565b602080825282518282018190526000919060409081850190868401855b8281101561597c578151805185528681015187860152850151615967868601826156a3565b50610120939093019290850190600101615942565b5091979650505050505050565b602081016002831061599d5761599d61567d565b91905290565b600080600080608085870312156159b957600080fd5b6159c285615637565b966020860135965060408601359560600135945092505050565b80151581146113d657600080fd5b600080604083850312156159fd57600080fd5b615a0683615637565b91506020830135615a16816159dc565b809150509250929050565b615a2a81615693565b9052565b805182526020810151615a47602084018261ffff169052565b50604081015160408301526060810151615a6b606084018265ffffffffffff169052565b506080810151615a85608084018265ffffffffffff169052565b5060a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152506101208082015181840152506101408082015181840152506101608082015161218e82850182615a21565b61018081016112aa8284615a2e565b602080825282518282018190526000919060409081850190868401855b8281101561597c578151805185528681015187860152858101518686015260609081015190615b3881870183615a2e565b50506101e0939093019290850190600101615b07565b600181811c90821680615b6257607f821691505b602082108114156154e557634e487b7160e01b600052602260045260246000fd5b600060208284031215615b9557600080fd5b5051919050565b600082821015615bae57615bae615609565b500390565b6000816000190483118215151615615bcd57615bcd615609565b500290565b600082615bef57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000600019821415615c3457615c34615609565b5060010190565b82815260408101615c4b83615693565b8260208301529392505050565b6001600160a01b03929092168252602082015260400190565b600060208284031215615c8357600080fd5b8151611770816159dc565b828152610100810161177060208301846156a3565b6001600160e01b031991909116815260200190565b600081615cc757615cc7615609565b50600019019056fec4f8f7f5ee45326dd80cc2262cf4948c0aa62c4ed9b775cbe9662ca3618994d3ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220e147f8db36d790d87b37772e1baf6c0932f5345d8bcbb31daca1afd7a334e2c864736f6c634300080a00330000000000000000000000006c3c3a22ab3725c017d41d31b23efaf51a8ece480000000000000000000000009bff9f810d19cdb4bf7701c9d5ad101e91cda08d000000000000000000000000f19308f923582a6f7c465e5ce7a9dc1bec6665b1000000000000000000000000a2d21205aa7273baddfc8e9551e05e23bb49ce4600000000000000000000000015e5b9b9adf208cc7ca3ae1e6a49506eb5f397dd
Deployed Bytecode
0x6080604052600436106104ae5760003560e01c8062281d14146104d8578062ae5faa146104fc57806301ffc9a71461052957806306fdde0314610559578063095ea7b31461057b5780630cbe28d61461059b57806310cc8ee7146105bb57806312065fe0146105db5780631371bb40146105ee57806313aad5101461063457806318160ddd146106495780631ae409c01461065e578063216630b4146106735780632277d1bd14610688578063236393851461069d57806323b5675f146106b257806323b872dd146106c757806324f33a5b146106e7578063276b5c1a146106fc57806329b70d7a146107115780632d02347a146107475780632f77195114610774578063300284f214610789578063313ce567146107a957806333f3fd78146107c557806337c4f8c4146107e5578063392e353d14610805578063395093511461083a578063398015271461085a5780633a9693e11461087a5780633c34267f1461089a5780633d05012d146108ba578063403b285b146108cf57806341d6831a146108f657806345a1b92c1461090b578063462a8c2f1461092b5780634cf2d48f146109585780634df833af14610978578063510f8b9c1461098d578063544a6c59146109ad57806354f5d028146109f3578063566d0be314610a085780635742744114610a285780635a3c8b7d14610a485780635c1c5cb314610a5d5780635c3ef13014610a725780636272683314610ab8578063682d2d1114610acd578063692b6fdc14610aed5780636c52876b14610b1a5780636f60963314610b2f5780636f9170f614610b4457806370a0823114610b7d57806370c9b00214610b9d578063715018a614610bbd5780637629052d14610bd25780637789281e14610bf257806377a5426914610c075780637b763a2c14610c275780637d6b325314610c475780637ec26dca14610c67578063800bb26914610c7c578063842e298114610c91578063856a73da14610cbe578063880a083614610cde57806389de416514610cf35780638b13cdae14610d1357806392c1df5414610d335780639332812414610d485780639474782014610d6857806395d89b4114610d7d57806396d9720814610d925780639a5a6cd914610db25780639ed9922014610dd2578063a2573e5b14610df2578063a457c2d714610e10578063a76222af14610e30578063a9059cbb14610e45578063af4fb76314610e65578063af835b8a14610e7a578063b0977f6914610ea7578063b0aebfbc14610ebc578063b8fac78914610edc578063b984c94614610ef1578063baf20eef14610f06578063bb88603c14610f26578063c081f4c014610f3b578063c50312ad14610f50578063d16baeb914610f86578063d6f8688f14610fa6578063d819e19814610fe6578063d9af94af14611013578063dd62ed3e14611026578063dff96e9a14611046578063e33a3c941461105b578063e3af6d0a1461107b578063e3d3227d146110ae578063e8052174146110c3578063efe17023146110e3578063f2fde38b14611103578063f63ec50e14611123578063f80b0cfb14611138578063faa94d3b1461114d578063fac940f41461116d578063fbf9529d14611180578063fe9497a614611195578063ffb75cab146111b557600080fd5b366104d35734156104d15734603760008282546104cb919061561f565b90915550505b005b600080fd5b3480156104e457600080fd5b50600b545b6040519081526020015b60405180910390f35b34801561050857600080fd5b5061051c610517366004615653565b6111e2565b6040516104f39190615704565b34801561053557600080fd5b50610549610544366004615712565b6112b0565b60405190151581526020016104f3565b34801561056557600080fd5b5061056e6112e6565b6040516104f3919061573c565b34801561058757600080fd5b50610549610596366004615653565b611378565b3480156105a757600080fd5b506104d16105b6366004615791565b611390565b3480156105c757600080fd5b506104d16105d63660046157aa565b6113d9565b3480156105e757600080fd5b50476104e9565b3480156105fa57600080fd5b506104e96106093660046157d6565b6001600160a01b039182166000908152602f6020908152604080832093909416825291909152205490565b34801561064057600080fd5b506104d161154e565b34801561065557600080fd5b506002546104e9565b34801561066a57600080fd5b506006546104e9565b34801561067f57600080fd5b50601a546104e9565b34801561069457600080fd5b506104d1611558565b3480156106a957600080fd5b506104e961172d565b3480156106be57600080fd5b50600d546104e9565b3480156106d357600080fd5b506105496106e2366004615809565b611751565b3480156106f357600080fd5b50600e546104e9565b34801561070857600080fd5b506026546104e9565b34801561071d57600080fd5b506104e961072c366004615845565b6001600160a01b03166000908152602e602052604090205490565b34801561075357600080fd5b506104e9610762366004615791565b60009081526016602052604090205490565b34801561078057600080fd5b506019546104e9565b34801561079557600080fd5b506105496107a4366004615653565b611777565b3480156107b557600080fd5b50604051601281526020016104f3565b3480156107d157600080fd5b506104d16107e0366004615860565b6117f8565b3480156107f157600080fd5b506104d1610800366004615791565b611826565b34801561081157600080fd5b506108256108203660046158b0565b61184f565b604080519283526020830191909152016104f3565b34801561084657600080fd5b50610549610855366004615653565b611873565b34801561086657600080fd5b506104e96108753660046158d2565b611895565b34801561088657600080fd5b506104d1610895366004615845565b6118e7565b3480156108a657600080fd5b506104d16108b5366004615791565b611964565b3480156108c657600080fd5b506037546104e9565b3480156108db57600080fd5b506032546001600160a01b03165b6040516104f39190615911565b34801561090257600080fd5b506036546104e9565b34801561091757600080fd5b506104d1610926366004615653565b6119d3565b34801561093757600080fd5b506104e9610946366004615791565b60009081526010602052604090205490565b34801561096457600080fd5b506104d1610973366004615845565b611a36565b34801561098457600080fd5b506038546104e9565b34801561099957600080fd5b506104e96109a8366004615845565b611a87565b3480156109b957600080fd5b506104e96109c83660046157d6565b6001600160a01b039182166000908152603a6020908152604080832093909416825291909152205490565b3480156109ff57600080fd5b50602c546104e9565b348015610a1457600080fd5b506104d1610a23366004615791565b611aef565b348015610a3457600080fd5b50610825610a433660046158b0565b611b2a565b348015610a5457600080fd5b506009546104e9565b348015610a6957600080fd5b506104d1611b6d565b348015610a7e57600080fd5b506104e9610a8d3660046157d6565b6001600160a01b039182166000908152603c6020908152604080832093909416825291909152205490565b348015610ac457600080fd5b506104d1611bad565b348015610ad957600080fd5b506104e9610ae8366004615653565b611cc1565b348015610af957600080fd5b506104e9610b08366004615791565b60009081526011602052604090205490565b348015610b2657600080fd5b506104e9611e2a565b348015610b3b57600080fd5b506008546104e9565b348015610b5057600080fd5b50610549610b5f366004615845565b6001600160a01b03166000908152603b602052604090205460ff1690565b348015610b8957600080fd5b506104e9610b98366004615845565b611e42565b348015610ba957600080fd5b50610825610bb83660046158b0565b611e5d565b348015610bc957600080fd5b506104d1611e81565b348015610bde57600080fd5b506104d1610bed366004615845565b611e93565b348015610bfe57600080fd5b506022546104e9565b348015610c1357600080fd5b506104d1610c22366004615860565b611ee4565b348015610c3357600080fd5b506104d1610c42366004615653565b611f01565b348015610c5357600080fd5b506104d1610c62366004615845565b611f29565b348015610c7357600080fd5b506017546104e9565b348015610c8857600080fd5b506104e9611f7a565b348015610c9d57600080fd5b50610cb1610cac366004615845565b611f92565b6040516104f39190615925565b348015610cca57600080fd5b50610549610cd9366004615653565b612091565b348015610cea57600080fd5b506021546104e9565b348015610cff57600080fd5b50610825610d0e366004615653565b612112565b348015610d1f57600080fd5b506104e9610d2e366004615791565b612142565b348015610d3f57600080fd5b50601c546104e9565b348015610d5457600080fd5b50600f5460ff166040516104f39190615989565b348015610d7457600080fd5b506104e961214d565b348015610d8957600080fd5b5061056e612158565b348015610d9e57600080fd5b506104d1610dad3660046159a3565b612167565b348015610dbe57600080fd5b506104e9610dcd366004615845565b612194565b348015610dde57600080fd5b506104d1610ded3660046159a3565b6121cf565b348015610dfe57600080fd5b506031546001600160a01b03166108e9565b348015610e1c57600080fd5b50610549610e2b366004615653565b6121ec565b348015610e3c57600080fd5b506104e9612272565b348015610e5157600080fd5b50610549610e60366004615653565b6122e4565b348015610e7157600080fd5b506104e96122f2565b348015610e8657600080fd5b506104e9610e95366004615791565b60009081526012602052604090205490565b348015610eb357600080fd5b506023546104e9565b348015610ec857600080fd5b506104d1610ed7366004615845565b612304565b348015610ee857600080fd5b506025546104e9565b348015610efd57600080fd5b506020546104e9565b348015610f1257600080fd5b506104d1610f21366004615791565b612381565b348015610f3257600080fd5b506104d16123a5565b348015610f4757600080fd5b506024546104e9565b348015610f5c57600080fd5b506104e9610f6b366004615845565b6001600160a01b03166000908152601d602052604090205490565b348015610f9257600080fd5b506104d1610fa13660046159ea565b6123ff565b348015610fb257600080fd5b50610fc6610fc1366004615653565b612459565b6040805194855260208501939093529183015260608201526080016104f3565b348015610ff257600080fd5b50611006611001366004615653565b61257a565b6040516104f39190615adb565b34801561101f57600080fd5b50426104e9565b34801561103257600080fd5b506104e96110413660046157d6565b61265f565b34801561105257600080fd5b50601b546104e9565b34801561106757600080fd5b506104e9611076366004615845565b61268a565b34801561108757600080fd5b507f0000000000000000000000000000000000000000000000000000000065df437f6104e9565b3480156110ba57600080fd5b506104d16126e9565b3480156110cf57600080fd5b506104e96110de366004615845565b612783565b3480156110ef57600080fd5b506104d16110fe366004615653565b61279e565b34801561110f57600080fd5b506104d161111e366004615845565b6127d0565b34801561112f57600080fd5b50600a546104e9565b34801561114457600080fd5b506018546104e9565b34801561115957600080fd5b506104e9611168366004615845565b6127e1565b6104d161117b3660046157aa565b6127fc565b34801561118c57600080fd5b506007546104e9565b3480156111a157600080fd5b506104e96111b0366004615845565b61292b565b3480156111c157600080fd5b506111d56111d0366004615845565b61298a565b6040516104f39190615aea565b6111ea615503565b6001600160a01b038316600090815260286020908152604080832085845282528083205483526029825291829020825160e0810184528154815260018201549281019290925260028082015461ffff81169484019490945265ffffffffffff62010000850481166060850152600160401b9094049093166080830152600381015460a083015260048101549192909160c084019160ff909116908111156112935761129361567d565b60028111156112a4576112a461567d565b90525090505b92915050565b60006001600160e01b031982166301ffc9a760e01b14806112aa57506001600160e01b031982166311686e4b60e21b1492915050565b6060600380546112f590615b4e565b80601f016020809104026020016040519081016040528092919081815260200182805461132190615b4e565b801561136e5780601f106113435761010080835404028352916020019161136e565b820191906000526020600020905b81548152906001019060200180831161135157829003601f168201915b5050505050905090565b600033611386818585612a9b565b5060019392505050565b611398612bbf565b6113a0612e0d565b6113cc336113c733846113b260065490565b600160036113c2600f5460ff1690565b612e67565b6130c9565b6113d66001600555565b50565b6113e1612bbf565b6113e9612e0d565b826113f333611e42565b101561141257604051631d78718160e01b815260040160405180910390fd5b33321461147957336000908152603b602052604090205460ff166114795760405162461bcd60e51b815260206004820152601960248201527821b7b73a3930b1ba103737ba103bb434ba32b634b9ba32b21760391b60448201526064015b60405180910390fd5b80156114885761148881613176565b6114923384613207565b61153f3361153a3386866114a560075490565b600654600f5460ff168960008b116114be576000613327565b603360009054906101000a90046001600160a01b03166001600160a01b031663665f8efb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611511573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115359190615b83565b613327565b61345e565b6115496001600555565b505050565b611556612bbf565b565b611560612bbf565b611568612e0d565b600061157360225490565b6021546115809190615b9c565b905060018110156115a45760405163df8afe1960e01b815260040160405180910390fd5b6000806000806036546000146115c8576115bc61359b565b92965090945090925090505b60006115d360065490565b9050600060016115e5601689856137a9565b60018111156115f6576115f661567d565b148015611614575060008160018111156116125761161261567d565b145b61161e5780611623565b506001805b506001611632604589856137a9565b60018111156116435761164361567d565b1480156116615750600081600181111561165f5761165f61567d565b145b61166b5780611670565b506001805b5060016116806101a489856137a9565b60018111156116915761169161567d565b1480156116af575060008160018111156116ad576116ad61567d565b145b6116b957806116be565b506001805b5060018160018111156116d3576116d361567d565b141561170a576000600f5460ff1660018111156116f2576116f261567d565b141561170a5761170a600f805460ff19166001179055565b851561171c5761171c8686858761384f565b505050505050506115566001600555565b60006019546018546017546117429190615b9c565b61174c9190615b9c565b905090565b60003361175f85828561389a565b61176a85858561390e565b60019150505b9392505050565b60006001600160a01b0383166117a0576040516329d6af1160e01b815260040160405180910390fd5b336000818152603a602090815260408083206001600160a01b038816808552925280832086905551859391927ff8e109bcddf5e12132b7cd8a8517d97498f50c7ac595874d6f513243098b079891a450600192915050565b611800612bbf565b611808612e0d565b6118158585858585613aa0565b61181f6001600555565b5050505050565b61182e612bbf565b611836612e0d565b6113cc33600061184833856001613b15565b6001613d13565b60009182526014602090815260408084209284529190529020600181015490549091565b600033611386818585611886838361265f565b611890919061561f565b612a9b565b6000806118aa866118a560085490565b613e25565b905060006118b88583613e35565b90506118da87876118c860095490565b600b546118d489611a87565b86613e4f565b925050505b949350505050565b6031546001600160a01b0316336001600160a01b03161461191b576040516339e2f41f60e21b815260040160405180910390fd5b6001600160a01b038116611942576040516329d6af1160e01b815260040160405180910390fd5b603180546001600160a01b0319166001600160a01b0392909216919091179055565b61196c612bbf565b611974612e0d565b8061199257604051630aa71b7760e41b815260040160405180910390fd5b8061199c33611e42565b10156119bb57604051631d78718160e01b815260040160405180910390fd5b6119c53382613207565b6113cc336000836000613d13565b6035546001600160a01b03163314611a1b5760405162461bcd60e51b815260206004820152600b60248201526a09edcd8f240a8d2e8c2dcb60ab1b6044820152606401611470565b8060386000828254611a2d919061561f565b90915550505050565b611a3e613f7e565b6001600160a01b038116611a65576040516329d6af1160e01b815260040160405180910390fd5b603480546001600160a01b0319166001600160a01b0392909216919091179055565b600080611a9383612783565b905080611aa35750600092915050565b680204fce5e3e2502611601f1b8110611ac65750676f05b59d3b20000092915050565b680204fce5e3e2502611601f1b611ae582676f05b59d3b200000615bb3565b6117709190615bd2565b611af7612bbf565b611aff612e0d565b6113cc336000611b233385611b1360065490565b600260036113c2600f5460ff1690565b6002613d13565b6000806000611b3860075490565b9050611b45858583613fa9565b9250611b59670de0b6b3a764000082615bd2565b611b639086615bd2565b9150509250929050565b611b75612bbf565b611b7d612e0d565b600080600080611b8b61359b565b9350935093509350611b9f8484848461384f565b505050506115566001600555565b611bb5612bbf565b611bbd612e0d565b600080600080611bcd6016614000565b9092509050611bdc828561561f565b9350611be8818461561f565b9250611bf46045614000565b9092509050611c03828561561f565b9350611c0f818461561f565b9250611c1c6101a4614000565b9092509050611c2b828561561f565b9350611c37818461561f565b925083158015611c45575082155b15611c63576040516354d2b34960e01b815260040160405180910390fd5b8315611c7457611c74335b85614037565b8215611c8457611c8433846140d3565b6040518390859033907ff01da32686223933d8a18a391060918c7f11a3648639edd87ae013e2e273174390600090a4505050506115566001600555565b6001600160a01b0382166000908152601e602090815260408083208484529091528120805460019091015481611d0a57604051637a2e11eb60e01b815260040160405180910390fd5b6000828152601f6020908152604080832081516101808101835281548152600182015461ffff169381019390935260028082015492840192909252600381015465ffffffffffff8082166060860152600160301b909104166080840152600481015460a0840152600581015460c0840152600681015460e0840152600781015461010084015260088101546101208401526009810154610140840152600a810154909161016084019160ff1690811115611dc657611dc661567d565b6002811115611dd757611dd761567d565b815250509050806040015193506000611dfc8260a00151836000015185601c5461416e565b9050611e0b6298968082615bd2565b611e15908661561f565b611e1f908661561f565b979650505050505050565b6000611e3560245490565b601b5461174c919061561f565b6001600160a01b031660009081526020819052604090205490565b60009182526013602090815260408084209284529190529020600181015490549091565b611e89613f7e565b61155660006141be565b611e9b613f7e565b6001600160a01b038116611ec2576040516329d6af1160e01b815260040160405180910390fd5b603580546001600160a01b0319166001600160a01b0392909216919091179055565b611eec612bbf565b611ef4612e0d565b61181585858585856141e0565b611f09612bbf565b611f11612e0d565b611f1b828261420f565b611f256001600555565b5050565b611f31613f7e565b6001600160a01b038116611f58576040516329d6af1160e01b815260040160405180910390fd5b603380546001600160a01b0319166001600160a01b0392909216919091179055565b6000611f8560255490565b60205461174c9190615b9c565b6001600160a01b038116600090815260276020526040812054606091816001600160401b03811115611fc657611fc6615bf4565b604051908082528060200260200182016040528015611fff57816020015b611fec615540565b815260200190600190039081611fe45790505b50905060015b82811161208957604080516060810182528281526001600160a01b038716600090815260286020908152838220858352815290839020549082015290810161204d87846111e2565b90528261205b600184615b9c565b8151811061206b5761206b615c0a565b6020026020010181905250808061208190615c20565b915050612005565b509392505050565b60006001600160a01b0383166120ba576040516329d6af1160e01b815260040160405180910390fd5b336000818152603c602090815260408083206001600160a01b038816808552925280832086905551859391927fd508e6bf29a4128e58df993e4fe1db1d926db54e85247bc919df2c52eb78212591a450600192915050565b6001600160a01b039190911660009081526015602090815260408083209383529290522080546001909101549091565b60006112aa8261426d565b600061174c30611e42565b6060600480546112f590615b4e565b61216f612bbf565b612177612e0d565b61218484848484336141e0565b61218e6001600555565b50505050565b6001600160a01b0381166000908152602b60205260408120816121b6846127e1565b8152602001908152602001600020600101549050919050565b6121d7612bbf565b6121df612e0d565b6121848484848433613aa0565b600033816121fa828661265f565b90508381101561225a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401611470565b6122678286868403612a9b565b506001949350505050565b6035546040516370a0823160e01b81526000916001600160a01b0316906370a08231906122a3903090600401615911565b602060405180830381865afa1580156122c0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174c9190615b83565b60003361138681858561390e565b600060225460215461174c9190615b9c565b6032546001600160a01b0316336001600160a01b031614612338576040516339e2f41f60e21b815260040160405180910390fd5b6001600160a01b03811661235f576040516329d6af1160e01b815260040160405180910390fd5b603280546001600160a01b0319166001600160a01b0392909216919091179055565b612389612bbf565b612391612e0d565b6113cc6123a033836000613b15565b6142ce565b6123ad612bbf565b6033546001600160a01b0316336001600160a01b0316146123e157604051630eb3f67960e21b815260040160405180910390fd5b603354611556906001600160a01b03166123fa81611e42565b613207565b612407613f7e565b6001600160a01b03821661242e576040516329d6af1160e01b815260040160405180910390fd5b6001600160a01b03919091166000908152603b60205260409020805460ff1916911515919091179055565b60008060008060006124778660009081526012602052604090205490565b90506124838787612112565b90935091506000612493886127e1565b9050835b82811161256e576000806124ab8a84611e5d565b9150915060006124bb8b8561184f565b50905060006124cc8d8988866142f6565b9850905083158015906124de57508015155b1561250d57670de0b6b3a76400006124f68583615bb3565b6125009190615bd2565b61250a908c61561f565b9a505b811580159061251b57508015155b1561254a57670de0b6b3a76400006125338383615bb3565b61253d9190615bd2565b612547908b61561f565b99505b61255585600161561f565b985050505050808061256690615c20565b915050612497565b50505092959194509250565b612582615561565b6001600160a01b0383166000908152601e602090815260408083208584528252808320548352601f82529182902082516101808101845281548152600182015461ffff169281019290925260028082015493830193909352600381015465ffffffffffff8082166060850152600160301b909104166080830152600481015460a0830152600581015460c0830152600681015460e0830152600781015461010083015260088101546101208301526009810154610140830152600a8101549192909161016084019160ff909116908111156112935761129361567d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080612698836016612459565b509092506126aa91508290508361561f565b91506126b7836045612459565b509092506126c991508290508361561f565b91506126d7836101a4612459565b5090925061177091508290508361561f565b6033546001600160a01b0316336001600160a01b03161461271d576040516339e2f41f60e21b815260040160405180910390fd5b600160395460ff1660018111156127365761273661567d565b141561275557604051633ee45dcb60e21b815260040160405180910390fd5b6039805460ff19166001179055603354611556906001600160a01b03166714adf4b7320334b9601e1b6130c9565b6001600160a01b03166000908152602d602052604090205490565b6127a6612bbf565b6127ae612e0d565b611f1b826113c784846127c060065490565b600160046113c2600f5460ff1690565b6127d8613f7e565b6113d6816141be565b6001600160a01b03166000908152602a602052604090205490565b612804612e0d565b61280c612bbf565b6103e861281833610f6b565b61282390600161561f565b1115612842576040516334da899760e11b815260040160405180910390fd5b80156128515761285181613176565b60006040518060c001604052808581526020018481526020018381526020018561287a601c5490565b612884919061561f565b815260200161289260175490565b61289d90600161561f565b81526020016128af866118a560085490565b9052905060006128eb3383516020850151600954600a54600b546128d233611a87565b89606001518a608001518b60a001518c6040015161437f565b601a546128f8919061561f565b90506129168260800151836060015183601792909255601c55601a55565b61291f85614420565b50506115496001600555565b600080612939836016612459565b5091925061294b91508290508361561f565b9150612958836045612459565b5091925061296a91508290508361561f565b9150612978836101a4612459565b5091925061177091508290508361561f565b6001600160a01b0381166000908152601d6020526040902054606090806001600160401b038111156129be576129be615bf4565b6040519080825280602002602001820160405280156129f757816020015b6129e46155e1565b8152602001906001900390816129dc5790505b50915060015b818111612a9457604080516080810182528281526001600160a01b0386166000908152601e6020908152838220858352808252848320805483860152928690529052600101549181019190915260608101612a58868461257a565b905283612a66600184615b9c565b81518110612a7657612a76615c0a565b60200260200101819052508080612a8c90615c20565b9150506129fd565b5050919050565b6001600160a01b038316612afd5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401611470565b6001600160a01b038216612b5e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401611470565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600654600062015180612bf27f0000000000000000000000000000000000000000000000000000000065df437f42615b9c565b612bfc9190615bd2565b612c0790600161561f565b905081811115611f2557600854600954600a54600b546000612c298787615b9c565b905060005b81811015612de957612710612c4561271a88615bb3565b612c4f9190615bd2565b9550612710612c606126ed87615bb3565b612c6a9190615bd2565b9450612710612c7b6126ed86615bb3565b612c859190615bd2565b935068327cb2734119d3b7a9601f1b861115612cab5768327cb2734119d3b7a9601f1b95505b600c548810158015612cbe5750600d5415155b8015612cce5750611b58600e5414155b15612d20576032600d6000828254612ce69190615b9c565b925050819055506032600e6000828254612d00919061561f565b925050819055506007600c6000828254612d1a919061561f565b90915550505b6958f03ee118a13e800000851015612d40576958f03ee118a13e80000094505b612d4e6103e8612710615bb3565b841015612d6657612d636103e8612710615bb3565b93505b60458711612d8257612d7b6202361f84615b9c565b9250612d87565b600092505b85612d9189615c20565b604080518881526020810188905290810186905290995089907f1b4cf4ae62850d5107d63ca4895b7d62305df42148813646f7f4a76638a9618a9060600160405180910390a380612de181615c20565b915050612c2e565b5050600893909355600991909155600a55600b5560065550600f805460ff19169055565b60026005541415612e605760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611470565b6002600555565b6001600160a01b038616600090815260286020908152604080832088845290915281205480612ea95760405163de9d71e560e01b815260040160405180910390fd5b6000818152602960209081526040808320815160e0810183528154815260018201549381019390935260028082015461ffff81169385019390935265ffffffffffff62010000840481166060860152600160401b9093049092166080840152600381015460a08401526004810154909160c084019160ff1690811115612f3157612f3161567d565b6002811115612f4257612f4261567d565b905250905060018160c001516002811115612f5f57612f5f61567d565b1415612f7e5760405163081b599f60e41b815260040160405180910390fd5b60028160c001516002811115612f9657612f9661567d565b1415612fb55760405163c3fb2f4760e01b815260040160405180910390fd5b6004856004811115612fc957612fc961567d565b148015612fe15750806080015165ffffffffffff1642105b15612fff57604051639d2f92f560e01b815260040160405180910390fd5b60208101518151613016908b9083908b898c614508565b50600187600481111561302b5761302b61567d565b14156130655760256000815461304090615c20565b909155506000838152602960205260409020600401805460ff191660011790556130af565b60028760048111156130795761307961567d565b14156130af5760266000815461308e90615c20565b909155506000838152602960205260409020600401805460ff191660021790555b6130bb8a84848a6146b3565b9a9950505050505050505050565b6001600160a01b03821661311f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401611470565b8060026000828254613131919061561f565b90915550506001600160a01b03821660008181526020818152604080832080548601905551848152600080516020615cf0833981519152910160405180910390a35050565b73f19308f923582a6f7c465e5ce7a9dc1bec6665b16333f3fd783360315460405160e084901b6001600160e01b03191681526001600160a01b03928316600480830191909152602482018790526044820181905260648201529116608482015260a401600060405180830381600087803b1580156131f357600080fd5b505af115801561181f573d6000803e3d6000fd5b6001600160a01b0382166132675760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401611470565b6001600160a01b038216600090815260208190526040902054818110156132db5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401611470565b6001600160a01b038316600081815260208181526040808320868603905560028054879003905551858152919291600080516020615cf0833981519152910160405180910390a3505050565b6001600160a01b03881660009081526027602052604081208054829190829061334f90615c20565b918290555090506103e88111156133795760405163174a8f9960e21b815260040160405180910390fd5b601e881080613389575061033e88115b156133a75760405163d1b1ca9d60e01b815260040160405180910390fd5b60006133b48a8a8a613fa9565b905060016133ca670de0b6b3a764000083615bd2565b10156133e95760405163082aaa8760e41b815260040160405180910390fd5b84156134325760006133fc86868d614775565b90506107d081111561340d57506107d05b61271061341a8284615bb3565b6134249190615bd2565b61342e908361561f565b9150505b613440828c8c8c858a6147ba565b61344f8b828c8a8a6000614508565b9b9a5050505050505050505050565b8060011415611f255760166000526012602052600080516020615cd08339815191525415611f255760166000526012602052600080516020615cd0833981519152546134ab90600161561f565b6001600160a01b038316600090815260156020908152604080832060168452825282209290925560459052601290527f2438ba9a9fcd62a1364c4e295291b48be211763142dce8144a28ac91969f666f5461350790600161561f565b6001600160a01b03831660009081526015602090815260408083206045845282528220929092556101a49052601290527fb7ff304c5ab3d0f93c4868e4aee66ebe077d23da2da94c4b2280ba2f567bd0225461356490600161561f565b6001600160a01b03831660009081526015602090815260408083206101a4845290915290206001600160601b039190911690555050565b6000806000806000603654905080600014156135ca57604051630b0daf9d60e21b815260040160405180910390fd5b60006036819055604051829133917f97934fea6c25f21bceb486fba06c291987ec0bc4e293ea7b328285bdb07a180f9190a3620f424061360c610bb883615bb3565b6136169190615bd2565b94506136228582615b9c565b9050612710613630600d5490565b61363a9083615bb3565b6136449190615bd2565b9350612710613652600e5490565b61365c9083615bb3565b6136669190615bd2565b925061271061367660c883615bb3565b6136809190615bd2565b9150600082846136908785615b9c565b61369a9190615b9c565b6136a49190615b9c565b9050801561371f5760006127106136bd610dac84615bb3565b6136c79190615bd2565b905060006127106136da610bb885615bb3565b6136e49190615bd2565b90506136f1601683614971565b6136fc604582614971565b61371c6101a48261370d8587615b9c565b6137179190615b9c565b614971565b50505b60375480156137a0576000603781905561271061373e610dac84615bb3565b6137489190615bd2565b9050600061271061375b610bb885615bb3565b6137659190615bd2565b905061377260168361498f565b61377d60458261498f565b61379d6101a48261378e8587615b9c565b6137989190615b9c565b61498f565b50505b50505090919293565b6000838152601660205260408120548210156137c757506000611770565b6137d0846149ad565b600084815260106020908152604080832054601190925290912054811580156137f7575080155b1561380757600092505050611770565b61381386838388614a18565b506040518290879033907f973833b060ae272a085ff5b17b764e39ddac6a5612bdc9337f586dc7efee604990600090a450600195945050505050565b61385833611c6e565b60315461386e906001600160a01b031682614037565b603354613884906001600160a01b031684614037565b60345461218e906001600160a01b031683614037565b60006138a6848461265f565b9050600019811461218e57818110156139015760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401611470565b61218e8484848403612a9b565b6001600160a01b0383166139725760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401611470565b6001600160a01b0382166139d45760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401611470565b6001600160a01b03831660009081526020819052604090205481811015613a4c5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401611470565b6001600160a01b0384811660008181526020818152604080832087870390559387168083529184902080548701905592518581529092600080516020615cf0833981519152910160405180910390a361218e565b83613abe57604051630aa71b7760e41b815260040160405180910390fd5b83613ac886611e42565b1015613ae757604051631d78718160e01b815260040160405180910390fd5b613af285338661389a565b613afc8383614ae1565b613b068585613207565b61181f85858585856000614c01565b6001600160a01b0383166000908152601e602090815260408083208584529091528120805460019091015481613b5e57604051637a2e11eb60e01b815260040160405180910390fd5b6000828152601f6020908152604080832081516101808101835281548152600182015461ffff169381019390935260028082015492840192909252600381015465ffffffffffff8082166060860152600160301b909104166080840152600481015460a0840152600581015460c0840152600681015460e0840152600781015461010084015260088101546101208401526009810154610140840152600a810154909161016084019160ff1690811115613c1a57613c1a61567d565b6002811115613c2b57613c2b61567d565b905250905060018161016001516002811115613c4957613c4961567d565b1415613c68576040516339f4887960e21b815260040160405180910390fd5b60028161016001516002811115613c8157613c8161567d565b1415613ca0576040516323acf12560e01b815260040160405180910390fd5b42816080015165ffffffffffff16118015613ccc57506000856001811115613cca57613cca61567d565b145b15613cea57604051636971be5760e11b815260040160405180910390fd5b8060400151601a6000828254613d009190615b9c565b90915550611e1f90508784848489614cff565b6001600160a01b0384166000908152602d602052604081208054849290613d3b90849061561f565b9250508190555081602c6000828254613d54919061561f565b90915550506001600160a01b03831615613dd2576001600160a01b0383166000908152602e602052604081208054849290613d9090849061561f565b90915550506001600160a01b038084166000908152602f6020908152604080832093881683529290529081208054849290613dcc90849061561f565b90915550505b826001600160a01b0316846001600160a01b03167fdf82885dedaf240ee119dba88f242ab92b4bff124f1c029d077cad9a57fb97c68484604051613e17929190615c3b565b60405180910390a350505050565b6000620186a0611ae58484615bb3565b60008082613e4585612710615bb3565b6118df9190615bd2565b60008086613e5d8988615bb3565b613e679190615bb3565b905086600114613eab57612710613e7f600189615b9c565b613e8a600b84615bb3565b613e949190615bb3565b613e9e9190615bd2565b613ea89082615b9c565b90505b9050808415613ee557620f42406064613ec48784615bb3565b613ece9190615bd2565b613ed89190615bd2565b613ee2908361561f565b91505b8315613f2157670de0b6b3a76400006064613f008684615bb3565b613f0a9190615bd2565b613f149190615bd2565b613f1e908361561f565b91505b8215613f65576103e88311613f365782613f3a565b6103e85b92506000612710613f4b8585615bb3565b613f559190615bd2565b9050613f61818461561f565b9250505b613f72620186a083615bd2565b98975050505050505050565b6030546001600160a01b0316331461155657604051635e8a044f60e01b815260040160405180910390fd5b60008364174876e800613fbb8561426d565b613fc59083615bb3565b613fcf9190615bd2565b613fd9908261561f565b9050613fed670de0b6b3a764000084615bd2565b613ff79082615bd2565b95945050505050565b600080808080806140113388612459565b935093509350935061402b6140233390565b888484614f29565b50919590945092505050565b6001600160a01b03821661405e576040516329d6af1160e01b815260040160405180910390fd5b60355460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906140909085908590600401615c58565b6020604051808303816000875af11580156140af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115499190615c71565b6001600160a01b0382166140fa576040516329d6af1160e01b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614147576040519150601f19603f3d011682016040523d82523d6000602084013e61414c565b606091505b505090508061154957604051633ad7296360e11b815260040160405180910390fd5b600082821161417f575060006118df565b620186a0670de0b6b3a76400006141968585615b9c565b6141a08789615bb3565b6141aa9190615bb3565b6141b49190615bb3565b613ff79190615bd2565b603080546001600160a01b0319166001600160a01b0392909216919091179055565b6141e985614fd6565b6141f38383614ae1565b61181f856142058787611b1360065490565b8585856002614c01565b6142188261505b565b614223600080614ae1565b600061423183836001613b15565b60315490915061425d906001600160a01b031661271061425384610320615bb3565b6113c79190615bd2565b6115498382600080336001614c01565b6000601e82116142815750620f4240919050565b600061428e601e84615b9c565b9050600061429f601e61033e615b9c565b8211156142b8576142b3601e61033e615b9c565b6142ba565b815b9050610190613e4564174876e80083615bb3565b6142d833826130c9565b6032546113d6906001600160a01b0316612710614253846064615bb3565b600080845b848111614374576001600160a01b0387166000908152602b60209081526040808320848452909152902054841061435a576001600160a01b0387166000908152602b60209081526040808320848452909152902060010154925061435f565b614374565b9450848061436c81615c20565b9150506142fb565b509095939450505050565b600089158061438e575060fa8a115b156143ac576040516332c13ef760e01b815260040160405180910390fd5b8a15806143bb5750620186a08b115b156143d9576040516304c7176560e31b815260040160405180910390fd5b600082156143ee576143eb8385613e35565b90505b6143fc8c8c8c8b8b86613e4f565b91506144108d8d8d858d8d8b8d8c8c6150af565b509b9a5050505050505050505050565b600061442f826118a560085490565b6035549091506001600160a01b03166323b872dd336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018490526064016020604051808303816000875af1158015614497573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144bb9190615c71565b5080603660008282546144ce919061561f565b909155505060065460405182919033907fd833e83f161e4ddfb1306cdf11a374a0a23393f008f9394b85999b988c232e3690600090a45050565b6001600160a01b0386166000908152602a6020908152604080832054602b83528184208185529092528220600101548284600481111561454a5761454a61567d565b14156145d4578161455a57600192505b614564888261561f565b6001600160a01b038a166000908152602b602052604081209061458685615c20565b94508481526020019081526020016000206001018190555087602160008282546145b0919061561f565b9250508190555086602360008282546145c9919061561f565b909155506146499050565b6145de8882615b9c565b6001600160a01b038a166000908152602b602052604081209061460085615c20565b945084815260200190815260200160002060010181905550876022600082825461462a919061561f565b9250508190555086602360008282546146439190615b9c565b90915550505b600085600181111561465d5761465d61567d565b146146725761466d86600161561f565b614674565b855b6001600160a01b039099166000818152602b6020908152604080832086845282528083209c909c55918152602a90915298909820559695505050505050565b6000808360000151905060006146e3856060015165ffffffffffff16866080015165ffffffffffff1642876152d6565b9050600060646146f38385615bb3565b6146fd9190615bd2565b90506147098184615b9c565b9350806024600082825461471d919061561f565b90915550506040805185815260208101839052839189916001600160a01b038c16917f971d9ff3287b3ba75194105e7281e55c93b0a89cad9915664bb3fd9211f8d5f1910160405180910390a4505050949350505050565b600080670de0b6b3a764000061478b8585615bb3565b6147959190615bd2565b90506000816147a661271088615bb3565b6147b09190615bd2565b9695505050505050565b60006020600081546147cb90615c20565b9182905550905060006147e16201518086615bb3565b6147eb904261561f565b905060006040518060e001604052808881526020018681526020018761ffff1681526020014265ffffffffffff1681526020018365ffffffffffff168152602001858152602001600060028111156148455761484561567d565b90526001600160a01b03891660009081526028602090815260408083208d845282528083208790558683526029825291829020835181559083015160018083019190915591830151600280830180546060870151608088015161ffff9095166001600160401b0319909216919091176201000065ffffffffffff928316021765ffffffffffff60401b1916600160401b91909416029290921790915560a0840151600383015560c0840151600483018054959650869593949193909260ff199091169190849081111561491a5761491a61567d565b021790555090505082886001600160a01b03167f04e1761ddc1451be2b9abb20d50c7e317778879612685874154566bbb4acafc7888460405161495e929190615c8e565b60405180910390a3505050505050505050565b60008281526010602052604081208054839290611a2d90849061561f565b60008281526011602052604081208054839290611a2d90849061561f565b60008181526016602052604090205460065481811061154957826149d18383615b9c565b6149db9190615bd2565b6149e690600161561f565b6149f09084615bb3565b60008481526016602052604081208054909190614a0e90849061561f565b9091555050505050565b6000848152601060209081526040808320839055601182528083208390556012909152812080548290614a4a90615c20565b9182905550905081614a64670de0b6b3a764000086615bb3565b614a6e9190615bd2565b600086815260136020908152604080832085845290915290206001810191909155600654905581614aa7670de0b6b3a764000085615bb3565b614ab19190615bd2565b60009586526014602090815260408088208489529091529095206001810195909555600654909455509192915050565b6008614aed838361561f565b1115614b0c57604051632902579f60e01b815260040160405180910390fd5b6040516301ffc9a760e01b80825233916301ffc9a791614b2e91600401615ca3565b602060405180830381865afa158015614b4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b6f9190615c71565b1580614be357506040516301ffc9a760e01b815233906301ffc9a790614ba0906311686e4b60e21b90600401615ca3565b602060405180830381865afa158015614bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614be19190615c71565b155b15611f255760405163d03681f360e01b815260040160405180910390fd5b614c0d86338784613d13565b6000808415614c4757614c236127106064615bb3565b612710614c30878a615bb3565b614c3a9190615bb3565b614c449190615bd2565b91505b8515614c7e57614c5a6127106064615bb3565b612710614c67888a615bb3565b614c719190615bb3565b614c7b9190615bd2565b90505b8115614c8e57614c8e84836130c9565b8015614c9e57614c9e88826130c9565b6040516311686e4b60e21b815233906345a1b92c90614cc3908b908b90600401615c58565b600060405180830381600087803b158015614cdd57600080fd5b505af1158015614cf1573d6000803e3d6000fd5b505050505050505050505050565b600080826001811115614d1457614d1461567d565b1415614d37576000858152601f60205260409020600a01805460ff191660011790555b6001826001811115614d4b57614d4b61567d565b1415614d6e576000858152601f60205260409020600a01805460ff191660021790555b6000806000856080015165ffffffffffff16421115614daa57614da7866080015165ffffffffffff1642614da29190615b9c565b6153be565b91505b6000856001811115614dbe57614dbe61567d565b1415614ddd57614dda8660a00151876000015189601c5461416e565b90505b614dea6298968082615bd2565b8660400151614df9919061561f565b93506064614e078386615bb3565b614e119190615bd2565b9250614e1d8385615b9c565b93506000856001811115614e3357614e3361567d565b1415614e4d57601860008154614e4890615c20565b909155505b6001856001811115614e6157614e6161567d565b1415614e7b57601960008154614e7690615c20565b909155505b8215614e995782601b6000828254614e93919061561f565b90915550505b6000856001811115614ead57614ead61567d565b1415614ecf576000888152601f60205260409020600681018590556008018390555b81888a6001600160a01b03167fbd866a3fbf35e201f790e87581b1afbb3165e879df5d35313a4875a70b9f3b368787604051614f15929190918252602082015260400190565b60405180910390a450505095945050505050565b6001600160a01b03841660009081526015602090815260408083208684529091529020548214614f7a576001600160a01b038416600090815260156020908152604080832086845290915290208290555b6001600160a01b0384166000908152601560209081526040808320868452909152902060010154811461218e576001600160a01b0384166000908152601560209081526040808320868452909152902060010181905550505050565b6000614fe28233610a8d565b90506000198114611f25578061500b57604051632048203360e01b815260040160405180910390fd5b6001600160a01b0382166000908152603c6020526040812090335b6001600160a01b03166001600160a01b031681526020019081526020016000206000815461505390615cb8565b909155505050565b600061506782336109c8565b90506000198114611f25578061509057604051632048203360e01b815260040160405180910390fd5b6001600160a01b0382166000908152603a602052604081209033615026565b60006040518061018001604052808b81526020018a61ffff1681526020018981526020014265ffffffffffff168152602001620151808b6150f09190615bb3565b6150fa904261561f565b65ffffffffffff1681526020018881526020018781526020016000815260200184815260200160008152602001838152602001600060028111156151405761514061567d565b90526001600160a01b038c166000908152601d6020526040812080549293509091829061516c90615c20565b91829055506001600160a01b038d166000908152601e6020908152604080832084845282528083208a815560019081018a90558a8452601f8352928190208651815591860151828401805461ffff90921661ffff199092169190911790558501516002808301919091556060860151600383018054608089015165ffffffffffff908116600160301b026001600160601b031990921693169290921791909117905560a0860151600483015560c0860151600583015560e08601516006830155610100860151600783015561012086015160088301556101408601516009830155610160860151600a83018054959650879593949193909260ff199091169190849081111561527d5761527d61567d565b021790555090505084868d6001600160a01b03167f2b2d6cbbd64131cfb538b30ae4a9dc516d6fe02b65e223719e216846f0118a95856040516152c09190615adb565b60405180910390a4505050505050505050505050565b60008383106153515760006152eb8585615b9c565b905060006152fd620151806007615bb3565b9050808211615311576000925050506118df565b6153486201518061532c6153258486615b9c565b60016154d4565b6153369190615bd2565b61534190600161561f565b60636154eb565b925050506118df565b60028260048111156153655761536561567d565b1415615373575060006118df565b600261537f8686615b9c565b6153899190615bd2565b615393908661561f565b4210156153b3576040516354d335b760e11b815260040160405180910390fd5b506032949350505050565b60006153ce620151806007615bb3565b82116153dc57506000919050565b620151806153ec6007600161561f565b6153f69190615bb3565b821161540457506001919050565b620151806154146007600261561f565b61541e9190615bb3565b821161542c57506003919050565b6201518061543c6007600361561f565b6154469190615bb3565b821161545457506008919050565b620151806154646007600461561f565b61546e9190615bb3565b821161547c57506011919050565b6201518061548c6007600561561f565b6154969190615bb3565b82116154a457506023919050565b620151806154b46007600661561f565b6154be9190615bb3565b82116154cc57506048919050565b506063919050565b6000818311156154e55750816112aa565b50919050565b6000818311156154fc5750806112aa565b5090919050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a081018290529060c08201905b905290565b6040518060600160405280600081526020016000815260200161553b615503565b60405180610180016040528060008152602001600061ffff16815260200160008152602001600065ffffffffffff168152602001600065ffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000600281111561553b5761553b61567d565b604051806080016040528060008152602001600081526020016000815260200161553b615561565b634e487b7160e01b600052601160045260246000fd5b6000821982111561563257615632615609565b500190565b80356001600160a01b038116811461564e57600080fd5b919050565b6000806040838503121561566657600080fd5b61566f83615637565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b600381106113d6576113d661567d565b805182526020810151602083015261ffff6040820151166040830152606081015165ffffffffffff8082166060850152806080840151166080850152505060a081015160a083015260c08101516156f981615693565b8060c0840152505050565b60e081016112aa82846156a3565b60006020828403121561572457600080fd5b81356001600160e01b03198116811461177057600080fd5b600060208083528351808285015260005b818110156157695785810183015185820160400152820161574d565b8181111561577b576000604083870101525b50601f01601f1916929092016040019392505050565b6000602082840312156157a357600080fd5b5035919050565b6000806000606084860312156157bf57600080fd5b505081359360208301359350604090920135919050565b600080604083850312156157e957600080fd5b6157f283615637565b915061580060208401615637565b90509250929050565b60008060006060848603121561581e57600080fd5b61582784615637565b925061583560208501615637565b9150604084013590509250925092565b60006020828403121561585757600080fd5b61177082615637565b600080600080600060a0868803121561587857600080fd5b61588186615637565b94506020860135935060408601359250606086013591506158a460808701615637565b90509295509295909350565b600080604083850312156158c357600080fd5b50508035926020909101359150565b600080600080608085870312156158e857600080fd5b84359350602085013592506040850135915061590660608601615637565b905092959194509250565b6001600160a01b0391909116815260200190565b602080825282518282018190526000919060409081850190868401855b8281101561597c578151805185528681015187860152850151615967868601826156a3565b50610120939093019290850190600101615942565b5091979650505050505050565b602081016002831061599d5761599d61567d565b91905290565b600080600080608085870312156159b957600080fd5b6159c285615637565b966020860135965060408601359560600135945092505050565b80151581146113d657600080fd5b600080604083850312156159fd57600080fd5b615a0683615637565b91506020830135615a16816159dc565b809150509250929050565b615a2a81615693565b9052565b805182526020810151615a47602084018261ffff169052565b50604081015160408301526060810151615a6b606084018265ffffffffffff169052565b506080810151615a85608084018265ffffffffffff169052565b5060a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152506101208082015181840152506101408082015181840152506101608082015161218e82850182615a21565b61018081016112aa8284615a2e565b602080825282518282018190526000919060409081850190868401855b8281101561597c578151805185528681015187860152858101518686015260609081015190615b3881870183615a2e565b50506101e0939093019290850190600101615b07565b600181811c90821680615b6257607f821691505b602082108114156154e557634e487b7160e01b600052602260045260246000fd5b600060208284031215615b9557600080fd5b5051919050565b600082821015615bae57615bae615609565b500390565b6000816000190483118215151615615bcd57615bcd615609565b500290565b600082615bef57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000600019821415615c3457615c34615609565b5060010190565b82815260408101615c4b83615693565b8260208301529392505050565b6001600160a01b03929092168252602082015260400190565b600060208284031215615c8357600080fd5b8151611770816159dc565b828152610100810161177060208301846156a3565b6001600160e01b031991909116815260200190565b600081615cc757615cc7615609565b50600019019056fec4f8f7f5ee45326dd80cc2262cf4948c0aa62c4ed9b775cbe9662ca3618994d3ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220e147f8db36d790d87b37772e1baf6c0932f5345d8bcbb31daca1afd7a334e2c864736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006c3c3a22ab3725c017d41d31b23efaf51a8ece480000000000000000000000009bff9f810d19cdb4bf7701c9d5ad101e91cda08d000000000000000000000000f19308f923582a6f7c465e5ce7a9dc1bec6665b1000000000000000000000000a2d21205aa7273baddfc8e9551e05e23bb49ce4600000000000000000000000015e5b9b9adf208cc7ca3ae1e6a49506eb5f397dd
-----Decoded View---------------
Arg [0] : genesisAddress (address): 0x6c3C3A22ab3725C017d41d31B23EfaF51A8ecE48
Arg [1] : buyAndBurnAddress (address): 0x9Bff9F810D19cDb4BF7701C9d5aD101E91CdA08d
Arg [2] : titanxAddress (address): 0xF19308F923582A6f7c465e5CE7a9Dc1BEC6665B1
Arg [3] : treasuryAddress (address): 0xA2d21205Aa7273BadDFC8E9551e05E23bB49ce46
Arg [4] : investmentAddress (address): 0x15E5B9B9Adf208cC7CA3aE1e6a49506eB5f397Dd
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000006c3c3a22ab3725c017d41d31b23efaf51a8ece48
Arg [1] : 0000000000000000000000009bff9f810d19cdb4bf7701c9d5ad101e91cda08d
Arg [2] : 000000000000000000000000f19308f923582a6f7c465e5ce7a9dc1bec6665b1
Arg [3] : 000000000000000000000000a2d21205aa7273baddfc8e9551e05e23bb49ce46
Arg [4] : 00000000000000000000000015e5b9b9adf208cc7ca3ae1e6a49506eb5f397dd
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.