Source Code
Latest 17 from a total of 17 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Release | 20011662 | 657 days ago | IN | 0 ETH | 0.00193666 | ||||
| Release | 20011637 | 657 days ago | IN | 0 ETH | 0.00183086 | ||||
| Harvest Pool | 20011634 | 657 days ago | IN | 0 ETH | 0.00444817 | ||||
| Release | 20010602 | 657 days ago | IN | 0 ETH | 0.00113193 | ||||
| Harvest Pool | 20010585 | 657 days ago | IN | 0 ETH | 0.0026019 | ||||
| Release | 20010569 | 657 days ago | IN | 0 ETH | 0.00119 | ||||
| Harvest Pool | 20010562 | 657 days ago | IN | 0 ETH | 0.0027735 | ||||
| Harvest Pool | 20010562 | 657 days ago | IN | 0 ETH | 0.0035882 | ||||
| Deposit Pool | 20009665 | 657 days ago | IN | 0 ETH | 0.00111114 | ||||
| Deposit Pool | 20009568 | 657 days ago | IN | 0 ETH | 0.00094202 | ||||
| Deposit Pool | 20009560 | 657 days ago | IN | 0 ETH | 0.00111314 | ||||
| Deposit Pool | 20009154 | 657 days ago | IN | 0 ETH | 0.00094014 | ||||
| Deposit Pool | 20009149 | 657 days ago | IN | 0 ETH | 0.00111078 | ||||
| Deposit Pool | 20009121 | 657 days ago | IN | 0 ETH | 0.00111114 | ||||
| Deposit Pool | 20009108 | 657 days ago | IN | 0 ETH | 0.00094002 | ||||
| Deposit Pool | 20009105 | 657 days ago | IN | 0 ETH | 0.0014529 | ||||
| Set Pool | 19986793 | 661 days ago | IN | 0 ETH | 0.00239092 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60a06040 | 19986769 | 661 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
IFOInitializableV8
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 1 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma experimental ABIEncoderV2;
import "@openzeppelin-4.5.0/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin-4.5.0/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin-4.5.0/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/IIFOV8.sol";
import "./libraries/IFOLibV8.sol";
import "./utils/WhiteListV2.sol";
import "./interfaces/IPancakeProfile.sol";
import "./ICakeV3.sol";
/**
* @title IFOInitializableV8
*/
contract IFOInitializableV8 is IIFOV8, ReentrancyGuard, Whitelist {
using SafeERC20 for IERC20;
// The address of the smart chef factory
address private immutable IFO_FACTORY;
// Whether it is initialized
bool private isInitialized;
// all the addresses
// [0] lpToken [1] offeringToken [2] pancakeProfile [3] iCake [4] adminAddress [5] admissionProfile
address[6] public addresses;
// The timestamp when IFO starts
uint256 public startTimestamp;
// The timestamp when IFO ends
uint256 public endTimestamp;
// Max buffer seconds (for sanity checks)
uint256 public MAX_BUFFER_SECONDS;
// Max pool id (sometimes only public sale exist)
uint8 public MAX_POOL_ID;
// The minimum point special sale require
uint256 public pointThreshold;
// point config
PointConfig public pointConfig;
// Total tokens distributed across the pools
uint256 public totalTokensOffered;
// Struct that contains each pool characteristics
struct PoolCharacteristics {
uint256 raisingAmountPool; // amount of tokens raised for the pool (in LP tokens)
uint256 offeringAmountPool; // amount of tokens offered for the pool (in offeringTokens)
uint256 limitPerUserInLP; // limit of tokens per user (if 0, it is ignored)
bool hasTax; // tax on the overflow (if any, it works with _calculateTaxOverflow)
uint256 flatTaxRate; // new rate for flat tax
uint256 totalAmountPool; // total amount pool deposited (in LP tokens)
uint256 sumTaxesOverflow; // total taxes collected (starts at 0, increases with each harvest if overflow)
SaleType saleType; // previously bool checking if a sale is special(private), currently uint act as "sale type"
// 0: public sale
// 1: private sale
// 2: basic sale
VestingConfig vestingConfig;
}
// Array of PoolCharacteristics of size NUMBER_POOLS
PoolCharacteristics[2] private _poolInformation;
// Checks if user has claimed points
mapping(address => bool) private _hasClaimedPoints;
// Struct that contains each user information for both pools
struct UserInfo {
uint256 amountPool; // How many tokens the user has provided for pool
bool claimedPool; // Whether the user has claimed (default: false) for pool
}
// It maps the address to pool id to UserInfo
mapping(address => mapping(uint8 => UserInfo)) private _userInfo;
// It maps user address to credit used amount
mapping(address => uint256) public userCreditUsed;
// It maps if nft token id was used
mapping(uint256 => address) public tokenIdUsed;
// It maps user address with NFT id
mapping(address => uint256) public userNftTokenId;
// vesting startTime, everyone will be started at same timestamp
uint256 public vestingStartTime;
// A flag for vesting is being revoked
bool public vestingRevoked;
// Struct that contains vesting schedule
struct VestingSchedule {
bool isVestingInitialized;
// beneficiary of tokens after they are released
address beneficiary;
// pool id
uint8 pid;
// total amount of tokens to be released at the end of the vesting
uint256 amountTotal;
// amount of tokens has been released
uint256 released;
}
bytes32[] private vestingSchedulesIds;
mapping(bytes32 => VestingSchedule) private vestingSchedules;
uint256 private vestingSchedulesTotalAmount;
mapping(address => uint256) private holdersVestingCount;
// Admin withdraw events
event AdminWithdraw(uint256 amountLP, uint256 amountOfferingToken);
// Admin recovers token
event AdminTokenRecovery(address tokenAddress, uint256 amountTokens);
// Deposit event
event Deposit(address indexed user, uint256 amount, uint8 indexed pid);
// Harvest event
event Harvest(address indexed user, uint256 offeringAmount, uint256 excessAmount, uint8 indexed pid);
// Create VestingSchedule event
event CreateVestingSchedule(address indexed user, uint256 offeringAmount, uint256 excessAmount, uint8 indexed pid);
// Event for new start & end timestamps
event NewStartAndEndTimestamps(uint256 startTimestamp, uint256 endTimestamp);
// Event with point parameters for IFO
event PointParametersSet(uint256 campaignId, uint256 numberPoints, uint256 thresholdPoints);
// Event when parameters are set for one of the pools
event PoolParametersSet(uint256 offeringAmountPool, uint256 raisingAmountPool, uint8 pid);
// Event when released new amount
event Released(address indexed beneficiary, uint256 amount);
// Event when revoked
event Revoked();
error PoolIdNotValid();
error TokensNotDepositedProperly();
error NotEnoughIFOCreditLeft();
error NewAmountAboveUserLimit();
error ProfileNotActive();
error NotMeetAnyoneOfRequiredConditions();
error NFTRequirementsMustBeMetForHarvest();
error NFTUsedByAnotherAddressAlready();
error NFTTokenIdNotSameAsRegistered();
error CanNotBeLPToken();
error CanNotBeOfferingToken();
error VestingOnlyBeneficiaryOrOwnerCanRelease();
error VestingNotEnoughToRelease();
error VestingIsRevoked();
error OnlyOwner();
/**
* @notice Constructor
*/
constructor() public {
IFO_FACTORY = msg.sender;
}
/**
* @notice It initializes the contract
* @dev It can only be called once.
* @param _addresses: [0] lpToken [1] offeringToken [2] pancakeProfile [3] iCake [4] adminAddress [5] admissionProfile
* @param _startAndEndTimestamps: [0] startTimestamp [1] endTimestamp
* @param _maxBufferSeconds: maximum buffer of blocks from the current block number
* @param _maxPoolId: maximum id of pools, sometimes only public sale exist
* @param _pointThreshold: threshold of user's point in pancake profile
* @param _vestingStartTime: the start timestamp of vesting
*/
function initialize(
address[] calldata _addresses,
uint256[] calldata _startAndEndTimestamps,
uint256 _maxBufferSeconds,
uint8 _maxPoolId,
uint256 _pointThreshold,
uint256 _vestingStartTime
) public {
// Check validation
IFOLibV8.InitializePreCheck(
isInitialized,
IFO_FACTORY,
_addresses.length,
_startAndEndTimestamps.length,
_maxPoolId
);
// Make this contract initialized
isInitialized = true;
if (_addresses[2] != address(0)) {
IPancakeProfile(_addresses[2]).getTeamProfile(1);
}
if (_addresses[3] != address(0)) {
ICakeV3(_addresses[3]).admin();
}
// [0] lpToken
// [1] offeringToken
// [2] pancakeProfile
// [3] iCake
// [4] adminAddress
// [5] admissionProfile
for (uint8 i = 0; i < _addresses.length; i++) {
addresses[i] = _addresses[i];
}
startTimestamp = _startAndEndTimestamps[0];
endTimestamp = _startAndEndTimestamps[1];
MAX_BUFFER_SECONDS = _maxBufferSeconds;
MAX_POOL_ID = _maxPoolId;
pointThreshold = _pointThreshold;
vestingStartTime = _vestingStartTime;
// Transfer ownership to admin
transferOwnership(_addresses[4]);
}
/**
* @notice It allows users to deposit LP tokens to pool
* @param _amount: the number of LP token used (18 decimals)
* @param _pid: pool id
*/
function depositPool(uint256 _amount, uint8 _pid) external override nonReentrant {
// Checks whether the pool id is valid
_checkPid(_pid);
// Check validation
IFOLibV8.DepositPoolPreCheck(
_amount,
addresses[2], // pancakeProfileAddress
_poolInformation[_pid].saleType,
_poolInformation[_pid].offeringAmountPool,
_poolInformation[_pid].raisingAmountPool,
startTimestamp,
endTimestamp
);
// Verify tokens were deposited properly
if (IERC20(addresses[1]).balanceOf(address(this)) < totalTokensOffered) {
revert TokensNotDepositedProperly();
}
if (_poolInformation[_pid].saleType == SaleType.PUBLIC || _poolInformation[_pid].saleType == SaleType.BASIC) {
// public and basic sales
if (addresses[3] != address(0) && _poolInformation[_pid].saleType != SaleType.BASIC) {
// getUserCredit from ICake contract when it is presented and not basic sales
uint256 ifoCredit = ICakeV3(addresses[3]).getUserCredit(msg.sender);
if (userCreditUsed[msg.sender] + _amount > ifoCredit) {
revert NotEnoughIFOCreditLeft();
}
}
_deposit(_amount, _pid);
// Updates Accumulative deposit lpTokens
userCreditUsed[msg.sender] = userCreditUsed[msg.sender] + (_poolInformation[_pid].saleType == SaleType.PUBLIC ? _amount : 0);
} else {
// private sales
if (addresses[2] != address(0)) {
(
,
uint256 profileNumberPoints,
,
address profileAddress,
uint256 tokenId,
bool active
) = IPancakeProfile(addresses[2]).getUserProfile(msg.sender);
if (!active) revert ProfileNotActive();
if (!_isQualifiedPoints(profileNumberPoints) &&
!isQualifiedWhitelist(msg.sender) &&
!_isQualifiedNFT(msg.sender, profileAddress, tokenId)) {
revert NotMeetAnyoneOfRequiredConditions();
}
// Update tokenIdUsed
if (!_isQualifiedPoints(profileNumberPoints) &&
!isQualifiedWhitelist(msg.sender) &&
profileAddress == addresses[5]) {
if (tokenIdUsed[tokenId] == address(0)) {
// update tokenIdUsed
tokenIdUsed[tokenId] = msg.sender;
} else {
if (tokenIdUsed[tokenId] != msg.sender) {
revert NFTUsedByAnotherAddressAlready();
}
}
if (userNftTokenId[msg.sender] == 0) {
// update userNftTokenId
userNftTokenId[msg.sender] = tokenId;
} else {
if (userNftTokenId[msg.sender] != tokenId) {
revert NFTTokenIdNotSameAsRegistered();
}
}
}
}
_deposit(_amount, _pid);
}
}
/**
* @notice It allows users to harvest from pool
* @param _pid: pool id
*/
function harvestPool(uint8 _pid) external override nonReentrant {
// Checks whether the pool id is valid
_checkPid(_pid);
// Check validation
IFOLibV8.HarvestPoolPreCheck(
endTimestamp,
_userInfo[msg.sender][_pid].amountPool,
_userInfo[msg.sender][_pid].claimedPool
);
if (userNftTokenId[msg.sender] != 0) {
(, , , address profileAddress, uint256 tokenId, bool isActive) = IPancakeProfile(addresses[2])
.getUserProfile(msg.sender);
if (!isActive || profileAddress != addresses[5] || userNftTokenId[msg.sender] != tokenId) {
revert NFTRequirementsMustBeMetForHarvest();
}
}
// Claim points if possible
_claimPoints(msg.sender);
// Updates the harvest status
_userInfo[msg.sender][_pid].claimedPool = true;
// Updates the vesting startTime
if (vestingStartTime == 0) {
vestingStartTime = block.timestamp;
}
// Initialize the variables for offering, refunding user amounts, and tax amount
(
uint256 offeringTokenAmount,
uint256 refundingTokenAmount,
uint256 userTaxOverflow
) = _calculateOfferingAndRefundingAmountsPool(msg.sender, _pid);
// Increment the sumTaxesOverflow
if (userTaxOverflow > 0) {
_poolInformation[_pid].sumTaxesOverflow = _poolInformation[_pid].sumTaxesOverflow + userTaxOverflow;
}
// Transfer these tokens back to the user if quantity > 0
if (offeringTokenAmount > 0) {
if (100 - _poolInformation[_pid].vestingConfig.percentage > 0) {
uint256 amount = offeringTokenAmount * (100 - _poolInformation[_pid].vestingConfig.percentage) / 100;
// Transfer the tokens at TGE
IERC20(addresses[1]).safeTransfer(msg.sender, amount);
emit Harvest(msg.sender, amount, refundingTokenAmount, _pid);
}
// If this pool is Vesting modal, create a VestingSchedule for each user
if (_poolInformation[_pid].vestingConfig.percentage > 0) {
uint256 amount = offeringTokenAmount * _poolInformation[_pid].vestingConfig.percentage / 100;
// Create VestingSchedule object
_createVestingSchedule(msg.sender, _pid, amount);
emit CreateVestingSchedule(msg.sender, amount, refundingTokenAmount, _pid);
}
}
if (refundingTokenAmount > 0) {
IERC20(addresses[0]).safeTransfer(msg.sender, refundingTokenAmount);
}
}
/**
* @notice It allows the admin to withdraw funds
* @param _lpAmount: the number of LP token to withdraw (18 decimals)
* @param _offerAmount: the number of offering amount to withdraw
* @dev This function is only callable by admin.
*/
function finalWithdraw(uint256 _lpAmount, uint256 _offerAmount) external override {
_isOwner();
// Check validation
IFOLibV8.FinalWithdrawPreCheck(
_lpAmount,
IERC20(addresses[0]).balanceOf(address(this)),
_offerAmount,
IERC20(addresses[1]).balanceOf(address(this))
);
if (_lpAmount > 0) {
IERC20(addresses[0]).safeTransfer(msg.sender, _lpAmount);
}
if (_offerAmount > 0) {
IERC20(addresses[1]).safeTransfer(msg.sender, _offerAmount);
}
emit AdminWithdraw(_lpAmount, _offerAmount);
}
/**
* @notice It allows the admin to recover wrong tokens sent to the contract
* @param _tokenAddress: the address of the token to withdraw (18 decimals)
* @param _tokenAmount: the number of token amount to withdraw
* @dev This function is only callable by admin.
*/
function recoverWrongTokens(address _tokenAddress, uint256 _tokenAmount) external {
_isOwner();
if (_tokenAddress == addresses[0]) {
revert CanNotBeLPToken();
}
if (_tokenAddress == addresses[1]) {
revert CanNotBeOfferingToken();
}
IERC20(_tokenAddress).safeTransfer(msg.sender, _tokenAmount);
emit AdminTokenRecovery(_tokenAddress, _tokenAmount);
}
/**
* @notice It sets parameters for pool
* @param _offeringAmountPool: offering amount (in tokens)
* @param _raisingAmountPool: raising amount (in LP tokens)
* @param _limitPerUserInLP: limit per user (in LP tokens)
* @param _hasTax: if the pool has a tax
* @param _flatTaxRate: flat tax rate
* @param _pid: pool id
* @param _saleType: // previously bool checking if a sale is special(private), currently uint act as "sale type"
// 0: public sale
// 1: private sale
// 2: basic sale
* @param _vestingConfig: vesting config parameters
* @dev This function is only callable by admin.
*/
function setPool(
uint256 _offeringAmountPool,
uint256 _raisingAmountPool,
uint256 _limitPerUserInLP,
bool _hasTax,
uint256 _flatTaxRate,
uint8 _pid,
SaleType _saleType,
VestingConfig calldata _vestingConfig
) external override {
_isOwner();
// Checks whether the pool id is valid
_checkPid(_pid);
// Check validation
IFOLibV8.SetPoolPreCheck(
startTimestamp,
_hasTax,
_flatTaxRate,
_vestingConfig.percentage,
_vestingConfig.duration,
_vestingConfig.slicePeriodSeconds
);
_poolInformation[_pid].offeringAmountPool = _offeringAmountPool;
_poolInformation[_pid].raisingAmountPool = _raisingAmountPool;
_poolInformation[_pid].limitPerUserInLP = _limitPerUserInLP;
_poolInformation[_pid].hasTax = _hasTax;
_poolInformation[_pid].flatTaxRate = _flatTaxRate;
_poolInformation[_pid].saleType = _saleType;
_poolInformation[_pid].vestingConfig.percentage = _vestingConfig.percentage;
_poolInformation[_pid].vestingConfig.cliff = _vestingConfig.cliff;
_poolInformation[_pid].vestingConfig.duration = _vestingConfig.duration;
_poolInformation[_pid].vestingConfig.slicePeriodSeconds = _vestingConfig.slicePeriodSeconds;
uint256 tokensDistributedAcrossPools;
for (uint8 i = 0; i <= MAX_POOL_ID; i++) {
tokensDistributedAcrossPools = tokensDistributedAcrossPools + _poolInformation[i].offeringAmountPool;
}
// Update totalTokensOffered
totalTokensOffered = tokensDistributedAcrossPools;
emit PoolParametersSet(_offeringAmountPool, _raisingAmountPool, _pid);
}
/**
* @notice It updates point parameters for the IFO.
* @param _pointConfig: the point reward and requirement for user participate in IFO
* @dev This function is only callable by admin.
*/
function updatePointParameters(
PointConfig calldata _pointConfig
) external override {
_isOwner();
// Check validation
IFOLibV8.UpdatePointParametersPreCheck(
endTimestamp
);
pointConfig.numberPoints = _pointConfig.numberPoints;
pointConfig.campaignId = _pointConfig.campaignId;
pointConfig.thresholdPoints = _pointConfig.thresholdPoints;
emit PointParametersSet(_pointConfig.campaignId, _pointConfig.numberPoints, _pointConfig.thresholdPoints);
}
/**
* @notice It allows the admin to update start and end blocks
* @param _startAndEndTimestamps: [0] startTimestamp [1] endTimestamp
* @dev This function is only callable by admin.
*/
function updateStartAndEndTimestamps(uint256[] calldata _startAndEndTimestamps) external {
_isOwner();
// Check validation
IFOLibV8.UpdateStartAndEndTimestampsPreCheck(
MAX_BUFFER_SECONDS,
_startAndEndTimestamps.length,
startTimestamp,
_startAndEndTimestamps[0], // startTimestamp
_startAndEndTimestamps[1] // endTimestamp
);
startTimestamp = _startAndEndTimestamps[0];
endTimestamp = _startAndEndTimestamps[1];
emit NewStartAndEndTimestamps(_startAndEndTimestamps[0], _startAndEndTimestamps[1]);
}
/**
* @notice It returns the pool information
* @param _pid: pool id
* @return raisingAmountPool: amount of LP tokens raised (in LP tokens)
* @return offeringAmountPool: amount of tokens offered for the pool (in offeringTokens)
* @return limitPerUserInLP; // limit of tokens per user (if 0, it is ignored)
* @return hasTax: tax on the overflow (if any, it works with _calculateTaxOverflow)
* @return flatTaxRate: new rate of flat tax
* @return totalAmountPool: total amount pool deposited (in LP tokens)
* @return sumTaxesOverflow: total taxes collected (starts at 0, increases with each harvest if overflow)
*/
function viewPoolInformation(uint256 _pid)
external
view
returns (
uint256,
uint256,
uint256,
bool,
uint256,
uint256,
SaleType
) {
return (
_poolInformation[_pid].raisingAmountPool,
_poolInformation[_pid].offeringAmountPool,
_poolInformation[_pid].limitPerUserInLP,
_poolInformation[_pid].hasTax,
_poolInformation[_pid].totalAmountPool,
_poolInformation[_pid].sumTaxesOverflow,
_poolInformation[_pid].saleType
);
}
/**
* @notice It returns the pool vesting information
* @param _pid: pool id
* @return vestingPercentage: the percentage of vesting part, claimingPercentage + vestingPercentage should be 100
* @return vestingCliff: the cliff of vesting
* @return vestingDuration: the duration of vesting
* @return vestingSlicePeriodSeconds: the slice period seconds of vesting
*/
function viewPoolVestingInformation(uint256 _pid)
external
view
override
returns (
uint256,
uint256,
uint256,
uint256
)
{
return (
_poolInformation[_pid].vestingConfig.percentage,
_poolInformation[_pid].vestingConfig.cliff,
_poolInformation[_pid].vestingConfig.duration,
_poolInformation[_pid].vestingConfig.slicePeriodSeconds
);
}
/**
* @notice It returns the tax overflow rate calculated for a pool
* @dev 100,000,000,000 means 0.1 (10%) / 1 means 0.0000000000001 (0.0000001%) / 1,000,000,000,000 means 1 (100%)
* @param _pid: pool id
* @return It returns the tax percentage
*/
function viewPoolTaxRateOverflow(uint256 _pid) external view returns (uint256) {
if (!_poolInformation[_pid].hasTax) {
return 0;
} else {
if (_poolInformation[_pid].flatTaxRate > 0) {
return _poolInformation[_pid].flatTaxRate;
} else {
return
_calculateTaxOverflow(
_poolInformation[_pid].totalAmountPool,
_poolInformation[_pid].raisingAmountPool
);
}
}
}
/**
* @notice External view function to see user allocations for both pools
* @param _user: user address
* @param _pids[]: array of pids
* @return
*/
function viewUserAllocationPools(address _user, uint8[] calldata _pids) external view returns (uint256[] memory) {
uint256[] memory allocationPools = new uint256[](_pids.length);
for (uint8 i = 0; i < _pids.length; i++) {
allocationPools[i] = _getUserAllocationPool(_user, _pids[i]);
}
return allocationPools;
}
/**
* @notice External view function to see user information
* @param _user: user address
* @param _pids[]: array of pids
*/
function viewUserInfo(address _user, uint8[] calldata _pids)
external
view
returns (uint256[] memory, bool[] memory) {
uint256[] memory amountPools = new uint256[](_pids.length);
bool[] memory statusPools = new bool[](_pids.length);
for (uint8 i = 0; i <= MAX_POOL_ID; i++) {
amountPools[i] = _userInfo[_user][i].amountPool;
statusPools[i] = _userInfo[_user][i].claimedPool;
}
return (amountPools, statusPools);
}
/**
* @notice External view function to see user offering and refunding amounts for both pools
* @param _user: user address
* @param _pids: array of pids
*/
function viewUserOfferingAndRefundingAmountsForPools(address _user, uint8[] calldata _pids)
external
view
returns (uint256[3][] memory) {
uint256[3][] memory amountPools = new uint256[3][](_pids.length);
for (uint8 i = 0; i < _pids.length; i++) {
uint256 userOfferingAmountPool;
uint256 userRefundingAmountPool;
uint256 userTaxAmountPool;
if (_poolInformation[_pids[i]].raisingAmountPool > 0) {
(
userOfferingAmountPool,
userRefundingAmountPool,
userTaxAmountPool
) = _calculateOfferingAndRefundingAmountsPool(_user, _pids[i]);
}
amountPools[i] = [userOfferingAmountPool, userRefundingAmountPool, userTaxAmountPool];
}
return amountPools;
}
/**
* @notice Returns the vesting schedule information of a given holder and index
* @return The vesting schedule object
*/
function getVestingScheduleByAddressAndIndex(address _holder, uint256 _index)
external
view
returns (VestingSchedule memory)
{
return getVestingSchedule(computeVestingScheduleIdForAddressAndIndex(_holder, _index));
}
/**
* @notice Returns the total amount of vesting schedules
* @return The vesting schedule total amount
*/
function getVestingSchedulesTotalAmount() external view returns (uint256) {
return vestingSchedulesTotalAmount;
}
/**
* @notice Release vested amount of offering tokens
* @param _vestingScheduleId the vesting schedule identifier
*/
function release(bytes32 _vestingScheduleId) external nonReentrant {
// Check validation
IFOLibV8.IsVestingInitializedPreCheck(
vestingSchedules[_vestingScheduleId].isVestingInitialized
);
VestingSchedule storage vestingSchedule = vestingSchedules[_vestingScheduleId];
bool isBeneficiary = msg.sender == vestingSchedule.beneficiary;
bool isOwner = msg.sender == owner();
if (!isBeneficiary && !isOwner) {
revert VestingOnlyBeneficiaryOrOwnerCanRelease();
}
uint256 vestedAmount = _computeReleasableAmount(vestingSchedule);
if (vestedAmount <= 0) {
revert VestingNotEnoughToRelease();
}
vestingSchedule.released = vestingSchedule.released + vestedAmount;
vestingSchedulesTotalAmount = vestingSchedulesTotalAmount - vestedAmount;
IERC20(addresses[1]).safeTransfer(vestingSchedule.beneficiary, vestedAmount);
emit Released(vestingSchedule.beneficiary, vestedAmount);
}
/**
* @notice Revokes all the vesting schedules
*/
function revoke() external {
_isOwner();
if (vestingRevoked) {
revert VestingIsRevoked();
}
vestingRevoked = true;
emit Revoked();
}
/**
* @notice Returns the number of vesting schedules managed by the contract
* @return The number of vesting count
*/
function getVestingSchedulesCount() public view returns (uint256) {
return vestingSchedulesIds.length;
}
/**
* @notice Returns the vested amount of tokens for the given vesting schedule identifier
* @return The number of vested count
*/
function computeReleasableAmount(bytes32 _vestingScheduleId) public view returns (uint256) {
// Check validation
IFOLibV8.IsVestingInitializedPreCheck(
vestingSchedules[_vestingScheduleId].isVestingInitialized
);
return _computeReleasableAmount(vestingSchedules[_vestingScheduleId]);
}
/**
* @notice Returns the vesting schedule information of a given identifier
* @return The vesting schedule object
*/
function getVestingSchedule(bytes32 _vestingScheduleId) public view returns (VestingSchedule memory) {
return vestingSchedules[_vestingScheduleId];
}
/**
* @notice Returns the amount of offering token that can be withdrawn by the owner
* @return The amount of offering token
*/
function getWithdrawableOfferingTokenAmount() public view returns (uint256) {
return IERC20(addresses[1]).balanceOf(address(this)) - vestingSchedulesTotalAmount;
}
/**
* @notice Computes the next vesting schedule identifier for a given holder address
* @return The id string
*/
function computeNextVestingScheduleIdForHolder(address _holder) public view returns (bytes32) {
return computeVestingScheduleIdForAddressAndIndex(_holder, holdersVestingCount[_holder]);
}
/**
* @notice Computes the next vesting schedule identifier for an address and an index
* @return The id string
*/
function computeVestingScheduleIdForAddressAndIndex(address _holder, uint256 _index) public pure returns (bytes32) {
return keccak256(abi.encodePacked(_holder, _index));
}
/**
* @notice Computes the next vesting schedule identifier for an address and an pid
* @return The id string
*/
function computeVestingScheduleIdForAddressAndPid(address _holder, uint8 _pid) external view returns (bytes32) {
// Checks whether the pool id is valid
if (_pid > MAX_POOL_ID) {
return bytes32(0);
}
bytes32 vestingScheduleId = computeVestingScheduleIdForAddressAndIndex(_holder, 0);
VestingSchedule memory vestingSchedule = vestingSchedules[vestingScheduleId];
if (vestingSchedule.pid == _pid) {
return vestingScheduleId;
} else {
return computeVestingScheduleIdForAddressAndIndex(_holder, 1);
}
}
/**
* @notice Computes the releasable amount of tokens for a vesting schedule
* @return The amount of releasable tokens
*/
function _computeReleasableAmount(VestingSchedule memory _vestingSchedule) internal view returns (uint256) {
if (block.timestamp < vestingStartTime + _poolInformation[_vestingSchedule.pid].vestingConfig.cliff) {
return 0;
} else if (
block.timestamp >= vestingStartTime + _poolInformation[_vestingSchedule.pid].vestingConfig.duration ||
vestingRevoked
) {
return _vestingSchedule.amountTotal - _vestingSchedule.released;
} else {
uint256 timeFromStart = block.timestamp - vestingStartTime;
uint256 secondsPerSlice = _poolInformation[_vestingSchedule.pid].vestingConfig.slicePeriodSeconds;
uint256 vestedSlicePeriods = timeFromStart / secondsPerSlice;
uint256 vestedSeconds = vestedSlicePeriods * secondsPerSlice;
uint256 vestedAmount = _vestingSchedule.amountTotal * vestedSeconds / _poolInformation[_vestingSchedule.pid].vestingConfig.duration;
vestedAmount = vestedAmount - _vestingSchedule.released;
return vestedAmount;
}
}
/**
* @notice Creates a new vesting schedule for a beneficiary
* @param _beneficiary address of the beneficiary to whom vested tokens are transferred
* @param _pid the pool id
* @param _amount total amount of tokens to be released at the end of the vesting
*/
function _createVestingSchedule(
address _beneficiary,
uint8 _pid,
uint256 _amount
) internal {
require(
getWithdrawableOfferingTokenAmount() >= _amount,
"can not create vesting schedule with sufficient tokens"
);
bytes32 vestingScheduleId = computeNextVestingScheduleIdForHolder(_beneficiary);
require(vestingSchedules[vestingScheduleId].beneficiary == address(0), "vestingScheduleId is been created");
vestingSchedules[vestingScheduleId] = VestingSchedule(true, _beneficiary, _pid, _amount, 0);
vestingSchedulesTotalAmount = vestingSchedulesTotalAmount + _amount;
vestingSchedulesIds.push(vestingScheduleId);
holdersVestingCount[_beneficiary]++;
}
/**
* @notice It allows users to claim points
* @param _user: user address
*/
function _claimPoints(address _user) internal {
if (addresses[2] != address(0)) {
if (!_hasClaimedPoints[_user] && pointConfig.numberPoints > 0) {
uint256 sumPools;
for (uint8 i = 0; i <= MAX_POOL_ID; i++) {
sumPools = sumPools + _userInfo[msg.sender][i].amountPool;
}
if (sumPools > pointConfig.thresholdPoints) {
_hasClaimedPoints[_user] = true;
// Increase user points
IPancakeProfile(addresses[2]).increaseUserPoints(msg.sender, pointConfig.numberPoints, pointConfig.campaignId);
}
}
}
}
/**
* @notice It calculates the tax overflow given the raisingAmountPool and the totalAmountPool.
* @dev 100,000,000,000 means 0.1 (10%) / 1 means 0.0000000000001 (0.0000001%) / 1,000,000,000,000 means 1 (100%)
* @return It returns the tax percentage
*/
function _calculateTaxOverflow(uint256 _totalAmountPool, uint256 _raisingAmountPool)
internal
pure
returns (uint256)
{
uint256 ratioOverflow = _totalAmountPool / _raisingAmountPool;
if (ratioOverflow >= 1500) {
return 250000000; // 0.0125%
} else if (ratioOverflow >= 1000) {
return 500000000; // 0.05%
} else if (ratioOverflow >= 500) {
return 1000000000; // 0.1%
} else if (ratioOverflow >= 250) {
return 1250000000; // 0.125%
} else if (ratioOverflow >= 100) {
return 1500000000; // 0.15%
} else if (ratioOverflow >= 50) {
return 2500000000; // 0.25%
} else {
return 5000000000; // 0.5%
}
}
/**
* @notice It calculates the offering amount for a user and the number of LP tokens to transfer back.
* @param _user: user address
* @param _pid: pool id
* @return {uint256, uint256, uint256} It returns the offering amount, the refunding amount (in LP tokens),
* and the tax (if any, else 0)
*/
function _calculateOfferingAndRefundingAmountsPool(address _user, uint8 _pid)
internal
view
returns (
uint256,
uint256,
uint256
)
{
uint256 userOfferingAmount;
uint256 userRefundingAmount;
uint256 taxAmount;
if (_poolInformation[_pid].totalAmountPool > _poolInformation[_pid].raisingAmountPool) {
// Calculate allocation for the user
uint256 allocation = _getUserAllocationPool(_user, _pid);
// Calculate the offering amount for the user based on the offeringAmount for the pool
userOfferingAmount = _poolInformation[_pid].offeringAmountPool * allocation / 1e12;
// Calculate the payAmount
uint256 payAmount = _poolInformation[_pid].raisingAmountPool * allocation / 1e12;
// Calculate the pre-tax refunding amount
userRefundingAmount = _userInfo[_user][_pid].amountPool - payAmount;
// Retrieve the tax rate
if (_poolInformation[_pid].hasTax) {
uint256 tax = _poolInformation[_pid].flatTaxRate;
if (tax == 0) {
tax = _calculateTaxOverflow(
_poolInformation[_pid].totalAmountPool,
_poolInformation[_pid].raisingAmountPool
);
}
// Calculate the final taxAmount
taxAmount = userRefundingAmount * tax / 1e12;
// Adjust the refunding amount
userRefundingAmount = userRefundingAmount - taxAmount;
}
} else {
// _userInfo[_user] / (raisingAmount / offeringAmount)
userOfferingAmount = _userInfo[_user][_pid].amountPool * _poolInformation[_pid].offeringAmountPool / _poolInformation[_pid].raisingAmountPool;
}
return (userOfferingAmount, userRefundingAmount, taxAmount);
}
/**
* @notice It returns the user allocation for pool
* @dev 100,000,000,000 means 0.1 (10%) / 1 means 0.0000000000001 (0.0000001%) / 1,000,000,000,000 means 1 (100%)
* @param _user: user address
* @param _pid: pool id
* @return It returns the user's share of pool
*/
function _getUserAllocationPool(address _user, uint8 _pid) internal view returns (uint256) {
if (_pid > MAX_POOL_ID) {
return 0;
}
if (_poolInformation[_pid].totalAmountPool > 0) {
return _userInfo[_user][_pid].amountPool * 1e12 / _poolInformation[_pid].totalAmountPool;
} else {
return 0;
}
}
function isQualifiedWhitelist(address _user) public view returns (bool) {
return isWhitelisted(_user);
}
function isQualifiedPoints(address _user) external view returns (bool) {
if (addresses[2] == address(0)) {
return true;
}
if (!IPancakeProfile(addresses[2]).getUserStatus(_user)) {
return false;
}
(, uint256 profileNumberPoints, , , , ) = IPancakeProfile(addresses[2]).getUserProfile(_user);
return _isQualifiedPoints(profileNumberPoints);
}
function isQualifiedNFT(address _user) external view returns (bool) {
if (addresses[2] == address(0)) {
return true;
}
if (!IPancakeProfile(addresses[2]).getUserStatus(_user)) {
return false;
}
(, , , address profileAddress, uint256 tokenId, ) = IPancakeProfile(addresses[2]).getUserProfile(
_user
);
return _isQualifiedNFT(_user, profileAddress, tokenId);
}
function _isQualifiedPoints(uint256 profileNumberPoints) internal view returns (bool) {
return (pointThreshold != 0 && profileNumberPoints >= pointThreshold);
}
function _isQualifiedNFT(
address _user,
address profileAddress,
uint256 tokenId
) internal view returns (bool) {
return (profileAddress == addresses[5] &&
(tokenIdUsed[tokenId] == address(0) || tokenIdUsed[tokenId] == _user));
}
function _isOwner() internal view {
if (owner() != msg.sender) revert OnlyOwner();
}
function _deposit(uint256 _amount, uint8 _pid) internal {
// Transfers funds to this contract
IERC20(addresses[0]).safeTransferFrom(msg.sender, address(this), _amount);
// Update the user status
_userInfo[msg.sender][_pid].amountPool = _userInfo[msg.sender][_pid].amountPool + _amount;
// Check if the pool has a limit per user
if (_poolInformation[_pid].limitPerUserInLP > 0) {
// Checks whether the limit has been reached
if (_userInfo[msg.sender][_pid].amountPool > _poolInformation[_pid].limitPerUserInLP) {
revert NewAmountAboveUserLimit();
}
}
// Updates the totalAmount for pool
_poolInformation[_pid].totalAmountPool = _poolInformation[_pid].totalAmountPool + _amount;
emit Deposit(msg.sender, _amount, _pid);
}
function _checkPid(uint8 _pid) internal view {
if (_pid > MAX_POOL_ID) {
revert PoolIdNotValid();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../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.
*
* By default, the owner account will be the one that deploys the contract. 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;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public 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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_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 v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 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 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @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).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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, it is bubbled up by this
* function (like regular Solidity function calls).
*
* 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.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @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`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// 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 {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
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 division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma experimental ABIEncoderV2;
import "@openzeppelin-4.5.0/contracts/access/Ownable.sol";
import "@openzeppelin-4.5.0/contracts/utils/math/SafeMath.sol";
import "@openzeppelin-4.5.0/contracts/token/ERC20/utils/SafeERC20.sol";
interface IVeCake {
function getUserInfo(address _user) external view returns (
int128 amount,
uint256 end,
address cakePoolProxy,
uint128 cakeAmount,
uint48 lockEndTime,
uint48 migrationTime,
uint16 cakePoolType,
uint16 withdrawFlag
);
function balanceOfAtTime(address _user, uint256 _timestamp) external view returns (uint256);
}
interface IIFODeployer {
function currIFOAddress() external view returns (address);
}
interface IIFOInitializable {
function endTimestamp() external view returns (uint256);
}
contract ICakeV3 is Ownable {
using SafeMath for uint256;
address public admin;
address public immutable veCakeAddress;
address public ifoDeployerAddress;
uint256 public ratio;
uint256 public constant RATION_PRECISION = 1000;
uint256 public constant MIN_CEILING_DURATION = 1 weeks;
event UpdateRatio(uint256 newRatio);
event UpdateIfoDeployerAddress(address indexed newAddress);
/**
* @notice Constructor
* @param _veCakeAddress: veCake contract
*/
constructor(
address _veCakeAddress
) public {
veCakeAddress = _veCakeAddress;
admin = owner();
ratio = 1000;
}
/**
* @notice calculate iCake credit per user.
* @param _user: user address.
* @param _endTime: user lock end time on veCake contract.
*/
function getUserCreditWithTime(address _user, uint256 _endTime) external view returns (uint256) {
require(_user != address(0), "getUserCredit: Invalid user address");
// require the end time must be in the future
// require(_endTime > block.timestamp, "end must be in future");
// instead let's filter the time to current if too old
if (_endTime <= block.timestamp){
_endTime = block.timestamp;
}
return _sumUserCredit(_user, _endTime);
}
/**
* @notice calculate iCake credit per user with Ifo address.
* @param _user: user address.
* @param _ifo: the ifo contract.
*/
function getUserCreditWithIfoAddr(address _user, address _ifo) external view returns (uint256) {
require(_user != address(0), "getUserCredit: Invalid user address");
require(_ifo != address(0), "getUserCredit: Invalid ifo address");
uint256 _endTime = IIFOInitializable(_ifo).endTimestamp();
if (_endTime <= block.timestamp){
_endTime = block.timestamp;
}
return _sumUserCredit(_user, _endTime);
}
/**
* @notice calculate iCake credit per user for next ifo.
* @param _user: user address.
*/
function getUserCreditForNextIfo(address _user) external view returns (uint256) {
require(_user != address(0), "getUserCredit: Invalid user address");
address currIFOAddress = IIFODeployer(ifoDeployerAddress).currIFOAddress();
uint256 _endTime = block.timestamp;
if (currIFOAddress != address(0)) {
_endTime = IIFOInitializable(currIFOAddress).endTimestamp();
if (_endTime <= block.timestamp){
_endTime = block.timestamp;
}
}
return _sumUserCredit(_user, _endTime);
}
function getUserCredit(address _user) external view returns (uint256) {
require(_user != address(0), "getUserCredit: Invalid user address");
uint256 _endTime = IIFOInitializable(msg.sender).endTimestamp();
return _sumUserCredit(_user, _endTime);
}
/**
* @notice update ratio for iCake calculation.
* @param _newRatio: new ratio
*/
function updateRatio(uint256 _newRatio) external onlyOwner {
require(_newRatio <= RATION_PRECISION, "updateRatio: Invalid ratio");
require(ratio != _newRatio, "updateRatio: Ratio not changed");
ratio = _newRatio;
emit UpdateRatio(ratio);
}
/**
* @notice update deployer address of IFO.
* @param _newAddress: new deployer address
*/
function updateIfoDeployerAddress(address _newAddress) external onlyOwner {
require(_newAddress != address(0), "updateIfoDeployerAddress: Address can not be empty");
ifoDeployerAddress = _newAddress;
emit UpdateIfoDeployerAddress(_newAddress);
}
/**
* @notice get user and proxy credit from veCake contract and sum together
* @param _user user's address
* @param _endTime timestamp to calculate user's veCake amount
*/
function _sumUserCredit(address _user, uint256 _endTime) internal view returns (uint256) {
// get native
uint256 veNative = IVeCake(veCakeAddress).balanceOfAtTime(_user, _endTime);
// get proxy/migrated
uint256 veMigrate = 0;
( , ,address cakePoolProxy, , , , , ) = IVeCake(veCakeAddress).getUserInfo(_user);
if (cakePoolProxy != address(0)) {
veMigrate = IVeCake(veCakeAddress).balanceOfAtTime(cakePoolProxy, _endTime);
}
return (veNative + veMigrate) * ratio / RATION_PRECISION;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/** @title IIFOV8.
* @notice It is an interface for IFOV8.sol
*/
interface IIFOV8 {
enum SaleType {
PUBLIC, //0
PRIVATE, //1
BASIC //2
}
struct VestingConfig {
uint256 percentage;
uint256 cliff;
uint256 duration;
uint256 slicePeriodSeconds;
}
struct PointConfig {
uint256 campaignId;
uint256 numberPoints;
uint256 thresholdPoints;
}
function depositPool(uint256 _amount, uint8 _pid) external;
function harvestPool(uint8 _pid) external;
function finalWithdraw(uint256 _lpAmount, uint256 _offerAmount) external;
function setPool(
uint256 _offeringAmountPool,
uint256 _raisingAmountPool,
uint256 _limitPerUserInLP,
bool _hasTax,
uint256 _flatTaxRate,
uint8 _pid,
SaleType _saleType,
VestingConfig memory _vestingConfig
) external;
function updatePointParameters(
PointConfig memory _pointConfig
) external;
function viewPoolInformation(uint256 _pid)
external
view
returns (
uint256,
uint256,
uint256,
bool,
uint256,
uint256,
SaleType
);
function viewPoolVestingInformation(uint256 _pid)
external
view
returns (
uint256,
uint256,
uint256,
uint256
);
function viewPoolTaxRateOverflow(uint256 _pid) external view returns (uint256);
function viewUserAllocationPools(address _user, uint8[] calldata _pids) external view returns (uint256[] memory);
function viewUserInfo(address _user, uint8[] calldata _pids)
external
view
returns (uint256[] memory, bool[] memory);
function viewUserOfferingAndRefundingAmountsForPools(address _user, uint8[] calldata _pids)
external
view
returns (uint256[3][] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma experimental ABIEncoderV2;
interface IPancakeProfile {
/**
* @dev Check the user's profile for a given address
*/
function getUserProfile(address _userAddress)
external
view
returns (
uint256,
uint256,
uint256,
address,
uint256,
bool
);
/**
* @dev Check the user's status for a given address
*/
function getUserStatus(address _userAddress) external view returns (bool);
function getTeamProfile(uint256 _teamId)
external
view
returns (
string memory,
string memory,
uint256,
uint256,
bool
);
/**
* @dev To increase the number of points for a user.
* Callable only by point admins
*/
function increaseUserPoints(
address _userAddress,
uint256 _numberPoints,
uint256 _campaignId
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "../interfaces/IIFOV8.sol";
import "../interfaces/IPancakeProfile.sol";
import "../ICakeV3.sol";
library IFOLibV8 {
error PoolIdNotValid();
error EndTimeTooFar();
error StartTimeMustInferiorToEndTime();
error StartTimeMustGreaterThanCurrentBlockTime();
error AlreadyInitialized();
error NotFactory();
error AddressesLengthNotCorrect();
error StartAndEndTimestampsLengthNotCorrect();
error ShouldNotLargerThanTheNumberOfPools();
error MustHaveAnActiveProfile();
error PoolNotSet();
error TooEarly();
error TooLate();
error AmountMustExceedZero();
error DidNotParticipate();
error AlreadyHarvested();
error NotEnoughLPTokens();
error NotEnoughOfferingTokens();
error IFOHasStarted();
error IFOHasEnded();
error FlatTaxRateMustBeLessThan1e12();
error FlatTaxRateMustBe0WhenHasTaxIsFalse();
error VestingPercentageShouldRangeIn0And100();
error VestingDurationMustExceeds0();
error VestingSlicePerSecondsMustBeExceeds1();
error VestingSlicePerSecondsMustBeInteriorDuration();
error VestingNotExist();
function InitializePreCheck(
bool isInitialized,
address IFO_FACTORY,
uint256 addresses_length,
uint256 startAndEndTimestamps_length,
uint8 maxPoolId
) internal view {
if (isInitialized) {
revert AlreadyInitialized();
}
if (msg.sender != IFO_FACTORY) {
revert NotFactory();
}
if (addresses_length != 6) {
revert AddressesLengthNotCorrect();
}
if (startAndEndTimestamps_length != 2) {
revert StartAndEndTimestampsLengthNotCorrect();
}
if (maxPoolId >= 2) {
revert ShouldNotLargerThanTheNumberOfPools();
}
}
function DepositPoolPreCheck(
uint256 amount,
address pancakeProfileAddress,
IIFOV8.SaleType saleType,
uint256 offeringAmountPool,
uint256 raisingAmountPool,
uint256 startTimestamp,
uint256 endTimestamp
) internal view {
if (pancakeProfileAddress != address(0) && saleType != IIFOV8.SaleType.BASIC) {
// Checks whether the user has an active profile when provided profile SC and not basic sale
if (!IPancakeProfile(pancakeProfileAddress).getUserStatus(msg.sender)) {
revert MustHaveAnActiveProfile();
}
}
// Checks that pool was set
if (offeringAmountPool == 0 || raisingAmountPool == 0) {
revert PoolNotSet();
}
// Checks whether the timestamp is not too early
if (block.timestamp <= startTimestamp) {
revert TooEarly();
}
// Checks whether the timestamp is not too late
if (block.timestamp > endTimestamp) {
revert TooLate();
}
// Checks that the amount deposited is not inferior to 0
if (amount == 0) {
revert AmountMustExceedZero();
}
}
function HarvestPoolPreCheck(
uint256 endTimestamp,
uint256 amountPool,
bool claimedPool
) internal view {
// Checks whether pool id is valid
if (block.timestamp <= endTimestamp) {
revert TooEarly();
}
// Checks whether the user has participated
if (amountPool == 0) {
revert DidNotParticipate();
}
// Checks whether the user has already harvested
if (claimedPool) {
revert AlreadyHarvested();
}
}
function FinalWithdrawPreCheck(
uint256 lpAmount,
uint256 lpTokenBalanceOf,
uint256 offerAmount,
uint256 offeringTokenBalanceOf
) internal view {
if (lpAmount > lpTokenBalanceOf) {
revert NotEnoughLPTokens();
}
if (offerAmount > offeringTokenBalanceOf) {
revert NotEnoughOfferingTokens();
}
}
function SetPoolPreCheck(
uint256 startTimestamp,
bool hasTax,
uint256 flatTaxRate,
uint256 vestingPercentage,
uint256 vestingDuration,
uint256 vestingSlicePeriodSeconds
) internal view {
if (block.timestamp >= startTimestamp) {
revert IFOHasStarted();
}
if (flatTaxRate >= 1e12) {
revert FlatTaxRateMustBeLessThan1e12();
}
if (vestingPercentage > 100) {
revert VestingPercentageShouldRangeIn0And100();
}
if (vestingDuration == 0) {
revert VestingDurationMustExceeds0();
}
if (vestingSlicePeriodSeconds < 1) {
revert VestingSlicePerSecondsMustBeExceeds1();
}
if (vestingSlicePeriodSeconds > vestingDuration) {
revert VestingSlicePerSecondsMustBeInteriorDuration();
}
if (!hasTax) {
if (flatTaxRate != 0) {
revert FlatTaxRateMustBe0WhenHasTaxIsFalse();
}
}
}
function UpdatePointParametersPreCheck(
uint256 endTimestamp
) internal view {
if (block.timestamp >= endTimestamp) {
revert IFOHasEnded();
}
}
function UpdateStartAndEndTimestampsPreCheck(
uint256 MAX_BUFFER_SECONDS,
uint256 startAndEndTimestamps_length,
uint256 currentStartTimestamp,
uint256 startTimestamp,
uint256 endTimestamp
) internal view {
if (startAndEndTimestamps_length != 2) {
revert StartAndEndTimestampsLengthNotCorrect();
}
if (endTimestamp >= (block.timestamp + MAX_BUFFER_SECONDS)) revert EndTimeTooFar();
if (block.timestamp >= currentStartTimestamp) revert IFOHasStarted();
if (startTimestamp >= endTimestamp) revert StartTimeMustInferiorToEndTime();
if (block.timestamp >= startTimestamp) revert StartTimeMustGreaterThanCurrentBlockTime();
}
function IsVestingInitializedPreCheck(bool isVestingInitialized) internal view {
if (!isVestingInitialized) {
revert VestingNotExist();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "@openzeppelin-4.5.0/contracts/access/Ownable.sol";
contract Whitelist is Ownable {
mapping(address => bool) private whitelist;
event WhitelistedAddressAdded(address indexed _user);
event WhitelistedAddressRemoved(address indexed _user);
/**
* @dev throws if user is not whitelisted.
* @param _user address
*/
modifier onlyIfWhitelisted(address _user) {
require(whitelist[_user]);
_;
}
/**
* @dev add single address to whitelist
*/
function addAddressToWhitelist(address _user) external onlyOwner {
whitelist[_user] = true;
emit WhitelistedAddressAdded(_user);
}
/**
* @dev add addresses to whitelist
*/
function addAddressesToWhitelist(address[] calldata _users) external onlyOwner {
for (uint256 i = 0; i < _users.length; i++) {
whitelist[_users[i]] = true;
emit WhitelistedAddressAdded(_users[i]);
}
}
/**
* @dev remove single address from whitelist
*/
function removeAddressFromWhitelist(address _user) external onlyOwner {
whitelist[_user] = false;
emit WhitelistedAddressRemoved(_user);
}
/**
* @dev remove addresses from whitelist
*/
function removeAddressesFromWhitelist(address[] calldata _users) external onlyOwner {
for (uint256 i = 0; i < _users.length; i++) {
whitelist[_users[i]] = false;
emit WhitelistedAddressRemoved(_users[i]);
}
}
/**
* @dev getter to determine if address is in whitelist
*/
function isWhitelisted(address _user) public view returns (bool) {
return whitelist[_user];
}
}{
"optimizer": {
"enabled": true,
"runs": 1
},
"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":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressesLengthNotCorrect","type":"error"},{"inputs":[],"name":"AlreadyHarvested","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AmountMustExceedZero","type":"error"},{"inputs":[],"name":"CanNotBeLPToken","type":"error"},{"inputs":[],"name":"CanNotBeOfferingToken","type":"error"},{"inputs":[],"name":"DidNotParticipate","type":"error"},{"inputs":[],"name":"EndTimeTooFar","type":"error"},{"inputs":[],"name":"FlatTaxRateMustBe0WhenHasTaxIsFalse","type":"error"},{"inputs":[],"name":"FlatTaxRateMustBeLessThan1e12","type":"error"},{"inputs":[],"name":"IFOHasEnded","type":"error"},{"inputs":[],"name":"IFOHasStarted","type":"error"},{"inputs":[],"name":"MustHaveAnActiveProfile","type":"error"},{"inputs":[],"name":"NFTRequirementsMustBeMetForHarvest","type":"error"},{"inputs":[],"name":"NFTTokenIdNotSameAsRegistered","type":"error"},{"inputs":[],"name":"NFTUsedByAnotherAddressAlready","type":"error"},{"inputs":[],"name":"NewAmountAboveUserLimit","type":"error"},{"inputs":[],"name":"NotEnoughIFOCreditLeft","type":"error"},{"inputs":[],"name":"NotEnoughLPTokens","type":"error"},{"inputs":[],"name":"NotEnoughOfferingTokens","type":"error"},{"inputs":[],"name":"NotFactory","type":"error"},{"inputs":[],"name":"NotMeetAnyoneOfRequiredConditions","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"PoolIdNotValid","type":"error"},{"inputs":[],"name":"PoolNotSet","type":"error"},{"inputs":[],"name":"ProfileNotActive","type":"error"},{"inputs":[],"name":"ShouldNotLargerThanTheNumberOfPools","type":"error"},{"inputs":[],"name":"StartAndEndTimestampsLengthNotCorrect","type":"error"},{"inputs":[],"name":"StartTimeMustGreaterThanCurrentBlockTime","type":"error"},{"inputs":[],"name":"StartTimeMustInferiorToEndTime","type":"error"},{"inputs":[],"name":"TokensNotDepositedProperly","type":"error"},{"inputs":[],"name":"TooEarly","type":"error"},{"inputs":[],"name":"TooLate","type":"error"},{"inputs":[],"name":"VestingDurationMustExceeds0","type":"error"},{"inputs":[],"name":"VestingIsRevoked","type":"error"},{"inputs":[],"name":"VestingNotEnoughToRelease","type":"error"},{"inputs":[],"name":"VestingNotExist","type":"error"},{"inputs":[],"name":"VestingOnlyBeneficiaryOrOwnerCanRelease","type":"error"},{"inputs":[],"name":"VestingPercentageShouldRangeIn0And100","type":"error"},{"inputs":[],"name":"VestingSlicePerSecondsMustBeExceeds1","type":"error"},{"inputs":[],"name":"VestingSlicePerSecondsMustBeInteriorDuration","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountTokens","type":"uint256"}],"name":"AdminTokenRecovery","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountLP","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfferingToken","type":"uint256"}],"name":"AdminWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"offeringAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"excessAmount","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"CreateVestingSchedule","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"offeringAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"excessAmount","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"name":"NewStartAndEndTimestamps","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numberPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"thresholdPoints","type":"uint256"}],"name":"PointParametersSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"offeringAmountPool","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"raisingAmountPool","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"PoolParametersSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Released","type":"event"},{"anonymous":false,"inputs":[],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"}],"name":"WhitelistedAddressAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"}],"name":"WhitelistedAddressRemoved","type":"event"},{"inputs":[],"name":"MAX_BUFFER_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_POOL_ID","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"addAddressToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_users","type":"address[]"}],"name":"addAddressesToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"addresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"}],"name":"computeNextVestingScheduleIdForHolder","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_vestingScheduleId","type":"bytes32"}],"name":"computeReleasableAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"computeVestingScheduleIdForAddressAndIndex","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"},{"internalType":"uint8","name":"_pid","type":"uint8"}],"name":"computeVestingScheduleIdForAddressAndPid","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint8","name":"_pid","type":"uint8"}],"name":"depositPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lpAmount","type":"uint256"},{"internalType":"uint256","name":"_offerAmount","type":"uint256"}],"name":"finalWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_vestingScheduleId","type":"bytes32"}],"name":"getVestingSchedule","outputs":[{"components":[{"internalType":"bool","name":"isVestingInitialized","type":"bool"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint8","name":"pid","type":"uint8"},{"internalType":"uint256","name":"amountTotal","type":"uint256"},{"internalType":"uint256","name":"released","type":"uint256"}],"internalType":"struct IFOInitializableV8.VestingSchedule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getVestingScheduleByAddressAndIndex","outputs":[{"components":[{"internalType":"bool","name":"isVestingInitialized","type":"bool"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint8","name":"pid","type":"uint8"},{"internalType":"uint256","name":"amountTotal","type":"uint256"},{"internalType":"uint256","name":"released","type":"uint256"}],"internalType":"struct IFOInitializableV8.VestingSchedule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVestingSchedulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVestingSchedulesTotalAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawableOfferingTokenAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_pid","type":"uint8"}],"name":"harvestPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"internalType":"uint256[]","name":"_startAndEndTimestamps","type":"uint256[]"},{"internalType":"uint256","name":"_maxBufferSeconds","type":"uint256"},{"internalType":"uint8","name":"_maxPoolId","type":"uint8"},{"internalType":"uint256","name":"_pointThreshold","type":"uint256"},{"internalType":"uint256","name":"_vestingStartTime","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"isQualifiedNFT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"isQualifiedPoints","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"isQualifiedWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pointConfig","outputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"uint256","name":"numberPoints","type":"uint256"},{"internalType":"uint256","name":"thresholdPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pointThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"recoverWrongTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_vestingScheduleId","type":"bytes32"}],"name":"release","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"removeAddressFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_users","type":"address[]"}],"name":"removeAddressesFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revoke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offeringAmountPool","type":"uint256"},{"internalType":"uint256","name":"_raisingAmountPool","type":"uint256"},{"internalType":"uint256","name":"_limitPerUserInLP","type":"uint256"},{"internalType":"bool","name":"_hasTax","type":"bool"},{"internalType":"uint256","name":"_flatTaxRate","type":"uint256"},{"internalType":"uint8","name":"_pid","type":"uint8"},{"internalType":"enum IIFOV8.SaleType","name":"_saleType","type":"uint8"},{"components":[{"internalType":"uint256","name":"percentage","type":"uint256"},{"internalType":"uint256","name":"cliff","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"slicePeriodSeconds","type":"uint256"}],"internalType":"struct IIFOV8.VestingConfig","name":"_vestingConfig","type":"tuple"}],"name":"setPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenIdUsed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensOffered","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":[{"components":[{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"uint256","name":"numberPoints","type":"uint256"},{"internalType":"uint256","name":"thresholdPoints","type":"uint256"}],"internalType":"struct IIFOV8.PointConfig","name":"_pointConfig","type":"tuple"}],"name":"updatePointParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_startAndEndTimestamps","type":"uint256[]"}],"name":"updateStartAndEndTimestamps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userCreditUsed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userNftTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vestingRevoked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vestingStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"viewPoolInformation","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"enum IIFOV8.SaleType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"viewPoolTaxRateOverflow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"viewPoolVestingInformation","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint8[]","name":"_pids","type":"uint8[]"}],"name":"viewUserAllocationPools","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint8[]","name":"_pids","type":"uint8[]"}],"name":"viewUserInfo","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint8[]","name":"_pids","type":"uint8[]"}],"name":"viewUserOfferingAndRefundingAmountsForPools","outputs":[{"internalType":"uint256[3][]","name":"","type":"uint256[3][]"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a06040523480156200001157600080fd5b50600160005562000022336200002c565b336080526200007e565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6080516143c46200009a60003960006111e301526143c46000f3fe608060405234801561001057600080fd5b506004361061023b5760003560e01c806306cec8571461024057806313083617146102685780631e3bba081461027a5780632374876c1461028d57806324953eaa146102a2578063286dd3f5146102b557806328fddfaf146102c857806337f859b8146102d55780633af32abf146102e85780633f138d4b146102fb57806346ab91bf1461030e57806348deb4711461033457806349032cdb1461033c5780634af3c9b71461035c57806354070e391461037d57806367d42a8b146103865780636865f6e914610399578063715018a6146103ac578063760b3180146103b457806379795108146103bd5780637b9417c8146103c55780637f1bdd76146103d85780638518b3c5146103eb5780638af104da146104215780638da5cb5b146104345780639ef346b41461043c5780639f1b52481461049a578063a47ff7e5146104ad578063a85adeab146104ce578063a8660a78146104d7578063ae8973a0146104e0578063b0adb220146104f3578063b1ced5e7146104fc578063b6549f751461051b578063b86c6f1414610523578063c029773714610556578063ca463ca414610569578063caa7f23214610589578063d04dac151461059c578063e2ec6ec3146105af578063e6fd48bc146105c2578063e9050763146105cb578063ea1bb3d5146105de578063edf26d9b146105f1578063f2fde38b14610604578063f51321d714610617578063f7c469f01461062a578063f9cd5c121461063d578063feebf5291461065d575b600080fd5b61025361024e366004613aab565b61067d565b60405190151581526020015b60405180910390f35b6032545b60405190815260200161025f565b61026c610288366004613ad9565b61068e565b6102a061029b366004613b0e565b61073c565b005b6102a06102b0366004613b74565b610afd565b6102a06102c3366004613aab565b610bed565b6031546102539060ff1681565b61026c6102e3366004613bb5565b610c53565b6102536102f6366004613aab565b610d04565b6102a0610309366004613bce565b610d22565b61032161031c366004613bb5565b610dd9565b60405161025f9796959493929190613c10565b60345461026c565b61026c61034a366004613aab565b602f6020526000908152604090205481565b61036f61036a366004613c6b565b610ebc565b60405161025f929190613cfa565b61026c600c5481565b6102a0610394366004613bb5565b611018565b6102a06103a7366004613d53565b6111d7565b6102a06114c0565b61026c60125481565b61026c6114fb565b6102a06103d3366004613aab565b611580565b6102a06103e6366004613dee565b6115e9565b6104146103f9366004613bb5565b602e602052600090815260409020546001600160a01b031681565b60405161025f9190613e11565b61026c61042f366004613bce565b611b46565b610414611b88565b61044f61044a366004613bb5565b611b97565b60405161025f91908151151581526020808301516001600160a01b03169082015260408083015160ff1690820152606080830151908201526080918201519181019190915260a00190565b6102a06104a8366004613e25565b611c03565b600f546010546011546104bf92919083565b60405161025f93929190613e47565b61026c600b5481565b61026c60305481565b6102a06104ee366004613e5d565b611d4e565b61026c600e5481565b600d546105099060ff1681565b60405160ff909116815260200161025f565b6102a0611db8565b610536610531366004613bb5565b611e1c565b60408051948552602085019390935291830152606082015260800161025f565b610253610564366004613aab565b611ea9565b61057c610577366004613c6b565b611fca565b60405161025f9190613e75565b6102a0610597366004613b74565b612115565b6102536105aa366004613aab565b612202565b6102a06105bd366004613b74565b61232c565b61026c600a5481565b6102a06105d9366004613eed565b612417565b61026c6105ec366004613bb5565b61267c565b6104146105ff366004613bb5565b612700565b6102a0610612366004613aab565b612720565b61044f610625366004613bce565b6127c0565b61026c610638366004613aab565b6127d5565b61065061064b366004613c6b565b6127f9565b60405161025f9190613f7c565b61026c61066b366004613aab565b602d6020526000908152604090205481565b600061068882610d04565b92915050565b600d5460009060ff90811690831611156106aa57506000610688565b60006106b7846000611b46565b600081815260336020908152604091829020825160a081018452815460ff808216151583526001600160a01b0361010083041694830194909452600160a81b900483169381018490526001820154606082015260029091015460808201529293508516141561072857509050610688565b610733856001611b46565b95945050505050565b600260005414156107685760405162461bcd60e51b815260040161075f90613f8f565b60405180910390fd5b6002600055610776816128b4565b600b54336000908152602c6020908152604080832060ff8681168552925290912080546001909101546107aa9392166128de565b336000908152602f60205260409020541561089557600654604051634c3f70ab60e11b8152600091829182916001600160a01b03169063987ee156906107f4903390600401613e11565b60c060405180830381865afa158015610811573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108359190613fdc565b95509550955050505080158061085957506009546001600160a01b03848116911614155b806108735750336000908152602f60205260409020548214155b15610891576040516319a9a2ef60e01b815260040160405180910390fd5b5050505b61089e3361293b565b336000908152602c6020908152604080832060ff8516845290915290206001908101805460ff191690911790556030546108d757426030555b60008060006108e63385612a71565b91945092509050801561093e578060138560ff166002811061090a5761090a613fc6565b600c02016006015461091c9190614051565b60138560ff166002811061093257610932613fc6565b600c0201600601819055505b8215610ade57600060138560ff166002811061095c5761095c613fc6565b600c02016008016000015460646109739190614069565b1115610a25576000606460138660ff166002811061099357610993613fc6565b600c02016008016000015460646109aa9190614069565b6109b49086614080565b6109be919061409f565b90506109dc3382600460015b01546001600160a01b03169190612cb2565b8460ff16336001600160a01b03167f51524c2e5edfedf8b01b29719c661e4fbe27e71734e7cd773dabb7cb712fb3b38386604051610a1b9291906140c1565b60405180910390a3505b600060138560ff1660028110610a3d57610a3d613fc6565b600c0201600801600001541115610ade576000606460138660ff1660028110610a6857610a68613fc6565b600c02016008016000015485610a7e9190614080565b610a88919061409f565b9050610a95338683612d08565b8460ff16336001600160a01b03167f4b386667138d87683f75b2e46ad8ac192b053af4c8875da8689415997663a9508386604051610ad49291906140c1565b60405180910390a3505b8115610af257610af23383600460006109ca565b505060016000555050565b33610b06611b88565b6001600160a01b031614610b2c5760405162461bcd60e51b815260040161075f906140cf565b60005b81811015610be857600060026000858585818110610b4f57610b4f613fc6565b9050602002016020810190610b649190613aab565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055828282818110610b9e57610b9e613fc6565b9050602002016020810190610bb39190613aab565b6001600160a01b031660008051602061436f83398151915260405160405180910390a280610be081614104565b915050610b2f565b505050565b33610bf6611b88565b6001600160a01b031614610c1c5760405162461bcd60e51b815260040161075f906140cf565b6001600160a01b038116600081815260026020526040808220805460ff191690555160008051602061436f8339815191529190a250565b600060138260028110610c6857610c68613fc6565b600c02016003015460ff16610c7f57506000919050565b600060138360028110610c9457610c94613fc6565b600c0201600401541115610cc45760138260028110610cb557610cb5613fc6565b600c0201600401549050919050565b61068860138360028110610cda57610cda613fc6565b600c02016005015460138460028110610cf557610cf5613fc6565b600c020154612f10565b919050565b6001600160a01b031660009081526002602052604090205460ff1690565b610d2a612fae565b6004546001600160a01b0383811691161415610d59576040516310da472360e01b815260040160405180910390fd5b6005546001600160a01b0383811691161415610d885760405163a8dfadb960e01b815260040160405180910390fd5b610d9c6001600160a01b0383163383612cb2565b7f74545154aac348a3eac92596bd1971957ca94795f4e954ec5f613b55fab781298282604051610dcd92919061411f565b60405180910390a15050565b600080600080600080600060138860028110610df757610df7613fc6565b600c02015460138960028110610e0f57610e0f613fc6565b600c02016001015460138a60028110610e2a57610e2a613fc6565b600c02016002015460138b60028110610e4557610e45613fc6565b600c02016003015460ff1660138c60028110610e6357610e63613fc6565b600c02016005015460138d60028110610e7e57610e7e613fc6565b600c02016006015460138e60028110610e9957610e99613fc6565b600c020160070154959e949d50929b509099509750955060ff9091169350915050565b6060806000836001600160401b03811115610ed957610ed9614138565b604051908082528060200260200182016040528015610f02578160200160208202803683370190505b5090506000846001600160401b03811115610f1f57610f1f614138565b604051908082528060200260200182016040528015610f48578160200160208202803683370190505b50905060005b600d5460ff9081169082161161100b576001600160a01b0388166000908152602c6020908152604080832060ff85168085529252909120548451909185918110610f9a57610f9a613fc6565b6020908102919091018101919091526001600160a01b0389166000908152602c8252604080822060ff8086168085529190945291206001015484519216918491908110610fe957610fe9613fc6565b91151560209283029190910190910152806110038161414e565b915050610f4e565b5090969095509350505050565b6002600054141561103b5760405162461bcd60e51b815260040161075f90613f8f565b600260009081558181526033602052604090205461105b9060ff16612fde565b6000818152603360205260408120805490916101009091046001600160a01b0316331490611087611b88565b6001600160a01b0316336001600160a01b0316149050811580156110a9575080155b156110c7576040516361c042c160e01b815260040160405180910390fd5b6040805160a081018252845460ff808216151583526001600160a01b036101008304166020840152600160a81b9091041691810191909152600184015460608201526002840154608082015260009061111f90612ffc565b90506000811161114257604051632d973f4d60e11b815260040160405180910390fd5b8084600201546111529190614051565b6002850155603454611165908290614069565b60345583546111869061010090046001600160a01b031682600460016109ca565b83546040518281526101009091046001600160a01b0316907fb21fb52d5749b80f3182f8c6992236b5e5576681880914484d7f4c9b062e619e9060200160405180910390a250506001600055505050565b60035461120a9060ff167f0000000000000000000000000000000000000000000000000000000000000000898887613151565b6003805460ff1916600117905560008888600281811061122c5761122c613fc6565b90506020020160208101906112419190613aab565b6001600160a01b0316146112ec578787600281811061126257611262613fc6565b90506020020160208101906112779190613aab565b60405163aee2f47f60e01b8152600160048201526001600160a01b03919091169063aee2f47f90602401600060405180830381865afa1580156112be573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112e69190810190614221565b50505050505b60008888600381811061130157611301613fc6565b90506020020160208101906113169190613aab565b6001600160a01b0316146113af578787600381811061133757611337613fc6565b905060200201602081019061134c9190613aab565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611389573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ad91906142ac565b505b60005b60ff811688111561142e5788888260ff168181106113d2576113d2613fc6565b90506020020160208101906113e79190613aab565b60048260ff16600681106113fd576113fd613fc6565b0180546001600160a01b0319166001600160a01b0392909216919091179055806114268161414e565b9150506113b2565b508585600081811061144257611442613fc6565b6020029190910135600a55508585600181811061146157611461613fc6565b6020029190910135600b5550600c849055600d805460ff191660ff8516179055600e82905560308190556114b6888860048181106114a1576114a1613fc6565b90506020020160208101906106129190613aab565b5050505050505050565b336114c9611b88565b6001600160a01b0316146114ef5760405162461bcd60e51b815260040161075f906140cf565b6114f96000613205565b565b6034546005546040516370a0823160e01b8152600092916001600160a01b0316906370a0823190611530903090600401613e11565b602060405180830381865afa15801561154d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157191906142c9565b61157b9190614069565b905090565b33611589611b88565b6001600160a01b0316146115af5760405162461bcd60e51b815260040161075f906140cf565b6001600160a01b038116600081815260026020526040808220805460ff191660011790555160008051602061434f8339815191529190a250565b6002600054141561160c5760405162461bcd60e51b815260040161075f90613f8f565b600260005561161a816128b4565b61169c826004600201546001600160a01b0316601360ff85166002811061164357611643613fc6565b600c020160070160009054906101000a900460ff1660138560ff166002811061166e5761166e613fc6565b600c02016001015460138660ff166002811061168c5761168c613fc6565b600c020154600a54600b54613257565b6012546005546040516370a0823160e01b81526001600160a01b03909116906370a08231906116cf903090600401613e11565b602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171091906142c9565b101561172f5760405163726da7d560e11b815260040160405180910390fd5b600060138260ff166002811061174757611747613fc6565b600c02016007015460ff16600281111561176357611763613bfa565b14806117a05750600260138260ff166002811061178257611782613fc6565b600c02016007015460ff16600281111561179e5761179e613bfa565b145b15611924576007546001600160a01b0316158015906117f15750600260138260ff16600281106117d2576117d2613fc6565b600c02016007015460ff1660028111156117ee576117ee613bfa565b14155b156118a9576007546040516336b5bc3760e21b81526000916001600160a01b03169063dad6f0dc90611827903390600401613e11565b602060405180830381865afa158015611844573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186891906142c9565b336000908152602d60205260409020549091508190611888908590614051565b11156118a757604051630448a42b60e21b815260040160405180910390fd5b505b6118b382826133a1565b600060138260ff16600281106118cb576118cb613fc6565b600c02016007015460ff1660028111156118e7576118e7613bfa565b146118f35760006118f5565b815b336000908152602d602052604090205461190f9190614051565b336000908152602d6020526040902055611b3d565b6006546001600160a01b031615611b33576000808080600460020154604051634c3f70ab60e11b81526001600160a01b039091169063987ee1569061196d903390600401613e11565b60c060405180830381865afa15801561198a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ae9190613fdc565b95509550955050945050806119d65760405163f7bd660760e01b815260040160405180910390fd5b6119df84613515565b1580156119f257506119f03361067d565b155b8015611a065750611a0433848461352e565b155b15611a24576040516309a318fb60e31b815260040160405180910390fd5b611a2d84613515565b158015611a405750611a3e3361067d565b155b8015611a5957506009546001600160a01b038481169116145b15611b2e576000828152602e60205260409020546001600160a01b0316611a9d576000828152602e6020526040902080546001600160a01b03191633179055611ad4565b6000828152602e60205260409020546001600160a01b03163314611ad45760405163d69933c360e01b815260040160405180910390fd5b336000908152602f6020526040902054611aff57336000908152602f60205260409020829055611b2e565b336000908152602f60205260409020548214611b2e57604051630236c46360e51b815260040160405180910390fd5b505050505b611b3d82826133a1565b50506001600055565b6040516001600160601b0319606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b6001546001600160a01b031690565b611b9f613a4a565b50600090815260336020908152604091829020825160a081018452815460ff808216151583526001600160a01b0361010083041694830194909452600160a81b90049092169282019290925260018201546060820152600290910154608082015290565b611c0b612fae565b600480546040516370a0823160e01b8152611cf59285926001600160a01b0316916370a0823191611c3e91309101613e11565b602060405180830381865afa158015611c5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7f91906142c9565b6005546040516370a0823160e01b815285916001600160a01b0316906370a0823190611caf903090600401613e11565b602060405180830381865afa158015611ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf091906142c9565b61358f565b8115611d0957611d093383600460006109ca565b8015611d1d57611d1d3382600460016109ca565b7f94ebb62a252249c867ecb758d386f50a95be7e8df9e1c52917c9cf494327dd7d8282604051610dcd9291906140c1565b611d56612fae565b611d61600b546135d7565b602081013560108190558135600f819055604080840135601181905590517f2058a318dbdfd2edd92a32cfa0ee233a30b165b83b421830109cb22ae86f674593611dad93929091613e47565b60405180910390a150565b611dc0612fae565b60315460ff1615611de457604051630476d49560e21b815260040160405180910390fd5b6031805460ff191660011790556040517f44825a4b2df8acb19ce4e1afba9aa850c8b65cdb7942e2078f27d0b0960efee690600090a1565b60008060008060138560028110611e3557611e35613fc6565b600c02016008016000015460138660028110611e5357611e53613fc6565b600c02016008016001015460138760028110611e7157611e71613fc6565b600c02016008016002015460138860028110611e8f57611e8f613fc6565b600c02016008016003015493509350935093509193509193565b6006546000906001600160a01b0316611ec457506001919050565b60065460405163ea0d5dcd60e01b81526001600160a01b039091169063ea0d5dcd90611ef4908590600401613e11565b602060405180830381865afa158015611f11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f3591906142e2565b611f4157506000919050565b600654604051634c3f70ab60e11b81526000916001600160a01b03169063987ee15690611f72908690600401613e11565b60c060405180830381865afa158015611f8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb39190613fdc565b50505050915050611fc381613515565b9392505050565b60606000826001600160401b03811115611fe657611fe6614138565b60405190808252806020026020018201604052801561201f57816020015b61200c613a78565b8152602001906001900390816120045790505b50905060005b60ff811684111561210c57600080600080601389898760ff1681811061204d5761204d613fc6565b90506020020160208101906120629190613b0e565b60ff166002811061207557612075613fc6565b600c02015411156120bb576120b38989898760ff1681811061209957612099613fc6565b90506020020160208101906120ae9190613b0e565b612a71565b919450925090505b604051806060016040528084815260200183815260200182815250858560ff16815181106120eb576120eb613fc6565b602002602001018190525050505080806121049061414e565b915050612025565b50949350505050565b61211d612fae565b612163600c5483839050600a548585600081811061213d5761213d613fc6565b905060200201358686600181811061215757612157613fc6565b905060200201356135f7565b8181600081811061217657612176613fc6565b6020029190910135600a55508181600181811061219557612195613fc6565b6020029190910135600b55507f57df350cfad05a64accd73700fee8a7febd6d8430e035e45f0599ca62494aa8b82826000816121d3576121d3613fc6565b90506020020135838360018181106121ed576121ed613fc6565b90506020020135604051610dcd9291906140c1565b6006546000906001600160a01b031661221d57506001919050565b60065460405163ea0d5dcd60e01b81526001600160a01b039091169063ea0d5dcd9061224d908590600401613e11565b602060405180830381865afa15801561226a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228e91906142e2565b61229a57506000919050565b600080600460020154604051634c3f70ab60e11b81526001600160a01b039091169063987ee156906122d0908790600401613e11565b60c060405180830381865afa1580156122ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123119190613fdc565b509450945050505061232484838361352e565b949350505050565b33612335611b88565b6001600160a01b03161461235b5760405162461bcd60e51b815260040161075f906140cf565b60005b81811015610be85760016002600085858581811061237e5761237e613fc6565b90506020020160208101906123939190613aab565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790558282828181106123cd576123cd613fc6565b90506020020160208101906123e29190613aab565b6001600160a01b031660008051602061434f83398151915260405160405180910390a28061240f81614104565b91505061235e565b61241f612fae565b612428836128b4565b600a546124429086868435604086013560608701356136a1565b8760138460ff166002811061245957612459613fc6565b600c0201600101819055508660138460ff166002811061247b5761247b613fc6565b600c02015585601360ff85166002811061249757612497613fc6565b600c0201600201819055508460138460ff16600281106124b9576124b9613fc6565b600c020160030160006101000a81548160ff0219169083151502179055508360138460ff16600281106124ee576124ee613fc6565b600c0201600401819055508160138460ff166002811061251057612510613fc6565b600c020160070160006101000a81548160ff0219169083600281111561253857612538613bfa565b02179055508035601360ff85166002811061255557612555613fc6565b600c020160080160000181905550806020013560138460ff166002811061257e5761257e613fc6565b600c020160080160010181905550806040013560138460ff16600281106125a7576125a7613fc6565b600c020160080160020181905550806060013560138460ff16600281106125d0576125d0613fc6565b600c0201600b01556000805b600d5460ff908116908216116126295760138160ff166002811061260257612602613fc6565b600c020160010154826126159190614051565b9150806126218161414e565b9150506125dc565b506012819055604080518a8152602081018a905260ff86168183015290517fddaf243a142670be60c19ff7116b5d8b124717b29bb4cc03cead42161614105b9181900360600190a1505050505050505050565b6000818152603360205260408120546126979060ff16612fde565b600082815260336020908152604091829020825160a081018452815460ff808216151583526001600160a01b0361010083041694830194909452600160a81b90049092169282019290925260018201546060820152600290910154608082015261068890612ffc565b6004816006811061271057600080fd5b01546001600160a01b0316905081565b33612729611b88565b6001600160a01b03161461274f5760405162461bcd60e51b815260040161075f906140cf565b6001600160a01b0381166127b45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161075f565b6127bd81613205565b50565b6127c8613a4a565b611fc361044a8484611b46565b6001600160a01b038116600090815260356020526040812054610688908390611b46565b60606000826001600160401b0381111561281557612815614138565b60405190808252806020026020018201604052801561283e578160200160208202803683370190505b50905060005b60ff811684111561210c576128828686868460ff1681811061286857612868613fc6565b905060200201602081019061287d9190613b0e565b61378d565b828260ff168151811061289757612897613fc6565b6020908102919091010152806128ac8161414e565b915050612844565b600d5460ff90811690821611156127bd57604051630a26ca2560e31b815260040160405180910390fd5b8242116128fe5760405163085de62560e01b815260040160405180910390fd5b8161291c576040516337191a8560e21b815260040160405180910390fd5b8015610be8576040516302cce53760e21b815260040160405180910390fd5b6006546001600160a01b0316156127bd576001600160a01b0381166000908152602b602052604090205460ff16158015612976575060105415155b156127bd576000805b600d5460ff908116908216116129cb57336000908152602c6020908152604080832060ff851684529091529020546129b79083614051565b9150806129c38161414e565b91505061297f565b50601154811115612a6d576001600160a01b0382166000908152602b60205260409020805460ff19166001179055600460020154601054600f54604051630dee0bfb60e11b8152336004820152602481019290925260448201526001600160a01b0390911690631bdc17f690606401600060405180830381600087803b158015612a5457600080fd5b505af1158015612a68573d6000803e3d6000fd5b505050505b5050565b60008060008060008060138760ff1660028110612a9057612a90613fc6565b600c020154601360ff891660028110612aab57612aab613fc6565b600c0201600501541115612c2d576000612ac5898961378d565b905064e8d4a510008160138a60ff1660028110612ae457612ae4613fc6565b600c020160010154612af69190614080565b612b00919061409f565b9350600064e8d4a510008260138b60ff1660028110612b2157612b21613fc6565b600c020154612b309190614080565b612b3a919061409f565b6001600160a01b038b166000908152602c6020908152604080832060ff8e168452909152902054909150612b6f908290614069565b935060138960ff1660028110612b8757612b87613fc6565b600c02016003015460ff1615612c2657600060138a60ff1660028110612baf57612baf613fc6565b600c02016004015490508060001415612bfc57612bf960138b60ff1660028110612bdb57612bdb613fc6565b600c02016005015460138c60ff1660028110610cf557610cf5613fc6565b90505b64e8d4a51000612c0c8287614080565b612c16919061409f565b9350612c228486614069565b9450505b5050612ca4565b60138760ff1660028110612c4357612c43613fc6565b600c020154601360ff891660028110612c5e57612c5e613fc6565b600c0201600101546001600160a01b038a166000908152602c6020908152604080832060ff8d168452909152902054612c979190614080565b612ca1919061409f565b92505b919450925090509250925092565b610be88363a9059cbb60e01b8484604051602401612cd192919061411f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261383c565b80612d116114fb565b1015612d7e5760405162461bcd60e51b815260206004820152603660248201527f63616e206e6f74206372656174652076657374696e67207363686564756c6520604482015275776974682073756666696369656e7420746f6b656e7360501b606482015260840161075f565b6000612d89846127d5565b60008181526033602052604090205490915061010090046001600160a01b031615612e005760405162461bcd60e51b815260206004820152602160248201527f76657374696e675363686564756c654964206973206265656e206372656174656044820152601960fa1b606482015260840161075f565b6040805160a08101825260018082526001600160a01b03878116602080850191825260ff898116868801908152606087018a81526000608089018181528b825260339095529890982096518754945191516001600160a81b0319909516901515610100600160a81b0319161761010091909516029390931760ff60a81b1916600160a81b92909316919091029190911783559251908201559051600290910155603454612eae908390614051565b60345560328054600181019091557f11df491316f14931039edfd4f8964c9a443b862f02d4c7611d18c2bc4e6ff697018190556001600160a01b0384166000908152603560205260408120805491612f0583614104565b919050555050505050565b600080612f1d838561409f565b90506105dc8110612f3557630ee6b280915050610688565b6103e88110612f4b57631dcd6500915050610688565b6101f48110612f6157633b9aca00915050610688565b60fa8110612f7657634a817c80915050610688565b60648110612f8b576359682f00915050610688565b60328110612fa057639502f900915050610688565b64012a05f200915050610688565b33612fb7611b88565b6001600160a01b0316146114f957604051635fc483c560e01b815260040160405180910390fd5b806127bd57604051638bc0c80560e01b815260040160405180910390fd5b60006013826040015160ff166002811061301857613018613fc6565b600c0201600801600101546030546130309190614051565b42101561303f57506000919050565b6013826040015160ff166002811061305957613059613fc6565b600c0201600801600201546030546130719190614051565b42101580613081575060315460ff165b1561309a57816080015182606001516106889190614069565b6000603054426130aa9190614069565b905060006013846040015160ff16600281106130c8576130c8613fc6565b600c0201600801600301549050600081836130e3919061409f565b905060006130f18383614080565b905060006013876040015160ff166002811061310f5761310f613fc6565b600c02016008016002015482886060015161312a9190614080565b613134919061409f565b90508660800151816131469190614069565b979650505050505050565b841561316f5760405162dc149f60e41b815260040160405180910390fd5b336001600160a01b0385161461319857604051631966391b60e11b815260040160405180910390fd5b826006146131b957604051633b9b621f60e01b815260040160405180910390fd5b816002146131da57604051631397ee3560e31b815260040160405180910390fd5b60028160ff16106131fe5760405163a854b3bd60e01b815260040160405180910390fd5b5050505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038616158015906132815750600285600281111561327e5761327e613bfa565b14155b156133105760405163ea0d5dcd60e01b81526001600160a01b0387169063ea0d5dcd906132b2903390600401613e11565b602060405180830381865afa1580156132cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f391906142e2565b6133105760405163645bb1bd60e11b815260040160405180910390fd5b83158061331b575082155b1561333957604051633c67586360e01b815260040160405180910390fd5b8142116133595760405163085de62560e01b815260040160405180910390fd5b8042111561337a5760405163ecdd1c2960e01b815260040160405180910390fd5b8661339857604051639e6c689560e01b815260040160405180910390fd5b50505050505050565b6004546133b9906001600160a01b031633308561390e565b336000908152602c6020908152604080832060ff851684529091529020546133e2908390614051565b336000908152602c6020908152604080832060ff86168085529252822092909255906013906002811061341757613417613fc6565b600c02016002015411156134805760138160ff166002811061343b5761343b613fc6565b600c020160020154336000908152602c6020908152604080832060ff8616845290915290205411156134805760405163037351d360e11b815260040160405180910390fd5b8160138260ff166002811061349757613497613fc6565b600c0201600501546134a99190614051565b60138260ff16600281106134bf576134bf613fc6565b600c0201600501819055508060ff16336001600160a01b03167ff763e680fce25a97ffd55d8b705370c98b47b2285f7b3b2900c43606fd4180458460405161350991815260200190565b60405180910390a35050565b6000600e54600014158015610688575050600e54111590565b60006004600501546001600160a01b03848116911614801561232457506000828152602e60205260409020546001600160a01b0316158061232457506000828152602e60205260409020546001600160a01b03858116911614949350505050565b828411156135b0576040516330a3824960e21b815260040160405180910390fd5b808211156135d157604051632af9b86160e01b815260040160405180910390fd5b50505050565b8042106127bd57604051630ffe6bd560e21b815260040160405180910390fd5b8360021461361857604051631397ee3560e31b815260040160405180910390fd5b6136228542614051565b81106136415760405163eb47c4f360e01b815260040160405180910390fd5b824210613661576040516365be5cfd60e11b815260040160405180910390fd5b808210613681576040516311af708560e21b815260040160405180910390fd5b8142106131fe5760405163582314d560e11b815260040160405180910390fd5b8542106136c1576040516365be5cfd60e11b815260040160405180910390fd5b64e8d4a5100084106136e657604051634494446160e11b815260040160405180910390fd5b606483111561370857604051630e07a92f60e01b815260040160405180910390fd5b8161372657604051630914cb9d60e41b815260040160405180910390fd5b600181101561374857604051631018767560e11b815260040160405180910390fd5b8181111561376957604051630cdbeed760e01b815260040160405180910390fd5b84612a68578315612a68576040516355d8bb6760e01b815260040160405180910390fd5b600d5460009060ff90811690831611156137a957506000610688565b600060138360ff16600281106137c1576137c1613fc6565b600c02016005015411156138345760138260ff16600281106137e5576137e5613fc6565b600c0201600501546001600160a01b0384166000908152602c6020908152604080832060ff871684529091529020546138239064e8d4a51000614080565b61382d919061409f565b9050610688565b506000610688565b6000613891826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139469092919063ffffffff16565b805190915015610be857808060200190518101906138af91906142e2565b610be85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161075f565b6040516001600160a01b03808516602483015283166044820152606481018290526135d19085906323b872dd60e01b90608401612cd1565b60606123248484600085856001600160a01b0385163b6139a85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161075f565b600080866001600160a01b031685876040516139c491906142ff565b60006040518083038185875af1925050503d8060008114613a01576040519150601f19603f3d011682016040523d82523d6000602084013e613a06565b606091505b509150915061314682828660608315613a20575081611fc3565b825115613a305782518084602001fd5b8160405162461bcd60e51b815260040161075f919061431b565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b03811681146127bd57600080fd5b600060208284031215613abd57600080fd5b8135611fc381613a96565b803560ff81168114610cff57600080fd5b60008060408385031215613aec57600080fd5b8235613af781613a96565b9150613b0560208401613ac8565b90509250929050565b600060208284031215613b2057600080fd5b611fc382613ac8565b60008083601f840112613b3b57600080fd5b5081356001600160401b03811115613b5257600080fd5b6020830191508360208260051b8501011115613b6d57600080fd5b9250929050565b60008060208385031215613b8757600080fd5b82356001600160401b03811115613b9d57600080fd5b613ba985828601613b29565b90969095509350505050565b600060208284031215613bc757600080fd5b5035919050565b60008060408385031215613be157600080fd5b8235613bec81613a96565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b600060e08201905088825287602083015286604083015285151560608301528460808301528360a083015260038310613c5957634e487b7160e01b600052602160045260246000fd5b8260c083015298975050505050505050565b600080600060408486031215613c8057600080fd5b8335613c8b81613a96565b925060208401356001600160401b03811115613ca657600080fd5b613cb286828701613b29565b9497909650939450505050565b600081518084526020808501945080840160005b83811015613cef57815187529582019590820190600101613cd3565b509495945050505050565b604081526000613d0d6040830185613cbf565b82810360208481019190915284518083528582019282019060005b81811015613d46578451151583529383019391830191600101613d28565b5090979650505050505050565b60008060008060008060008060c0898b031215613d6f57600080fd5b88356001600160401b0380821115613d8657600080fd5b613d928c838d01613b29565b909a50985060208b0135915080821115613dab57600080fd5b50613db88b828c01613b29565b90975095505060408901359350613dd160608a01613ac8565b92506080890135915060a089013590509295985092959890939650565b60008060408385031215613e0157600080fd5b82359150613b0560208401613ac8565b6001600160a01b0391909116815260200190565b60008060408385031215613e3857600080fd5b50508035926020909101359150565b9283526020830191909152604082015260600190565b600060608284031215613e6f57600080fd5b50919050565b602080825282518282018190526000919084820190604085019084805b82811015613ed257845184835b6003811015613ebc57825182529188019190880190600101613e9f565b5050509385019360609390930192600101613e92565b5091979650505050505050565b80151581146127bd57600080fd5b600080600080600080600080888a03610160811215613f0b57600080fd5b8935985060208a0135975060408a0135965060608a0135613f2b81613edf565b955060808a01359450613f4060a08b01613ac8565b935060c08a013560038110613f5457600080fd5b9250608060df1982011215613f6857600080fd5b5060e0890190509295985092959890939650565b602081526000611fc36020830184613cbf565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60008060008060008060c08789031215613ff557600080fd5b865195506020870151945060408701519350606087015161401581613a96565b608088015160a0890151919450925061402d81613edf565b809150509295509295509295565b634e487b7160e01b600052601160045260246000fd5b600082198211156140645761406461403b565b500190565b60008282101561407b5761407b61403b565b500390565b600081600019048311821515161561409a5761409a61403b565b500290565b6000826140bc57634e487b7160e01b600052601260045260246000fd5b500490565b918252602082015260400190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60006000198214156141185761411861403b565b5060010190565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052604160045260246000fd5b600060ff821660ff8114156141655761416561403b565b60010192915050565b60005b83811015614189578181015183820152602001614171565b838111156135d15750506000910152565b600082601f8301126141ab57600080fd5b81516001600160401b03808211156141c5576141c5614138565b604051601f8301601f19908116603f011681019082821181831017156141ed576141ed614138565b8160405283815286602085880101111561420657600080fd5b61421784602083016020890161416e565b9695505050505050565b600080600080600060a0868803121561423957600080fd5b85516001600160401b038082111561425057600080fd5b61425c89838a0161419a565b9650602088015191508082111561427257600080fd5b5061427f8882890161419a565b9450506040860151925060608601519150608086015161429e81613edf565b809150509295509295909350565b6000602082840312156142be57600080fd5b8151611fc381613a96565b6000602082840312156142db57600080fd5b5051919050565b6000602082840312156142f457600080fd5b8151611fc381613edf565b6000825161431181846020870161416e565b9190910192915050565b602081526000825180602084015261433a81604085016020870161416e565b601f01601f1916919091016040019291505056fed1bba68c128cc3f427e5831b3c6f99f480b6efa6b9e80c757768f6124158cc3ff1abf01a1043b7c244d128e8595cf0c1d10743b022b03a02dffd8ca3bf729f5aa26469706673582212200a84ff8121fa476fac7e72a07173efe9e8d336f22c8e54f9ba7d236b693a09d064736f6c634300080a0033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061023b5760003560e01c806306cec8571461024057806313083617146102685780631e3bba081461027a5780632374876c1461028d57806324953eaa146102a2578063286dd3f5146102b557806328fddfaf146102c857806337f859b8146102d55780633af32abf146102e85780633f138d4b146102fb57806346ab91bf1461030e57806348deb4711461033457806349032cdb1461033c5780634af3c9b71461035c57806354070e391461037d57806367d42a8b146103865780636865f6e914610399578063715018a6146103ac578063760b3180146103b457806379795108146103bd5780637b9417c8146103c55780637f1bdd76146103d85780638518b3c5146103eb5780638af104da146104215780638da5cb5b146104345780639ef346b41461043c5780639f1b52481461049a578063a47ff7e5146104ad578063a85adeab146104ce578063a8660a78146104d7578063ae8973a0146104e0578063b0adb220146104f3578063b1ced5e7146104fc578063b6549f751461051b578063b86c6f1414610523578063c029773714610556578063ca463ca414610569578063caa7f23214610589578063d04dac151461059c578063e2ec6ec3146105af578063e6fd48bc146105c2578063e9050763146105cb578063ea1bb3d5146105de578063edf26d9b146105f1578063f2fde38b14610604578063f51321d714610617578063f7c469f01461062a578063f9cd5c121461063d578063feebf5291461065d575b600080fd5b61025361024e366004613aab565b61067d565b60405190151581526020015b60405180910390f35b6032545b60405190815260200161025f565b61026c610288366004613ad9565b61068e565b6102a061029b366004613b0e565b61073c565b005b6102a06102b0366004613b74565b610afd565b6102a06102c3366004613aab565b610bed565b6031546102539060ff1681565b61026c6102e3366004613bb5565b610c53565b6102536102f6366004613aab565b610d04565b6102a0610309366004613bce565b610d22565b61032161031c366004613bb5565b610dd9565b60405161025f9796959493929190613c10565b60345461026c565b61026c61034a366004613aab565b602f6020526000908152604090205481565b61036f61036a366004613c6b565b610ebc565b60405161025f929190613cfa565b61026c600c5481565b6102a0610394366004613bb5565b611018565b6102a06103a7366004613d53565b6111d7565b6102a06114c0565b61026c60125481565b61026c6114fb565b6102a06103d3366004613aab565b611580565b6102a06103e6366004613dee565b6115e9565b6104146103f9366004613bb5565b602e602052600090815260409020546001600160a01b031681565b60405161025f9190613e11565b61026c61042f366004613bce565b611b46565b610414611b88565b61044f61044a366004613bb5565b611b97565b60405161025f91908151151581526020808301516001600160a01b03169082015260408083015160ff1690820152606080830151908201526080918201519181019190915260a00190565b6102a06104a8366004613e25565b611c03565b600f546010546011546104bf92919083565b60405161025f93929190613e47565b61026c600b5481565b61026c60305481565b6102a06104ee366004613e5d565b611d4e565b61026c600e5481565b600d546105099060ff1681565b60405160ff909116815260200161025f565b6102a0611db8565b610536610531366004613bb5565b611e1c565b60408051948552602085019390935291830152606082015260800161025f565b610253610564366004613aab565b611ea9565b61057c610577366004613c6b565b611fca565b60405161025f9190613e75565b6102a0610597366004613b74565b612115565b6102536105aa366004613aab565b612202565b6102a06105bd366004613b74565b61232c565b61026c600a5481565b6102a06105d9366004613eed565b612417565b61026c6105ec366004613bb5565b61267c565b6104146105ff366004613bb5565b612700565b6102a0610612366004613aab565b612720565b61044f610625366004613bce565b6127c0565b61026c610638366004613aab565b6127d5565b61065061064b366004613c6b565b6127f9565b60405161025f9190613f7c565b61026c61066b366004613aab565b602d6020526000908152604090205481565b600061068882610d04565b92915050565b600d5460009060ff90811690831611156106aa57506000610688565b60006106b7846000611b46565b600081815260336020908152604091829020825160a081018452815460ff808216151583526001600160a01b0361010083041694830194909452600160a81b900483169381018490526001820154606082015260029091015460808201529293508516141561072857509050610688565b610733856001611b46565b95945050505050565b600260005414156107685760405162461bcd60e51b815260040161075f90613f8f565b60405180910390fd5b6002600055610776816128b4565b600b54336000908152602c6020908152604080832060ff8681168552925290912080546001909101546107aa9392166128de565b336000908152602f60205260409020541561089557600654604051634c3f70ab60e11b8152600091829182916001600160a01b03169063987ee156906107f4903390600401613e11565b60c060405180830381865afa158015610811573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108359190613fdc565b95509550955050505080158061085957506009546001600160a01b03848116911614155b806108735750336000908152602f60205260409020548214155b15610891576040516319a9a2ef60e01b815260040160405180910390fd5b5050505b61089e3361293b565b336000908152602c6020908152604080832060ff8516845290915290206001908101805460ff191690911790556030546108d757426030555b60008060006108e63385612a71565b91945092509050801561093e578060138560ff166002811061090a5761090a613fc6565b600c02016006015461091c9190614051565b60138560ff166002811061093257610932613fc6565b600c0201600601819055505b8215610ade57600060138560ff166002811061095c5761095c613fc6565b600c02016008016000015460646109739190614069565b1115610a25576000606460138660ff166002811061099357610993613fc6565b600c02016008016000015460646109aa9190614069565b6109b49086614080565b6109be919061409f565b90506109dc3382600460015b01546001600160a01b03169190612cb2565b8460ff16336001600160a01b03167f51524c2e5edfedf8b01b29719c661e4fbe27e71734e7cd773dabb7cb712fb3b38386604051610a1b9291906140c1565b60405180910390a3505b600060138560ff1660028110610a3d57610a3d613fc6565b600c0201600801600001541115610ade576000606460138660ff1660028110610a6857610a68613fc6565b600c02016008016000015485610a7e9190614080565b610a88919061409f565b9050610a95338683612d08565b8460ff16336001600160a01b03167f4b386667138d87683f75b2e46ad8ac192b053af4c8875da8689415997663a9508386604051610ad49291906140c1565b60405180910390a3505b8115610af257610af23383600460006109ca565b505060016000555050565b33610b06611b88565b6001600160a01b031614610b2c5760405162461bcd60e51b815260040161075f906140cf565b60005b81811015610be857600060026000858585818110610b4f57610b4f613fc6565b9050602002016020810190610b649190613aab565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055828282818110610b9e57610b9e613fc6565b9050602002016020810190610bb39190613aab565b6001600160a01b031660008051602061436f83398151915260405160405180910390a280610be081614104565b915050610b2f565b505050565b33610bf6611b88565b6001600160a01b031614610c1c5760405162461bcd60e51b815260040161075f906140cf565b6001600160a01b038116600081815260026020526040808220805460ff191690555160008051602061436f8339815191529190a250565b600060138260028110610c6857610c68613fc6565b600c02016003015460ff16610c7f57506000919050565b600060138360028110610c9457610c94613fc6565b600c0201600401541115610cc45760138260028110610cb557610cb5613fc6565b600c0201600401549050919050565b61068860138360028110610cda57610cda613fc6565b600c02016005015460138460028110610cf557610cf5613fc6565b600c020154612f10565b919050565b6001600160a01b031660009081526002602052604090205460ff1690565b610d2a612fae565b6004546001600160a01b0383811691161415610d59576040516310da472360e01b815260040160405180910390fd5b6005546001600160a01b0383811691161415610d885760405163a8dfadb960e01b815260040160405180910390fd5b610d9c6001600160a01b0383163383612cb2565b7f74545154aac348a3eac92596bd1971957ca94795f4e954ec5f613b55fab781298282604051610dcd92919061411f565b60405180910390a15050565b600080600080600080600060138860028110610df757610df7613fc6565b600c02015460138960028110610e0f57610e0f613fc6565b600c02016001015460138a60028110610e2a57610e2a613fc6565b600c02016002015460138b60028110610e4557610e45613fc6565b600c02016003015460ff1660138c60028110610e6357610e63613fc6565b600c02016005015460138d60028110610e7e57610e7e613fc6565b600c02016006015460138e60028110610e9957610e99613fc6565b600c020160070154959e949d50929b509099509750955060ff9091169350915050565b6060806000836001600160401b03811115610ed957610ed9614138565b604051908082528060200260200182016040528015610f02578160200160208202803683370190505b5090506000846001600160401b03811115610f1f57610f1f614138565b604051908082528060200260200182016040528015610f48578160200160208202803683370190505b50905060005b600d5460ff9081169082161161100b576001600160a01b0388166000908152602c6020908152604080832060ff85168085529252909120548451909185918110610f9a57610f9a613fc6565b6020908102919091018101919091526001600160a01b0389166000908152602c8252604080822060ff8086168085529190945291206001015484519216918491908110610fe957610fe9613fc6565b91151560209283029190910190910152806110038161414e565b915050610f4e565b5090969095509350505050565b6002600054141561103b5760405162461bcd60e51b815260040161075f90613f8f565b600260009081558181526033602052604090205461105b9060ff16612fde565b6000818152603360205260408120805490916101009091046001600160a01b0316331490611087611b88565b6001600160a01b0316336001600160a01b0316149050811580156110a9575080155b156110c7576040516361c042c160e01b815260040160405180910390fd5b6040805160a081018252845460ff808216151583526001600160a01b036101008304166020840152600160a81b9091041691810191909152600184015460608201526002840154608082015260009061111f90612ffc565b90506000811161114257604051632d973f4d60e11b815260040160405180910390fd5b8084600201546111529190614051565b6002850155603454611165908290614069565b60345583546111869061010090046001600160a01b031682600460016109ca565b83546040518281526101009091046001600160a01b0316907fb21fb52d5749b80f3182f8c6992236b5e5576681880914484d7f4c9b062e619e9060200160405180910390a250506001600055505050565b60035461120a9060ff167f00000000000000000000000011b63467cf299d634d7c1a07221d78c5f08095d7898887613151565b6003805460ff1916600117905560008888600281811061122c5761122c613fc6565b90506020020160208101906112419190613aab565b6001600160a01b0316146112ec578787600281811061126257611262613fc6565b90506020020160208101906112779190613aab565b60405163aee2f47f60e01b8152600160048201526001600160a01b03919091169063aee2f47f90602401600060405180830381865afa1580156112be573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112e69190810190614221565b50505050505b60008888600381811061130157611301613fc6565b90506020020160208101906113169190613aab565b6001600160a01b0316146113af578787600381811061133757611337613fc6565b905060200201602081019061134c9190613aab565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611389573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ad91906142ac565b505b60005b60ff811688111561142e5788888260ff168181106113d2576113d2613fc6565b90506020020160208101906113e79190613aab565b60048260ff16600681106113fd576113fd613fc6565b0180546001600160a01b0319166001600160a01b0392909216919091179055806114268161414e565b9150506113b2565b508585600081811061144257611442613fc6565b6020029190910135600a55508585600181811061146157611461613fc6565b6020029190910135600b5550600c849055600d805460ff191660ff8516179055600e82905560308190556114b6888860048181106114a1576114a1613fc6565b90506020020160208101906106129190613aab565b5050505050505050565b336114c9611b88565b6001600160a01b0316146114ef5760405162461bcd60e51b815260040161075f906140cf565b6114f96000613205565b565b6034546005546040516370a0823160e01b8152600092916001600160a01b0316906370a0823190611530903090600401613e11565b602060405180830381865afa15801561154d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157191906142c9565b61157b9190614069565b905090565b33611589611b88565b6001600160a01b0316146115af5760405162461bcd60e51b815260040161075f906140cf565b6001600160a01b038116600081815260026020526040808220805460ff191660011790555160008051602061434f8339815191529190a250565b6002600054141561160c5760405162461bcd60e51b815260040161075f90613f8f565b600260005561161a816128b4565b61169c826004600201546001600160a01b0316601360ff85166002811061164357611643613fc6565b600c020160070160009054906101000a900460ff1660138560ff166002811061166e5761166e613fc6565b600c02016001015460138660ff166002811061168c5761168c613fc6565b600c020154600a54600b54613257565b6012546005546040516370a0823160e01b81526001600160a01b03909116906370a08231906116cf903090600401613e11565b602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171091906142c9565b101561172f5760405163726da7d560e11b815260040160405180910390fd5b600060138260ff166002811061174757611747613fc6565b600c02016007015460ff16600281111561176357611763613bfa565b14806117a05750600260138260ff166002811061178257611782613fc6565b600c02016007015460ff16600281111561179e5761179e613bfa565b145b15611924576007546001600160a01b0316158015906117f15750600260138260ff16600281106117d2576117d2613fc6565b600c02016007015460ff1660028111156117ee576117ee613bfa565b14155b156118a9576007546040516336b5bc3760e21b81526000916001600160a01b03169063dad6f0dc90611827903390600401613e11565b602060405180830381865afa158015611844573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186891906142c9565b336000908152602d60205260409020549091508190611888908590614051565b11156118a757604051630448a42b60e21b815260040160405180910390fd5b505b6118b382826133a1565b600060138260ff16600281106118cb576118cb613fc6565b600c02016007015460ff1660028111156118e7576118e7613bfa565b146118f35760006118f5565b815b336000908152602d602052604090205461190f9190614051565b336000908152602d6020526040902055611b3d565b6006546001600160a01b031615611b33576000808080600460020154604051634c3f70ab60e11b81526001600160a01b039091169063987ee1569061196d903390600401613e11565b60c060405180830381865afa15801561198a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ae9190613fdc565b95509550955050945050806119d65760405163f7bd660760e01b815260040160405180910390fd5b6119df84613515565b1580156119f257506119f03361067d565b155b8015611a065750611a0433848461352e565b155b15611a24576040516309a318fb60e31b815260040160405180910390fd5b611a2d84613515565b158015611a405750611a3e3361067d565b155b8015611a5957506009546001600160a01b038481169116145b15611b2e576000828152602e60205260409020546001600160a01b0316611a9d576000828152602e6020526040902080546001600160a01b03191633179055611ad4565b6000828152602e60205260409020546001600160a01b03163314611ad45760405163d69933c360e01b815260040160405180910390fd5b336000908152602f6020526040902054611aff57336000908152602f60205260409020829055611b2e565b336000908152602f60205260409020548214611b2e57604051630236c46360e51b815260040160405180910390fd5b505050505b611b3d82826133a1565b50506001600055565b6040516001600160601b0319606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b6001546001600160a01b031690565b611b9f613a4a565b50600090815260336020908152604091829020825160a081018452815460ff808216151583526001600160a01b0361010083041694830194909452600160a81b90049092169282019290925260018201546060820152600290910154608082015290565b611c0b612fae565b600480546040516370a0823160e01b8152611cf59285926001600160a01b0316916370a0823191611c3e91309101613e11565b602060405180830381865afa158015611c5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7f91906142c9565b6005546040516370a0823160e01b815285916001600160a01b0316906370a0823190611caf903090600401613e11565b602060405180830381865afa158015611ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf091906142c9565b61358f565b8115611d0957611d093383600460006109ca565b8015611d1d57611d1d3382600460016109ca565b7f94ebb62a252249c867ecb758d386f50a95be7e8df9e1c52917c9cf494327dd7d8282604051610dcd9291906140c1565b611d56612fae565b611d61600b546135d7565b602081013560108190558135600f819055604080840135601181905590517f2058a318dbdfd2edd92a32cfa0ee233a30b165b83b421830109cb22ae86f674593611dad93929091613e47565b60405180910390a150565b611dc0612fae565b60315460ff1615611de457604051630476d49560e21b815260040160405180910390fd5b6031805460ff191660011790556040517f44825a4b2df8acb19ce4e1afba9aa850c8b65cdb7942e2078f27d0b0960efee690600090a1565b60008060008060138560028110611e3557611e35613fc6565b600c02016008016000015460138660028110611e5357611e53613fc6565b600c02016008016001015460138760028110611e7157611e71613fc6565b600c02016008016002015460138860028110611e8f57611e8f613fc6565b600c02016008016003015493509350935093509193509193565b6006546000906001600160a01b0316611ec457506001919050565b60065460405163ea0d5dcd60e01b81526001600160a01b039091169063ea0d5dcd90611ef4908590600401613e11565b602060405180830381865afa158015611f11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f3591906142e2565b611f4157506000919050565b600654604051634c3f70ab60e11b81526000916001600160a01b03169063987ee15690611f72908690600401613e11565b60c060405180830381865afa158015611f8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb39190613fdc565b50505050915050611fc381613515565b9392505050565b60606000826001600160401b03811115611fe657611fe6614138565b60405190808252806020026020018201604052801561201f57816020015b61200c613a78565b8152602001906001900390816120045790505b50905060005b60ff811684111561210c57600080600080601389898760ff1681811061204d5761204d613fc6565b90506020020160208101906120629190613b0e565b60ff166002811061207557612075613fc6565b600c02015411156120bb576120b38989898760ff1681811061209957612099613fc6565b90506020020160208101906120ae9190613b0e565b612a71565b919450925090505b604051806060016040528084815260200183815260200182815250858560ff16815181106120eb576120eb613fc6565b602002602001018190525050505080806121049061414e565b915050612025565b50949350505050565b61211d612fae565b612163600c5483839050600a548585600081811061213d5761213d613fc6565b905060200201358686600181811061215757612157613fc6565b905060200201356135f7565b8181600081811061217657612176613fc6565b6020029190910135600a55508181600181811061219557612195613fc6565b6020029190910135600b55507f57df350cfad05a64accd73700fee8a7febd6d8430e035e45f0599ca62494aa8b82826000816121d3576121d3613fc6565b90506020020135838360018181106121ed576121ed613fc6565b90506020020135604051610dcd9291906140c1565b6006546000906001600160a01b031661221d57506001919050565b60065460405163ea0d5dcd60e01b81526001600160a01b039091169063ea0d5dcd9061224d908590600401613e11565b602060405180830381865afa15801561226a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228e91906142e2565b61229a57506000919050565b600080600460020154604051634c3f70ab60e11b81526001600160a01b039091169063987ee156906122d0908790600401613e11565b60c060405180830381865afa1580156122ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123119190613fdc565b509450945050505061232484838361352e565b949350505050565b33612335611b88565b6001600160a01b03161461235b5760405162461bcd60e51b815260040161075f906140cf565b60005b81811015610be85760016002600085858581811061237e5761237e613fc6565b90506020020160208101906123939190613aab565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790558282828181106123cd576123cd613fc6565b90506020020160208101906123e29190613aab565b6001600160a01b031660008051602061434f83398151915260405160405180910390a28061240f81614104565b91505061235e565b61241f612fae565b612428836128b4565b600a546124429086868435604086013560608701356136a1565b8760138460ff166002811061245957612459613fc6565b600c0201600101819055508660138460ff166002811061247b5761247b613fc6565b600c02015585601360ff85166002811061249757612497613fc6565b600c0201600201819055508460138460ff16600281106124b9576124b9613fc6565b600c020160030160006101000a81548160ff0219169083151502179055508360138460ff16600281106124ee576124ee613fc6565b600c0201600401819055508160138460ff166002811061251057612510613fc6565b600c020160070160006101000a81548160ff0219169083600281111561253857612538613bfa565b02179055508035601360ff85166002811061255557612555613fc6565b600c020160080160000181905550806020013560138460ff166002811061257e5761257e613fc6565b600c020160080160010181905550806040013560138460ff16600281106125a7576125a7613fc6565b600c020160080160020181905550806060013560138460ff16600281106125d0576125d0613fc6565b600c0201600b01556000805b600d5460ff908116908216116126295760138160ff166002811061260257612602613fc6565b600c020160010154826126159190614051565b9150806126218161414e565b9150506125dc565b506012819055604080518a8152602081018a905260ff86168183015290517fddaf243a142670be60c19ff7116b5d8b124717b29bb4cc03cead42161614105b9181900360600190a1505050505050505050565b6000818152603360205260408120546126979060ff16612fde565b600082815260336020908152604091829020825160a081018452815460ff808216151583526001600160a01b0361010083041694830194909452600160a81b90049092169282019290925260018201546060820152600290910154608082015261068890612ffc565b6004816006811061271057600080fd5b01546001600160a01b0316905081565b33612729611b88565b6001600160a01b03161461274f5760405162461bcd60e51b815260040161075f906140cf565b6001600160a01b0381166127b45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161075f565b6127bd81613205565b50565b6127c8613a4a565b611fc361044a8484611b46565b6001600160a01b038116600090815260356020526040812054610688908390611b46565b60606000826001600160401b0381111561281557612815614138565b60405190808252806020026020018201604052801561283e578160200160208202803683370190505b50905060005b60ff811684111561210c576128828686868460ff1681811061286857612868613fc6565b905060200201602081019061287d9190613b0e565b61378d565b828260ff168151811061289757612897613fc6565b6020908102919091010152806128ac8161414e565b915050612844565b600d5460ff90811690821611156127bd57604051630a26ca2560e31b815260040160405180910390fd5b8242116128fe5760405163085de62560e01b815260040160405180910390fd5b8161291c576040516337191a8560e21b815260040160405180910390fd5b8015610be8576040516302cce53760e21b815260040160405180910390fd5b6006546001600160a01b0316156127bd576001600160a01b0381166000908152602b602052604090205460ff16158015612976575060105415155b156127bd576000805b600d5460ff908116908216116129cb57336000908152602c6020908152604080832060ff851684529091529020546129b79083614051565b9150806129c38161414e565b91505061297f565b50601154811115612a6d576001600160a01b0382166000908152602b60205260409020805460ff19166001179055600460020154601054600f54604051630dee0bfb60e11b8152336004820152602481019290925260448201526001600160a01b0390911690631bdc17f690606401600060405180830381600087803b158015612a5457600080fd5b505af1158015612a68573d6000803e3d6000fd5b505050505b5050565b60008060008060008060138760ff1660028110612a9057612a90613fc6565b600c020154601360ff891660028110612aab57612aab613fc6565b600c0201600501541115612c2d576000612ac5898961378d565b905064e8d4a510008160138a60ff1660028110612ae457612ae4613fc6565b600c020160010154612af69190614080565b612b00919061409f565b9350600064e8d4a510008260138b60ff1660028110612b2157612b21613fc6565b600c020154612b309190614080565b612b3a919061409f565b6001600160a01b038b166000908152602c6020908152604080832060ff8e168452909152902054909150612b6f908290614069565b935060138960ff1660028110612b8757612b87613fc6565b600c02016003015460ff1615612c2657600060138a60ff1660028110612baf57612baf613fc6565b600c02016004015490508060001415612bfc57612bf960138b60ff1660028110612bdb57612bdb613fc6565b600c02016005015460138c60ff1660028110610cf557610cf5613fc6565b90505b64e8d4a51000612c0c8287614080565b612c16919061409f565b9350612c228486614069565b9450505b5050612ca4565b60138760ff1660028110612c4357612c43613fc6565b600c020154601360ff891660028110612c5e57612c5e613fc6565b600c0201600101546001600160a01b038a166000908152602c6020908152604080832060ff8d168452909152902054612c979190614080565b612ca1919061409f565b92505b919450925090509250925092565b610be88363a9059cbb60e01b8484604051602401612cd192919061411f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261383c565b80612d116114fb565b1015612d7e5760405162461bcd60e51b815260206004820152603660248201527f63616e206e6f74206372656174652076657374696e67207363686564756c6520604482015275776974682073756666696369656e7420746f6b656e7360501b606482015260840161075f565b6000612d89846127d5565b60008181526033602052604090205490915061010090046001600160a01b031615612e005760405162461bcd60e51b815260206004820152602160248201527f76657374696e675363686564756c654964206973206265656e206372656174656044820152601960fa1b606482015260840161075f565b6040805160a08101825260018082526001600160a01b03878116602080850191825260ff898116868801908152606087018a81526000608089018181528b825260339095529890982096518754945191516001600160a81b0319909516901515610100600160a81b0319161761010091909516029390931760ff60a81b1916600160a81b92909316919091029190911783559251908201559051600290910155603454612eae908390614051565b60345560328054600181019091557f11df491316f14931039edfd4f8964c9a443b862f02d4c7611d18c2bc4e6ff697018190556001600160a01b0384166000908152603560205260408120805491612f0583614104565b919050555050505050565b600080612f1d838561409f565b90506105dc8110612f3557630ee6b280915050610688565b6103e88110612f4b57631dcd6500915050610688565b6101f48110612f6157633b9aca00915050610688565b60fa8110612f7657634a817c80915050610688565b60648110612f8b576359682f00915050610688565b60328110612fa057639502f900915050610688565b64012a05f200915050610688565b33612fb7611b88565b6001600160a01b0316146114f957604051635fc483c560e01b815260040160405180910390fd5b806127bd57604051638bc0c80560e01b815260040160405180910390fd5b60006013826040015160ff166002811061301857613018613fc6565b600c0201600801600101546030546130309190614051565b42101561303f57506000919050565b6013826040015160ff166002811061305957613059613fc6565b600c0201600801600201546030546130719190614051565b42101580613081575060315460ff165b1561309a57816080015182606001516106889190614069565b6000603054426130aa9190614069565b905060006013846040015160ff16600281106130c8576130c8613fc6565b600c0201600801600301549050600081836130e3919061409f565b905060006130f18383614080565b905060006013876040015160ff166002811061310f5761310f613fc6565b600c02016008016002015482886060015161312a9190614080565b613134919061409f565b90508660800151816131469190614069565b979650505050505050565b841561316f5760405162dc149f60e41b815260040160405180910390fd5b336001600160a01b0385161461319857604051631966391b60e11b815260040160405180910390fd5b826006146131b957604051633b9b621f60e01b815260040160405180910390fd5b816002146131da57604051631397ee3560e31b815260040160405180910390fd5b60028160ff16106131fe5760405163a854b3bd60e01b815260040160405180910390fd5b5050505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038616158015906132815750600285600281111561327e5761327e613bfa565b14155b156133105760405163ea0d5dcd60e01b81526001600160a01b0387169063ea0d5dcd906132b2903390600401613e11565b602060405180830381865afa1580156132cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f391906142e2565b6133105760405163645bb1bd60e11b815260040160405180910390fd5b83158061331b575082155b1561333957604051633c67586360e01b815260040160405180910390fd5b8142116133595760405163085de62560e01b815260040160405180910390fd5b8042111561337a5760405163ecdd1c2960e01b815260040160405180910390fd5b8661339857604051639e6c689560e01b815260040160405180910390fd5b50505050505050565b6004546133b9906001600160a01b031633308561390e565b336000908152602c6020908152604080832060ff851684529091529020546133e2908390614051565b336000908152602c6020908152604080832060ff86168085529252822092909255906013906002811061341757613417613fc6565b600c02016002015411156134805760138160ff166002811061343b5761343b613fc6565b600c020160020154336000908152602c6020908152604080832060ff8616845290915290205411156134805760405163037351d360e11b815260040160405180910390fd5b8160138260ff166002811061349757613497613fc6565b600c0201600501546134a99190614051565b60138260ff16600281106134bf576134bf613fc6565b600c0201600501819055508060ff16336001600160a01b03167ff763e680fce25a97ffd55d8b705370c98b47b2285f7b3b2900c43606fd4180458460405161350991815260200190565b60405180910390a35050565b6000600e54600014158015610688575050600e54111590565b60006004600501546001600160a01b03848116911614801561232457506000828152602e60205260409020546001600160a01b0316158061232457506000828152602e60205260409020546001600160a01b03858116911614949350505050565b828411156135b0576040516330a3824960e21b815260040160405180910390fd5b808211156135d157604051632af9b86160e01b815260040160405180910390fd5b50505050565b8042106127bd57604051630ffe6bd560e21b815260040160405180910390fd5b8360021461361857604051631397ee3560e31b815260040160405180910390fd5b6136228542614051565b81106136415760405163eb47c4f360e01b815260040160405180910390fd5b824210613661576040516365be5cfd60e11b815260040160405180910390fd5b808210613681576040516311af708560e21b815260040160405180910390fd5b8142106131fe5760405163582314d560e11b815260040160405180910390fd5b8542106136c1576040516365be5cfd60e11b815260040160405180910390fd5b64e8d4a5100084106136e657604051634494446160e11b815260040160405180910390fd5b606483111561370857604051630e07a92f60e01b815260040160405180910390fd5b8161372657604051630914cb9d60e41b815260040160405180910390fd5b600181101561374857604051631018767560e11b815260040160405180910390fd5b8181111561376957604051630cdbeed760e01b815260040160405180910390fd5b84612a68578315612a68576040516355d8bb6760e01b815260040160405180910390fd5b600d5460009060ff90811690831611156137a957506000610688565b600060138360ff16600281106137c1576137c1613fc6565b600c02016005015411156138345760138260ff16600281106137e5576137e5613fc6565b600c0201600501546001600160a01b0384166000908152602c6020908152604080832060ff871684529091529020546138239064e8d4a51000614080565b61382d919061409f565b9050610688565b506000610688565b6000613891826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139469092919063ffffffff16565b805190915015610be857808060200190518101906138af91906142e2565b610be85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161075f565b6040516001600160a01b03808516602483015283166044820152606481018290526135d19085906323b872dd60e01b90608401612cd1565b60606123248484600085856001600160a01b0385163b6139a85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161075f565b600080866001600160a01b031685876040516139c491906142ff565b60006040518083038185875af1925050503d8060008114613a01576040519150601f19603f3d011682016040523d82523d6000602084013e613a06565b606091505b509150915061314682828660608315613a20575081611fc3565b825115613a305782518084602001fd5b8160405162461bcd60e51b815260040161075f919061431b565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b03811681146127bd57600080fd5b600060208284031215613abd57600080fd5b8135611fc381613a96565b803560ff81168114610cff57600080fd5b60008060408385031215613aec57600080fd5b8235613af781613a96565b9150613b0560208401613ac8565b90509250929050565b600060208284031215613b2057600080fd5b611fc382613ac8565b60008083601f840112613b3b57600080fd5b5081356001600160401b03811115613b5257600080fd5b6020830191508360208260051b8501011115613b6d57600080fd5b9250929050565b60008060208385031215613b8757600080fd5b82356001600160401b03811115613b9d57600080fd5b613ba985828601613b29565b90969095509350505050565b600060208284031215613bc757600080fd5b5035919050565b60008060408385031215613be157600080fd5b8235613bec81613a96565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b600060e08201905088825287602083015286604083015285151560608301528460808301528360a083015260038310613c5957634e487b7160e01b600052602160045260246000fd5b8260c083015298975050505050505050565b600080600060408486031215613c8057600080fd5b8335613c8b81613a96565b925060208401356001600160401b03811115613ca657600080fd5b613cb286828701613b29565b9497909650939450505050565b600081518084526020808501945080840160005b83811015613cef57815187529582019590820190600101613cd3565b509495945050505050565b604081526000613d0d6040830185613cbf565b82810360208481019190915284518083528582019282019060005b81811015613d46578451151583529383019391830191600101613d28565b5090979650505050505050565b60008060008060008060008060c0898b031215613d6f57600080fd5b88356001600160401b0380821115613d8657600080fd5b613d928c838d01613b29565b909a50985060208b0135915080821115613dab57600080fd5b50613db88b828c01613b29565b90975095505060408901359350613dd160608a01613ac8565b92506080890135915060a089013590509295985092959890939650565b60008060408385031215613e0157600080fd5b82359150613b0560208401613ac8565b6001600160a01b0391909116815260200190565b60008060408385031215613e3857600080fd5b50508035926020909101359150565b9283526020830191909152604082015260600190565b600060608284031215613e6f57600080fd5b50919050565b602080825282518282018190526000919084820190604085019084805b82811015613ed257845184835b6003811015613ebc57825182529188019190880190600101613e9f565b5050509385019360609390930192600101613e92565b5091979650505050505050565b80151581146127bd57600080fd5b600080600080600080600080888a03610160811215613f0b57600080fd5b8935985060208a0135975060408a0135965060608a0135613f2b81613edf565b955060808a01359450613f4060a08b01613ac8565b935060c08a013560038110613f5457600080fd5b9250608060df1982011215613f6857600080fd5b5060e0890190509295985092959890939650565b602081526000611fc36020830184613cbf565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60008060008060008060c08789031215613ff557600080fd5b865195506020870151945060408701519350606087015161401581613a96565b608088015160a0890151919450925061402d81613edf565b809150509295509295509295565b634e487b7160e01b600052601160045260246000fd5b600082198211156140645761406461403b565b500190565b60008282101561407b5761407b61403b565b500390565b600081600019048311821515161561409a5761409a61403b565b500290565b6000826140bc57634e487b7160e01b600052601260045260246000fd5b500490565b918252602082015260400190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60006000198214156141185761411861403b565b5060010190565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052604160045260246000fd5b600060ff821660ff8114156141655761416561403b565b60010192915050565b60005b83811015614189578181015183820152602001614171565b838111156135d15750506000910152565b600082601f8301126141ab57600080fd5b81516001600160401b03808211156141c5576141c5614138565b604051601f8301601f19908116603f011681019082821181831017156141ed576141ed614138565b8160405283815286602085880101111561420657600080fd5b61421784602083016020890161416e565b9695505050505050565b600080600080600060a0868803121561423957600080fd5b85516001600160401b038082111561425057600080fd5b61425c89838a0161419a565b9650602088015191508082111561427257600080fd5b5061427f8882890161419a565b9450506040860151925060608601519150608086015161429e81613edf565b809150509295509295909350565b6000602082840312156142be57600080fd5b8151611fc381613a96565b6000602082840312156142db57600080fd5b5051919050565b6000602082840312156142f457600080fd5b8151611fc381613edf565b6000825161431181846020870161416e565b9190910192915050565b602081526000825180602084015261433a81604085016020870161416e565b601f01601f1916919091016040019291505056fed1bba68c128cc3f427e5831b3c6f99f480b6efa6b9e80c757768f6124158cc3ff1abf01a1043b7c244d128e8595cf0c1d10743b022b03a02dffd8ca3bf729f5aa26469706673582212200a84ff8121fa476fac7e72a07173efe9e8d336f22c8e54f9ba7d236b693a09d064736f6c634300080a0033
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.