Source Code
Latest 25 from a total of 4,618 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Purchase Token W... | 22134743 | 198 days ago | IN | 0.035 ETH | 0.0006318 | ||||
Purchase Token W... | 22129686 | 198 days ago | IN | 0.052 ETH | 0.00039714 | ||||
Purchase Token W... | 22129673 | 198 days ago | IN | 0.00594 ETH | 0.000396 | ||||
Purchase Token W... | 22127748 | 199 days ago | IN | 0 ETH | 0.0001655 | ||||
Purchase Token W... | 22125380 | 199 days ago | IN | 0.0001 ETH | 0.00062208 | ||||
Purchase Token W... | 22119388 | 200 days ago | IN | 0.0219 ETH | 0.00058565 | ||||
Purchase Token W... | 22119260 | 200 days ago | IN | 0.0796 ETH | 0.00060677 | ||||
Purchase Token W... | 22116704 | 200 days ago | IN | 0.0001 ETH | 0.00079537 | ||||
Purchase Token W... | 22112782 | 201 days ago | IN | 0.24 ETH | 0.00061296 | ||||
Purchase Token W... | 22110889 | 201 days ago | IN | 0.147 ETH | 0.00061727 | ||||
Purchase Token W... | 22110474 | 201 days ago | IN | 0 ETH | 0.00019003 | ||||
Purchase Token W... | 22110430 | 201 days ago | IN | 0.1 ETH | 0.00055662 | ||||
Purchase Token W... | 22107962 | 202 days ago | IN | 0.009 ETH | 0.00060166 | ||||
Purchase Token W... | 22105989 | 202 days ago | IN | 0.00051 ETH | 0.00013771 | ||||
Purchase Token W... | 22105097 | 202 days ago | IN | 0.0001 ETH | 0.00007982 | ||||
Purchase Token W... | 22105085 | 202 days ago | IN | 0.001 ETH | 0.0000819 | ||||
Purchase Token W... | 22105044 | 202 days ago | IN | 0.01 ETH | 0.00038907 | ||||
Purchase Token W... | 22104947 | 202 days ago | IN | 0.09 ETH | 0.00042357 | ||||
Purchase Token W... | 22104919 | 202 days ago | IN | 0.0015 ETH | 0.00060914 | ||||
Purchase Token W... | 22104648 | 202 days ago | IN | 0.0045 ETH | 0.0006051 | ||||
Purchase Token W... | 22103992 | 202 days ago | IN | 0.015 ETH | 0.00061193 | ||||
Purchase Token W... | 22097180 | 203 days ago | IN | 0.0105 ETH | 0.00061059 | ||||
Purchase Token W... | 22096087 | 203 days ago | IN | 0.041 ETH | 0.00062818 | ||||
Purchase Token W... | 22095783 | 203 days ago | IN | 0 ETH | 0.00069445 | ||||
Purchase Token W... | 22094940 | 203 days ago | IN | 0 ETH | 0.00008329 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
Transfer | 22459945 | 152 days ago | 0.002358 ETH | ||||
Transfer | 22459945 | 152 days ago | 0.000262 ETH | ||||
Purchase With Cl... | 22459945 | 152 days ago | 0.00262 ETH | ||||
Transfer | 22134743 | 198 days ago | 0.004375 ETH | ||||
Transfer | 22134743 | 198 days ago | 0.0007 ETH | ||||
Transfer | 22134743 | 198 days ago | 0.007875 ETH | ||||
Transfer | 22134743 | 198 days ago | 0.02205 ETH | ||||
Transfer | 22129686 | 198 days ago | 0.0065 ETH | ||||
Transfer | 22129686 | 198 days ago | 0.00104 ETH | ||||
Transfer | 22129686 | 198 days ago | 0.0117 ETH | ||||
Transfer | 22129686 | 198 days ago | 0.03276 ETH | ||||
Transfer | 22129673 | 198 days ago | 0.0007425 ETH | ||||
Transfer | 22129673 | 198 days ago | 0.0001188 ETH | ||||
Transfer | 22129673 | 198 days ago | 0.0013365 ETH | ||||
Transfer | 22129673 | 198 days ago | 0.0037422 ETH | ||||
Transfer | 22125380 | 199 days ago | 0.0000125 ETH | ||||
Transfer | 22125380 | 199 days ago | 0.000002 ETH | ||||
Transfer | 22125380 | 199 days ago | 0.0000225 ETH | ||||
Transfer | 22125380 | 199 days ago | 0.000063 ETH | ||||
Transfer | 22119388 | 200 days ago | 0.0027375 ETH | ||||
Transfer | 22119388 | 200 days ago | 0.000438 ETH | ||||
Transfer | 22119388 | 200 days ago | 0.0049275 ETH | ||||
Transfer | 22119388 | 200 days ago | 0.013797 ETH | ||||
Transfer | 22119260 | 200 days ago | 0.00995 ETH | ||||
Transfer | 22119260 | 200 days ago | 0.001592 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
PreSale
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import { ReentrancyGuardTransient } from "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol"; import { Rounds, Ownable } from "./Rounds.sol"; import { ILockup, IPreSale } from "./ILockup.sol"; import { IClaims, ClaimInfo } from "./IClaims.sol"; import { ETH, PPM, ZeroAddress, ZeroLengthArray, IdenticalValue, ArrayLengthMismatch, InvalidSignature, InvalidData } from "./Common.sol"; /// @title PreSale contract /// @notice Implements presale of the token /// @dev The presale contract allows you to purchase presale token with allowed tokens /// and there will be certain rounds contract PreSale is IPreSale, Rounds, ReentrancyGuardTransient { using SafeERC20 for IERC20; using Address for address payable; /// @member nftAmounts The nft amounts /// @member roundPrice The round number struct ClaimNFT { uint256[] nftAmounts; uint256 roundPrice; } /// @member price The price of token from price feed /// @member normalizationFactorForToken The normalization factor to achieve return value of 18 decimals ,while calculating token purchases and always with different token decimals /// @member normalizationFactorForNFT The normalization factor is the value which helps us to convert decimals of USDT to purchase token decimals and always with different token decimals struct TokenInfo { uint256 latestPrice; uint8 normalizationFactorForToken; uint8 normalizationFactorForNFT; } /// @member projectAmount The amount tansferred to project wallet /// @member platformAmount The amount tansferred to platform wallet /// @member burnAmount The amount tansferred to burn wallet /// @member equivalence The amount tansferred to claims contract struct TransferInfo { uint256 projectAmount; uint256 platformAmount; uint256 burnAmount; uint256 equivalence; } /// @dev To achieve return value of required decimals during calculation uint256 private constant NORMALIZARION_FACTOR = 1e30; /// @dev The constant value helps in calculating project amount uint256 private constant PROJECT_PERCENTAGE_PPM = 630_000; /// @dev The constant value helps in calculating discount uint256 private constant FIRST_ROUND_PPM = 200_000; /// @dev The constant value helps in calculating discount uint256 private constant OTHER_ROUND_PPM = 70_000; /// @dev The constant value helps in calculating amount uint256 private constant CLAIMS_PERCENTAGE_PPM = 250_000; /// @dev The constant value helps in calculating plaform amount uint256 private constant PLATFORM_PERCENTAGE_PPM = 100_000; /// @dev The constant value helps in calculating burn amount uint256 private constant BURN_PERCENTAGE_PPM = 20_000; /// @dev The max leader's wallet length uint256 private constant LEADERS_LENGTH = 5; /// @notice The maximum number of tokens that will be sold in presale uint256 public immutable maxCap; /// @notice The address of claims contract IClaims public immutable claimsContract; /// @notice The address of lockup contract ILockup public immutable lockup; /// @notice That buyEnabled or not bool public buyEnabled = true; /// @notice The address of signer wallet address public signerWallet; /// @notice The address of the project wallet address public projectWallet; /// @notice The address of the platform wallet address public platformWallet; /// @notice The address of the burn wallet address public burnWallet; /// @notice Sum of tokens purchased in presale uint256 public totalPurchases; /// @notice The array of prices of each nft uint256[] public nftPricing; /// @notice Gives claim info of user in every round mapping(address => mapping(uint32 => uint256)) public claims; /// @notice Gives info about address's permission mapping(address => bool) public blacklistAddress; /// @notice Gives claim info of user nft in every round mapping(address => mapping(uint32 => ClaimNFT[])) public claimNFT; /// @dev Emitted when token is purchased with ETH event PurchasedWithETH( address indexed by, string code, uint256 amountPurchasedETH, uint32 indexed round, address[] leaders, uint256[] percentages, uint256 indexed roundPrice, uint256 tokenPurchased ); /// @dev Emitted when presale tokens are purchased with any token event PurchasedWithToken( IERC20 indexed token, uint256 tokenPrice, address indexed by, string code, uint256 amountPurchased, uint256 tokenPurchased, uint32 indexed round, address[] leaders, uint256[] percentages ); /// @dev Emitted when NFT is purchased with ETH event PurchasedWithETHForNFT( address indexed by, string code, uint256 amountInETH, uint256 ethPrice, uint32 indexed round, address[] leaders, uint256[] percentages, uint256 roundPrice, uint256[] nftAmounts ); /// @dev Emitted when NFT is purchased with any token event PurchasedWithTokenForNFT( IERC20 indexed token, uint256 tokenPrice, address indexed by, string code, uint256 amountPurchased, uint32 indexed round, address[] leaders, uint256[] percentages, uint256 roundPrice, uint256[] nftAmounts ); /// @dev Emitted when tokens are purchased with claim amount event PurchasedWithClaimAmount( address indexed by, uint256 amount, IERC20 token, uint32 indexed round, uint256 indexed tokenPrice, uint256 tokenPurchased ); /// @dev Emitted when address of signer is updated event SignerUpdated(address oldSigner, address newSigner); /// @dev Emitted when address of platform wallet is updated event PlatformWalletUpdated(address oldPlatformWallet, address newPlatformWallet); /// @dev Emitted when address of project wallet is updated event ProjectWalletUpdated(address oldProjectWallet, address newProjectWallet); /// @dev Emitted when address of burn wallet is updated event BurnWalletUpdated(address oldBurnWallet, address newBurnWallet); /// @dev Emitted when blacklist access of address is updated event BlacklistUpdated(address which, bool accessNow); /// @dev Emitted when buying access changes event BuyEnableUpdated(bool oldAccess, bool newAccess); /// @dev Emitted when NFT prices are updated event PricingUpdated(uint256[] oldPrices, uint256[] newPrices); /// @notice Thrown when address is blacklisted error Blacklisted(); /// @notice Thrown when buy is disabled error BuyNotEnabled(); /// @notice Thrown when sign deadline is expired error DeadlineExpired(); /// @notice Thrown when Eth price suddenly drops while purchasing tokens error UnexpectedPriceDifference(); /// @notice Thrown when value to transfer is zero error ZeroValue(); /// @notice Thrown when price from price feed returns zero error PriceNotFound(); /// @notice Thrown when max cap is reached error MaxCapReached(); /// @notice Thrown when caller is not claims contract error OnlyClaims(); /// @notice Thrown when purchase amount is less than required error InvalidPurchase(); /// @notice Thrown when both price feed and reference price are non zero error CodeSyncIssue(); /// @notice Thrown if the price is not updated error PriceNotUpdated(); /// @notice Thrown if the sum of agents percentage is greater than required error InvalidPercentage(); /// @notice Thrown if the roundId of price is not updated error RoundIdNotUpdated(); /// @notice Thrown when array length of leaders are greater than required error InvalidArrayLength(); /// @notice Thrown when array is not sorted error ArrayNotSorted(); /// @dev Restricts when updating wallet/contract address with zero address modifier checkAddressZero(address which) { _checkAddressZero(which); _; } /// @dev Ensures that buy is enabled when buying modifier canBuy() { _canBuy(); _; } /// @dev Constructor /// @param projectWalletAddress The address of project wallet /// @param platformWalletAddress The address of platform wallet /// @param burnWalletAddress The address of burn wallet /// @param signerAddress The address of signer wallet /// @param claimsContractAddress The address of claim contract /// @param lockupContractAddress The address of lockup contract /// @param owner The address of owner wallet /// @param lastRound The last round created /// @param nftPrices The prices of nfts /// @param initMaxCap The max cap of gems token constructor( address projectWalletAddress, address platformWalletAddress, address burnWalletAddress, address signerAddress, IClaims claimsContractAddress, ILockup lockupContractAddress, address owner, uint32 lastRound, uint256[] memory nftPrices, uint256 initMaxCap ) Rounds(lastRound) Ownable(owner) checkAddressZero(signerAddress) checkAddressZero(address(claimsContractAddress)) checkAddressZero(address(lockupContractAddress)) checkAddressZero(projectWalletAddress) checkAddressZero(platformWalletAddress) checkAddressZero(burnWalletAddress) { if (nftPrices.length == 0) { revert ZeroLengthArray(); } for (uint256 i = 0; i < nftPrices.length; ++i) { _checkValue(nftPrices[i]); } projectWallet = projectWalletAddress; platformWallet = platformWalletAddress; burnWallet = burnWalletAddress; signerWallet = signerAddress; claimsContract = claimsContractAddress; lockup = lockupContractAddress; nftPricing = nftPrices; _checkValue(initMaxCap); maxCap = initMaxCap; } /// @notice Changes access of buying /// @param enabled The decision about buying function enableBuy(bool enabled) external onlyOwner { if (buyEnabled == enabled) { revert IdenticalValue(); } emit BuyEnableUpdated({ oldAccess: buyEnabled, newAccess: enabled }); buyEnabled = enabled; } /// @notice Changes signer wallet address /// @param newSigner The address of the new signer wallet function changeSigner(address newSigner) external checkAddressZero(newSigner) onlyOwner { address oldSigner = signerWallet; if (oldSigner == newSigner) { revert IdenticalValue(); } emit SignerUpdated({ oldSigner: oldSigner, newSigner: newSigner }); signerWallet = newSigner; } /// @notice Changes platform wallet address /// @param newPlatformWallet The address of the new platform wallet function updatePlatformWallet(address newPlatformWallet) external checkAddressZero(newPlatformWallet) onlyOwner { address oldPlatformWallet = platformWallet; if (oldPlatformWallet == newPlatformWallet) { revert IdenticalValue(); } emit PlatformWalletUpdated({ oldPlatformWallet: oldPlatformWallet, newPlatformWallet: newPlatformWallet }); platformWallet = newPlatformWallet; } /// @notice Changes project wallet address /// @param newProjectWallet The address of the new project wallet function updateProjectWallet(address newProjectWallet) external checkAddressZero(newProjectWallet) onlyOwner { address oldProjectWallet = projectWallet; if (oldProjectWallet == newProjectWallet) { revert IdenticalValue(); } emit ProjectWalletUpdated({ oldProjectWallet: oldProjectWallet, newProjectWallet: newProjectWallet }); projectWallet = newProjectWallet; } /// @notice Changes burn wallet address /// @param newBurnWallet The address of the new burn wallet function updateBurnWallet(address newBurnWallet) external checkAddressZero(newBurnWallet) onlyOwner { address oldBurnWallet = burnWallet; if (oldBurnWallet == newBurnWallet) { revert IdenticalValue(); } emit BurnWalletUpdated({ oldBurnWallet: oldBurnWallet, newBurnWallet: newBurnWallet }); burnWallet = newBurnWallet; } /// @notice Changes the access of any address in contract interaction /// @param which The address for which access is updated /// @param access The access decision of `which` address function updateBlackListedUser(address which, bool access) external checkAddressZero(which) onlyOwner { bool oldAccess = blacklistAddress[which]; if (oldAccess == access) { revert IdenticalValue(); } emit BlacklistUpdated({ which: which, accessNow: access }); blacklistAddress[which] = access; } /// @notice Changes the nft prices /// @param newPrices The new prices of nfts function updatePricing(uint256[] calldata newPrices) external onlyOwner { for (uint256 i = 0; i < newPrices.length; ++i) { _checkValue(newPrices[i]); } emit PricingUpdated({ oldPrices: nftPricing, newPrices: newPrices }); nftPricing = newPrices; } /// @notice Purchases presale token with ETH /// @param code The code is used to verify signature of the user /// @param round The round in which user wants to purchase /// @param deadline The deadline is validity of the signature /// @param minAmountToken The minAmountToken user agrees to purchase /// @param indexes The indexes at which user has locked tokens /// @param leaders The indexes of leaders /// @param percentages The indexes of leaders percentage /// @param v The `v` signature parameter /// @param r The `r` signature parameter /// @param s The `s` signature parameter function purchaseTokenWithETH( string memory code, uint32 round, uint256 deadline, uint256 minAmountToken, uint256[] calldata indexes, address[] calldata leaders, uint256[] calldata percentages, uint8 v, bytes32 r, bytes32 s ) external payable nonReentrant canBuy { // The input must have been signed by the presale signer _validatePurchaseWithETH(msg.value, round, deadline, code, v, r, s); uint256 roundPrice = _getRoundPriceForToken(msg.sender, indexes, round, ETH); TokenInfo memory tokenInfo = getLatestPrice(ETH); if (tokenInfo.latestPrice == 0) { revert PriceNotFound(); } TransferInfo memory transferInfo = _calculateTransferAmounts(msg.value, leaders, percentages); uint256 toReturn = _calculateAndUpdateTokenAmount( msg.value, tokenInfo.latestPrice, tokenInfo.normalizationFactorForToken, roundPrice ); if (toReturn < minAmountToken) { revert UnexpectedPriceDifference(); } _transferFundsETH(transferInfo); claims[msg.sender][round] += toReturn; _updateCommissions(leaders, percentages, msg.value, round, ETH); emit PurchasedWithETH({ by: msg.sender, code: code, amountPurchasedETH: msg.value, round: round, leaders: leaders, percentages: percentages, roundPrice: roundPrice, tokenPurchased: toReturn }); } /// @notice Purchases presale token with any token /// @param token The purchase token /// @param referenceNormalizationFactor The normalization factor /// @param referenceTokenPrice The current price of token in 10 decimals /// @param purchaseAmount The purchase amount /// @param minAmountToken The minAmountToken user agrees to purchase /// @param indexes The indexes at which user has locked tokens /// @param leaders The indexes of leaders /// @param percentages The indexes of leaders percentage /// @param code The code is used to verify signature of the user /// @param round The round in which user wants to purchase /// @param deadline The deadline is validity of the signature /// @param v The `v` signature parameter /// @param r The `r` signature parameter /// @param s The `s` signature parameter function purchaseTokenWithToken( IERC20 token, uint8 referenceNormalizationFactor, uint256 referenceTokenPrice, uint256 purchaseAmount, uint256 minAmountToken, uint256[] calldata indexes, address[] calldata leaders, uint256[] calldata percentages, string memory code, uint32 round, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external canBuy nonReentrant { // The input must have been signed by the presale signer _validatePurchaseWithToken( token, round, deadline, code, referenceTokenPrice, referenceNormalizationFactor, v, r, s ); uint256 roundPrice = _getRoundPriceForToken(msg.sender, indexes, round, token); (uint256 latestPrice, uint8 normalizationFactor) = _validatePrice( token, referenceTokenPrice, referenceNormalizationFactor ); TransferInfo memory transferInfo = _calculateTransferAmounts(purchaseAmount, leaders, percentages); uint256 toReturn = _calculateAndUpdateTokenAmount(purchaseAmount, latestPrice, normalizationFactor, roundPrice); if (toReturn < minAmountToken) { revert UnexpectedPriceDifference(); } _transferFundsToken(token, transferInfo); claims[msg.sender][round] += toReturn; _updateCommissions(leaders, percentages, purchaseAmount, round, token); emit PurchasedWithToken({ token: token, tokenPrice: latestPrice, by: msg.sender, code: code, amountPurchased: purchaseAmount, tokenPurchased: toReturn, round: round, leaders: leaders, percentages: percentages }); } /// @notice Purchases NFT with ETH /// @param code The code is used to verify signature of the user /// @param round The round in which user wants to purchase /// @param nftAmounts The nftAmounts is array of nfts selected /// @param deadline The deadline is validity of the signature /// @param indexes The indexes at which user has locked tokens /// @param leaders The indexes of leaders /// @param percentages The indexes of leaders percentage /// @param v The `v` signature parameter /// @param r The `r` signature parameter /// @param s The `s` signature parameter function purchaseNFTWithETH( string memory code, uint32 round, uint256[] calldata nftAmounts, uint256 deadline, uint256[] calldata indexes, address[] calldata leaders, uint256[] calldata percentages, uint8 v, bytes32 r, bytes32 s ) external payable canBuy nonReentrant { uint256[] memory nftPrices = nftPricing; _validateArrays(nftAmounts.length, nftPrices.length); // The input must have been signed by the presale signer _validatePurchaseWithETH(msg.value, round, deadline, code, v, r, s); TokenInfo memory tokenInfo = getLatestPrice(ETH); if (tokenInfo.latestPrice == 0) { revert PriceNotFound(); } (uint256 roundPrice, uint256 value) = _processPurchaseNFT( ETH, tokenInfo.latestPrice, tokenInfo.normalizationFactorForNFT, round, indexes, nftAmounts, nftPrices ); TransferInfo memory transferInfo = _calculateTransferAmounts(value, leaders, percentages); if (msg.value < value) { revert InvalidPurchase(); } uint256 amountUnused = msg.value - value; if (amountUnused > 0) { payable(msg.sender).sendValue(amountUnused); } _transferFundsETH(transferInfo); _updateCommissions(leaders, percentages, value, round, ETH); emit PurchasedWithETHForNFT({ by: msg.sender, code: code, amountInETH: value, ethPrice: tokenInfo.latestPrice, round: round, leaders: leaders, percentages: percentages, roundPrice: roundPrice, nftAmounts: nftAmounts }); } /// @notice Purchases NFT with any token /// @param token The purchase token /// @param referenceTokenPrice The current price of token in 10 decimals /// @param referenceNormalizationFactor The normalization factor /// @param code The code is used to verify signature of the user /// @param round The round in which user wants to purchase /// @param leaders The indexes of leaders /// @param percentages The indexes of leaders percentage /// @param nftAmounts The nftAmounts is array of nfts selected /// @param deadline The deadline is validity of the signature /// @param indexes The indexes at which user has locked tokens /// @param v The `v` signature parameter /// @param r The `r` signature parameter /// @param s The `s` signature parameter function purchaseNFTWithToken( IERC20 token, uint256 referenceTokenPrice, uint8 referenceNormalizationFactor, string memory code, uint32 round, uint256[] calldata nftAmounts, uint256 deadline, uint256[] calldata indexes, address[] calldata leaders, uint256[] calldata percentages, uint8 v, bytes32 r, bytes32 s ) external canBuy nonReentrant { uint256[] memory nftPrices = nftPricing; _validateArrays(nftAmounts.length, nftPrices.length); // The input must have been signed by the presale signer _validatePurchaseWithToken( token, round, deadline, code, referenceTokenPrice, referenceNormalizationFactor, v, r, s ); TokenInfo memory tokenInfo = getLatestPrice(token); if (tokenInfo.latestPrice != 0) { if (referenceTokenPrice != 0 || referenceNormalizationFactor != 0) { revert CodeSyncIssue(); } } // If price feed isn't available,we fallback to the reference price if (tokenInfo.latestPrice == 0) { if (referenceTokenPrice == 0 || referenceNormalizationFactor == 0) { revert ZeroValue(); } tokenInfo.latestPrice = referenceTokenPrice; tokenInfo.normalizationFactorForNFT = referenceNormalizationFactor; } (uint256 roundPrice, uint256 value) = _processPurchaseNFT( token, tokenInfo.latestPrice, tokenInfo.normalizationFactorForNFT, round, indexes, nftAmounts, nftPrices ); TransferInfo memory transferInfo = _calculateTransferAmounts(value, leaders, percentages); _transferFundsToken(token, transferInfo); _updateCommissions(leaders, percentages, value, round, token); emit PurchasedWithTokenForNFT({ token: token, tokenPrice: tokenInfo.latestPrice, by: msg.sender, code: code, amountPurchased: value, round: round, leaders: leaders, percentages: percentages, roundPrice: roundPrice, nftAmounts: nftAmounts }); } /// @inheritdoc IPreSale function purchaseWithClaim( IERC20 token, uint256 referenceTokenPrice, uint8 referenceNormalizationFactor, uint256 amount, uint256 minAmountToken, uint256[] calldata indexes, address recipient, uint32 round ) external payable canBuy nonReentrant { if (msg.sender != address(claimsContract)) { revert OnlyClaims(); } _checkBlacklist(recipient); if (!allowedTokens[round][token].access) { revert TokenDisallowed(); } uint256 roundPrice = _getRoundPriceForToken(recipient, indexes, round, token); (uint256 latestPrice, uint8 normalizationFactor) = _validatePrice( token, referenceTokenPrice, referenceNormalizationFactor ); uint256 toReturn = _calculateAndUpdateTokenAmount(amount, latestPrice, normalizationFactor, roundPrice); if (toReturn < minAmountToken) { revert UnexpectedPriceDifference(); } claims[recipient][round] += toReturn; uint256 platformAmount = (amount * PLATFORM_PERCENTAGE_PPM) / PPM; if (token == ETH) { payable(platformWallet).sendValue(platformAmount); payable(projectWallet).sendValue(amount - platformAmount); } else { token.safeTransferFrom(msg.sender, platformWallet, platformAmount); token.safeTransferFrom(msg.sender, projectWallet, amount - platformAmount); } emit PurchasedWithClaimAmount({ by: recipient, amount: amount, token: token, round: round, tokenPrice: latestPrice, tokenPurchased: toReturn }); } /// @notice The Chainlink inherited function, give us tokens live price function getLatestPrice(IERC20 token) public view returns (TokenInfo memory) { PriceFeedData memory data = tokenData[token]; TokenInfo memory tokenInfo; if (address(data.priceFeed) == address(0)) { return tokenInfo; } ( uint80 roundId, /*uint80 roundID*/ int price /*uint256 startedAt*/ /*uint80 answeredInRound*/, , uint256 updatedAt, ) = /*uint256 timeStamp*/ data.priceFeed.latestRoundData(); if (roundId == 0) { revert RoundIdNotUpdated(); } if (updatedAt == 0 || block.timestamp - updatedAt > data.tolerance) { revert PriceNotUpdated(); } return TokenInfo({ latestPrice: uint256(price), normalizationFactorForToken: data.normalizationFactorForToken, normalizationFactorForNFT: data.normalizationFactorForNFT }); } /// @dev Checks value, if zero then reverts function _checkValue(uint256 value) private pure { if (value == 0) { revert ZeroValue(); } } /// @dev Validates blacklist address, round and deadline function _validatePurchase(uint32 round, uint256 deadline, IERC20 token) private view { if (block.timestamp > deadline) { revert DeadlineExpired(); } _checkBlacklist(msg.sender); if (!allowedTokens[round][token].access) { revert TokenDisallowed(); } _verifyInRound(round); } /// @dev The helper function which verifies signature, signed by signerWallet, reverts if Invalid function _verifyCode(string memory code, uint256 deadline, uint8 v, bytes32 r, bytes32 s) private view { bytes32 encodedMessageHash = keccak256(abi.encodePacked(msg.sender, code, deadline)); _verifyMessage(encodedMessageHash, v, r, s); } /// @dev The helper function which verifies signature, signed by signerWallet, reverts if Invalid function _verifyCodeWithPrice( string memory code, uint256 deadline, uint256 referenceTokenPrice, IERC20 token, uint256 normalizationFactor, uint8 v, bytes32 r, bytes32 s ) private view { bytes32 encodedMessageHash = keccak256( abi.encodePacked(msg.sender, code, referenceTokenPrice, deadline, token, normalizationFactor) ); _verifyMessage(encodedMessageHash, v, r, s); } /// @dev Verifies the address that signed a hashed message (`hash`) with /// `signature` function _verifyMessage(bytes32 encodedMessageHash, uint8 v, bytes32 r, bytes32 s) private view { if (signerWallet != ECDSA.recover(MessageHashUtils.toEthSignedMessageHash(encodedMessageHash), v, r, s)) { revert InvalidSignature(); } } /// @dev Process nft purchase by calculating nft prices and purchase amount function _processPurchaseNFT( IERC20 token, uint256 price, uint256 normalizationFactor, uint32 round, uint256[] calldata indexes, uint256[] calldata nftAmounts, uint256[] memory nftPrices ) private returns (uint256, uint256) { uint256 value; uint256 totalNFTPrices = 0; for (uint256 i = 0; i < nftPrices.length; ++i) { uint256 nfts = nftAmounts[i]; uint256 prices = nftPrices[i]; // (10**0 * 10**6 +10**10) -10**10 = 6 decimals value += (nfts * prices * (10 ** (normalizationFactor))) / price; totalNFTPrices += nfts * prices; } uint256 roundPrice = _getRoundPriceForToken(msg.sender, indexes, round, token); _updateTokenPurchases((totalNFTPrices * NORMALIZARION_FACTOR) / roundPrice); claimNFT[msg.sender][round].push(ClaimNFT({ nftAmounts: nftAmounts, roundPrice: roundPrice })); return (roundPrice, value); } /// @dev Checks that address is blacklisted or not function _checkBlacklist(address which) private view { if (blacklistAddress[which]) { revert Blacklisted(); } } /// @dev Checks max cap and updates total purchases function _updateTokenPurchases(uint256 newPurchase) private { if (newPurchase + totalPurchases > maxCap) { revert MaxCapReached(); } totalPurchases += newPurchase; } /// @dev Validates round, deadline and signature function _validatePurchaseWithETH( uint256 amount, uint32 round, uint256 deadline, string memory code, uint8 v, bytes32 r, bytes32 s ) private view { _checkValue(amount); _validatePurchase(round, deadline, ETH); _verifyCode(code, deadline, v, r, s); } /// @dev Validates round, deadline and signature function _validatePurchaseWithToken( IERC20 token, uint32 round, uint256 deadline, string memory code, uint256 referenceTokenPrice, uint256 normalizationFactor, uint8 v, bytes32 r, bytes32 s ) private view { _validatePurchase(round, deadline, token); _verifyCodeWithPrice(code, deadline, referenceTokenPrice, token, normalizationFactor, v, r, s); } /// @dev Checks discounted round price if eligible else returns round price function _getRoundPriceForToken( address user, uint256[] memory indexes, uint32 round, IERC20 token ) private view returns (uint256) { uint256 customPrice = allowedTokens[round][token].customPrice; uint256 roundPrice = customPrice > 0 ? customPrice : rounds[round].price; uint256 lockedAmount; uint256 indexLength = indexes.length; if (indexLength == 0) { return roundPrice; } for (uint256 i; i < indexLength; ++i) { if (indexLength != i + 1) { if (indexes[i] >= indexes[i + 1]) { revert ArrayNotSorted(); } } (uint256 amount, ) = lockup.stakes(user, indexes[i]); lockedAmount += amount; if (lockedAmount >= lockup.minStakeAmount()) { if (round == 1) { roundPrice -= ((roundPrice * FIRST_ROUND_PPM) / PPM); } else { roundPrice -= ((roundPrice * OTHER_ROUND_PPM) / PPM); } break; } } return roundPrice; } /// @dev Calculates and update the token amount function _calculateAndUpdateTokenAmount( uint256 purchaseAmount, uint256 referenceTokenPrice, uint256 normalizationFactor, uint256 roundPrice ) private returns (uint256) { // toReturn= (10**11 * 10**10 +10**15) -10**18 = 18 decimals uint256 toReturn = (purchaseAmount * referenceTokenPrice * (10 ** normalizationFactor)) / roundPrice; _updateTokenPurchases(toReturn); return toReturn; } /// @dev Provides us live price of token from price feed or returns reference price and reverts if price is zero function _validatePrice( IERC20 token, uint256 referenceTokenPrice, uint8 referenceNormalizationFactor ) private view returns (uint256, uint8) { TokenInfo memory tokenInfo = getLatestPrice(token); if (tokenInfo.latestPrice != 0) { if (referenceTokenPrice != 0 || referenceNormalizationFactor != 0) { revert CodeSyncIssue(); } } // If price feed isn't available,we fallback to the reference price if (tokenInfo.latestPrice == 0) { if (referenceTokenPrice == 0 || referenceNormalizationFactor == 0) { revert ZeroValue(); } tokenInfo.latestPrice = referenceTokenPrice; tokenInfo.normalizationFactorForToken = referenceNormalizationFactor; } return (tokenInfo.latestPrice, tokenInfo.normalizationFactorForToken); } /// @dev Distribute ETH to multiple recipients function _transferFundsETH(TransferInfo memory transferInfo) private { payable(projectWallet).sendValue(transferInfo.projectAmount); payable(platformWallet).sendValue(transferInfo.platformAmount); payable(burnWallet).sendValue(transferInfo.burnAmount); payable(address(claimsContract)).sendValue(transferInfo.equivalence); } /// @dev Distribute token to multiple recipients function _transferFundsToken(IERC20 token, TransferInfo memory transferInfo) private { token.safeTransferFrom(msg.sender, projectWallet, transferInfo.projectAmount); token.safeTransferFrom(msg.sender, platformWallet, transferInfo.platformAmount); token.safeTransferFrom(msg.sender, burnWallet, transferInfo.burnAmount); token.safeTransferFrom(msg.sender, address(claimsContract), transferInfo.equivalence); } /// @dev Checks zero address, if zero then reverts /// @param which The `which` address to check for zero address function _checkAddressZero(address which) private pure { if (which == address(0)) { revert ZeroAddress(); } } /// @dev Checks buyEnabled, if not then reverts function _canBuy() private view { if (!buyEnabled) { revert BuyNotEnabled(); } } /// @dev Calculates transfer amounts function _calculateTransferAmounts( uint256 amount, address[] memory leaders, uint256[] memory percentages ) private pure returns (TransferInfo memory transferInfo) { _checkValue(amount); transferInfo.burnAmount = (amount * BURN_PERCENTAGE_PPM) / PPM; transferInfo.platformAmount = (amount * PLATFORM_PERCENTAGE_PPM) / PPM; transferInfo.projectAmount = (amount * PROJECT_PERCENTAGE_PPM) / PPM; uint256 toLength = leaders.length; uint256 sumPercentage; if (toLength == 0) { revert InvalidData(); } if (toLength > LEADERS_LENGTH) { revert InvalidArrayLength(); } if (toLength != percentages.length) { revert ArrayLengthMismatch(); } for (uint256 j; j < toLength; ++j) { sumPercentage += percentages[j]; } if (sumPercentage == 0) { revert ZeroValue(); } if (sumPercentage > CLAIMS_PERCENTAGE_PPM) { revert InvalidPercentage(); } transferInfo.equivalence = (amount * sumPercentage) / PPM; if (sumPercentage < CLAIMS_PERCENTAGE_PPM) { transferInfo.platformAmount += (((amount * CLAIMS_PERCENTAGE_PPM) / PPM) - transferInfo.equivalence); } } /// @dev Updates the amounts of agents /// @param leaders The indexes of leaders /// @param percentages The indexes of leaders percentage /// @param amount The amount used to calculate leaders comission /// @param round The round in which user wants to purchase /// @param token The token address in which comissions will be set function _updateCommissions( address[] memory leaders, uint256[] memory percentages, uint256 amount, uint32 round, IERC20 token ) private { uint256 toLength = leaders.length; ClaimInfo[] memory claimInfo = new ClaimInfo[](toLength); for (uint256 i = 0; i < toLength; ++i) { claimInfo[i] = ClaimInfo({ token: token, amount: (amount * percentages[i]) / PPM }); } claimsContract.addClaimInfo(leaders, round, claimInfo); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); function getRoundData( uint80 _roundId ) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @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 virtual onlyOwner { _transferOwnership(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 virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol) pragma solidity ^0.8.20; import {Ownable} from "./Ownable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This extension of the {Ownable} contract includes a two-step mechanism to transfer * ownership, where the new owner must call {acceptOwnership} in order to replace the * old one. This can help prevent common mistakes, such as transfers of ownership to * incorrect accounts, or to contracts that are unable to interact with the * permission system. * * The initial owner is specified at deployment time in the constructor for `Ownable`. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2Step is Ownable { address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. * * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); if (pendingOwner() != sender) { revert OwnableUnauthorizedAccount(sender); } _transferOwnership(sender); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ 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 value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` 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 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC1363} from "../../../interfaces/IERC1363.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { /** * @dev An operation with an ERC-20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. * * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being * set here. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements. */ function _callOptionalReturn(IERC20 token, bytes memory data) private { uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) // bubble errors if iszero(success) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } returnSize := returndatasize() returnValue := mload(0) } if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { bool success; uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) returnSize := returndatasize() returnValue := mload(0) } return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS } /** * @dev The signature derives the `address(0)`. */ error ECDSAInvalidSignature(); /** * @dev The signature has an invalid length. */ error ECDSAInvalidSignatureLength(uint256 length); /** * @dev The signature has an S value that is in the upper half order. */ error ECDSAInvalidSignatureS(bytes32 s); /** * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not * return address(0) without also returning an error description. Errors are documented using an enum (error type) * and a bytes32 providing additional information about the error. * * If no error is returned, then the address can be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function tryRecover( bytes32 hash, bytes memory signature ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly ("memory-safe") { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures] */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { unchecked { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); // We do not check for an overflow here since the shift operation results in 0 or 1. uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS, s); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature, bytes32(0)); } return (signer, RecoverError.NoError, bytes32(0)); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); _throwError(error, errorArg); return recovered; } /** * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. */ function _throwError(RecoverError error, bytes32 errorArg) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert ECDSAInvalidSignature(); } else if (error == RecoverError.InvalidSignatureLength) { revert ECDSAInvalidSignatureLength(uint256(errorArg)); } else if (error == RecoverError.InvalidSignatureS) { revert ECDSAInvalidSignatureS(errorArg); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.sol"; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an ERC-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing a bytes32 `messageHash` with * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with * keccak256, although any bytes32 value can be safely used because the final digest will * be re-hashed. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { assembly ("memory-safe") { mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) } } /** * @dev Returns the keccak256 digest of an ERC-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing an arbitrary `message` with * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); } /** * @dev Returns the keccak256 digest of an ERC-191 signed data with version * `0x00` (data with intended validator). * * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended * `validator` address. Then hashing the result. * * See {ECDSA-recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked(hex"19_00", validator, data)); } /** * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`). * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * See {ECDSA-recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { assembly ("memory-safe") { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * 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[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol) pragma solidity ^0.8.20; import {Panic} from "../Panic.sol"; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an success flag (no overflow). */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow). */ function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow). */ function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). */ function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. * * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute * one branch when needed, making this function more expensive. */ function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) { unchecked { // branchless ternary works because: // b ^ (a ^ b) == a // b ^ 0 == b return b ^ ((a ^ b) * SafeCast.toUint(condition)); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return ternary(a > b, a, b); } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return ternary(a < b, a, b); } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. Panic.panic(Panic.DIVISION_BY_ZERO); } // The following calculation ensures accurate ceiling division without overflow. // Since a is non-zero, (a - 1) / b will not overflow. // The largest possible result occurs when (a - 1) / b is type(uint256).max, // but the largest value we can obtain is type(uint256).max - 1, which happens // when a = type(uint256).max and b = 1. unchecked { return SafeCast.toUint(a > 0) * ((a - 1) / b + 1); } } /** * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2²⁵⁶ + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0. if (denominator <= prod1) { Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW)); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv ≡ 1 mod 2⁴. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2⁸ inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ inverse *= 2 - denominator * inverse; // inverse mod 2³² inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @dev Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); } /** * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. * * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0. * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. * * If the input value is not inversible, 0 is returned. * * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}. */ function invMod(uint256 a, uint256 n) internal pure returns (uint256) { unchecked { if (n == 0) return 0; // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) // Used to compute integers x and y such that: ax + ny = gcd(a, n). // When the gcd is 1, then the inverse of a modulo n exists and it's x. // ax + ny = 1 // ax = 1 + (-y)n // ax ≡ 1 (mod n) # x is the inverse of a modulo n // If the remainder is 0 the gcd is n right away. uint256 remainder = a % n; uint256 gcd = n; // Therefore the initial coefficients are: // ax + ny = gcd(a, n) = n // 0a + 1n = n int256 x = 0; int256 y = 1; while (remainder != 0) { uint256 quotient = gcd / remainder; (gcd, remainder) = ( // The old remainder is the next gcd to try. remainder, // Compute the next remainder. // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd // where gcd is at most n (capped to type(uint256).max) gcd - remainder * quotient ); (x, y) = ( // Increment the coefficient of a. y, // Decrement the coefficient of n. // Can overflow, but the result is casted to uint256 so that the // next value of y is "wrapped around" to a value between 0 and n - 1. x - y * int256(quotient) ); } if (gcd != 1) return 0; // No inverse exists. return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative. } } /** * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`. * * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that * `a**(p-2)` is the modular multiplicative inverse of a in Fp. * * NOTE: this function does NOT check that `p` is a prime greater than `2`. */ function invModPrime(uint256 a, uint256 p) internal view returns (uint256) { unchecked { return Math.modExp(a, p - 2, p); } } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) * * Requirements: * - modulus can't be zero * - underlying staticcall to precompile must succeed * * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make * sure the chain you're using it on supports the precompiled contract for modular exponentiation * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, * the underlying function will succeed given the lack of a revert, but the result may be incorrectly * interpreted as 0. */ function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { (bool success, uint256 result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying * to operate modulo 0 or if the underlying precompile reverted. * * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack * of a revert, but the result may be incorrectly interpreted as 0. */ function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { if (m == 0) return (false, 0); assembly ("memory-safe") { let ptr := mload(0x40) // | Offset | Content | Content (Hex) | // |-----------|------------|--------------------------------------------------------------------| // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x60:0x7f | value of b | 0x<.............................................................b> | // | 0x80:0x9f | value of e | 0x<.............................................................e> | // | 0xa0:0xbf | value of m | 0x<.............................................................m> | mstore(ptr, 0x20) mstore(add(ptr, 0x20), 0x20) mstore(add(ptr, 0x40), 0x20) mstore(add(ptr, 0x60), b) mstore(add(ptr, 0x80), e) mstore(add(ptr, 0xa0), m) // Given the result < m, it's guaranteed to fit in 32 bytes, // so we can use the memory scratch space located at offset 0. success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) result := mload(0x00) } } /** * @dev Variant of {modExp} that supports inputs of arbitrary length. */ function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { (bool success, bytes memory result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Variant of {tryModExp} that supports inputs of arbitrary length. */ function tryModExp( bytes memory b, bytes memory e, bytes memory m ) internal view returns (bool success, bytes memory result) { if (_zeroBytes(m)) return (false, new bytes(0)); uint256 mLen = m.length; // Encode call args in result and move the free memory pointer result = abi.encodePacked(b.length, e.length, mLen, b, e, m); assembly ("memory-safe") { let dataPtr := add(result, 0x20) // Write result on top of args to avoid allocating extra memory. success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) // Overwrite the length. // result.length > returndatasize() is guaranteed because returndatasize() == m.length mstore(result, mLen) // Set the memory pointer after the returned data. mstore(0x40, add(dataPtr, mLen)) } } /** * @dev Returns whether the provided byte array is zero. */ function _zeroBytes(bytes memory byteArray) private pure returns (bool) { for (uint256 i = 0; i < byteArray.length; ++i) { if (byteArray[i] != 0) { return false; } } return true; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * This method is based on Newton's method for computing square roots; the algorithm is restricted to only * using integer operations. */ function sqrt(uint256 a) internal pure returns (uint256) { unchecked { // Take care of easy edge cases when a == 0 or a == 1 if (a <= 1) { return a; } // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between // the current value as `ε_n = | x_n - sqrt(a) |`. // // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is // bigger than any uint256. // // By noticing that // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar // to the msb function. uint256 aa = a; uint256 xn = 1; if (aa >= (1 << 128)) { aa >>= 128; xn <<= 64; } if (aa >= (1 << 64)) { aa >>= 64; xn <<= 32; } if (aa >= (1 << 32)) { aa >>= 32; xn <<= 16; } if (aa >= (1 << 16)) { aa >>= 16; xn <<= 8; } if (aa >= (1 << 8)) { aa >>= 8; xn <<= 4; } if (aa >= (1 << 4)) { aa >>= 4; xn <<= 2; } if (aa >= (1 << 2)) { xn <<= 1; } // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). // // We can refine our estimation by noticing that the middle of that interval minimizes the error. // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). // This is going to be our x_0 (and ε_0) xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) // From here, Newton's method give us: // x_{n+1} = (x_n + a / x_n) / 2 // // One should note that: // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a // = ((x_n² + a) / (2 * x_n))² - a // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) // = (x_n² - a)² / (2 * x_n)² // = ((x_n² - a) / (2 * x_n))² // ≥ 0 // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n // // This gives us the proof of quadratic convergence of the sequence: // ε_{n+1} = | x_{n+1} - sqrt(a) | // = | (x_n + a / x_n) / 2 - sqrt(a) | // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | // = | (x_n - sqrt(a))² / (2 * x_n) | // = | ε_n² / (2 * x_n) | // = ε_n² / | (2 * x_n) | // // For the first iteration, we have a special case where x_0 is known: // ε_1 = ε_0² / | (2 * x_0) | // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) // ≤ 2**(2*e-4) / (3 * 2**(e-1)) // ≤ 2**(e-3) / 3 // ≤ 2**(e-3-log2(3)) // ≤ 2**(e-4.5) // // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: // ε_{n+1} = ε_n² / | (2 * x_n) | // ≤ (2**(e-k))² / (2 * 2**(e-1)) // ≤ 2**(2*e-2*k) / 2**e // ≤ 2**(e-2*k) xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either // sqrt(a) or sqrt(a) + 1. return xn - SafeCast.toUint(xn > a / xn); } } /** * @dev Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 exp; unchecked { exp = 128 * SafeCast.toUint(value > (1 << 128) - 1); value >>= exp; result += exp; exp = 64 * SafeCast.toUint(value > (1 << 64) - 1); value >>= exp; result += exp; exp = 32 * SafeCast.toUint(value > (1 << 32) - 1); value >>= exp; result += exp; exp = 16 * SafeCast.toUint(value > (1 << 16) - 1); value >>= exp; result += exp; exp = 8 * SafeCast.toUint(value > (1 << 8) - 1); value >>= exp; result += exp; exp = 4 * SafeCast.toUint(value > (1 << 4) - 1); value >>= exp; result += exp; exp = 2 * SafeCast.toUint(value > (1 << 2) - 1); value >>= exp; result += exp; result += SafeCast.toUint(value > 1); } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 isGt; unchecked { isGt = SafeCast.toUint(value > (1 << 128) - 1); value >>= isGt * 128; result += isGt * 16; isGt = SafeCast.toUint(value > (1 << 64) - 1); value >>= isGt * 64; result += isGt * 8; isGt = SafeCast.toUint(value > (1 << 32) - 1); value >>= isGt * 32; result += isGt * 4; isGt = SafeCast.toUint(value > (1 << 16) - 1); value >>= isGt * 16; result += isGt * 2; result += SafeCast.toUint(value > (1 << 8) - 1); } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { assembly ("memory-safe") { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. * * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute * one branch when needed, making this function more expensive. */ function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) { unchecked { // branchless ternary works because: // b ^ (a ^ b) == a // b ^ 0 == b return b ^ ((a ^ b) * int256(SafeCast.toUint(condition))); } } /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return ternary(a > b, a, b); } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return ternary(a < b, a, b); } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson. // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift, // taking advantage of the most significant (or "sign" bit) in two's complement representation. // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result, // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative). int256 mask = n >> 255; // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it. return uint256((n + mask) ^ mask); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol) pragma solidity ^0.8.20; /** * @dev Helper library for emitting standardized panic codes. * * ```solidity * contract Example { * using Panic for uint256; * * // Use any of the declared internal constants * function foo() { Panic.GENERIC.panic(); } * * // Alternatively * function foo() { Panic.panic(Panic.GENERIC); } * } * ``` * * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. * * _Available since v5.1._ */ // slither-disable-next-line unused-state library Panic { /// @dev generic / unspecified error uint256 internal constant GENERIC = 0x00; /// @dev used by the assert() builtin uint256 internal constant ASSERT = 0x01; /// @dev arithmetic underflow or overflow uint256 internal constant UNDER_OVERFLOW = 0x11; /// @dev division or modulo by zero uint256 internal constant DIVISION_BY_ZERO = 0x12; /// @dev enum conversion error uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; /// @dev invalid encoding in storage uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; /// @dev empty array pop uint256 internal constant EMPTY_ARRAY_POP = 0x31; /// @dev array out of bounds access uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; /// @dev resource error (too large allocation or too large array) uint256 internal constant RESOURCE_ERROR = 0x41; /// @dev calling invalid internal function uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; /// @dev Reverts with a panic code. Recommended to use with /// the internal constants with predefined codes. function panic(uint256 code) internal pure { assembly ("memory-safe") { mstore(0x00, 0x4e487b71) mstore(0x20, code) revert(0x1c, 0x24) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuardTransient.sol) pragma solidity ^0.8.24; import {TransientSlot} from "./TransientSlot.sol"; /** * @dev Variant of {ReentrancyGuard} that uses transient storage. * * NOTE: This variant only works on networks where EIP-1153 is available. * * _Available since v5.1._ */ abstract contract ReentrancyGuardTransient { using TransientSlot for *; // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant REENTRANCY_GUARD_STORAGE = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); /** * @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 if (_reentrancyGuardEntered()) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true); } function _nonReentrantAfter() private { REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false); } /** * @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 REENTRANCY_GUARD_STORAGE.asBoolean().tload(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; assembly ("memory-safe") { ptr := add(buffer, add(32, length)) } while (true) { ptr--; assembly ("memory-safe") { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal * representation, according to EIP-55. */ function toChecksumHexString(address addr) internal pure returns (string memory) { bytes memory buffer = bytes(toHexString(addr)); // hash the hex part of buffer (skip length + 2 bytes, length 40) uint256 hashValue; assembly ("memory-safe") { hashValue := shr(96, keccak256(add(buffer, 0x22), 40)) } for (uint256 i = 41; i > 1; --i) { // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f) if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) { // case shift by xoring with 0x20 buffer[i] ^= 0x20; } hashValue >>= 4; } return string(buffer); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/TransientSlot.sol) // This file was procedurally generated from scripts/generate/templates/TransientSlot.js. pragma solidity ^0.8.24; /** * @dev Library for reading and writing value-types to specific transient storage slots. * * Transient slots are often used to store temporary values that are removed after the current transaction. * This library helps with reading and writing to such slots without the need for inline assembly. * * * Example reading and writing values using transient storage: * ```solidity * contract Lock { * using TransientSlot for *; * * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; * * modifier locked() { * require(!_LOCK_SLOT.asBoolean().tload()); * * _LOCK_SLOT.asBoolean().tstore(true); * _; * _LOCK_SLOT.asBoolean().tstore(false); * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library TransientSlot { /** * @dev UDVT that represent a slot holding a address. */ type AddressSlot is bytes32; /** * @dev Cast an arbitrary slot to a AddressSlot. */ function asAddress(bytes32 slot) internal pure returns (AddressSlot) { return AddressSlot.wrap(slot); } /** * @dev UDVT that represent a slot holding a bool. */ type BooleanSlot is bytes32; /** * @dev Cast an arbitrary slot to a BooleanSlot. */ function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) { return BooleanSlot.wrap(slot); } /** * @dev UDVT that represent a slot holding a bytes32. */ type Bytes32Slot is bytes32; /** * @dev Cast an arbitrary slot to a Bytes32Slot. */ function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) { return Bytes32Slot.wrap(slot); } /** * @dev UDVT that represent a slot holding a uint256. */ type Uint256Slot is bytes32; /** * @dev Cast an arbitrary slot to a Uint256Slot. */ function asUint256(bytes32 slot) internal pure returns (Uint256Slot) { return Uint256Slot.wrap(slot); } /** * @dev UDVT that represent a slot holding a int256. */ type Int256Slot is bytes32; /** * @dev Cast an arbitrary slot to a Int256Slot. */ function asInt256(bytes32 slot) internal pure returns (Int256Slot) { return Int256Slot.wrap(slot); } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(AddressSlot slot) internal view returns (address value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(AddressSlot slot, address value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(BooleanSlot slot) internal view returns (bool value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(BooleanSlot slot, bool value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Bytes32Slot slot) internal view returns (bytes32 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Bytes32Slot slot, bytes32 value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Uint256Slot slot) internal view returns (uint256 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Uint256Slot slot, uint256 value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Int256Slot slot) internal view returns (int256 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Int256Slot slot, int256 value) internal { assembly ("memory-safe") { tstore(slot, value) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @dev The address of the Ethereum IERC20 constant ETH = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); /// @dev The constant value helps in calculating percentages uint256 constant PPM = 1_000_000; /// @notice Thrown when updating an address with zero address error ZeroAddress(); /// @notice Thrown when updating with an array of no values error ZeroLengthArray(); /// @notice Thrown when updating with the same value as previously stored error IdenticalValue(); /// @notice Thrown when two array lengths does not match error ArrayLengthMismatch(); /// @notice Thrown when sign is invalid error InvalidSignature(); /// @notice Thrown when input array length is zero error InvalidData();
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @member token The token address /// @member amount The token amount struct ClaimInfo { IERC20 token; uint256 amount; } interface IClaims { /// @notice Sets claim token and amount in the given round /// @param to The address of the leader /// @param claims The claim token and amount of the leader function addClaimInfo(address[] calldata to, uint32 round, ClaimInfo[] calldata claims) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IRounds } from "./IRounds.sol"; interface ILockup { /// @notice Returns locked amount of user at given index /// @param user The address of the user /// @param index The index number at which user has locked amount function stakes(address user, uint256 index) external view returns (uint256 amount, uint256 endTime); /// @notice Returns the minimum lockup amount function minStakeAmount() external view returns (uint256); } interface IPreSale is IRounds { /// @notice Purchases token with claim amount /// @param token The purchase token /// @param tokenPrice The current price of token in 10 decimals /// @param referenceNormalizationFactor The value to handle decimals /// @param amount The purchase amount /// @param minAmountToken The minimum amount of token recipient will get /// @param indexes The indexes at which user has locked tokens /// @param recipient The address of the recipient /// @param round The round in which user will purchase function purchaseWithClaim( IERC20 token, uint256 tokenPrice, uint8 referenceNormalizationFactor, uint256 amount, uint256 minAmountToken, uint256[] calldata indexes, address recipient, uint32 round ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; interface IRounds { /// @notice Returns the round details of the round function rounds(uint32 round) external view returns (uint256 startTime, uint256 endTime, uint256 price); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Ownable, Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol"; import { TokenRegistry } from "./TokenRegistry.sol"; import { IRounds } from "./IRounds.sol"; import { ZeroAddress, ArrayLengthMismatch, ZeroLengthArray } from "./Common.sol"; /// @title Rounds contract /// @notice Implements the round creation and updating of presale /// @dev The rounds contract allows you to create a round, update a round abstract contract Rounds is IRounds, TokenRegistry { /// @member access The access of the token /// @member customPrice The customPrice price in the round for the token struct AllowedToken { bool access; uint256 customPrice; } /// @member startTime The start time of round /// @member endTime The end time of round /// @member price The price in usd per token struct RoundData { uint256 startTime; uint256 endTime; uint256 price; } /// @dev The round index of last round created uint32 internal immutable _startRound; /// @dev The count of rounds created uint32 internal _roundIndex; /// @notice mapping gives us access info of the token in a given round mapping(uint32 => mapping(IERC20 => AllowedToken)) public allowedTokens; /// @inheritdoc IRounds mapping(uint32 => RoundData) public rounds; /// @dev Emitted when creating a new round event RoundCreated(uint32 indexed newRound, RoundData roundData); /// @dev Emitted when round is updated event RoundUpdated(uint32 indexed round, RoundData roundData); /// @dev Emitted when token access is updated event TokensAccessUpdated(uint32 indexed round, IERC20 indexed token, bool indexed access, uint256 customPrice); /// @notice Thrown when round time is not started error RoundNotStarted(); /// @notice Thrown when round time is ended error RoundEnded(); /// @notice Thrown when Round is not created error IncorrectRound(); /// @notice Thrown when new round price is less than previous round price error PriceLessThanOldRound(); /// @notice Thrown when round start time is invalid error InvalidStartTime(); /// @notice Thrown when round end time is invalid error InvalidEndTime(); /// @notice Thrown when new price is invalid error PriceInvalid(); /// @notice Thrown when startTime is incorrect when updating round error IncorrectStartTime(); /// @notice Thrown when endTime is incorrect when updating round error IncorrectEndTime(); /// @notice Thrown when round price is greater than next round while updating error PriceGreaterThanNextRound(); /// @notice Thrown when Token is restricted in given round error TokenDisallowed(); /// @dev Constructor. /// @param lastRound The last round created constructor(uint32 lastRound) { _startRound = lastRound; _roundIndex = lastRound; } /// @notice Creates a new round /// @param startTime The startTime of the round /// @param endTime The endTime of the round /// @param price The presale token price in 18 decimals, because our calculations returns a value in 36 decimals and to get returning value in 18 decimals we divide by round price function createNewRound(uint256 startTime, uint256 endTime, uint256 price) external onlyOwner { RoundData memory prevRoundData = rounds[_roundIndex]; uint32 newRound = ++_roundIndex; if (price < prevRoundData.price) { revert PriceLessThanOldRound(); } if (startTime < prevRoundData.endTime) { revert InvalidStartTime(); } _verifyRound(startTime, endTime, price); prevRoundData = RoundData({ startTime: startTime, endTime: endTime, price: price }); rounds[newRound] = prevRoundData; emit RoundCreated({ newRound: newRound, roundData: prevRoundData }); } /// @notice Updates the access of tokens in a given round /// @param round The round in which you want to update /// @param tokens addresses of the tokens /// @param accesses The access for the tokens /// @param customPrices The customPrice prices if any for the tokens function updateAllowedTokens( uint32 round, IERC20[] calldata tokens, bool[] calldata accesses, uint256[] calldata customPrices ) external onlyOwner { uint256 tokensLength = tokens.length; if (tokensLength == 0) { revert ZeroLengthArray(); } if (tokensLength != accesses.length || accesses.length != customPrices.length) { revert ArrayLengthMismatch(); } mapping(IERC20 => AllowedToken) storage selectedRound = allowedTokens[round]; for (uint256 i = 0; i < tokensLength; ++i) { IERC20 token = tokens[i]; if (address(token) == address(0)) { revert ZeroAddress(); } AllowedToken memory allowedToken = AllowedToken({ access: accesses[i], customPrice: customPrices[i] }); selectedRound[token] = allowedToken; emit TokensAccessUpdated({ round: round, token: token, access: allowedToken.access, customPrice: allowedToken.customPrice }); } } /// @notice Updates round data /// @param round The Round that will be updated /// @param startTime The StartTime of the round /// @param endTime The EndTime of the round /// @param price The price of the round in 18 decimals function updateRound(uint32 round, uint256 startTime, uint256 endTime, uint256 price) external onlyOwner { if (round <= _startRound || round > _roundIndex) { revert IncorrectRound(); } RoundData memory previousRound = rounds[round - 1]; RoundData memory nextRound = rounds[round + 1]; if (startTime < previousRound.endTime) { revert IncorrectStartTime(); } if (round != _roundIndex && endTime > nextRound.startTime) { revert IncorrectEndTime(); } if (price < previousRound.price) { revert PriceLessThanOldRound(); } if (round != _roundIndex && price > nextRound.price) { revert PriceGreaterThanNextRound(); } _verifyRound(startTime, endTime, price); rounds[round] = RoundData({ startTime: startTime, endTime: endTime, price: price }); emit RoundUpdated({ round: round, roundData: rounds[round] }); } /// @notice Returns total rounds created /// @return The Round count function getRoundCount() external view returns (uint32) { return _roundIndex; } /// @dev Validates array length and values function _validateArrays(uint256 firstLength, uint256 secondLength) internal pure { if (firstLength == 0) { revert ZeroLengthArray(); } if (firstLength != secondLength) { revert ArrayLengthMismatch(); } } /// @dev Checks round start and end time, reverts if Invalid function _verifyInRound(uint32 round) internal view { RoundData memory dataRound = rounds[round]; if (block.timestamp < dataRound.startTime) { revert RoundNotStarted(); } if (block.timestamp >= dataRound.endTime) { revert RoundEnded(); } } /// @dev Checks the validity of startTime, endTime and price function _verifyRound(uint256 startTime, uint256 endTime, uint256 price) internal view { if (startTime < block.timestamp) { revert InvalidStartTime(); } if (endTime <= startTime) { revert InvalidEndTime(); } if (price == 0) { revert PriceInvalid(); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Ownable, Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol"; import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; import { ZeroAddress, ArrayLengthMismatch, ZeroLengthArray, IdenticalValue } from "./Common.sol"; /// @title Tokens Registry contract /// @notice Implements the price feed of the tokens abstract contract TokenRegistry is Ownable2Step { /// @member priceFeed The Chainlink price feed address /// @member normalizationFactorForToken The normalization factor to achieve return value of 18 decimals, while calculating presale token purchases and always with different token decimals /// @member normalizationFactorForNFT The normalization factor is the value which helps us to convert decimals of USDT to purchase token decimals and always with different token decimals /// @member tolerance The pricefeed live price should be updated in tolerance time to get better price struct PriceFeedData { AggregatorV3Interface priceFeed; uint8 normalizationFactorForToken; uint8 normalizationFactorForNFT; uint256 tolerance; } /// @notice Gives us onchain price oracle address of the token mapping(IERC20 => PriceFeedData) public tokenData; /// @dev Emitted when address of Chainlink price feed contract is added for the token event TokenDataAdded(IERC20 token, PriceFeedData data); /// @notice Sets token price feeds and normalization factors /// @param tokens The addresses of the tokens /// @param priceFeedData Contains the price feed of the tokens, tolerance and the normalization factor function setTokenPriceFeed(IERC20[] calldata tokens, PriceFeedData[] calldata priceFeedData) external onlyOwner { uint256 tokensLength = tokens.length; if (tokensLength == 0) { revert ZeroLengthArray(); } if (tokensLength != priceFeedData.length) { revert ArrayLengthMismatch(); } for (uint256 i = 0; i < tokensLength; ++i) { PriceFeedData calldata data = priceFeedData[i]; IERC20 token = tokens[i]; PriceFeedData memory currentPriceFeedData = tokenData[token]; if (address(token) == address(0) || address(data.priceFeed) == address(0)) { revert ZeroAddress(); } if ( currentPriceFeedData.priceFeed == data.priceFeed && currentPriceFeedData.normalizationFactorForToken == data.normalizationFactorForToken && currentPriceFeedData.normalizationFactorForNFT == data.normalizationFactorForNFT && currentPriceFeedData.tolerance == data.tolerance ) { revert IdenticalValue(); } emit TokenDataAdded({ token: token, data: data }); tokenData[token] = data; } } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 1000000 }, "evmVersion": "cancun", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"projectWalletAddress","type":"address"},{"internalType":"address","name":"platformWalletAddress","type":"address"},{"internalType":"address","name":"burnWalletAddress","type":"address"},{"internalType":"address","name":"signerAddress","type":"address"},{"internalType":"contract IClaims","name":"claimsContractAddress","type":"address"},{"internalType":"contract ILockup","name":"lockupContractAddress","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"lastRound","type":"uint32"},{"internalType":"uint256[]","name":"nftPrices","type":"uint256[]"},{"internalType":"uint256","name":"initMaxCap","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"ArrayNotSorted","type":"error"},{"inputs":[],"name":"Blacklisted","type":"error"},{"inputs":[],"name":"BuyNotEnabled","type":"error"},{"inputs":[],"name":"CodeSyncIssue","type":"error"},{"inputs":[],"name":"DeadlineExpired","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"IdenticalValue","type":"error"},{"inputs":[],"name":"IncorrectEndTime","type":"error"},{"inputs":[],"name":"IncorrectRound","type":"error"},{"inputs":[],"name":"IncorrectStartTime","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidArrayLength","type":"error"},{"inputs":[],"name":"InvalidData","type":"error"},{"inputs":[],"name":"InvalidEndTime","type":"error"},{"inputs":[],"name":"InvalidPercentage","type":"error"},{"inputs":[],"name":"InvalidPurchase","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidStartTime","type":"error"},{"inputs":[],"name":"MaxCapReached","type":"error"},{"inputs":[],"name":"OnlyClaims","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"PriceGreaterThanNextRound","type":"error"},{"inputs":[],"name":"PriceInvalid","type":"error"},{"inputs":[],"name":"PriceLessThanOldRound","type":"error"},{"inputs":[],"name":"PriceNotFound","type":"error"},{"inputs":[],"name":"PriceNotUpdated","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"RoundEnded","type":"error"},{"inputs":[],"name":"RoundIdNotUpdated","type":"error"},{"inputs":[],"name":"RoundNotStarted","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TokenDisallowed","type":"error"},{"inputs":[],"name":"UnexpectedPriceDifference","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroLengthArray","type":"error"},{"inputs":[],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"which","type":"address"},{"indexed":false,"internalType":"bool","name":"accessNow","type":"bool"}],"name":"BlacklistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldBurnWallet","type":"address"},{"indexed":false,"internalType":"address","name":"newBurnWallet","type":"address"}],"name":"BurnWalletUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"oldAccess","type":"bool"},{"indexed":false,"internalType":"bool","name":"newAccess","type":"bool"}],"name":"BuyEnableUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPlatformWallet","type":"address"},{"indexed":false,"internalType":"address","name":"newPlatformWallet","type":"address"}],"name":"PlatformWalletUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"oldPrices","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"newPrices","type":"uint256[]"}],"name":"PricingUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldProjectWallet","type":"address"},{"indexed":false,"internalType":"address","name":"newProjectWallet","type":"address"}],"name":"ProjectWalletUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":true,"internalType":"uint32","name":"round","type":"uint32"},{"indexed":true,"internalType":"uint256","name":"tokenPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenPurchased","type":"uint256"}],"name":"PurchasedWithClaimAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"string","name":"code","type":"string"},{"indexed":false,"internalType":"uint256","name":"amountPurchasedETH","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"round","type":"uint32"},{"indexed":false,"internalType":"address[]","name":"leaders","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"percentages","type":"uint256[]"},{"indexed":true,"internalType":"uint256","name":"roundPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenPurchased","type":"uint256"}],"name":"PurchasedWithETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"string","name":"code","type":"string"},{"indexed":false,"internalType":"uint256","name":"amountInETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethPrice","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"round","type":"uint32"},{"indexed":false,"internalType":"address[]","name":"leaders","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"percentages","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"roundPrice","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"nftAmounts","type":"uint256[]"}],"name":"PurchasedWithETHForNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenPrice","type":"uint256"},{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"string","name":"code","type":"string"},{"indexed":false,"internalType":"uint256","name":"amountPurchased","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenPurchased","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"round","type":"uint32"},{"indexed":false,"internalType":"address[]","name":"leaders","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"percentages","type":"uint256[]"}],"name":"PurchasedWithToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenPrice","type":"uint256"},{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"string","name":"code","type":"string"},{"indexed":false,"internalType":"uint256","name":"amountPurchased","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"round","type":"uint32"},{"indexed":false,"internalType":"address[]","name":"leaders","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"percentages","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"roundPrice","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"nftAmounts","type":"uint256[]"}],"name":"PurchasedWithTokenForNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"newRound","type":"uint32"},{"components":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"indexed":false,"internalType":"struct Rounds.RoundData","name":"roundData","type":"tuple"}],"name":"RoundCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"round","type":"uint32"},{"components":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"indexed":false,"internalType":"struct Rounds.RoundData","name":"roundData","type":"tuple"}],"name":"RoundUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldSigner","type":"address"},{"indexed":false,"internalType":"address","name":"newSigner","type":"address"}],"name":"SignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"normalizationFactorForToken","type":"uint8"},{"internalType":"uint8","name":"normalizationFactorForNFT","type":"uint8"},{"internalType":"uint256","name":"tolerance","type":"uint256"}],"indexed":false,"internalType":"struct TokenRegistry.PriceFeedData","name":"data","type":"tuple"}],"name":"TokenDataAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"round","type":"uint32"},{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":true,"internalType":"bool","name":"access","type":"bool"},{"indexed":false,"internalType":"uint256","name":"customPrice","type":"uint256"}],"name":"TokensAccessUpdated","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"contract IERC20","name":"","type":"address"}],"name":"allowedTokens","outputs":[{"internalType":"bool","name":"access","type":"bool"},{"internalType":"uint256","name":"customPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"blacklistAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burnWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"buyEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newSigner","type":"address"}],"name":"changeSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"claimNFT","outputs":[{"internalType":"uint256","name":"roundPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"claims","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimsContract","outputs":[{"internalType":"contract IClaims","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"createNewRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"enableBuy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getLatestPrice","outputs":[{"components":[{"internalType":"uint256","name":"latestPrice","type":"uint256"},{"internalType":"uint8","name":"normalizationFactorForToken","type":"uint8"},{"internalType":"uint8","name":"normalizationFactorForNFT","type":"uint8"}],"internalType":"struct PreSale.TokenInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRoundCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockup","outputs":[{"internalType":"contract ILockup","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nftPricing","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"code","type":"string"},{"internalType":"uint32","name":"round","type":"uint32"},{"internalType":"uint256[]","name":"nftAmounts","type":"uint256[]"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"internalType":"address[]","name":"leaders","type":"address[]"},{"internalType":"uint256[]","name":"percentages","type":"uint256[]"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"purchaseNFTWithETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"referenceTokenPrice","type":"uint256"},{"internalType":"uint8","name":"referenceNormalizationFactor","type":"uint8"},{"internalType":"string","name":"code","type":"string"},{"internalType":"uint32","name":"round","type":"uint32"},{"internalType":"uint256[]","name":"nftAmounts","type":"uint256[]"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"internalType":"address[]","name":"leaders","type":"address[]"},{"internalType":"uint256[]","name":"percentages","type":"uint256[]"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"purchaseNFTWithToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"code","type":"string"},{"internalType":"uint32","name":"round","type":"uint32"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"minAmountToken","type":"uint256"},{"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"internalType":"address[]","name":"leaders","type":"address[]"},{"internalType":"uint256[]","name":"percentages","type":"uint256[]"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"purchaseTokenWithETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint8","name":"referenceNormalizationFactor","type":"uint8"},{"internalType":"uint256","name":"referenceTokenPrice","type":"uint256"},{"internalType":"uint256","name":"purchaseAmount","type":"uint256"},{"internalType":"uint256","name":"minAmountToken","type":"uint256"},{"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"internalType":"address[]","name":"leaders","type":"address[]"},{"internalType":"uint256[]","name":"percentages","type":"uint256[]"},{"internalType":"string","name":"code","type":"string"},{"internalType":"uint32","name":"round","type":"uint32"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"purchaseTokenWithToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"referenceTokenPrice","type":"uint256"},{"internalType":"uint8","name":"referenceNormalizationFactor","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountToken","type":"uint256"},{"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint32","name":"round","type":"uint32"}],"name":"purchaseWithClaim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"rounds","outputs":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"components":[{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"normalizationFactorForToken","type":"uint8"},{"internalType":"uint8","name":"normalizationFactorForNFT","type":"uint8"},{"internalType":"uint256","name":"tolerance","type":"uint256"}],"internalType":"struct TokenRegistry.PriceFeedData[]","name":"priceFeedData","type":"tuple[]"}],"name":"setTokenPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signerWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"name":"tokenData","outputs":[{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"normalizationFactorForToken","type":"uint8"},{"internalType":"uint8","name":"normalizationFactorForNFT","type":"uint8"},{"internalType":"uint256","name":"tolerance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPurchases","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"round","type":"uint32"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"bool[]","name":"accesses","type":"bool[]"},{"internalType":"uint256[]","name":"customPrices","type":"uint256[]"}],"name":"updateAllowedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"which","type":"address"},{"internalType":"bool","name":"access","type":"bool"}],"name":"updateBlackListedUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newBurnWallet","type":"address"}],"name":"updateBurnWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPlatformWallet","type":"address"}],"name":"updatePlatformWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"newPrices","type":"uint256[]"}],"name":"updatePricing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newProjectWallet","type":"address"}],"name":"updateProjectWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"round","type":"uint32"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"updateRound","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
610100604052346103f157615276803803908161001b816103f5565b9182396101408183810103126103f1576100348161041a565b906100416020820161041a565b9261004e6040830161041a565b9361005b6060840161041a565b608084015190916001600160a01b03821682036103f15760a0850151926001600160a01b03841684036103f15761009460c0870161041a565b9760e08701519863ffffffff8a168a036103f157610100880151976001600160401b0389116103f157878101601f8a83010112156103f157808901516001600160401b0381116103a3576100ed60208260051b016103f5565b9960208b8381520190819a840160208460051b8387010101116103f157602081850101915b60208460051b838701010183106103e157505050506101200151996001600160a01b038216156103c957600180546001600160a01b03199081169091555f80546001600160a01b039485169281168317825563ffffffff9416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3806080521663ffffffff196003541617600355600654926101b08361042e565b6101c26001600160a01b03861661042e565b6101d46001600160a01b03871661042e565b6101dd8961042e565b6101e68161042e565b6101ef8261042e565b8751156103b7575f5b885181101561021c5780610216602060019360051b8c010151610450565b016101f8565b50600780546001600160a01b03199081166001600160a01b039b8c1617909155600880548216928b169290921782556009805490911692909916919091179097556001600160a81b0319909116951b610100600160a81b03169490941760011760065560c09390935260e09290925251906001600160401b0382116103a3576801000000000000000082116103a357600b5482600b5580831061035f575b50600b5f5260205f205f5b83811061034b57846102d681610450565b60a052604051614e0c908161046a8239608051816120b0015260a05181818161297d0152614b73015260c0518181816107ad015281816119a001528181613bfc01528181613ca201528181613edc0152614a02015260e051818181612ddb0152818161428a0152818161459701526147750152f35b6001906020845194019381840155016102c5565b600b5f527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db99081019083015b81811061039857506102ba565b5f815560010161038b565b634e487b7160e01b5f52604160045260245ffd5b604051630f59b9ff60e01b8152600490fd5b604051631e4fbdf760e01b81525f6004820152602490fd5b8251815260209283019201610112565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176103a357604052565b51906001600160a01b03821682036103f157565b6001600160a01b03161561043e57565b60405163d92e233d60e01b8152600490fd5b1561045757565b604051637c946ed760e01b8152600490fdfe610180806040526004361015610013575f80fd5b5f3560e01c9081630622874914612dff5750806306490f4714612d915780630a7e0c5614612bd7578063161c9d0114612a0257806316345f18146129a057806323548b8b1461294857806327e45c2c146128c05780632a2530261461274d5780632a302af71461231e5780632d55e7df1461205a57806341e7e34114611fa65780635962a94114611f6b57806364f0d35e14611f175780636de7da7814611ed6578063715018a614611e335780637192762814611d505780637459663314611b0757806379a6d51f14611a9d57806379ba5097146119c45780637fcb09721461195657806382e0c47d1461140157806383ed138514610fd65780638da5cb5b14610f8657806392f5888114610ef957806395f0024014610e62578063aad2b72314610d60578063ad9bf0f414610afd578063ada4ef3014610a1a578063ade1721e14610700578063b38393891461061d578063beb08ab9146105cc578063e09590d1146104ad578063e30c39781461045c578063e9f8958f146103e0578063f2fde38b14610335578063f3290d75146102cd578063f582d2931461028d578063fa2af9da1461023c5763fc7a822d146101ca575f80fd5b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857600435600b5481101561023857602090600b5f527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90154604051908152f35b5f80fd5b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602073ffffffffffffffffffffffffffffffffffffffff60085416604051908152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602060ff600654166040519015158152f35b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385773ffffffffffffffffffffffffffffffffffffffff610319612ea4565b165f52600d602052602060ff60405f2054166040519015158152f35b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385761036c612ea4565b61037461361f565b73ffffffffffffffffffffffffffffffffffffffff80911690817fffffffffffffffffffffffff000000000000000000000000000000000000000060015416176001555f54167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b346102385760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610417612ea4565b73ffffffffffffffffffffffffffffffffffffffff610434612e60565b91165f52600c60205263ffffffff60405f2091165f52602052602060405f2054604051908152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346102385760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610238576104e4612ea4565b60243580151591828203610238578061051173ffffffffffffffffffffffffffffffffffffffff92614079565b61051961361f565b16805f52600d6020528260ff60405f2054161515146105a2577f6a12b3df6cba4203bd7fd06b816789f87de8c594299aed5717ae070fac781bac60406105a0948151908482526020820152a15f52600d60205260405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b005b60046040517f2620eb3a000000000000000000000000000000000000000000000000000000008152fd5b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602073ffffffffffffffffffffffffffffffffffffffff60075416604051908152f35b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610654612ea4565b61065d81614079565b61066561361f565b60095473ffffffffffffffffffffffffffffffffffffffff80831692919081168381146105a2576040805173ffffffffffffffffffffffffffffffffffffffff92831681529390911660208401527fffffffffffffffffffffffff0000000000000000000000000000000000000000927fe678f864bcd4f50e0554d3b42d5a0007424f154c8b29d4845c7c727f319cfd929190a11617600955005b6101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610733612ea4565b61073b613000565b6064359060a43567ffffffffffffffff81116102385761075f903690600401612e73565b60c4949194359373ffffffffffffffffffffffffffffffffffffffff91828616948587036102385760e4359063ffffffff821697888303610238576107a26136af565b6107aa6136e6565b857f00000000000000000000000000000000000000000000000000000000000000001633036109f0576107dc81614a2a565b885f52600460205260405f209386881694855f5260205260ff60405f205416156109c6578761084f9461082b9361081b61084a9e6108219536916134ea565b90614719565b916024358861490a565b61084460ff61083d84899e959e6130f3565b92166138dd565b906130f3565b6135e8565b9061085982614b63565b608435821061099c57855f52600c60205260405f20875f5260205260405f206108838382546135cd565b9055620186a09384840294848604148415171561096f577f7abcb23b61318b8b612c876bdf3070978b03e1fea48e9ee7bffb0b5b9c2f3a7c95620f4240606096049073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84145f1461093f5750610903826108f8836109099560085416613aea565b600754169186613180565b90613aea565b60405192835260208301526040820152a45f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b90610962836109578361096a96600854163387614a7f565b600754169187613180565b913390614a7f565b610909565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60046040517fbde82093000000000000000000000000000000000000000000000000000000008152fd5b60046040517f49a8defd000000000000000000000000000000000000000000000000000000008152fd5b60046040517f049809b1000000000000000000000000000000000000000000000000000000008152fd5b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610a51612ea4565b610a5a81614079565b610a6261361f565b60085473ffffffffffffffffffffffffffffffffffffffff80831692919081168381146105a2576040805173ffffffffffffffffffffffffffffffffffffffff92831681529390911660208401527fffffffffffffffffffffffff0000000000000000000000000000000000000000927ff84f6b525c89a18c80bbbc0c62a7eb5390956d6b8432ab067b49963a98f8c38f9190a11617600855005b6101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385767ffffffffffffffff60043581811161023857610b49903690600401612faa565b610b51612e60565b9060843583811161023857610b6a903690600401612e73565b93909160a43582811161023857610b85903690600401612e73565b909260c4359081116102385785610be0610ba6610be6933690600401612e73565b979099610bd9610bb4612ff0565b610bbc6136e6565b610bc46136af565b610124359061010435908a604435893461374a565b36916134ea565b33614217565b95610bef61318d565b94855115610d3657610c3c8861084a610c1e610c0c36888b613494565b610c173687896134ea565b90346138eb565b98610844610c3660ff602084519401511692346130f3565b916138dd565b95610c4687614b63565b606435871061099c577f09ff9f46a6c9284498f93ec69501b476a932c559367ec813559ecc046c47970c95610d0594610c81610cf793613ba5565b335f52600c602052610cce60405f209a63ffffffff81169b8c5f5260205260405f20610cae8c82546135cd565b9055610cbb368486613494565b3490610cc836898b6134ea565b90613c21565b610ce36040519760a0895260a0890190613538565b91346020890152878303604089015261357b565b9184830360608601526130b6565b9260808201528033930390a45f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b60046040517f358e2ce7000000000000000000000000000000000000000000000000000000008152fd5b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610d97612ea4565b610da081614079565b610da861361f565b6006549073ffffffffffffffffffffffffffffffffffffffff808360081c1690821681146105a2576040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527fffffffffffffffffffffff0000000000000000000000000000000000000000ff9274ffffffffffffffffffffffffffffffffffffffff009290917f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb91a160081b169116176006555f80f35b346102385760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610e99612ea4565b610ea1612e60565b73ffffffffffffffffffffffffffffffffffffffff60443592165f52600e60205263ffffffff60405f2091165f5260205260405f2090815481101561023857610eee60019160209361303f565b500154604051908152f35b346102385760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610f30612e4d565b6024359073ffffffffffffffffffffffffffffffffffffffff82168092036102385763ffffffff165f52600460205260405f20905f526020526040805f20600160ff825416910154825191151582526020820152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b346102385760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385767ffffffffffffffff60043581811161023857611026903690600401612e73565b602492918260243511610238573660236024350112156102385760243560040135928311610238573660248460071b81350101116102385761106661361f565b81156113d7578282036113ad575f5b82811061107e57005b838110156113815773ffffffffffffffffffffffffffffffffffffffff6110ae6110a9838686613085565b613095565b1690815f52600260205260405f206040516110c881612eff565b815473ffffffffffffffffffffffffffffffffffffffff811682526001602083019360ff8360a01c16855260ff604085019360a81c1683520154916060810192835285158015611352575b6113285773ffffffffffffffffffffffffffffffffffffffff90511673ffffffffffffffffffffffffffffffffffffffff6111568b8760071b6024350101613095565b16149283611303575b50826112de575b50816112c8575b506105a257604051828152868260071b60243501013573ffffffffffffffffffffffffffffffffffffffff8116809103610238576001938491602084015260448460071b602435010160ff6111c182613010565b16604085015260648560071b60243501019160ff6111de84613010565b1660608601527fe0ec1b96a1e4f66c20cac6575b2dd77087e61f31bc392fc4d419f8094731614760a060848860071b60243501013596876080820152a15f52600260205260405f209173ffffffffffffffffffffffffffffffffffffffff61124e8c8860071b6024350101613095565b167fffffffffffffffffffff0000000000000000000000000000000000000000000075ff0000000000000000000000000000000000000000006112b574ff00000000000000000000000000000000000000006112ab8854976135da565b60a01b16946135da565b60a81b1693161717178155015501611075565b90505160848260071b602435010135148761116d565b60ff919250511660ff6112fa60648560071b60243501016135da565b16149088611166565b60ff919350511660ff61131f60448660071b60243501016135da565b1614918961115f565b60046040517fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b5073ffffffffffffffffffffffffffffffffffffffff61137a8b8760071b6024350101613095565b1615611113565b847f4e487b71000000000000000000000000000000000000000000000000000000005f5260326004525ffd5b60046040517fa24a13a6000000000000000000000000000000000000000000000000000000008152fd5b60046040517f0f59b9ff000000000000000000000000000000000000000000000000000000008152fd5b34610238576101a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857611439612ea4565b611441613000565b9060643567ffffffffffffffff811161023857611462903690600401612faa565b63ffffffff60843516608435036102385760a43567ffffffffffffffff811161023857611493903690600401612e73565b60e43567ffffffffffffffff8111610238576114b3903690600401612e73565b9061010052936101043567ffffffffffffffff8111610238576114da903690600401612e73565b94906101243567ffffffffffffffff8111610238576114fd903690600401612e73565b60ff61014435166101443503610238576115156136af565b61151d6136e6565b61152561340e565b60c05261153560c051518761373d565b61155861018435610164356101443560ff8e166024358960c4356084358d614096565b6115618561339d565b998a5161190f575b8a51156118b8575b5089989798519860ff60408c015116610120525f9a5f8060e0525b60c0515160e051101561161f578b9c60e09c9b9c516115ac908b8d613085565b359d8e60e05160c051906115bf916138c9565b5160a05260a0516115cf916130f3565b610120516115dc906138dd565b6115e5916130f3565b906115ef916135e8565b6115f8916135cd565b9c60a051611605916130f3565b61160e916135cd565b9a600160e0510160e052999a61158c565b95979a50611645878d949596989b61163f608435913690610100516134ea565b33614719565b956c0c9f2c9cd04674edea40000000818181020481148215171561096f57876116729161167793026135e8565b614b63565b335f52600e60205260405f2063ffffffff608435165f5260205260405f20604051906116a282612ec7565b6116ad368e8d6134ea565b825287602083015280546801000000000000000081101561185f576116d79160018201815561303f565b91909161188c57805180519067ffffffffffffffff821161185f579060208493928f958361170491613106565b01835f5260205f206080525f5b8281106118465750505093899896936117a96117da946117886117827f5dbe2f6653b097c725ea541b559d74537b278e5d5ccbe362a3ede46a219de3689f9e611770906117e89c9861181e9f9c60206001910151910155873691613494565b61177b368b8d6134ea565b90886138eb565b826149a4565b61179336858e613494565b85608435916117a3368b8d6134ea565b90613e56565b51986117c76040519b8c9b8c5260e060208d015260e08c0190613538565b9260408b015289830360608b015261357b565b9186830360808801526130b6565b9060a084015282810360c084015263ffffffff608435169773ffffffffffffffffffffffffffffffffffffffff339816966130b6565b0390a45f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b81516080518201558f9550602090910190600101611711565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b602435158015611904575b6118da576024358b5260ff1660408b01528a611571565b60046040517f7c946ed7000000000000000000000000000000000000000000000000000000008152fd5b5060ff8116156118c3565b6024351580159061194a575b156115695760046040517ff443cb16000000000000000000000000000000000000000000000000000000008152fd5b5060ff8116151561191b565b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760015473ffffffffffffffffffffffffffffffffffffffff3381831603611a6d577fffffffffffffffffffffffff00000000000000000000000000000000000000008092166001555f549133908316175f553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60246040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152fd5b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385763ffffffff611ad9612e4d565b165f526005602052606060405f20805490600260018201549101549060405192835260208301526040820152f35b34610238576101c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857611b3f612ea4565b6024359060ff8216918281036102385767ffffffffffffffff906064359060443560a43584811161023857611b78903690600401612e73565b929060c43586811161023857611b92903690600401612e73565b91909560e43588811161023857611bad903690600401612e73565b9390986101043590811161023857611bc9903690600401612faa565b96610124359563ffffffff87169c8d880361023857610164359060ff82168203610238578c611c568f94611c42908f9d8f888f61163f611c4d9f611c6d9d610bd9611c5d9c611c3c9761084a9f611c1e6136af565b611c266136e6565b6101a435928b6101843593610144358b8d614096565b9761490a565b99909c883691613494565b918a36916134ea565b90876138eb565b9561084460ff61083d8c896130f3565b97611c7789614b63565b608435891061099c577ff82ed9a6275dc6dc2ba90dda55208d564fe360a9368512a219d6cbf1f95b427998611cf58c61181e988f8e8891611cbb611d299b866149a4565b335f52600c60205260405f20905f5260205260405f20611cdc8782546135cd565b90556117a3611cec368a8a613494565b918c36916134ea565b611d11604051998a998a5260c060208b015260c08a0190613538565b9360408901526060880152868303608088015261357b565b9083820360a085015273ffffffffffffffffffffffffffffffffffffffff339816966130b6565b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857611d87612ea4565b611d9081614079565b611d9861361f565b60075473ffffffffffffffffffffffffffffffffffffffff80831692919081168381146105a2576040805173ffffffffffffffffffffffffffffffffffffffff92831681529390911660208401527fffffffffffffffffffffffff0000000000000000000000000000000000000000927fb91dbdeaf34f885ccae2d8abc3967cb03c079b6af2c7944e3893fd29427d75e79190a11617600755005b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857611e6961361f565b5f73ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000806001541660015582549081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602063ffffffff60035416604051908152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602073ffffffffffffffffffffffffffffffffffffffff60065460081c16604051908152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610238576020600a54604051908152f35b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760043580151580910361023857611fea61361f565b6006549060ff821615158181146105a2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00917fe557486689c0bf71dde8cb27e7e87ed23badcf92ea724f4a0368676720d416f6604060ff938151908152836020820152a1169116176006555f80f35b346102385760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857612091612e4d565b60243590606435906044356120a461361f565b63ffffffff80921693827f0000000000000000000000000000000000000000000000000000000000000000168511801590612311575b6122e7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff850183811161096f5783165f526020926005845260405f2060405161212381612ee3565b8154815260406002600184015493888401948552015491019081526001880183811161096f5783165f526005865260405f209260026040519461216586612ee3565b80548652600181015489870152015492604085019384525185106122bd5760035416881415809381946122b2575b506122885751861061225e5781612253575b506122295783606093826121dd7fcf17268674ed4ffa34a117862c7b380287afb4c202e842a5f391b92219c0e02a9786600296613646565b604051906121ea82612ee3565b815281810194855260408101928352875f526005825260405f2090519485825551928360018301555193849101556040519384528301526040820152a2005b60046040517fecdcda19000000000000000000000000000000000000000000000000000000008152fd5b9050518411866121a5565b60046040517f434c92c9000000000000000000000000000000000000000000000000000000008152fd5b60046040517f649bb635000000000000000000000000000000000000000000000000000000008152fd5b905051851189612193565b60046040517f442db2a5000000000000000000000000000000000000000000000000000000008152fd5b60046040517f82a99657000000000000000000000000000000000000000000000000000000008152fd5b50826003541685116120da565b6101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760043567ffffffffffffffff811161023857612369903690600401612faa565b612371612e60565b9060443567ffffffffffffffff811161023857612392903690600401612e73565b6101405260843567ffffffffffffffff8111610238576123b6903690600401612e73565b929060a43567ffffffffffffffff8111610238576123d8903690600401612e73565b93909260c43567ffffffffffffffff8111610238576123fb903690600401612e73565b919095612406612ff0565b9561240f6136af565b6124176136e6565b61244661242261340e565b9761243189516101405161373d565b61012435906101043590866064358f3461374a565b61244e61318d565b998a5115610d36578a999897969a519960ff604082015116985f9c5f9d5f610160525b8a51610160511015612501579d8a8e9f8d9e9f8c9d9e9d610160516101405161249992613085565b3592610160516124a8916138c9565b519d6124b48f856130f3565b906124be906138dd565b6124c7916130f3565b906124d1916135e8565b6124da916135cd565b9b6124e4916130f3565b6124ed916135cd565b610160805160010190529d9c9b9a99612471565b96979899508d9a508361251961251f928e36916134ea565b33614524565b996c0c9f2c9cd04674edea400000009081810291818304149015171561096f576116728b61254c926135e8565b335f52600e60205260405f2063ffffffff84165f5260205260405f206040519061257582612ec7565b61258336610140518d6134ea565b82528b602083015280546801000000000000000081101561185f576125ad9160018201815561303f565b91909161188c57805180519067ffffffffffffffff821161185f576020906125d58386613106565b01835f5260205f205f5b83811061273957505050506020600191015191015561260d612602368787613494565b61177b368b856134ea565b9786341061270f576126ad876126d79763ffffffff976126bb966126647f8c39703f35c4905baa5728ffbd407e438efbfd3c9b2840fa6ca172e9b1228f1d9e61265860e09e34613180565b806126ff575b50613ba5565b61267f8985612674368787613494565b610cc8368b8d6134ea565b516126956040519d8d8f9e8f9081520190613538565b9360208d015260408c01528a830360608c015261357b565b9187830360808901526130b6565b9760a085015283880360c08501521695339561014051906130b6565b0390a35f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b6127099033613aea565b5f61265e565b60046040517f53d13992000000000000000000000000000000000000000000000000000000008152fd5b6001906020845194019381840155016125df565b346102385760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760043560443560243561278d61361f565b6003549263ffffffff9384811694855f52600560205260405f2091604051916127b583612ee3565b8354835260406002600186015495602086019687520154930192835280881461096f5760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000980116968791161760035551841061225e575181106128965782826128447f6877931d901fa420de6b1b5c5b565c4422ab189963a871c828e7b992220e95e39560609585613646565b6040519261285184612ee3565b83526020830190815260408301918252855f52600560205260405f209251928381558151600182015560028351910155604051928352516020830152516040820152a2005b60046040517fb290253c000000000000000000000000000000000000000000000000000000008152fd5b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857608073ffffffffffffffffffffffffffffffffffffffff8061290f612ea4565b165f52600260205260405f2060ff60018254920154916040519381168452818160a01c16602085015260a81c1660408301526060820152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760606129e16129dc612ea4565b61339d565b60ff6040805192805184528260208201511660208501520151166040820152f35b34610238576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385767ffffffffffffffff60043581811161023857612a53903690600401612e73565b91612a5c61361f565b5f5b838110612bba575060405190604082019160408152600b5480935260608101600b5f527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db95f5b88868210612ba6575050509080612ae583827f434c23397dc47fd4a6b168de7abb8861c6bddc55b261df6bfb58d89c92be92db9503602084015288886130b6565b0390a1831161185f5768010000000000000000831161185f5782600b55808310612b48575b505f5b828110612b1657005b81357f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db982015590830190600101612b0d565b7f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db901827f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9015b818110612b9b5750612b0a565b5f8155600101612b8e565b825484529092019160019182019101612aa4565b80612bd1612bcb6001938787613085565b3561363f565b01612a5e565b346102385760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857612c0e612e4d565b67ffffffffffffffff60243581811161023857612c2f903690600401612e73565b909160443581811161023857612c49903690600401612e73565b909160643590811161023857612c63903690600401612e73565b9095612c6d61361f565b84156113d757828514801590612d87575b6113ad5763ffffffff1691825f52602090600460205260405f20955f5b818110612ca457005b73ffffffffffffffffffffffffffffffffffffffff612cc76110a983858d613085565b1690811561132857612cda81858a613085565b3580151580910361023857600192887fc1a8d3b5c8695d3120c5ea6e6afca4fd990747cccf9c4513cbc02baf1c32e40d888f8e95612d1a888e8b94613085565b359660405191612d2983612ec7565b8252838201978852865f52835260405f209051151596612d7488839060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b519182910155604051908152a401612c9b565b5081831415612c7e565b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760209073ffffffffffffffffffffffffffffffffffffffff600954168152f35b6004359063ffffffff8216820361023857565b6024359063ffffffff8216820361023857565b9181601f840112156102385782359167ffffffffffffffff8311610238576020808501948460051b01011161023857565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361023857565b6040810190811067ffffffffffffffff82111761185f57604052565b6060810190811067ffffffffffffffff82111761185f57604052565b6080810190811067ffffffffffffffff82111761185f57604052565b67ffffffffffffffff811161185f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761185f57604052565b67ffffffffffffffff811161185f57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f8201121561023857803590612fc182612f70565b92612fcf6040519485612f2f565b8284526020838301011161023857815f926020809301838601378301015290565b60e4359060ff8216820361023857565b6044359060ff8216820361023857565b359060ff8216820361023857565b359073ffffffffffffffffffffffffffffffffffffffff8216820361023857565b8054821015613058575f5260205f209060011b01905f90565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b91908110156130585760051b0190565b3573ffffffffffffffffffffffffffffffffffffffff811681036102385790565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116102385760209260051b809284830137010190565b8181029291811591840414171561096f57565b9068010000000000000000811161185f5781549181815582821061312957505050565b5f5260205f2091820191015b818110613140575050565b5f8155600101613135565b6040519061315882612ee3565b5f6040838281528260208201520152565b519069ffffffffffffffffffff8216820361023857565b9190820391821161096f57565b61319561314b565b5073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5f52600260205260408051907f6a26712a1b2f732f4c1fd85f9d6ed8235573aaa2a79aa2bab72c2423a73a9faf906131e283612eff565b81549173ffffffffffffffffffffffffffffffffffffffff80841685526001602086019260ff8660a01c16845260ff8588019660a81c1686520154906060860191825261322d61314b565b955116948515613394575060a06004958451968780927ffeaf968c0000000000000000000000000000000000000000000000000000000082525afa90811561338a575f80965f93613326575b5069ffffffffffffffffffff16156132fd5781159182156132e7575b50506132be5760ff80915116925116918151936132b185612ee3565b8452602084015282015290565b600482517f1f4bcb2b000000000000000000000000000000000000000000000000000000008152fd5b6132f391925042613180565b9051105f80613295565b600484517fa5959c59000000000000000000000000000000000000000000000000000000008152fd5b965050905060a0853d60a011613382575b8161334460a09383612f2f565b810103126102385761335585613169565b9069ffffffffffffffffffff602087015192613378608060608a01519901613169565b5092969290613279565b3d9150613337565b83513d5f823e3d90fd5b94505050505090565b6133a561314b565b5073ffffffffffffffffffffffffffffffffffffffff8091165f526002602052604090815f20918051926133d884612eff565b80549280841685526001602086019260ff8660a01c16845260ff8588019660a81c1686520154906060860191825261322d61314b565b60405190600b54808352826020916020820190600b5f527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9935f905b8282106134625750505061346092500383612f2f565b565b85548452600195860195889550938101939091019061344a565b67ffffffffffffffff811161185f5760051b60200190565b929161349f8261347c565b916134ad6040519384612f2f565b829481845260208094019160051b810192831161023857905b8282106134d35750505050565b8380916134df8461301e565b8152019101906134c6565b92916134f58261347c565b916135036040519384612f2f565b829481845260208094019160051b810192831161023857905b8282106135295750505050565b8135815290830190830161351c565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b9190808252602080920192915f5b828110613597575050505090565b90919293828060019273ffffffffffffffffffffffffffffffffffffffff6135be8961301e565b16815201950193929101613589565b9190820180921161096f57565b3560ff811681036102385790565b81156135f2570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b73ffffffffffffffffffffffffffffffffffffffff5f54163303611a6d57565b156118da57565b90428210612896571115613685571561365b57565b60046040517f2013535a000000000000000000000000000000000000000000000000000000008152fd5b60046040517f38af65f7000000000000000000000000000000000000000000000000000000008152fd5b60ff60065416156136bc57565b60046040517f4f9852e8000000000000000000000000000000000000000000000000000000008152fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805c613713576001905d565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b80156113d757036113ad57565b61375a909796959493929761363f565b86421161389f5763ffffffff9061377033614a2a565b1695865f52602060048152604097885f2073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5f52825260ff895f20541615613876575f5260058152875f2088516137ba81612ee3565b8154908181528a60026001850154948684019586520154910152421061384d575142101561382457605461381c91613460989951938185928301963360601b8852805191829101603485015e8201906034820152036034810184520182612f2f565b519020614bcf565b600488517f6b5fd31b000000000000000000000000000000000000000000000000000000008152fd5b600489517f8e9c6e1c000000000000000000000000000000000000000000000000000000008152fd5b600489517f49a8defd000000000000000000000000000000000000000000000000000000008152fd5b60046040517f1ab7da6b000000000000000000000000000000000000000000000000000000008152fd5b80518210156130585760209160051b010190565b604d811161096f57600a0a90565b9092916040908151926138fd84612eff565b5f845260208401935f8552838101935f855260608201935f855282986139228561363f565b614e209384860297861595878a041486171561096f57620f42408099049052620186a0808702908782041486171561096f57889004895262099cf0808702908782041486171561096f578890049052515f918115613ac15760058211613a985780518203613a6f57905f915b818310613a4c575050508015613a23576203d090918282116139fa575080866139b88493876130f3565b048652106139c9575b505050505050565b80830292830414171561096f576139ed926139e692519104613180565b82516135cd565b90525f80808080806139c1565b600490517f1f3b85d3000000000000000000000000000000000000000000000000000000008152fd5b600482517f7c946ed7000000000000000000000000000000000000000000000000000000008152fd5b909192613a66600191613a5f86856138c9565b51906135cd565b9301919061398e565b600484517fa24a13a6000000000000000000000000000000000000000000000000000000008152fd5b600484517f9d89020a000000000000000000000000000000000000000000000000000000008152fd5b600484517f5cb045db000000000000000000000000000000000000000000000000000000008152fd5b814710613b6d575f80809373ffffffffffffffffffffffffffffffffffffffff8294165af13d15613b68573d613b1f81612f70565b90613b2d6040519283612f2f565b81525f60203d92013e5b15613b3e57565b60046040517fd6bda275000000000000000000000000000000000000000000000000000000008152fd5b613b37565b6044824790604051917fcf47918100000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b61346090606073ffffffffffffffffffffffffffffffffffffffff91613bd18360075416825190613aea565b613be48360085416602083015190613aea565b613bf78360095416604083015190613aea565b0151907f000000000000000000000000000000000000000000000000000000000000000016613aea565b805190613c2d8261347c565b91604094613c3d86519485612f2f565b818452613c498261347c565b947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060209601865f5b828110613e35575050505f5b838110613dd6575050505073ffffffffffffffffffffffffffffffffffffffff92837f00000000000000000000000000000000000000000000000000000000000000001693843b15610238579095929185519687947f47437b680000000000000000000000000000000000000000000000000000000086526064860160606004880152835180915282608488019401905f5b818110613dbd5750505063ffffffff1660248601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8583030160448601528080855193848152019401925f905b88848310613d975750505050505091815f81819503925af1908115613d8e5750613d855750565b61346090612f1b565b513d5f823e3d90fd5b8551805183168852840151848801528a9750909501949382019360019190910190613d5e565b8251871686528b98509484019491840191600101613d10565b80620f4240613df1613dea600194866138c9565b51866130f3565b04895190613dfe82612ec7565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee825289820152613e2382896138c9565b52613e2e81886138c9565b5001613c7e565b8951613e4081612ec7565b5f81525f8382015282828a010152018790613c72565b93909192938051613e668161347c565b92604095613e7687519586612f2f565b828552613e828361347c565b957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060209701875f5b828110614058575050505f5b848110613ffe57505050505073ffffffffffffffffffffffffffffffffffffffff92837f00000000000000000000000000000000000000000000000000000000000000001693843b15610238579095929185519687947f47437b680000000000000000000000000000000000000000000000000000000086526064860160606004880152835180915282608488019401905f5b818110613fe55750505063ffffffff1660248601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8583030160448601528080855193848152019401925f905b88848310613fbf5750505050505091815f81819503925af1908115613d8e5750613d855750565b8551805183168852840151848801528a9750909501949382019360019190910190613f98565b8251871686528b98509484019491840191600101613f4a565b80620f4240614012613dea600194866138c9565b048a519061401f82612ec7565b73ffffffffffffffffffffffffffffffffffffffff871682528a820152614046828a6138c9565b5261405181896138c9565b5001613eb7565b8a5161406381612ec7565b5f81525f8382015282828b010152018890613eab565b73ffffffffffffffffffffffffffffffffffffffff161561132857565b9192939098979695949883421161389f5763ffffffff906140b633614a2a565b1698895f526020926004845260409a8b5f2073ffffffffffffffffffffffffffffffffffffffff83165f52855260ff8c5f205416156141ee575f52600584528a5f208b5161410381612ee3565b8154908181528d6002600185015494898401958652015491015242106141c5575142101561419c579161381c93917fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060a8946134609c9d519785899687019a3360601b8c52805191829101603489015e8601946034860152605485015260601b1660748301526088820152036088810184520182612f2f565b60048b517f6b5fd31b000000000000000000000000000000000000000000000000000000008152fd5b60048c517f8e9c6e1c000000000000000000000000000000000000000000000000000000008152fd5b60048c517f49a8defd000000000000000000000000000000000000000000000000000000008152fd5b909163ffffffff1690815f526004602093818552604093845f2073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5f5286526001946001815f2001548015155f14614510575b80975f96855192831561450257505f9792979273ffffffffffffffffffffffffffffffffffffffff96877f000000000000000000000000000000000000000000000000000000000000000016945b8a81106142c3575b50505050505050505050505090565b8b81018082116144d657808c0361448c575b506142e081836138c9565b51928751907f584b62a10000000000000000000000000000000000000000000000000000000082528a86168c8301526024948583015288826044818b5afa908115614451575f9161445b575b61433692506135cd565b9287517ff188768400000000000000000000000000000000000000000000000000000000815286818d818b5afa908115614451575f91614424575b5084101561438157508b016142ac565b9a50505050505050509050929092145f146143f85762030d40918284029284840414841517156143ce57505090620f42406143bd920490613180565b5f80808080808080808080806142b4565b6011907f4e487b71000000000000000000000000000000000000000000000000000000005f52525ffd5b62011170918284029284840414841517156143ce57505090620f424061441f920490613180565b6143bd565b90508681813d831161444a575b61443b8183612f2f565b8101031261023857515f614371565b503d614431565b89513d5f823e3d90fd5b90508882813d8311614485575b6144728183612f2f565b810103126102385761433691519061432c565b503d614468565b6144a161449983856138c9565b5191846138c9565b5111156144ae575f6142d5565b8987517f5b938576000000000000000000000000000000000000000000000000000000008152fd5b60118b7f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b995050505050505050505090565b50815f52600587526002815f20015461425e565b909163ffffffff1690815f526004602093818552604093845f2073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5f5286526001946001815f2001548015155f14614705575b80975f96855192831561450257505f9792979273ffffffffffffffffffffffffffffffffffffffff96877f000000000000000000000000000000000000000000000000000000000000000016945b8a81106145cf5750505050505050505050505090565b8b81018082116144d657808c036146eb575b506145ec81836138c9565b51928751907f584b62a10000000000000000000000000000000000000000000000000000000082528a86168c8301526024948583015288826044818b5afa908115614451575f916146ba575b61464292506135cd565b9287517ff188768400000000000000000000000000000000000000000000000000000000815286818d818b5afa908115614451575f9161468d575b5084101561438157508b016145b9565b90508681813d83116146b3575b6146a48183612f2f565b8101031261023857515f61467d565b503d61469a565b90508882813d83116146e4575b6146d18183612f2f565b8101031261023857614642915190614638565b503d6146c7565b6146f861449983856138c9565b5111156144ae575f6145e1565b50815f52600587526002815f20015461456b565b929163ffffffff1691825f526004906020938285526040805f2073ffffffffffffffffffffffffffffffffffffffff8094165f5286526001956001825f2001548015155f146148f557905b81985f88519384156148e6575092977f0000000000000000000000000000000000000000000000000000000000000000871693905f5b8a81106147b05750505050505050505050505090565b8b81018082116144d657808c036148cc575b506147cd81836138c9565b51928751907f584b62a10000000000000000000000000000000000000000000000000000000082528a86168c8301526024948583015288826044818b5afa908115614451575f9161489b575b61482392506135cd565b9287517ff188768400000000000000000000000000000000000000000000000000000000815286818d818b5afa908115614451575f9161486e575b5084101561438157508b0161479a565b90508681813d8311614894575b6148858183612f2f565b8101031261023857515f61485e565b503d61487b565b90508882813d83116148c5575b6148b28183612f2f565b8101031261023857614823915190614819565b503d6148a8565b6148d961449983856138c9565b5111156144ae575f6147c2565b9a505050505050505050505090565b50825f52600581526002825f20015490614764565b6149169093929361339d565b92835161495f575b835115614935575b505060ff602083519301511690565b81158015614954575b6118da5760ff9184521660208301525f80614926565b5060ff81161561493e565b8115801590614998575b1561491e5760046040517ff443cb16000000000000000000000000000000000000000000000000000000008152fd5b5060ff81161515614969565b9061346091606073ffffffffffffffffffffffffffffffffffffffff926149d384600754168251903386614a7f565b6149e884600854166020830151903386614a7f565b6149fd84600954166040830151903386614a7f565b0151917f000000000000000000000000000000000000000000000000000000000000000016903390614a7f565b73ffffffffffffffffffffffffffffffffffffffff165f52600d60205260ff60405f205416614a5557565b60046040517f09550c77000000000000000000000000000000000000000000000000000000008152fd5b92906040519160208301917f23b872dd00000000000000000000000000000000000000000000000000000000835273ffffffffffffffffffffffffffffffffffffffff9485809216602486015216604484015260648301526064825260a082019082821067ffffffffffffffff83111761185f576020925f92604052519082865af115614b58575f513d614b4f57508082163b155b614b1c575050565b60249250604051917f5274afe7000000000000000000000000000000000000000000000000000000008352166004820152fd5b60011415614b14565b6040513d5f823e3d90fd5b600a5490614b7182826135cd565b7f000000000000000000000000000000000000000000000000000000000000000010614ba557614ba0916135cd565b600a55565b60046040517ff10b176b000000000000000000000000000000000000000000000000000000008152fd5b92614c2790614c30929373ffffffffffffffffffffffffffffffffffffffff948560065460081c16967f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f52601c52603c5f20614c62565b90929192614cf1565b1603614c3857565b60046040517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614ce6579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15614b58575f5173ffffffffffffffffffffffffffffffffffffffff811615614cdc57905f905f90565b505f906001905f90565b5050505f9160039190565b6004811015614da95780614d03575050565b60018103614d355760046040517ff645eedf000000000000000000000000000000000000000000000000000000008152fd5b60028103614d6e57602482604051907ffce698f70000000000000000000000000000000000000000000000000000000082526004820152fd5b600314614d785750565b602490604051907fd78bce0c0000000000000000000000000000000000000000000000000000000082526004820152fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffdfea2646970667358221220b1ecf4e9ce5db9e3b095ac0789c1a5040771ec895742a0a324fff2008535afbe64736f6c6343000819003300000000000000000000000060bcf12a2da761e909c3bc29f1cd13ef1e4847a0000000000000000000000000a2f78a912ba4337692a399407728784fb6b24fb1000000000000000000000000e1de0ef1fa1f3e5e1f2b2ad134fb2c3135cefa3b0000000000000000000000008002917a84db1b1ef57f7cf0b19f5f5c611db9d50000000000000000000000001890cf752f1be4d60f3b22168c7a6afebd9d74c70000000000000000000000006a1aa5ac35f38bdb25bbd976e8eca942b23260b20000000000000000000000005d7f0ed4ea8eb7a6e0a6acf1de9c91be0696871600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000010f6b2be4706a13fc20000000000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000001dcd6500000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000006fc23ac000000000000000000000000000000000000000000000000000000001176592e00
Deployed Bytecode
0x610180806040526004361015610013575f80fd5b5f3560e01c9081630622874914612dff5750806306490f4714612d915780630a7e0c5614612bd7578063161c9d0114612a0257806316345f18146129a057806323548b8b1461294857806327e45c2c146128c05780632a2530261461274d5780632a302af71461231e5780632d55e7df1461205a57806341e7e34114611fa65780635962a94114611f6b57806364f0d35e14611f175780636de7da7814611ed6578063715018a614611e335780637192762814611d505780637459663314611b0757806379a6d51f14611a9d57806379ba5097146119c45780637fcb09721461195657806382e0c47d1461140157806383ed138514610fd65780638da5cb5b14610f8657806392f5888114610ef957806395f0024014610e62578063aad2b72314610d60578063ad9bf0f414610afd578063ada4ef3014610a1a578063ade1721e14610700578063b38393891461061d578063beb08ab9146105cc578063e09590d1146104ad578063e30c39781461045c578063e9f8958f146103e0578063f2fde38b14610335578063f3290d75146102cd578063f582d2931461028d578063fa2af9da1461023c5763fc7a822d146101ca575f80fd5b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857600435600b5481101561023857602090600b5f527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90154604051908152f35b5f80fd5b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602073ffffffffffffffffffffffffffffffffffffffff60085416604051908152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602060ff600654166040519015158152f35b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385773ffffffffffffffffffffffffffffffffffffffff610319612ea4565b165f52600d602052602060ff60405f2054166040519015158152f35b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385761036c612ea4565b61037461361f565b73ffffffffffffffffffffffffffffffffffffffff80911690817fffffffffffffffffffffffff000000000000000000000000000000000000000060015416176001555f54167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b346102385760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610417612ea4565b73ffffffffffffffffffffffffffffffffffffffff610434612e60565b91165f52600c60205263ffffffff60405f2091165f52602052602060405f2054604051908152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346102385760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610238576104e4612ea4565b60243580151591828203610238578061051173ffffffffffffffffffffffffffffffffffffffff92614079565b61051961361f565b16805f52600d6020528260ff60405f2054161515146105a2577f6a12b3df6cba4203bd7fd06b816789f87de8c594299aed5717ae070fac781bac60406105a0948151908482526020820152a15f52600d60205260405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b005b60046040517f2620eb3a000000000000000000000000000000000000000000000000000000008152fd5b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602073ffffffffffffffffffffffffffffffffffffffff60075416604051908152f35b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610654612ea4565b61065d81614079565b61066561361f565b60095473ffffffffffffffffffffffffffffffffffffffff80831692919081168381146105a2576040805173ffffffffffffffffffffffffffffffffffffffff92831681529390911660208401527fffffffffffffffffffffffff0000000000000000000000000000000000000000927fe678f864bcd4f50e0554d3b42d5a0007424f154c8b29d4845c7c727f319cfd929190a11617600955005b6101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610733612ea4565b61073b613000565b6064359060a43567ffffffffffffffff81116102385761075f903690600401612e73565b60c4949194359373ffffffffffffffffffffffffffffffffffffffff91828616948587036102385760e4359063ffffffff821697888303610238576107a26136af565b6107aa6136e6565b857f0000000000000000000000001890cf752f1be4d60f3b22168c7a6afebd9d74c71633036109f0576107dc81614a2a565b885f52600460205260405f209386881694855f5260205260ff60405f205416156109c6578761084f9461082b9361081b61084a9e6108219536916134ea565b90614719565b916024358861490a565b61084460ff61083d84899e959e6130f3565b92166138dd565b906130f3565b6135e8565b9061085982614b63565b608435821061099c57855f52600c60205260405f20875f5260205260405f206108838382546135cd565b9055620186a09384840294848604148415171561096f577f7abcb23b61318b8b612c876bdf3070978b03e1fea48e9ee7bffb0b5b9c2f3a7c95620f4240606096049073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84145f1461093f5750610903826108f8836109099560085416613aea565b600754169186613180565b90613aea565b60405192835260208301526040820152a45f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b90610962836109578361096a96600854163387614a7f565b600754169187613180565b913390614a7f565b610909565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60046040517fbde82093000000000000000000000000000000000000000000000000000000008152fd5b60046040517f49a8defd000000000000000000000000000000000000000000000000000000008152fd5b60046040517f049809b1000000000000000000000000000000000000000000000000000000008152fd5b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610a51612ea4565b610a5a81614079565b610a6261361f565b60085473ffffffffffffffffffffffffffffffffffffffff80831692919081168381146105a2576040805173ffffffffffffffffffffffffffffffffffffffff92831681529390911660208401527fffffffffffffffffffffffff0000000000000000000000000000000000000000927ff84f6b525c89a18c80bbbc0c62a7eb5390956d6b8432ab067b49963a98f8c38f9190a11617600855005b6101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385767ffffffffffffffff60043581811161023857610b49903690600401612faa565b610b51612e60565b9060843583811161023857610b6a903690600401612e73565b93909160a43582811161023857610b85903690600401612e73565b909260c4359081116102385785610be0610ba6610be6933690600401612e73565b979099610bd9610bb4612ff0565b610bbc6136e6565b610bc46136af565b610124359061010435908a604435893461374a565b36916134ea565b33614217565b95610bef61318d565b94855115610d3657610c3c8861084a610c1e610c0c36888b613494565b610c173687896134ea565b90346138eb565b98610844610c3660ff602084519401511692346130f3565b916138dd565b95610c4687614b63565b606435871061099c577f09ff9f46a6c9284498f93ec69501b476a932c559367ec813559ecc046c47970c95610d0594610c81610cf793613ba5565b335f52600c602052610cce60405f209a63ffffffff81169b8c5f5260205260405f20610cae8c82546135cd565b9055610cbb368486613494565b3490610cc836898b6134ea565b90613c21565b610ce36040519760a0895260a0890190613538565b91346020890152878303604089015261357b565b9184830360608601526130b6565b9260808201528033930390a45f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b60046040517f358e2ce7000000000000000000000000000000000000000000000000000000008152fd5b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610d97612ea4565b610da081614079565b610da861361f565b6006549073ffffffffffffffffffffffffffffffffffffffff808360081c1690821681146105a2576040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527fffffffffffffffffffffff0000000000000000000000000000000000000000ff9274ffffffffffffffffffffffffffffffffffffffff009290917f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb91a160081b169116176006555f80f35b346102385760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610e99612ea4565b610ea1612e60565b73ffffffffffffffffffffffffffffffffffffffff60443592165f52600e60205263ffffffff60405f2091165f5260205260405f2090815481101561023857610eee60019160209361303f565b500154604051908152f35b346102385760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857610f30612e4d565b6024359073ffffffffffffffffffffffffffffffffffffffff82168092036102385763ffffffff165f52600460205260405f20905f526020526040805f20600160ff825416910154825191151582526020820152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b346102385760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385767ffffffffffffffff60043581811161023857611026903690600401612e73565b602492918260243511610238573660236024350112156102385760243560040135928311610238573660248460071b81350101116102385761106661361f565b81156113d7578282036113ad575f5b82811061107e57005b838110156113815773ffffffffffffffffffffffffffffffffffffffff6110ae6110a9838686613085565b613095565b1690815f52600260205260405f206040516110c881612eff565b815473ffffffffffffffffffffffffffffffffffffffff811682526001602083019360ff8360a01c16855260ff604085019360a81c1683520154916060810192835285158015611352575b6113285773ffffffffffffffffffffffffffffffffffffffff90511673ffffffffffffffffffffffffffffffffffffffff6111568b8760071b6024350101613095565b16149283611303575b50826112de575b50816112c8575b506105a257604051828152868260071b60243501013573ffffffffffffffffffffffffffffffffffffffff8116809103610238576001938491602084015260448460071b602435010160ff6111c182613010565b16604085015260648560071b60243501019160ff6111de84613010565b1660608601527fe0ec1b96a1e4f66c20cac6575b2dd77087e61f31bc392fc4d419f8094731614760a060848860071b60243501013596876080820152a15f52600260205260405f209173ffffffffffffffffffffffffffffffffffffffff61124e8c8860071b6024350101613095565b167fffffffffffffffffffff0000000000000000000000000000000000000000000075ff0000000000000000000000000000000000000000006112b574ff00000000000000000000000000000000000000006112ab8854976135da565b60a01b16946135da565b60a81b1693161717178155015501611075565b90505160848260071b602435010135148761116d565b60ff919250511660ff6112fa60648560071b60243501016135da565b16149088611166565b60ff919350511660ff61131f60448660071b60243501016135da565b1614918961115f565b60046040517fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b5073ffffffffffffffffffffffffffffffffffffffff61137a8b8760071b6024350101613095565b1615611113565b847f4e487b71000000000000000000000000000000000000000000000000000000005f5260326004525ffd5b60046040517fa24a13a6000000000000000000000000000000000000000000000000000000008152fd5b60046040517f0f59b9ff000000000000000000000000000000000000000000000000000000008152fd5b34610238576101a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857611439612ea4565b611441613000565b9060643567ffffffffffffffff811161023857611462903690600401612faa565b63ffffffff60843516608435036102385760a43567ffffffffffffffff811161023857611493903690600401612e73565b60e43567ffffffffffffffff8111610238576114b3903690600401612e73565b9061010052936101043567ffffffffffffffff8111610238576114da903690600401612e73565b94906101243567ffffffffffffffff8111610238576114fd903690600401612e73565b60ff61014435166101443503610238576115156136af565b61151d6136e6565b61152561340e565b60c05261153560c051518761373d565b61155861018435610164356101443560ff8e166024358960c4356084358d614096565b6115618561339d565b998a5161190f575b8a51156118b8575b5089989798519860ff60408c015116610120525f9a5f8060e0525b60c0515160e051101561161f578b9c60e09c9b9c516115ac908b8d613085565b359d8e60e05160c051906115bf916138c9565b5160a05260a0516115cf916130f3565b610120516115dc906138dd565b6115e5916130f3565b906115ef916135e8565b6115f8916135cd565b9c60a051611605916130f3565b61160e916135cd565b9a600160e0510160e052999a61158c565b95979a50611645878d949596989b61163f608435913690610100516134ea565b33614719565b956c0c9f2c9cd04674edea40000000818181020481148215171561096f57876116729161167793026135e8565b614b63565b335f52600e60205260405f2063ffffffff608435165f5260205260405f20604051906116a282612ec7565b6116ad368e8d6134ea565b825287602083015280546801000000000000000081101561185f576116d79160018201815561303f565b91909161188c57805180519067ffffffffffffffff821161185f579060208493928f958361170491613106565b01835f5260205f206080525f5b8281106118465750505093899896936117a96117da946117886117827f5dbe2f6653b097c725ea541b559d74537b278e5d5ccbe362a3ede46a219de3689f9e611770906117e89c9861181e9f9c60206001910151910155873691613494565b61177b368b8d6134ea565b90886138eb565b826149a4565b61179336858e613494565b85608435916117a3368b8d6134ea565b90613e56565b51986117c76040519b8c9b8c5260e060208d015260e08c0190613538565b9260408b015289830360608b015261357b565b9186830360808801526130b6565b9060a084015282810360c084015263ffffffff608435169773ffffffffffffffffffffffffffffffffffffffff339816966130b6565b0390a45f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b81516080518201558f9550602090910190600101611711565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b602435158015611904575b6118da576024358b5260ff1660408b01528a611571565b60046040517f7c946ed7000000000000000000000000000000000000000000000000000000008152fd5b5060ff8116156118c3565b6024351580159061194a575b156115695760046040517ff443cb16000000000000000000000000000000000000000000000000000000008152fd5b5060ff8116151561191b565b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000001890cf752f1be4d60f3b22168c7a6afebd9d74c7168152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760015473ffffffffffffffffffffffffffffffffffffffff3381831603611a6d577fffffffffffffffffffffffff00000000000000000000000000000000000000008092166001555f549133908316175f553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60246040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152fd5b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385763ffffffff611ad9612e4d565b165f526005602052606060405f20805490600260018201549101549060405192835260208301526040820152f35b34610238576101c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857611b3f612ea4565b6024359060ff8216918281036102385767ffffffffffffffff906064359060443560a43584811161023857611b78903690600401612e73565b929060c43586811161023857611b92903690600401612e73565b91909560e43588811161023857611bad903690600401612e73565b9390986101043590811161023857611bc9903690600401612faa565b96610124359563ffffffff87169c8d880361023857610164359060ff82168203610238578c611c568f94611c42908f9d8f888f61163f611c4d9f611c6d9d610bd9611c5d9c611c3c9761084a9f611c1e6136af565b611c266136e6565b6101a435928b6101843593610144358b8d614096565b9761490a565b99909c883691613494565b918a36916134ea565b90876138eb565b9561084460ff61083d8c896130f3565b97611c7789614b63565b608435891061099c577ff82ed9a6275dc6dc2ba90dda55208d564fe360a9368512a219d6cbf1f95b427998611cf58c61181e988f8e8891611cbb611d299b866149a4565b335f52600c60205260405f20905f5260205260405f20611cdc8782546135cd565b90556117a3611cec368a8a613494565b918c36916134ea565b611d11604051998a998a5260c060208b015260c08a0190613538565b9360408901526060880152868303608088015261357b565b9083820360a085015273ffffffffffffffffffffffffffffffffffffffff339816966130b6565b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857611d87612ea4565b611d9081614079565b611d9861361f565b60075473ffffffffffffffffffffffffffffffffffffffff80831692919081168381146105a2576040805173ffffffffffffffffffffffffffffffffffffffff92831681529390911660208401527fffffffffffffffffffffffff0000000000000000000000000000000000000000927fb91dbdeaf34f885ccae2d8abc3967cb03c079b6af2c7944e3893fd29427d75e79190a11617600755005b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857611e6961361f565b5f73ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000806001541660015582549081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602063ffffffff60035416604051908152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602073ffffffffffffffffffffffffffffffffffffffff60065460081c16604051908152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610238576020600a54604051908152f35b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760043580151580910361023857611fea61361f565b6006549060ff821615158181146105a2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00917fe557486689c0bf71dde8cb27e7e87ed23badcf92ea724f4a0368676720d416f6604060ff938151908152836020820152a1169116176006555f80f35b346102385760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857612091612e4d565b60243590606435906044356120a461361f565b63ffffffff80921693827f0000000000000000000000000000000000000000000000000000000000000000168511801590612311575b6122e7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff850183811161096f5783165f526020926005845260405f2060405161212381612ee3565b8154815260406002600184015493888401948552015491019081526001880183811161096f5783165f526005865260405f209260026040519461216586612ee3565b80548652600181015489870152015492604085019384525185106122bd5760035416881415809381946122b2575b506122885751861061225e5781612253575b506122295783606093826121dd7fcf17268674ed4ffa34a117862c7b380287afb4c202e842a5f391b92219c0e02a9786600296613646565b604051906121ea82612ee3565b815281810194855260408101928352875f526005825260405f2090519485825551928360018301555193849101556040519384528301526040820152a2005b60046040517fecdcda19000000000000000000000000000000000000000000000000000000008152fd5b9050518411866121a5565b60046040517f434c92c9000000000000000000000000000000000000000000000000000000008152fd5b60046040517f649bb635000000000000000000000000000000000000000000000000000000008152fd5b905051851189612193565b60046040517f442db2a5000000000000000000000000000000000000000000000000000000008152fd5b60046040517f82a99657000000000000000000000000000000000000000000000000000000008152fd5b50826003541685116120da565b6101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760043567ffffffffffffffff811161023857612369903690600401612faa565b612371612e60565b9060443567ffffffffffffffff811161023857612392903690600401612e73565b6101405260843567ffffffffffffffff8111610238576123b6903690600401612e73565b929060a43567ffffffffffffffff8111610238576123d8903690600401612e73565b93909260c43567ffffffffffffffff8111610238576123fb903690600401612e73565b919095612406612ff0565b9561240f6136af565b6124176136e6565b61244661242261340e565b9761243189516101405161373d565b61012435906101043590866064358f3461374a565b61244e61318d565b998a5115610d36578a999897969a519960ff604082015116985f9c5f9d5f610160525b8a51610160511015612501579d8a8e9f8d9e9f8c9d9e9d610160516101405161249992613085565b3592610160516124a8916138c9565b519d6124b48f856130f3565b906124be906138dd565b6124c7916130f3565b906124d1916135e8565b6124da916135cd565b9b6124e4916130f3565b6124ed916135cd565b610160805160010190529d9c9b9a99612471565b96979899508d9a508361251961251f928e36916134ea565b33614524565b996c0c9f2c9cd04674edea400000009081810291818304149015171561096f576116728b61254c926135e8565b335f52600e60205260405f2063ffffffff84165f5260205260405f206040519061257582612ec7565b61258336610140518d6134ea565b82528b602083015280546801000000000000000081101561185f576125ad9160018201815561303f565b91909161188c57805180519067ffffffffffffffff821161185f576020906125d58386613106565b01835f5260205f205f5b83811061273957505050506020600191015191015561260d612602368787613494565b61177b368b856134ea565b9786341061270f576126ad876126d79763ffffffff976126bb966126647f8c39703f35c4905baa5728ffbd407e438efbfd3c9b2840fa6ca172e9b1228f1d9e61265860e09e34613180565b806126ff575b50613ba5565b61267f8985612674368787613494565b610cc8368b8d6134ea565b516126956040519d8d8f9e8f9081520190613538565b9360208d015260408c01528a830360608c015261357b565b9187830360808901526130b6565b9760a085015283880360c08501521695339561014051906130b6565b0390a35f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b6127099033613aea565b5f61265e565b60046040517f53d13992000000000000000000000000000000000000000000000000000000008152fd5b6001906020845194019381840155016125df565b346102385760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760043560443560243561278d61361f565b6003549263ffffffff9384811694855f52600560205260405f2091604051916127b583612ee3565b8354835260406002600186015495602086019687520154930192835280881461096f5760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000980116968791161760035551841061225e575181106128965782826128447f6877931d901fa420de6b1b5c5b565c4422ab189963a871c828e7b992220e95e39560609585613646565b6040519261285184612ee3565b83526020830190815260408301918252855f52600560205260405f209251928381558151600182015560028351910155604051928352516020830152516040820152a2005b60046040517fb290253c000000000000000000000000000000000000000000000000000000008152fd5b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857608073ffffffffffffffffffffffffffffffffffffffff8061290f612ea4565b165f52600260205260405f2060ff60018254920154916040519381168452818160a01c16602085015260a81c1660408301526060820152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760206040517f000000000000000000000000000000000000000010f6b2be4706a13fc20000008152f35b346102385760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760606129e16129dc612ea4565b61339d565b60ff6040805192805184528260208201511660208501520151166040820152f35b34610238576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385767ffffffffffffffff60043581811161023857612a53903690600401612e73565b91612a5c61361f565b5f5b838110612bba575060405190604082019160408152600b5480935260608101600b5f527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db95f5b88868210612ba6575050509080612ae583827f434c23397dc47fd4a6b168de7abb8861c6bddc55b261df6bfb58d89c92be92db9503602084015288886130b6565b0390a1831161185f5768010000000000000000831161185f5782600b55808310612b48575b505f5b828110612b1657005b81357f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db982015590830190600101612b0d565b7f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db901827f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9015b818110612b9b5750612b0a565b5f8155600101612b8e565b825484529092019160019182019101612aa4565b80612bd1612bcb6001938787613085565b3561363f565b01612a5e565b346102385760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857612c0e612e4d565b67ffffffffffffffff60243581811161023857612c2f903690600401612e73565b909160443581811161023857612c49903690600401612e73565b909160643590811161023857612c63903690600401612e73565b9095612c6d61361f565b84156113d757828514801590612d87575b6113ad5763ffffffff1691825f52602090600460205260405f20955f5b818110612ca457005b73ffffffffffffffffffffffffffffffffffffffff612cc76110a983858d613085565b1690811561132857612cda81858a613085565b3580151580910361023857600192887fc1a8d3b5c8695d3120c5ea6e6afca4fd990747cccf9c4513cbc02baf1c32e40d888f8e95612d1a888e8b94613085565b359660405191612d2983612ec7565b8252838201978852865f52835260405f209051151596612d7488839060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b519182910155604051908152a401612c9b565b5081831415612c7e565b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261023857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006a1aa5ac35f38bdb25bbd976e8eca942b23260b2168152f35b34610238575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102385760209073ffffffffffffffffffffffffffffffffffffffff600954168152f35b6004359063ffffffff8216820361023857565b6024359063ffffffff8216820361023857565b9181601f840112156102385782359167ffffffffffffffff8311610238576020808501948460051b01011161023857565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361023857565b6040810190811067ffffffffffffffff82111761185f57604052565b6060810190811067ffffffffffffffff82111761185f57604052565b6080810190811067ffffffffffffffff82111761185f57604052565b67ffffffffffffffff811161185f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761185f57604052565b67ffffffffffffffff811161185f57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f8201121561023857803590612fc182612f70565b92612fcf6040519485612f2f565b8284526020838301011161023857815f926020809301838601378301015290565b60e4359060ff8216820361023857565b6044359060ff8216820361023857565b359060ff8216820361023857565b359073ffffffffffffffffffffffffffffffffffffffff8216820361023857565b8054821015613058575f5260205f209060011b01905f90565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b91908110156130585760051b0190565b3573ffffffffffffffffffffffffffffffffffffffff811681036102385790565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116102385760209260051b809284830137010190565b8181029291811591840414171561096f57565b9068010000000000000000811161185f5781549181815582821061312957505050565b5f5260205f2091820191015b818110613140575050565b5f8155600101613135565b6040519061315882612ee3565b5f6040838281528260208201520152565b519069ffffffffffffffffffff8216820361023857565b9190820391821161096f57565b61319561314b565b5073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5f52600260205260408051907f6a26712a1b2f732f4c1fd85f9d6ed8235573aaa2a79aa2bab72c2423a73a9faf906131e283612eff565b81549173ffffffffffffffffffffffffffffffffffffffff80841685526001602086019260ff8660a01c16845260ff8588019660a81c1686520154906060860191825261322d61314b565b955116948515613394575060a06004958451968780927ffeaf968c0000000000000000000000000000000000000000000000000000000082525afa90811561338a575f80965f93613326575b5069ffffffffffffffffffff16156132fd5781159182156132e7575b50506132be5760ff80915116925116918151936132b185612ee3565b8452602084015282015290565b600482517f1f4bcb2b000000000000000000000000000000000000000000000000000000008152fd5b6132f391925042613180565b9051105f80613295565b600484517fa5959c59000000000000000000000000000000000000000000000000000000008152fd5b965050905060a0853d60a011613382575b8161334460a09383612f2f565b810103126102385761335585613169565b9069ffffffffffffffffffff602087015192613378608060608a01519901613169565b5092969290613279565b3d9150613337565b83513d5f823e3d90fd5b94505050505090565b6133a561314b565b5073ffffffffffffffffffffffffffffffffffffffff8091165f526002602052604090815f20918051926133d884612eff565b80549280841685526001602086019260ff8660a01c16845260ff8588019660a81c1686520154906060860191825261322d61314b565b60405190600b54808352826020916020820190600b5f527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9935f905b8282106134625750505061346092500383612f2f565b565b85548452600195860195889550938101939091019061344a565b67ffffffffffffffff811161185f5760051b60200190565b929161349f8261347c565b916134ad6040519384612f2f565b829481845260208094019160051b810192831161023857905b8282106134d35750505050565b8380916134df8461301e565b8152019101906134c6565b92916134f58261347c565b916135036040519384612f2f565b829481845260208094019160051b810192831161023857905b8282106135295750505050565b8135815290830190830161351c565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b9190808252602080920192915f5b828110613597575050505090565b90919293828060019273ffffffffffffffffffffffffffffffffffffffff6135be8961301e565b16815201950193929101613589565b9190820180921161096f57565b3560ff811681036102385790565b81156135f2570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b73ffffffffffffffffffffffffffffffffffffffff5f54163303611a6d57565b156118da57565b90428210612896571115613685571561365b57565b60046040517f2013535a000000000000000000000000000000000000000000000000000000008152fd5b60046040517f38af65f7000000000000000000000000000000000000000000000000000000008152fd5b60ff60065416156136bc57565b60046040517f4f9852e8000000000000000000000000000000000000000000000000000000008152fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805c613713576001905d565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b80156113d757036113ad57565b61375a909796959493929761363f565b86421161389f5763ffffffff9061377033614a2a565b1695865f52602060048152604097885f2073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5f52825260ff895f20541615613876575f5260058152875f2088516137ba81612ee3565b8154908181528a60026001850154948684019586520154910152421061384d575142101561382457605461381c91613460989951938185928301963360601b8852805191829101603485015e8201906034820152036034810184520182612f2f565b519020614bcf565b600488517f6b5fd31b000000000000000000000000000000000000000000000000000000008152fd5b600489517f8e9c6e1c000000000000000000000000000000000000000000000000000000008152fd5b600489517f49a8defd000000000000000000000000000000000000000000000000000000008152fd5b60046040517f1ab7da6b000000000000000000000000000000000000000000000000000000008152fd5b80518210156130585760209160051b010190565b604d811161096f57600a0a90565b9092916040908151926138fd84612eff565b5f845260208401935f8552838101935f855260608201935f855282986139228561363f565b614e209384860297861595878a041486171561096f57620f42408099049052620186a0808702908782041486171561096f57889004895262099cf0808702908782041486171561096f578890049052515f918115613ac15760058211613a985780518203613a6f57905f915b818310613a4c575050508015613a23576203d090918282116139fa575080866139b88493876130f3565b048652106139c9575b505050505050565b80830292830414171561096f576139ed926139e692519104613180565b82516135cd565b90525f80808080806139c1565b600490517f1f3b85d3000000000000000000000000000000000000000000000000000000008152fd5b600482517f7c946ed7000000000000000000000000000000000000000000000000000000008152fd5b909192613a66600191613a5f86856138c9565b51906135cd565b9301919061398e565b600484517fa24a13a6000000000000000000000000000000000000000000000000000000008152fd5b600484517f9d89020a000000000000000000000000000000000000000000000000000000008152fd5b600484517f5cb045db000000000000000000000000000000000000000000000000000000008152fd5b814710613b6d575f80809373ffffffffffffffffffffffffffffffffffffffff8294165af13d15613b68573d613b1f81612f70565b90613b2d6040519283612f2f565b81525f60203d92013e5b15613b3e57565b60046040517fd6bda275000000000000000000000000000000000000000000000000000000008152fd5b613b37565b6044824790604051917fcf47918100000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b61346090606073ffffffffffffffffffffffffffffffffffffffff91613bd18360075416825190613aea565b613be48360085416602083015190613aea565b613bf78360095416604083015190613aea565b0151907f0000000000000000000000001890cf752f1be4d60f3b22168c7a6afebd9d74c716613aea565b805190613c2d8261347c565b91604094613c3d86519485612f2f565b818452613c498261347c565b947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060209601865f5b828110613e35575050505f5b838110613dd6575050505073ffffffffffffffffffffffffffffffffffffffff92837f0000000000000000000000001890cf752f1be4d60f3b22168c7a6afebd9d74c71693843b15610238579095929185519687947f47437b680000000000000000000000000000000000000000000000000000000086526064860160606004880152835180915282608488019401905f5b818110613dbd5750505063ffffffff1660248601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8583030160448601528080855193848152019401925f905b88848310613d975750505050505091815f81819503925af1908115613d8e5750613d855750565b61346090612f1b565b513d5f823e3d90fd5b8551805183168852840151848801528a9750909501949382019360019190910190613d5e565b8251871686528b98509484019491840191600101613d10565b80620f4240613df1613dea600194866138c9565b51866130f3565b04895190613dfe82612ec7565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee825289820152613e2382896138c9565b52613e2e81886138c9565b5001613c7e565b8951613e4081612ec7565b5f81525f8382015282828a010152018790613c72565b93909192938051613e668161347c565b92604095613e7687519586612f2f565b828552613e828361347c565b957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060209701875f5b828110614058575050505f5b848110613ffe57505050505073ffffffffffffffffffffffffffffffffffffffff92837f0000000000000000000000001890cf752f1be4d60f3b22168c7a6afebd9d74c71693843b15610238579095929185519687947f47437b680000000000000000000000000000000000000000000000000000000086526064860160606004880152835180915282608488019401905f5b818110613fe55750505063ffffffff1660248601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8583030160448601528080855193848152019401925f905b88848310613fbf5750505050505091815f81819503925af1908115613d8e5750613d855750565b8551805183168852840151848801528a9750909501949382019360019190910190613f98565b8251871686528b98509484019491840191600101613f4a565b80620f4240614012613dea600194866138c9565b048a519061401f82612ec7565b73ffffffffffffffffffffffffffffffffffffffff871682528a820152614046828a6138c9565b5261405181896138c9565b5001613eb7565b8a5161406381612ec7565b5f81525f8382015282828b010152018890613eab565b73ffffffffffffffffffffffffffffffffffffffff161561132857565b9192939098979695949883421161389f5763ffffffff906140b633614a2a565b1698895f526020926004845260409a8b5f2073ffffffffffffffffffffffffffffffffffffffff83165f52855260ff8c5f205416156141ee575f52600584528a5f208b5161410381612ee3565b8154908181528d6002600185015494898401958652015491015242106141c5575142101561419c579161381c93917fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060a8946134609c9d519785899687019a3360601b8c52805191829101603489015e8601946034860152605485015260601b1660748301526088820152036088810184520182612f2f565b60048b517f6b5fd31b000000000000000000000000000000000000000000000000000000008152fd5b60048c517f8e9c6e1c000000000000000000000000000000000000000000000000000000008152fd5b60048c517f49a8defd000000000000000000000000000000000000000000000000000000008152fd5b909163ffffffff1690815f526004602093818552604093845f2073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5f5286526001946001815f2001548015155f14614510575b80975f96855192831561450257505f9792979273ffffffffffffffffffffffffffffffffffffffff96877f0000000000000000000000006a1aa5ac35f38bdb25bbd976e8eca942b23260b216945b8a81106142c3575b50505050505050505050505090565b8b81018082116144d657808c0361448c575b506142e081836138c9565b51928751907f584b62a10000000000000000000000000000000000000000000000000000000082528a86168c8301526024948583015288826044818b5afa908115614451575f9161445b575b61433692506135cd565b9287517ff188768400000000000000000000000000000000000000000000000000000000815286818d818b5afa908115614451575f91614424575b5084101561438157508b016142ac565b9a50505050505050509050929092145f146143f85762030d40918284029284840414841517156143ce57505090620f42406143bd920490613180565b5f80808080808080808080806142b4565b6011907f4e487b71000000000000000000000000000000000000000000000000000000005f52525ffd5b62011170918284029284840414841517156143ce57505090620f424061441f920490613180565b6143bd565b90508681813d831161444a575b61443b8183612f2f565b8101031261023857515f614371565b503d614431565b89513d5f823e3d90fd5b90508882813d8311614485575b6144728183612f2f565b810103126102385761433691519061432c565b503d614468565b6144a161449983856138c9565b5191846138c9565b5111156144ae575f6142d5565b8987517f5b938576000000000000000000000000000000000000000000000000000000008152fd5b60118b7f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b995050505050505050505090565b50815f52600587526002815f20015461425e565b909163ffffffff1690815f526004602093818552604093845f2073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5f5286526001946001815f2001548015155f14614705575b80975f96855192831561450257505f9792979273ffffffffffffffffffffffffffffffffffffffff96877f0000000000000000000000006a1aa5ac35f38bdb25bbd976e8eca942b23260b216945b8a81106145cf5750505050505050505050505090565b8b81018082116144d657808c036146eb575b506145ec81836138c9565b51928751907f584b62a10000000000000000000000000000000000000000000000000000000082528a86168c8301526024948583015288826044818b5afa908115614451575f916146ba575b61464292506135cd565b9287517ff188768400000000000000000000000000000000000000000000000000000000815286818d818b5afa908115614451575f9161468d575b5084101561438157508b016145b9565b90508681813d83116146b3575b6146a48183612f2f565b8101031261023857515f61467d565b503d61469a565b90508882813d83116146e4575b6146d18183612f2f565b8101031261023857614642915190614638565b503d6146c7565b6146f861449983856138c9565b5111156144ae575f6145e1565b50815f52600587526002815f20015461456b565b929163ffffffff1691825f526004906020938285526040805f2073ffffffffffffffffffffffffffffffffffffffff8094165f5286526001956001825f2001548015155f146148f557905b81985f88519384156148e6575092977f0000000000000000000000006a1aa5ac35f38bdb25bbd976e8eca942b23260b2871693905f5b8a81106147b05750505050505050505050505090565b8b81018082116144d657808c036148cc575b506147cd81836138c9565b51928751907f584b62a10000000000000000000000000000000000000000000000000000000082528a86168c8301526024948583015288826044818b5afa908115614451575f9161489b575b61482392506135cd565b9287517ff188768400000000000000000000000000000000000000000000000000000000815286818d818b5afa908115614451575f9161486e575b5084101561438157508b0161479a565b90508681813d8311614894575b6148858183612f2f565b8101031261023857515f61485e565b503d61487b565b90508882813d83116148c5575b6148b28183612f2f565b8101031261023857614823915190614819565b503d6148a8565b6148d961449983856138c9565b5111156144ae575f6147c2565b9a505050505050505050505090565b50825f52600581526002825f20015490614764565b6149169093929361339d565b92835161495f575b835115614935575b505060ff602083519301511690565b81158015614954575b6118da5760ff9184521660208301525f80614926565b5060ff81161561493e565b8115801590614998575b1561491e5760046040517ff443cb16000000000000000000000000000000000000000000000000000000008152fd5b5060ff81161515614969565b9061346091606073ffffffffffffffffffffffffffffffffffffffff926149d384600754168251903386614a7f565b6149e884600854166020830151903386614a7f565b6149fd84600954166040830151903386614a7f565b0151917f0000000000000000000000001890cf752f1be4d60f3b22168c7a6afebd9d74c716903390614a7f565b73ffffffffffffffffffffffffffffffffffffffff165f52600d60205260ff60405f205416614a5557565b60046040517f09550c77000000000000000000000000000000000000000000000000000000008152fd5b92906040519160208301917f23b872dd00000000000000000000000000000000000000000000000000000000835273ffffffffffffffffffffffffffffffffffffffff9485809216602486015216604484015260648301526064825260a082019082821067ffffffffffffffff83111761185f576020925f92604052519082865af115614b58575f513d614b4f57508082163b155b614b1c575050565b60249250604051917f5274afe7000000000000000000000000000000000000000000000000000000008352166004820152fd5b60011415614b14565b6040513d5f823e3d90fd5b600a5490614b7182826135cd565b7f000000000000000000000000000000000000000010f6b2be4706a13fc200000010614ba557614ba0916135cd565b600a55565b60046040517ff10b176b000000000000000000000000000000000000000000000000000000008152fd5b92614c2790614c30929373ffffffffffffffffffffffffffffffffffffffff948560065460081c16967f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f52601c52603c5f20614c62565b90929192614cf1565b1603614c3857565b60046040517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614ce6579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15614b58575f5173ffffffffffffffffffffffffffffffffffffffff811615614cdc57905f905f90565b505f906001905f90565b5050505f9160039190565b6004811015614da95780614d03575050565b60018103614d355760046040517ff645eedf000000000000000000000000000000000000000000000000000000008152fd5b60028103614d6e57602482604051907ffce698f70000000000000000000000000000000000000000000000000000000082526004820152fd5b600314614d785750565b602490604051907fd78bce0c0000000000000000000000000000000000000000000000000000000082526004820152fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffdfea2646970667358221220b1ecf4e9ce5db9e3b095ac0789c1a5040771ec895742a0a324fff2008535afbe64736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000060bcf12a2da761e909c3bc29f1cd13ef1e4847a0000000000000000000000000a2f78a912ba4337692a399407728784fb6b24fb1000000000000000000000000e1de0ef1fa1f3e5e1f2b2ad134fb2c3135cefa3b0000000000000000000000008002917a84db1b1ef57f7cf0b19f5f5c611db9d50000000000000000000000001890cf752f1be4d60f3b22168c7a6afebd9d74c70000000000000000000000006a1aa5ac35f38bdb25bbd976e8eca942b23260b20000000000000000000000005d7f0ed4ea8eb7a6e0a6acf1de9c91be0696871600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000010f6b2be4706a13fc20000000000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000001dcd6500000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000006fc23ac000000000000000000000000000000000000000000000000000000001176592e00
-----Decoded View---------------
Arg [0] : projectWalletAddress (address): 0x60bCf12A2dA761E909C3bc29f1cD13Ef1e4847A0
Arg [1] : platformWalletAddress (address): 0xA2F78A912BA4337692a399407728784FB6B24FB1
Arg [2] : burnWalletAddress (address): 0xe1dE0eF1fa1F3e5e1f2b2aD134Fb2C3135CEfa3B
Arg [3] : signerAddress (address): 0x8002917a84DB1B1Ef57f7Cf0B19f5F5c611db9D5
Arg [4] : claimsContractAddress (address): 0x1890cF752f1be4D60f3b22168c7A6aFEbd9D74C7
Arg [5] : lockupContractAddress (address): 0x6A1aa5ac35f38Bdb25BBD976E8eca942b23260b2
Arg [6] : owner (address): 0x5D7F0ED4EA8EB7a6e0A6Acf1DE9c91Be06968716
Arg [7] : lastRound (uint32): 0
Arg [8] : nftPrices (uint256[]): 200000000,500000000,1000000000,5000000000,10000000000,30000000000,75000000000
Arg [9] : initMaxCap (uint256): 5250000000000000000000000000
-----Encoded View---------------
18 Constructor Arguments found :
Arg [0] : 00000000000000000000000060bcf12a2da761e909c3bc29f1cd13ef1e4847a0
Arg [1] : 000000000000000000000000a2f78a912ba4337692a399407728784fb6b24fb1
Arg [2] : 000000000000000000000000e1de0ef1fa1f3e5e1f2b2ad134fb2c3135cefa3b
Arg [3] : 0000000000000000000000008002917a84db1b1ef57f7cf0b19f5f5c611db9d5
Arg [4] : 0000000000000000000000001890cf752f1be4d60f3b22168c7a6afebd9d74c7
Arg [5] : 0000000000000000000000006a1aa5ac35f38bdb25bbd976e8eca942b23260b2
Arg [6] : 0000000000000000000000005d7f0ed4ea8eb7a6e0a6acf1de9c91be06968716
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [9] : 000000000000000000000000000000000000000010f6b2be4706a13fc2000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [11] : 000000000000000000000000000000000000000000000000000000000bebc200
Arg [12] : 000000000000000000000000000000000000000000000000000000001dcd6500
Arg [13] : 000000000000000000000000000000000000000000000000000000003b9aca00
Arg [14] : 000000000000000000000000000000000000000000000000000000012a05f200
Arg [15] : 00000000000000000000000000000000000000000000000000000002540be400
Arg [16] : 00000000000000000000000000000000000000000000000000000006fc23ac00
Arg [17] : 0000000000000000000000000000000000000000000000000000001176592e00
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.