Source Code
Overview
HYPE Balance
HYPE Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 17610080 | 91 days ago | Contract Creation | 0 HYPE |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ChallengeFactory
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 10000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/proxy/Clones.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./Challenge.sol";
/**
* @title ChallengeFactory
* @notice Factory contract for deploying Challenge instances as minimal proxies
* @dev Uses EIP-1167 minimal proxy pattern for gas-efficient deployment
*/
contract ChallengeFactory is Ownable {
using Clones for address;
// Challenge implementation contract
address public immutable challengeImplementation;
// Admin address for all challenges
address public admin;
// Registry of all challenges
address[] public challenges;
// Mapping from creator to their challenges
mapping(address => address[]) public challengesByCreator;
// Events
event ChallengeCreated(
address indexed challenge,
address indexed creator,
address prizeToken,
uint256 requiredContribution,
uint256 requiredStartingBalance,
uint64 startTime,
uint64 endTime
);
event AdminUpdated(address indexed oldAdmin, address indexed newAdmin);
/**
* @notice Constructor
* @param _admin Initial admin address for all challenges
*/
constructor(address _admin) Ownable(msg.sender) {
require(_admin != address(0), "Invalid admin address");
// Deploy the implementation contract
challengeImplementation = address(new Challenge());
admin = _admin;
emit AdminUpdated(address(0), _admin);
}
/**
* @notice Create a new trading challenge
* @param prizeToken ERC20 token for prize pool
* @param requiredContribution Amount each participant must contribute
* @param requiredStartingBalance Required starting balance on HyperCore
* @param startTime Challenge start timestamp
* @param endTime Challenge end timestamp
* @param splitsBps Array of basis points for prize distribution (must sum to 10000)
* @param whitelist Array of whitelisted addresses (empty for open registration)
* @return challenge Address of the newly created challenge
*/
function createChallenge(
address prizeToken,
uint256 requiredContribution,
uint256 requiredStartingBalance,
uint64 startTime,
uint64 endTime,
uint16[] memory splitsBps,
address[] memory whitelist
) external returns (address challenge) {
// Deploy minimal proxy clone
challenge = challengeImplementation.clone();
// Initialize the challenge
// TODO: Pass actual HyperCore helper address when available (currently using address(0))
Challenge(challenge).initialize(
prizeToken,
requiredContribution,
requiredStartingBalance,
startTime,
endTime,
splitsBps,
whitelist,
msg.sender, // creator
address(0), // hyperHelper - temporarily disabled
admin
);
// Register in storage
challenges.push(challenge);
challengesByCreator[msg.sender].push(challenge);
emit ChallengeCreated(
challenge,
msg.sender,
prizeToken,
requiredContribution,
requiredStartingBalance,
startTime,
endTime
);
return challenge;
}
/**
* @notice Update admin address for future challenges (owner only)
* @param newAdmin New admin address
*/
function updateAdmin(address newAdmin) external onlyOwner {
require(newAdmin != address(0), "Invalid admin address");
address oldAdmin = admin;
admin = newAdmin;
emit AdminUpdated(oldAdmin, newAdmin);
}
// ============ View Functions ============
/**
* @notice Get total number of challenges created
*/
function challengesCount() external view returns (uint256) {
return challenges.length;
}
/**
* @notice Get challenge address at index
*/
function challengeAt(uint256 index) external view returns (address) {
require(index < challenges.length, "Index out of bounds");
return challenges[index];
}
/**
* @notice Get all challenges created by a specific creator
*/
function getChallengesByCreator(address creator) external view returns (address[] memory) {
return challengesByCreator[creator];
}
/**
* @notice Get number of challenges created by a specific creator
*/
function challengesCountByCreator(address creator) external view returns (uint256) {
return challengesByCreator[creator].length;
}
/**
* @notice Get all challenges (use with caution for large arrays)
*/
function getAllChallenges() external view returns (address[] memory) {
return challenges;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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 AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
struct AccessControlStorage {
mapping(bytes32 role => RoleData) _roles;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
assembly {
$.slot := AccessControlStorageLocation
}
}
/**
* @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);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/// @inheritdoc IERC165
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) {
AccessControlStorage storage $ = _getAccessControlStorage();
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) {
AccessControlStorage storage $ = _getAccessControlStorage();
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 {
AccessControlStorage storage $ = _getAccessControlStorage();
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) {
AccessControlStorage storage $ = _getAccessControlStorage();
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) {
AccessControlStorage storage $ = _getAccessControlStorage();
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.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
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.4.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.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 ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/// @inheritdoc IERC165
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) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol)
pragma solidity >=0.8.4;
/**
* @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.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (proxy/Clones.sol)
pragma solidity ^0.8.20;
import {Create2} from "../utils/Create2.sol";
import {Errors} from "../utils/Errors.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library Clones {
error CloneArgumentsTooLong();
/**
* @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`.
*
* This function uses the create opcode, which should never revert.
*
* WARNING: This function does not check if `implementation` has code. A clone that points to an address
* without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they
* have no effect and leave the clone uninitialized, allowing a third party to initialize it later.
*/
function clone(address implementation) internal returns (address instance) {
return clone(implementation, 0);
}
/**
* @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency
* to the new contract.
*
* WARNING: This function does not check if `implementation` has code. A clone that points to an address
* without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they
* have no effect and leave the clone uninitialized, allowing a third party to initialize it later.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function clone(address implementation, uint256 value) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
assembly ("memory-safe") {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(value, 0x09, 0x37)
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple times will revert, since
* the clones cannot be deployed twice at the same address.
*
* WARNING: This function does not check if `implementation` has code. A clone that points to an address
* without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they
* have no effect and leave the clone uninitialized, allowing a third party to initialize it later.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
return cloneDeterministic(implementation, salt, 0);
}
/**
* @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with
* a `value` parameter to send native currency to the new contract.
*
* WARNING: This function does not check if `implementation` has code. A clone that points to an address
* without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they
* have no effect and leave the clone uninitialized, allowing a third party to initialize it later.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function cloneDeterministic(
address implementation,
bytes32 salt,
uint256 value
) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
assembly ("memory-safe") {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(value, 0x09, 0x37, salt)
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
/**
* @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
* immutable arguments. These are provided through `args` and cannot be changed after deployment. To
* access the arguments within the implementation, use {fetchCloneArgs}.
*
* This function uses the create opcode, which should never revert.
*
* WARNING: This function does not check if `implementation` has code. A clone that points to an address
* without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they
* have no effect and leave the clone uninitialized, allowing a third party to initialize it later.
*/
function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {
return cloneWithImmutableArgs(implementation, args, 0);
}
/**
* @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`
* parameter to send native currency to the new contract.
*
* WARNING: This function does not check if `implementation` has code. A clone that points to an address
* without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they
* have no effect and leave the clone uninitialized, allowing a third party to initialize it later.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function cloneWithImmutableArgs(
address implementation,
bytes memory args,
uint256 value
) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
assembly ("memory-safe") {
instance := create(value, add(bytecode, 0x20), mload(bytecode))
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
* immutable arguments. These are provided through `args` and cannot be changed after deployment. To
* access the arguments within the implementation, use {fetchCloneArgs}.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same
* `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice
* at the same address.
*
* WARNING: This function does not check if `implementation` has code. A clone that points to an address
* without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they
* have no effect and leave the clone uninitialized, allowing a third party to initialize it later.
*/
function cloneDeterministicWithImmutableArgs(
address implementation,
bytes memory args,
bytes32 salt
) internal returns (address instance) {
return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0);
}
/**
* @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs],
* but with a `value` parameter to send native currency to the new contract.
*
* WARNING: This function does not check if `implementation` has code. A clone that points to an address
* without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they
* have no effect and leave the clone uninitialized, allowing a third party to initialize it later.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function cloneDeterministicWithImmutableArgs(
address implementation,
bytes memory args,
bytes32 salt,
uint256 value
) internal returns (address instance) {
bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
return Create2.deploy(value, salt, bytecode);
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
*/
function predictDeterministicAddressWithImmutableArgs(
address implementation,
bytes memory args,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
return Create2.computeAddress(salt, keccak256(bytecode), deployer);
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
*/
function predictDeterministicAddressWithImmutableArgs(
address implementation,
bytes memory args,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this));
}
/**
* @dev Get the immutable args attached to a clone.
*
* - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this
* function will return an empty array.
* - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or
* `cloneDeterministicWithImmutableArgs`, this function will return the args array used at
* creation.
* - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This
* function should only be used to check addresses that are known to be clones.
*/
function fetchCloneArgs(address instance) internal view returns (bytes memory) {
bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short
assembly ("memory-safe") {
extcodecopy(instance, add(result, 32), 45, mload(result))
}
return result;
}
/**
* @dev Helper that prepares the initcode of the proxy with immutable args.
*
* An assembly variant of this function requires copying the `args` array, which can be efficiently done using
* `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using
* abi.encodePacked is more expensive but also more portable and easier to review.
*
* NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes.
* With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes.
*/
function _cloneCodeWithImmutableArgs(
address implementation,
bytes memory args
) private pure returns (bytes memory) {
if (args.length > 24531) revert CloneArgumentsTooLong();
return
abi.encodePacked(
hex"61",
uint16(args.length + 45),
hex"3d81600a3d39f3363d3d373d3d3d363d73",
implementation,
hex"5af43d82803e903d91602b57fd5bf3",
args
);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @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
// 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/Create2.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
* `CREATE2` can be used to compute in advance the address where a smart
* contract will be deployed, which allows for interesting new mechanisms known
* as 'counterfactual interactions'.
*
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
* information.
*/
library Create2 {
/**
* @dev There's no code to deploy.
*/
error Create2EmptyBytecode();
/**
* @dev Deploys a contract using `CREATE2`. The address where the contract
* will be deployed can be known in advance via {computeAddress}.
*
* The bytecode for a contract can be obtained from Solidity with
* `type(contractName).creationCode`.
*
* Requirements:
*
* - `bytecode` must not be empty.
* - `salt` must have not been used for `bytecode` already.
* - the factory must have a balance of at least `amount`.
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
*/
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
if (bytecode.length == 0) {
revert Create2EmptyBytecode();
}
assembly ("memory-safe") {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
// if no address was created, and returndata is not empty, bubble revert
if and(iszero(addr), not(iszero(returndatasize()))) {
let p := mload(0x40)
returndatacopy(p, 0, returndatasize())
revert(p, returndatasize())
}
}
if (addr == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
* `bytecodeHash` or `salt` will result in a new destination address.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
assembly ("memory-safe") {
let ptr := mload(0x40) // Get free memory pointer
// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
// |-------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |-------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
mstore(add(ptr, 0x40), bytecodeHash)
mstore(add(ptr, 0x20), salt)
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
mstore8(start, 0xff)
addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @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
pragma solidity ^0.8.24;
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/IHyperCoreHelper.sol";
/**
* @title Challenge
* @notice Trading challenge contract with prize pool escrow and HyperCore balance verification
* @dev Deployed as minimal proxies via ChallengeFactory
*/
contract Challenge is Initializable, AccessControlUpgradeable, ReentrancyGuardUpgradeable {
// Custom Errors
error InvalidPrizeToken();
error InvalidTimeRange();
error StartTimeMustBeInFuture();
error MustHaveAtLeastOneWinner();
error InvalidHelperAddress();
error InvalidAdminAddress();
error SplitsMustSumTo10000Bps();
error RegistrationClosed();
error AlreadyRegistered();
error NotWhitelisted();
error InvalidAddresses();
error IncorrectStartingBalance();
error NotAParticipant();
error ChallengeNotEnded();
error AlreadyFinalized();
error ChallengeCanceled();
error WinnersCountMismatch();
error WinnerNotRegistered();
error WinnerIsDisqualified();
error NotFinalized();
error NotAWinner();
error AlreadyClaimed();
error ParticipantDisqualified();
error SweepPeriodNotReached();
error NoFundsToSweep();
error AlreadyCanceled();
error NotCanceled();
error AlreadyRefunded();
error NoDepositToRefund();
error IndexOutOfBounds();
using SafeERC20 for IERC20;
// Participant information
struct Participant {
address primary; // Primary (root) wallet address
address proxy; // Privy-created proxy trading address
uint256 depositPaid; // Amount contributed to prize pool
uint64 registeredAt; // Registration timestamp
bool disqualified; // Disqualification status
bool claimed; // Prize claim status
bool refunded; // Refund claim status (for canceled challenges)
}
// Events
event ChallengeInitialized(
address indexed prizeToken,
uint256 requiredContribution,
uint256 requiredStartingBalance,
uint64 startTime,
uint64 endTime,
uint16[] splitsBps,
uint256 whitelistCount,
address indexed creator
);
event Registered(address indexed primary, address indexed proxy, uint256 amount);
event Disqualified(address indexed primary, bytes32 reasonHash);
event Finalized(address[] winners, uint256[] shares, uint256 totalPool);
event Claimed(address indexed primary, uint256 amount);
event Canceled();
event Refunded(address indexed primary, uint256 amount);
event Swept(uint256 amount);
// Core parameters (immutable after initialization)
IERC20 public prizeToken;
uint256 public requiredContribution;
uint256 public requiredStartingBalance;
uint64 public startTime;
uint64 public endTime;
uint16[] public splitsBps; // Basis points (10000 = 100%)
address public creator;
IHyperCoreHelper public hyperHelper;
address public admin;
// State
mapping(address => Participant) public participants;
address[] public participantList;
mapping(address => bool) public whitelist;
bool public whitelistEnabled;
uint256 public prizePool;
bool public finalized;
bool public canceled;
address[] public winners;
mapping(address => uint256) public winnerShares;
uint64 public finalizeTimestamp;
// Constants
uint256 private constant BASIS_POINTS = 10000;
uint64 private constant UNCLAIMED_SWEEP_PERIOD = 30 days;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Initialize the challenge (called by factory)
* @param _prizeToken ERC20 token for prize pool
* @param _requiredContribution Amount each participant must contribute
* @param _requiredStartingBalance Required starting balance on HyperCore
* @param _startTime Challenge start timestamp
* @param _endTime Challenge end timestamp
* @param _splitsBps Array of basis points for prize distribution
* @param _whitelist Array of whitelisted addresses (empty for open registration)
* @param _creator Address of challenge creator
* @param _hyperHelper HyperCore helper contract address
* @param _admin Deltadash admin address
*/
function initialize(
address _prizeToken,
uint256 _requiredContribution,
uint256 _requiredStartingBalance,
uint64 _startTime,
uint64 _endTime,
uint16[] memory _splitsBps,
address[] memory _whitelist,
address _creator,
address _hyperHelper,
address _admin
) external initializer {
if (_prizeToken == address(0)) revert InvalidPrizeToken();
if (_startTime >= _endTime) revert InvalidTimeRange();
if (_startTime <= block.timestamp) revert StartTimeMustBeInFuture();
if (_splitsBps.length == 0) revert MustHaveAtLeastOneWinner();
// TODO: Re-enable when HyperCore helper contract is available
// if (_hyperHelper == address(0)) revert InvalidHelperAddress();
if (_admin == address(0)) revert InvalidAdminAddress();
// Verify splits sum to 100%
uint256 totalBps = 0;
for (uint256 i = 0; i < _splitsBps.length; i++) {
totalBps += _splitsBps[i];
}
if (totalBps != BASIS_POINTS) revert SplitsMustSumTo10000Bps();
__AccessControl_init();
__ReentrancyGuard_init();
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
prizeToken = IERC20(_prizeToken);
requiredContribution = _requiredContribution;
requiredStartingBalance = _requiredStartingBalance;
startTime = _startTime;
endTime = _endTime;
splitsBps = _splitsBps;
creator = _creator;
// TODO: Re-enable when HyperCore helper contract is available
// hyperHelper = IHyperCoreHelper(_hyperHelper);
admin = _admin;
// Setup whitelist if provided
if (_whitelist.length > 0) {
whitelistEnabled = true;
for (uint256 i = 0; i < _whitelist.length; i++) {
whitelist[_whitelist[i]] = true;
}
}
emit ChallengeInitialized(
_prizeToken,
_requiredContribution,
_requiredStartingBalance,
_startTime,
_endTime,
_splitsBps,
_whitelist.length,
_creator
);
}
/**
* @notice Register for the challenge with prize contribution and balance verification
* @param primary Primary (root) wallet address
* @param proxy Privy-created proxy trading address on HyperCore
*/
function register(address primary, address proxy) external nonReentrant {
if (block.timestamp >= startTime) revert RegistrationClosed();
if (participants[primary].primary != address(0)) revert AlreadyRegistered();
if (whitelistEnabled && !whitelist[primary]) revert NotWhitelisted();
if (primary == address(0) || proxy == address(0)) revert InvalidAddresses();
// TODO: Re-enable when HyperCore helper contract is available
// Verify starting balance on HyperCore via helper
// uint256 balance = hyperHelper.accountEquity(proxy);
// if (balance != requiredStartingBalance) revert IncorrectStartingBalance();
// Transfer prize contribution from msg.sender
prizeToken.safeTransferFrom(msg.sender, address(this), requiredContribution);
// Record participant
participants[primary] = Participant({
primary: primary,
proxy: proxy,
depositPaid: requiredContribution,
registeredAt: uint64(block.timestamp),
disqualified: false,
claimed: false,
refunded: false
});
participantList.push(primary);
prizePool += requiredContribution;
emit Registered(primary, proxy, requiredContribution);
}
/**
* @notice Register for the challenge with a single transaction using a permit signature
* @param primary Primary (root) wallet address
* @param proxy Privy-created proxy trading address on HyperCore
* @param deadline The deadline for the permit signature
* @param v The recovery id of the signature
* @param r The r-value of the signature
* @param s The s-value of the signature
*/
function registerWithPermit(
address primary,
address proxy,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external nonReentrant {
if (block.timestamp >= startTime) revert RegistrationClosed();
if (participants[primary].primary != address(0)) revert AlreadyRegistered();
if (whitelistEnabled && !whitelist[primary]) revert NotWhitelisted();
if (primary == address(0) || proxy == address(0)) revert InvalidAddresses();
// Use permit to approve the transfer
IERC20Permit(address(prizeToken)).permit(
msg.sender,
address(this),
requiredContribution,
deadline,
v,
r,
s
);
// Transfer prize contribution
prizeToken.safeTransferFrom(msg.sender, address(this), requiredContribution);
// Record participant
participants[primary] = Participant({
primary: primary,
proxy: proxy,
depositPaid: requiredContribution,
registeredAt: uint64(block.timestamp),
disqualified: false,
claimed: false,
refunded: false
});
participantList.push(primary);
prizePool += requiredContribution;
emit Registered(primary, proxy, requiredContribution);
}
/**
* @notice Disqualify a participant (admin only)
* @param primary Primary address of participant to disqualify
* @param reasonHash Hash of disqualification reason
*/
function disqualify(address primary, bytes32 reasonHash) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (participants[primary].primary == address(0)) revert NotAParticipant();
participants[primary].disqualified = true;
emit Disqualified(primary, reasonHash);
}
/**
* @notice Finalize challenge and set winners (admin only)
* @param winnersOrdered Array of winner addresses in order (1st, 2nd, 3rd, etc.)
*/
function finalizeAndSetWinners(address[] calldata winnersOrdered)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
if (block.timestamp < endTime) revert ChallengeNotEnded();
if (finalized) revert AlreadyFinalized();
if (canceled) revert ChallengeCanceled();
if (winnersOrdered.length != splitsBps.length) revert WinnersCountMismatch();
// Validate winners and compute shares
for (uint256 i = 0; i < winnersOrdered.length; i++) {
address winner = winnersOrdered[i];
if (participants[winner].primary == address(0)) revert WinnerNotRegistered();
if (participants[winner].disqualified) revert WinnerIsDisqualified();
uint256 share = (prizePool * splitsBps[i]) / BASIS_POINTS;
winnerShares[winner] += share; // Accumulate for multi-placement winners
}
winners = winnersOrdered;
finalized = true;
finalizeTimestamp = uint64(block.timestamp);
// Prepare shares array for event
uint256[] memory shares = new uint256[](winnersOrdered.length);
for (uint256 i = 0; i < winnersOrdered.length; i++) {
shares[i] = winnerShares[winnersOrdered[i]];
}
emit Finalized(winnersOrdered, shares, prizePool);
}
/**
* @notice Claim prize winnings (winners only)
*/
function claim() external nonReentrant {
address primary = msg.sender;
if (!finalized) revert NotFinalized();
if (participants[primary].primary == address(0)) revert NotAParticipant();
if (winnerShares[primary] == 0) revert NotAWinner();
if (participants[primary].claimed) revert AlreadyClaimed();
if (participants[primary].disqualified) revert ParticipantDisqualified();
participants[primary].claimed = true;
uint256 amount = winnerShares[primary];
prizeToken.safeTransfer(primary, amount);
emit Claimed(primary, amount);
}
/**
* @notice Sweep unclaimed prizes to admin after 30 days (admin only)
*/
function sweepUnclaimedToAdmin() external onlyRole(DEFAULT_ADMIN_ROLE) {
if (!finalized) revert NotFinalized();
if (block.timestamp < finalizeTimestamp + UNCLAIMED_SWEEP_PERIOD) revert SweepPeriodNotReached();
uint256 balance = prizeToken.balanceOf(address(this));
if (balance == 0) revert NoFundsToSweep();
prizeToken.safeTransfer(admin, balance);
emit Swept(balance);
}
/**
* @notice Cancel challenge and enable refunds (admin only)
*/
function abortAndEnableRefunds() external onlyRole(DEFAULT_ADMIN_ROLE) {
if (finalized) revert AlreadyFinalized();
if (canceled) revert AlreadyCanceled();
canceled = true;
emit Canceled();
}
/**
* @notice Claim refund after challenge cancellation
*/
function claimRefund() external nonReentrant {
if (!canceled) revert NotCanceled();
address primary = msg.sender;
Participant storage participant = participants[primary];
if (participant.primary == address(0)) revert NotAParticipant();
if (participant.refunded) revert AlreadyRefunded();
if (participant.depositPaid == 0) revert NoDepositToRefund();
participant.refunded = true;
uint256 amount = participant.depositPaid;
prizeToken.safeTransfer(primary, amount);
emit Refunded(primary, amount);
}
/**
* @notice Batch refund for canceled challenges (admin helper)
* @param primaries Array of participant addresses to refund
*/
function batchRefund(address[] calldata primaries) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (!canceled) revert NotCanceled();
for (uint256 i = 0; i < primaries.length; i++) {
address primary = primaries[i];
Participant storage participant = participants[primary];
if (participant.primary != address(0) &&
!participant.refunded &&
participant.depositPaid > 0) {
participant.refunded = true;
uint256 amount = participant.depositPaid;
prizeToken.safeTransfer(primary, amount);
emit Refunded(primary, amount);
}
}
}
// ============ View Functions ============
/**
* @notice Get challenge parameters
*/
function getParams() external view returns (
address _prizeToken,
uint256 _requiredContribution,
uint256 _requiredStartingBalance,
uint64 _startTime,
uint64 _endTime,
uint16[] memory _splitsBps,
address _creator
) {
return (
address(prizeToken),
requiredContribution,
requiredStartingBalance,
startTime,
endTime,
splitsBps,
creator
);
}
/**
* @notice Get number of participants
*/
function participantsCount() external view returns (uint256) {
return participantList.length;
}
/**
* @notice Get participant address at index
*/
function participantAt(uint256 index) external view returns (address) {
if (index >= participantList.length) revert IndexOutOfBounds();
return participantList[index];
}
/**
* @notice Get participant details
*/
function getParticipant(address primary) external view returns (
address _primary,
address _proxy,
uint256 _depositPaid,
uint64 _registeredAt,
bool _disqualified,
bool _claimed,
bool _refunded
) {
Participant memory p = participants[primary];
return (
p.primary,
p.proxy,
p.depositPaid,
p.registeredAt,
p.disqualified,
p.claimed,
p.refunded
);
}
/**
* @notice Check if address is whitelisted
*/
function isWhitelisted(address addr) external view returns (bool) {
if (!whitelistEnabled) return true;
return whitelist[addr];
}
/**
* @notice Get winners and their shares
*/
function getWinners() external view returns (address[] memory, uint256[] memory) {
uint256[] memory shares = new uint256[](winners.length);
for (uint256 i = 0; i < winners.length; i++) {
shares[i] = winnerShares[winners[i]];
}
return (winners, shares);
}
/**
* @notice Get all splits in basis points
*/
function getSplitsBps() external view returns (uint16[] memory) {
return splitsBps;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/**
* @title IHyperCoreHelper
* @notice Interface for the HyperCore <-> HyperEVM helper contract
* @dev This interface allows reading balances and account equity from HyperCore
* The actual implementation is provided by Hyperliquid
*/
interface IHyperCoreHelper {
/**
* @notice Get the token balance for a proxy address on HyperCore
* @param proxy The trading proxy address to query
* @param token The token address (0x0 for native, or token contract address)
* @return The balance in the token's native decimals
*/
function balanceOf(address proxy, address token) external view returns (uint256);
/**
* @notice Get the total account equity for a proxy address on HyperCore
* @param proxy The trading proxy address to query
* @return The total account equity (typically in USD with 6 decimals)
*/
function accountEquity(address proxy) external view returns (uint256);
}{
"optimizer": {
"enabled": true,
"runs": 10000
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FailedDeployment","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"challenge","type":"address"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"address","name":"prizeToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"requiredContribution","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requiredStartingBalance","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"startTime","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"endTime","type":"uint64"}],"name":"ChallengeCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"challengeAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"challengeImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"challenges","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"challengesByCreator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"challengesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creator","type":"address"}],"name":"challengesCountByCreator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"prizeToken","type":"address"},{"internalType":"uint256","name":"requiredContribution","type":"uint256"},{"internalType":"uint256","name":"requiredStartingBalance","type":"uint256"},{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint16[]","name":"splitsBps","type":"uint16[]"},{"internalType":"address[]","name":"whitelist","type":"address[]"}],"name":"createChallenge","outputs":[{"internalType":"address","name":"challenge","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllChallenges","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creator","type":"address"}],"name":"getChallengesByCreator","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"updateAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a03461019d576001600160401b0390601f6145fc38819003918201601f19168301929190848411838510176101a257816020928492604096875283398101031261019d57516001600160a01b0392838216929183900361019d57331561018557600080546001600160a01b03198082163390811784558551939791949193919284167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08980a3851561014357508351906137108083019182118383101761012f57908291610eec8339039086f08015610125579084929116608052600154161760015551917f101b8081ff3b56bbf45deb824d86a3b0fd38b7e3dd42421105cf8abe9106db0b8180a3610d3390816101b982396080518181816105630152610afd0152f35b83513d87823e3d90fd5b634e487b7160e01b88526041600452602488fd5b62461bcd60e51b815260206004820152601560248201527f496e76616c69642061646d696e206164647265737300000000000000000000006044820152606490fd5b8151631e4fbdf760e01b815260006004820152602490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b600090813560e01c90816307beb24d14610b2157508063242fdb9114610ad05780633f00ddfa14610a3357806344dea67114610a15578063715018a614610997578063829ef1ac146108f7578063834c69cc146104385780638b3944e5146103d05780638da5cb5b1461039d5780638f1d37761461034d578063c85e6437146102a9578063e2f273bd146101b7578063f2fde38b146100f15763f851a440146100bb57600080fd5b346100ee57806003193601126100ee57602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b80fd5b50346100ee5760206003193601126100ee5761010b610b63565b610113610cac565b73ffffffffffffffffffffffffffffffffffffffff80911690811561018657600054827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b602483604051907f1e4fbdf70000000000000000000000000000000000000000000000000000000082526004820152fd5b50346100ee5760206003193601126100ee576101d1610b63565b6101d9610cac565b73ffffffffffffffffffffffffffffffffffffffff80911690811561024b57600154827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600155167f101b8081ff3b56bbf45deb824d86a3b0fd38b7e3dd42421105cf8abe9106db0b8380a380f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f496e76616c69642061646d696e206164647265737300000000000000000000006044820152fd5b50346100ee576020806003193601126103495773ffffffffffffffffffffffffffffffffffffffff91826102db610b63565b16815260038252604081209260405193848592858354928381520192855285852094905b8683831061032d57859061031582870383610bd5565b610329604051928284938452830190610b8b565b0390f35b86548216855260019687019689965094019391909101906102ff565b5080fd5b50346100ee5760206003193601126100ee57600435906002548210156100ee57602073ffffffffffffffffffffffffffffffffffffffff61038d84610c2e565b9190546040519260031b1c168152f35b50346100ee57806003193601126100ee5773ffffffffffffffffffffffffffffffffffffffff6020915416604051908152f35b50346100ee5760406003193601126100ee576103ea610b63565b6024359173ffffffffffffffffffffffffffffffffffffffff80921681526003602052604081209081548410156100ee575060209261042891610c94565b90549060031b1c16604051908152f35b50346100ee5760e06003193601126100ee57610452610b63565b906064359167ffffffffffffffff831683036103495760843567ffffffffffffffff811681036108f35760a4359267ffffffffffffffff84116100ee57366023850112156100ee578360040135936104a985610c16565b906104b76040519283610bd5565b85825260208201906024829760051b8201019036821161087757602401915b8183106108d85750505067ffffffffffffffff60c435116103495736602360c4350112156103495760c4356004013561050e81610c16565b9061051c6040519283610bd5565b80825260208201903660248260051b60c43501011161087757602460c43501915b60248260051b60c435010183106108a5575050506e5af43d82803e903d91602b57fd5bf37f0000000000000000000000000000000000000000000000000000000000000000763d602d80600a3d3981f3363d3d373d3d3d363d7300000062ffffff8260881c1617855260781b1760205273ffffffffffffffffffffffffffffffffffffffff6037600985f01695861561087b5773ffffffffffffffffffffffffffffffffffffffff6001541691873b156108775792909184926040519485937f02b1f8e600000000000000000000000000000000000000000000000000000000855273ffffffffffffffffffffffffffffffffffffffff8a1660048601526024356024860152604435604486015267ffffffffffffffff8c16606486015267ffffffffffffffff8916608486015261014060a4860152518061014486015261016485019290865b81811061085757505050816106a69160031986809695030160c4860152610b8b565b903360e484015284610104840152610124830152038183895af1801561084c57610807575b50906002546801000000000000000092838210156107d8576106f582600160409401600255610c2e565b81549060031b9073ffffffffffffffffffffffffffffffffffffffff89831b921b1916179055338152600360205220918254908110156107d85760209561074c8267ffffffffffffffff9560018795018155610c94565b81549060031b9073ffffffffffffffffffffffffffffffffffffffff89831b921b191617905573ffffffffffffffffffffffffffffffffffffffff60405195168552602435878601526044356040860152166060840152166080820152817fef1354d888ce4c6ed53fed4428745e7d3ff16ebdc17daa2309c813f49333f7be60a03393a3604051908152f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff811161081f57604052386106cb565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b825161ffff16855289975088965060209485019490920191600101610684565b8480fd5b60046040517fb06ebf3d000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff8335168335036108d457823581526020928301920161053d565b8580fd5b823561ffff811681036108d4578152602092830192016104d6565b8280fd5b50346100ee57806003193601126100ee57604051600280548083529083526020808301937f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace92915b82821061096a576103298561095681890382610bd5565b604051918291602083526020830190610b8b565b835473ffffffffffffffffffffffffffffffffffffffff168652948501946001938401939091019061093f565b50346100ee57806003193601126100ee576109b0610cac565b8073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346100ee57806003193601126100ee576020600254604051908152f35b50346100ee5760206003193601126100ee57600435600254811015610a725773ffffffffffffffffffffffffffffffffffffffff61038d602092610c2e565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496e646578206f7574206f6620626f756e6473000000000000000000000000006044820152fd5b50346100ee57806003193601126100ee57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b90503461034957602060031936011261034957604060209273ffffffffffffffffffffffffffffffffffffffff610b56610b63565b1681526003845220548152f35b6004359073ffffffffffffffffffffffffffffffffffffffff82168203610b8657565b600080fd5b90815180825260208080930193019160005b828110610bab575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101610b9d565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176107d857604052565b67ffffffffffffffff81116107d85760051b60200190565b600254811015610c655760026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0190600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8054821015610c655760005260206000200190600090565b73ffffffffffffffffffffffffffffffffffffffff600054163303610ccd57565b60246040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152fdfea264697066735822122061cfd757ccde53a0275503145d3c8250929a4b74de3aace7b52a8c8eb279a39264736f6c6343000818003360808060405234620000bd577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff8260401c16620000ae57506001600160401b036002600160401b03198282160162000068575b60405161364d9081620000c38239f35b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a138808062000058565b63f92ee8a960e01b8152600490fd5b600080fdfe608080604052600436101561001357600080fd5b60009060e08235811c91826301ffc9a714612d055750816302b1f8e6146123a357816302d05d3f1461237c578163065bab2d1461232057816309e69ede146122605781630e6fdaa11461222d578163248a9ca3146121e15781632f2ff15d146121845781633197cbb61461215957816336568abe146120f95781633af32abf146120cb5781633f9942ff146120a55781634e71d92d14611ef857816351fb012d14611ed55781635bd2a70a14611aeb5781635e615a6b14611768578163611bea361461173a57816370afcf7d146117125781637143059f14611619578163719ce73e146115fb57816378e97925146115d35781637f3707221461152357816391d14854146114bc57816393f1be961461116d575080639b19251a146111305780639e89fcbe14610dbd578063a217fddf14610da1578063a2fb117514610d5e578063a9369a6214610b99578063aa6773541461084d578063b3f05b971461082a578063b53e9dfe1461080c578063b5545a3c14610697578063d0ef024a14610671578063d547741f14610610578063dd60c898146105f2578063df15c37e146104c4578063e09edb3a146104a6578063ee9b89721461047f578063f1935b0e146103ac578063f5ba401414610374578063f851a4401461034d5763fff96005146101fc57600080fd5b3461034a5761020a36612f2b565b6102126132c1565b600d5460ff91600891821c83161561032057845b818110610231578580f35b8061024761024260019385896130b9565b6130c9565b6001600160a01b039081811691828a5260209087825260408b208b8282541615158061030f575b80610302575b610285575b50505050505001610226565b7fd7dee2702d63ad89917b6a4da9981c90c4d24f8c2bdfd64c604ecae57d8d06519460028360036102f095016a01000000000000000000007fffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff82541617905501549384925416613467565b604051908152a238808080808b610279565b5060028201541515610274565b508a600383015460501c161561026e565b60046040517f76f1a003000000000000000000000000000000000000000000000000000000008152fd5b80fd5b503461034a578060031936011261034a5760206001600160a01b0360075416604051908152f35b503461034a57602060031936011261034a5760406020916001600160a01b0361039b612da5565b168152600f83522054604051908152f35b503461034a578060031936011261034a576103c56132c1565b600d5460ff81166104555760ff8160081c1661042b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017600d557f1afb0ae590df277bcb3a37f88612725bf1f7df4755792b1548a7efe77985ff778180a180f35b60046040517f4b06e2b6000000000000000000000000000000000000000000000000000000008152fd5b60046040517f475a2535000000000000000000000000000000000000000000000000000000008152fd5b503461034a578060031936011261034a5760206001600160a01b0360065416604051908152f35b503461034a578060031936011261034a576020600254604051908152f35b503461034a578060031936011261034a57600e54906104e2826130dd565b91815b8181106105b1575060405190819381835260208093018092600e86527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd90865b818110610594575050508561053b910386612e35565b604051948593604085019160408652518092526060850193955b82811061057457858061057087878382036020850152612ff0565b0390f35b86516001600160a01b031685529581019587955093810193600101610555565b82546001600160a01b031684529286019260019283019201610525565b806001600160a01b036105c960019396949596612ef4565b90549060031b1c168552600f60205260408520546105e78285613024565b5201929190926104e5565b503461034a578060031936011261034a576020600954604051908152f35b503461034a57604060031936011261034a5761066d600435610630612dc0565b908084527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020526106686001604086200154613332565b613377565b5080f35b503461034a578060031936011261034a576001600160a01b036020915416604051908152f35b503461034a578060031936011261034a576106b061340d565b60ff600d5460081c1615610320573381526008602052604081206001600160a01b039081815416156107e257600381019081549060ff8260501c166107b8576002015492831561078e5761073b926a01000000000000000000007fffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff8694161790553390855416613467565b6040519081527fd7dee2702d63ad89917b6a4da9981c90c4d24f8c2bdfd64c604ecae57d8d065160203392a260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005580f35b60046040517fba3ad750000000000000000000000000000000000000000000000000000000008152fd5b60046040517fa85e6f1a000000000000000000000000000000000000000000000000000000008152fd5b60046040517f179e806d000000000000000000000000000000000000000000000000000000008152fd5b503461034a578060031936011261034a576020600154604051908152f35b503461034a578060031936011261034a57602060ff600d54166040519015158152f35b503461034a57604060031936011261034a57610867612da5565b61086f612dc0565b9061087861340d565b67ffffffffffffffff918260035416421015610b6f576001600160a01b039182811692838652600860205280604087205416610b455760ff600b541680610b2e575b610b045783158015610afa575b610ad057610a6d9286610a2b866109ef856108ef610a689786541660015490309033906134cf565b6001549a600360405161090181612dea565b858152836020820199169d8e8a526040820190815260608201998442168b5260808301958a87528060408c60a087019b818d5260c088019e8f528152600860205220945116907fffffffffffffffffffffffff000000000000000000000000000000000000000091828654161785556001850192511690825416179055516002820155019651167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000087541617865551151585907fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff68ff0000000000000000835492151560401b169116179055565b5183547fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff1690151560481b69ff00000000000000000016178355565b5181547fffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff1690151560501b6aff0000000000000000000016179055565b61312c565b7f199098452639b249bef6f727bc09ce903cece47ca72a8518bef9367ad39b6de76020600154610a9f81600c54613038565b600c55604051908152a360017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005580f35b60046040517fca07b5fb000000000000000000000000000000000000000000000000000000008152fd5b50808316156108c7565b60046040517f584a7938000000000000000000000000000000000000000000000000000000008152fd5b50838652600a60205260ff604087205416156108ba565b60046040517f3a81d6fc000000000000000000000000000000000000000000000000000000008152fd5b60046040517f2fc209f3000000000000000000000000000000000000000000000000000000008152fd5b503461034a578060031936011261034a57610bb26132c1565b60ff600d541615610d345767ffffffffffffffff62278d00816010541601818111610d0757164210610cdd576001600160a01b0380825416906040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481865afa908115610cd2578491610c9c575b508015610c7257610c68817f7f221332ee403570bf4d61630b58189ea566ff1635269001e9df6a890f413dd8946020946007541690613467565b604051908152a180f35b60046040517f56727c09000000000000000000000000000000000000000000000000000000008152fd5b90506020813d602011610cca575b81610cb760209383612e35565b81010312610cc6575138610c2e565b8380fd5b3d9150610caa565b6040513d86823e3d90fd5b60046040517f52d9521a000000000000000000000000000000000000000000000000000000008152fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b60046040517f1bee0d5a000000000000000000000000000000000000000000000000000000008152fd5b503461034a57602060031936011261034a5760043590600e5482101561034a5760206001600160a01b03610d9184612ef4565b9190546040519260031b1c168152f35b503461034a578060031936011261034a57602090604051908152f35b503461034a5760c060031936011261034a57610dd7612da5565b610ddf612dc0565b906064359160ff8316809303610cc657610df761340d565b67ffffffffffffffff918260035416421015610b6f576001600160a01b039182821692838752600860205280604088205416610b455760ff600b541680611119575b610b04578315801561110f575b610ad05780875416876001978854833b1561110b5760e4908360405195869485937fd505accf00000000000000000000000000000000000000000000000000000000855233600486015230602486015260448501526044356064850152608484015260843560a484015260a43560c48401525af18015611100576110bf575b5080879182541687543033610ed9936134cf565b86549260405196610ee988612dea565b86885282602089019216978883526040810195865260608101958242168752608082019386855260a08301958787528060c0850198808a528c8152600860205260409020945116907fffffffffffffffffffffffff000000000000000000000000000000000000000091828654161785558d85019251169082541617905551600282015560030194511684547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016178455511515610fde9084907fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff68ff0000000000000000835492151560401b169116179055565b5182547fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff1690151560481b69ff000000000000000000161782555181547fffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff1690151560501b6aff000000000000000000001617905561105c9061312c565b825480600c549061106c91613038565b600c5560405190815260207f199098452639b249bef6f727bc09ce903cece47ca72a8518bef9367ad39b6de791a37f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005580f35b8581989298116110d3576040529538610ec5565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d8a823e3d90fd5b8280fd5b5080821615610e46565b50838752600a60205260ff60408820541615610e39565b503461034a57602060031936011261034a5760ff60406020926001600160a01b03611159612da5565b168152600a84522054166040519015158152f35b823461034a578060031936011261034a5790604051918280936004548082526020948580930191600486527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b955b81600f8201106113e957846112569754938383106113d3575b8383106113ba575b8383106113a2575b838310611389575b838310611370575b838310611357575b83831061133e575b838310611325575b83831061130c575b8383106112f3575b8383106112da575b8383106112c1575b8383106112a8575b83831061128f575b838310611278575b50501061126a575b5090500383612e35565b610570604051928284938452830190612f78565b60f01c81520183908661124c565b9461ffff85600194971c168152019301848a611244565b91948160019161ffff8760d01c1681520195019161123c565b91948160019161ffff8760c01c16815201950191611234565b91948160019161ffff8760b01c1681520195019161122c565b91948160019161ffff8760a01c16815201950191611224565b91948160019161ffff8760901c1681520195019161121c565b91948160019161ffff8760801c16815201950191611214565b91948160019161ffff8760701c1681520195019161120c565b91948160019161ffff8760601c16815201950191611204565b91948160019161ffff8760501c168152019501916111fc565b91948160019161ffff8760401c168152019501916111f4565b91948160019161ffff8760301c168152019501916111ec565b91948160019161ffff87831c168152019501916111e4565b91948160019161ffff8760101c168152019501916111dc565b91948160019161ffff87168152019501916111d4565b926010929550600191945061020090875461ffff80821683528082871c168b84015280828c1c16604084015280828082818d8282606092828260301c16848d01526080908c82858560401c169101528c60a095858560501c16878301528560c09a8b921c16910152838360701c16908d01521c166101008a0152828260901c166101208a01521c16610140870152828260b01c166101608701521c16610180840152808260d01c166101a084015281891c166101c083015260f01c6101e0820152019501910192859287949592956111bb565b823461034a57604060031936011261034a5760ff60406020926114dd612dc0565b60043582527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680085526001600160a01b038383209116825284522054166040519015158152f35b823461034a57604060031936011261034a5761153d612da5565b6115456132c1565b6001600160a01b03809116908183526008602052604083205416156107e257808252600860205260036040832001680100000000000000007fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff8254161790557f1512e1dc29352e822b4021e4d3963167c8f3594ea1eb05500a59a7816725f28460206040516024358152a280f35b823461034a578060031936011261034a57602067ffffffffffffffff60035416604051908152f35b823461034a578060031936011261034a576020600c54604051908152f35b823461034a57602060031936011261034a5760406001600160a01b03918261163f612da5565b1681526008602052209061057060c06040519361165b85612dea565b838154169384865260018201541694856020820152600360028301549283604084015201549167ffffffffffffffff83169081606084015260ff8460401c1615159283608082015260ff808660481c161515958660a084015260501c16151595869101526040519788978895929360c0959298979467ffffffffffffffff9260e089019a6001600160a01b038092168a52166020890152604088015216606086015215156080850152151560a08401521515910152565b823461034a578060031936011261034a57602067ffffffffffffffff60105416604051908152f35b823461034a57602060031936011261034a576004359060045482101561034a57602061ffff610d9184612fb0565b905034611ae75781600319360112611ae7576001600160a01b0380835416906001938454936002549260035467ffffffffffffffff916005541694604051978895600454808b526020809b0191600481527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b82600f830110611a1f57928c9d8a936118b39c9d9e9361188496549285838310611a0b575b8383106119f4575b8383106119de575b8383106119c7575b8383106119b0575b838310611999575b838310611982575b83831061196b575b838310611954575b83831061193d575b838310611926575b83831061190f575b8383106118f8575b8383106118e1575b8d8484106118cb575b505050106118bd575b5090500387612e35565b604051998a998a528901526040880152818116606088015260401c1660808601528060a0860152840190612f78565b9060c08301520390f35b60f01c8152018c903861187a565b85901c61ffff168652909401930138858d611871565b81929561ffff8660d01c1681520194019085611868565b81929561ffff8660c01c1681520194019085611860565b81929561ffff8660b01c1681520194019085611858565b81929561ffff8660a01c1681520194019085611850565b81929561ffff8660901c1681520194019085611848565b81929561ffff8660801c1681520194019085611840565b81929561ffff8660701c1681520194019085611838565b81929561ffff8660601c1681520194019085611830565b81929561ffff8660501c1681520194019085611828565b81929561ffff8660401c1681520194019085611820565b81929561ffff8660301c1681520194019085611818565b81929561ffff86831c1681520194019085611810565b81929561ffff8660101c1681520194019085611808565b81929561ffff861681520194019085611800565b928d6102006010928f8c9088548092819261ffff938491828216885282828c1c16818901521c16604086015282828082816060828260301c16818c0152828260808d81848460401c169101528d60a094848460501c16868301528460c0998a921c169101528d8a848460701c169101521c166101008c0152828260901c166101208c01521c16610140890152828260b01c166101608901521c16610180860152828260d01c166101a08601521c166101c083015260f01c6101e08201520194019101906117db565b5080fd5b823461034a57611afa36612f2b565b611b059291926132c1565b67ffffffffffffffff9260038460035460401c164210611eab57600d549060ff9160ff81166104555760ff60089160081c16611e81576004548503611e5757855b858110611d455750505050838211611d1857680100000000000000008211611d1857600e5482600e55808310611ce2575b5080939193600e8452835b858110611ca1575050600191600160ff19600d541617600d5542167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006010541617601055611bcf846130dd565b835b858110611c665750600c54946040519381606086016060875252608085019391865b818110611c3d57877fedb0a93e843e57147c9a010516fab3c5e332aac3dc438d6d4327258566a4b3d088808c611c318b8b8482036020860152612ff0565b9060408301520390a180f35b909183956001600160a01b03611c538396612dd6565b1681526020908101960193929101611bf3565b92836001600160a01b03611c806102428997859a886130b9565b168652600f6020526040862054611c978285613024565b5201949294611bd1565b6001906020611cb2849896986130c9565b930192817fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd015501949294611b82565b611d1290837fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd9182019101613074565b84611b77565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6001600160a01b0380611d5c610242848a8a6130b9565b169081895260209084825260408a20541615611e2d57818952838152858560408b20015460401c16611e0357600c549161ffff611d9885612fb0565b905490881b1c1692838102938185041490151715611dd6576001939291600f918b5252611dce61271060408b2092048254613038565b905501611b46565b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b60046040517f8d641af7000000000000000000000000000000000000000000000000000000008152fd5b60046040517f0a866adb000000000000000000000000000000000000000000000000000000008152fd5b60046040517fa1e14eae000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd65ab5b7000000000000000000000000000000000000000000000000000000008152fd5b60046040517f996afe4a000000000000000000000000000000000000000000000000000000008152fd5b823461034a578060031936011261034a57602060ff600b54166040519015158152f35b823461034a578060031936011261034a57611f1161340d565b60ff600d541615610d34573381526020600881526001600160a01b039081604084205416156107e257338352600f815260408320541561207b573383526008815260ff600360408520015460481c16612051573383526008815260ff600360408520015460401c16612027577fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a90338452600881526003604085200169010000000000000000007fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff825416179055600f8152611ff7604085205480943390875416613467565b6040519283523392a260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005580f35b60046040517f0b3482ba000000000000000000000000000000000000000000000000000000008152fd5b60046040517f646cf558000000000000000000000000000000000000000000000000000000008152fd5b60046040517fb19a9f82000000000000000000000000000000000000000000000000000000008152fd5b823461034a578060031936011261034a57602060ff600d5460081c166040519015158152f35b823461034a57602060031936011261034a5760206120ef6120ea612da5565b61308b565b6040519015158152f35b823461034a57604060031936011261034a57612113612dc0565b336001600160a01b0382160361212f5761066d90600435613377565b60046040517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b823461034a578060031936011261034a57602067ffffffffffffffff60035460401c16604051908152f35b823461034a57604060031936011261034a5761066d6004356121a4612dc0565b908084527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020526121dc6001604086200154613332565b613221565b823461034a57602060031936011261034a576001604060209260043581527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268008452200154604051908152f35b823461034a57602060031936011261034a576004359060095482101561034a5760206001600160a01b03610d9184612e8e565b823461034a57602060031936011261034a5760406001600160a01b039182612286612da5565b16815260086020522090610570818354169160018401541692600360028201549101549360405194859460ff8260501c169360ff8360481c169367ffffffffffffffff60ff8560401c169416928895929360c0959298979467ffffffffffffffff9260e089019a6001600160a01b038092168a52166020890152604088015216606086015215156080850152151560a08401521515910152565b823461034a57602060031936011261034a57600435600954811015612352576001600160a01b03610d91602092612e8e565b60046040517f4e23d035000000000000000000000000000000000000000000000000000000008152fd5b823461034a578060031936011261034a5760206001600160a01b0360055416604051908152f35b823461034a5761014060031936011261034a576123be612da5565b6064359167ffffffffffffffff8316830361034a5767ffffffffffffffff608435166084350361034a5760a4359067ffffffffffffffff821161034a573660238301121561034a5781600401359261241584612e76565b926124236040519485612e35565b84845260208401906024829660051b82010190368211612d0157602401915b818310612ce65750505060c4359467ffffffffffffffff861161110b573660238701121561110b5785600401359561247987612e76565b966124876040519889612e35565b8088526024602089019160051b83010191368311612ce257602401905b828210612cca5750505060e435916001600160a01b0383168303610cc657610104356001600160a01b03811603610cc6576001600160a01b0361012435166101243503610cc6577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549167ffffffffffffffff83161580612cbc575b600167ffffffffffffffff8516149081612cb2575b159081612ca9575b50612c7f5760017fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005560ff8360401c1615612c2a575b6001600160a01b03821615612c005767ffffffffffffffff6084351667ffffffffffffffff82161015612bd6574267ffffffffffffffff82161115612bac57855115612b82576001600160a01b03610124351615612b5857849785985b87518a10156126205761261860019161ffff6126108d8c613024565b511690613038565b9901986125f4565b908861271089949303612b2e5761263561353e565b61263d61353e565b61264561353e565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00556126756101243561316f565b506001600160a01b0385167fffffffffffffffffffffffff00000000000000000000000000000000000000008954161788556024356001556044356002556003546fffffffffffffffff000000000000000060843560401b16907fffffffffffffffffffffffffffffffff0000000000000000000000000000000067ffffffffffffffff86169116171760035583519067ffffffffffffffff8211612b0157680100000000000000008211612b015760045482600455808310612a36575b509060048952885b8160041c81106129d657507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff08116808203612964575b5050506001600160a01b0386167fffffffffffffffffffffffff000000000000000000000000000000000000000060055416176005556001600160a01b0361012435167fffffffffffffffffffffffff00000000000000000000000000000000000000006007541617600755805161290a575b7f1e46d0911bb122a20b8fd093c4dd79dff64291aee93ac7c238210811e5da8311916001600160a01b038060ff9861285d67ffffffffffffffff9551976040519687966024358852604435602089015216604087015267ffffffffffffffff60843516606087015260c0608087015260c0860190612f78565b9660a0850152169516930390a360401c16156128765780f35b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b93929190600160ff19600b541617600b55865b855181101561295857806001600160a01b0361293b60019389613024565b51168952600a602052604089208260ff198254161790550161291d565b509293919290916127e4565b9189928a5b81840381106129a35750505060041c7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0155878080612771565b90919360206129cc60019261ffff8851169085851b60031b9161ffff809116831b921b19161790565b9501929101612969565b898a5b60108110612a0e57507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b82015560010161273b565b845190949160019160209161ffff600489901b81811b199092169216901b17920194016129d9565b600f612a9e91601e8560011b1680612aa4575b500160041c7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01600f840160041c7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01613074565b89612733565b7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19a83870160041c01907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160200360031b1c1690558c612a49565b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60046040517f7b476b83000000000000000000000000000000000000000000000000000000008152fd5b60046040517f05bb467c000000000000000000000000000000000000000000000000000000008152fd5b60046040517f9ff3f719000000000000000000000000000000000000000000000000000000008152fd5b60046040517f9519947b000000000000000000000000000000000000000000000000000000008152fd5b60046040517f536a71af000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe5b318af000000000000000000000000000000000000000000000000000000008152fd5b680100000000000000017fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000008416177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055612597565b60046040517ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b9050158961253d565b303b159150612535565b5060ff8360401c1615612520565b60208091612cd784612dd6565b8152019101906124a4565b8580fd5b823561ffff81168103612ce257815260209283019201612442565b8480fd5b839034611ae7576020600319360112611ae7576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361110b57602092507f7965db0b000000000000000000000000000000000000000000000000000000008114908115612d7b575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612d74565b600435906001600160a01b0382168203612dbb57565b600080fd5b602435906001600160a01b0382168203612dbb57565b35906001600160a01b0382168203612dbb57565b60e0810190811067ffffffffffffffff821117612e0657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612e0657604052565b67ffffffffffffffff8111612e065760051b60200190565b600954811015612ec55760096000527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0190600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600e54811015612ec557600e6000527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd0190600090565b906020600319830112612dbb5760043567ffffffffffffffff92838211612dbb5780602383011215612dbb578160040135938411612dbb5760248460051b83010111612dbb576024019190565b90815180825260208080930193019160005b828110612f98575050505090565b835161ffff1685529381019392810192600101612f8a565b90600454821015612ec5576004600052601e8260041c7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b019260011b1690565b90815180825260208080930193019160005b828110613010575050505090565b835185529381019392810192600101613002565b8051821015612ec55760209160051b010190565b9190820180921161304557565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81811061307f575050565b60008155600101613074565b60ff600b5416156130b3576001600160a01b0316600052600a60205260ff6040600020541690565b50600190565b9190811015612ec55760051b0190565b356001600160a01b0381168103612dbb5790565b906130e782612e76565b6130f46040519182612e35565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06131228294612e76565b0190602036910137565b60095468010000000000000000811015612e06578060016131509201600955612e8e565b6001600160a01b039291928084549260031b9316831b921b1916179055565b6001600160a01b031660008181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d60205260408120549091907f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268009060ff1661321c578280526020526040822081835260205260408220600160ff1982541617905533917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b505090565b906000918083527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800806020526001600160a01b036040852093169283855260205260ff604085205416156000146132bb578184526020526040832082845260205260408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b50505090565b3360009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604081205460ff16156132fb5750565b604490604051907fe2517d3f0000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000203360005260205260ff60406000205416156132fb5750565b906000918083527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800806020526001600160a01b036040852093169283855260205260ff6040852054166000146132bb57818452602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00600281541461343d5760029055565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff841117612e06576134cd92604052613597565b565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612e06576134cd92604052613597565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561356d57565b60046040517fd7e6bcf8000000000000000000000000000000000000000000000000000000008152fd5b906000602091828151910182855af11561360b576000513d61360257506001600160a01b0381163b155b6135c85750565b6024906001600160a01b03604051917f5274afe7000000000000000000000000000000000000000000000000000000008352166004820152fd5b600114156135c1565b6040513d6000823e3d90fdfea26469706673582212204af082915857906f9adc0684174d01435daf879e28ed6bdc7e32b0ed2dfdb42a64736f6c634300081800330000000000000000000000005d9310ed92ba615fcfd62941727059660eef5533
Deployed Bytecode
0x608080604052600436101561001357600080fd5b600090813560e01c90816307beb24d14610b2157508063242fdb9114610ad05780633f00ddfa14610a3357806344dea67114610a15578063715018a614610997578063829ef1ac146108f7578063834c69cc146104385780638b3944e5146103d05780638da5cb5b1461039d5780638f1d37761461034d578063c85e6437146102a9578063e2f273bd146101b7578063f2fde38b146100f15763f851a440146100bb57600080fd5b346100ee57806003193601126100ee57602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b80fd5b50346100ee5760206003193601126100ee5761010b610b63565b610113610cac565b73ffffffffffffffffffffffffffffffffffffffff80911690811561018657600054827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b602483604051907f1e4fbdf70000000000000000000000000000000000000000000000000000000082526004820152fd5b50346100ee5760206003193601126100ee576101d1610b63565b6101d9610cac565b73ffffffffffffffffffffffffffffffffffffffff80911690811561024b57600154827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600155167f101b8081ff3b56bbf45deb824d86a3b0fd38b7e3dd42421105cf8abe9106db0b8380a380f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f496e76616c69642061646d696e206164647265737300000000000000000000006044820152fd5b50346100ee576020806003193601126103495773ffffffffffffffffffffffffffffffffffffffff91826102db610b63565b16815260038252604081209260405193848592858354928381520192855285852094905b8683831061032d57859061031582870383610bd5565b610329604051928284938452830190610b8b565b0390f35b86548216855260019687019689965094019391909101906102ff565b5080fd5b50346100ee5760206003193601126100ee57600435906002548210156100ee57602073ffffffffffffffffffffffffffffffffffffffff61038d84610c2e565b9190546040519260031b1c168152f35b50346100ee57806003193601126100ee5773ffffffffffffffffffffffffffffffffffffffff6020915416604051908152f35b50346100ee5760406003193601126100ee576103ea610b63565b6024359173ffffffffffffffffffffffffffffffffffffffff80921681526003602052604081209081548410156100ee575060209261042891610c94565b90549060031b1c16604051908152f35b50346100ee5760e06003193601126100ee57610452610b63565b906064359167ffffffffffffffff831683036103495760843567ffffffffffffffff811681036108f35760a4359267ffffffffffffffff84116100ee57366023850112156100ee578360040135936104a985610c16565b906104b76040519283610bd5565b85825260208201906024829760051b8201019036821161087757602401915b8183106108d85750505067ffffffffffffffff60c435116103495736602360c4350112156103495760c4356004013561050e81610c16565b9061051c6040519283610bd5565b80825260208201903660248260051b60c43501011161087757602460c43501915b60248260051b60c435010183106108a5575050506e5af43d82803e903d91602b57fd5bf37f00000000000000000000000013b031a0fea7af2019fd55b2a6195f3f1801b9fa763d602d80600a3d3981f3363d3d373d3d3d363d7300000062ffffff8260881c1617855260781b1760205273ffffffffffffffffffffffffffffffffffffffff6037600985f01695861561087b5773ffffffffffffffffffffffffffffffffffffffff6001541691873b156108775792909184926040519485937f02b1f8e600000000000000000000000000000000000000000000000000000000855273ffffffffffffffffffffffffffffffffffffffff8a1660048601526024356024860152604435604486015267ffffffffffffffff8c16606486015267ffffffffffffffff8916608486015261014060a4860152518061014486015261016485019290865b81811061085757505050816106a69160031986809695030160c4860152610b8b565b903360e484015284610104840152610124830152038183895af1801561084c57610807575b50906002546801000000000000000092838210156107d8576106f582600160409401600255610c2e565b81549060031b9073ffffffffffffffffffffffffffffffffffffffff89831b921b1916179055338152600360205220918254908110156107d85760209561074c8267ffffffffffffffff9560018795018155610c94565b81549060031b9073ffffffffffffffffffffffffffffffffffffffff89831b921b191617905573ffffffffffffffffffffffffffffffffffffffff60405195168552602435878601526044356040860152166060840152166080820152817fef1354d888ce4c6ed53fed4428745e7d3ff16ebdc17daa2309c813f49333f7be60a03393a3604051908152f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff811161081f57604052386106cb565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b825161ffff16855289975088965060209485019490920191600101610684565b8480fd5b60046040517fb06ebf3d000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff8335168335036108d457823581526020928301920161053d565b8580fd5b823561ffff811681036108d4578152602092830192016104d6565b8280fd5b50346100ee57806003193601126100ee57604051600280548083529083526020808301937f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace92915b82821061096a576103298561095681890382610bd5565b604051918291602083526020830190610b8b565b835473ffffffffffffffffffffffffffffffffffffffff168652948501946001938401939091019061093f565b50346100ee57806003193601126100ee576109b0610cac565b8073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346100ee57806003193601126100ee576020600254604051908152f35b50346100ee5760206003193601126100ee57600435600254811015610a725773ffffffffffffffffffffffffffffffffffffffff61038d602092610c2e565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496e646578206f7574206f6620626f756e6473000000000000000000000000006044820152fd5b50346100ee57806003193601126100ee57602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000013b031a0fea7af2019fd55b2a6195f3f1801b9fa168152f35b90503461034957602060031936011261034957604060209273ffffffffffffffffffffffffffffffffffffffff610b56610b63565b1681526003845220548152f35b6004359073ffffffffffffffffffffffffffffffffffffffff82168203610b8657565b600080fd5b90815180825260208080930193019160005b828110610bab575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101610b9d565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176107d857604052565b67ffffffffffffffff81116107d85760051b60200190565b600254811015610c655760026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0190600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8054821015610c655760005260206000200190600090565b73ffffffffffffffffffffffffffffffffffffffff600054163303610ccd57565b60246040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152fdfea264697066735822122061cfd757ccde53a0275503145d3c8250929a4b74de3aace7b52a8c8eb279a39264736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005d9310ed92ba615fcfd62941727059660eef5533
-----Decoded View---------------
Arg [0] : _admin (address): 0x5d9310eD92bA615fCFD62941727059660EEF5533
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000005d9310ed92ba615fcfd62941727059660eef5533
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in HYPE
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.