- Contract name:
- PresaleManage
- Optimization enabled
- true
- Compiler version
- v0.8.13+commit.abaa5c0e
- Optimization runs
- 5000
- EVM Version
- default
- Verified at
- 2024-07-20T06:18:39.147510Z
contracts/Presale/Meter/PresaleManage.sol
// SPDX-License-Identifier: UNLICENSED
// @Credits Unicrypt Network 2021
// This contract generates Presale01 contracts and registers them in the PresaleFactory.
// Ideally you should not interact with this contract directly, and use the Octofi presale app instead so warnings can be shown where necessary.
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "../TransferHelper.sol";
import "../PresaleSettings.sol";
import "./SharedStructs.sol";
import "./PresaleLockForwarder.sol";
import "./PresaleFactory.sol";
import "./Presale.sol";
contract PresaleManage {
using EnumerableSet for EnumerableSet.AddressSet;
EnumerableSet.AddressSet private presales;
PresaleFactory internal presaleFactory;
address public presale_lock_forward_addr;
address public presale_setting_addr;
PresaleLockForwarder _lock;
address private uniswap_factory_address;
address private uniswap_pair_address;
address private weth_address;
address payable owner;
SharedStructs.PresaleInfo presale_info;
SharedStructs.PresaleLink presalelink;
PresaleSettings public settings;
event OwnerWithdrawSuccess(uint256 value);
event CreatePreslaeSuccess(address, address);
constructor(
address payable _owner,
address lock_addr,
address uniswapfactory_addr,
address uniswaprouter_Addr,
address weth_addr,
PresaleFactory _presaleFactory
) {
owner = _owner;
uniswap_factory_address = uniswapfactory_addr;
weth_address = weth_addr;
_lock = new PresaleLockForwarder(
address(this),
lock_addr,
uniswapfactory_addr,
uniswaprouter_Addr,
weth_addr
);
presale_lock_forward_addr = address(_lock);
PresaleSettings _setting;
_setting = new PresaleSettings(address(this), _owner, lock_addr);
_setting.init(owner, 0.01 ether, owner, 10, owner, 10, owner, 10);
presale_setting_addr = address(_setting);
settings = PresaleSettings(presale_setting_addr);
presaleFactory = _presaleFactory;
}
function ownerWithdraw() public {
require(
msg.sender == settings.getCreateFeeAddress(),
"Only creater can withdraw"
);
address payable reciver = payable(settings.getCreateFeeAddress());
reciver.transfer(address(this).balance);
// owner.transfer(address(this).balance);
emit OwnerWithdrawSuccess(address(this).balance);
}
/**
* @notice Creates a new Presale contract and registers it in the PresaleFactory.sol.
*/
function calculateAmountRequired(
uint256 _amount,
uint256 _tokenPrice,
uint256 _listingRate,
uint256 _liquidityPercent,
uint256 _tokenFee
) public pure returns (uint256) {
uint256 tokenamount = (_amount * _tokenPrice) / (10**18);
uint256 TokenFee = (((_amount * _tokenFee) / 100) / 10**18) *
_tokenPrice;
uint256 liqudityrateamount = (_amount * _listingRate) / (10**18);
uint256 liquiditytoken = (liqudityrateamount * _liquidityPercent) / 100;
uint256 tokensRequiredForPresale = tokenamount +
liquiditytoken +
TokenFee;
return tokensRequiredForPresale;
}
function createPresale(
SharedStructs.PresaleInfo memory _presale_info,
SharedStructs.PresaleLink memory _presalelink
) public payable {
presale_info = _presale_info;
presalelink = _presalelink;
// if ( (presale_info.presale_end - presale_info.presale_start) < 1 weeks) {
// presale_info.presale_end = presale_info.presale_start + 1 weeks;
// }
// if ( (presale_info.lock_end - presale_info.lock_start) < 4 weeks) {
// presale_info.lock_end = presale_info.lock_start + 4 weeks;
// }
// Charge ETH fee for contract creation
require(
msg.value >= settings.getPresaleCreateFee() + settings.getLockFee(),
"Balance is insufficent"
);
require(_presale_info.token_rate > 0, "token rate is invalid");
require(
_presale_info.raise_min < _presale_info.raise_max,
"raise min/max in invalid"
);
require(
_presale_info.softcap <= _presale_info.hardcap,
"softcap/hardcap is invalid"
);
require(
_presale_info.liqudity_percent >= 30 &&
_presale_info.liqudity_percent <= 100,
"Liqudity percent is invalid"
);
require(_presale_info.listing_rate > 0, "Listing rate is invalid");
require(
(_presale_info.presale_end - _presale_info.presale_start) > 0,
"Presale start/end time is invalid"
);
require(
(_presale_info.lock_end - _presale_info.lock_start) >= 4 weeks,
"Lock end is invalid"
);
// Calculate required token amount
uint256 tokensRequiredForPresale = calculateAmountRequired(
_presale_info.hardcap,
_presale_info.token_rate,
_presale_info.listing_rate,
_presale_info.liqudity_percent,
settings.getSoldFee()
);
// Create New presale
PresaleV1 newPresale = presaleFactory.deploy{
value: settings.getLockFee()
}(
address(this),
weth_address,
presale_setting_addr,
presale_lock_forward_addr
);
// newPresale.delegatecall(bytes4(sha3("destroy()")));
if (address(newPresale) == address(0)) {
// newPresale.destroy();
require(false, "Create presale Failed");
}
TransferHelper.safeTransferFrom(
address(_presale_info.sale_token),
address(msg.sender),
address(newPresale),
tokensRequiredForPresale
);
newPresale.init_private(_presale_info);
newPresale.init_link(_presalelink);
newPresale.init_fee();
presales.add(address(newPresale));
emit CreatePreslaeSuccess(address(newPresale), address(msg.sender));
}
function getCount() external view returns (uint256) {
return presales.length();
}
function getBalance() external view returns (uint256) {
return address(this).balance;
}
function getPresaleAt(uint256 index) external view returns (address) {
return presales.at(index);
}
function IsRegistered(address presale_addr) external view returns (bool) {
return presales.contains(presale_addr);
}
}
contracts/interfaces/IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(
address src,
address dst,
uint256 wad
) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function balanceOf(address owner) external view returns (uint256);
function decimals() external view returns (uint256);
}
contracts/interfaces/IUniswapV2Router01.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
)
external
returns (
uint256 amountA,
uint256 amountB,
uint256 liquidity
);
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (
uint256 amountToken,
uint256 amountETH,
uint256 liquidity
);
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountToken, uint256 amountETH);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) external pure returns (uint256 amountB);
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountOut);
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountIn);
function getAmountsOut(uint256 amountIn, address[] calldata path)
external
view
returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, address[] calldata path)
external
view
returns (uint256[] memory amounts);
}
@openzeppelin/contracts/security/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
@openzeppelin/contracts/utils/structs/EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}
contracts/interfaces/IUniswapV2Router02.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IUniswapV2Router01.sol";
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
}
contracts/LiquidityLock/LPLock.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract LPLocker {
address public owner;
uint256 public price;
uint256 public penaltyfee;
struct holder {
address holderAddress;
mapping(address => Token) tokens;
}
struct Token {
uint256 balance;
address tokenAddress;
uint256 unlockTime;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only available to the contract owner.");
_;
}
mapping(address => holder) public holders;
constructor(address _owner, uint256 _price) {
owner = _owner;
price = _price;
penaltyfee = 10; // default value
}
event Hold(
address indexed holder,
address token,
uint256 amount,
uint256 unlockTime
);
event PanicWithdraw(
address indexed holder,
address token,
uint256 amount,
uint256 unlockTime
);
event Withdrawal(address indexed holder, address token, uint256 amount);
event FeesClaimed();
event SetOwnerSuccess(address owner);
event SetPriceSuccess(uint256 _price);
event SetPenaltyFeeSuccess(uint256 _fee);
event OwnerWithdrawSuccess(uint256 amount);
function lpLock(
address token,
uint256 amount,
uint256 unlockTime,
address withdrawer
) public payable {
require(msg.value >= price, "Required price is low");
holder storage holder0 = holders[withdrawer];
holder0.holderAddress = withdrawer;
Token storage lockedToken = holders[withdrawer].tokens[token];
if (lockedToken.balance > 0) {
lockedToken.balance += amount;
if (lockedToken.unlockTime < unlockTime) {
lockedToken.unlockTime = unlockTime;
}
} else {
holders[withdrawer].tokens[token] = Token(
amount,
token,
unlockTime
);
}
IERC20(token).transferFrom(withdrawer, address(this), amount);
emit Hold(withdrawer, token, amount, unlockTime);
}
function withdraw(address token) public {
holder storage holder0 = holders[msg.sender];
require(
msg.sender == holder0.holderAddress,
"Only available to the token owner."
);
require(
block.timestamp > holder0.tokens[token].unlockTime,
"Unlock time not reached yet."
);
uint256 amount = holder0.tokens[token].balance;
holder0.tokens[token].balance = 0;
IERC20(token).transfer(msg.sender, amount);
emit Withdrawal(msg.sender, token, amount);
}
function panicWithdraw(address token) public {
holder storage holder0 = holders[msg.sender];
require(
msg.sender == holder0.holderAddress,
"Only available to the token owner."
);
uint256 feeAmount = (holder0.tokens[token].balance / 100) * penaltyfee;
uint256 withdrawalAmount = holder0.tokens[token].balance - feeAmount;
holder0.tokens[token].balance = 0;
//Transfers fees to the contract administrator/owner
// holders[address(owner)].tokens[token].balance = feeAmount;
// Transfers fees to the token owner
IERC20(token).transfer(msg.sender, withdrawalAmount);
// Transfers fees to the contract administrator/owner
IERC20(token).transfer(owner, feeAmount);
emit PanicWithdraw(
msg.sender,
token,
withdrawalAmount,
holder0.tokens[token].unlockTime
);
}
// function claimTokenListFees(address[] memory tokenList) public onlyOwner {
// for (uint256 i = 0; i < tokenList.length; i++) {
// uint256 amount = holders[owner].tokens[tokenList[i]].balance;
// if (amount > 0) {
// holders[owner].tokens[tokenList[i]].balance = 0;
// IERC20(tokenList[i]).transfer(owner, amount);
// }
// }
// emit FeesClaimed();
// }
// function claimTokenFees(address token) public onlyOwner {
// uint256 amount = holders[owner].tokens[token].balance;
// require(amount > 0, "No fees available for claiming.");
// holders[owner].tokens[token].balance = 0;
// IERC20(token).transfer(owner, amount);
// emit FeesClaimed();
// }
function OwnerWithdraw() public onlyOwner {
uint256 amount = address(this).balance;
address payable ownerAddress = payable(owner);
ownerAddress.transfer(amount);
emit OwnerWithdrawSuccess(amount);
}
function getcurtime() public view returns (uint256) {
return block.timestamp;
}
function GetBalance(address token) public view returns (uint256) {
Token storage lockedToken = holders[msg.sender].tokens[token];
return lockedToken.balance;
}
function SetOwner(address contractowner) public onlyOwner {
owner = contractowner;
emit SetOwnerSuccess(owner);
}
function SetPrice(uint256 _price) public onlyOwner {
price = _price;
emit SetPriceSuccess(price);
}
// function GetPrice() public view returns (uint256) {
// return price;
// }
function SetPenaltyFee(uint256 _penaltyfee) public onlyOwner {
penaltyfee = _penaltyfee;
emit SetPenaltyFeeSuccess(penaltyfee);
}
// function GetPenaltyFee() public view returns (uint256) {
// return penaltyfee;
// }
function GetUnlockTime(address token) public view returns (uint256) {
Token storage lockedToken = holders[msg.sender].tokens[token];
return lockedToken.unlockTime;
}
}
contracts/Presale/Meter/Presale.sol
// SPDX-License-Identifier: UNLICENSED
// @Credits Defi Site Network 2021
// Presale contract. Version 1
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../../interfaces/IWETH.sol";
import "../TransferHelper.sol";
import "./SharedStructs.sol";
import "./PresaleLockForwarder.sol";
import "../PresaleSettings.sol";
contract PresaleV1 is ReentrancyGuard {
/// @notice Presale Contract Version, used to choose the correct ABI to decode the contract
// uint256 public contract_version = 1;
struct PresaleFeeInfo {
uint256 raised_fee; // divided by 100
uint256 sold_fee; // divided by 100
uint256 referral_fee; // divided by 100
address payable raise_fee_address;
address payable sole_fee_address;
address payable referral_fee_address; // if this is not address(0), there is a valid referral
}
struct PresaleStatus {
bool lp_generation_complete; // final flag required to end a presale and enable withdrawls
bool force_failed; // set this flag to force fail the presale
uint256 raised_amount; // total base currency raised (usually ETH)
uint256 sold_amount; // total presale tokens sold
uint256 token_withdraw; // total tokens withdrawn post successful presale
uint256 base_withdraw; // total base tokens withdrawn on presale failure
uint256 num_buyers; // number of unique participants
}
struct BuyerInfo {
uint256 base; // total base token (usually ETH) deposited by user, can be withdrawn on presale failure
uint256 sale; // num presale tokens a user is owed, can be withdrawn on presale success
}
struct TokenInfo {
string name;
string symbol;
uint256 totalsupply;
uint256 decimal;
}
SharedStructs.PresaleInfo public presale_info;
PresaleStatus public status;
SharedStructs.PresaleLink public link;
PresaleFeeInfo public presale_fee_info;
TokenInfo public tokeninfo;
address manage_addr;
// IUniswapV2Factory public uniswapfactory;
IWETH private WETH;
PresaleSettings public presale_setting;
PresaleLockForwarder public presale_lock_forwarder;
mapping(address => BuyerInfo) public buyers;
event UserDepsitedSuccess(address, uint256);
event UserWithdrawSuccess(uint256);
event UserWithdrawTokensSuccess(uint256);
event AddLiquidtySuccess(uint256);
constructor(
address manage,
address wethfact,
address setting,
address lockaddr
) payable {
presale_setting = PresaleSettings(setting);
require(
msg.value >= presale_setting.getLockFee(),
"Balance is insufficent"
);
manage_addr = manage;
// uniswapfactory = IUniswapV2Factory(uniswapfact);
WETH = IWETH(wethfact);
presale_lock_forwarder = PresaleLockForwarder(lockaddr);
}
function init_private(SharedStructs.PresaleInfo memory _presale_info)
external
{
require(msg.sender == manage_addr, "Only manage address is available");
presale_info = _presale_info;
//Set token token info
tokeninfo.name = IERC20Metadata(_presale_info.sale_token).name();
tokeninfo.symbol = IERC20Metadata(_presale_info.sale_token).symbol();
tokeninfo.decimal = IERC20Metadata(_presale_info.sale_token).decimals();
tokeninfo.totalsupply = IERC20Metadata(_presale_info.sale_token)
.totalSupply();
}
function init_link(SharedStructs.PresaleLink memory _link) external {
require(msg.sender == manage_addr, "Only manage address is available");
link = _link;
}
function init_fee() external {
require(msg.sender == manage_addr, "Only manage address is available");
presale_fee_info.raised_fee = presale_setting.getRasiedFee(); // divided by 100
presale_fee_info.sold_fee = presale_setting.getSoldFee(); // divided by 100
presale_fee_info.referral_fee = presale_setting.getRefferralFee(); // divided by 100
presale_fee_info.raise_fee_address = presale_setting
.getRaisedFeeAddress();
presale_fee_info.sole_fee_address = presale_setting.getSoleFeeAddress();
presale_fee_info.referral_fee_address = presale_setting
.getReferralFeeAddress(); // if this is not address(0), there is a valid referral
}
modifier onlyPresaleOwner() {
require(presale_info.presale_owner == msg.sender, "NOT PRESALE OWNER");
_;
}
// uint256 tempstatus;
// function setTempStatus(uint256 flag) public {
// tempstatus = flag;
// }
function presaleStatus() public view returns (uint256) {
// return tempstatus;
if (status.force_failed) {
return 3; // FAILED - force fail
}
if (
(block.timestamp > presale_info.presale_end) &&
(status.raised_amount < presale_info.softcap)
) {
return 3;
}
if (status.raised_amount >= presale_info.hardcap) {
return 2; // SUCCESS - hardcap met
}
if (
(block.timestamp > presale_info.presale_end) &&
(status.raised_amount >= presale_info.softcap)
) {
return 2; // SUCCESS - preslae end and soft cap reached
}
if (
(block.timestamp >= presale_info.presale_start) &&
(block.timestamp <= presale_info.presale_end)
) {
return 1; // ACTIVE - deposits enabled
}
return 0; // QUED - awaiting start block
}
// accepts msg.value for eth or _amount for ERC20 tokens
function userDeposit() public payable nonReentrant {
require(presaleStatus() == 1, "NOT ACTIVE"); //
require(presale_info.raise_min <= msg.value, "balance is insufficent");
require(presale_info.raise_max >= msg.value, "balance is too much");
BuyerInfo storage buyer = buyers[msg.sender];
uint256 amount_in = msg.value;
uint256 allowance = presale_info.raise_max - buyer.base;
uint256 remaining = presale_info.hardcap - status.raised_amount;
allowance = allowance > remaining ? remaining : allowance;
if (amount_in > allowance) {
amount_in = allowance;
}
uint256 tokensSold = (amount_in * presale_info.token_rate) / (10**18);
require(tokensSold > 0, "ZERO TOKENS");
require(
tokensSold <=
IERC20(presale_info.sale_token).balanceOf(address(this)),
"Token reamin error"
);
if (buyer.base == 0) {
status.num_buyers++;
}
buyers[msg.sender].base = buyers[msg.sender].base + amount_in;
buyers[msg.sender].sale = buyers[msg.sender].sale + tokensSold;
status.raised_amount = status.raised_amount + amount_in;
status.sold_amount = status.sold_amount + tokensSold;
// return unused ETH
if (amount_in < msg.value) {
payable(msg.sender).transfer(msg.value - amount_in);
}
emit UserDepsitedSuccess(msg.sender, msg.value);
}
// withdraw presale tokens
// percentile withdrawls allows fee on transfer or rebasing tokens to still work
function userWithdrawTokens() public nonReentrant {
require(status.lp_generation_complete, "AWAITING LP GENERATION");
BuyerInfo storage buyer = buyers[msg.sender];
uint256 tokensRemainingDenominator = status.sold_amount -
status.token_withdraw;
uint256 tokensOwed = (IERC20(presale_info.sale_token).balanceOf(
address(this)
) * buyer.sale) / tokensRemainingDenominator;
require(tokensOwed > 0, "NOTHING TO WITHDRAW");
status.token_withdraw = status.token_withdraw + buyer.sale;
buyers[msg.sender].sale = 0;
buyers[msg.sender].base = 0;
TransferHelper.safeTransfer(
address(presale_info.sale_token),
msg.sender,
tokensOwed
);
emit UserWithdrawTokensSuccess(tokensOwed);
}
// on presale failure
// percentile withdrawls allows fee on transfer or rebasing tokens to still work
function userWithdrawBaseTokens() public nonReentrant {
require(presaleStatus() == 3, "NOT FAILED"); // FAILED
if (msg.sender == presale_info.presale_owner) {
ownerWithdrawTokens();
// return;
}
BuyerInfo storage buyer = buyers[msg.sender];
uint256 baseRemainingDenominator = status.raised_amount -
status.base_withdraw;
uint256 remainingBaseBalance = address(this).balance;
uint256 tokensOwed = (remainingBaseBalance * buyer.base) /
baseRemainingDenominator;
require(tokensOwed > 0, "NOTHING TO WITHDRAW");
status.base_withdraw = status.base_withdraw + buyer.base;
buyer.base = 0;
buyer.sale = 0;
address payable reciver = payable(msg.sender);
reciver.transfer(tokensOwed);
emit UserWithdrawSuccess(tokensOwed);
// TransferHelper.safeTransferBaseToken(address(presale_info.base_token), msg.sender, tokensOwed, false);
}
// on presale failure
// allows the owner to withdraw the tokens they sent for presale & initial liquidity
function ownerWithdrawTokens() private onlyPresaleOwner {
require(presaleStatus() == 3, "Only failed status"); // FAILED
TransferHelper.safeTransfer(
address(presale_info.sale_token),
presale_info.presale_owner,
IERC20(presale_info.sale_token).balanceOf(address(this))
);
emit UserWithdrawSuccess(
IERC20(presale_info.sale_token).balanceOf(address(this))
);
}
// Can be called at any stage before or during the presale to cancel it before it ends.
// If the pair already exists on uniswap and it contains the presale token as liquidity
// the final stage of the presale 'addLiquidity()' will fail. This function
// allows anyone to end the presale prematurely to release funds in such a case.
function forceFailIfPairExists() public {
require(!status.lp_generation_complete && !status.force_failed);
if (
presale_lock_forwarder.uniswapPairIsInitialised(
address(presale_info.sale_token),
address(WETH)
)
) {
status.force_failed = true;
}
}
// if something goes wrong in LP generation
// function forceFail () external {
// require(msg.sender == OCTOFI_FEE_ADDRESS);
// status.force_failed = true;
// }
// on presale success, this is the final step to end the presale, lock liquidity and enable withdrawls of the sale token.
// This function does not use percentile distribution. Rebasing mechanisms, fee on transfers, or any deflationary logic
// are not taken into account at this stage to ensure stated liquidity is locked and the pool is initialised according to
// the presale parameters and fixed prices.
function addLiquidity() public nonReentrant onlyPresaleOwner {
require(!status.lp_generation_complete, "GENERATION COMPLETE");
require(presaleStatus() == 2, "NOT SUCCESS"); // SUCCESS
// Fail the presale if the pair exists and contains presale token liquidity
if (
presale_lock_forwarder.uniswapPairIsInitialised(
address(presale_info.sale_token),
address(WETH)
)
) {
status.force_failed = true;
emit AddLiquidtySuccess(0);
return;
}
// require(!presale_lock_forwarder.uniswapPairIsInitialised(address(presale_info.sale_token), address(WETH)), "Liqudity exist");
uint256 presale_raisedfee = (status.raised_amount *
presale_setting.getRasiedFee()) / 100;
// base token liquidity
uint256 baseLiquidity = ((status.raised_amount - presale_raisedfee) *
(presale_info.liqudity_percent)) / 100;
// WETH.deposit{value : baseLiquidity}();
// require(WETH.approve(address(presale_lock_forwarder), baseLiquidity), 'approve failed.');
// TransferHelper.safeApprove(address(presale_info.base_token), address(presale_lock_forwarder), baseLiquidity);
// sale token liquidity
uint256 tokenLiquidity = (baseLiquidity * presale_info.listing_rate) /
(10**18);
require(tokenLiquidity > 0, "ZERO Tokens");
TransferHelper.safeApprove(
address(presale_info.sale_token),
address(presale_lock_forwarder),
tokenLiquidity
);
presale_lock_forwarder.lockLiquidity{
value: presale_setting.getLockFee() + baseLiquidity
}(
address(presale_info.sale_token),
baseLiquidity,
tokenLiquidity,
presale_info.lock_end,
presale_info.presale_owner
);
uint256 presaleSoldFee = (status.sold_amount *
presale_setting.getSoldFee()) / 100;
address payable reciver = payable(
address(presale_fee_info.raise_fee_address)
);
reciver.transfer(presale_raisedfee);
// TransferHelper.safeTransferBaseToken(address(presale_info.base_token), presale_fee_info.raise_fee_address, presale_raisedfee, false);
TransferHelper.safeTransfer(
address(presale_info.sale_token),
presale_fee_info.sole_fee_address,
presaleSoldFee
);
// burn unsold tokens
uint256 remainingSBalance = IERC20(presale_info.sale_token).balanceOf(
address(this)
);
if (remainingSBalance > status.sold_amount) {
uint256 burnAmount = remainingSBalance - status.sold_amount;
TransferHelper.safeTransfer(
address(presale_info.sale_token),
0x000000000000000000000000000000000000dEaD,
burnAmount
);
}
// send remaining base tokens to presale owner
uint256 remainingBaseBalance = address(this).balance;
address payable presale_fee_reciver = payable(
address(presale_info.presale_owner)
);
presale_fee_reciver.transfer(remainingBaseBalance);
status.lp_generation_complete = true;
emit AddLiquidtySuccess(1);
}
function destroy() public {
require(status.lp_generation_complete, "lp generation incomplete");
selfdestruct(presale_info.presale_owner);
}
// function getTokenNmae() public view returns (string memory) {
// return presale_info.sale_token.name();
// }
// function getTokenSymbol() public view returns (string memory) {
// return presale_info.sale_token.symbol();
// }
}
contracts/Presale/Meter/PresaleFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Presale.sol";
contract PresaleFactory {
function deploy(
address manage,
address wethfact,
address setting,
address lockaddr
) external payable returns (PresaleV1) {
return
(new PresaleV1){value: msg.value}(
manage,
wethfact,
setting,
lockaddr
);
}
}
contracts/Presale/Meter/PresaleLockForwarder.sol
// SPDX-License-Identifier: UNLICENSED
// @Credits Unicrypt Network 2021
/**
This contract creates the lock on behalf of each presale. This contract will be whitelisted to bypass the flat rate
ETH fee. Please do not use the below locking code in your own contracts as the lock will fail without the ETH fee
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./PresaleManage.sol";
import "../../interfaces/IWETH.sol";
import "../../interfaces/IUniswapV2Factory.sol";
import "../../interfaces/IUniswapV2Router02.sol";
import "../../interfaces/IUniswapV2Pair.sol";
import "../../LiquidityLock/LPLock.sol";
import "../TransferHelper.sol";
contract PresaleLockForwarder {
LPLocker public lplocker;
IUniswapV2Factory public uniswapfactory;
IUniswapV2Router02 public uniswaprouter;
PresaleManage manage;
IWETH public WETH;
mapping(address => address) public locked_lp_tokens;
mapping(address => address) public locked_lp_owner;
constructor(
address _manage,
address lplock_addrress,
address unifactaddr,
address unirouter,
address wethaddr
) public {
lplocker = LPLocker(lplock_addrress);
uniswapfactory = IUniswapV2Factory(unifactaddr);
uniswaprouter = IUniswapV2Router02(unirouter);
WETH = IWETH(wethaddr);
manage = PresaleManage(_manage);
}
/**
Send in _token0 as the PRESALE token, _token1 as the BASE token (usually WETH) for the check to work. As anyone can create a pair,
and send WETH to it while a presale is running, but no one should have access to the presale token. If they do and they send it to
the pair, scewing the initial liquidity, this function will return true
*/
function uniswapPairIsInitialised(address _token0, address _token1)
public
view
returns (bool)
{
address pairAddress = uniswapfactory.getPair(_token0, _token1);
if (pairAddress == address(0)) {
return false;
}
uint256 balance = IERC20(_token0).balanceOf(pairAddress);
if (balance > 0) {
return true;
}
return false;
}
// function lockLiquidity (IERC20 _saleToken, uint256 _unlock_date, address payable _withdrawer) payable external {
// require(msg.value >= lplocker.price(), 'Balance is insufficient');
// address pair = uniswapfactory.getPair(address(WETH), address(_saleToken));
// uint256 totalLPTokensMinted = IUniswapV2Pair(pair).balanceOf(address(this));
// require(totalLPTokensMinted != 0 , "LP creation failed");
// TransferHelper.safeApprove(pair, address(lplocker), totalLPTokensMinted);
// uint256 unlock_date = _unlock_date > 9999999999 ? 9999999999 : _unlock_date;
// lplocker.lpLock{value:lplocker.price()}(pair, totalLPTokensMinted, unlock_date, _withdrawer );
// lptokens[msg.sender] = pair;
// }
function lockLiquidity(
address _saleToken,
uint256 _baseAmount,
uint256 _saleAmount,
uint256 _unlock_date,
address payable _withdrawer
) external payable {
require(manage.IsRegistered(msg.sender), "PRESALE NOT REGISTERED");
require(
msg.value >= lplocker.price() + _baseAmount,
"Balance is insufficient"
);
// if (pair == address(0)) {
// uniswapfactory.createPair(address(WETH), address(_saleToken));
// pair = uniswapfactory.getPair(address(WETH), address(_saleToken));
// }
// require(WETH.transferFrom(msg.sender, address(this), _baseAmount), 'WETH transfer failed.');
// TransferHelper.safeTransferFrom(address(_baseToken), msg.sender, address(pair), _baseAmount);
TransferHelper.safeTransferFrom(
address(_saleToken),
msg.sender,
address(this),
_saleAmount
);
// IUniswapV2Pair(pair).mint(address(this));
// return;
// require(WETH.approve(address(uniswaprouter), _baseAmount), 'router approve failed.');
// _saleToken.approve(address(uniswaprouter), _saleAmount);
TransferHelper.safeApprove(
address(_saleToken),
address(uniswaprouter),
_saleAmount
);
// construct token path
// address[] memory path = new address[](2);
// path[0] = address(WETH);
// path[1] = address(_saleToken);
// IUniswapV2Router02(uniswaprouter).swapExactTokensForTokens(
// WETH.balanceOf(address(this)).div(2),
// 0,
// path,
// address(this),
// block.timestamp + 5 minutes
// );
// // calculate balances and add liquidity
// uint256 wethBalance = WETH.balanceOf(address(this));
// uint256 balance = _saleToken.balanceOf(address(this));
// IUniswapV2Router02(uniswaprouter).addLiquidity(
// address(_saleToken),
// address(WETH),
// balance,
// wethBalance,
// 0,
// 0,
// address(this),
// block.timestamp + 5 minutes
// );
IUniswapV2Router02(address(uniswaprouter)).addLiquidityETH{
value: _baseAmount
}(
address(_saleToken),
_saleAmount,
0,
0,
payable(address(this)),
block.timestamp + 5 minutes
);
address pair = uniswapfactory.getPair(
address(WETH),
address(_saleToken)
);
uint256 totalLPTokensMinted = IUniswapV2Pair(pair).balanceOf(
address(this)
);
require(totalLPTokensMinted != 0, "LP creation failed");
TransferHelper.safeApprove(
pair,
address(lplocker),
totalLPTokensMinted
);
uint256 unlock_date = _unlock_date > 9999999999
? 9999999999
: _unlock_date;
lplocker.lpLock{value: lplocker.price()}(
pair,
totalLPTokensMinted,
unlock_date,
_withdrawer
);
locked_lp_tokens[address(_saleToken)] = pair;
locked_lp_owner[address(_saleToken)] = _withdrawer;
payable(_withdrawer).transfer(address(this).balance);
}
}
contracts/Presale/Meter/SharedStructs.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library SharedStructs {
struct PresaleInfo {
address payable presale_owner;
address sale_token; // sale token
uint256 token_rate; // 1 base token = ? s_tokens, fixed price
uint256 raise_min; // maximum base token BUY amount per buyer
uint256 raise_max; // the amount of presale tokens up for presale
uint256 hardcap; // Maximum riase amount
uint256 softcap; //Minimum raise amount
uint256 liqudity_percent; // divided by 1000
uint256 listing_rate; // fixed rate at which the token will list on uniswap
uint256 lock_end; // uniswap lock timestamp -> e.g. 2 weeks
uint256 lock_start;
uint256 presale_end; // presale period
uint256 presale_start; // presale start
}
struct PresaleLink {
string website_link;
string github_link;
string twitter_link;
string reddit_link;
string telegram_link;
}
}
contracts/Presale/PresaleSettings.sol
// SPDX-License-Identifier: UNLICENSED
// @Credits Unicrypt Network 2021
// Settings to initialize presale contracts and edit fees.
pragma solidity ^0.8.0;
interface ILpLocker {
function price() external pure returns (uint256);
}
contract PresaleSettings {
address private owner;
address private manage;
ILpLocker locker;
struct SettingsInfo {
uint256 raised_fee; // divided by 100
uint256 sold_fee; // divided by 100
uint256 referral_fee; // divided by 100
uint256 presale_create_fee; // divided by 100
address payable raise_fee_address;
address payable sole_fee_address;
address payable referral_fee_address; // if this is not address(0), there is a valid referral
address payable create_fee_address; // if this is not address(0), there is a valid referral
}
SettingsInfo public info;
modifier onlyOwner() {
require(owner == msg.sender, "Ownable: caller is not the owner");
_;
}
modifier onlyManager() {
require(manage == msg.sender, "Ownable: caller is not the manager");
_;
}
event setRaiseFeeAddrSuccess(address indexed addr);
event setRaisedFeeSuccess(uint256 num);
event setSoleFeeAddrSuccess(address indexed addr);
event setSoldFeeSuccess(uint256 num);
event setReferralFeeAddrSuccess(address addr);
event setReferralFeeSuccess(uint256 num);
event setCreateFeeAddrSuccess(address addr);
event setCreateFeeSuccess(uint256 num);
event setFeeInfoSuccess(uint256);
constructor(
address _manage,
address _owner,
address lockaddr
) public {
owner = _owner;
manage = _manage;
locker = ILpLocker(lockaddr);
}
function init(
address payable _presale_create_fee_addr,
uint256 _presale_create_fee,
address payable _raise_fee_addr,
uint256 _raised_fee,
address payable _sole_fee_address,
uint256 _sold_fee,
address payable _referral_fee_address,
uint256 _referral_fee
) public onlyManager {
info.presale_create_fee = _presale_create_fee;
info.raise_fee_address = _raise_fee_addr;
info.raised_fee = _raised_fee;
info.sole_fee_address = _sole_fee_address;
info.sold_fee = _sold_fee;
info.referral_fee_address = _referral_fee_address;
info.referral_fee = _referral_fee;
info.create_fee_address = _presale_create_fee_addr;
}
function getRaisedFeeAddress()
external
view
returns (address payable _raise_fee_addr)
{
return info.raise_fee_address;
}
function setRaisedFeeAddress(address payable _raised_fee_addr)
external
onlyOwner
{
info.raise_fee_address = _raised_fee_addr;
emit setRaiseFeeAddrSuccess(info.raise_fee_address);
}
function getRasiedFee() external view returns (uint256) {
return info.raised_fee;
}
function setRaisedFee(uint256 _raised_fee) external onlyOwner {
info.raised_fee = _raised_fee;
emit setRaisedFeeSuccess(info.raised_fee);
}
function getSoleFeeAddress()
external
view
returns (address payable _sole_fee_address)
{
return info.sole_fee_address;
}
function setSoleFeeAddress(address payable _sole_fee_address)
external
onlyOwner
{
info.sole_fee_address = _sole_fee_address;
emit setSoleFeeAddrSuccess(info.sole_fee_address);
}
function getSoldFee() external view returns (uint256) {
return info.sold_fee;
}
function setSoldFee(uint256 _sold_fee) external onlyOwner {
info.sold_fee = _sold_fee;
emit setSoldFeeSuccess(info.sold_fee);
}
function getReferralFeeAddress() external view returns (address payable) {
return info.referral_fee_address;
}
function setReferralFeeAddress(address payable _referral_fee_address)
external
onlyOwner
{
info.sole_fee_address = _referral_fee_address;
emit setReferralFeeAddrSuccess(info.referral_fee_address);
}
function getRefferralFee() external view returns (uint256) {
return info.referral_fee;
}
function setRefferralFee(uint256 _referral_fee) external onlyOwner {
info.referral_fee = _referral_fee;
emit setReferralFeeSuccess(info.referral_fee);
}
function getLockFee() external view returns (uint256) {
return locker.price();
}
function getPresaleCreateFee() external view returns (uint256) {
return info.presale_create_fee;
}
function setSetPresaleCreateFee(uint256 _presale_create_fee)
external
onlyOwner
{
info.presale_create_fee = _presale_create_fee;
emit setCreateFeeSuccess(info.presale_create_fee);
}
function getCreateFeeAddress() external view returns (address payable) {
return info.create_fee_address;
}
function setCreateFeeAddress(address payable _create_fee_address)
external
onlyOwner
{
info.create_fee_address = _create_fee_address;
emit setReferralFeeAddrSuccess(info.create_fee_address);
}
function setFeeInfo(
address payable _create_address,
address payable _raise_address,
address payable _sold_address,
uint256 _create_fee,
uint256 _raise_fee,
uint256 _sold_fee
) external onlyOwner {
info.create_fee_address = _create_address;
info.raise_fee_address = _raise_address;
info.sole_fee_address = _sold_address;
info.presale_create_fee = _create_fee;
info.raised_fee = _raise_fee;
info.sold_fee = _sold_fee;
emit setFeeInfoSuccess(1);
}
}
contracts/Presale/TransferHelper.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
helper methods for interacting with ERC20 tokens that do not consistently return true/false
with the addition of a transfer function to send eth or an erc20 token
*/
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x095ea7b3, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper: APPROVE_FAILED"
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0xa9059cbb, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper: TRANSFER_FAILED"
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x23b872dd, from, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper: TRANSFER_FROM_FAILED"
);
}
// sends ETH or an erc20 token
function safeTransferBaseToken(
address token,
address payable to,
uint256 value,
bool isERC20
) internal {
if (!isERC20) {
to.transfer(value);
} else {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0xa9059cbb, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper: TRANSFER_FAILED"
);
}
}
}
contracts/interfaces/IUniswapV2Factory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapV2Factory {
event PairCreated(
address indexed token0,
address indexed token1,
address pair,
uint256
);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB)
external
view
returns (address pair);
function allPairs(uint256) external view returns (address pair);
function allPairsLength() external view returns (uint256);
function createPair(address tokenA, address tokenB)
external
returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
contracts/interfaces/IUniswapV2Pair.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapV2Pair {
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
event Transfer(address indexed from, address indexed to, uint256 value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function allowance(address owner, address spender)
external
view
returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint256);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
event Burn(
address indexed sender,
uint256 amount0,
uint256 amount1,
address indexed to
);
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint256);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
);
function price0CumulativeLast() external view returns (uint256);
function price1CumulativeLast() external view returns (uint256);
function kLast() external view returns (uint256);
function burn(address to)
external
returns (uint256 amount0, uint256 amount1);
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","devdoc","userdoc","storageLayout","evm.gasEstimates"],"":["ast"]}},"optimizer":{"runs":5000,"enabled":true},"metadata":{"useLiteralContent":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_owner","internalType":"address payable"},{"type":"address","name":"lock_addr","internalType":"address"},{"type":"address","name":"uniswapfactory_addr","internalType":"address"},{"type":"address","name":"uniswaprouter_Addr","internalType":"address"},{"type":"address","name":"weth_addr","internalType":"address"},{"type":"address","name":"_presaleFactory","internalType":"contract PresaleFactory"}]},{"type":"event","name":"CreatePreslaeSuccess","inputs":[{"type":"address","name":"","internalType":"address","indexed":false},{"type":"address","name":"","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"OwnerWithdrawSuccess","inputs":[{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"IsRegistered","inputs":[{"type":"address","name":"presale_addr","internalType":"address"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calculateAmountRequired","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"uint256","name":"_tokenPrice","internalType":"uint256"},{"type":"uint256","name":"_listingRate","internalType":"uint256"},{"type":"uint256","name":"_liquidityPercent","internalType":"uint256"},{"type":"uint256","name":"_tokenFee","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createPresale","inputs":[{"type":"tuple","name":"_presale_info","internalType":"struct SharedStructs.PresaleInfo","components":[{"type":"address","name":"presale_owner","internalType":"address payable"},{"type":"address","name":"sale_token","internalType":"address"},{"type":"uint256","name":"token_rate","internalType":"uint256"},{"type":"uint256","name":"raise_min","internalType":"uint256"},{"type":"uint256","name":"raise_max","internalType":"uint256"},{"type":"uint256","name":"hardcap","internalType":"uint256"},{"type":"uint256","name":"softcap","internalType":"uint256"},{"type":"uint256","name":"liqudity_percent","internalType":"uint256"},{"type":"uint256","name":"listing_rate","internalType":"uint256"},{"type":"uint256","name":"lock_end","internalType":"uint256"},{"type":"uint256","name":"lock_start","internalType":"uint256"},{"type":"uint256","name":"presale_end","internalType":"uint256"},{"type":"uint256","name":"presale_start","internalType":"uint256"}]},{"type":"tuple","name":"_presalelink","internalType":"struct SharedStructs.PresaleLink","components":[{"type":"string","name":"website_link","internalType":"string"},{"type":"string","name":"github_link","internalType":"string"},{"type":"string","name":"twitter_link","internalType":"string"},{"type":"string","name":"reddit_link","internalType":"string"},{"type":"string","name":"telegram_link","internalType":"string"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBalance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getPresaleAt","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"ownerWithdraw","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"presale_lock_forward_addr","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"presale_setting_addr","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract PresaleSettings"}],"name":"settings","inputs":[]}]
Contract Creation Code
0x60806040523480156200001157600080fd5b50604051620037bc380380620037bc833981016040819052620000349162000272565b600980546001600160a01b038089166001600160a01b0319928316179092556006805487841690831617905560088054928516929091169190911790556040513090869086908690869062000089906200023d565b6001600160a01b0395861681529385166020850152918416604084015283166060830152909116608082015260a001604051809103906000f080158015620000d5573d6000803e3d6000fd5b50600580546001600160a01b03929092166001600160a01b031992831681179091556003805490921617905560405160009030908890889062000118906200024b565b6001600160a01b03938416815291831660208301529091166040820152606001604051809103906000f08015801562000155573d6000803e3d6000fd5b50600954604051637e6117e960e11b81526001600160a01b0391821660048201819052662386f26fc10000602483015260448201819052600a606483018190526084830182905260a4830181905260c483019190915260e482015291925082169063fcc22fd29061010401600060405180830381600087803b158015620001db57600080fd5b505af1158015620001f0573d6000803e3d6000fd5b5050600480546001600160a01b039485166001600160a01b03199182168117909255601c805482169092179091556002805495909416941693909317909155506200030695505050505050565b610f828062001ad283390190565b610d688062002a5483390190565b6001600160a01b03811681146200026f57600080fd5b50565b60008060008060008060c087890312156200028c57600080fd5b8651620002998162000259565b6020880151909650620002ac8162000259565b6040880151909550620002bf8162000259565b6060880151909450620002d28162000259565b6080880151909350620002e58162000259565b60a0880151909250620002f88162000259565b809150509295509295509295565b6117bc80620003166000396000f3fe6080604052600436106100b15760003560e01c8063a725976711610069578063b014afb31161004e578063b014afb3146101a0578063c224122d146101b3578063e06174e4146101e357600080fd5b8063a72597671461016b578063a87d942c1461018b57600080fd5b806312065fe01161009a57806312065fe0146101215780634311de8f14610134578063a00d16961461014b57600080fd5b8063108a67a6146100b65780631185168a146100f3575b600080fd5b3480156100c257600080fd5b506003546100d6906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ff57600080fd5b5061011361010e3660046110a9565b610203565b6040519081526020016100ea565b34801561012d57600080fd5b5047610113565b34801561014057600080fd5b506101496102be565b005b34801561015757600080fd5b506004546100d6906001600160a01b031681565b34801561017757600080fd5b506100d66101863660046110e4565b610490565b34801561019757600080fd5b506101136104a2565b6101496101ae36600461130c565b6104b3565b3480156101bf57600080fd5b506101d36101ce3660046113fb565b610dc0565b60405190151581526020016100ea565b3480156101ef57600080fd5b50601c546100d6906001600160a01b031681565b600080670de0b6b3a76400006102198789611447565b6102239190611484565b9050600086670de0b6b3a7640000606461023d878c611447565b6102479190611484565b6102519190611484565b61025b9190611447565b90506000670de0b6b3a7640000610272888b611447565b61027c9190611484565b90506000606461028c8884611447565b6102969190611484565b90506000836102a583876114bf565b6102af91906114bf565b9b9a5050505050505050505050565b601c60009054906101000a90046001600160a01b03166001600160a01b0316635a305ff86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610311573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033591906114d7565b6001600160a01b0316336001600160a01b03161461039a5760405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920637265617465722063616e2077697468647261770000000000000060448201526064015b60405180910390fd5b601c54604080517f5a305ff800000000000000000000000000000000000000000000000000000000815290516000926001600160a01b031691635a305ff89160048083019260209291908290030181865afa1580156103fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042191906114d7565b6040519091506001600160a01b038216904780156108fc02916000818181858888f19350505050158015610459573d6000803e3d6000fd5b506040514781527fc67a6e2c9e13b320d5ce7e24743ea93ba9261320310966dd6240569493690eff9060200160405180910390a150565b600061049c8183610dcc565b92915050565b60006104ae6000610ddf565b905090565b8151600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b0393841617909155602080850151600b805490931693169290921790556040830151600c556060830151600d556080830151600e5560a0830151600f5560c083015160105560e08301516011556101008301516012556101208301516013556101408301516014556101608301516015556101808301516016558151805183926017926105779284929190910190611010565b5060208281015180516105909260018501920190611010565b50604082015180516105ac916002840191602090910190611010565b50606082015180516105c8916003840191602090910190611010565b50608082015180516105e4916004840191602090910190611010565b5050601c54604080517fdb28dbd100000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216925063db28dbd19160048083019260209291908290030181865afa158015610649573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066d91906114f4565b601c60009054906101000a90046001600160a01b03166001600160a01b0316632107c1016040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e491906114f4565b6106ee91906114bf565b34101561073d5760405162461bcd60e51b815260206004820152601660248201527f42616c616e636520697320696e737566666963656e74000000000000000000006044820152606401610391565b60008260400151116107915760405162461bcd60e51b815260206004820152601560248201527f746f6b656e207261746520697320696e76616c696400000000000000000000006044820152606401610391565b81608001518260600151106107e85760405162461bcd60e51b815260206004820152601860248201527f7261697365206d696e2f6d617820696e20696e76616c696400000000000000006044820152606401610391565b8160a001518260c0015111156108405760405162461bcd60e51b815260206004820152601a60248201527f736f66746361702f6861726463617020697320696e76616c69640000000000006044820152606401610391565b601e8260e001511015801561085a575060648260e0015111155b6108a65760405162461bcd60e51b815260206004820152601b60248201527f4c697175646974792070657263656e7420697320696e76616c696400000000006044820152606401610391565b6000826101000151116108fb5760405162461bcd60e51b815260206004820152601760248201527f4c697374696e67207261746520697320696e76616c69640000000000000000006044820152606401610391565b6000826101800151836101600151610913919061150d565b116109865760405162461bcd60e51b815260206004820152602160248201527f50726573616c652073746172742f656e642074696d6520697320696e76616c6960448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610391565b6224ea008261014001518361012001516109a0919061150d565b10156109ee5760405162461bcd60e51b815260206004820152601360248201527f4c6f636b20656e6420697320696e76616c6964000000000000000000000000006044820152606401610391565b6000610a7f8360a0015184604001518561010001518660e00151601c60009054906101000a90046001600160a01b03166001600160a01b0316636159ae596040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a5b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061010e91906114f4565b600254601c54604080517fdb28dbd100000000000000000000000000000000000000000000000000000000815290519394506000936001600160a01b039384169363fd82b73a93169163db28dbd19160048083019260209291908290030181865afa158015610af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1691906114f4565b6008546004805460035460405160e087901b7fffffffff0000000000000000000000000000000000000000000000000000000016815230938101939093526001600160a01b039384166024840152908316604483015291909116606482015260840160206040518083038185885af1158015610b96573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610bbb91906114d7565b90506001600160a01b038116610c135760405162461bcd60e51b815260206004820152601560248201527f4372656174652070726573616c65204661696c656400000000000000000000006044820152606401610391565b610c238460200151338385610de9565b6040517f3c6ec90f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821690633c6ec90f90610c68908790600401611524565b600060405180830381600087803b158015610c8257600080fd5b505af1158015610c96573d6000803e3d6000fd5b50506040517f87d512590000000000000000000000000000000000000000000000000000000081526001600160a01b03841692506387d512599150610cdf90869060040161162b565b600060405180830381600087803b158015610cf957600080fd5b505af1158015610d0d573d6000803e3d6000fd5b50505050806001600160a01b031663ac34c96d6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610d4c57600080fd5b505af1158015610d60573d6000803e3d6000fd5b50505050610d78816000610f6090919063ffffffff16565b50604080516001600160a01b03831681523360208201527f7ce97a7f0c83b2f9f5bd5df597d7052e608d181e21e81fe7fc9a1e7f38b48c29910160405180910390a150505050565b600061049c8183610f75565b6000610dd88383610f97565b9392505050565b600061049c825490565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691610e7b91906116c6565b6000604051808303816000865af19150503d8060008114610eb8576040519150601f19603f3d011682016040523d82523d6000602084013e610ebd565b606091505b5091509150818015610ee7575080511580610ee7575080806020019051810190610ee791906116e2565b610f585760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610391565b505050505050565b6000610dd8836001600160a01b038416610fc1565b6001600160a01b03811660009081526001830160205260408120541515610dd8565b6000826000018281548110610fae57610fae611704565b9060005260206000200154905092915050565b60008181526001830160205260408120546110085750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561049c565b50600061049c565b82805461101c90611733565b90600052602060002090601f01602090048101928261103e5760008555611084565b82601f1061105757805160ff1916838001178555611084565b82800160010185558215611084579182015b82811115611084578251825591602001919060010190611069565b50611090929150611094565b5090565b5b808211156110905760008155600101611095565b600080600080600060a086880312156110c157600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b6000602082840312156110f657600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171561114f5761114f6110fd565b60405290565b6040516101a0810167ffffffffffffffff8111828210171561114f5761114f6110fd565b6001600160a01b038116811461118e57600080fd5b50565b803561119c81611179565b919050565b600082601f8301126111b257600080fd5b813567ffffffffffffffff808211156111cd576111cd6110fd565b604051601f8301601f19908116603f011681019082821181831017156111f5576111f56110fd565b8160405283815286602085880101111561120e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060a0828403121561124057600080fd5b61124861112c565b9050813567ffffffffffffffff8082111561126257600080fd5b61126e858386016111a1565b8352602084013591508082111561128457600080fd5b611290858386016111a1565b602084015260408401359150808211156112a957600080fd5b6112b5858386016111a1565b604084015260608401359150808211156112ce57600080fd5b6112da858386016111a1565b606084015260808401359150808211156112f357600080fd5b50611300848285016111a1565b60808301525092915050565b6000808284036101c081121561132157600080fd5b6101a08082121561133157600080fd5b611339611155565b915061134485611191565b825261135260208601611191565b602083015260408581013590830152606080860135908301526080808601359083015260a0808601359083015260c0808601359083015260e080860135908301526101008086013590830152610120808601359083015261014080860135908301526101608086013590830152610180808601359083015290925083013567ffffffffffffffff8111156113e557600080fd5b6113f18582860161122e565b9150509250929050565b60006020828403121561140d57600080fd5b8135610dd881611179565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561147f5761147f611418565b500290565b6000826114ba577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600082198211156114d2576114d2611418565b500190565b6000602082840312156114e957600080fd5b8151610dd881611179565b60006020828403121561150657600080fd5b5051919050565b60008282101561151f5761151f611418565b500390565b81516001600160a01b031681526101a08101602083015161155060208401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151818401525061016080840151818401525061018080840151818401525092915050565b60005b838110156115ea5781810151838201526020016115d2565b838111156115f9576000848401525b50505050565b600081518084526116178160208601602086016115cf565b601f01601f19169290920160200192915050565b602081526000825160a0602084015261164760c08401826115ff565b90506020840151601f198085840301604086015261166583836115ff565b9250604086015191508085840301606086015261168283836115ff565b9250606086015191508085840301608086015261169f83836115ff565b925060808601519150808584030160a0860152506116bd82826115ff565b95945050505050565b600082516116d88184602087016115cf565b9190910192915050565b6000602082840312156116f457600080fd5b81518015158114610dd857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c9082168061174757607f821691505b602082108103611780577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b5091905056fea2646970667358221220958e01f8f533a950948772b5b4bce89288bec333340932f8aca80957cc1c827564736f6c634300080d0033608060405234801561001057600080fd5b50604051610f82380380610f8283398101604081905261002f916100af565b600080546001600160a01b03199081166001600160a01b039687161790915560018054821694861694909417909355600280548416928516929092179091556004805483169184169190911790556003805490911692909116919091179055610114565b80516001600160a01b03811681146100aa57600080fd5b919050565b600080600080600060a086880312156100c757600080fd5b6100d086610093565b94506100de60208701610093565b93506100ec60408701610093565b92506100fa60608701610093565b915061010860808701610093565b90509295509295909350565b610e5f806101236000396000f3fe60806040526004361061007b5760003560e01c8063ad5c46481161004e578063ad5c464814610122578063b2522e2e14610142578063de9d122d14610178578063f96a0d21146101ae57600080fd5b80632431ba73146100805780632c26fb02146100bd578063443603b6146100dd5780638d8c70bb146100f2575b600080fd5b34801561008c57600080fd5b506002546100a0906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100c957600080fd5b506001546100a0906001600160a01b031681565b6100f06100eb366004610c76565b6101ce565b005b3480156100fe57600080fd5b5061011261010d366004610ccc565b610816565b60405190151581526020016100b4565b34801561012e57600080fd5b506004546100a0906001600160a01b031681565b34801561014e57600080fd5b506100a061015d366004610d05565b6006602052600090815260409020546001600160a01b031681565b34801561018457600080fd5b506100a0610193366004610d05565b6005602052600090815260409020546001600160a01b031681565b3480156101ba57600080fd5b506000546100a0906001600160a01b031681565b6003546040517fc224122d0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b039091169063c224122d90602401602060405180830381865afa15801561022f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102539190610d29565b6102be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f50524553414c45204e4f5420524547495354455245440000000000000000000060448201526064015b60405180910390fd5b600054604080517fa035b1fe000000000000000000000000000000000000000000000000000000008152905186926001600160a01b03169163a035b1fe9160048083019260209291908290030181865afa158015610320573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103449190610d4b565b61034e9190610d64565b3410156103b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f42616c616e636520697320696e73756666696369656e7400000000000000000060448201526064016102b5565b6103c38533308661096a565b6002546103db9086906001600160a01b031685610afb565b6002546001600160a01b031663f305d719858786600080306103ff4261012c610d64565b60405160e089901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039687166004820152602481019590955260448501939093526064840191909152909216608482015260a481019190915260c40160606040518083038185885af1158015610484573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104a99190610da3565b5050600154600480546040517fe6a439050000000000000000000000000000000000000000000000000000000081526001600160a01b03918216928101929092528881166024830152600093509091169063e6a4390590604401602060405180830381865afa158015610520573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105449190610dd1565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156105a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cb9190610d4b565b905080600003610637576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4c50206372656174696f6e206661696c6564000000000000000000000000000060448201526064016102b5565b60005461064f9083906001600160a01b031683610afb565b60006402540be3ff8511610663578461066a565b6402540be3ff5b600054604080517fa035b1fe00000000000000000000000000000000000000000000000000000000815290519293506001600160a01b0390911691636610cc2091839163a035b1fe916004808201926020929091908290030181865afa1580156106d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106fc9190610d4b565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0380881660048301526024820187905260448201869052881660648201526084016000604051808303818588803b15801561076957600080fd5b505af115801561077d573d6000803e3d6000fd5b5050506001600160a01b03808b1660009081526005602090815260408083208054858b167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560069092528083208054948b16949092168417909155519193504780156108fc0293509190818181858888f1935050505015801561080b573d6000803e3d6000fd5b505050505050505050565b6001546040517fe6a439050000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301528381166024830152600092839291169063e6a4390590604401602060405180830381865afa158015610885573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a99190610dd1565b90506001600160a01b0381166108c3576000915050610964565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038281166004830152600091908616906370a0823190602401602060405180830381865afa158015610926573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094a9190610d4b565b9050801561095d57600192505050610964565b6000925050505b92915050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291516000928392908816916109fc9190610dee565b6000604051808303816000865af19150503d8060008114610a39576040519150601f19603f3d011682016040523d82523d6000602084013e610a3e565b606091505b5091509150818015610a68575080511580610a68575080806020019051810190610a689190610d29565b610af3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c45440000000000000000000000000000000000000000000000000000000060648201526084016102b5565b505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790529151600092839290871691610b859190610dee565b6000604051808303816000865af19150503d8060008114610bc2576040519150601f19603f3d011682016040523d82523d6000602084013e610bc7565b606091505b5091509150818015610bf1575080511580610bf1575080806020019051810190610bf19190610d29565b610c57576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5472616e7366657248656c7065723a20415050524f56455f4641494c4544000060448201526064016102b5565b5050505050565b6001600160a01b0381168114610c7357600080fd5b50565b600080600080600060a08688031215610c8e57600080fd5b8535610c9981610c5e565b94506020860135935060408601359250606086013591506080860135610cbe81610c5e565b809150509295509295909350565b60008060408385031215610cdf57600080fd5b8235610cea81610c5e565b91506020830135610cfa81610c5e565b809150509250929050565b600060208284031215610d1757600080fd5b8135610d2281610c5e565b9392505050565b600060208284031215610d3b57600080fd5b81518015158114610d2257600080fd5b600060208284031215610d5d57600080fd5b5051919050565b60008219821115610d9e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600080600060608486031215610db857600080fd5b8351925060208401519150604084015190509250925092565b600060208284031215610de357600080fd5b8151610d2281610c5e565b6000825160005b81811015610e0f5760208186018101518583015201610df5565b81811115610e1e576000828501525b50919091019291505056fea2646970667358221220fcaa47d1a6232b506fab43c836f8a1612496f5fe834dc55c171c253b07cab9ff64736f6c634300080d0033608060405234801561001057600080fd5b50604051610d68380380610d6883398101604081905261002f9161008b565b600080546001600160a01b03199081166001600160a01b0394851617909155600180548216948416949094179093556002805490931691161790556100ce565b80516001600160a01b038116811461008657600080fd5b919050565b6000806000606084860312156100a057600080fd5b6100a98461006f565b92506100b76020850161006f565b91506100c56040850161006f565b90509250925092565b610c8b806100dd6000396000f3fe608060405234801561001057600080fd5b506004361061016c5760003560e01c80637480ba7f116100cd578063b25b298f11610081578063fafd117111610066578063fafd117114610315578063fca19d2714610328578063fcc22fd21461033057600080fd5b8063b25b298f14610305578063db28dbd11461030d57600080fd5b806389b23cff116100b257806389b23cff146102ce578063a4f2fb58146102df578063afa5bd91146102f257600080fd5b80637480ba7f146102ac57806386c90a9f146102bd57600080fd5b80635a305ff8116101245780635ed88cc8116101095780635ed88cc81461027e5780636159ae59146102915780636843ac491461029957600080fd5b80635a305ff8146102465780635cec3a331461026b57600080fd5b80633b44ba27116101555780633b44ba271461020b5780633b5eff581461022057806348fd86811461023357600080fd5b80632107c10114610171578063370158ea14610188575b600080fd5b6006545b6040519081526020015b60405180910390f35b600354600454600554600654600754600854600954600a546101be97969594936001600160a01b03908116938116928116911688565b6040805198895260208901979097529587019490945260608601929092526001600160a01b03908116608086015290811660a085015290811660c08401521660e08201526101000161017f565b61021e610219366004610b27565b610343565b005b61021e61022e366004610b49565b610404565b61021e610241366004610ba8565b6104fe565b600a546001600160a01b03165b6040516001600160a01b03909116815260200161017f565b61021e610279366004610ba8565b610594565b61021e61028c366004610b27565b610623565b600454610175565b61021e6102a7366004610b27565b6106e3565b6007546001600160a01b0316610253565b6009546001600160a01b0316610253565b6008546001600160a01b0316610253565b61021e6102ed366004610ba8565b6107a9565b61021e610300366004610ba8565b610838565b600554610175565b6101756108c7565b61021e610323366004610b27565b610953565b600354610175565b61021e61033e366004610bc1565b610a0f565b6000546001600160a01b031633146103a25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b600780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f914c3dc0d36d367cfbf9c2d12b8ecbce32c53f61073b6786b731d626ca28cd1690600090a250565b6000546001600160a01b0316331461045e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610399565b600a80546001600160a01b038881167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255600780548884169083161790556008805492871692909116919091179055600683905560038290556004819055604051600181527f5b04e2909297afc4d97c5e73529a4c22bd078759a55cf46f4b6ff9b82f264fe29060200160405180910390a1505050505050565b6000546001600160a01b031633146105585760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610399565b60048190556040518181527fa85e85cd3258e19490ec75acd2bac57bbcd073866e3bf52a554d744f9b6ea430906020015b60405180910390a150565b6000546001600160a01b031633146105ee5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610399565b60068190556040518181527f1422ff3e1c021de75f6e67bd772dde2ca40e95cb2a377835d93cc55b0d353ced90602001610589565b6000546001600160a01b0316331461067d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610399565b600a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f2dce471c25dfcbd96624037a30e7e4f73e4ab05bd2c075c9408315de4cb8a0ce90602001610589565b6000546001600160a01b0316331461073d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610399565b600880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691909117909155600954604051911681527f2dce471c25dfcbd96624037a30e7e4f73e4ab05bd2c075c9408315de4cb8a0ce90602001610589565b6000546001600160a01b031633146108035760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610399565b60038190556040518181527f169df7c4f78e51723fa449c0f67297f01c285b0a209cbf5753a023c2d5dccf2590602001610589565b6000546001600160a01b031633146108925760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610399565b60058190556040518181527fa2e5a2568fd883a302b07f53b61680d293c18e9e05bd4efe55e346582df1940c90602001610589565b600254604080517fa035b1fe00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163a035b1fe9160048083019260209291908290030181865afa15801561092a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094e9190610c3c565b905090565b6000546001600160a01b031633146109ad5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610399565b600880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517fb7b4de15f8656e985c19351858b30725bdefae6318b15dbc4d9cf56ca193a1c990600090a250565b6001546001600160a01b03163314610a8f5760405162461bcd60e51b815260206004820152602260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206d616e616760448201527f65720000000000000000000000000000000000000000000000000000000000006064820152608401610399565b600696909655600780547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b039788161790915560039490945560088054851693861693909317909255600455600980548316918416919091179055600592909255600a80549092169216919091179055565b80356001600160a01b0381168114610b2257600080fd5b919050565b600060208284031215610b3957600080fd5b610b4282610b0b565b9392505050565b60008060008060008060c08789031215610b6257600080fd5b610b6b87610b0b565b9550610b7960208801610b0b565b9450610b8760408801610b0b565b9350606087013592506080870135915060a087013590509295509295509295565b600060208284031215610bba57600080fd5b5035919050565b600080600080600080600080610100898b031215610bde57600080fd5b610be789610b0b565b975060208901359650610bfc60408a01610b0b565b955060608901359450610c1160808a01610b0b565b935060a08901359250610c2660c08a01610b0b565b915060e089013590509295985092959890939650565b600060208284031215610c4e57600080fd5b505191905056fea26469706673582212206d4e06eb493d0173ee2ebeccca293eaa9c2a09a25b5b4e07b7ad0ad4c375a7f964736f6c634300080d00330000000000000000000000008df97eab2651e87a8a4080008ddabf6824c9f672000000000000000000000000dcefb3e8322bb3bae8f4355c97ac8aa189b57e5900000000000000000000000024fe5f1891a4c709db87842bc80516a1494cc32300000000000000000000000002232dabaffedfc136843c26d951dfe87ab00dca0000000000000000000000001336f973cbd16db4368655514395d0818a949c2c000000000000000000000000ed9a3d8a2f2549aaea2b7f40be0e246c8a4bc015
Deployed ByteCode
0x6080604052600436106100b15760003560e01c8063a725976711610069578063b014afb31161004e578063b014afb3146101a0578063c224122d146101b3578063e06174e4146101e357600080fd5b8063a72597671461016b578063a87d942c1461018b57600080fd5b806312065fe01161009a57806312065fe0146101215780634311de8f14610134578063a00d16961461014b57600080fd5b8063108a67a6146100b65780631185168a146100f3575b600080fd5b3480156100c257600080fd5b506003546100d6906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ff57600080fd5b5061011361010e3660046110a9565b610203565b6040519081526020016100ea565b34801561012d57600080fd5b5047610113565b34801561014057600080fd5b506101496102be565b005b34801561015757600080fd5b506004546100d6906001600160a01b031681565b34801561017757600080fd5b506100d66101863660046110e4565b610490565b34801561019757600080fd5b506101136104a2565b6101496101ae36600461130c565b6104b3565b3480156101bf57600080fd5b506101d36101ce3660046113fb565b610dc0565b60405190151581526020016100ea565b3480156101ef57600080fd5b50601c546100d6906001600160a01b031681565b600080670de0b6b3a76400006102198789611447565b6102239190611484565b9050600086670de0b6b3a7640000606461023d878c611447565b6102479190611484565b6102519190611484565b61025b9190611447565b90506000670de0b6b3a7640000610272888b611447565b61027c9190611484565b90506000606461028c8884611447565b6102969190611484565b90506000836102a583876114bf565b6102af91906114bf565b9b9a5050505050505050505050565b601c60009054906101000a90046001600160a01b03166001600160a01b0316635a305ff86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610311573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033591906114d7565b6001600160a01b0316336001600160a01b03161461039a5760405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920637265617465722063616e2077697468647261770000000000000060448201526064015b60405180910390fd5b601c54604080517f5a305ff800000000000000000000000000000000000000000000000000000000815290516000926001600160a01b031691635a305ff89160048083019260209291908290030181865afa1580156103fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042191906114d7565b6040519091506001600160a01b038216904780156108fc02916000818181858888f19350505050158015610459573d6000803e3d6000fd5b506040514781527fc67a6e2c9e13b320d5ce7e24743ea93ba9261320310966dd6240569493690eff9060200160405180910390a150565b600061049c8183610dcc565b92915050565b60006104ae6000610ddf565b905090565b8151600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b0393841617909155602080850151600b805490931693169290921790556040830151600c556060830151600d556080830151600e5560a0830151600f5560c083015160105560e08301516011556101008301516012556101208301516013556101408301516014556101608301516015556101808301516016558151805183926017926105779284929190910190611010565b5060208281015180516105909260018501920190611010565b50604082015180516105ac916002840191602090910190611010565b50606082015180516105c8916003840191602090910190611010565b50608082015180516105e4916004840191602090910190611010565b5050601c54604080517fdb28dbd100000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216925063db28dbd19160048083019260209291908290030181865afa158015610649573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066d91906114f4565b601c60009054906101000a90046001600160a01b03166001600160a01b0316632107c1016040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e491906114f4565b6106ee91906114bf565b34101561073d5760405162461bcd60e51b815260206004820152601660248201527f42616c616e636520697320696e737566666963656e74000000000000000000006044820152606401610391565b60008260400151116107915760405162461bcd60e51b815260206004820152601560248201527f746f6b656e207261746520697320696e76616c696400000000000000000000006044820152606401610391565b81608001518260600151106107e85760405162461bcd60e51b815260206004820152601860248201527f7261697365206d696e2f6d617820696e20696e76616c696400000000000000006044820152606401610391565b8160a001518260c0015111156108405760405162461bcd60e51b815260206004820152601a60248201527f736f66746361702f6861726463617020697320696e76616c69640000000000006044820152606401610391565b601e8260e001511015801561085a575060648260e0015111155b6108a65760405162461bcd60e51b815260206004820152601b60248201527f4c697175646974792070657263656e7420697320696e76616c696400000000006044820152606401610391565b6000826101000151116108fb5760405162461bcd60e51b815260206004820152601760248201527f4c697374696e67207261746520697320696e76616c69640000000000000000006044820152606401610391565b6000826101800151836101600151610913919061150d565b116109865760405162461bcd60e51b815260206004820152602160248201527f50726573616c652073746172742f656e642074696d6520697320696e76616c6960448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610391565b6224ea008261014001518361012001516109a0919061150d565b10156109ee5760405162461bcd60e51b815260206004820152601360248201527f4c6f636b20656e6420697320696e76616c6964000000000000000000000000006044820152606401610391565b6000610a7f8360a0015184604001518561010001518660e00151601c60009054906101000a90046001600160a01b03166001600160a01b0316636159ae596040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a5b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061010e91906114f4565b600254601c54604080517fdb28dbd100000000000000000000000000000000000000000000000000000000815290519394506000936001600160a01b039384169363fd82b73a93169163db28dbd19160048083019260209291908290030181865afa158015610af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1691906114f4565b6008546004805460035460405160e087901b7fffffffff0000000000000000000000000000000000000000000000000000000016815230938101939093526001600160a01b039384166024840152908316604483015291909116606482015260840160206040518083038185885af1158015610b96573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610bbb91906114d7565b90506001600160a01b038116610c135760405162461bcd60e51b815260206004820152601560248201527f4372656174652070726573616c65204661696c656400000000000000000000006044820152606401610391565b610c238460200151338385610de9565b6040517f3c6ec90f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821690633c6ec90f90610c68908790600401611524565b600060405180830381600087803b158015610c8257600080fd5b505af1158015610c96573d6000803e3d6000fd5b50506040517f87d512590000000000000000000000000000000000000000000000000000000081526001600160a01b03841692506387d512599150610cdf90869060040161162b565b600060405180830381600087803b158015610cf957600080fd5b505af1158015610d0d573d6000803e3d6000fd5b50505050806001600160a01b031663ac34c96d6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610d4c57600080fd5b505af1158015610d60573d6000803e3d6000fd5b50505050610d78816000610f6090919063ffffffff16565b50604080516001600160a01b03831681523360208201527f7ce97a7f0c83b2f9f5bd5df597d7052e608d181e21e81fe7fc9a1e7f38b48c29910160405180910390a150505050565b600061049c8183610f75565b6000610dd88383610f97565b9392505050565b600061049c825490565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691610e7b91906116c6565b6000604051808303816000865af19150503d8060008114610eb8576040519150601f19603f3d011682016040523d82523d6000602084013e610ebd565b606091505b5091509150818015610ee7575080511580610ee7575080806020019051810190610ee791906116e2565b610f585760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610391565b505050505050565b6000610dd8836001600160a01b038416610fc1565b6001600160a01b03811660009081526001830160205260408120541515610dd8565b6000826000018281548110610fae57610fae611704565b9060005260206000200154905092915050565b60008181526001830160205260408120546110085750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561049c565b50600061049c565b82805461101c90611733565b90600052602060002090601f01602090048101928261103e5760008555611084565b82601f1061105757805160ff1916838001178555611084565b82800160010185558215611084579182015b82811115611084578251825591602001919060010190611069565b50611090929150611094565b5090565b5b808211156110905760008155600101611095565b600080600080600060a086880312156110c157600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b6000602082840312156110f657600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171561114f5761114f6110fd565b60405290565b6040516101a0810167ffffffffffffffff8111828210171561114f5761114f6110fd565b6001600160a01b038116811461118e57600080fd5b50565b803561119c81611179565b919050565b600082601f8301126111b257600080fd5b813567ffffffffffffffff808211156111cd576111cd6110fd565b604051601f8301601f19908116603f011681019082821181831017156111f5576111f56110fd565b8160405283815286602085880101111561120e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060a0828403121561124057600080fd5b61124861112c565b9050813567ffffffffffffffff8082111561126257600080fd5b61126e858386016111a1565b8352602084013591508082111561128457600080fd5b611290858386016111a1565b602084015260408401359150808211156112a957600080fd5b6112b5858386016111a1565b604084015260608401359150808211156112ce57600080fd5b6112da858386016111a1565b606084015260808401359150808211156112f357600080fd5b50611300848285016111a1565b60808301525092915050565b6000808284036101c081121561132157600080fd5b6101a08082121561133157600080fd5b611339611155565b915061134485611191565b825261135260208601611191565b602083015260408581013590830152606080860135908301526080808601359083015260a0808601359083015260c0808601359083015260e080860135908301526101008086013590830152610120808601359083015261014080860135908301526101608086013590830152610180808601359083015290925083013567ffffffffffffffff8111156113e557600080fd5b6113f18582860161122e565b9150509250929050565b60006020828403121561140d57600080fd5b8135610dd881611179565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561147f5761147f611418565b500290565b6000826114ba577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600082198211156114d2576114d2611418565b500190565b6000602082840312156114e957600080fd5b8151610dd881611179565b60006020828403121561150657600080fd5b5051919050565b60008282101561151f5761151f611418565b500390565b81516001600160a01b031681526101a08101602083015161155060208401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151818401525061016080840151818401525061018080840151818401525092915050565b60005b838110156115ea5781810151838201526020016115d2565b838111156115f9576000848401525b50505050565b600081518084526116178160208601602086016115cf565b601f01601f19169290920160200192915050565b602081526000825160a0602084015261164760c08401826115ff565b90506020840151601f198085840301604086015261166583836115ff565b9250604086015191508085840301606086015261168283836115ff565b9250606086015191508085840301608086015261169f83836115ff565b925060808601519150808584030160a0860152506116bd82826115ff565b95945050505050565b600082516116d88184602087016115cf565b9190910192915050565b6000602082840312156116f457600080fd5b81518015158114610dd857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c9082168061174757607f821691505b602082108103611780577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b5091905056fea2646970667358221220958e01f8f533a950948772b5b4bce89288bec333340932f8aca80957cc1c827564736f6c634300080d0033