Latest 25 from a total of 420,354 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Approve | 23965686 | 28 mins ago | IN | 0 ETH | 0.00006117 | ||||
| Approve | 23965208 | 2 hrs ago | IN | 0 ETH | 0.00010402 | ||||
| Approve | 23965135 | 2 hrs ago | IN | 0 ETH | 0.00010843 | ||||
| Approve | 23964272 | 5 hrs ago | IN | 0 ETH | 0.00009825 | ||||
| Approve | 23964151 | 5 hrs ago | IN | 0 ETH | 0.00000603 | ||||
| Approve | 23964061 | 5 hrs ago | IN | 0 ETH | 0.00009258 | ||||
| Approve | 23963901 | 6 hrs ago | IN | 0 ETH | 0.00010592 | ||||
| Approve | 23963896 | 6 hrs ago | IN | 0 ETH | 0.00001518 | ||||
| Approve | 23963732 | 7 hrs ago | IN | 0 ETH | 0.00007426 | ||||
| Approve | 23963731 | 7 hrs ago | IN | 0 ETH | 0.00004547 | ||||
| Start Stake | 23963700 | 7 hrs ago | IN | 0 ETH | 0.00084493 | ||||
| Transfer | 23963595 | 7 hrs ago | IN | 0 ETH | 0.00002433 | ||||
| Transfer | 23962808 | 10 hrs ago | IN | 0 ETH | 0.00000875 | ||||
| Approve | 23962706 | 10 hrs ago | IN | 0 ETH | 0.00006363 | ||||
| Approve | 23962522 | 11 hrs ago | IN | 0 ETH | 0.00001179 | ||||
| Approve | 23962358 | 11 hrs ago | IN | 0 ETH | 0.00011195 | ||||
| Transfer | 23962248 | 12 hrs ago | IN | 0 ETH | 0.00008462 | ||||
| Transfer | 23961714 | 13 hrs ago | IN | 0 ETH | 0.00012394 | ||||
| Approve | 23961113 | 15 hrs ago | IN | 0 ETH | 0.00002701 | ||||
| Transfer | 23961066 | 16 hrs ago | IN | 0 ETH | 0.00007316 | ||||
| Approve | 23960891 | 16 hrs ago | IN | 0 ETH | 0.0000203 | ||||
| Approve | 23960875 | 16 hrs ago | IN | 0 ETH | 0.00002026 | ||||
| Approve | 23960872 | 16 hrs ago | IN | 0 ETH | 0.00002024 | ||||
| Approve | 23960734 | 17 hrs ago | IN | 0 ETH | 0.00005874 | ||||
| Approve | 23960687 | 17 hrs ago | IN | 0 ETH | 0.00001517 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Transfer | 23959523 | 21 hrs ago | 0.08392792 ETH | ||||
| Transfer | 23957831 | 26 hrs ago | 0.00035588 ETH | ||||
| Transfer | 23957778 | 27 hrs ago | 0.00069502 ETH | ||||
| Transfer | 23953284 | 42 hrs ago | 0.00002051 ETH | ||||
| Transfer | 23952018 | 46 hrs ago | 0.00088784 ETH | ||||
| Transfer | 23950244 | 2 days ago | 0.00001034 ETH | ||||
| Transfer | 23948835 | 2 days ago | 0.00040833 ETH | ||||
| Transfer | 23946558 | 2 days ago | 0.00101999 ETH | ||||
| Transfer | 23946000 | 2 days ago | 0.00180129 ETH | ||||
| Transfer | 23945203 | 2 days ago | 0.0010194 ETH | ||||
| Transfer | 23937002 | 4 days ago | 0.00172801 ETH | ||||
| Transfer | 23930830 | 4 days ago | 0.00059101 ETH | ||||
| Transfer | 23920152 | 6 days ago | 0.62027847 ETH | ||||
| Transfer | 23898158 | 9 days ago | 0.01079474 ETH | ||||
| Transfer | 23893744 | 10 days ago | 0.00007982 ETH | ||||
| Transfer | 23879485 | 12 days ago | 0.00670479 ETH | ||||
| Transfer | 23852284 | 15 days ago | 0.00592526 ETH | ||||
| Transfer | 23841017 | 17 days ago | 0.02694318 ETH | ||||
| Transfer | 23816176 | 21 days ago | 0.00372283 ETH | ||||
| Transfer | 23801878 | 23 days ago | 0.00006423 ETH | ||||
| Transfer | 23780290 | 26 days ago | 0.00486427 ETH | ||||
| Transfer | 23773884 | 26 days ago | 0.00055839 ETH | ||||
| Transfer | 23772251 | 27 days ago | 0.00137473 ETH | ||||
| Transfer | 23764498 | 28 days ago | 0.0004569 ETH | ||||
| Transfer | 23761528 | 28 days ago | 0.00005632 ETH |
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
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
Contract ABI
API[{"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
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 99.91% | $3,122.9 | 1,170.8564 | $3,656,471.55 | |
| ETH | 0.02% | <$0.000001 | 6,761,233,551.427 | $607.35 | |
| ETH | <0.01% | $0.999811 | 29.7 | $29.69 | |
| ETH | <0.01% | <$0.000001 | 95,114,599 | $1.31 | |
| ETH | <0.01% | $1.54 | 0.82 | $1.26 | |
| ETH | <0.01% | $0.000313 | 1,067 | $0.3336 | |
| BSC | 0.07% | $3,124.32 | 0.7693 | $2,403.64 | |
| BSC | <0.01% | $1 | 178.81 | $178.81 | |
| BSC | <0.01% | $903.08 | 0.00014324 | $0.129354 | |
| ARB | <0.01% | $3,123.07 | 0.042 | $131.13 | |
| ZKSYNC | <0.01% | $3,123.4 | 0.0277 | $86.52 | |
| OP | <0.01% | $3,122.9 | 0.00128 | $4 | |
| BASE | <0.01% | $3,123.17 | 0.00072007 | $2.25 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.