Overview
ETH Balance
ETH Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Authorized F... | 38486184 | 8 hrs ago | IN | 0 ETH | 0.00000006 |
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 38486869 | 7 hrs ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;
import {CallOptionFactory} from "./CallOptionFactory.sol";
/// @title CallOptionFactoryDeployer
/// @notice Deploys CallOptionFactory contracts for TokenLaunchFactory
contract CallOptionFactoryDeployer {
address public authorizedFactory;
address public immutable admin;
error UnauthorizedCaller();
constructor(address _admin) {
if (_admin == address(0)) revert UnauthorizedCaller();
admin = _admin;
}
function setAuthorizedFactory(address factory) external {
if (msg.sender != admin) revert UnauthorizedCaller();
if (authorizedFactory != address(0)) revert UnauthorizedCaller();
authorizedFactory = factory;
}
function deploy(
address token,
address treasury,
address buyback,
address creator
) external returns (address callOptionFactory) {
if (msg.sender != authorizedFactory) revert UnauthorizedCaller();
callOptionFactory = address(new CallOptionFactory(token, treasury, buyback, authorizedFactory, creator));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {CallOption} from "./CallOption.sol";
/// @title CallOptionFactory
/// @notice Holds option allocation and deploys per-member call options sharing a global strike.
contract CallOptionFactory is AccessControl {
using SafeERC20 for IERC20;
bytes32 public constant SCHEDULER_ROLE = keccak256("SCHEDULER_ROLE");
struct OptionInfo {
address option;
address beneficiary;
uint256 amount;
uint256 vestingEnd;
uint256 createdAt;
}
address public immutable token;
address public immutable treasury;
address public immutable buybackAddress;
address public immutable strategySetter;
address public strategy;
bool public strategySet;
uint160 public strikePriceX96;
bool public strikeSet;
OptionInfo[] internal _allOptions;
mapping(address => uint256[]) internal _beneficiaryToIndices;
event StrategySet(address indexed strategy);
event StrikeSet(uint160 sqrtPriceX96);
event OptionCreated(address indexed option, address indexed beneficiary, uint256 amount, uint256 vestingEnd);
error InvalidAddress();
error InvalidAmount();
error Unauthorized();
error StrategyAlreadySet();
error StrikeAlreadySet();
error InsufficientBalance();
constructor(address _token, address _treasury, address _buybackAddress, address _strategySetter, address admin) {
if (_token == address(0) || _treasury == address(0) || _buybackAddress == address(0)) revert InvalidAddress();
if (_strategySetter == address(0) || admin == address(0)) revert InvalidAddress();
token = _token;
treasury = _treasury;
buybackAddress = _buybackAddress;
strategySetter = _strategySetter;
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(SCHEDULER_ROLE, admin);
}
function setStrategy(address newStrategy) external {
if (msg.sender != strategySetter) revert Unauthorized();
if (newStrategy == address(0)) revert InvalidAddress();
if (strategySet) revert StrategyAlreadySet();
strategy = newStrategy;
strategySet = true;
emit StrategySet(newStrategy);
}
function setStrike(uint160 sqrtPriceX96) external {
if (!strategySet || msg.sender != strategy) revert Unauthorized();
if (strikeSet) revert StrikeAlreadySet();
if (sqrtPriceX96 == 0) revert InvalidAmount();
strikePriceX96 = sqrtPriceX96;
strikeSet = true;
emit StrikeSet(sqrtPriceX96);
}
function createOption(address beneficiary, uint256 amount, uint256 vestingEnd)
external
onlyRole(SCHEDULER_ROLE)
returns (address option)
{
if (beneficiary == address(0)) revert InvalidAddress();
if (amount == 0) revert InvalidAmount();
if (IERC20(token).balanceOf(address(this)) < amount) revert InsufficientBalance();
option = address(
new CallOption(token, beneficiary, amount, buybackAddress, treasury, address(this), vestingEnd)
);
IERC20(token).safeTransfer(option, amount);
_allOptions.push(
OptionInfo({
option: option,
beneficiary: beneficiary,
amount: amount,
vestingEnd: vestingEnd,
createdAt: block.timestamp
})
);
_beneficiaryToIndices[beneficiary].push(_allOptions.length - 1);
emit OptionCreated(option, beneficiary, amount, vestingEnd);
}
function createOptions(
address[] calldata beneficiaries,
uint256[] calldata amounts,
uint256[] calldata vestingEnds
) external onlyRole(SCHEDULER_ROLE) returns (address[] memory options) {
uint256 count = beneficiaries.length;
if (count == 0) revert InvalidAmount();
if (amounts.length != count || vestingEnds.length != count) revert InvalidAmount();
options = new address[](count);
for (uint256 i = 0; i < count; i++) {
address beneficiary = beneficiaries[i];
uint256 amount = amounts[i];
uint256 vestingEnd = vestingEnds[i];
if (beneficiary == address(0)) revert InvalidAddress();
if (amount == 0) revert InvalidAmount();
if (IERC20(token).balanceOf(address(this)) < amount) revert InsufficientBalance();
address option = address(
new CallOption(token, beneficiary, amount, buybackAddress, treasury, address(this), vestingEnd)
);
IERC20(token).safeTransfer(option, amount);
_allOptions.push(
OptionInfo({
option: option,
beneficiary: beneficiary,
amount: amount,
vestingEnd: vestingEnd,
createdAt: block.timestamp
})
);
_beneficiaryToIndices[beneficiary].push(_allOptions.length - 1);
options[i] = option;
emit OptionCreated(option, beneficiary, amount, vestingEnd);
}
}
function getOptionsPaginated(uint256 offset, uint256 limit)
external
view
returns (OptionInfo[] memory options, uint256 totalCount)
{
totalCount = _allOptions.length;
if (offset == 0 && limit == 0) {
options = _allOptions;
return (options, totalCount);
}
if (limit == 0) limit = totalCount;
if (offset >= totalCount) return (new OptionInfo[](0), totalCount);
uint256 count = (offset + limit > totalCount) ? (totalCount - offset) : limit;
options = new OptionInfo[](count);
for (uint256 i = 0; i < count; i++) {
options[i] = _allOptions[offset + i];
}
}
function getOptionsByBeneficiaryPaginated(address beneficiary, uint256 offset, uint256 limit)
external
view
returns (OptionInfo[] memory options, uint256 totalCount)
{
uint256[] storage indices = _beneficiaryToIndices[beneficiary];
totalCount = indices.length;
if (offset == 0 && limit == 0) {
options = new OptionInfo[](totalCount);
for (uint256 i = 0; i < totalCount; i++) {
options[i] = _allOptions[indices[i]];
}
return (options, totalCount);
}
if (limit == 0) limit = totalCount;
if (offset >= totalCount) return (new OptionInfo[](0), totalCount);
uint256 count = (offset + limit > totalCount) ? (totalCount - offset) : limit;
options = new OptionInfo[](count);
for (uint256 i = 0; i < count; i++) {
options[i] = _allOptions[indices[offset + i]];
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {FullMath} from "v4-core/libraries/FullMath.sol";
interface ICallOptionFactory {
function strikePriceX96() external view returns (uint160);
function strikeSet() external view returns (bool);
}
/// @title CallOption
/// @notice European-style call option with factory-set strike price
contract CallOption {
using SafeERC20 for IERC20;
uint256 public constant MIN_VESTING = 365 days;
address public immutable token;
address public immutable treasury;
address public immutable buybackAddress;
address public immutable factory;
address public team;
uint256 public immutable totalAmount;
uint256 public immutable vestingStart;
uint256 public vestingEnd;
uint256 public exercised;
event HolderChanged(address indexed oldHolder, address indexed newHolder);
event Exercised(address indexed holder, uint256 tokenAmount, uint256 ethPaid);
error InvalidAddress();
error InvalidAmount();
error Unauthorized();
error StrikeNotSet();
error VestingTooShort();
constructor(
address _token,
address _team,
uint256 _totalAmount,
address _buybackAddress,
address _treasury,
address _factory,
uint256 _vestingEnd
) {
if (_token == address(0) || _team == address(0)) revert InvalidAddress();
if (_buybackAddress == address(0) || _treasury == address(0) || _factory == address(0)) {
revert InvalidAddress();
}
if (_totalAmount == 0) revert InvalidAmount();
token = _token;
team = _team;
totalAmount = _totalAmount;
buybackAddress = _buybackAddress;
treasury = _treasury;
factory = _factory;
vestingStart = block.timestamp;
if (_vestingEnd < vestingStart + MIN_VESTING) revert VestingTooShort();
vestingEnd = _vestingEnd;
}
function updateTeam(address newTeam) external {
if (msg.sender != team) revert Unauthorized();
if (newTeam == address(0)) revert InvalidAddress();
address old = team;
team = newTeam;
emit HolderChanged(old, newTeam);
}
function getExercisableAmount() public view returns (uint256) {
if (block.timestamp >= vestingEnd) {
return totalAmount - exercised;
}
uint256 elapsed = block.timestamp - vestingStart;
uint256 duration = vestingEnd - vestingStart;
uint256 vested = (totalAmount * elapsed) / duration;
return vested > exercised ? vested - exercised : 0;
}
function exercise(uint256 tokenAmount) external payable {
if (msg.sender != team) revert Unauthorized();
if (!ICallOptionFactory(factory).strikeSet()) revert StrikeNotSet();
if (tokenAmount == 0) revert InvalidAmount();
if (tokenAmount > getExercisableAmount()) revert InvalidAmount();
uint160 strikePriceX96 = ICallOptionFactory(factory).strikePriceX96();
uint256 sqrtPriceSquared = uint256(strikePriceX96) * uint256(strikePriceX96);
uint256 ethRequired = FullMath.mulDiv(tokenAmount, sqrtPriceSquared, 1 << 192);
if (msg.value < ethRequired) revert InvalidAmount();
exercised += tokenAmount;
uint256 treasuryAmount = ethRequired / 100;
uint256 buybackAmount = ethRequired - treasuryAmount;
(bool success1,) = treasury.call{value: treasuryAmount}("");
if (!success1) revert InvalidAmount();
(bool success2,) = buybackAddress.call{value: buybackAmount}("");
if (!success2) revert InvalidAmount();
IERC20(token).safeTransfer(team, tokenAmount);
if (msg.value > ethRequired) {
(bool refund,) = msg.sender.call{value: msg.value - ethRequired}("");
if (!refund) revert InvalidAmount();
}
emit Exercised(team, tokenAmount, ethRequired);
}
receive() external payable {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted to signal this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2**256 + prod0
uint256 prod0 = a * b; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
assembly ("memory-safe") {
result := div(prod0, denominator)
}
return result;
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
uint256 remainder;
assembly ("memory-safe") {
remainder := mulmod(a, b, denominator)
}
// Subtract 256 bit number from 512 bit number
assembly ("memory-safe") {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
uint256 twos = (0 - denominator) & denominator;
// Divide denominator by power of two
assembly ("memory-safe") {
denominator := div(denominator, twos)
}
// Divide [prod1 prod0] by the factors of two
assembly ("memory-safe") {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly ("memory-safe") {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
// Invert denominator mod 2**256
// Now that denominator is an odd number, it has an inverse
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // inverse mod 2**256
// Because the division is now exact we can divide by multiplying
// with the modular inverse of denominator. This will give us the
// correct result modulo 2**256. Since the preconditions guarantee
// that the outcome is less than 2**256, this is the final result.
// We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inv;
return result;
}
}
/// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
result = mulDiv(a, b, denominator);
if (mulmod(a, b, denominator) != 0) {
require(++result > 0);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";{
"remappings": [
"@ensdomains/=lib/v4-periphery/lib/v4-core/node_modules/@ensdomains/",
"@openzeppelin/=lib/liquidity-launcher/lib/openzeppelin-contracts/",
"@openzeppelin/contracts/=lib/liquidity-launcher/lib/openzeppelin-contracts/contracts/",
"@openzeppelin-latest/=lib/liquidity-launcher/lib/openzeppelin-contracts/",
"@optimism/=lib/liquidity-launcher/lib/optimism/packages/contracts-bedrock/",
"@solady/=lib/liquidity-launcher/lib/solady/",
"@uniswap/v4-core/=lib/v4-periphery/lib/v4-core/",
"@uniswap/v4-periphery/=lib/v4-periphery/",
"@uniswap/uerc20-factory/=lib/liquidity-launcher/lib/uerc20-factory/src/",
"blocknumberish/=lib/liquidity-launcher/lib/blocknumberish/",
"ds-test/=lib/v4-periphery/lib/v4-core/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/liquidity-launcher/lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-gas-snapshot/=lib/v4-periphery/lib/forge-gas-snapshot/src/",
"forge-std/=lib/forge-std/src/",
"hardhat/=lib/v4-periphery/lib/v4-core/node_modules/hardhat/",
"openzeppelin-contracts/=lib/liquidity-launcher/lib/openzeppelin-contracts/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"permit2/=lib/v4-periphery/lib/permit2/",
"solady/=lib/liquidity-launcher/lib/solady/src/",
"solmate/=lib/v4-periphery/lib/v4-core/lib/solmate/",
"v4-core/=lib/v4-periphery/lib/v4-core/src/",
"v4-periphery/=lib/v4-periphery/",
"scripts/=lib/liquidity-launcher/lib/optimism/packages/contracts-bedrock/scripts/",
"liquidity-launcher/src/token-factories/uerc20-factory/=lib/liquidity-launcher/lib/uerc20-factory/src/",
"liquidity-launcher/src/=lib/liquidity-launcher/src/",
"liquidity-launcher/=lib/liquidity-launcher/",
"periphery/=lib/liquidity-launcher/src/periphery/",
"continuous-clearing-auction/=lib/liquidity-launcher/lib/continuous-clearing-auction/",
"ll/=lib/liquidity-launcher/src/"
],
"optimizer": {
"enabled": true,
"runs": 800
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"UnauthorizedCaller","type":"error"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authorizedFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"treasury","type":"address"},{"internalType":"address","name":"buyback","type":"address"},{"internalType":"address","name":"creator","type":"address"}],"name":"deploy","outputs":[{"internalType":"address","name":"callOptionFactory","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"factory","type":"address"}],"name":"setAuthorizedFactory","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a0604052348015600e575f80fd5b50604051612fcb380380612fcb833981016040819052602b916061565b6001600160a01b038116605157604051635c427cd960e01b815260040160405180910390fd5b6001600160a01b0316608052608c565b5f602082840312156070575f80fd5b81516001600160a01b03811681146085575f80fd5b9392505050565b608051612f226100a95f395f81816096015260d60152612f225ff3fe608060405234801561000f575f80fd5b506004361061004a575f3560e01c80630852f9f31461004e5780632625dbae1461007c578063f851a44014610091578063fd82b73a146100b8575b5f80fd5b5f54610060906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b61008f61008a36600461023b565b6100cb565b005b6100607f000000000000000000000000000000000000000000000000000000000000000081565b6100606100c636600461025b565b610176565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461011457604051635c427cd960e01b815260040160405180910390fd5b5f546001600160a01b03161561013d57604051635c427cd960e01b815260040160405180910390fd5b5f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f80546001600160a01b031633146101a157604051635c427cd960e01b815260040160405180910390fd5b5f546040518691869186916001600160a01b03169086906101c190610213565b6001600160a01b0395861681529385166020850152918416604084015283166060830152909116608082015260a001604051809103905ff080158015610209573d5f803e3d5ffd5b5095945050505050565b612c40806102ad83390190565b80356001600160a01b0381168114610236575f80fd5b919050565b5f6020828403121561024b575f80fd5b61025482610220565b9392505050565b5f805f806080858703121561026e575f80fd5b61027785610220565b935061028560208601610220565b925061029360408601610220565b91506102a160608601610220565b90509295919450925056fe610100604052348015610010575f80fd5b50604051612c40380380612c4083398101604081905261002f916101da565b6001600160a01b038516158061004c57506001600160a01b038416155b8061005e57506001600160a01b038316155b1561007c5760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b038216158061009957506001600160a01b038116155b156100b75760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0380861660805284811660a05283811660c052821660e0526100e05f82610116565b5061010b7f2c0e86ef42968f843b5fc3a6f6d421401da96923e1a6a2299b016956535a3b8282610116565b50505050505061023b565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166101b6575f838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561016e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016101b9565b505f5b92915050565b80516001600160a01b03811681146101d5575f80fd5b919050565b5f805f805f60a086880312156101ee575f80fd5b6101f7866101bf565b9450610205602087016101bf565b9350610213604087016101bf565b9250610221606087016101bf565b915061022f608087016101bf565b90509295509295909350565b60805160a05160c05160e0516129856102bb5f395f81816101ca0152610d2401525f81816103800152818161067b0152610f8601525f81816102e20152818161069c0152610fa701525f81816103e1015281816105c5015281816106580152818161073101528181610ed101528181610f63015261103c01526129855ff3fe608060405234801561000f575f80fd5b5060043610610179575f3560e01c806361d027b3116100d2578063ba657e4311610088578063f25a13a011610063578063f25a13a0146103b5578063f80d9940146103c8578063fc0c546a146103dc575f80fd5b8063ba657e4314610368578063cc2fbd661461037b578063d547741f146103a2575f80fd5b806391d14854116100b857806391d1485414610318578063a217fddf1461034e578063a8c62e7614610355575f80fd5b806361d027b3146102dd5780637ee383be14610304575f80fd5b806325eb9fc41161013257806333a100ca1161010d57806333a100ca1461029057806336568abe146102a35780635c8ab63d146102b6575f80fd5b806325eb9fc414610255578063281762901461026a5780632f2ff15d1461027d575f80fd5b806313074d761161016257806313074d76146101c557806321acf8e714610204578063248a9ca314610225575f80fd5b806301ffc9a71461017d57806302c5ab5c146101a5575b5f80fd5b61019061018b36600461181a565b610403565b60405190151581526020015b60405180910390f35b6101b86101b3366004611889565b610439565b60405161019c9190611928565b6101ec7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161019c565b610217610212366004611973565b610967565b60405161019c929190611993565b610247610233366004611a21565b5f9081526020819052604090206001015490565b60405190815260200161019c565b610268610263366004611a4c565b610bf2565b005b6002546101ec906001600160a01b031681565b61026861028b366004611a67565b610cef565b61026861029e366004611a4c565b610d19565b6102686102b1366004611a67565b610e10565b6102477f2c0e86ef42968f843b5fc3a6f6d421401da96923e1a6a2299b016956535a3b8281565b6101ec7f000000000000000000000000000000000000000000000000000000000000000081565b60015461019090600160a01b900460ff1681565b610190610326366004611a67565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6102475f81565b6001546101ec906001600160a01b031681565b6101ec610376366004611a95565b610e48565b6101ec7f000000000000000000000000000000000000000000000000000000000000000081565b6102686103b0366004611a67565b611218565b6102176103c3366004611a95565b61123c565b60025461019090600160a01b900460ff1681565b6101ec7f000000000000000000000000000000000000000000000000000000000000000081565b5f6001600160e01b03198216637965db0b60e01b148061043357506301ffc9a760e01b6001600160e01b03198316145b92915050565b60607f2c0e86ef42968f843b5fc3a6f6d421401da96923e1a6a2299b016956535a3b82610465816115aa565b865f8190036104875760405163162908e360e11b815260040160405180910390fd5b85811415806104965750838114155b156104b45760405163162908e360e11b815260040160405180910390fd5b8067ffffffffffffffff8111156104cd576104cd611ac7565b6040519080825280602002602001820160405280156104f6578160200160208202803683370190505b5092505f5b8181101561095a575f8a8a8381811061051657610516611adb565b905060200201602081019061052b9190611a4c565b90505f89898481811061054057610540611adb565b9050602002013590505f88888581811061055c5761055c611adb565b60200291909101359150506001600160a01b03831661058e5760405163e6c4247b60e01b815260040160405180910390fd5b815f036105ae5760405163162908e360e11b815260040160405180910390fd5b6040516370a0823160e01b815230600482015282907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610612573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106369190611aef565b101561065557604051631e9acf1760e31b815260040160405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000084847f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030876040516106c99061180d565b6001600160a01b0397881681529587166020870152604086019490945291851660608501528416608084015290921660a082015260c081019190915260e001604051809103905ff080158015610721573d5f803e3d5ffd5b5090506107586001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682856115b7565b6040805160a0810182526001600160a01b038084168252868116602080840182815284860189815260608601898152426080880190815260038054600181810183555f8381529a5160059092027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b81018054938c1673ffffffffffffffffffffffffffffffffffffffff1994851617905596517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c8801805491909b1692169190911790985592517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d85015590517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85e840155517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85f90920191909155918452600490529290912091546108a99190611b1a565b81546001810183555f928352602090922090910155875181908990879081106108d4576108d4611adb565b60200260200101906001600160a01b031690816001600160a01b031681525050836001600160a01b0316816001600160a01b03167f9d9a013de1517641ccbdd2b943f59d6fccdd3513d61250862517650d3d2906dd8585604051610942929190918252602082015260400190565b60405180910390a35050600190920191506104fb9050565b5050509695505050505050565b60035460609083158015610979575082155b15610a15576003805480602002602001604051908101604052809291908181526020015f905b82821015610a0a575f8481526020908190206040805160a0810182526005860290920180546001600160a01b0390811684526001808301549091168486015260028201549284019290925260038101546060840152600401546080830152908352909201910161099f565b505050509150610beb565b825f03610a20578092505b808410610a9657604080515f8082526020820190925290610a8e565b610a7b6040518060a001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b815260200190600190039081610a3c5790505b509150610beb565b5f81610aa28587611b2d565b11610aad5783610ab7565b610ab78583611b1a565b90508067ffffffffffffffff811115610ad257610ad2611ac7565b604051908082528060200260200182016040528015610b4257816020015b610b2f6040518060a001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b815260200190600190039081610af05790505b5092505f5b81811015610be8576003610b5b8288611b2d565b81548110610b6b57610b6b611adb565b5f9182526020918290206040805160a081018252600590930290910180546001600160a01b039081168452600182015416938301939093526002830154908201526003820154606082015260049091015460808201528451859083908110610bd557610bd5611adb565b6020908102919091010152600101610b47565b50505b9250929050565b600154600160a01b900460ff161580610c1657506001546001600160a01b03163314155b15610c33576040516282b42960e81b815260040160405180910390fd5b600254600160a01b900460ff1615610c5e57604051631af303c760e01b815260040160405180910390fd5b806001600160a01b03165f03610c875760405163162908e360e11b815260040160405180910390fd5b6002805474ffffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117600160a01b179091556040519081527f1b59d5a2d34b361e48285194e1ff6db828fdd770307b7b376a0c6b6be40269f39060200160405180910390a150565b5f82815260208190526040902060010154610d09816115aa565b610d13838361161e565b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d61576040516282b42960e81b815260040160405180910390fd5b6001600160a01b038116610d885760405163e6c4247b60e01b815260040160405180910390fd5b600154600160a01b900460ff1615610db35760405163e71ebde160e01b815260040160405180910390fd5b6001805474ffffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117600160a01b179091556040517fe70d79dad95c835bdd87e9cf4665651c9e5abb3b756e4fd2bf45f29c95c3aa40905f90a250565b6001600160a01b0381163314610e395760405163334bd91960e11b815260040160405180910390fd5b610e4382826116c5565b505050565b5f7f2c0e86ef42968f843b5fc3a6f6d421401da96923e1a6a2299b016956535a3b82610e73816115aa565b6001600160a01b038516610e9a5760405163e6c4247b60e01b815260040160405180910390fd5b835f03610eba5760405163162908e360e11b815260040160405180910390fd5b6040516370a0823160e01b815230600482015284907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610f1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f429190611aef565b1015610f6157604051631e9acf1760e31b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000085857f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000003088604051610fd49061180d565b6001600160a01b0397881681529587166020870152604086019490945291851660608501528416608084015290921660a082015260c081019190915260e001604051809103905ff08015801561102c573d5f803e3d5ffd5b5091506110636001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001683866115b7565b6040805160a0810182526001600160a01b03808516825287811660208084018281528486018a8152606086018a8152426080880190815260038054600181810183555f8381529a5160059092027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b81018054938c1673ffffffffffffffffffffffffffffffffffffffff1994851617905596517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c8801805491909b1692169190911790985592517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d85015590517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85e840155517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85f90920191909155918452600490529290912091546111b49190611b1a565b81546001810183555f9283526020928390200155604080518681529182018590526001600160a01b0387811692908516917f9d9a013de1517641ccbdd2b943f59d6fccdd3513d61250862517650d3d2906dd910160405180910390a3509392505050565b5f82815260208190526040902060010154611232816115aa565b610d1383836116c5565b6001600160a01b0383165f908152600460205260409020805460609184158015611264575083155b156113b0578167ffffffffffffffff81111561128257611282611ac7565b6040519080825280602002602001820160405280156112f257816020015b6112df6040518060a001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b8152602001906001900390816112a05790505b5092505f5b828110156113a957600382828154811061131357611313611adb565b905f5260205f2001548154811061132c5761132c611adb565b5f9182526020918290206040805160a081018252600590930290910180546001600160a01b03908116845260018201541693830193909352600283015490820152600382015460608201526004909101546080820152845185908390811061139657611396611adb565b60209081029190910101526001016112f7565b50506115a2565b835f036113bb578193505b81851061143257604080515f8082526020820190925290611429565b6114166040518060a001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b8152602001906001900390816113d75790505b509250506115a2565b5f8261143e8688611b2d565b116114495784611453565b6114538684611b1a565b90508067ffffffffffffffff81111561146e5761146e611ac7565b6040519080825280602002602001820160405280156114de57816020015b6114cb6040518060a001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b81526020019060019003908161148c5790505b5093505f5b8181101561159e576003836114f8838a611b2d565b8154811061150857611508611adb565b905f5260205f2001548154811061152157611521611adb565b5f9182526020918290206040805160a081018252600590930290910180546001600160a01b03908116845260018201541693830193909352600283015490820152600382015460608201526004909101546080820152855186908390811061158b5761158b611adb565b60209081029190910101526001016114e3565b5050505b935093915050565b6115b48133611746565b50565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b179052610e439084906117a1565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166116be575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556116763390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610433565b505f610433565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16156116be575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610433565b5f828152602081815260408083206001600160a01b038516845290915290205460ff1661179d5760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044015b60405180910390fd5b5050565b5f8060205f8451602086015f885af1806117c0576040513d5f823e3d81fd5b50505f513d915081156117d75780600114156117e4565b6001600160a01b0384163b155b15610d1357604051635274afe760e01b81526001600160a01b0385166004820152602401611794565b610e0f80611b4183390190565b5f6020828403121561182a575f80fd5b81356001600160e01b031981168114611841575f80fd5b9392505050565b5f8083601f840112611858575f80fd5b50813567ffffffffffffffff81111561186f575f80fd5b6020830191508360208260051b8501011115610beb575f80fd5b5f805f805f806060878903121561189e575f80fd5b863567ffffffffffffffff8111156118b4575f80fd5b6118c089828a01611848565b909750955050602087013567ffffffffffffffff8111156118df575f80fd5b6118eb89828a01611848565b909550935050604087013567ffffffffffffffff81111561190a575f80fd5b61191689828a01611848565b979a9699509497509295939492505050565b602080825282518282018190525f918401906040840190835b818110156119685783516001600160a01b0316835260209384019390920191600101611941565b509095945050505050565b5f8060408385031215611984575f80fd5b50508035926020909101359150565b604080825283519082018190525f9060208501906060840190835b81811015611a0e5783516001600160a01b0381511684526001600160a01b0360208201511660208501526040810151604085015260608101516060850152608081015160808501525060a0830192506020840193506001810190506119ae565b5050602093909301939093525092915050565b5f60208284031215611a31575f80fd5b5035919050565b6001600160a01b03811681146115b4575f80fd5b5f60208284031215611a5c575f80fd5b813561184181611a38565b5f8060408385031215611a78575f80fd5b823591506020830135611a8a81611a38565b809150509250929050565b5f805f60608486031215611aa7575f80fd5b8335611ab281611a38565b95602085013595506040909401359392505050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215611aff575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561043357610433611b06565b8082018082111561043357610433611b0656fe610140604052348015610010575f80fd5b50604051610e0f380380610e0f83398101604081905261002f9161016f565b6001600160a01b038716158061004c57506001600160a01b038616155b1561006a5760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b038416158061008757506001600160a01b038316155b8061009957506001600160a01b038216155b156100b75760405163e6c4247b60e01b815260040160405180910390fd5b845f036100d75760405163162908e360e11b815260040160405180910390fd5b6001600160a01b038781166080525f80546001600160a01b03191688831617905561010086905284811660c05283811660a052821660e05242610120819052610125906301e13380906101e8565b81101561014557604051631dd59aab60e31b815260040160405180910390fd5b6001555061020d945050505050565b80516001600160a01b038116811461016a575f80fd5b919050565b5f805f805f805f60e0888a031215610185575f80fd5b61018e88610154565b965061019c60208901610154565b604089015190965094506101b260608901610154565b93506101c060808901610154565b92506101ce60a08901610154565b91505f60c089015190508091505092959891949750929550565b8082018082111561020757634e487b7160e01b5f52601160045260245ffd5b92915050565b60805160a05160c05160e0516101005161012051610b7c6102935f395f81816101480152818161081a015261084401525f8181610115015281816107eb015261087a01525f81816102580152818161030b01526103f101525f818161028b015261059401525f818161017b015261050401525f81816102be01526106310152610b7c5ff3fe6080604052600436106100d1575f3560e01c806385f2aef21161007c578063ba3dd62c11610057578063ba3dd62c14610233578063c45a015514610247578063cc2fbd661461027a578063fc0c546a146102ad575f80fd5b806385f2aef2146101e1578063b07f0a41146101ff578063b23f359414610214575f80fd5b806361d027b3116100ac57806361d027b31461016a57806363e63e3b146101b557806384a1931f146101cc575f80fd5b806314c68b1b146100dc5780631a39d8ef14610104578063254800d414610137575f80fd5b366100d857005b5f80fd5b3480156100e7575f80fd5b506100f160025481565b6040519081526020015b60405180910390f35b34801561010f575f80fd5b506100f17f000000000000000000000000000000000000000000000000000000000000000081565b348015610142575f80fd5b506100f17f000000000000000000000000000000000000000000000000000000000000000081565b348015610175575f80fd5b5061019d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100fb565b3480156101c0575f80fd5b506100f16301e1338081565b3480156101d7575f80fd5b506100f160015481565b3480156101ec575f80fd5b505f5461019d906001600160a01b031681565b61021261020d366004610a4d565b6102e0565b005b34801561021f575f80fd5b5061021261022e366004610a7b565b610721565b34801561023e575f80fd5b506100f16107d8565b348015610252575f80fd5b5061019d7f000000000000000000000000000000000000000000000000000000000000000081565b348015610285575f80fd5b5061019d7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102b8575f80fd5b5061019d7f000000000000000000000000000000000000000000000000000000000000000081565b5f546001600160a01b03163314610309576040516282b42960e81b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f80d99406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610365573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103899190610a96565b6103a6576040516307b6ee3160e31b815260040160405180910390fd5b805f036103c65760405163162908e360e11b815260040160405180910390fd5b6103ce6107d8565b8111156103ee5760405163162908e360e11b815260040160405180910390fd5b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663281762906040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061046f9190610ab5565b90505f6104856001600160a01b03831680610ae4565b90505f6104ac848378010000000000000000000000000000000000000000000000006108ce565b9050803410156104cf5760405163162908e360e11b815260040160405180910390fd5b8360025f8282546104e09190610b01565b909155505f90506104f2606483610b14565b90505f6104ff8284610b33565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836040515f6040518083038185875af1925050503d805f811461056a576040519150601f19603f3d011682016040523d82523d5f602084013e61056f565b606091505b50509050806105915760405163162908e360e11b815260040160405180910390fd5b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836040515f6040518083038185875af1925050503d805f81146105fa576040519150601f19603f3d011682016040523d82523d5f602084013e6105ff565b606091505b50509050806106215760405163162908e360e11b815260040160405180910390fd5b5f5461065a906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691168a61096b565b843411156106d0575f3361066e8734610b33565b6040515f81818185875af1925050503d805f81146106a7576040519150601f19603f3d011682016040523d82523d5f602084013e6106ac565b606091505b50509050806106ce5760405163162908e360e11b815260040160405180910390fd5b505b5f54604080518a8152602081018890526001600160a01b03909216917fac58150721d2aba094a1ef6101fc1fa5cc087a32ba8204364468d6fa70d6a359910160405180910390a25050505050505050565b5f546001600160a01b0316331461074a576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0381166107715760405163e6c4247b60e01b815260040160405180910390fd5b5f80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f076c2af751a37d3871addf9a6fdedbaf3827fb030bf1d04c43a1421420fcc9879190a35050565b5f60015442106108145760025461080f907f0000000000000000000000000000000000000000000000000000000000000000610b33565b905090565b5f61083f7f000000000000000000000000000000000000000000000000000000000000000042610b33565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001546108709190610b33565b90505f8161089e847f0000000000000000000000000000000000000000000000000000000000000000610ae4565b6108a89190610b14565b905060025481116108b9575f6108c6565b6002546108c69082610b33565b935050505090565b5f838302815f19858709828110838203039150508084116108ed575f80fd5b805f036108ff57508290049050610964565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b1790526109d29084906109d7565b505050565b5f8060205f8451602086015f885af1806109f6576040513d5f823e3d81fd5b50505f513d91508115610a0d578060011415610a1a565b6001600160a01b0384163b155b15610a4757604051635274afe760e01b81526001600160a01b038516600482015260240160405180910390fd5b50505050565b5f60208284031215610a5d575f80fd5b5035919050565b6001600160a01b0381168114610a78575f80fd5b50565b5f60208284031215610a8b575f80fd5b813561096481610a64565b5f60208284031215610aa6575f80fd5b81518015158114610964575f80fd5b5f60208284031215610ac5575f80fd5b815161096481610a64565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610afb57610afb610ad0565b92915050565b80820180821115610afb57610afb610ad0565b5f82610b2e57634e487b7160e01b5f52601260045260245ffd5b500490565b81810381811115610afb57610afb610ad056fea264697066735822122075103441580227521f719fe34692970a0d6888811b4f34e40c4eba414a15f44e64736f6c634300081a0033a2646970667358221220395da0ab2bb3015c00e748cd3facb27bcc0dd8a25e7c532f69420e98892a397964736f6c634300081a0033a26469706673582212205ee68e2504ec2c818cfc4bab111a93e12d3090b31897879ad731cd3df567b39e64736f6c634300081a0033000000000000000000000000e911f518449ba0011d84b047b4cde50daa081ec1
Deployed Bytecode
0x608060405234801561000f575f80fd5b506004361061004a575f3560e01c80630852f9f31461004e5780632625dbae1461007c578063f851a44014610091578063fd82b73a146100b8575b5f80fd5b5f54610060906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b61008f61008a36600461023b565b6100cb565b005b6100607f000000000000000000000000e911f518449ba0011d84b047b4cde50daa081ec181565b6100606100c636600461025b565b610176565b336001600160a01b037f000000000000000000000000e911f518449ba0011d84b047b4cde50daa081ec1161461011457604051635c427cd960e01b815260040160405180910390fd5b5f546001600160a01b03161561013d57604051635c427cd960e01b815260040160405180910390fd5b5f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f80546001600160a01b031633146101a157604051635c427cd960e01b815260040160405180910390fd5b5f546040518691869186916001600160a01b03169086906101c190610213565b6001600160a01b0395861681529385166020850152918416604084015283166060830152909116608082015260a001604051809103905ff080158015610209573d5f803e3d5ffd5b5095945050505050565b612c40806102ad83390190565b80356001600160a01b0381168114610236575f80fd5b919050565b5f6020828403121561024b575f80fd5b61025482610220565b9392505050565b5f805f806080858703121561026e575f80fd5b61027785610220565b935061028560208601610220565b925061029360408601610220565b91506102a160608601610220565b90509295919450925056fe610100604052348015610010575f80fd5b50604051612c40380380612c4083398101604081905261002f916101da565b6001600160a01b038516158061004c57506001600160a01b038416155b8061005e57506001600160a01b038316155b1561007c5760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b038216158061009957506001600160a01b038116155b156100b75760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0380861660805284811660a05283811660c052821660e0526100e05f82610116565b5061010b7f2c0e86ef42968f843b5fc3a6f6d421401da96923e1a6a2299b016956535a3b8282610116565b50505050505061023b565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166101b6575f838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561016e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016101b9565b505f5b92915050565b80516001600160a01b03811681146101d5575f80fd5b919050565b5f805f805f60a086880312156101ee575f80fd5b6101f7866101bf565b9450610205602087016101bf565b9350610213604087016101bf565b9250610221606087016101bf565b915061022f608087016101bf565b90509295509295909350565b60805160a05160c05160e0516129856102bb5f395f81816101ca0152610d2401525f81816103800152818161067b0152610f8601525f81816102e20152818161069c0152610fa701525f81816103e1015281816105c5015281816106580152818161073101528181610ed101528181610f63015261103c01526129855ff3fe608060405234801561000f575f80fd5b5060043610610179575f3560e01c806361d027b3116100d2578063ba657e4311610088578063f25a13a011610063578063f25a13a0146103b5578063f80d9940146103c8578063fc0c546a146103dc575f80fd5b8063ba657e4314610368578063cc2fbd661461037b578063d547741f146103a2575f80fd5b806391d14854116100b857806391d1485414610318578063a217fddf1461034e578063a8c62e7614610355575f80fd5b806361d027b3146102dd5780637ee383be14610304575f80fd5b806325eb9fc41161013257806333a100ca1161010d57806333a100ca1461029057806336568abe146102a35780635c8ab63d146102b6575f80fd5b806325eb9fc414610255578063281762901461026a5780632f2ff15d1461027d575f80fd5b806313074d761161016257806313074d76146101c557806321acf8e714610204578063248a9ca314610225575f80fd5b806301ffc9a71461017d57806302c5ab5c146101a5575b5f80fd5b61019061018b36600461181a565b610403565b60405190151581526020015b60405180910390f35b6101b86101b3366004611889565b610439565b60405161019c9190611928565b6101ec7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161019c565b610217610212366004611973565b610967565b60405161019c929190611993565b610247610233366004611a21565b5f9081526020819052604090206001015490565b60405190815260200161019c565b610268610263366004611a4c565b610bf2565b005b6002546101ec906001600160a01b031681565b61026861028b366004611a67565b610cef565b61026861029e366004611a4c565b610d19565b6102686102b1366004611a67565b610e10565b6102477f2c0e86ef42968f843b5fc3a6f6d421401da96923e1a6a2299b016956535a3b8281565b6101ec7f000000000000000000000000000000000000000000000000000000000000000081565b60015461019090600160a01b900460ff1681565b610190610326366004611a67565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6102475f81565b6001546101ec906001600160a01b031681565b6101ec610376366004611a95565b610e48565b6101ec7f000000000000000000000000000000000000000000000000000000000000000081565b6102686103b0366004611a67565b611218565b6102176103c3366004611a95565b61123c565b60025461019090600160a01b900460ff1681565b6101ec7f000000000000000000000000000000000000000000000000000000000000000081565b5f6001600160e01b03198216637965db0b60e01b148061043357506301ffc9a760e01b6001600160e01b03198316145b92915050565b60607f2c0e86ef42968f843b5fc3a6f6d421401da96923e1a6a2299b016956535a3b82610465816115aa565b865f8190036104875760405163162908e360e11b815260040160405180910390fd5b85811415806104965750838114155b156104b45760405163162908e360e11b815260040160405180910390fd5b8067ffffffffffffffff8111156104cd576104cd611ac7565b6040519080825280602002602001820160405280156104f6578160200160208202803683370190505b5092505f5b8181101561095a575f8a8a8381811061051657610516611adb565b905060200201602081019061052b9190611a4c565b90505f89898481811061054057610540611adb565b9050602002013590505f88888581811061055c5761055c611adb565b60200291909101359150506001600160a01b03831661058e5760405163e6c4247b60e01b815260040160405180910390fd5b815f036105ae5760405163162908e360e11b815260040160405180910390fd5b6040516370a0823160e01b815230600482015282907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610612573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106369190611aef565b101561065557604051631e9acf1760e31b815260040160405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000084847f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000030876040516106c99061180d565b6001600160a01b0397881681529587166020870152604086019490945291851660608501528416608084015290921660a082015260c081019190915260e001604051809103905ff080158015610721573d5f803e3d5ffd5b5090506107586001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682856115b7565b6040805160a0810182526001600160a01b038084168252868116602080840182815284860189815260608601898152426080880190815260038054600181810183555f8381529a5160059092027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b81018054938c1673ffffffffffffffffffffffffffffffffffffffff1994851617905596517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c8801805491909b1692169190911790985592517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d85015590517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85e840155517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85f90920191909155918452600490529290912091546108a99190611b1a565b81546001810183555f928352602090922090910155875181908990879081106108d4576108d4611adb565b60200260200101906001600160a01b031690816001600160a01b031681525050836001600160a01b0316816001600160a01b03167f9d9a013de1517641ccbdd2b943f59d6fccdd3513d61250862517650d3d2906dd8585604051610942929190918252602082015260400190565b60405180910390a35050600190920191506104fb9050565b5050509695505050505050565b60035460609083158015610979575082155b15610a15576003805480602002602001604051908101604052809291908181526020015f905b82821015610a0a575f8481526020908190206040805160a0810182526005860290920180546001600160a01b0390811684526001808301549091168486015260028201549284019290925260038101546060840152600401546080830152908352909201910161099f565b505050509150610beb565b825f03610a20578092505b808410610a9657604080515f8082526020820190925290610a8e565b610a7b6040518060a001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b815260200190600190039081610a3c5790505b509150610beb565b5f81610aa28587611b2d565b11610aad5783610ab7565b610ab78583611b1a565b90508067ffffffffffffffff811115610ad257610ad2611ac7565b604051908082528060200260200182016040528015610b4257816020015b610b2f6040518060a001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b815260200190600190039081610af05790505b5092505f5b81811015610be8576003610b5b8288611b2d565b81548110610b6b57610b6b611adb565b5f9182526020918290206040805160a081018252600590930290910180546001600160a01b039081168452600182015416938301939093526002830154908201526003820154606082015260049091015460808201528451859083908110610bd557610bd5611adb565b6020908102919091010152600101610b47565b50505b9250929050565b600154600160a01b900460ff161580610c1657506001546001600160a01b03163314155b15610c33576040516282b42960e81b815260040160405180910390fd5b600254600160a01b900460ff1615610c5e57604051631af303c760e01b815260040160405180910390fd5b806001600160a01b03165f03610c875760405163162908e360e11b815260040160405180910390fd5b6002805474ffffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117600160a01b179091556040519081527f1b59d5a2d34b361e48285194e1ff6db828fdd770307b7b376a0c6b6be40269f39060200160405180910390a150565b5f82815260208190526040902060010154610d09816115aa565b610d13838361161e565b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d61576040516282b42960e81b815260040160405180910390fd5b6001600160a01b038116610d885760405163e6c4247b60e01b815260040160405180910390fd5b600154600160a01b900460ff1615610db35760405163e71ebde160e01b815260040160405180910390fd5b6001805474ffffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117600160a01b179091556040517fe70d79dad95c835bdd87e9cf4665651c9e5abb3b756e4fd2bf45f29c95c3aa40905f90a250565b6001600160a01b0381163314610e395760405163334bd91960e11b815260040160405180910390fd5b610e4382826116c5565b505050565b5f7f2c0e86ef42968f843b5fc3a6f6d421401da96923e1a6a2299b016956535a3b82610e73816115aa565b6001600160a01b038516610e9a5760405163e6c4247b60e01b815260040160405180910390fd5b835f03610eba5760405163162908e360e11b815260040160405180910390fd5b6040516370a0823160e01b815230600482015284907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610f1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f429190611aef565b1015610f6157604051631e9acf1760e31b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000085857f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000003088604051610fd49061180d565b6001600160a01b0397881681529587166020870152604086019490945291851660608501528416608084015290921660a082015260c081019190915260e001604051809103905ff08015801561102c573d5f803e3d5ffd5b5091506110636001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001683866115b7565b6040805160a0810182526001600160a01b03808516825287811660208084018281528486018a8152606086018a8152426080880190815260038054600181810183555f8381529a5160059092027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b81018054938c1673ffffffffffffffffffffffffffffffffffffffff1994851617905596517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c8801805491909b1692169190911790985592517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d85015590517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85e840155517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85f90920191909155918452600490529290912091546111b49190611b1a565b81546001810183555f9283526020928390200155604080518681529182018590526001600160a01b0387811692908516917f9d9a013de1517641ccbdd2b943f59d6fccdd3513d61250862517650d3d2906dd910160405180910390a3509392505050565b5f82815260208190526040902060010154611232816115aa565b610d1383836116c5565b6001600160a01b0383165f908152600460205260409020805460609184158015611264575083155b156113b0578167ffffffffffffffff81111561128257611282611ac7565b6040519080825280602002602001820160405280156112f257816020015b6112df6040518060a001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b8152602001906001900390816112a05790505b5092505f5b828110156113a957600382828154811061131357611313611adb565b905f5260205f2001548154811061132c5761132c611adb565b5f9182526020918290206040805160a081018252600590930290910180546001600160a01b03908116845260018201541693830193909352600283015490820152600382015460608201526004909101546080820152845185908390811061139657611396611adb565b60209081029190910101526001016112f7565b50506115a2565b835f036113bb578193505b81851061143257604080515f8082526020820190925290611429565b6114166040518060a001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b8152602001906001900390816113d75790505b509250506115a2565b5f8261143e8688611b2d565b116114495784611453565b6114538684611b1a565b90508067ffffffffffffffff81111561146e5761146e611ac7565b6040519080825280602002602001820160405280156114de57816020015b6114cb6040518060a001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b81526020019060019003908161148c5790505b5093505f5b8181101561159e576003836114f8838a611b2d565b8154811061150857611508611adb565b905f5260205f2001548154811061152157611521611adb565b5f9182526020918290206040805160a081018252600590930290910180546001600160a01b03908116845260018201541693830193909352600283015490820152600382015460608201526004909101546080820152855186908390811061158b5761158b611adb565b60209081029190910101526001016114e3565b5050505b935093915050565b6115b48133611746565b50565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b179052610e439084906117a1565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166116be575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556116763390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610433565b505f610433565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16156116be575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610433565b5f828152602081815260408083206001600160a01b038516845290915290205460ff1661179d5760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044015b60405180910390fd5b5050565b5f8060205f8451602086015f885af1806117c0576040513d5f823e3d81fd5b50505f513d915081156117d75780600114156117e4565b6001600160a01b0384163b155b15610d1357604051635274afe760e01b81526001600160a01b0385166004820152602401611794565b610e0f80611b4183390190565b5f6020828403121561182a575f80fd5b81356001600160e01b031981168114611841575f80fd5b9392505050565b5f8083601f840112611858575f80fd5b50813567ffffffffffffffff81111561186f575f80fd5b6020830191508360208260051b8501011115610beb575f80fd5b5f805f805f806060878903121561189e575f80fd5b863567ffffffffffffffff8111156118b4575f80fd5b6118c089828a01611848565b909750955050602087013567ffffffffffffffff8111156118df575f80fd5b6118eb89828a01611848565b909550935050604087013567ffffffffffffffff81111561190a575f80fd5b61191689828a01611848565b979a9699509497509295939492505050565b602080825282518282018190525f918401906040840190835b818110156119685783516001600160a01b0316835260209384019390920191600101611941565b509095945050505050565b5f8060408385031215611984575f80fd5b50508035926020909101359150565b604080825283519082018190525f9060208501906060840190835b81811015611a0e5783516001600160a01b0381511684526001600160a01b0360208201511660208501526040810151604085015260608101516060850152608081015160808501525060a0830192506020840193506001810190506119ae565b5050602093909301939093525092915050565b5f60208284031215611a31575f80fd5b5035919050565b6001600160a01b03811681146115b4575f80fd5b5f60208284031215611a5c575f80fd5b813561184181611a38565b5f8060408385031215611a78575f80fd5b823591506020830135611a8a81611a38565b809150509250929050565b5f805f60608486031215611aa7575f80fd5b8335611ab281611a38565b95602085013595506040909401359392505050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215611aff575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561043357610433611b06565b8082018082111561043357610433611b0656fe610140604052348015610010575f80fd5b50604051610e0f380380610e0f83398101604081905261002f9161016f565b6001600160a01b038716158061004c57506001600160a01b038616155b1561006a5760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b038416158061008757506001600160a01b038316155b8061009957506001600160a01b038216155b156100b75760405163e6c4247b60e01b815260040160405180910390fd5b845f036100d75760405163162908e360e11b815260040160405180910390fd5b6001600160a01b038781166080525f80546001600160a01b03191688831617905561010086905284811660c05283811660a052821660e05242610120819052610125906301e13380906101e8565b81101561014557604051631dd59aab60e31b815260040160405180910390fd5b6001555061020d945050505050565b80516001600160a01b038116811461016a575f80fd5b919050565b5f805f805f805f60e0888a031215610185575f80fd5b61018e88610154565b965061019c60208901610154565b604089015190965094506101b260608901610154565b93506101c060808901610154565b92506101ce60a08901610154565b91505f60c089015190508091505092959891949750929550565b8082018082111561020757634e487b7160e01b5f52601160045260245ffd5b92915050565b60805160a05160c05160e0516101005161012051610b7c6102935f395f81816101480152818161081a015261084401525f8181610115015281816107eb015261087a01525f81816102580152818161030b01526103f101525f818161028b015261059401525f818161017b015261050401525f81816102be01526106310152610b7c5ff3fe6080604052600436106100d1575f3560e01c806385f2aef21161007c578063ba3dd62c11610057578063ba3dd62c14610233578063c45a015514610247578063cc2fbd661461027a578063fc0c546a146102ad575f80fd5b806385f2aef2146101e1578063b07f0a41146101ff578063b23f359414610214575f80fd5b806361d027b3116100ac57806361d027b31461016a57806363e63e3b146101b557806384a1931f146101cc575f80fd5b806314c68b1b146100dc5780631a39d8ef14610104578063254800d414610137575f80fd5b366100d857005b5f80fd5b3480156100e7575f80fd5b506100f160025481565b6040519081526020015b60405180910390f35b34801561010f575f80fd5b506100f17f000000000000000000000000000000000000000000000000000000000000000081565b348015610142575f80fd5b506100f17f000000000000000000000000000000000000000000000000000000000000000081565b348015610175575f80fd5b5061019d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100fb565b3480156101c0575f80fd5b506100f16301e1338081565b3480156101d7575f80fd5b506100f160015481565b3480156101ec575f80fd5b505f5461019d906001600160a01b031681565b61021261020d366004610a4d565b6102e0565b005b34801561021f575f80fd5b5061021261022e366004610a7b565b610721565b34801561023e575f80fd5b506100f16107d8565b348015610252575f80fd5b5061019d7f000000000000000000000000000000000000000000000000000000000000000081565b348015610285575f80fd5b5061019d7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102b8575f80fd5b5061019d7f000000000000000000000000000000000000000000000000000000000000000081565b5f546001600160a01b03163314610309576040516282b42960e81b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f80d99406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610365573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103899190610a96565b6103a6576040516307b6ee3160e31b815260040160405180910390fd5b805f036103c65760405163162908e360e11b815260040160405180910390fd5b6103ce6107d8565b8111156103ee5760405163162908e360e11b815260040160405180910390fd5b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663281762906040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061046f9190610ab5565b90505f6104856001600160a01b03831680610ae4565b90505f6104ac848378010000000000000000000000000000000000000000000000006108ce565b9050803410156104cf5760405163162908e360e11b815260040160405180910390fd5b8360025f8282546104e09190610b01565b909155505f90506104f2606483610b14565b90505f6104ff8284610b33565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836040515f6040518083038185875af1925050503d805f811461056a576040519150601f19603f3d011682016040523d82523d5f602084013e61056f565b606091505b50509050806105915760405163162908e360e11b815260040160405180910390fd5b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836040515f6040518083038185875af1925050503d805f81146105fa576040519150601f19603f3d011682016040523d82523d5f602084013e6105ff565b606091505b50509050806106215760405163162908e360e11b815260040160405180910390fd5b5f5461065a906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691168a61096b565b843411156106d0575f3361066e8734610b33565b6040515f81818185875af1925050503d805f81146106a7576040519150601f19603f3d011682016040523d82523d5f602084013e6106ac565b606091505b50509050806106ce5760405163162908e360e11b815260040160405180910390fd5b505b5f54604080518a8152602081018890526001600160a01b03909216917fac58150721d2aba094a1ef6101fc1fa5cc087a32ba8204364468d6fa70d6a359910160405180910390a25050505050505050565b5f546001600160a01b0316331461074a576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0381166107715760405163e6c4247b60e01b815260040160405180910390fd5b5f80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f076c2af751a37d3871addf9a6fdedbaf3827fb030bf1d04c43a1421420fcc9879190a35050565b5f60015442106108145760025461080f907f0000000000000000000000000000000000000000000000000000000000000000610b33565b905090565b5f61083f7f000000000000000000000000000000000000000000000000000000000000000042610b33565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001546108709190610b33565b90505f8161089e847f0000000000000000000000000000000000000000000000000000000000000000610ae4565b6108a89190610b14565b905060025481116108b9575f6108c6565b6002546108c69082610b33565b935050505090565b5f838302815f19858709828110838203039150508084116108ed575f80fd5b805f036108ff57508290049050610964565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b1790526109d29084906109d7565b505050565b5f8060205f8451602086015f885af1806109f6576040513d5f823e3d81fd5b50505f513d91508115610a0d578060011415610a1a565b6001600160a01b0384163b155b15610a4757604051635274afe760e01b81526001600160a01b038516600482015260240160405180910390fd5b50505050565b5f60208284031215610a5d575f80fd5b5035919050565b6001600160a01b0381168114610a78575f80fd5b50565b5f60208284031215610a8b575f80fd5b813561096481610a64565b5f60208284031215610aa6575f80fd5b81518015158114610964575f80fd5b5f60208284031215610ac5575f80fd5b815161096481610a64565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610afb57610afb610ad0565b92915050565b80820180821115610afb57610afb610ad0565b5f82610b2e57634e487b7160e01b5f52601260045260245ffd5b500490565b81810381811115610afb57610afb610ad056fea264697066735822122075103441580227521f719fe34692970a0d6888811b4f34e40c4eba414a15f44e64736f6c634300081a0033a2646970667358221220395da0ab2bb3015c00e748cd3facb27bcc0dd8a25e7c532f69420e98892a397964736f6c634300081a0033a26469706673582212205ee68e2504ec2c818cfc4bab111a93e12d3090b31897879ad731cd3df567b39e64736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e911f518449ba0011d84b047b4cde50daa081ec1
-----Decoded View---------------
Arg [0] : _admin (address): 0xe911f518449ba0011D84b047B4cde50dAA081eC1
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000e911f518449ba0011d84b047b4cde50daa081ec1
Net Worth in USD
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.