ERC-20
Overview
Max Total Supply
111,855,230,455,261.238536691501355172 TITANX
Holders
19,761
Market
Price
$0.00 @ 0.000000 ETH (+2.99%)
Onchain Market Cap
$65,452,423.67
Circulating Supply Market Cap
$0.00
Other Info
Token Contract (WITH 18 Decimals)
Balance
709,087.476873851850531105 TITANXValue
$0.41 ( ~0.000124954920483341 Eth) [0.0000%]Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
TITANX
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 20 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "./openzeppelin/security/ReentrancyGuard.sol"; import "./openzeppelin/token/ERC20/ERC20.sol"; import "./openzeppelin/interfaces/IERC165.sol"; import "../interfaces/ITitanOnBurn.sol"; import "../interfaces/ITITANX.sol"; import "../libs/calcFunctions.sol"; import "./GlobalInfo.sol"; import "./MintInfo.sol"; import "./StakeInfo.sol"; import "./BurnInfo.sol"; import "./OwnerInfo.sol"; //custom errors error TitanX_InvalidAmount(); error TitanX_InsufficientBalance(); error TitanX_NotSupportedContract(); error TitanX_InsufficientProtocolFees(); error TitanX_FailedToSendAmount(); error TitanX_NotAllowed(); error TitanX_NoCycleRewardToClaim(); error TitanX_NoSharesExist(); error TitanX_EmptyUndistributeFees(); error TitanX_InvalidBurnRewardPercent(); error TitanX_InvalidBatchCount(); error TitanX_InvalidMintLadderInterval(); error TitanX_InvalidMintLadderRange(); error TitanX_MaxedWalletMints(); error TitanX_LPTokensHasMinted(); error TitanX_InvalidAddress(); error TitanX_InsufficientBurnAllowance(); /** @title Titan X */ contract TITANX is ERC20, ReentrancyGuard, GlobalInfo, MintInfo, StakeInfo, BurnInfo, OwnerInfo { /** Storage Variables*/ /** @dev stores genesis wallet address */ address private s_genesisAddress; /** @dev stores buy and burn contract address */ address private s_buyAndBurnAddress; /** @dev tracks collected protocol fees until it is distributed */ uint88 private s_undistributedEth; /** @dev tracks burn reward from distributeETH() 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 user + project burn stakes allowance */ mapping(address => mapping(address => uint256)) private s_allowanceBurnStakes; event ProtocolFeeRecevied(address indexed user, uint256 indexed day, uint256 indexed amount); event ETHDistributed(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); 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) ERC20("TITAN X", "TITANX") { if (genesisAddress == address(0)) revert TitanX_InvalidAddress(); if (buyAndBurnAddress == address(0)) revert TitanX_InvalidAddress(); s_genesisAddress = genesisAddress; s_buyAndBurnAddress = buyAndBurnAddress; } /**** Mint Functions *****/ /** @notice create a new mint * @param mintPower 1 - 100 * @param numOfDays mint length of 1 - 280 */ function startMint( uint256 mintPower, uint256 numOfDays ) external payable nonReentrant dailyUpdate { if (getUserLatestMintId(_msgSender()) + 1 > MAX_MINT_PER_WALLET) revert TitanX_MaxedWalletMints(); uint256 gMintPower = getGlobalMintPower() + mintPower; uint256 currentTRank = getGlobalTRank() + 1; uint256 gMinting = getTotalMinting() + _startMint( _msgSender(), mintPower, numOfDays, getCurrentMintableTitan(), getCurrentMintPowerBonus(), getCurrentEAABonus(), getUserBurnAmplifierBonus(_msgSender()), gMintPower, currentTRank, getBatchMintCost(mintPower, 1, getCurrentMintCost()) ); _updateMintStats(currentTRank, gMintPower, gMinting); _protocolFees(mintPower, 1); } /** @notice create new mints in batch of up to 100 mints * @param mintPower 1 - 100 * @param numOfDays mint length of 1 - 280 * @param count 1 - 100 */ function batchMint( uint256 mintPower, uint256 numOfDays, uint256 count ) external payable nonReentrant dailyUpdate { if (count == 0 || count > MAX_BATCH_MINT_COUNT) revert TitanX_InvalidBatchCount(); if (getUserLatestMintId(_msgSender()) + count > MAX_MINT_PER_WALLET) revert TitanX_MaxedWalletMints(); _startBatchMint( _msgSender(), mintPower, numOfDays, getCurrentMintableTitan(), getCurrentMintPowerBonus(), getCurrentEAABonus(), getUserBurnAmplifierBonus(_msgSender()), count, getBatchMintCost(mintPower, 1, getCurrentMintCost()) //only need 1 mint cost for all mints ); _protocolFees(mintPower, count); } /** @notice create new mints in ladder up to 100 mints * @param mintPower 1 - 100 * @param minDay minimum mint length * @param maxDay maximum mint lenght * @param dayInterval day increase from previous mint length * @param countPerInterval how many mints per mint length */ function batchMintLadder( uint256 mintPower, uint256 minDay, uint256 maxDay, uint256 dayInterval, uint256 countPerInterval ) external payable nonReentrant dailyUpdate { if (dayInterval == 0) revert TitanX_InvalidMintLadderInterval(); if (maxDay < minDay || minDay == 0 || maxDay > MAX_MINT_LENGTH) revert TitanX_InvalidMintLadderRange(); uint256 count = getBatchMintLadderCount(minDay, maxDay, dayInterval, countPerInterval); if (count == 0 || count > MAX_BATCH_MINT_COUNT) revert TitanX_InvalidBatchCount(); if (getUserLatestMintId(_msgSender()) + count > MAX_MINT_PER_WALLET) revert TitanX_MaxedWalletMints(); uint256 mintCost = getBatchMintCost(mintPower, 1, getCurrentMintCost()); //only need 1 mint cost for all mints _startbatchMintLadder( _msgSender(), mintPower, minDay, maxDay, dayInterval, countPerInterval, getCurrentMintableTitan(), getCurrentMintPowerBonus(), getCurrentEAABonus(), getUserBurnAmplifierBonus(_msgSender()), mintCost ); _protocolFees(mintPower, count); } /** @notice claim a matured mint * @param id mint id */ function claimMint(uint256 id) external dailyUpdate nonReentrant { _mintReward(_claimMint(_msgSender(), id, MintAction.CLAIM)); } /** @notice batch claim matured mint of up to 100 claims per run */ function batchClaimMint() external dailyUpdate nonReentrant { _mintReward(_batchClaimMint(_msgSender())); } /**** Stake Functions *****/ /** @notice start a new stake * @param amount titan amount * @param numOfDays stake length */ function startStake(uint256 amount, uint256 numOfDays) external dailyUpdate nonReentrant { if (balanceOf(_msgSender()) < amount) revert TitanX_InsufficientBalance(); _burn(_msgSender(), amount); _initFirstSharesCycleIndex( _msgSender(), _startStake( _msgSender(), amount, numOfDays, getCurrentShareRate(), getCurrentContractDay(), getGlobalPayoutTriggered() ) ); } /** @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 distributeETH() external dailyUpdate nonReentrant { (uint256 incentiveFee, uint256 buyAndBurnFunds, uint256 genesisWallet) = _distributeETH(); _sendFunds(incentiveFee, buyAndBurnFunds, genesisWallet); } /** @notice trigger cylce payouts for day 8, 28, 90, 369, 888 including the burn reward cycle 28 * As long as the cycle has met its maturiy day (eg. Cycle8 is day 8), payout can be triggered in any day onwards */ function triggerPayouts() external dailyUpdate nonReentrant { uint256 globalActiveShares = getGlobalShares() - getGlobalExpiredShares(); if (globalActiveShares < 1) revert TitanX_NoSharesExist(); uint256 incentiveFee; uint256 buyAndBurnFunds; uint256 genesisWallet; if (s_undistributedEth != 0) (incentiveFee, buyAndBurnFunds, genesisWallet) = _distributeETH(); uint256 currentContractDay = getCurrentContractDay(); PayoutTriggered isTriggered = PayoutTriggered.NO; _triggerCyclePayout(DAY8, globalActiveShares, currentContractDay) == PayoutTriggered.YES && isTriggered == PayoutTriggered.NO ? isTriggered = PayoutTriggered.YES : isTriggered; _triggerCyclePayout(DAY28, globalActiveShares, currentContractDay) == PayoutTriggered.YES && isTriggered == PayoutTriggered.NO ? isTriggered = PayoutTriggered.YES : isTriggered; _triggerCyclePayout(DAY90, globalActiveShares, currentContractDay) == PayoutTriggered.YES && isTriggered == PayoutTriggered.NO ? isTriggered = PayoutTriggered.YES : isTriggered; _triggerCyclePayout(DAY369, globalActiveShares, currentContractDay) == PayoutTriggered.YES && isTriggered == PayoutTriggered.NO ? isTriggered = PayoutTriggered.YES : isTriggered; _triggerCyclePayout(DAY888, 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, genesisWallet); } /** @notice claim all user available ETH payouts in one call */ function claimUserAvailableETHPayouts() external dailyUpdate nonReentrant { uint256 reward = _claimCyclePayout(DAY8, PayoutClaim.SHARES); reward += _claimCyclePayout(DAY28, PayoutClaim.SHARES); reward += _claimCyclePayout(DAY90, PayoutClaim.SHARES); reward += _claimCyclePayout(DAY369, PayoutClaim.SHARES); reward += _claimCyclePayout(DAY888, PayoutClaim.SHARES); if (reward == 0) revert TitanX_NoCycleRewardToClaim(); _sendViaCall(payable(_msgSender()), reward); emit RewardClaimed(_msgSender(), reward); } /** @notice claim all user available burn rewards in one call */ function claimUserAvailableETHBurnPool() external dailyUpdate nonReentrant { uint256 reward = _claimCyclePayout(DAY28, PayoutClaim.BURN); if (reward == 0) revert TitanX_NoCycleRewardToClaim(); _sendViaCall(payable(_msgSender()), reward); emit RewardClaimed(_msgSender(), reward); } /** @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 TitanX_InvalidAddress(); s_buyAndBurnAddress = contractAddress; } /** @notice enable burn pool to start accumulate reward. Only owner can call this function. */ function enableBurnPoolReward() external onlyOwner { s_burnPoolEnabled = BurnPoolEnabled.TRUE; } /** @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 TitanX_NotAllowed(); if (newAddress == address(0)) revert TitanX_InvalidAddress(); s_genesisAddress = 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 TitanX_NotAllowed(); if (s_initialLPMinted == InitialLPMinted.YES) revert TitanX_LPTokensHasMinted(); s_initialLPMinted = InitialLPMinted.YES; _mint(s_buyAndBurnAddress, INITAL_LP_TOKENS); } /** @notice burn all BuyAndBurn contract Titan */ function burnLPTokens() external dailyUpdate { _burn(s_buyAndBurnAddress, balanceOf(s_buyAndBurnAddress)); } //private functions /** @dev mint reward to user and 1% to genesis wallet * @param reward titan amount */ function _mintReward(uint256 reward) private { _mint(_msgSender(), reward); _mint(s_genesisAddress, (reward * 800) / PERCENT_BPS); } /** @dev send ETH to respective parties * @param incentiveFee fees for caller to run distributeETH() * @param buyAndBurnFunds funds for buy and burn * @param genesisWalletFunds funds for genesis wallet */ function _sendFunds( uint256 incentiveFee, uint256 buyAndBurnFunds, uint256 genesisWalletFunds ) private { _sendViaCall(payable(_msgSender()), incentiveFee); _sendViaCall(payable(s_genesisAddress), genesisWalletFunds); _sendViaCall(payable(s_buyAndBurnAddress), buyAndBurnFunds); } /** @dev calculation to distribute collected protocol fees into different pools/parties */ function _distributeETH() private returns (uint256 incentiveFee, uint256 buyAndBurnFunds, uint256 genesisWallet) { uint256 accumulatedFees = s_undistributedEth; if (accumulatedFees == 0) revert TitanX_EmptyUndistributeFees(); s_undistributedEth = 0; emit ETHDistributed(_msgSender(), accumulatedFees); incentiveFee = (accumulatedFees * INCENTIVE_FEE_PERCENT) / INCENTIVE_FEE_PERCENT_BASE; //0.01% accumulatedFees -= incentiveFee; buyAndBurnFunds = (accumulatedFees * PERCENT_TO_BUY_AND_BURN) / PERCENT_BPS; uint256 cylceBurnReward = (accumulatedFees * PERCENT_TO_BURN_PAYOUTS) / PERCENT_BPS; genesisWallet = (accumulatedFees * PERCENT_TO_GENESIS) / PERCENT_BPS; uint256 cycleRewardPool = accumulatedFees - buyAndBurnFunds - cylceBurnReward - genesisWallet; if (s_burnPoolEnabled == BurnPoolEnabled.TRUE) s_cycleBurnReward += uint88(cylceBurnReward); else buyAndBurnFunds += cylceBurnReward; //cycle payout if (cycleRewardPool != 0) { uint256 cycle8Reward = (cycleRewardPool * CYCLE_8_PERCENT) / PERCENT_BPS; uint256 cycle28Reward = (cycleRewardPool * CYCLE_28_PERCENT) / PERCENT_BPS; uint256 cycle90Reward = (cycleRewardPool * CYCLE_90_PERCENT) / PERCENT_BPS; uint256 cycle369Reward = (cycleRewardPool * CYCLE_369_PERCENT) / PERCENT_BPS; _setCyclePayoutPool(DAY8, cycle8Reward); _setCyclePayoutPool(DAY28, cycle28Reward); _setCyclePayoutPool(DAY90, cycle90Reward); _setCyclePayoutPool(DAY369, cycle369Reward); _setCyclePayoutPool( DAY888, cycleRewardPool - cycle8Reward - cycle28Reward - cycle90Reward - cycle369Reward ); } } /** @dev calcualte required protocol fees, and return the balance (if any) * @param mintPower mint power 1-100 * @param count how many mints */ function _protocolFees(uint256 mintPower, uint256 count) private { uint256 protocolFee; protocolFee = getBatchMintCost(mintPower, count, getCurrentMintCost()); if (msg.value < protocolFee) revert TitanX_InsufficientProtocolFees(); uint256 feeBalance; s_undistributedEth += uint88(protocolFee); feeBalance = msg.value - protocolFee; if (feeBalance != 0) { _sendViaCall(payable(_msgSender()), feeBalance); } emit ProtocolFeeRecevied(_msgSender(), getCurrentContractDay(), protocolFee); } /** @dev calculate payouts for each cycle day tracked by cycle index * @param cycleNo cylce day 8, 28, 90, 369, 888 * @param globalActiveShares global active shares * @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); if (reward == 0) return PayoutTriggered.NO; //calculate cycle reward per share and get new cycle Index uint256 cycleIndex = _calculateCycleRewardPerShare(cycleNo, reward, globalActiveShares); //calculate burn reward if cycle is 28 uint256 totalCycleBurn = getCycleBurnTotal(cycleIndex); uint256 burnReward; if (cycleNo == DAY28 && totalCycleBurn != 0) { burnReward = s_cycleBurnReward; if (burnReward != 0) { s_cycleBurnReward = 0; _calculateCycleBurnRewardPerToken(cycleIndex, burnReward, totalCycleBurn); } } emit CyclePayoutTriggered(_msgSender(), cycleNo, reward, burnReward); return PayoutTriggered.YES; } /** @dev calculate user reward with specified cycle day and claim type (shares/burn) and update user's last claim cycle index * @param cycleNo cycle day 8, 28, 90, 369, 888 * @param payoutClaim claim type - (Shares=0/Burn=1) */ function _claimCyclePayout(uint256 cycleNo, PayoutClaim payoutClaim) private returns (uint256) { ( uint256 reward, uint256 userClaimCycleIndex, uint256 userClaimSharesIndex, uint256 userClaimBurnCycleIndex ) = _calculateUserCycleReward(_msgSender(), cycleNo, payoutClaim); if (payoutClaim == PayoutClaim.SHARES) _updateUserClaimIndexes( _msgSender(), cycleNo, userClaimCycleIndex, userClaimSharesIndex ); if (payoutClaim == PayoutClaim.BURN) { _updateUserBurnCycleClaimIndex(_msgSender(), cycleNo, userClaimBurnCycleIndex); } return reward; } /** @dev burn liquid Titan 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 titan amount * @param userRebatePercentage percentage for user rebate in liquid titan (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid titan (0 - 8) * @param rewardPaybackAddress builder can opt to receive fee in another address */ function _burnLiquidTitan( address user, uint256 amount, uint256 userRebatePercentage, uint256 rewardPaybackPercentage, address rewardPaybackAddress ) private { if (amount == 0) revert TitanX_InvalidAmount(); if (balanceOf(user) < amount) revert TitanX_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 titan (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid titan (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 TitanX_InvalidBurnRewardPercent(); //Only supported contracts is allowed to call this function if ( !IERC165(_msgSender()).supportsInterface(IERC165.supportsInterface.selector) || !IERC165(_msgSender()).supportsInterface(type(ITitanOnBurn).interfaceId) ) revert TitanX_NotSupportedContract(); } /** @dev update burn stats and mint reward to builder or user if applicable * @param user user address * @param amount titan amount burned * @param userRebatePercentage percentage for user rebate in liquid titan (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid titan (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 { uint256 index = getCurrentCycleIndex(DAY28) + 1; /** set to the latest cylceIndex + 1 for fresh wallet * same concept as _initFirstSharesCycleIndex, refer to its dev comment */ if (getUserBurnTotal(user) == 0) _updateUserBurnCycleClaimIndex(user, DAY28, index); _updateBurnAmount(user, _msgSender(), amount, index, 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); ITitanOnBurn(_msgSender()).onBurn(user, 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 TitanX_InvalidAddress(); (bool sent, ) = to.call{value: amount}(""); if (!sent) revert TitanX_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 TitanX_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 TitanX_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 8, 28, 90, 369, 888 * @param payoutClaim claim type (Shares=0/Burn=1) * @return rewards calculated reward * @return userClaimCycleIndex last claim cycle index * @return userClaimSharesIndex last claim shares index * @return userClaimBurnCycleIndex last claim burn cycle index */ function _calculateUserCycleReward( address user, uint256 cycleNo, PayoutClaim payoutClaim ) private view returns ( uint256 rewards, uint256 userClaimCycleIndex, uint256 userClaimSharesIndex, uint256 userClaimBurnCycleIndex ) { uint256 cycleMaxIndex = getCurrentCycleIndex(cycleNo); if (payoutClaim == PayoutClaim.SHARES) { (userClaimCycleIndex, userClaimSharesIndex) = getUserLastClaimIndex(user, cycleNo); uint256 sharesMaxIndex = getUserLatestShareIndex(user); for (uint256 i = userClaimCycleIndex; i <= cycleMaxIndex; i++) { (uint256 payoutPerShare, uint256 payoutDay) = getPayoutPerShare(cycleNo, i); uint256 shares; //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; } if (payoutPerShare != 0 && shares != 0) { //reward has 18 decimals scaling, so here divide by 1e18 rewards += (shares * payoutPerShare) / SCALING_FACTOR_1e18; } userClaimCycleIndex = i + 1; } } else if (cycleNo == DAY28 && payoutClaim == PayoutClaim.BURN) { userClaimBurnCycleIndex = getUserLastBurnClaimIndex(user, cycleNo); for (uint256 i = userClaimBurnCycleIndex; i <= cycleMaxIndex; i++) { uint256 burnPayoutPerToken = getCycleBurnPayoutPerToken(i); rewards += (burnPayoutPerToken != 0) ? (burnPayoutPerToken * _getUserCycleBurnTotal(user, i)) / SCALING_FACTOR_1e18 : 0; userClaimBurnCycleIndex = i + 1; } } } /** @notice get contract ETH balance * @return balance eth balance */ function getBalance() public view returns (uint256) { return address(this).balance; } /** @notice get undistributed ETH balance * @return amount eth amount */ function getUndistributedEth() public view returns (uint256) { return s_undistributedEth; } /** @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, DAY8, PayoutClaim.SHARES); reward += _reward; (_reward, , , ) = _calculateUserCycleReward(user, DAY28, PayoutClaim.SHARES); reward += _reward; (_reward, , , ) = _calculateUserCycleReward(user, DAY90, PayoutClaim.SHARES); reward += _reward; (_reward, , , ) = _calculateUserCycleReward(user, DAY369, PayoutClaim.SHARES); reward += _reward; (_reward, , , ) = _calculateUserCycleReward(user, DAY888, PayoutClaim.SHARES); reward += _reward; } /** @notice get user burn reward ETH payout * @param user user address * @return reward burn reward */ function getUserBurnPoolETHClaimableTotal(address user) public view returns (uint256 reward) { (reward, , , ) = _calculateUserCycleReward(user, DAY28, PayoutClaim.BURN); } /** @notice get total penalties from mint and stake * @return amount total penalties */ function getTotalPenalties() public view returns (uint256) { return getTotalMintPenalty() + getTotalStakePenalty(); } /** @notice get burn pool reward * @return reward burn pool reward */ function getCycleBurnPool() public view returns (uint256) { return s_cycleBurnReward; } /** @notice get user current burn cycle percentage * @return percentage in 18 decimals */ function getCurrentUserBurnCyclePercentage() public view returns (uint256) { uint256 index = getCurrentCycleIndex(DAY28) + 1; uint256 cycleBurnTotal = getCycleBurnTotal(index); return cycleBurnTotal == 0 ? 0 : (_getUserCycleBurnTotal(_msgSender(), index) * 100 * SCALING_FACTOR_1e18) / cycleBurnTotal; } /** @notice get user current cycle total titan burned * @param user user address * @return burnTotal total titan burned in curreny burn cycle */ function getUserCycleBurnTotal(address user) public view returns (uint256) { return _getUserCycleBurnTotal(user, getCurrentCycleIndex(DAY28) + 1); } function isBurnPoolEnabled() public view returns (BurnPoolEnabled) { return s_burnPoolEnabled; } /** @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]; } //Public functions for devs to intergrate with Titan /** @notice allow anyone to sync dailyUpdate manually */ function manualDailyUpdate() public dailyUpdate {} /** @notice Burn Titan 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 titan amount * @param userRebatePercentage percentage for user rebate in liquid titan (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid titan (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 { _burnLiquidTitan( user, amount, userRebatePercentage, rewardPaybackPercentage, rewardPaybackAddress ); } /** @notice Burn Titan 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 titan amount * @param userRebatePercentage percentage for user rebate in liquid titan (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid titan (0 - 8) */ function burnTokens( address user, uint256 amount, uint256 userRebatePercentage, uint256 rewardPaybackPercentage ) public dailyUpdate nonReentrant { _burnLiquidTitan(user, amount, userRebatePercentage, rewardPaybackPercentage, _msgSender()); } /** @notice allows user to burn liquid titan directly from contract * @param amount titan amount */ function userBurnTokens(uint256 amount) public dailyUpdate nonReentrant { if (amount == 0) revert TitanX_InvalidAmount(); if (balanceOf(_msgSender()) < amount) revert TitanX_InsufficientBalance(); _burn(_msgSender(), amount); _updateBurnAmount( _msgSender(), address(0), amount, getCurrentCycleIndex(DAY28) + 1, 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 titan (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid titan (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 titan (0 - 8) * @param rewardPaybackPercentage percentage for builder fee in liquid titan (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() ), getCurrentCycleIndex(DAY28) + 1, 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), getCurrentCycleIndex(DAY28) + 1, 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 TitanX_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 TitanX_InvalidAddress(); s_allowanceBurnStakes[_msgSender()][spender] = amount; emit ApproveBurnStakes(_msgSender(), spender, amount); return true; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "./openzeppelin/utils/Context.sol"; error TitanX_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 TitanX_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/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 titan burn amount uint256 private s_totalTitanBurned; //mappings //track wallet address -> total titan burn amount mapping(address => uint256) private s_userBurnAmount; //track contract/project address -> total titan burn amount mapping(address => uint256) private s_project_BurnAmount; //track contract/project address, wallet address -> total titan burn amount mapping(address => mapping(address => uint256)) private s_projectUser_BurnAmount; /** @dev cycleIndex is increased when triggerPayouts() was called successfully * so we track data in current cycleIndex + 1 which means tracking for the next cycle payout * cycleIndex is passed from the TITANX contract during function call */ //track cycleIndex + 1 -> total burn amount mapping(uint256 => uint256) private s_cycle28TotalBurn; //track address, cycleIndex + 1 -> total burn amount mapping(address => mapping(uint256 => uint256)) private s_userCycle28TotalBurn; //track cycleIndex + 1 -> burn payout per token mapping(uint256 => uint256) private s_cycle28BurnPayoutPerToken; //events /** @dev log user burn titan event * project can be address(0) if user burns Titan directly from Titan contract * burnPoolCycleIndex is the cycle 28 index, which reuse the same index as Day 28 cycle index * titanSource 0=Liquid, 1=Mint, 2=Stake */ event TitanBurned( address indexed user, address indexed project, uint256 indexed burnPoolCycleIndex, uint256 amount, BurnSource titanSource ); //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 titan amount burned * @param cycleIndex cycle payout triggered index */ function _updateBurnAmount( address user, address project, uint256 amount, uint256 cycleIndex, BurnSource source ) internal { s_userBurnAmount[user] += amount; s_totalTitanBurned += amount; s_cycle28TotalBurn[cycleIndex] += amount; s_userCycle28TotalBurn[user][cycleIndex] += amount; if (project != address(0)) { s_project_BurnAmount[project] += amount; s_projectUser_BurnAmount[project][user] += amount; } emit TitanBurned(user, project, cycleIndex, amount, source); } /** * @dev calculate burn reward per titan burned based on total reward / total titan burned in current cycle * @param cycleIndex wallet address * @param reward contract address * @param cycleBurnAmount titan amount burned */ function _calculateCycleBurnRewardPerToken( uint256 cycleIndex, uint256 reward, uint256 cycleBurnAmount ) internal { //add 18 decimals to reward for better precision in calculation s_cycle28BurnPayoutPerToken[cycleIndex] = (reward * SCALING_FACTOR_1e18) / cycleBurnAmount; } /** @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 titan amount from all users burn or projects burn * @return totalBurnAmount returns entire burned titan */ function getTotalBurnTotal() public view returns (uint256) { return s_totalTitanBurned; } /** @notice return user address total burned titan * @return userBurnAmount returns user address total burned titan */ function getUserBurnTotal(address user) public view returns (uint256) { return s_userBurnAmount[user]; } /** @notice return project address total burned titan amount * @return projectTotalBurnAmount returns project total burned titan */ function getProjectBurnTotal(address contractAddress) public view returns (uint256) { return s_project_BurnAmount[contractAddress]; } /** @notice return user address total burned titan amount via a project address * @param contractAddress project address * @param user user address * @return projectUserTotalBurnAmount returns user address total burned titan via a project address */ function getProjectUserBurnTotal( address contractAddress, address user ) public view returns (uint256) { return s_projectUser_BurnAmount[contractAddress][user]; } /** @notice return cycle28 total burned titan amount with the specified cycleIndex * @param cycleIndex cycle index * @return cycle28TotalBurn returns cycle28 total burned titan amount with the specified cycleIndex */ function getCycleBurnTotal(uint256 cycleIndex) public view returns (uint256) { return s_cycle28TotalBurn[cycleIndex]; } /** @notice return cycle28 total burned titan amount with the specified cycleIndex * @param user user address * @param cycleIndex cycle index * @return cycle28TotalBurn returns cycle28 user address total burned titan amount with the specified cycleIndex */ function _getUserCycleBurnTotal( address user, uint256 cycleIndex ) internal view returns (uint256) { return s_userCycle28TotalBurn[user][cycleIndex]; } /** @notice return cycle28 burn payout per titan with the specified cycleIndex * @param cycleIndex cycle index * @return cycle28TotalBurn returns cycle28 burn payout per titan with the specified cycleIndex */ function getCycleBurnPayoutPerToken(uint256 cycleIndex) public view returns (uint256) { return s_cycle28BurnPayoutPerToken[cycleIndex]; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "../libs/calcFunctions.sol"; //custom errors error TitanX_InvalidStakeLength(); error TitanX_RequireOneMinimumShare(); error TitanX_ExceedMaxAmountPerStake(); error TitanX_NoStakeExists(); error TitanX_StakeHasEnded(); error TitanX_StakeNotMatured(); error TitanX_StakeHasBurned(); error TitanX_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 titan */ uint256 private s_globalTitanStaked; /** @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 { uint152 titanAmount; uint128 shares; uint16 numOfDays; uint48 stakeStartTs; uint48 maturityTs; 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 indexed userStakeInfo ); event StakeEnded( address indexed user, uint256 indexed globalStakeId, uint256 titanAmount, uint256 indexed penalty, uint256 penaltyAmount ); //functions /** @dev create a new stake * @param user user address * @param amount titan amount * @param numOfDays stake lenght * @param shareRate current share rate * @param day current contract day * @param isPayoutTriggered has global payout triggered * @return isFirstShares first created shares or not */ function _startStake( address user, uint256 amount, uint256 numOfDays, uint256 shareRate, uint256 day, PayoutTriggered isPayoutTriggered ) internal returns (uint256 isFirstShares) { uint256 sId = ++s_addressSId[user]; if (sId > MAX_STAKE_PER_WALLET) revert TitanX_MaxedWalletStakes(); if (numOfDays < MIN_STAKE_LENGTH || numOfDays > MAX_STAKE_LENGTH) revert TitanX_InvalidStakeLength(); //calculate shares uint256 shares = calculateShares(amount, numOfDays, shareRate); if (shares / SCALING_FACTOR_1e18 < 1) revert TitanX_RequireOneMinimumShare(); uint256 currentGStakeId = ++s_globalStakeId; uint256 maturityTs; maturityTs = block.timestamp + (numOfDays * SECONDS_IN_DAY); UserStakeInfo memory userStakeInfo = UserStakeInfo({ titanAmount: uint152(amount), shares: uint128(shares), numOfDays: uint16(numOfDays), stakeStartTs: uint48(block.timestamp), maturityTs: uint48(maturityTs), status: StakeStatus.ACTIVE }); /** 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; //update shares changes isFirstShares = _updateSharesStats( user, shares, amount, day, isPayoutTriggered, StakeAction.START ); 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 titan titan principle */ function _endStake( address user, uint256 id, uint256 day, StakeAction action, StakeAction payOther, PayoutTriggered isPayoutTriggered ) internal returns (uint256 titan) { uint256 globalStakeId = s_addressSIdToGlobalStakeId[user][id]; if (globalStakeId == 0) revert TitanX_NoStakeExists(); UserStakeInfo memory userStakeInfo = s_globalStakeIdToStakeInfo[globalStakeId]; if (userStakeInfo.status == StakeStatus.ENDED) revert TitanX_StakeHasEnded(); if (userStakeInfo.status == StakeStatus.BURNED) revert TitanX_StakeHasBurned(); //end stake for others requires matured stake to prevent EES for others if (payOther == StakeAction.END_OTHER && block.timestamp < userStakeInfo.maturityTs) revert TitanX_StakeNotMatured(); //update shares changes uint256 shares = userStakeInfo.shares; _updateSharesStats(user, shares, userStakeInfo.titanAmount, 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; } titan = _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 titan 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_globalTitanStaked += amount; } else { s_addressIdToActiveShares[user][++index].activeShares = previousShares - shares; s_globalExpiredShares += shares; s_globalTitanStaked -= 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 = uint128( 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 titanAmount = userStakeInfo.titanAmount; //penalty is in percentage uint256 penalty = calculateEndStakePenalty( userStakeInfo.stakeStartTs, userStakeInfo.maturityTs, block.timestamp, action ); uint256 penaltyAmount; penaltyAmount = (titanAmount * penalty) / 100; principle = titanAmount - 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 titan staked * @return totalTitanStaked total titan staked */ function getTotalTitanStaked() public view returns (uint256) { return s_globalTitanStaked; } /** @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: uint128(s_addressSIdToGlobalStakeId[user][i]), stakeInfo: getUserStakeInfo(user, i) }); } return stakes; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; import "../libs/calcFunctions.sol"; //custom errors error TitanX_InvalidMintLength(); error TitanX_InvalidMintPower(); error TitanX_NoMintExists(); error TitanX_MintHasClaimed(); error TitanX_MintNotMature(); error TitanX_MintHasBurned(); abstract contract MintInfo { //variables /** @dev track global tRank */ uint256 private s_globalTRank; /** @dev track total mint claimed */ uint256 private s_globalMintClaim; /** @dev track total mint burned */ uint256 private s_globalMintBurn; /** @dev track total titan minting */ uint256 private s_globalTitanMinting; /** @dev track total titan penalty */ uint256 private s_globalTitanMintPenalty; /** @dev track global mint power */ uint256 private s_globalMintPower; //mappings /** @dev track address => mintId */ mapping(address => uint256) private s_addressMId; /** @dev track address, mintId => tRank info (gTrank, gMintPower) */ mapping(address => mapping(uint256 => TRankInfo)) private s_addressMIdToTRankInfo; /** @dev track global tRank => mintInfo*/ mapping(uint256 => UserMintInfo) private s_tRankToMintInfo; //structs struct UserMintInfo { uint8 mintPower; uint16 numOfDays; uint96 mintableTitan; uint48 mintStartTs; uint48 maturityTs; uint32 mintPowerBonus; uint32 EAABonus; uint128 mintedTitan; uint64 mintCost; MintStatus status; } struct TRankInfo { uint256 tRank; uint256 gMintPower; } struct UserMint { uint256 mId; uint256 tRank; uint256 gMintPower; UserMintInfo mintInfo; } //events event MintStarted( address indexed user, uint256 indexed tRank, uint256 indexed gMintpower, UserMintInfo userMintInfo ); event MintClaimed( address indexed user, uint256 indexed tRank, 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 mintableTitan mintable titan * @param mintPowerBonus mint power bonus * @param EAABonus EAA bonus * @param burnAmpBonus burn amplifier bonus * @param gMintPower global mint power * @param currentTRank current global tRank * @param mintCost actual mint cost paid for a mint */ function _startMint( address user, uint256 mintPower, uint256 numOfDays, uint256 mintableTitan, uint256 mintPowerBonus, uint256 EAABonus, uint256 burnAmpBonus, uint256 gMintPower, uint256 currentTRank, uint256 mintCost ) internal returns (uint256 mintable) { if (numOfDays == 0 || numOfDays > MAX_MINT_LENGTH) revert TitanX_InvalidMintLength(); if (mintPower == 0 || mintPower > MAX_MINT_POWER_CAP) revert TitanX_InvalidMintPower(); //calculate mint reward up front with the provided params mintable = calculateMintReward(mintPower, numOfDays, mintableTitan, EAABonus, burnAmpBonus); //store variables into mint info UserMintInfo memory userMintInfo = UserMintInfo({ mintPower: uint8(mintPower), numOfDays: uint16(numOfDays), mintableTitan: uint96(mintable), mintPowerBonus: uint32(mintPowerBonus), EAABonus: uint32(EAABonus), mintStartTs: uint48(block.timestamp), maturityTs: uint48(block.timestamp + (numOfDays * SECONDS_IN_DAY)), mintedTitan: 0, mintCost: uint64(mintCost), status: MintStatus.ACTIVE }); /** s_addressMId[user] tracks mintId for each addrress * s_addressMIdToTRankInfo[user][id] tracks current mint tRank and gPowerMint * s_tRankToMintInfo[currentTRank] stores mint info */ uint256 id = ++s_addressMId[user]; s_addressMIdToTRankInfo[user][id].tRank = currentTRank; s_addressMIdToTRankInfo[user][id].gMintPower = gMintPower; s_tRankToMintInfo[currentTRank] = userMintInfo; emit MintStarted(user, currentTRank, gMintPower, userMintInfo); } /** @dev create new mint in a batch of up to max 100 mints with the same mint length * @param user user address * @param mintPower mint power * @param numOfDays mint lenght * @param mintableTitan mintable titan * @param mintPowerBonus mint power bonus * @param EAABonus EAA bonus * @param burnAmpBonus burn amplifier bonus * @param mintCost actual mint cost paid for a mint */ function _startBatchMint( address user, uint256 mintPower, uint256 numOfDays, uint256 mintableTitan, uint256 mintPowerBonus, uint256 EAABonus, uint256 burnAmpBonus, uint256 count, uint256 mintCost ) internal { uint256 gMintPower = s_globalMintPower; uint256 currentTRank = s_globalTRank; uint256 gMinting = s_globalTitanMinting; for (uint256 i = 0; i < count; i++) { gMintPower += mintPower; gMinting += _startMint( user, mintPower, numOfDays, mintableTitan, mintPowerBonus, EAABonus, burnAmpBonus, gMintPower, ++currentTRank, mintCost ); } _updateMintStats(currentTRank, gMintPower, gMinting); } /** @dev create new mint in a batch of up to max 100 mints with different mint length * @param user user address * @param mintPower mint power * @param minDay minimum start day * @param maxDay maximum end day * @param dayInterval days interval between each new mint length * @param countPerInterval number of mint(s) to create in each mint length interval * @param mintableTitan mintable titan * @param mintPowerBonus mint power bonus * @param EAABonus EAA bonus * @param burnAmpBonus burn amplifier bonus * @param mintCost actual mint cost paid for a mint */ function _startbatchMintLadder( address user, uint256 mintPower, uint256 minDay, uint256 maxDay, uint256 dayInterval, uint256 countPerInterval, uint256 mintableTitan, uint256 mintPowerBonus, uint256 EAABonus, uint256 burnAmpBonus, uint256 mintCost ) internal { uint256 gMintPower = s_globalMintPower; uint256 currentTRank = s_globalTRank; uint256 gMinting = s_globalTitanMinting; /**first for loop is used to determine mint length * minDay is the starting mint length * maxDay is the max mint length where it stops * dayInterval increases the minDay for the next mint */ for (; minDay <= maxDay; minDay += dayInterval) { /**first for loop is used to determine mint length * second for loop is to create number mints per mint length */ for (uint256 j = 0; j < countPerInterval; j++) { gMintPower += mintPower; gMinting += _startMint( user, mintPower, minDay, mintableTitan, mintPowerBonus, EAABonus, burnAmpBonus, gMintPower, ++currentTRank, mintCost ); } } _updateMintStats(currentTRank, gMintPower, gMinting); } /** @dev update variables * @param currentTRank current tRank * @param gMintPower current global mint power * @param gMinting current global minting */ function _updateMintStats(uint256 currentTRank, uint256 gMintPower, uint256 gMinting) internal { s_globalTRank = currentTRank; s_globalMintPower = gMintPower; s_globalTitanMinting = 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 tRank = s_addressMIdToTRankInfo[user][id].tRank; uint256 gMintPower = s_addressMIdToTRankInfo[user][id].gMintPower; if (tRank == 0) revert TitanX_NoMintExists(); UserMintInfo memory mint = s_tRankToMintInfo[tRank]; if (mint.status == MintStatus.CLAIMED) revert TitanX_MintHasClaimed(); if (mint.status == MintStatus.BURNED) revert TitanX_MintHasBurned(); //Only check maturity for claim mint action, burn mint bypass this check if (mint.maturityTs > block.timestamp && action == MintAction.CLAIM) revert TitanX_MintNotMature(); s_globalTitanMinting -= mint.mintableTitan; reward = _calculateClaimReward(user, tRank, gMintPower, mint, action); } /** @dev calculate reward up to 100 claims for batch claim function. Only calculate active and matured mints. * @param user user address * @return reward total batch claims final calculated reward after all bonuses and penalty (if any) */ function _batchClaimMint(address user) internal returns (uint256 reward) { uint256 maxId = s_addressMId[user]; uint256 claimCount; uint256 tRank; uint256 gMinting; UserMintInfo memory mint; for (uint256 i = 1; i <= maxId; i++) { tRank = s_addressMIdToTRankInfo[user][i].tRank; mint = s_tRankToMintInfo[tRank]; if (mint.status == MintStatus.ACTIVE && block.timestamp >= mint.maturityTs) { reward += _calculateClaimReward( user, tRank, s_addressMIdToTRankInfo[user][i].gMintPower, mint, MintAction.CLAIM ); gMinting += mint.mintableTitan; ++claimCount; } if (claimCount == 100) break; } s_globalTitanMinting -= gMinting; } /** @dev calculate final reward with bonuses and penalty (if any) * @param user user address * @param tRank mint's tRank * @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 tRank, uint256 gMintPower, UserMintInfo memory userMintInfo, MintAction action ) private returns (uint256 reward) { if (action == MintAction.CLAIM) s_tRankToMintInfo[tRank].status = MintStatus.CLAIMED; if (action == MintAction.BURN) s_tRankToMintInfo[tRank].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.mintableTitan) + (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_globalTitanMintPenalty += penaltyAmount; //only stored minted amount for claim mint if (action == MintAction.CLAIM) s_tRankToMintInfo[tRank].mintedTitan = uint128(reward); emit MintClaimed(user, tRank, 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]; } /** @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_tRankToMintInfo[s_addressMIdToTRankInfo[user][id].tRank]; } /** @notice Return all mints info of an address * @param user address * @return mintInfos all mints info of an address including mint id, tRank 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, tRank: s_addressMIdToTRankInfo[user][i].tRank, gMintPower: s_addressMIdToTRankInfo[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 tRank * @return globalTRank global tRank */ function getGlobalTRank() public view returns (uint256) { return s_globalTRank; } /** @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_globalTRank - s_globalMintClaim - s_globalMintBurn; } /** @notice Return total minting titan * @return totalMinting total minting titan */ function getTotalMinting() public view returns (uint256) { return s_globalTitanMinting; } /** @notice Return total titan penalty * @return totalTitanPenalty total titan penalty */ function getTotalMintPenalty() public view returns (uint256) { return s_globalTitanMintPenalty; } }
// 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 800 ether and increases capped at 2800 ether, uint72 has enough size */ uint72 private s_currentshareRate; /** @dev mintCost starts 0.2 ether increases and capped at 1 ether, uint64 has enough size */ uint64 private s_currentMintCost; /** @dev mintableTitan starts 8m ether decreases and capped at 800 ether, uint96 has enough size */ uint96 private s_currentMintableTitan; /** @dev mintPowerBonus starts 350_000_000 and decreases capped at 35_000, uint32 has enough size */ uint32 private s_currentMintPowerBonus; /** @dev EAABonus starts 10_000_000 and decreases to 0, uint32 has enough size */ uint32 private s_currentEAABonus; /** @dev track if any of the cycle day 8, 28, 90, 369, 888 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 8, 28, 90, 369, 888 when distributeETH() is called */ mapping(uint256 => uint256) private s_cyclePayouts; /** @dev track payout index for each cycle day, increased by 1 when triggerPayouts() is called succesfully * eg. curent index is 2, s_cyclePayoutIndex[DAY8] = 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[DAY8][2].day = 8 * s_CyclePayoutPerShare[DAY8][2].payoutPerShare = 0.1 */ mapping(uint256 => mapping(uint256 => CycleRewardPerShare)) private s_cyclePayoutPerShare; /** @dev track user last payout reward claim index for cycleIndex, burnCycleIndex and sharesIndex * so calculation would start from next index instead of the first index * [address][DAY8].cycleIndex = 1 * [address][DAY8].burnCycleIndex = 1 * [address][DAY8].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[DAY8] = 8 * s_nextCyclePayoutDay[DAY28] = 28 */ mapping(uint256 => uint256) s_nextCyclePayoutDay; //structs struct CycleRewardPerShare { uint256 day; uint256 payoutPerShare; } struct UserCycleClaimIndex { uint96 cycleIndex; uint96 burnCycleIndex; uint64 sharesIndex; } //event event GlobalDailyUpdateStats( uint256 indexed day, uint256 indexed mintCost, uint256 indexed shareRate, uint256 mintableTitan, 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 = uint64(START_MAX_MINT_COST); s_currentMintableTitan = uint96(START_MAX_MINTABLE_PER_DAY); s_currentshareRate = uint72(START_SHARE_RATE); s_currentMintPowerBonus = uint32(START_MINTPOWER_INCREASE_BONUS); s_currentEAABonus = uint32(EAA_START); s_nextCyclePayoutDay[DAY8] = DAY8; s_nextCyclePayoutDay[DAY28] = DAY28; s_nextCyclePayoutDay[DAY90] = DAY90; s_nextCyclePayoutDay[DAY369] = DAY369; s_nextCyclePayoutDay[DAY888] = DAY888; } /** @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 newShareRate = s_currentshareRate; uint256 newMintableTitan = s_currentMintableTitan; 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; newShareRate = (newShareRate * DAILY_SHARE_RATE_INCREASE_STEP) / PERCENT_BPS; newMintableTitan = (newMintableTitan * DAILY_SUPPLY_MINTABLE_REDUCTION) / PERCENT_BPS; newMintPowerBonus = (newMintPowerBonus * DAILY_MINTPOWER_INCREASE_BONUS_REDUCTION) / PERCENT_BPS; if (newMintCost > 1 ether) { newMintCost = CAPPED_MAX_MINT_COST; } if (newShareRate > CAPPED_MAX_RATE) newShareRate = CAPPED_MAX_RATE; if (newMintableTitan < CAPPED_MIN_DAILY_TITAN_MINTABLE) { newMintableTitan = CAPPED_MIN_DAILY_TITAN_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, newShareRate, newMintableTitan, newMintPowerBonus, newEAABonus ); } s_currentMintCost = uint64(newMintCost); s_currentshareRate = uint72(newShareRate); s_currentMintableTitan = uint96(newMintableTitan); s_currentMintPowerBonus = uint32(newMintPowerBonus); s_currentEAABonus = uint32(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[DAY8] != 0) { s_addressCycleToLastClaimIndex[user][DAY8].cycleIndex = uint96( s_cyclePayoutIndex[DAY8] + 1 ); s_addressCycleToLastClaimIndex[user][DAY28].cycleIndex = uint96( s_cyclePayoutIndex[DAY28] + 1 ); s_addressCycleToLastClaimIndex[user][DAY90].cycleIndex = uint96( s_cyclePayoutIndex[DAY90] + 1 ); s_addressCycleToLastClaimIndex[user][DAY369].cycleIndex = uint96( s_cyclePayoutIndex[DAY369] + 1 ); s_addressCycleToLastClaimIndex[user][DAY888].cycleIndex = uint96( s_cyclePayoutIndex[DAY888] + 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 8, 28, 90, 369, 888 * @param reward total accumulated reward in cycle day 8, 28, 90, 369, 888 * @param globalActiveShares global active shares * @return index return latest current cycleIndex */ function _calculateCycleRewardPerShare( uint256 cycleNo, uint256 reward, uint256 globalActiveShares ) internal returns (uint256 index) { s_cyclePayouts[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(); } /** @dev update with the last index where a user has claimed the payout reward * @param user user address * @param cycleNo cylce day 8, 28, 90, 369, 888 * @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 = uint96(userClaimCycleIndex); if (userClaimSharesIndex != s_addressCycleToLastClaimIndex[user][cycleNo].sharesIndex) s_addressCycleToLastClaimIndex[user][cycleNo].sharesIndex = uint64( userClaimSharesIndex ); } /** @dev update with the last index where a user has claimed the burn payout reward * @param user user address * @param cycleNo cylce day 8, 28, 90, 369, 888 * @param userClaimBurnCycleIndex last claimed burn cycle index */ function _updateUserBurnCycleClaimIndex( address user, uint256 cycleNo, uint256 userClaimBurnCycleIndex ) internal { if (userClaimBurnCycleIndex != s_addressCycleToLastClaimIndex[user][cycleNo].burnCycleIndex) s_addressCycleToLastClaimIndex[user][cycleNo].burnCycleIndex = uint96( userClaimBurnCycleIndex ); } /** @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 8, 28, 90, 369, 888 pool * @param cycleNo cycle day 8, 28, 90, 369, 888 * @param reward reward from distributeETH() */ function _setCyclePayoutPool(uint256 cycleNo, uint256 reward) internal { s_cyclePayouts[cycleNo] += reward; } /** @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 8, 28, 90, 369, 888 */ 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); } } /** 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 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 titan * @return currentMintableTitan current mintable titan */ function getCurrentMintableTitan() public view returns (uint256) { return s_currentMintableTitan; } /** @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 8, 28, 90, 369, 888 * @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 8, 28, 90, 369, 888 * @return currentPayoutPool current accumulated payout pool */ function getCyclePayoutPool(uint256 cycleNo) public view returns (uint256) { return s_cyclePayouts[cycleNo]; } /** @notice Returns the calculated payout per share and contract day for the specified cycle day and index * @param cycleNo cycle day 8, 28, 90, 369, 888 * @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 user's last claimed shares payout indexes for the specified cycle day * @param user user address * @param cycleNo cycle day 8, 28, 90, 369, 888 * @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 user's last claimed burn payout index for the specified cycle day * @param user user address * @param cycleNo cycle day 8, 28, 90, 369, 888 * @return burnCycleIndex burn cycle index */ function getUserLastBurnClaimIndex( address user, uint256 cycleNo ) public view returns (uint256 burnCycleIndex) { return s_addressCycleToLastClaimIndex[user][cycleNo].burnCycleIndex; } /** @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 8, 28, 90, 369, 888 * @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 "./constant.sol"; import "./enum.sol"; //TitanX /**@notice get batch mint ladder total count * @param minDay minimum mint length * @param maxDay maximum mint length, cap at 280 * @param dayInterval day increase from previous mint length * @param countPerInterval number of mints per minth length * @return count total mints */ function getBatchMintLadderCount( uint256 minDay, uint256 maxDay, uint256 dayInterval, uint256 countPerInterval ) pure returns (uint256 count) { if (maxDay > minDay) { count = (((maxDay - minDay) / dayInterval) + 1) * countPerInterval; } } /** @notice get incentive fee in 4 decimals scaling * @return fee fee */ function getIncentiveFeePercent() pure returns (uint256) { return (INCENTIVE_FEE_PERCENT * 1e4) / INCENTIVE_FEE_PERCENT_BASE; } /** @notice get batch mint cost * @param mintPower mint power (1 - 100) * @param count number of mints * @return mintCost total mint cost */ function getBatchMintCost( uint256 mintPower, uint256 count, uint256 mintCost ) pure returns (uint256) { return (mintCost * mintPower * count) / MAX_MINT_POWER_CAP; } //MintInfo /** @notice the formula to calculate mint reward at create new mint * @param mintPower mint power 1 - 100 * @param numOfDays mint length 1 - 280 * @param mintableTitan current contract day mintable titan * @param EAABonus current contract day EAA Bonus * @param burnAmpBonus user burn amplifier bonus from getUserBurnAmplifierBonus(user) * @return reward base titan amount */ function calculateMintReward( uint256 mintPower, uint256 numOfDays, uint256 mintableTitan, uint256 EAABonus, uint256 burnAmpBonus ) pure returns (uint256 reward) { uint256 baseReward = (mintableTitan * 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; } 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 from mintinfo * @param gMintPower global mint power from mintinfo * @param globalMintPower current global mint power * @return bonus bonus amount in titan */ 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 TitanX_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 titan 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(amount, noOfDays)) / SCALING_FACTOR_1e11; shares /= (shareRate / SCALING_FACTOR_1e18); return shares; } /** @notice calculate share bonus * @param amount titan amount * @param noOfDays stake length * @return shareBonus calculated shares bonus in 11 decimals */ function calculateShareBonus(uint256 amount, uint256 noOfDays) pure returns (uint256 shareBonus) { uint256 cappedExtraDays = noOfDays <= LPB_MAX_DAYS ? noOfDays : LPB_MAX_DAYS; uint256 cappedStakedTitan = amount <= BPB_MAX_TITAN ? amount : BPB_MAX_TITAN; shareBonus = ((cappedExtraDays * SCALING_FACTOR_1e11) / LPB_PER_PERCENT) + ((cappedStakedTitan * SCALING_FACTOR_1e11) / BPB_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 TitanX_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; interface ITITANX { function balanceOf(address account) external returns (uint256); function getBalance() external; function mintLPTokens() external; function burnLPTokens() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; interface ITitanOnBurn { function onBurn(address user, uint256 amount) external; }
// 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.8.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]. * * 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}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * 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 value {ERC20} uses, unless this function is * 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 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 (last updated v4.8.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: 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 }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.10; // ===================== 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; // ===================== TITANX ========================================== uint256 constant PERCENT_TO_BUY_AND_BURN = 62_00; uint256 constant PERCENT_TO_CYCLE_PAYOUTS = 28_00; uint256 constant PERCENT_TO_BURN_PAYOUTS = 7_00; uint256 constant PERCENT_TO_GENESIS = 3_00; uint256 constant INCENTIVE_FEE_PERCENT = 3300; uint256 constant INCENTIVE_FEE_PERCENT_BASE = 1_000_000; uint256 constant INITAL_LP_TOKENS = 100_000_000_000 ether; // ===================== globalInfo ========================================== //Titan Supply Variables uint256 constant START_MAX_MINTABLE_PER_DAY = 8_000_000 ether; uint256 constant CAPPED_MIN_DAILY_TITAN_MINTABLE = 800 ether; uint256 constant DAILY_SUPPLY_MINTABLE_REDUCTION = 99_65; //EAA Variables uint256 constant EAA_START = 10 * SCALING_FACTOR_1e6; uint256 constant EAA_BONUSE_FIXED_REDUCTION_PER_DAY = 28_571; uint256 constant EAA_END = 0; uint256 constant MAX_BONUS_DAY = 350; //Mint Cost Variables uint256 constant START_MAX_MINT_COST = 0.2 ether; uint256 constant CAPPED_MAX_MINT_COST = 1 ether; uint256 constant DAILY_MINT_COST_INCREASE_STEP = 100_08; //mintPower Bonus Variables uint256 constant START_MINTPOWER_INCREASE_BONUS = 35 * SCALING_FACTOR_1e7; //starts at 35 with 1e7 scaling factor uint256 constant CAPPED_MIN_MINTPOWER_BONUS = 35 * SCALING_FACTOR_1e3; //capped min of 0.0035 * 1e7 = 35 * 1e3 uint256 constant DAILY_MINTPOWER_INCREASE_BONUS_REDUCTION = 99_65; //Share Rate Variables uint256 constant START_SHARE_RATE = 800 ether; uint256 constant DAILY_SHARE_RATE_INCREASE_STEP = 100_03; uint256 constant CAPPED_MAX_RATE = 2_800 ether; //Cycle Variables uint256 constant DAY8 = 8; uint256 constant DAY28 = 28; uint256 constant DAY90 = 90; uint256 constant DAY369 = 369; uint256 constant DAY888 = 888; uint256 constant CYCLE_8_PERCENT = 28_00; uint256 constant CYCLE_28_PERCENT = 28_00; uint256 constant CYCLE_90_PERCENT = 18_00; uint256 constant CYCLE_369_PERCENT = 18_00; uint256 constant CYCLE_888_PERCENT = 8_00; uint256 constant PERCENT_BPS = 100_00; // ===================== mintInfo ========================================== uint256 constant MAX_MINT_POWER_CAP = 100; uint256 constant MAX_MINT_LENGTH = 280; uint256 constant CLAIM_MINT_GRACE_PERIOD = 7; uint256 constant MAX_BATCH_MINT_COUNT = 100; 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 = 28; uint256 constant MAX_STAKE_LENGTH = 3500; uint256 constant END_STAKE_GRACE_PERIOD = 7; /* Stake Longer Pays Better bonus */ uint256 constant LPB_MAX_DAYS = 2888; uint256 constant LPB_PER_PERCENT = 825; /* Stake Bigger Pays Better bonus */ uint256 constant BPB_MAX_TITAN = 100 * 1e9 * SCALING_FACTOR_1e18; //100 billion uint256 constant BPB_PER_PERCENT = 1_250_000_000_000 * SCALING_FACTOR_1e18; // ===================== burnInfo ========================================== uint256 constant MAX_BURN_REWARD_PERCENT = 8;
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// 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.6.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 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); }
{ "optimizer": { "enabled": true, "runs": 20 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"genesisAddress","type":"address"},{"internalType":"address","name":"buyAndBurnAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"TitanX_AtLeastHalfMaturity","type":"error"},{"inputs":[],"name":"TitanX_EmptyUndistributeFees","type":"error"},{"inputs":[],"name":"TitanX_FailedToSendAmount","type":"error"},{"inputs":[],"name":"TitanX_InsufficientBalance","type":"error"},{"inputs":[],"name":"TitanX_InsufficientBurnAllowance","type":"error"},{"inputs":[],"name":"TitanX_InsufficientProtocolFees","type":"error"},{"inputs":[],"name":"TitanX_InvalidAddress","type":"error"},{"inputs":[],"name":"TitanX_InvalidAmount","type":"error"},{"inputs":[],"name":"TitanX_InvalidBatchCount","type":"error"},{"inputs":[],"name":"TitanX_InvalidBurnRewardPercent","type":"error"},{"inputs":[],"name":"TitanX_InvalidMintLadderInterval","type":"error"},{"inputs":[],"name":"TitanX_InvalidMintLadderRange","type":"error"},{"inputs":[],"name":"TitanX_InvalidMintLength","type":"error"},{"inputs":[],"name":"TitanX_InvalidMintPower","type":"error"},{"inputs":[],"name":"TitanX_InvalidStakeLength","type":"error"},{"inputs":[],"name":"TitanX_LPTokensHasMinted","type":"error"},{"inputs":[],"name":"TitanX_MaxedWalletMints","type":"error"},{"inputs":[],"name":"TitanX_MaxedWalletStakes","type":"error"},{"inputs":[],"name":"TitanX_MintHasBurned","type":"error"},{"inputs":[],"name":"TitanX_MintHasClaimed","type":"error"},{"inputs":[],"name":"TitanX_MintNotMature","type":"error"},{"inputs":[],"name":"TitanX_NoCycleRewardToClaim","type":"error"},{"inputs":[],"name":"TitanX_NoMintExists","type":"error"},{"inputs":[],"name":"TitanX_NoSharesExist","type":"error"},{"inputs":[],"name":"TitanX_NoStakeExists","type":"error"},{"inputs":[],"name":"TitanX_NotAllowed","type":"error"},{"inputs":[],"name":"TitanX_NotOnwer","type":"error"},{"inputs":[],"name":"TitanX_NotSupportedContract","type":"error"},{"inputs":[],"name":"TitanX_RequireOneMinimumShare","type":"error"},{"inputs":[],"name":"TitanX_StakeHasBurned","type":"error"},{"inputs":[],"name":"TitanX_StakeHasEnded","type":"error"},{"inputs":[],"name":"TitanX_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"},{"indexed":false,"internalType":"uint256","name":"burnReward","type":"uint256"}],"name":"CyclePayoutTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"day","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"mintCost","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"shareRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintableTitan","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":"uint256","name":"tRank","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":"tRank","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"gMintpower","type":"uint256"},{"components":[{"internalType":"uint8","name":"mintPower","type":"uint8"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint96","name":"mintableTitan","type":"uint96"},{"internalType":"uint48","name":"mintStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"internalType":"uint32","name":"mintPowerBonus","type":"uint32"},{"internalType":"uint32","name":"EAABonus","type":"uint32"},{"internalType":"uint128","name":"mintedTitan","type":"uint128"},{"internalType":"uint64","name":"mintCost","type":"uint64"},{"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"}],"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":"titanAmount","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":"uint152","name":"titanAmount","type":"uint152"},{"internalType":"uint128","name":"shares","type":"uint128"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint48","name":"stakeStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"internalType":"enum StakeStatus","name":"status","type":"uint8"}],"indexed":true,"internalType":"struct StakeInfo.UserStakeInfo","name":"userStakeInfo","type":"tuple"}],"name":"StakeStarted","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":"burnPoolCycleIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"enum BurnSource","name":"titanSource","type":"uint8"}],"name":"TitanBurned","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":"batchClaimMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintPower","type":"uint256"},{"internalType":"uint256","name":"numOfDays","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"batchMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintPower","type":"uint256"},{"internalType":"uint256","name":"minDay","type":"uint256"},{"internalType":"uint256","name":"maxDay","type":"uint256"},{"internalType":"uint256","name":"dayInterval","type":"uint256"},{"internalType":"uint256","name":"countPerInterval","type":"uint256"}],"name":"batchMintLadder","outputs":[],"stateMutability":"payable","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":"uint256","name":"id","type":"uint256"}],"name":"claimMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimUserAvailableETHBurnPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimUserAvailableETHPayouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"distributeETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableBurnPoolReward","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":[],"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":"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":"getCurrentMintableTitan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentShareRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentUserBurnCyclePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cycleIndex","type":"uint256"}],"name":"getCycleBurnPayoutPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCycleBurnPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cycleIndex","type":"uint256"}],"name":"getCycleBurnTotal","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":[],"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":"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":"getGlobalTRank","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":[],"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":"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":"getTotalTitanStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUndistributedEth","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":"getUserBurnPoolETHClaimableTotal","outputs":[{"internalType":"uint256","name":"reward","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":"getUserCycleBurnTotal","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":"getUserLastBurnClaimIndex","outputs":[{"internalType":"uint256","name":"burnCycleIndex","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":"uint8","name":"mintPower","type":"uint8"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint96","name":"mintableTitan","type":"uint96"},{"internalType":"uint48","name":"mintStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"internalType":"uint32","name":"mintPowerBonus","type":"uint32"},{"internalType":"uint32","name":"EAABonus","type":"uint32"},{"internalType":"uint128","name":"mintedTitan","type":"uint128"},{"internalType":"uint64","name":"mintCost","type":"uint64"},{"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":"tRank","type":"uint256"},{"internalType":"uint256","name":"gMintPower","type":"uint256"},{"components":[{"internalType":"uint8","name":"mintPower","type":"uint8"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint96","name":"mintableTitan","type":"uint96"},{"internalType":"uint48","name":"mintStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"internalType":"uint32","name":"mintPowerBonus","type":"uint32"},{"internalType":"uint32","name":"EAABonus","type":"uint32"},{"internalType":"uint128","name":"mintedTitan","type":"uint128"},{"internalType":"uint64","name":"mintCost","type":"uint64"},{"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":"uint152","name":"titanAmount","type":"uint152"},{"internalType":"uint128","name":"shares","type":"uint128"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint48","name":"stakeStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"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":"uint152","name":"titanAmount","type":"uint152"},{"internalType":"uint128","name":"shares","type":"uint128"},{"internalType":"uint16","name":"numOfDays","type":"uint16"},{"internalType":"uint48","name":"stakeStartTs","type":"uint48"},{"internalType":"uint48","name":"maturityTs","type":"uint48"},{"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":[],"name":"isBurnPoolEnabled","outputs":[{"internalType":"enum BurnPoolEnabled","name":"","type":"uint8"}],"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":[],"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":"uint256","name":"mintPower","type":"uint256"},{"internalType":"uint256","name":"numOfDays","type":"uint256"}],"name":"startMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"numOfDays","type":"uint256"}],"name":"startStake","outputs":[],"stateMutability":"nonpayable","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"}]
Contract Creation Code
60a060405234801562000010575f80fd5b5060405162006299380380620062998339810160408190526200003391620002a8565b604051806040016040528060078152602001660a892a8829c40b60cb1b815250604051806040016040528060068152602001650a892a8829cb60d31b81525081600390816200008391906200037e565b5060046200009282826200037e565b5050600160058190554260805260065550600780546001600160e81b0319167b069e10de76676d0800000002c68af0bb1400002b5e3af16b18800000179055620000e162989680602362000446565b6008805463ffffffff191663ffffffff929092169190911790556200010b620f4240600a62000446565b6008805463ffffffff929092166401000000000263ffffffff60201b19909216919091178155600d6020527f0b705463cf5f7356780ee6e96132d37412c1b5816a4d207b8dcd42c34976745755601c7fe08c955e5efff0d87732e6655002ef18ef6cad920399de609dbb470f9b22665f55605a7f6d7a92e696f0688f26e4b1ea6039fe4448d8a822e67ac794a76d0e65df6db552556101717fe1718144cbeaa1a32a28fee01ecb62ad9d07562e126ff79623a9a26eda05ca47556103785f8190527ff22d066e86e14b611c2c6318708f35a95ea9f6a2107f6122a10ad3badf8d4d0655620001f63390565b602a80546001600160a01b0319166001600160a01b039283161790558216620002325760405163f43167df60e01b815260040160405180910390fd5b6001600160a01b0381166200025a5760405163f43167df60e01b815260040160405180910390fd5b602b80546001600160a01b039384166001600160a01b031991821617909155602c805492909316911617905562000470565b80516001600160a01b0381168114620002a3575f80fd5b919050565b5f8060408385031215620002ba575f80fd5b620002c5836200028c565b9150620002d5602084016200028c565b90509250929050565b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806200030757607f821691505b6020821081036200032657634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111562000379575f81815260208120601f850160051c81016020861015620003545750805b601f850160051c820191505b81811015620003755782815560010162000360565b5050505b505050565b81516001600160401b038111156200039a576200039a620002de565b620003b281620003ab8454620002f2565b846200032c565b602080601f831160018114620003e8575f8415620003d05750858301515b5f19600386901b1c1916600185901b17855562000375565b5f85815260208120601f198616915b828110156200041857888601518255948401946001909101908401620003f7565b50858210156200043657878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b80820281158282048414176200046a57634e487b7160e01b5f52601160045260245ffd5b92915050565b608051615e09620004905f395f8181610ddf01526125850152615e095ff3fe608060405260043610610452575f3560e01c80637789281e1161023f578063b8fac78911610133578063b8fac78914610c9e578063b984c94614610cb2578063baf20eef14610cc6578063bb88603c14610ce5578063c081f4c014610cf9578063c50312ad14610d0d578063d819e19814610d41578063d9af94af14610d6d578063dd62ed3e14610d7f578063dff96e9a14610d9e578063e33a3c9414610db2578063e3af6d0a14610dd1578063e3d3227d14610e03578063e805217414610e17578063ea4e63ed14610e36578063efe1702314610e4a578063f2fde38b14610e69578063f63ec50e14610e88578063f80b0cfb14610ea2578063f948e38614610eb6578063faa94d3b14610eca578063fbf9529d14610ee9578063fd59212e14610f06578063ffb75cab14610f31575f80fd5b80637789281e14610a1957806377a5426914610a2d5780637b763a2c14610a4c5780637d6b325314610a6b5780637fa8381a14610a8a578063800bb26914610a9e578063842e298114610ab2578063856a73da14610ade578063880a083614610afd57806389de416514610b115780638e449fdc14610b3057806392c1df5414610b435780639332812414610b5757806395d89b4114610b7857806396d9720814610b8c5780639a5a6cd914610bab5780639c3459f014610bca5780639ed9922014610bde578063a779c1f014610bfd578063a9059cbb14610c1b578063af4fb76314610c3a578063af835b8a14610c4e578063b3c05b1d14610c6d578063b8b9b54914610c8a575f80fd5b8063300284f211610356578063300284f214610717578063313ce5671461073657806333f3fd7814610751578063348617f91461077057806337c4f8c41461078f5780633a9693e1146107ae5780633c34267f146107cd5780633dda7881146107ec578063462a8c2f146108005780634676736f1461082b5780635085aa481461083f578063510f8b9c1461086a578063544a6c591461088957806354f5d028146108cd578063560a701a146108e1578063566d0be3146109005780635c3ef1301461091f578063635d70f4146109635780636c52876b146109765780636f6096331461098a57806370a082311461099e57806370c9b002146109bd578063715018a6146109f15780637291fb1614610a05575f80fd5b8062281d1414610456578062ae5faa1461047d57806306fdde03146104a9578063095ea7b3146104ca5780630cbe28d6146104f95780630fe757c81461051a57806312065fe01461053e578063128bfcae146105505780631371bb401461056f57806313aad510146105b357806318160ddd146105c75780631ae409c0146105db5780631fd979e0146105ef578063216630b41461060257806321eef69d146106165780632277d1bd1461062a578063236393851461063e57806323b872dd14610652578063276b5c1a14610671578063280eed801461068557806329b70d7a146106a45780632d02347a146106d85780632f77195114610703575b5f80fd5b348015610461575f80fd5b5061046a610f5d565b6040519081526020015b60405180910390f35b348015610488575f80fd5b5061049c61049736600461574c565b610f70565b6040516104749190615803565b3480156104b4575f80fd5b506104bd611042565b6040516104749190615811565b3480156104d5575f80fd5b506104e96104e436600461574c565b6110d2565b6040519015158152602001610474565b348015610504575f80fd5b5061051861051336600461585c565b6110e9565b005b348015610525575f80fd5b50602c54600160a01b90046001600160581b031661046a565b348015610549575f80fd5b504761046a565b34801561055b575f80fd5b5061051861056a366004615873565b61112e565b34801561057a575f80fd5b5061046a610589366004615893565b6001600160a01b039182165f90815260266020908152604080832093909416825291909152205490565b3480156105be575f80fd5b506105186111b0565b3480156105d2575f80fd5b5060025461046a565b3480156105e6575f80fd5b5060065461046a565b6105186105fd3660046158c4565b6111ba565b34801561060d575f80fd5b5060115461046a565b348015610621575f80fd5b5061046a611285565b348015610635575f80fd5b506105186112f4565b348015610649575f80fd5b5061046a611559565b34801561065d575f80fd5b506104e961066c3660046158ed565b61157c565b34801561067c575f80fd5b50601d5461046a565b348015610690575f80fd5b5061046a61069f366004615926565b6115a1565b3480156106af575f80fd5b5061046a6106be366004615926565b6001600160a01b03165f9081526025602052604090205490565b3480156106e3575f80fd5b5061046a6106f236600461585c565b5f908152600d602052604090205490565b34801561070e575f80fd5b5060105461046a565b348015610722575f80fd5b506104e961073136600461574c565b6115b9565b348015610741575f80fd5b5060405160128152602001610474565b34801561075c575f80fd5b5061051861076b36600461593f565b611638565b34801561077b575f80fd5b5061046a61078a36600461574c565b611666565b34801561079a575f80fd5b506105186107a936600461585c565b61169d565b3480156107b9575f80fd5b506105186107c8366004615926565b6116da565b3480156107d8575f80fd5b506105186107e736600461585c565b611757565b3480156107f7575f80fd5b506105186117db565b34801561080b575f80fd5b5061046a61081a36600461585c565b5f9081526009602052604090205490565b348015610836575f80fd5b50600e5461046a565b34801561084a575f80fd5b5061046a61085936600461585c565b5f9081526027602052604090205490565b348015610875575f80fd5b5061046a610884366004615926565b6118b9565b348015610894575f80fd5b5061046a6108a3366004615893565b6001600160a01b039182165f908152602e6020908152604080832093909416825291909152205490565b3480156108d8575f80fd5b5060235461046a565b3480156108ec575f80fd5b5061046a6108fb366004615926565b611921565b34801561090b575f80fd5b5061051861091a36600461585c565b611940565b34801561092a575f80fd5b5061046a610939366004615893565b6001600160a01b039182165f908152602f6020908152604080832093909416825291909152205490565b610518610971366004615873565b61198b565b348015610981575f80fd5b5061046a611a78565b348015610995575f80fd5b5061046a611a8f565b3480156109a9575f80fd5b5061046a6109b8366004615926565b611aa5565b3480156109c8575f80fd5b506109dc6109d7366004615873565b611abf565b60408051928352602083019190915201610474565b3480156109fc575f80fd5b50610518611ae2565b348015610a10575f80fd5b50610518611af3565b348015610a24575f80fd5b5060195461046a565b348015610a38575f80fd5b50610518610a4736600461593f565b611b1e565b348015610a57575f80fd5b50610518610a6636600461574c565b611b3b565b348015610a76575f80fd5b50610518610a85366004615926565b611b55565b348015610a95575f80fd5b50610518611ba6565b348015610aa9575f80fd5b5061046a611bcb565b348015610abd575f80fd5b50610ad1610acc366004615926565b611be2565b604051610474919061598b565b348015610ae9575f80fd5b506104e9610af836600461574c565b611ce8565b348015610b08575f80fd5b5060185461046a565b348015610b1c575f80fd5b506109dc610b2b36600461574c565b611d67565b610518610b3e3660046159ee565b611daa565b348015610b4e575f80fd5b5060135461046a565b348015610b62575f80fd5b50610b6b611ed8565b6040516104749190615a35565b348015610b83575f80fd5b506104bd611ee8565b348015610b97575f80fd5b50610518610ba6366004615a48565b611ef7565b348015610bb6575f80fd5b5061046a610bc5366004615926565b611f24565b348015610bd5575f80fd5b50601a5461046a565b348015610be9575f80fd5b50610518610bf8366004615a48565b611f5d565b348015610c08575f80fd5b50602d54600160601b900460ff16610b6b565b348015610c26575f80fd5b506104e9610c3536600461574c565b611f7a565b348015610c45575f80fd5b5061046a611f87565b348015610c59575f80fd5b5061046a610c6836600461585c565b611f98565b348015610c78575f80fd5b50602d546001600160581b031661046a565b348015610c95575f80fd5b50610518611fa9565b348015610ca9575f80fd5b50601c5461046a565b348015610cbd575f80fd5b5060175461046a565b348015610cd1575f80fd5b50610518610ce036600461585c565b611fe2565b348015610cf0575f80fd5b50610518612000565b348015610d04575f80fd5b50601b5461046a565b348015610d18575f80fd5b5061046a610d27366004615926565b6001600160a01b03165f9081526014602052604090205490565b348015610d4c575f80fd5b50610d60610d5b36600461574c565b612026565b6040516104749190615b69565b348015610d78575f80fd5b504261046a565b348015610d8a575f80fd5b5061046a610d99366004615893565b612128565b348015610da9575f80fd5b5060125461046a565b348015610dbd575f80fd5b5061046a610dcc366004615926565b612152565b348015610ddc575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061046a565b348015610e0e575f80fd5b506105186121f4565b348015610e22575f80fd5b5061046a610e31366004615926565b61229b565b348015610e41575f80fd5b5061046a6122b5565b348015610e55575f80fd5b50610518610e6436600461574c565b6122cb565b348015610e74575f80fd5b50610518610e83366004615926565b6122f9565b348015610e93575f80fd5b5060085463ffffffff1661046a565b348015610ead575f80fd5b50600f5461046a565b348015610ec1575f80fd5b5061051861230a565b348015610ed5575f80fd5b5061046a610ee4366004615926565b612327565b348015610ef4575f80fd5b506007546001600160481b031661046a565b348015610f11575f80fd5b5061046a610f2036600461585c565b5f9081526029602052604090205490565b348015610f3c575f80fd5b50610f50610f4b366004615926565b612341565b6040516104749190615b78565b600854600160201b900463ffffffff1690565b610f78615667565b6001600160a01b0383165f908152601f60209081526040808320858452825280832054835281805291829020825160c08101845281546001600160981b0316815260018201546001600160801b0381169382019390935261ffff600160801b8404169381019390935265ffffffffffff600160901b830481166060850152600160c01b83041660808401529060a083019060ff600160f01b90910416600281111561102557611025615774565b600281111561103657611036615774565b90525090505b92915050565b60606003805461105190615bdb565b80601f016020809104026020016040519081016040528092919081815260200182805461107d90615bdb565b80156110c85780601f1061109f576101008083540402835291602001916110c8565b820191905f5260205f20905b8154815290600101906020018083116110ab57829003601f168201915b5050505050905090565b5f336110df818585612450565b5060019392505050565b6110f1612578565b6110f9612835565b6111213361111c338461110b60065490565b60016003611117611ed8565b61288e565b612b0f565b61112b6001600555565b50565b611136612578565b61113e612835565b8161114833611aa5565b1015611167576040516376f2de6d60e11b815260040160405180910390fd5b6111713383612bb9565b6111a23361119d33858561118d6007546001600160481b031690565b600654611198611ed8565b612cd6565b612f9f565b6111ac6001600555565b5050565b6111b8612578565b565b6111c2612835565b6111ca612578565b8015806111d75750606481115b156111f55760405163d487a0df60e01b815260040160405180910390fd5b6103e88161120233610d27565b61120c9190615c21565b111561122b5760405163f3d1ae6760e01b815260040160405180910390fd5b61126c3384846112396122b5565b60085463ffffffff1661124a610f5d565b611253336118b9565b886112678c6001611262611a8f565b613230565b61325a565b61127683826132d7565b6112806001600555565b505050565b5f80611291601c611f98565b61129c906001615c21565b5f8181526027602052604090205490915080156112eb5780670de0b6b3a76400006112c733856133a8565b6112d2906064615c34565b6112dc9190615c34565b6112e69190615c4b565b6112ed565b5f5b9250505090565b6112fc612578565b611304612835565b5f61130e60195490565b60185461131b9190615c6a565b9050600181101561133f576040516394d33ebf60e01b815260040160405180910390fd5b602c545f9081908190600160a01b90046001600160581b03161561136d576113656133cf565b919450925090505b5f61137760065490565b90505f600161138860088885613642565b600181111561139957611399615774565b1480156113b657505f8160018111156113b4576113b4615774565b145b6113c057806113c5565b506001805b5060016113d4601c8885613642565b60018111156113e5576113e5615774565b14801561140257505f81600181111561140057611400615774565b145b61140c5780611411565b506001805b506001611420605a8885613642565b600181111561143157611431615774565b14801561144e57505f81600181111561144c5761144c615774565b145b611458578061145d565b506001805b50600161146d6101718885613642565b600181111561147e5761147e615774565b14801561149b57505f81600181111561149957611499615774565b145b6114a557806114aa565b506001805b5060016114ba6103788885613642565b60018111156114cb576114cb615774565b1480156114e857505f8160018111156114e6576114e6615774565b145b6114f257806114f7565b506001805b50600181600181111561150c5761150c615774565b03611538575f61151a611ed8565b600181111561152b5761152b615774565b0361153857611538613738565b841561154957611549858585613752565b5050505050506111b86001600555565b5f601054600f54600e5461156d9190615c6a565b6115779190615c6a565b905090565b5f33611589858285613788565b6115948585856137fa565b60019150505b9392505050565b5f6115af82601c6001613989565b5091949350505050565b5f6001600160a01b0383166115e15760405163f43167df60e01b815260040160405180910390fd5b335f818152602e602090815260408083206001600160a01b038816808552925280832086905551859391927ff8e109bcddf5e12132b7cd8a8517d97498f50c7ac595874d6f513243098b079891a450600192915050565b611640612578565b611648612835565b6116558585858585613b7f565b61165f6001600555565b5050505050565b6001600160a01b03919091165f908152600c602090815260408083209383529290522054600160601b90046001600160601b031690565b6116a5612578565b6116ad612835565b611121335f6116be33856001613bf5565b6116c8601c611f98565b6116d3906001615c21565b6001613e24565b602b546001600160a01b0316336001600160a01b03161461170e5760405163060e508760e31b815260040160405180910390fd5b6001600160a01b0381166117355760405163f43167df60e01b815260040160405180910390fd5b602b80546001600160a01b0319166001600160a01b0392909216919091179055565b61175f612578565b611767612835565b805f0361178757604051631c95685960e21b815260040160405180910390fd5b8061179133611aa5565b10156117b0576040516376f2de6d60e11b815260040160405180910390fd5b6117ba3382612bb9565b611121335f836117ca601c611f98565b6117d5906001615c21565b5f613e24565b6117e3612578565b6117eb612835565b5f6117f760085f613f8d565b9050611804601c5f613f8d565b61180e9082615c21565b905061181b605a5f613f8d565b6118259082615c21565b90506118336101715f613f8d565b61183d9082615c21565b905061184b6103785f613f8d565b6118559082615c21565b9050805f0361187757604051635d0fdef160e01b815260040160405180910390fd5b611882335b82613ffa565b604051819033907f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241905f90a3506111b86001600555565b5f806118c48361229b565b9050805f036118d557505f92915050565b680204fce5e3e2502611601f1b81106118f85750676f05b59d3b20000092915050565b680204fce5e3e2502611601f1b61191782676f05b59d3b200000615c34565b61159a9190615c4b565b5f61103c82611930601c611f98565b61193b906001615c21565b6133a8565b611948612578565b611950612835565b611121335f61196f338561196360065490565b60026003611117611ed8565b611979601c611f98565b611984906001615c21565b6002613e24565b611993612835565b61199b612578565b6103e86119a733610d27565b6119b2906001615c21565b11156119d15760405163f3d1ae6760e01b815260040160405180910390fd5b5f826119dc60135490565b6119e69190615c21565b90505f6119f2600e5490565b6119fd906001615c21565b90505f611a3d338686611a0e6122b5565b60085463ffffffff16611a1f610f5d565b611a28336118b9565b8a8a611a388f6001611262611a8f565b614091565b601154611a4a9190615c21565b9050611a60828483600e92909255601355601155565b611a6b8560016132d7565b5050506111ac6001600555565b5f611a82601b5490565b6012546115779190615c21565b600754600160481b90046001600160401b031690565b6001600160a01b03165f9081526020819052604090205490565b5f918252600b602090815260408084209284529190529020600181015490549091565b611aea6143a1565b6111b85f6143cc565b611afb612578565b611b03612835565b611b14611b0f336143ee565b614607565b6111b86001600555565b611b26612578565b611b2e612835565b611655858585858561463a565b611b43612578565b611b4b612835565b6111a28282614669565b611b5d6143a1565b6001600160a01b038116611b845760405163f43167df60e01b815260040160405180910390fd5b602c80546001600160a01b0319166001600160a01b0392909216919091179055565b611bae6143a1565b602d80546001919060ff60601b1916600160601b835b0217905550565b5f611bd5601c5490565b6017546115779190615c6a565b6001600160a01b0381165f908152601e6020526040812054606091816001600160401b03811115611c1557611c15615c7d565b604051908082528060200260200182016040528015611c4e57816020015b611c3b61569c565b815260200190600190039081611c335790505b50905060015b828111611ce057604080516060810182528281526001600160a01b0387165f908152601f6020908152838220858352815290839020546001600160801b031690820152908101611ca48784610f70565b905282611cb2600184615c6a565b81518110611cc257611cc2615c91565b60200260200101819052508080611cd890615ca5565b915050611c54565b509392505050565b5f6001600160a01b038316611d105760405163f43167df60e01b815260040160405180910390fd5b335f818152602f602090815260408083206001600160a01b038816808552925280832086905551859391927fd508e6bf29a4128e58df993e4fe1db1d926db54e85247bc919df2c52eb78212591a450600192915050565b6001600160a01b03919091165f908152600c6020908152604080832093835292905220546001600160601b03811691600160c01b9091046001600160401b031690565b611db2612835565b611dba612578565b815f03611dda5760405163a87b21b760e01b815260040160405180910390fd5b83831080611de6575083155b80611df2575061011883115b15611e10576040516349e092bf60e01b815260040160405180910390fd5b5f611e1d858585856146ba565b9050801580611e2c5750606481115b15611e4a5760405163d487a0df60e01b815260040160405180910390fd5b6103e881611e5733610d27565b611e619190615c21565b1115611e805760405163f3d1ae6760e01b815260040160405180910390fd5b5f611e8f876001611262611a8f565b9050611ec2338888888888611ea26122b5565b60085463ffffffff16611eb3610f5d565b611ebc336118b9565b8b6146f7565b611ecc87836132d7565b505061165f6001600555565b600854600160401b900460ff1690565b60606004805461105190615bdb565b611eff612578565b611f07612835565b611f14848484843361463a565b611f1e6001600555565b50505050565b6001600160a01b0381165f90815260226020526040812081611f4584612327565b81526020019081526020015f20600101549050919050565b611f65612578565b611f6d612835565b611f148484848433613b7f565b5f336110df8185856137fa565b5f6019546018546115779190615c6a565b5f908152600a602052604090205490565b611fb1612578565b611fb9612835565b5f805f611fc46133cf565b925092509250611fd5838383613752565b5050506111b86001600555565b611fea612578565b611ff2612835565b611121611b0f33835f613bf5565b612008612578565b602c546111b8906001600160a01b031661202181611aa5565b612bb9565b61202e6156bb565b6001600160a01b0383165f90815260156020908152604080832085845282528083205483526016825291829020825161014081018452815460ff808216835261010080830461ffff1695840195909552630100000082046001600160601b031695830195909552600160781b810465ffffffffffff9081166060840152600160a81b8204166080830152600160d81b900463ffffffff90811660a0830152600183015490811660c0830152600160201b81046001600160801b031660e0830152600160a01b81046001600160401b031693820193909352929091610120840191600160e01b90910416600281111561102557611025615774565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b5f806121608360085f613989565b50919250612172915082905083615c21565b915061218083601c5f613989565b50919250612192915082905083615c21565b91506121a083605a5f613989565b509192506121b2915082905083615c21565b91506121c1836101715f613989565b509192506121d3915082905083615c21565b91506121e2836103785f613989565b5091925061159a915082905083615c21565b602c546001600160a01b0316336001600160a01b0316146122285760405163060e508760e31b815260040160405180910390fd5b6001602d54600160581b900460ff16600181111561224857612248615774565b03612266576040516304f0282f60e21b815260040160405180910390fd5b602d805460ff60581b1916600160581b179055602c546111b8906001600160a01b0316680a18f07d736b90be55601d1b612b0f565b6001600160a01b03165f9081526024602052604090205490565b600754600160881b90046001600160601b031690565b6122d3612578565b6122db612835565b6111a28261111c84846122ed60065490565b60016004611117611ed8565b6123016143a1565b61112b816143cc565b612312612578565b61231a612835565b5f611855601c6001613f8d565b6001600160a01b03165f9081526021602052604090205490565b6001600160a01b0381165f90815260146020526040902054606090806001600160401b0381111561237457612374615c7d565b6040519080825280602002602001820160405280156123ad57816020015b61239a61570c565b8152602001906001900390816123925790505b50915060015b81811161244957604080516080810182528281526001600160a01b0386165f9081526015602090815283822085835280825284832080548386015292869052905260010154918101919091526060810161240d8684612026565b90528361241b600184615c6a565b8151811061242b5761242b615c91565b6020026020010181905250808061244190615ca5565b9150506123b3565b5050919050565b6001600160a01b0383166124b75760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084015b60405180910390fd5b6001600160a01b0382166125185760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016124ae565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6006545f620151806125aa7f000000000000000000000000000000000000000000000000000000000000000042615c6a565b6125b49190615c4b565b6125bf906001615c21565b9050818111156111ac57600754600854600160481b82046001600160401b0316916001600160481b03811691600160881b9091046001600160601b03169063ffffffff80821691600160201b9004165f6126198888615c6a565b90505f5b818110156127905761271061263461271889615c34565b61263e9190615c4b565b965061271061264f61271388615c34565b6126599190615c4b565b955061271061266a6126ed87615c34565b6126749190615c4b565b94506127106126856126ed86615c34565b61268f9190615c4b565b9350670de0b6b3a76400008711156126ad57670de0b6b3a764000096505b6897c9ce4cf6d5c000008611156126cb576897c9ce4cf6d5c0000095505b682b5e3af16b188000008510156126e957682b5e3af16b1880000094505b6126f66103e86023615c34565b84101561270d5761270a6103e86023615c34565b93505b61015e881161272957612722616f9b84615c6a565b925061272d565b5f92505b85876127388b615ca5565b6040805189815260208101899052908101879052909b508b907fbfb08f20cf5a7f453097ba3bef35d62a510a1e9b58c8606dbd878334057589ac9060600160405180910390a48061278881615ca5565b91505061261d565b50600780546001600160601b038616600160881b02600167ffffffffffffffff60481b01600160e81b03196001600160401b038a16600160481b02166001600160e81b0319909216919091176001600160481b038816171790556008805463ffffffff848116600160201b0267ffffffffffffffff19909216908616171780825560068990555f919060ff60401b1916600160401b8302179055505050505050505050565b6002600554036128875760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016124ae565b6002600555565b6001600160a01b0386165f908152601f602090815260408083208884529091528120548082036128d157604051635ac2068d60e01b815260040160405180910390fd5b5f81815260208080526040808320815160c08101835281546001600160981b0316815260018201546001600160801b0381169482019490945261ffff600160801b8504169281019290925265ffffffffffff600160901b840481166060840152600160c01b8404166080830152909160a083019060ff600160f01b90910416600281111561296157612961615774565b600281111561297257612972615774565b905250905060018160a00151600281111561298f5761298f615774565b036129ad5760405163698e0d2960e01b815260040160405180910390fd5b60028160a0015160028111156129c5576129c5615774565b036129e3576040516337b7c87160e01b815260040160405180910390fd5b60048560048111156129f7576129f7615774565b148015612a0f5750806080015165ffffffffffff1642105b15612a2d57604051633ed019ef60e11b815260040160405180910390fd5b5f81602001516001600160801b03169050612a588a82845f01516001600160981b03168b898c614786565b506001876004811115612a6d57612a6d615774565b03612aa957601c5f8154612a8090615ca5565b909155505f8381526020805260409020600101805460ff60f01b1916600160f01b179055612af5565b6002876004811115612abd57612abd615774565b03612af557601d5f8154612ad090615ca5565b909155505f8381526020805260409020600101805460ff60f01b1916600160f11b1790555b612b018a84848a614932565b9a9950505050505050505050565b6001600160a01b038216612b655760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016124ae565b8060025f828254612b769190615c21565b90915550506001600160a01b0382165f81815260208181526040808320805486019055518481525f80516020615db4833981519152910160405180910390a35050565b6001600160a01b038216612c195760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016124ae565b6001600160a01b0382165f9081526020819052604090205481811015612c8c5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016124ae565b6001600160a01b0383165f818152602081815260408083208686039055600280548790039055518581529192915f80516020615db4833981519152910160405180910390a3505050565b6001600160a01b0386165f908152601e6020526040812080548291908290612cfd90615ca5565b918290555090506103e8811115612d2757604051632848b67960e01b815260040160405180910390fd5b601c861080612d375750610dac86115b15612d55576040516304b6f31d60e41b815260040160405180910390fd5b5f612d618888886149f8565b90506001612d77670de0b6b3a764000083615c4b565b1015612d9657604051632f41466b60e11b815260040160405180910390fd5b5f60175f8154612da590615ca5565b918290555090505f612dba620151808a615c34565b612dc49042615c21565b90505f6040518060c001604052808c6001600160981b03168152602001856001600160801b031681526020018b61ffff1681526020014265ffffffffffff1681526020018365ffffffffffff1681526020015f6002811115612e2857612e28615774565b90526001600160a01b038d165f908152601f60209081526040808320898452825280832087905586835281805291829020835181546001600160981b0319166001600160981b039091161781559083015160018201805493850151606086015160808701516001600160801b039094166001600160901b031990961695909517600160801b61ffff9092169190910217600160901b600160f01b031916600160901b65ffffffffffff9586160265ffffffffffff60c01b191617600160c01b94909216939093021780835560a0840151939450849391929060ff60f01b1916600160f01b836002811115612f1e57612f1e615774565b0217905550905050612f348c858d8b8b5f614786565b955080604051612f449190615cbd565b6040518091039020838d6001600160a01b03167fecd17a550d3024bd4dcec573e568e747e7843155893d1926213c848215a0d0298d604051612f8891815260200190565b60405180910390a450505050509695505050505050565b806001036111ac5760085f52600a6020527f2c1fd36ba11b13b555f58753742999069764391f450ca8727fe8a3eeffe6777554156111ac5760085f52600a6020527f2c1fd36ba11b13b555f58753742999069764391f450ca8727fe8a3eeffe677755461300d906001615c21565b6001600160a01b0383165f908152600c60209081526040808320600884528252822080546001600160601b0319166001600160601b039490941693909317909255601c9052600a90527f964ea767231031507a3f70c59b06c72a2054875e2bc2938da2a55d8f6cb774eb54613083906001615c21565b6001600160a01b0383165f908152600c60209081526040808320601c84528252822080546001600160601b0319166001600160601b039490941693909317909255605a9052600a90527f7f87218992b43f7ec59f3c8fd242b6759bfedfc613fdc2676bc53b4637f8f351546130f9906001615c21565b6001600160a01b0383165f908152600c60209081526040808320605a84528252822080546001600160601b0319166001600160601b0394909416939093179092556101719052600a90527fb03a258bbb90d8d1843170969b808b3100da20cb067e31b0b691b6f43141902e54613170906001615c21565b6001600160a01b0383165f908152600c6020908152604080832061017184528252822080546001600160601b0319166001600160601b0394909416939093179092556103789052600a90527fb65719cf4862d40ddcfbadca8d587b82e645261e95d3c4e28fef5a0d6eefb6d6546131e8906001615c21565b6001600160a01b0383165f908152600c602090815260408083206103788452909152902080546001600160601b03929092166001600160601b03199092169190911790555050565b5f60648361323e8685615c34565b6132489190615c34565b6132529190615c4b565b949350505050565b601354600e546011545f5b858110156132b4576132778c85615c21565b93506132968d8d8d8d8d8d8d8b61328d8c615ca5565b9b508b8e614091565b6132a09083615c21565b9150806132ac81615ca5565b915050613265565b506132c9828483600e92909255601355601155565b505050505050505050505050565b5f6132e58383611262611a8f565b9050803410156133085760405163110a614b60e31b815260040160405180910390fd5b5f81602c60148282829054906101000a90046001600160581b031661332d9190615d26565b92506101000a8154816001600160581b0302191690836001600160581b03160217905550813461335d9190615c6a565b9050801561336e5761336e3361187c565b8161337860065490565b60405133907fd833e83f161e4ddfb1306cdf11a374a0a23393f008f9394b85999b988c232e36905f90a450505050565b6001600160a01b03919091165f908152602860209081526040808320938352929052205490565b602c545f9081908190600160a01b90046001600160581b031680820361340857604051638b50f3bf60e01b815260040160405180910390fd5b602c8054600160a01b600160f81b0319169055604051819033907f55083a582b32208b745a21c8ce4f8d545be8cce1437f34637f08fc9d943eacb0905f90a3620f4240613457610ce483615c34565b6134619190615c4b565b935061346d8482615c6a565b905061271061347e61183883615c34565b6134889190615c4b565b92505f61271061349a6102bc84615c34565b6134a49190615c4b565b90506127106134b561012c84615c34565b6134bf9190615c4b565b92505f83826134ce8786615c6a565b6134d89190615c6a565b6134e29190615c6a565b90506001602d54600160601b900460ff16600181111561350457613504615774565b0361354f57602d80548391905f906135269084906001600160581b0316615d26565b92506101000a8154816001600160581b0302191690836001600160581b0316021790555061355c565b6135598286615c21565b94505b801561363a575f612710613572610af084615c34565b61357c9190615c4b565b90505f61271061358e610af085615c34565b6135989190615c4b565b90505f6127106135aa61070886615c34565b6135b49190615c4b565b90505f6127106135c661070887615c34565b6135d09190615c4b565b90506135dd600885614a46565b6135e8601c84614a46565b6135f3605a83614a46565b6135ff61017182614a46565b613635610378828486613612898b615c6a565b61361c9190615c6a565b6136269190615c6a565b6136309190615c6a565b614a46565b505050505b505050909192565b5f838152600d602052604081205482101561365e57505f61159a565b61366784614a6c565b5f8481526009602052604081205490819003613686575f91505061159a565b5f613692868387614ad5565b5f81815260276020526040812054919250601c881480156136b257508115155b156136e55750602d546001600160581b031680156136e557602d80546001600160581b03191690556136e5838284614b4e565b8388336001600160a01b03167fb0500ae1b0ee26fc5050483f49228da1236cb641eb890348119ae5abbfd6ab948460405161372291815260200190565b60405180910390a4506001979650505050505050565b600880546001919060ff60401b1916600160401b83611bc4565b61375c3384613ffa565b602b54613772906001600160a01b031682613ffa565b602c54611280906001600160a01b031683613ffa565b5f6137938484612128565b90505f198114611f1e57818110156137ed5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016124ae565b611f1e8484848403612450565b6001600160a01b03831661385e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016124ae565b6001600160a01b0382166138c05760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016124ae565b6001600160a01b0383165f90815260208190526040902054818110156139375760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016124ae565b6001600160a01b038481165f81815260208181526040808320878703905593871680835291849020805487019055925185815290925f80516020615db4833981519152910160405180910390a3611f1e565b5f805f805f61399787611f98565b90505f8660018111156139ac576139ac615774565b03613ac8576139bb8888611d67565b90945092505f6139ca89612327565b9050845b828111613ac1575f806139e18b84611abf565b90925090505f875b858111613a60576001600160a01b038e165f9081526022602090815260408083208484529091529020548310613a46576001600160a01b038e165f9081526022602090815260408083208484529091529020600101549150613a4b565b613a60565b97508780613a5881615ca5565b9150506139e9565b508215801590613a6f57508015155b15613a9e57670de0b6b3a7640000613a878483615c34565b613a919190615c4b565b613a9b908b615c21565b99505b613aa9846001615c21565b98505050508080613ab990615ca5565b9150506139ce565b5050613b75565b601c87148015613ae957506001866001811115613ae757613ae7615774565b145b15613b7557613af88888611666565b9150815b818111613b73575f8181526029602052604081205490819003613b1f575f613b46565b670de0b6b3a7640000613b328b846133a8565b613b3c9083615c34565b613b469190615c4b565b613b509088615c21565b9650613b5d826001615c21565b9350508080613b6b90615ca5565b915050613afc565b505b5093509350935093565b835f03613b9f57604051631c95685960e21b815260040160405180910390fd5b83613ba986611aa5565b1015613bc8576040516376f2de6d60e11b815260040160405180910390fd5b613bd3853386613788565b613bdd8383614b81565b613be78585612bb9565b61165f85858585855f614c9d565b6001600160a01b0383165f90815260156020908152604080832085845290915281208054600190910154818303613c3f5760405163ca288b0560e01b815260040160405180910390fd5b5f828152601660209081526040808320815161014081018352815460ff808216835261010080830461ffff1696840196909652630100000082046001600160601b031694830194909452600160781b810465ffffffffffff9081166060840152600160a81b8204166080830152600160d81b900463ffffffff90811660a0830152600183015490811660c0830152600160201b81046001600160801b031660e0830152600160a01b81046001600160401b031694820194909452929091610120840191600160e01b9004166002811115613d1b57613d1b615774565b6002811115613d2c57613d2c615774565b905250905060018161012001516002811115613d4a57613d4a615774565b03613d685760405163231cb75560e11b815260040160405180910390fd5b60028161012001516002811115613d8157613d81615774565b03613d9f57604051630382986760e61b815260040160405180910390fd5b42816080015165ffffffffffff16118015613dca57505f856001811115613dc857613dc8615774565b145b15613de85760405163305aa66560e21b815260040160405180910390fd5b80604001516001600160601b031660115f828254613e069190615c6a565b90915550613e1990508784848489614dd8565b979650505050505050565b6001600160a01b0385165f9081526024602052604081208054859290613e4b908490615c21565b925050819055508260235f828254613e639190615c21565b90915550505f8281526027602052604081208054859290613e85908490615c21565b90915550506001600160a01b0385165f90815260286020908152604080832085845290915281208054859290613ebc908490615c21565b90915550506001600160a01b03841615613f38576001600160a01b0384165f9081526025602052604081208054859290613ef7908490615c21565b90915550506001600160a01b038085165f90815260266020908152604080832093891683529290529081208054859290613f32908490615c21565b90915550505b81846001600160a01b0316866001600160a01b03167fa85336de4209a315f96a1cc9bc4a8c97cf271e2ec65bf17950058af934ba96528685604051613f7e929190615d4d565b60405180910390a45050505050565b5f80808080613f9d338888613989565b929650909450925090505f866001811115613fba57613fba615774565b03613fcb57613fcb33888585615025565b6001866001811115613fdf57613fdf615774565b03613fef57613fef338883615114565b509195945050505050565b6001600160a01b0382166140215760405163f43167df60e01b815260040160405180910390fd5b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f811461406a576040519150601f19603f3d011682016040523d82523d5f602084013e61406f565b606091505b5050905080611280576040516335abd07f60e01b815260040160405180910390fd5b5f8815806140a0575061011889115b156140be57604051636b47aabb60e11b815260040160405180910390fd5b8915806140cb575060648a115b156140e957604051637eece1ff60e11b815260040160405180910390fd5b6140f68a8a8a8989615198565b90505f6040518061014001604052808c60ff1681526020018b61ffff168152602001836001600160601b031681526020014265ffffffffffff168152602001620151808c6141449190615c34565b61414e9042615c21565b65ffffffffffff16815263ffffffff808b166020830152891660408201525f606082018190526001600160401b038616608083015260a0909101526001600160a01b038d165f9081526014602052604081208054929350909182906141b290615ca5565b91829055506001600160a01b038e165f908152601560209081526040808320848452825280832089815560019081018b90558984526016835292819020865181549388015192880151606089015160808a015160a08b015160ff90941662ffffff199097169690961761010061ffff9096168602176301000000600160a81b03191663010000006001600160601b039093169290920265ffffffffffff60781b191691909117600160781b65ffffffffffff9283160217600160a81b600160f81b031916600160a81b919095160263ffffffff60d81b191693909317600160d81b63ffffffff9485160217815560c0870151938101805460e089015193890151959094166001600160a01b031990941693909317600160201b6001600160801b03909316929092029190911767ffffffffffffffff60a01b198116600160a01b6001600160401b0390951694909402938417835561012087015194955086949193919291600160a01b600160e81b031990911660ff60e01b1990911617600160e01b83600281111561434657614346615774565b021790555090505085858e6001600160a01b03167f2109b8587b0ddbd9adf8ec24ce76bef548f2aee7aac34bc6aa0bb51b7cba9d67856040516143899190615b69565b60405180910390a450509a9950505050505050505050565b602a546001600160a01b031633146111b857604051630406091960e41b815260040160405180910390fd5b602a80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381165f908152601460205260408120548180806144116156bb565b60015b8581116145e5576001600160a01b0388165f9081526015602090815260408083208484528252808320548084526016835292819020815161014081018352815460ff808216835261010080830461ffff1696840196909652630100000082046001600160601b031694830194909452600160781b810465ffffffffffff9081166060840152600160a81b8204166080830152600160d81b900463ffffffff90811660a0830152600183015490811660c0830152600160201b81046001600160801b031660e0830152600160a01b81046001600160401b03169482019490945293975091610120840191600160e01b90910416600281111561451757614517615774565b600281111561452857614528615774565b90525091505f826101200151600281111561454557614545615774565b14801561455e5750816080015165ffffffffffff164210155b156145cb576001600160a01b0388165f908152601560209081526040808320848452909152812060010154614598918a9187918690614dd8565b6145a29088615c21565b965081604001516001600160601b0316836145bd9190615c21565b92506145c885615ca5565b94505b606485146145e557806145dd81615ca5565b915050614414565b508160115f8282546145f79190615c6a565b9091555095979650505050505050565b6146113382612b0f565b602b5461112b906001600160a01b031661271061463084610320615c34565b61111c9190615c4b565b61464385615274565b61464d8383614b81565b61165f8561465f878761196360065490565b8585856002614c9d565b614672826152f6565b61467c5f80614b81565b5f61468983836001613bf5565b602b549091506146ab906001600160a01b031661271061463084610320615c34565b61128083825f80336001614c9d565b5f848411156132525781836146cf8787615c6a565b6146d99190615c4b565b6146e4906001615c21565b6146ee9190615c34565b95945050505050565b601354600e546011545b8a8c11614762575f5b898110156147505761471c8e85615c21565b93506147328f8f8f8c8c8c8c8b61328d8c615ca5565b61473c9083615c21565b91508061474881615ca5565b91505061470a565b5061475b8a8d615c21565b9b50614701565b614776828483600e92909255601355601155565b5050505050505050505050505050565b6001600160a01b0386165f9081526021602090815260408083205460228352818420818552909252822060010154828460048111156147c7576147c7615774565b0361484e57815f036147d857600192505b6147e28882615c21565b6001600160a01b038a165f9081526022602052604081209061480385615ca5565b94508481526020019081526020015f20600101819055508760185f82825461482b9190615c21565b9250508190555086601a5f8282546148439190615c21565b909155506148bf9050565b6148588882615c6a565b6001600160a01b038a165f9081526022602052604081209061487985615ca5565b94508481526020019081526020015f20600101819055508760195f8282546148a19190615c21565b9250508190555086601a5f8282546148b99190615c6a565b90915550505b5f8560018111156148d2576148d2615774565b146148e7576148e2866001615c21565b6148e9565b855b6001600160a01b039099165f81815260226020908152604080832086845282528083206001600160801b039d909d16909c55918152602190915298909820559695505050505050565b5f80835f01516001600160981b031690505f614968856060015165ffffffffffff16866080015165ffffffffffff164287615349565b90505f60646149778385615c34565b6149819190615c4b565b905061498d8184615c6a565b935080601b5f8282546149a09190615c21565b90915550506040805185815260208101839052839189916001600160a01b038c16917f971d9ff3287b3ba75194105e7281e55c93b0a89cad9915664bb3fd9211f8d5f1910160405180910390a4505050949350505050565b5f8364174876e800614a0a828661542c565b614a149083615c34565b614a1e9190615c4b565b614a289082615c21565b9050614a3c670de0b6b3a764000084615c4b565b6146ee9082615c4b565b5f8281526009602052604081208054839290614a63908490615c21565b90915550505050565b5f818152600d60205260409020546006548181106112805782614a8f8383615c6a565b614a999190615c4b565b614aa4906001615c21565b614aae9084615c34565b5f848152600d602052604081208054909190614acb908490615c21565b9091555050505050565b5f838152600960209081526040808320839055600a909152812080548290614afc90615ca5565b9182905550905081614b16670de0b6b3a764000085615c34565b614b209190615c4b565b5f948552600b6020908152604080872084885290915290942060018101949094556006549093555090919050565b80614b61670de0b6b3a764000084615c34565b614b6b9190615c4b565b5f93845260296020526040909320929092555050565b6008614b8d8383615c21565b1115614bac576040516384c175bf60e01b815260040160405180910390fd5b6040516301ffc9a760e01b80825233916301ffc9a791614bce91600401615d6a565b602060405180830381865afa158015614be9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614c0d9190615d7f565b1580614c7f57506040516301ffc9a760e01b815233906301ffc9a790614c3e906311686e4b60e21b90600401615d6a565b602060405180830381865afa158015614c59573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614c7d9190615d7f565b155b156111ac5760405163272a45df60e11b815260040160405180910390fd5b5f614ca8601c611f98565b614cb3906001615c21565b9050614cbe8761229b565b5f03614cd057614cd087601c83615114565b614cdd8733888486613e24565b5f808515614d1657614cf26127106064615c34565b612710614cff888b615c34565b614d099190615c34565b614d139190615c4b565b91505b8615614d4d57614d296127106064615c34565b612710614d36898b615c34565b614d409190615c34565b614d4a9190615c4b565b90505b8115614d5d57614d5d8583612b0f565b8015614d6d57614d6d8982612b0f565b336040516311686e4b60e21b81526001600160a01b038b81166004830152602482018b905291909116906345a1b92c906044015f604051808303815f87803b158015614db7575f80fd5b505af1158015614dc9573d5f803e3d5ffd5b50505050505050505050505050565b5f80826001811115614dec57614dec615774565b03614e13575f858152601660205260409020600101805460ff60e01b1916600160e01b1790555b6001826001811115614e2757614e27615774565b03614e4e575f858152601660205260409020600101805460ff60e01b1916600160e11b1790555b5f805f856080015165ffffffffffff16421115614e8857614e85866080015165ffffffffffff1642614e809190615c6a565b6154da565b91505b5f856001811115614e9b57614e9b615774565b03614ec157614ebe8660a0015163ffffffff16875f015160ff16896013546155ee565b90505b614ece6298968082615c4b565b86604001516001600160601b0316614ee69190615c21565b93506064614ef48386615c34565b614efe9190615c4b565b9250614f0a8385615c6a565b93505f856001811115614f1f57614f1f615774565b03614f3757600f5f8154614f3290615ca5565b909155505b6001856001811115614f4b57614f4b615774565b03614f635760105f8154614f5e90615ca5565b909155505b8215614f80578260125f828254614f7a9190615c21565b90915550505b5f856001811115614f9357614f93615774565b03614fcb575f8881526016602052604090206001018054600160201b600160a01b031916600160201b6001600160801b038716021790555b81888a6001600160a01b03167fbd866a3fbf35e201f790e87581b1afbb3165e879df5d35313a4875a70b9f3b368787604051615011929190918252602082015260400190565b60405180910390a450505095945050505050565b6001600160a01b0384165f908152600c602090815260408083208684529091529020546001600160601b03168214615093576001600160a01b0384165f908152600c60209081526040808320868452909152902080546001600160601b0319166001600160601b0384161790555b6001600160a01b0384165f908152600c60209081526040808320868452909152902054600160c01b90046001600160401b03168114611f1e576001600160a01b0384165f908152600c60209081526040808320868452909152902080546001600160401b038316600160c01b026001600160c01b0390911617905550505050565b6001600160a01b0383165f908152600c60209081526040808320858452909152902054600160601b90046001600160601b03168114611280576001600160a01b0383165f908152600c60209081526040808320858452909152902080546001600160601b038316600160601b02600160601b600160c01b0319909116179055505050565b5f80856151a58887615c34565b6151af9190615c34565b9050856001146151f3576127106151c7600188615c6a565b6151d2600b84615c34565b6151dc9190615c34565b6151e69190615c4b565b6151f09082615c6a565b90505b905080831561522d57620f4240606461520c8684615c34565b6152169190615c4b565b6152209190615c4b565b61522a9083615c21565b91505b821561526957670de0b6b3a764000060646152488584615c34565b6152529190615c4b565b61525c9190615c4b565b6152669083615c21565b91505b613e19606483615c4b565b5f61527f8233610939565b90505f1981146111ac57805f036152a9576040516333e8663d60e01b815260040160405180910390fd5b6001600160a01b0382165f908152602f6020526040812090335b6001600160a01b03166001600160a01b031681526020019081526020015f205f81546152ee90615d9e565b909155505050565b5f61530182336108a3565b90505f1981146111ac57805f0361532b576040516333e8663d60e01b815260040160405180910390fd5b6001600160a01b0382165f908152602e6020526040812090336152c3565b5f838311156153c1575f61535d8585615c6a565b90505f61536e620151806007615c34565b9050808211615381575f92505050613252565b6153b86201518061539c6153958486615c6a565b600161563a565b6153a69190615c4b565b6153b1906001615c21565b6063615650565b92505050613252565b60028260048111156153d5576153d5615774565b036153e157505f613252565b60026153ed8686615c6a565b6153f79190615c4b565b6154019086615c21565b42101561542157604051632146841d60e01b815260040160405180910390fd5b506032949350505050565b5f80610b4883111561544057610b48615442565b825b90505f61545c670de0b6b3a764000064174876e800615c34565b85111561547f5761547a670de0b6b3a764000064174876e800615c34565b615481565b845b905061549b670de0b6b3a764000065012309ce5400615c34565b6154aa64174876e80083615c34565b6154b49190615c4b565b6103396154c664174876e80085615c34565b6154d09190615c4b565b6146ee9190615c21565b5f6154e9620151806007615c34565b82116154f657505f919050565b6201518061550660076001615c21565b6155109190615c34565b821161551e57506001919050565b6201518061552e60076002615c21565b6155389190615c34565b821161554657506003919050565b6201518061555660076003615c21565b6155609190615c34565b821161556e57506008919050565b6201518061557e60076004615c21565b6155889190615c34565b821161559657506011919050565b620151806155a660076005615c21565b6155b09190615c34565b82116155be57506023919050565b620151806155ce60076006615c21565b6155d89190615c34565b82116155e657506048919050565b506063919050565b5f8282116155fd57505f613252565b6064670de0b6b3a76400006156128585615c6a565b61561c8789615c34565b6156269190615c34565b6156309190615c34565b6146ee9190615c4b565b5f8183111561564a57508161103c565b50919050565b5f8183111561566057508061103c565b5090919050565b6040805160c0810182525f8082526020820181905291810182905260608101829052608081018290529060a08201905b905290565b60405180606001604052805f81526020015f8152602001615697615667565b60408051610140810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290529061012082015290565b60405180608001604052805f81526020015f81526020015f81526020016156976156bb565b80356001600160a01b0381168114615747575f80fd5b919050565b5f806040838503121561575d575f80fd5b61576683615731565b946020939093013593505050565b634e487b7160e01b5f52602160045260245ffd5b6003811061112b5761112b615774565b80516001600160981b031682526020808201516001600160801b03169083015260408082015161ffff169083015260608082015165ffffffffffff908116918401919091526080808301519091169083015260a08101516157f881615788565b8060a0840152505050565b60c0810161103c8284615798565b5f6020808352835180828501525f5b8181101561583c57858101830151858201604001528201615820565b505f604082860101526040601f19601f8301168501019250505092915050565b5f6020828403121561586c575f80fd5b5035919050565b5f8060408385031215615884575f80fd5b50508035926020909101359150565b5f80604083850312156158a4575f80fd5b6158ad83615731565b91506158bb60208401615731565b90509250929050565b5f805f606084860312156158d6575f80fd5b505081359360208301359350604090920135919050565b5f805f606084860312156158ff575f80fd5b61590884615731565b925061591660208501615731565b9150604084013590509250925092565b5f60208284031215615936575f80fd5b61159a82615731565b5f805f805f60a08688031215615953575f80fd5b61595c86615731565b945060208601359350604086013592506060860135915061597f60808701615731565b90509295509295909350565b602080825282518282018190525f919060409081850190868401855b828110156159e15781518051855286810151878601528501516159cc86860182615798565b506101009390930192908501906001016159a7565b5091979650505050505050565b5f805f805f60a08688031215615a02575f80fd5b505083359560208501359550604085013594606081013594506080013592509050565b6002811061112b5761112b615774565b60208101615a4283615a25565b91905290565b5f805f8060808587031215615a5b575f80fd5b615a6485615731565b966020860135965060408601359560600135945092505050565b615a8781615788565b9052565b805160ff1682526020810151615aa7602084018261ffff169052565b506040810151615ac260408401826001600160601b03169052565b506060810151615adc606084018265ffffffffffff169052565b506080810151615af6608084018265ffffffffffff169052565b5060a0810151615b0e60a084018263ffffffff169052565b5060c0810151615b2660c084018263ffffffff169052565b5060e0810151615b4160e08401826001600160801b03169052565b50610100818101516001600160401b03169083015261012080820151611f1e82850182615a7e565b610140810161103c8284615a8b565b602080825282518282018190525f919060409081850190868401855b828110156159e1578151805185528681015187860152858101518686015260609081015190615bc581870183615a8b565b50506101a0939093019290850190600101615b94565b600181811c90821680615bef57607f821691505b60208210810361564a57634e487b7160e01b5f52602260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8082018082111561103c5761103c615c0d565b808202811582820484141761103c5761103c615c0d565b5f82615c6557634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561103c5761103c615c0d565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f60018201615cb657615cb6615c0d565b5060010190565b60018060981b03825116815260018060801b03602083015116602082015261ffff60408301511660408201525f65ffffffffffff8060608501511660608401528060808501511660808401525060a0830151615d1881615788565b60a08301525060c001919050565b6001600160581b03818116838216019080821115615d4657615d46615c0d565b5092915050565b82815260408101615d5d83615788565b8260208301529392505050565b6001600160e01b031991909116815260200190565b5f60208284031215615d8f575f80fd5b8151801515811461159a575f80fd5b5f81615dac57615dac615c0d565b505f19019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122071469ca2e3781c6484e6a26608f18aac78ae1d7090596d38f7788b129f1f47da64736f6c63430008150033000000000000000000000000e5e0c13133782d967b002b3400e6ebea5d9814c00000000000000000000000001393ad734ea3c52865b4b541cf049dafd25c23a5
Deployed Bytecode
0x608060405260043610610452575f3560e01c80637789281e1161023f578063b8fac78911610133578063b8fac78914610c9e578063b984c94614610cb2578063baf20eef14610cc6578063bb88603c14610ce5578063c081f4c014610cf9578063c50312ad14610d0d578063d819e19814610d41578063d9af94af14610d6d578063dd62ed3e14610d7f578063dff96e9a14610d9e578063e33a3c9414610db2578063e3af6d0a14610dd1578063e3d3227d14610e03578063e805217414610e17578063ea4e63ed14610e36578063efe1702314610e4a578063f2fde38b14610e69578063f63ec50e14610e88578063f80b0cfb14610ea2578063f948e38614610eb6578063faa94d3b14610eca578063fbf9529d14610ee9578063fd59212e14610f06578063ffb75cab14610f31575f80fd5b80637789281e14610a1957806377a5426914610a2d5780637b763a2c14610a4c5780637d6b325314610a6b5780637fa8381a14610a8a578063800bb26914610a9e578063842e298114610ab2578063856a73da14610ade578063880a083614610afd57806389de416514610b115780638e449fdc14610b3057806392c1df5414610b435780639332812414610b5757806395d89b4114610b7857806396d9720814610b8c5780639a5a6cd914610bab5780639c3459f014610bca5780639ed9922014610bde578063a779c1f014610bfd578063a9059cbb14610c1b578063af4fb76314610c3a578063af835b8a14610c4e578063b3c05b1d14610c6d578063b8b9b54914610c8a575f80fd5b8063300284f211610356578063300284f214610717578063313ce5671461073657806333f3fd7814610751578063348617f91461077057806337c4f8c41461078f5780633a9693e1146107ae5780633c34267f146107cd5780633dda7881146107ec578063462a8c2f146108005780634676736f1461082b5780635085aa481461083f578063510f8b9c1461086a578063544a6c591461088957806354f5d028146108cd578063560a701a146108e1578063566d0be3146109005780635c3ef1301461091f578063635d70f4146109635780636c52876b146109765780636f6096331461098a57806370a082311461099e57806370c9b002146109bd578063715018a6146109f15780637291fb1614610a05575f80fd5b8062281d1414610456578062ae5faa1461047d57806306fdde03146104a9578063095ea7b3146104ca5780630cbe28d6146104f95780630fe757c81461051a57806312065fe01461053e578063128bfcae146105505780631371bb401461056f57806313aad510146105b357806318160ddd146105c75780631ae409c0146105db5780631fd979e0146105ef578063216630b41461060257806321eef69d146106165780632277d1bd1461062a578063236393851461063e57806323b872dd14610652578063276b5c1a14610671578063280eed801461068557806329b70d7a146106a45780632d02347a146106d85780632f77195114610703575b5f80fd5b348015610461575f80fd5b5061046a610f5d565b6040519081526020015b60405180910390f35b348015610488575f80fd5b5061049c61049736600461574c565b610f70565b6040516104749190615803565b3480156104b4575f80fd5b506104bd611042565b6040516104749190615811565b3480156104d5575f80fd5b506104e96104e436600461574c565b6110d2565b6040519015158152602001610474565b348015610504575f80fd5b5061051861051336600461585c565b6110e9565b005b348015610525575f80fd5b50602c54600160a01b90046001600160581b031661046a565b348015610549575f80fd5b504761046a565b34801561055b575f80fd5b5061051861056a366004615873565b61112e565b34801561057a575f80fd5b5061046a610589366004615893565b6001600160a01b039182165f90815260266020908152604080832093909416825291909152205490565b3480156105be575f80fd5b506105186111b0565b3480156105d2575f80fd5b5060025461046a565b3480156105e6575f80fd5b5060065461046a565b6105186105fd3660046158c4565b6111ba565b34801561060d575f80fd5b5060115461046a565b348015610621575f80fd5b5061046a611285565b348015610635575f80fd5b506105186112f4565b348015610649575f80fd5b5061046a611559565b34801561065d575f80fd5b506104e961066c3660046158ed565b61157c565b34801561067c575f80fd5b50601d5461046a565b348015610690575f80fd5b5061046a61069f366004615926565b6115a1565b3480156106af575f80fd5b5061046a6106be366004615926565b6001600160a01b03165f9081526025602052604090205490565b3480156106e3575f80fd5b5061046a6106f236600461585c565b5f908152600d602052604090205490565b34801561070e575f80fd5b5060105461046a565b348015610722575f80fd5b506104e961073136600461574c565b6115b9565b348015610741575f80fd5b5060405160128152602001610474565b34801561075c575f80fd5b5061051861076b36600461593f565b611638565b34801561077b575f80fd5b5061046a61078a36600461574c565b611666565b34801561079a575f80fd5b506105186107a936600461585c565b61169d565b3480156107b9575f80fd5b506105186107c8366004615926565b6116da565b3480156107d8575f80fd5b506105186107e736600461585c565b611757565b3480156107f7575f80fd5b506105186117db565b34801561080b575f80fd5b5061046a61081a36600461585c565b5f9081526009602052604090205490565b348015610836575f80fd5b50600e5461046a565b34801561084a575f80fd5b5061046a61085936600461585c565b5f9081526027602052604090205490565b348015610875575f80fd5b5061046a610884366004615926565b6118b9565b348015610894575f80fd5b5061046a6108a3366004615893565b6001600160a01b039182165f908152602e6020908152604080832093909416825291909152205490565b3480156108d8575f80fd5b5060235461046a565b3480156108ec575f80fd5b5061046a6108fb366004615926565b611921565b34801561090b575f80fd5b5061051861091a36600461585c565b611940565b34801561092a575f80fd5b5061046a610939366004615893565b6001600160a01b039182165f908152602f6020908152604080832093909416825291909152205490565b610518610971366004615873565b61198b565b348015610981575f80fd5b5061046a611a78565b348015610995575f80fd5b5061046a611a8f565b3480156109a9575f80fd5b5061046a6109b8366004615926565b611aa5565b3480156109c8575f80fd5b506109dc6109d7366004615873565b611abf565b60408051928352602083019190915201610474565b3480156109fc575f80fd5b50610518611ae2565b348015610a10575f80fd5b50610518611af3565b348015610a24575f80fd5b5060195461046a565b348015610a38575f80fd5b50610518610a4736600461593f565b611b1e565b348015610a57575f80fd5b50610518610a6636600461574c565b611b3b565b348015610a76575f80fd5b50610518610a85366004615926565b611b55565b348015610a95575f80fd5b50610518611ba6565b348015610aa9575f80fd5b5061046a611bcb565b348015610abd575f80fd5b50610ad1610acc366004615926565b611be2565b604051610474919061598b565b348015610ae9575f80fd5b506104e9610af836600461574c565b611ce8565b348015610b08575f80fd5b5060185461046a565b348015610b1c575f80fd5b506109dc610b2b36600461574c565b611d67565b610518610b3e3660046159ee565b611daa565b348015610b4e575f80fd5b5060135461046a565b348015610b62575f80fd5b50610b6b611ed8565b6040516104749190615a35565b348015610b83575f80fd5b506104bd611ee8565b348015610b97575f80fd5b50610518610ba6366004615a48565b611ef7565b348015610bb6575f80fd5b5061046a610bc5366004615926565b611f24565b348015610bd5575f80fd5b50601a5461046a565b348015610be9575f80fd5b50610518610bf8366004615a48565b611f5d565b348015610c08575f80fd5b50602d54600160601b900460ff16610b6b565b348015610c26575f80fd5b506104e9610c3536600461574c565b611f7a565b348015610c45575f80fd5b5061046a611f87565b348015610c59575f80fd5b5061046a610c6836600461585c565b611f98565b348015610c78575f80fd5b50602d546001600160581b031661046a565b348015610c95575f80fd5b50610518611fa9565b348015610ca9575f80fd5b50601c5461046a565b348015610cbd575f80fd5b5060175461046a565b348015610cd1575f80fd5b50610518610ce036600461585c565b611fe2565b348015610cf0575f80fd5b50610518612000565b348015610d04575f80fd5b50601b5461046a565b348015610d18575f80fd5b5061046a610d27366004615926565b6001600160a01b03165f9081526014602052604090205490565b348015610d4c575f80fd5b50610d60610d5b36600461574c565b612026565b6040516104749190615b69565b348015610d78575f80fd5b504261046a565b348015610d8a575f80fd5b5061046a610d99366004615893565b612128565b348015610da9575f80fd5b5060125461046a565b348015610dbd575f80fd5b5061046a610dcc366004615926565b612152565b348015610ddc575f80fd5b507f00000000000000000000000000000000000000000000000000000000653cb50b61046a565b348015610e0e575f80fd5b506105186121f4565b348015610e22575f80fd5b5061046a610e31366004615926565b61229b565b348015610e41575f80fd5b5061046a6122b5565b348015610e55575f80fd5b50610518610e6436600461574c565b6122cb565b348015610e74575f80fd5b50610518610e83366004615926565b6122f9565b348015610e93575f80fd5b5060085463ffffffff1661046a565b348015610ead575f80fd5b50600f5461046a565b348015610ec1575f80fd5b5061051861230a565b348015610ed5575f80fd5b5061046a610ee4366004615926565b612327565b348015610ef4575f80fd5b506007546001600160481b031661046a565b348015610f11575f80fd5b5061046a610f2036600461585c565b5f9081526029602052604090205490565b348015610f3c575f80fd5b50610f50610f4b366004615926565b612341565b6040516104749190615b78565b600854600160201b900463ffffffff1690565b610f78615667565b6001600160a01b0383165f908152601f60209081526040808320858452825280832054835281805291829020825160c08101845281546001600160981b0316815260018201546001600160801b0381169382019390935261ffff600160801b8404169381019390935265ffffffffffff600160901b830481166060850152600160c01b83041660808401529060a083019060ff600160f01b90910416600281111561102557611025615774565b600281111561103657611036615774565b90525090505b92915050565b60606003805461105190615bdb565b80601f016020809104026020016040519081016040528092919081815260200182805461107d90615bdb565b80156110c85780601f1061109f576101008083540402835291602001916110c8565b820191905f5260205f20905b8154815290600101906020018083116110ab57829003601f168201915b5050505050905090565b5f336110df818585612450565b5060019392505050565b6110f1612578565b6110f9612835565b6111213361111c338461110b60065490565b60016003611117611ed8565b61288e565b612b0f565b61112b6001600555565b50565b611136612578565b61113e612835565b8161114833611aa5565b1015611167576040516376f2de6d60e11b815260040160405180910390fd5b6111713383612bb9565b6111a23361119d33858561118d6007546001600160481b031690565b600654611198611ed8565b612cd6565b612f9f565b6111ac6001600555565b5050565b6111b8612578565b565b6111c2612835565b6111ca612578565b8015806111d75750606481115b156111f55760405163d487a0df60e01b815260040160405180910390fd5b6103e88161120233610d27565b61120c9190615c21565b111561122b5760405163f3d1ae6760e01b815260040160405180910390fd5b61126c3384846112396122b5565b60085463ffffffff1661124a610f5d565b611253336118b9565b886112678c6001611262611a8f565b613230565b61325a565b61127683826132d7565b6112806001600555565b505050565b5f80611291601c611f98565b61129c906001615c21565b5f8181526027602052604090205490915080156112eb5780670de0b6b3a76400006112c733856133a8565b6112d2906064615c34565b6112dc9190615c34565b6112e69190615c4b565b6112ed565b5f5b9250505090565b6112fc612578565b611304612835565b5f61130e60195490565b60185461131b9190615c6a565b9050600181101561133f576040516394d33ebf60e01b815260040160405180910390fd5b602c545f9081908190600160a01b90046001600160581b03161561136d576113656133cf565b919450925090505b5f61137760065490565b90505f600161138860088885613642565b600181111561139957611399615774565b1480156113b657505f8160018111156113b4576113b4615774565b145b6113c057806113c5565b506001805b5060016113d4601c8885613642565b60018111156113e5576113e5615774565b14801561140257505f81600181111561140057611400615774565b145b61140c5780611411565b506001805b506001611420605a8885613642565b600181111561143157611431615774565b14801561144e57505f81600181111561144c5761144c615774565b145b611458578061145d565b506001805b50600161146d6101718885613642565b600181111561147e5761147e615774565b14801561149b57505f81600181111561149957611499615774565b145b6114a557806114aa565b506001805b5060016114ba6103788885613642565b60018111156114cb576114cb615774565b1480156114e857505f8160018111156114e6576114e6615774565b145b6114f257806114f7565b506001805b50600181600181111561150c5761150c615774565b03611538575f61151a611ed8565b600181111561152b5761152b615774565b0361153857611538613738565b841561154957611549858585613752565b5050505050506111b86001600555565b5f601054600f54600e5461156d9190615c6a565b6115779190615c6a565b905090565b5f33611589858285613788565b6115948585856137fa565b60019150505b9392505050565b5f6115af82601c6001613989565b5091949350505050565b5f6001600160a01b0383166115e15760405163f43167df60e01b815260040160405180910390fd5b335f818152602e602090815260408083206001600160a01b038816808552925280832086905551859391927ff8e109bcddf5e12132b7cd8a8517d97498f50c7ac595874d6f513243098b079891a450600192915050565b611640612578565b611648612835565b6116558585858585613b7f565b61165f6001600555565b5050505050565b6001600160a01b03919091165f908152600c602090815260408083209383529290522054600160601b90046001600160601b031690565b6116a5612578565b6116ad612835565b611121335f6116be33856001613bf5565b6116c8601c611f98565b6116d3906001615c21565b6001613e24565b602b546001600160a01b0316336001600160a01b03161461170e5760405163060e508760e31b815260040160405180910390fd5b6001600160a01b0381166117355760405163f43167df60e01b815260040160405180910390fd5b602b80546001600160a01b0319166001600160a01b0392909216919091179055565b61175f612578565b611767612835565b805f0361178757604051631c95685960e21b815260040160405180910390fd5b8061179133611aa5565b10156117b0576040516376f2de6d60e11b815260040160405180910390fd5b6117ba3382612bb9565b611121335f836117ca601c611f98565b6117d5906001615c21565b5f613e24565b6117e3612578565b6117eb612835565b5f6117f760085f613f8d565b9050611804601c5f613f8d565b61180e9082615c21565b905061181b605a5f613f8d565b6118259082615c21565b90506118336101715f613f8d565b61183d9082615c21565b905061184b6103785f613f8d565b6118559082615c21565b9050805f0361187757604051635d0fdef160e01b815260040160405180910390fd5b611882335b82613ffa565b604051819033907f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241905f90a3506111b86001600555565b5f806118c48361229b565b9050805f036118d557505f92915050565b680204fce5e3e2502611601f1b81106118f85750676f05b59d3b20000092915050565b680204fce5e3e2502611601f1b61191782676f05b59d3b200000615c34565b61159a9190615c4b565b5f61103c82611930601c611f98565b61193b906001615c21565b6133a8565b611948612578565b611950612835565b611121335f61196f338561196360065490565b60026003611117611ed8565b611979601c611f98565b611984906001615c21565b6002613e24565b611993612835565b61199b612578565b6103e86119a733610d27565b6119b2906001615c21565b11156119d15760405163f3d1ae6760e01b815260040160405180910390fd5b5f826119dc60135490565b6119e69190615c21565b90505f6119f2600e5490565b6119fd906001615c21565b90505f611a3d338686611a0e6122b5565b60085463ffffffff16611a1f610f5d565b611a28336118b9565b8a8a611a388f6001611262611a8f565b614091565b601154611a4a9190615c21565b9050611a60828483600e92909255601355601155565b611a6b8560016132d7565b5050506111ac6001600555565b5f611a82601b5490565b6012546115779190615c21565b600754600160481b90046001600160401b031690565b6001600160a01b03165f9081526020819052604090205490565b5f918252600b602090815260408084209284529190529020600181015490549091565b611aea6143a1565b6111b85f6143cc565b611afb612578565b611b03612835565b611b14611b0f336143ee565b614607565b6111b86001600555565b611b26612578565b611b2e612835565b611655858585858561463a565b611b43612578565b611b4b612835565b6111a28282614669565b611b5d6143a1565b6001600160a01b038116611b845760405163f43167df60e01b815260040160405180910390fd5b602c80546001600160a01b0319166001600160a01b0392909216919091179055565b611bae6143a1565b602d80546001919060ff60601b1916600160601b835b0217905550565b5f611bd5601c5490565b6017546115779190615c6a565b6001600160a01b0381165f908152601e6020526040812054606091816001600160401b03811115611c1557611c15615c7d565b604051908082528060200260200182016040528015611c4e57816020015b611c3b61569c565b815260200190600190039081611c335790505b50905060015b828111611ce057604080516060810182528281526001600160a01b0387165f908152601f6020908152838220858352815290839020546001600160801b031690820152908101611ca48784610f70565b905282611cb2600184615c6a565b81518110611cc257611cc2615c91565b60200260200101819052508080611cd890615ca5565b915050611c54565b509392505050565b5f6001600160a01b038316611d105760405163f43167df60e01b815260040160405180910390fd5b335f818152602f602090815260408083206001600160a01b038816808552925280832086905551859391927fd508e6bf29a4128e58df993e4fe1db1d926db54e85247bc919df2c52eb78212591a450600192915050565b6001600160a01b03919091165f908152600c6020908152604080832093835292905220546001600160601b03811691600160c01b9091046001600160401b031690565b611db2612835565b611dba612578565b815f03611dda5760405163a87b21b760e01b815260040160405180910390fd5b83831080611de6575083155b80611df2575061011883115b15611e10576040516349e092bf60e01b815260040160405180910390fd5b5f611e1d858585856146ba565b9050801580611e2c5750606481115b15611e4a5760405163d487a0df60e01b815260040160405180910390fd5b6103e881611e5733610d27565b611e619190615c21565b1115611e805760405163f3d1ae6760e01b815260040160405180910390fd5b5f611e8f876001611262611a8f565b9050611ec2338888888888611ea26122b5565b60085463ffffffff16611eb3610f5d565b611ebc336118b9565b8b6146f7565b611ecc87836132d7565b505061165f6001600555565b600854600160401b900460ff1690565b60606004805461105190615bdb565b611eff612578565b611f07612835565b611f14848484843361463a565b611f1e6001600555565b50505050565b6001600160a01b0381165f90815260226020526040812081611f4584612327565b81526020019081526020015f20600101549050919050565b611f65612578565b611f6d612835565b611f148484848433613b7f565b5f336110df8185856137fa565b5f6019546018546115779190615c6a565b5f908152600a602052604090205490565b611fb1612578565b611fb9612835565b5f805f611fc46133cf565b925092509250611fd5838383613752565b5050506111b86001600555565b611fea612578565b611ff2612835565b611121611b0f33835f613bf5565b612008612578565b602c546111b8906001600160a01b031661202181611aa5565b612bb9565b61202e6156bb565b6001600160a01b0383165f90815260156020908152604080832085845282528083205483526016825291829020825161014081018452815460ff808216835261010080830461ffff1695840195909552630100000082046001600160601b031695830195909552600160781b810465ffffffffffff9081166060840152600160a81b8204166080830152600160d81b900463ffffffff90811660a0830152600183015490811660c0830152600160201b81046001600160801b031660e0830152600160a01b81046001600160401b031693820193909352929091610120840191600160e01b90910416600281111561102557611025615774565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b5f806121608360085f613989565b50919250612172915082905083615c21565b915061218083601c5f613989565b50919250612192915082905083615c21565b91506121a083605a5f613989565b509192506121b2915082905083615c21565b91506121c1836101715f613989565b509192506121d3915082905083615c21565b91506121e2836103785f613989565b5091925061159a915082905083615c21565b602c546001600160a01b0316336001600160a01b0316146122285760405163060e508760e31b815260040160405180910390fd5b6001602d54600160581b900460ff16600181111561224857612248615774565b03612266576040516304f0282f60e21b815260040160405180910390fd5b602d805460ff60581b1916600160581b179055602c546111b8906001600160a01b0316680a18f07d736b90be55601d1b612b0f565b6001600160a01b03165f9081526024602052604090205490565b600754600160881b90046001600160601b031690565b6122d3612578565b6122db612835565b6111a28261111c84846122ed60065490565b60016004611117611ed8565b6123016143a1565b61112b816143cc565b612312612578565b61231a612835565b5f611855601c6001613f8d565b6001600160a01b03165f9081526021602052604090205490565b6001600160a01b0381165f90815260146020526040902054606090806001600160401b0381111561237457612374615c7d565b6040519080825280602002602001820160405280156123ad57816020015b61239a61570c565b8152602001906001900390816123925790505b50915060015b81811161244957604080516080810182528281526001600160a01b0386165f9081526015602090815283822085835280825284832080548386015292869052905260010154918101919091526060810161240d8684612026565b90528361241b600184615c6a565b8151811061242b5761242b615c91565b6020026020010181905250808061244190615ca5565b9150506123b3565b5050919050565b6001600160a01b0383166124b75760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084015b60405180910390fd5b6001600160a01b0382166125185760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016124ae565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6006545f620151806125aa7f00000000000000000000000000000000000000000000000000000000653cb50b42615c6a565b6125b49190615c4b565b6125bf906001615c21565b9050818111156111ac57600754600854600160481b82046001600160401b0316916001600160481b03811691600160881b9091046001600160601b03169063ffffffff80821691600160201b9004165f6126198888615c6a565b90505f5b818110156127905761271061263461271889615c34565b61263e9190615c4b565b965061271061264f61271388615c34565b6126599190615c4b565b955061271061266a6126ed87615c34565b6126749190615c4b565b94506127106126856126ed86615c34565b61268f9190615c4b565b9350670de0b6b3a76400008711156126ad57670de0b6b3a764000096505b6897c9ce4cf6d5c000008611156126cb576897c9ce4cf6d5c0000095505b682b5e3af16b188000008510156126e957682b5e3af16b1880000094505b6126f66103e86023615c34565b84101561270d5761270a6103e86023615c34565b93505b61015e881161272957612722616f9b84615c6a565b925061272d565b5f92505b85876127388b615ca5565b6040805189815260208101899052908101879052909b508b907fbfb08f20cf5a7f453097ba3bef35d62a510a1e9b58c8606dbd878334057589ac9060600160405180910390a48061278881615ca5565b91505061261d565b50600780546001600160601b038616600160881b02600167ffffffffffffffff60481b01600160e81b03196001600160401b038a16600160481b02166001600160e81b0319909216919091176001600160481b038816171790556008805463ffffffff848116600160201b0267ffffffffffffffff19909216908616171780825560068990555f919060ff60401b1916600160401b8302179055505050505050505050565b6002600554036128875760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016124ae565b6002600555565b6001600160a01b0386165f908152601f602090815260408083208884529091528120548082036128d157604051635ac2068d60e01b815260040160405180910390fd5b5f81815260208080526040808320815160c08101835281546001600160981b0316815260018201546001600160801b0381169482019490945261ffff600160801b8504169281019290925265ffffffffffff600160901b840481166060840152600160c01b8404166080830152909160a083019060ff600160f01b90910416600281111561296157612961615774565b600281111561297257612972615774565b905250905060018160a00151600281111561298f5761298f615774565b036129ad5760405163698e0d2960e01b815260040160405180910390fd5b60028160a0015160028111156129c5576129c5615774565b036129e3576040516337b7c87160e01b815260040160405180910390fd5b60048560048111156129f7576129f7615774565b148015612a0f5750806080015165ffffffffffff1642105b15612a2d57604051633ed019ef60e11b815260040160405180910390fd5b5f81602001516001600160801b03169050612a588a82845f01516001600160981b03168b898c614786565b506001876004811115612a6d57612a6d615774565b03612aa957601c5f8154612a8090615ca5565b909155505f8381526020805260409020600101805460ff60f01b1916600160f01b179055612af5565b6002876004811115612abd57612abd615774565b03612af557601d5f8154612ad090615ca5565b909155505f8381526020805260409020600101805460ff60f01b1916600160f11b1790555b612b018a84848a614932565b9a9950505050505050505050565b6001600160a01b038216612b655760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016124ae565b8060025f828254612b769190615c21565b90915550506001600160a01b0382165f81815260208181526040808320805486019055518481525f80516020615db4833981519152910160405180910390a35050565b6001600160a01b038216612c195760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016124ae565b6001600160a01b0382165f9081526020819052604090205481811015612c8c5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016124ae565b6001600160a01b0383165f818152602081815260408083208686039055600280548790039055518581529192915f80516020615db4833981519152910160405180910390a3505050565b6001600160a01b0386165f908152601e6020526040812080548291908290612cfd90615ca5565b918290555090506103e8811115612d2757604051632848b67960e01b815260040160405180910390fd5b601c861080612d375750610dac86115b15612d55576040516304b6f31d60e41b815260040160405180910390fd5b5f612d618888886149f8565b90506001612d77670de0b6b3a764000083615c4b565b1015612d9657604051632f41466b60e11b815260040160405180910390fd5b5f60175f8154612da590615ca5565b918290555090505f612dba620151808a615c34565b612dc49042615c21565b90505f6040518060c001604052808c6001600160981b03168152602001856001600160801b031681526020018b61ffff1681526020014265ffffffffffff1681526020018365ffffffffffff1681526020015f6002811115612e2857612e28615774565b90526001600160a01b038d165f908152601f60209081526040808320898452825280832087905586835281805291829020835181546001600160981b0319166001600160981b039091161781559083015160018201805493850151606086015160808701516001600160801b039094166001600160901b031990961695909517600160801b61ffff9092169190910217600160901b600160f01b031916600160901b65ffffffffffff9586160265ffffffffffff60c01b191617600160c01b94909216939093021780835560a0840151939450849391929060ff60f01b1916600160f01b836002811115612f1e57612f1e615774565b0217905550905050612f348c858d8b8b5f614786565b955080604051612f449190615cbd565b6040518091039020838d6001600160a01b03167fecd17a550d3024bd4dcec573e568e747e7843155893d1926213c848215a0d0298d604051612f8891815260200190565b60405180910390a450505050509695505050505050565b806001036111ac5760085f52600a6020527f2c1fd36ba11b13b555f58753742999069764391f450ca8727fe8a3eeffe6777554156111ac5760085f52600a6020527f2c1fd36ba11b13b555f58753742999069764391f450ca8727fe8a3eeffe677755461300d906001615c21565b6001600160a01b0383165f908152600c60209081526040808320600884528252822080546001600160601b0319166001600160601b039490941693909317909255601c9052600a90527f964ea767231031507a3f70c59b06c72a2054875e2bc2938da2a55d8f6cb774eb54613083906001615c21565b6001600160a01b0383165f908152600c60209081526040808320601c84528252822080546001600160601b0319166001600160601b039490941693909317909255605a9052600a90527f7f87218992b43f7ec59f3c8fd242b6759bfedfc613fdc2676bc53b4637f8f351546130f9906001615c21565b6001600160a01b0383165f908152600c60209081526040808320605a84528252822080546001600160601b0319166001600160601b0394909416939093179092556101719052600a90527fb03a258bbb90d8d1843170969b808b3100da20cb067e31b0b691b6f43141902e54613170906001615c21565b6001600160a01b0383165f908152600c6020908152604080832061017184528252822080546001600160601b0319166001600160601b0394909416939093179092556103789052600a90527fb65719cf4862d40ddcfbadca8d587b82e645261e95d3c4e28fef5a0d6eefb6d6546131e8906001615c21565b6001600160a01b0383165f908152600c602090815260408083206103788452909152902080546001600160601b03929092166001600160601b03199092169190911790555050565b5f60648361323e8685615c34565b6132489190615c34565b6132529190615c4b565b949350505050565b601354600e546011545f5b858110156132b4576132778c85615c21565b93506132968d8d8d8d8d8d8d8b61328d8c615ca5565b9b508b8e614091565b6132a09083615c21565b9150806132ac81615ca5565b915050613265565b506132c9828483600e92909255601355601155565b505050505050505050505050565b5f6132e58383611262611a8f565b9050803410156133085760405163110a614b60e31b815260040160405180910390fd5b5f81602c60148282829054906101000a90046001600160581b031661332d9190615d26565b92506101000a8154816001600160581b0302191690836001600160581b03160217905550813461335d9190615c6a565b9050801561336e5761336e3361187c565b8161337860065490565b60405133907fd833e83f161e4ddfb1306cdf11a374a0a23393f008f9394b85999b988c232e36905f90a450505050565b6001600160a01b03919091165f908152602860209081526040808320938352929052205490565b602c545f9081908190600160a01b90046001600160581b031680820361340857604051638b50f3bf60e01b815260040160405180910390fd5b602c8054600160a01b600160f81b0319169055604051819033907f55083a582b32208b745a21c8ce4f8d545be8cce1437f34637f08fc9d943eacb0905f90a3620f4240613457610ce483615c34565b6134619190615c4b565b935061346d8482615c6a565b905061271061347e61183883615c34565b6134889190615c4b565b92505f61271061349a6102bc84615c34565b6134a49190615c4b565b90506127106134b561012c84615c34565b6134bf9190615c4b565b92505f83826134ce8786615c6a565b6134d89190615c6a565b6134e29190615c6a565b90506001602d54600160601b900460ff16600181111561350457613504615774565b0361354f57602d80548391905f906135269084906001600160581b0316615d26565b92506101000a8154816001600160581b0302191690836001600160581b0316021790555061355c565b6135598286615c21565b94505b801561363a575f612710613572610af084615c34565b61357c9190615c4b565b90505f61271061358e610af085615c34565b6135989190615c4b565b90505f6127106135aa61070886615c34565b6135b49190615c4b565b90505f6127106135c661070887615c34565b6135d09190615c4b565b90506135dd600885614a46565b6135e8601c84614a46565b6135f3605a83614a46565b6135ff61017182614a46565b613635610378828486613612898b615c6a565b61361c9190615c6a565b6136269190615c6a565b6136309190615c6a565b614a46565b505050505b505050909192565b5f838152600d602052604081205482101561365e57505f61159a565b61366784614a6c565b5f8481526009602052604081205490819003613686575f91505061159a565b5f613692868387614ad5565b5f81815260276020526040812054919250601c881480156136b257508115155b156136e55750602d546001600160581b031680156136e557602d80546001600160581b03191690556136e5838284614b4e565b8388336001600160a01b03167fb0500ae1b0ee26fc5050483f49228da1236cb641eb890348119ae5abbfd6ab948460405161372291815260200190565b60405180910390a4506001979650505050505050565b600880546001919060ff60401b1916600160401b83611bc4565b61375c3384613ffa565b602b54613772906001600160a01b031682613ffa565b602c54611280906001600160a01b031683613ffa565b5f6137938484612128565b90505f198114611f1e57818110156137ed5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016124ae565b611f1e8484848403612450565b6001600160a01b03831661385e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016124ae565b6001600160a01b0382166138c05760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016124ae565b6001600160a01b0383165f90815260208190526040902054818110156139375760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016124ae565b6001600160a01b038481165f81815260208181526040808320878703905593871680835291849020805487019055925185815290925f80516020615db4833981519152910160405180910390a3611f1e565b5f805f805f61399787611f98565b90505f8660018111156139ac576139ac615774565b03613ac8576139bb8888611d67565b90945092505f6139ca89612327565b9050845b828111613ac1575f806139e18b84611abf565b90925090505f875b858111613a60576001600160a01b038e165f9081526022602090815260408083208484529091529020548310613a46576001600160a01b038e165f9081526022602090815260408083208484529091529020600101549150613a4b565b613a60565b97508780613a5881615ca5565b9150506139e9565b508215801590613a6f57508015155b15613a9e57670de0b6b3a7640000613a878483615c34565b613a919190615c4b565b613a9b908b615c21565b99505b613aa9846001615c21565b98505050508080613ab990615ca5565b9150506139ce565b5050613b75565b601c87148015613ae957506001866001811115613ae757613ae7615774565b145b15613b7557613af88888611666565b9150815b818111613b73575f8181526029602052604081205490819003613b1f575f613b46565b670de0b6b3a7640000613b328b846133a8565b613b3c9083615c34565b613b469190615c4b565b613b509088615c21565b9650613b5d826001615c21565b9350508080613b6b90615ca5565b915050613afc565b505b5093509350935093565b835f03613b9f57604051631c95685960e21b815260040160405180910390fd5b83613ba986611aa5565b1015613bc8576040516376f2de6d60e11b815260040160405180910390fd5b613bd3853386613788565b613bdd8383614b81565b613be78585612bb9565b61165f85858585855f614c9d565b6001600160a01b0383165f90815260156020908152604080832085845290915281208054600190910154818303613c3f5760405163ca288b0560e01b815260040160405180910390fd5b5f828152601660209081526040808320815161014081018352815460ff808216835261010080830461ffff1696840196909652630100000082046001600160601b031694830194909452600160781b810465ffffffffffff9081166060840152600160a81b8204166080830152600160d81b900463ffffffff90811660a0830152600183015490811660c0830152600160201b81046001600160801b031660e0830152600160a01b81046001600160401b031694820194909452929091610120840191600160e01b9004166002811115613d1b57613d1b615774565b6002811115613d2c57613d2c615774565b905250905060018161012001516002811115613d4a57613d4a615774565b03613d685760405163231cb75560e11b815260040160405180910390fd5b60028161012001516002811115613d8157613d81615774565b03613d9f57604051630382986760e61b815260040160405180910390fd5b42816080015165ffffffffffff16118015613dca57505f856001811115613dc857613dc8615774565b145b15613de85760405163305aa66560e21b815260040160405180910390fd5b80604001516001600160601b031660115f828254613e069190615c6a565b90915550613e1990508784848489614dd8565b979650505050505050565b6001600160a01b0385165f9081526024602052604081208054859290613e4b908490615c21565b925050819055508260235f828254613e639190615c21565b90915550505f8281526027602052604081208054859290613e85908490615c21565b90915550506001600160a01b0385165f90815260286020908152604080832085845290915281208054859290613ebc908490615c21565b90915550506001600160a01b03841615613f38576001600160a01b0384165f9081526025602052604081208054859290613ef7908490615c21565b90915550506001600160a01b038085165f90815260266020908152604080832093891683529290529081208054859290613f32908490615c21565b90915550505b81846001600160a01b0316866001600160a01b03167fa85336de4209a315f96a1cc9bc4a8c97cf271e2ec65bf17950058af934ba96528685604051613f7e929190615d4d565b60405180910390a45050505050565b5f80808080613f9d338888613989565b929650909450925090505f866001811115613fba57613fba615774565b03613fcb57613fcb33888585615025565b6001866001811115613fdf57613fdf615774565b03613fef57613fef338883615114565b509195945050505050565b6001600160a01b0382166140215760405163f43167df60e01b815260040160405180910390fd5b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f811461406a576040519150601f19603f3d011682016040523d82523d5f602084013e61406f565b606091505b5050905080611280576040516335abd07f60e01b815260040160405180910390fd5b5f8815806140a0575061011889115b156140be57604051636b47aabb60e11b815260040160405180910390fd5b8915806140cb575060648a115b156140e957604051637eece1ff60e11b815260040160405180910390fd5b6140f68a8a8a8989615198565b90505f6040518061014001604052808c60ff1681526020018b61ffff168152602001836001600160601b031681526020014265ffffffffffff168152602001620151808c6141449190615c34565b61414e9042615c21565b65ffffffffffff16815263ffffffff808b166020830152891660408201525f606082018190526001600160401b038616608083015260a0909101526001600160a01b038d165f9081526014602052604081208054929350909182906141b290615ca5565b91829055506001600160a01b038e165f908152601560209081526040808320848452825280832089815560019081018b90558984526016835292819020865181549388015192880151606089015160808a015160a08b015160ff90941662ffffff199097169690961761010061ffff9096168602176301000000600160a81b03191663010000006001600160601b039093169290920265ffffffffffff60781b191691909117600160781b65ffffffffffff9283160217600160a81b600160f81b031916600160a81b919095160263ffffffff60d81b191693909317600160d81b63ffffffff9485160217815560c0870151938101805460e089015193890151959094166001600160a01b031990941693909317600160201b6001600160801b03909316929092029190911767ffffffffffffffff60a01b198116600160a01b6001600160401b0390951694909402938417835561012087015194955086949193919291600160a01b600160e81b031990911660ff60e01b1990911617600160e01b83600281111561434657614346615774565b021790555090505085858e6001600160a01b03167f2109b8587b0ddbd9adf8ec24ce76bef548f2aee7aac34bc6aa0bb51b7cba9d67856040516143899190615b69565b60405180910390a450509a9950505050505050505050565b602a546001600160a01b031633146111b857604051630406091960e41b815260040160405180910390fd5b602a80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381165f908152601460205260408120548180806144116156bb565b60015b8581116145e5576001600160a01b0388165f9081526015602090815260408083208484528252808320548084526016835292819020815161014081018352815460ff808216835261010080830461ffff1696840196909652630100000082046001600160601b031694830194909452600160781b810465ffffffffffff9081166060840152600160a81b8204166080830152600160d81b900463ffffffff90811660a0830152600183015490811660c0830152600160201b81046001600160801b031660e0830152600160a01b81046001600160401b03169482019490945293975091610120840191600160e01b90910416600281111561451757614517615774565b600281111561452857614528615774565b90525091505f826101200151600281111561454557614545615774565b14801561455e5750816080015165ffffffffffff164210155b156145cb576001600160a01b0388165f908152601560209081526040808320848452909152812060010154614598918a9187918690614dd8565b6145a29088615c21565b965081604001516001600160601b0316836145bd9190615c21565b92506145c885615ca5565b94505b606485146145e557806145dd81615ca5565b915050614414565b508160115f8282546145f79190615c6a565b9091555095979650505050505050565b6146113382612b0f565b602b5461112b906001600160a01b031661271061463084610320615c34565b61111c9190615c4b565b61464385615274565b61464d8383614b81565b61165f8561465f878761196360065490565b8585856002614c9d565b614672826152f6565b61467c5f80614b81565b5f61468983836001613bf5565b602b549091506146ab906001600160a01b031661271061463084610320615c34565b61128083825f80336001614c9d565b5f848411156132525781836146cf8787615c6a565b6146d99190615c4b565b6146e4906001615c21565b6146ee9190615c34565b95945050505050565b601354600e546011545b8a8c11614762575f5b898110156147505761471c8e85615c21565b93506147328f8f8f8c8c8c8c8b61328d8c615ca5565b61473c9083615c21565b91508061474881615ca5565b91505061470a565b5061475b8a8d615c21565b9b50614701565b614776828483600e92909255601355601155565b5050505050505050505050505050565b6001600160a01b0386165f9081526021602090815260408083205460228352818420818552909252822060010154828460048111156147c7576147c7615774565b0361484e57815f036147d857600192505b6147e28882615c21565b6001600160a01b038a165f9081526022602052604081209061480385615ca5565b94508481526020019081526020015f20600101819055508760185f82825461482b9190615c21565b9250508190555086601a5f8282546148439190615c21565b909155506148bf9050565b6148588882615c6a565b6001600160a01b038a165f9081526022602052604081209061487985615ca5565b94508481526020019081526020015f20600101819055508760195f8282546148a19190615c21565b9250508190555086601a5f8282546148b99190615c6a565b90915550505b5f8560018111156148d2576148d2615774565b146148e7576148e2866001615c21565b6148e9565b855b6001600160a01b039099165f81815260226020908152604080832086845282528083206001600160801b039d909d16909c55918152602190915298909820559695505050505050565b5f80835f01516001600160981b031690505f614968856060015165ffffffffffff16866080015165ffffffffffff164287615349565b90505f60646149778385615c34565b6149819190615c4b565b905061498d8184615c6a565b935080601b5f8282546149a09190615c21565b90915550506040805185815260208101839052839189916001600160a01b038c16917f971d9ff3287b3ba75194105e7281e55c93b0a89cad9915664bb3fd9211f8d5f1910160405180910390a4505050949350505050565b5f8364174876e800614a0a828661542c565b614a149083615c34565b614a1e9190615c4b565b614a289082615c21565b9050614a3c670de0b6b3a764000084615c4b565b6146ee9082615c4b565b5f8281526009602052604081208054839290614a63908490615c21565b90915550505050565b5f818152600d60205260409020546006548181106112805782614a8f8383615c6a565b614a999190615c4b565b614aa4906001615c21565b614aae9084615c34565b5f848152600d602052604081208054909190614acb908490615c21565b9091555050505050565b5f838152600960209081526040808320839055600a909152812080548290614afc90615ca5565b9182905550905081614b16670de0b6b3a764000085615c34565b614b209190615c4b565b5f948552600b6020908152604080872084885290915290942060018101949094556006549093555090919050565b80614b61670de0b6b3a764000084615c34565b614b6b9190615c4b565b5f93845260296020526040909320929092555050565b6008614b8d8383615c21565b1115614bac576040516384c175bf60e01b815260040160405180910390fd5b6040516301ffc9a760e01b80825233916301ffc9a791614bce91600401615d6a565b602060405180830381865afa158015614be9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614c0d9190615d7f565b1580614c7f57506040516301ffc9a760e01b815233906301ffc9a790614c3e906311686e4b60e21b90600401615d6a565b602060405180830381865afa158015614c59573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614c7d9190615d7f565b155b156111ac5760405163272a45df60e11b815260040160405180910390fd5b5f614ca8601c611f98565b614cb3906001615c21565b9050614cbe8761229b565b5f03614cd057614cd087601c83615114565b614cdd8733888486613e24565b5f808515614d1657614cf26127106064615c34565b612710614cff888b615c34565b614d099190615c34565b614d139190615c4b565b91505b8615614d4d57614d296127106064615c34565b612710614d36898b615c34565b614d409190615c34565b614d4a9190615c4b565b90505b8115614d5d57614d5d8583612b0f565b8015614d6d57614d6d8982612b0f565b336040516311686e4b60e21b81526001600160a01b038b81166004830152602482018b905291909116906345a1b92c906044015f604051808303815f87803b158015614db7575f80fd5b505af1158015614dc9573d5f803e3d5ffd5b50505050505050505050505050565b5f80826001811115614dec57614dec615774565b03614e13575f858152601660205260409020600101805460ff60e01b1916600160e01b1790555b6001826001811115614e2757614e27615774565b03614e4e575f858152601660205260409020600101805460ff60e01b1916600160e11b1790555b5f805f856080015165ffffffffffff16421115614e8857614e85866080015165ffffffffffff1642614e809190615c6a565b6154da565b91505b5f856001811115614e9b57614e9b615774565b03614ec157614ebe8660a0015163ffffffff16875f015160ff16896013546155ee565b90505b614ece6298968082615c4b565b86604001516001600160601b0316614ee69190615c21565b93506064614ef48386615c34565b614efe9190615c4b565b9250614f0a8385615c6a565b93505f856001811115614f1f57614f1f615774565b03614f3757600f5f8154614f3290615ca5565b909155505b6001856001811115614f4b57614f4b615774565b03614f635760105f8154614f5e90615ca5565b909155505b8215614f80578260125f828254614f7a9190615c21565b90915550505b5f856001811115614f9357614f93615774565b03614fcb575f8881526016602052604090206001018054600160201b600160a01b031916600160201b6001600160801b038716021790555b81888a6001600160a01b03167fbd866a3fbf35e201f790e87581b1afbb3165e879df5d35313a4875a70b9f3b368787604051615011929190918252602082015260400190565b60405180910390a450505095945050505050565b6001600160a01b0384165f908152600c602090815260408083208684529091529020546001600160601b03168214615093576001600160a01b0384165f908152600c60209081526040808320868452909152902080546001600160601b0319166001600160601b0384161790555b6001600160a01b0384165f908152600c60209081526040808320868452909152902054600160c01b90046001600160401b03168114611f1e576001600160a01b0384165f908152600c60209081526040808320868452909152902080546001600160401b038316600160c01b026001600160c01b0390911617905550505050565b6001600160a01b0383165f908152600c60209081526040808320858452909152902054600160601b90046001600160601b03168114611280576001600160a01b0383165f908152600c60209081526040808320858452909152902080546001600160601b038316600160601b02600160601b600160c01b0319909116179055505050565b5f80856151a58887615c34565b6151af9190615c34565b9050856001146151f3576127106151c7600188615c6a565b6151d2600b84615c34565b6151dc9190615c34565b6151e69190615c4b565b6151f09082615c6a565b90505b905080831561522d57620f4240606461520c8684615c34565b6152169190615c4b565b6152209190615c4b565b61522a9083615c21565b91505b821561526957670de0b6b3a764000060646152488584615c34565b6152529190615c4b565b61525c9190615c4b565b6152669083615c21565b91505b613e19606483615c4b565b5f61527f8233610939565b90505f1981146111ac57805f036152a9576040516333e8663d60e01b815260040160405180910390fd5b6001600160a01b0382165f908152602f6020526040812090335b6001600160a01b03166001600160a01b031681526020019081526020015f205f81546152ee90615d9e565b909155505050565b5f61530182336108a3565b90505f1981146111ac57805f0361532b576040516333e8663d60e01b815260040160405180910390fd5b6001600160a01b0382165f908152602e6020526040812090336152c3565b5f838311156153c1575f61535d8585615c6a565b90505f61536e620151806007615c34565b9050808211615381575f92505050613252565b6153b86201518061539c6153958486615c6a565b600161563a565b6153a69190615c4b565b6153b1906001615c21565b6063615650565b92505050613252565b60028260048111156153d5576153d5615774565b036153e157505f613252565b60026153ed8686615c6a565b6153f79190615c4b565b6154019086615c21565b42101561542157604051632146841d60e01b815260040160405180910390fd5b506032949350505050565b5f80610b4883111561544057610b48615442565b825b90505f61545c670de0b6b3a764000064174876e800615c34565b85111561547f5761547a670de0b6b3a764000064174876e800615c34565b615481565b845b905061549b670de0b6b3a764000065012309ce5400615c34565b6154aa64174876e80083615c34565b6154b49190615c4b565b6103396154c664174876e80085615c34565b6154d09190615c4b565b6146ee9190615c21565b5f6154e9620151806007615c34565b82116154f657505f919050565b6201518061550660076001615c21565b6155109190615c34565b821161551e57506001919050565b6201518061552e60076002615c21565b6155389190615c34565b821161554657506003919050565b6201518061555660076003615c21565b6155609190615c34565b821161556e57506008919050565b6201518061557e60076004615c21565b6155889190615c34565b821161559657506011919050565b620151806155a660076005615c21565b6155b09190615c34565b82116155be57506023919050565b620151806155ce60076006615c21565b6155d89190615c34565b82116155e657506048919050565b506063919050565b5f8282116155fd57505f613252565b6064670de0b6b3a76400006156128585615c6a565b61561c8789615c34565b6156269190615c34565b6156309190615c34565b6146ee9190615c4b565b5f8183111561564a57508161103c565b50919050565b5f8183111561566057508061103c565b5090919050565b6040805160c0810182525f8082526020820181905291810182905260608101829052608081018290529060a08201905b905290565b60405180606001604052805f81526020015f8152602001615697615667565b60408051610140810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290529061012082015290565b60405180608001604052805f81526020015f81526020015f81526020016156976156bb565b80356001600160a01b0381168114615747575f80fd5b919050565b5f806040838503121561575d575f80fd5b61576683615731565b946020939093013593505050565b634e487b7160e01b5f52602160045260245ffd5b6003811061112b5761112b615774565b80516001600160981b031682526020808201516001600160801b03169083015260408082015161ffff169083015260608082015165ffffffffffff908116918401919091526080808301519091169083015260a08101516157f881615788565b8060a0840152505050565b60c0810161103c8284615798565b5f6020808352835180828501525f5b8181101561583c57858101830151858201604001528201615820565b505f604082860101526040601f19601f8301168501019250505092915050565b5f6020828403121561586c575f80fd5b5035919050565b5f8060408385031215615884575f80fd5b50508035926020909101359150565b5f80604083850312156158a4575f80fd5b6158ad83615731565b91506158bb60208401615731565b90509250929050565b5f805f606084860312156158d6575f80fd5b505081359360208301359350604090920135919050565b5f805f606084860312156158ff575f80fd5b61590884615731565b925061591660208501615731565b9150604084013590509250925092565b5f60208284031215615936575f80fd5b61159a82615731565b5f805f805f60a08688031215615953575f80fd5b61595c86615731565b945060208601359350604086013592506060860135915061597f60808701615731565b90509295509295909350565b602080825282518282018190525f919060409081850190868401855b828110156159e15781518051855286810151878601528501516159cc86860182615798565b506101009390930192908501906001016159a7565b5091979650505050505050565b5f805f805f60a08688031215615a02575f80fd5b505083359560208501359550604085013594606081013594506080013592509050565b6002811061112b5761112b615774565b60208101615a4283615a25565b91905290565b5f805f8060808587031215615a5b575f80fd5b615a6485615731565b966020860135965060408601359560600135945092505050565b615a8781615788565b9052565b805160ff1682526020810151615aa7602084018261ffff169052565b506040810151615ac260408401826001600160601b03169052565b506060810151615adc606084018265ffffffffffff169052565b506080810151615af6608084018265ffffffffffff169052565b5060a0810151615b0e60a084018263ffffffff169052565b5060c0810151615b2660c084018263ffffffff169052565b5060e0810151615b4160e08401826001600160801b03169052565b50610100818101516001600160401b03169083015261012080820151611f1e82850182615a7e565b610140810161103c8284615a8b565b602080825282518282018190525f919060409081850190868401855b828110156159e1578151805185528681015187860152858101518686015260609081015190615bc581870183615a8b565b50506101a0939093019290850190600101615b94565b600181811c90821680615bef57607f821691505b60208210810361564a57634e487b7160e01b5f52602260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8082018082111561103c5761103c615c0d565b808202811582820484141761103c5761103c615c0d565b5f82615c6557634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561103c5761103c615c0d565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f60018201615cb657615cb6615c0d565b5060010190565b60018060981b03825116815260018060801b03602083015116602082015261ffff60408301511660408201525f65ffffffffffff8060608501511660608401528060808501511660808401525060a0830151615d1881615788565b60a08301525060c001919050565b6001600160581b03818116838216019080821115615d4657615d46615c0d565b5092915050565b82815260408101615d5d83615788565b8260208301529392505050565b6001600160e01b031991909116815260200190565b5f60208284031215615d8f575f80fd5b8151801515811461159a575f80fd5b5f81615dac57615dac615c0d565b505f19019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122071469ca2e3781c6484e6a26608f18aac78ae1d7090596d38f7788b129f1f47da64736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e5e0c13133782d967b002b3400e6ebea5d9814c00000000000000000000000001393ad734ea3c52865b4b541cf049dafd25c23a5
-----Decoded View---------------
Arg [0] : genesisAddress (address): 0xe5e0C13133782d967B002B3400E6Ebea5d9814C0
Arg [1] : buyAndBurnAddress (address): 0x1393ad734EA3c52865b4B541cf049dafd25c23a5
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000e5e0c13133782d967b002b3400e6ebea5d9814c0
Arg [1] : 0000000000000000000000001393ad734ea3c52865b4b541cf049dafd25c23a5
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.