Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
0x60e06040 | 17379141 | 394 days ago | IN | Create: FeeDistributor | 0 ETH | 0.16555823 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
FeeDistributor
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "../@openzeppelin/contracts/utils/introspection/ERC165.sol"; import "../@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import "../feeDistributorFactory/IFeeDistributorFactory.sol"; import "../assetRecovering/OwnableTokenRecoverer.sol"; import "./IFeeDistributor.sol"; import "../oracle/IOracle.sol"; /** * @notice Should be a Oracle contract * @param _passedAddress passed address that does not support IOracle interface */ error FeeDistributor__NotOracle(address _passedAddress); /** * @notice Initial client-only CL rewards must be zero * @param _firstValidatorId passed value for firstValidatorId */ error FeeDistributor__InvalidFirstValidatorId(uint64 _firstValidatorId); /** * @notice Initial client-only CL rewards must be zero * @param _validatorCount passed value for validatorCount */ error FeeDistributor__InvalidValidatorCount(uint16 _validatorCount); /** * @notice Should be a FeeDistributorFactory contract * @param _passedAddress passed address that does not support IFeeDistributorFactory interface */ error FeeDistributor__NotFactory(address _passedAddress); /** * @notice Service address should be a secure P2P address, not zero. */ error FeeDistributor__ZeroAddressService(); /** * @notice Client address should be different from service address. * @param _passedAddress passed client address that equals to the service address */ error FeeDistributor__ClientAddressEqualsService(address _passedAddress); /** * @notice Client address should be an actual client address, not zero. */ error FeeDistributor__ZeroAddressClient(); /** * @notice Client basis points should be >= 0 and <= 10000 * @param _clientBasisPoints passed incorrect client basis points */ error FeeDistributor__InvalidClientBasisPoints(uint96 _clientBasisPoints); /** * @notice The sum of (Client basis points + Referral basis points) should be >= 0 and <= 10000 * @param _clientBasisPoints passed client basis points * @param _referralBasisPoints passed referral basis points */ error FeeDistributor__ClientPlusReferralBasisPointsExceed10000(uint96 _clientBasisPoints, uint96 _referralBasisPoints); /** * @notice Referrer address should be different from service address. * @param _passedAddress passed referrer address that equals to the service address */ error FeeDistributor__ReferrerAddressEqualsService(address _passedAddress); /** * @notice Referrer address should be different from client address. * @param _passedAddress passed referrer address that equals to the client address */ error FeeDistributor__ReferrerAddressEqualsClient(address _passedAddress); /** * @notice Only factory can call `initialize`. * @param _msgSender sender address. * @param _actualFactory the actual factory address that can call `initialize`. */ error FeeDistributor__NotFactoryCalled(address _msgSender, IFeeDistributorFactory _actualFactory); /** * @notice `initialize` should only be called once. * @param _existingClient address of the client with which the contact has already been initialized. */ error FeeDistributor__ClientAlreadySet(address _existingClient); /** * @notice Cannot call `withdraw` if the client address is not set yet. * @dev The client address is supposed to be set by the factory. */ error FeeDistributor__ClientNotSet(); /** * @notice basisPoints of the referrer must be zero if referrer address is empty. * @param _referrerBasisPoints basisPoints of the referrer. */ error FeeDistributor__ReferrerBasisPointsMustBeZeroIfAddressIsZero(uint96 _referrerBasisPoints); /** * @notice service should be able to receive ether. * @param _service address of the service. */ error FeeDistributor__ServiceCannotReceiveEther(address _service); /** * @notice client should be able to receive ether. * @param _client address of the client. */ error FeeDistributor__ClientCannotReceiveEther(address _client); /** * @notice referrer should be able to receive ether. * @param _referrer address of the referrer. */ error FeeDistributor__ReferrerCannotReceiveEther(address _referrer); /** * @notice zero ether balance */ error FeeDistributor__NothingToWithdraw(); /** * @notice cannot withdraw until rewards (CL+EL) are enough to be split */ error FeeDistributor__WaitForEnoughRewardsToWithdraw(); /** * @notice Throws if called by any account other than the client. * @param _caller address of the caller * @param _client address of the client */ error FeeDistributor__CallerNotClient(address _caller, address _client); /** * @title Contract receiving MEV and priority fees * and distributing them to the service and the client. */ contract FeeDistributor is OwnableTokenRecoverer, ReentrancyGuard, ERC165, IFeeDistributor { // State variables /** * @notice address of FeeDistributorFactory */ IFeeDistributorFactory private immutable i_factory; /** * @notice address of Oracle */ IOracle private immutable i_oracle; /** * @notice address of the service (P2P) fee recipient */ address payable private immutable i_service; /** * @notice client config (address of the client, client basis points) */ FeeRecipient private s_clientConfig; /** * @notice referrer config (address of the referrer, referrer basis points) */ FeeRecipient private s_referrerConfig; /** * @notice amount of CL rewards (in Wei) that should belong to the client only * and should not be considered for splitting between the service and the referrer */ ValidatorData private s_validatorData; /** * @dev Set values that are constant, common for all the clients, known at the initial deploy time. * @param _factory address of FeeDistributorFactory * @param _service address of the service (P2P) fee recipient */ constructor( address _oracle, address _factory, address payable _service ) { if (!ERC165Checker.supportsInterface(_oracle, type(IOracle).interfaceId)) { revert FeeDistributor__NotOracle(_factory); } if (!ERC165Checker.supportsInterface(_factory, type(IFeeDistributorFactory).interfaceId)) { revert FeeDistributor__NotFactory(_factory); } if (_service == address(0)) { revert FeeDistributor__ZeroAddressService(); } i_oracle = IOracle(_oracle); i_factory = IFeeDistributorFactory(_factory); i_service = _service; bool serviceCanReceiveEther = _sendValue(_service, 0); if (!serviceCanReceiveEther) { revert FeeDistributor__ServiceCannotReceiveEther(_service); } } /** * @dev Throws if called by any account other than the client. */ modifier onlyClient() { address caller = _msgSender(); address clientAddress = s_clientConfig.recipient; if (clientAddress != caller) { revert FeeDistributor__CallerNotClient(caller, clientAddress); } _; } // Functions /** * @notice Accept ether from transactions */ receive() external payable { // only accept ether in an instance, not in a template if (s_clientConfig.recipient == address(0)) { revert FeeDistributor__ClientNotSet(); } } /** * @notice Set client address. * @dev Could not be in the constructor since it is different for different clients. * @dev _referrerConfig can be zero if there is no referrer. * @param _clientConfig address and basis points (percent * 100) of the client * @param _referrerConfig address and basis points (percent * 100) of the referrer. * @param _validatorData clientOnlyClRewards, firstValidatorId, and validatorCount */ function initialize( FeeRecipient calldata _clientConfig, FeeRecipient calldata _referrerConfig, ValidatorData calldata _validatorData ) external { if (msg.sender != address(i_factory)) { revert FeeDistributor__NotFactoryCalled(msg.sender, i_factory); } if (_clientConfig.recipient == address(0)) { revert FeeDistributor__ZeroAddressClient(); } if (_clientConfig.recipient == i_service) { revert FeeDistributor__ClientAddressEqualsService(_clientConfig.recipient); } if (s_clientConfig.recipient != address(0)) { revert FeeDistributor__ClientAlreadySet(s_clientConfig.recipient); } if (_clientConfig.basisPoints > 10000) { revert FeeDistributor__InvalidClientBasisPoints(_clientConfig.basisPoints); } if (_validatorData.firstValidatorId == 0) { revert FeeDistributor__InvalidFirstValidatorId(_validatorData.firstValidatorId); } if (_validatorData.validatorCount == 0) { revert FeeDistributor__InvalidValidatorCount(_validatorData.validatorCount); } if (_referrerConfig.recipient != address(0)) {// if there is a referrer if (_referrerConfig.recipient == i_service) { revert FeeDistributor__ReferrerAddressEqualsService(_referrerConfig.recipient); } if (_referrerConfig.recipient == _clientConfig.recipient) { revert FeeDistributor__ReferrerAddressEqualsClient(_referrerConfig.recipient); } if (_clientConfig.basisPoints + _referrerConfig.basisPoints > 10000) { revert FeeDistributor__ClientPlusReferralBasisPointsExceed10000(_clientConfig.basisPoints, _referrerConfig.basisPoints); } // set referrer config s_referrerConfig = _referrerConfig; } else {// if there is no referrer if (_referrerConfig.basisPoints != 0) { revert FeeDistributor__ReferrerBasisPointsMustBeZeroIfAddressIsZero(_referrerConfig.basisPoints); } } // set client config s_clientConfig = _clientConfig; // set validator data s_validatorData = _validatorData; emit Initialized( _clientConfig.recipient, _clientConfig.basisPoints, _referrerConfig.recipient, _referrerConfig.basisPoints ); bool clientCanReceiveEther = _sendValue(_clientConfig.recipient, 0); if (!clientCanReceiveEther) { revert FeeDistributor__ClientCannotReceiveEther(_clientConfig.recipient); } if (_referrerConfig.recipient != address(0)) {// if there is a referrer bool referrerCanReceiveEther = _sendValue(_referrerConfig.recipient, 0); if (!referrerCanReceiveEther) { revert FeeDistributor__ReferrerCannotReceiveEther(_referrerConfig.recipient); } } } /** * @notice Withdraw the whole balance of the contract according to the pre-defined basis points. * @dev In case someone (either service, or client, or referrer) fails to accept ether, * the owner will be able to recover some of their share. * This scenario is very unlikely. It can only happen if that someone is a contract * whose receive function changed its behavior since FeeDistributor's initialization. * It can never happen unless the receiving party themselves wants it to happen. * We strongly recommend against intentional reverts in the receive function * because the remaining parties might call `withdraw` again multiple times without waiting * for the owner to recover ether for the reverting party. * In fact, as a punishment for the reverting party, before the recovering, * 1 more regular `withdraw` will happen, rewarding the non-reverting parties again. * `recoverEther` function is just an emergency backup plan and does not replace `withdraw`. * * @param _proof Merkle proof (the leaf's sibling, and each non-leaf hash that could not otherwise be calculated without additional leaf nodes) * @param _amountInGwei total CL rewards earned by all validators in GWei (see _validatorCount) */ function withdraw( bytes32[] calldata _proof, uint256 _amountInGwei ) external nonReentrant { if (s_clientConfig.recipient == address(0)) { revert FeeDistributor__ClientNotSet(); } // get the contract's balance uint256 balance = address(this).balance; if (balance == 0) { // revert if there is no ether to withdraw revert FeeDistributor__NothingToWithdraw(); } // read from storage once ValidatorData memory vd = s_validatorData; // verify the data from the caller against the oracle i_oracle.verify(_proof, vd.firstValidatorId, vd.validatorCount, _amountInGwei); // Gwei to Wei uint256 amount = _amountInGwei * (10 ** 9); if (balance + amount < vd.clientOnlyClRewards) { // Can happen if the client has called emergencyEtherRecoveryWithoutOracleData before // but the actual rewards amount now appeared to be lower than the already split. // Should happen rarely. revert FeeDistributor__WaitForEnoughRewardsToWithdraw(); } // total to split = EL + CL - already split part of CL (should be OK unless halfBalance < serviceAmount) uint256 totalAmountToSplit = balance + amount - vd.clientOnlyClRewards; // set client basis points to value from storage config uint256 clientBp = s_clientConfig.basisPoints; // how much should service get uint256 serviceAmount = totalAmountToSplit - ((totalAmountToSplit * clientBp) / 10000); uint256 halfBalance = balance / 2; // how much should client get uint256 clientAmount; // if a half of the available balance is not enough to cover service (and referrer) shares // can happen when CL rewards (only accessible by client) are way much than EL rewards if (serviceAmount > halfBalance) { // client gets 50% of EL rewards clientAmount = halfBalance; // service (and referrer) get 50% of EL rewards combined (+1 wei in case balance is odd) serviceAmount = balance - halfBalance; // update the total amount being split to a smaller value to fit the actual balance of this contract totalAmountToSplit = (halfBalance * 10000) / (10000 - clientBp); } else { // send the remaining balance to client clientAmount = balance - serviceAmount; } // client gets the rest from CL as not split anymore amount s_validatorData.clientOnlyClRewards = uint176(vd.clientOnlyClRewards + (totalAmountToSplit - balance)); // how much should referrer get uint256 referrerAmount; if (s_referrerConfig.recipient != address(0)) { // if there is a referrer referrerAmount = (totalAmountToSplit * s_referrerConfig.basisPoints) / 10000; serviceAmount -= referrerAmount; // Send ETH to referrer. Ignore the possible yet unlikely revert in the receive function. _sendValue(s_referrerConfig.recipient, referrerAmount); } // Send ETH to service. Ignore the possible yet unlikely revert in the receive function. _sendValue(i_service, serviceAmount); // Send ETH to client. Ignore the possible yet unlikely revert in the receive function. _sendValue(s_clientConfig.recipient, clientAmount); emit Withdrawn(serviceAmount, clientAmount, referrerAmount); } /** * @notice Recover ether in a rare case when either service, or client, or referrer * refuse to accept ether. * @param _to receiver address * @param _proof Merkle proof (the leaf's sibling, and each non-leaf hash that could not otherwise be calculated without additional leaf nodes) * @param _amountInGwei total CL rewards earned by all validators in GWei (see _validatorCount) */ function recoverEther( address payable _to, bytes32[] calldata _proof, uint256 _amountInGwei ) external onlyOwner { this.withdraw(_proof, _amountInGwei); // get the contract's balance uint256 balance = address(this).balance; if (balance > 0) { // only happens if at least 1 party reverted in their receive bool success = _sendValue(_to, balance); if (success) { emit EtherRecovered(_to, balance); } else { emit EtherRecoveryFailed(_to, balance); } } } /** * @notice SHOULD NEVER BE CALLED NORMALLY!!!! Recover ether if oracle data (Merkle proof) is not available for some reason. */ function emergencyEtherRecoveryWithoutOracleData() external onlyClient nonReentrant { // get the contract's balance uint256 balance = address(this).balance; if (balance == 0) { // revert if there is no ether to withdraw revert FeeDistributor__NothingToWithdraw(); } uint256 halfBalance = balance / 2; // client gets 50% of EL rewards uint256 clientAmount = halfBalance; // service (and referrer) get 50% of EL rewards combined (+1 wei in case balance is odd) uint256 serviceAmount = balance - halfBalance; // the total amount being split fits the actual balance of this contract uint256 totalAmountToSplit = (halfBalance * 10000) / (10000 - s_clientConfig.basisPoints); // client gets the rest from CL as not split anymore amount s_validatorData.clientOnlyClRewards = uint176(s_validatorData.clientOnlyClRewards + (totalAmountToSplit - balance)); // how much should referrer get uint256 referrerAmount; if (s_referrerConfig.recipient != address(0)) { // if there is a referrer referrerAmount = (totalAmountToSplit * s_referrerConfig.basisPoints) / 10000; serviceAmount -= referrerAmount; // Send ETH to referrer. Ignore the possible yet unlikely revert in the receive function. _sendValue(s_referrerConfig.recipient, referrerAmount); } // Send ETH to service. Ignore the possible yet unlikely revert in the receive function. _sendValue(i_service, serviceAmount); // Send ETH to client. Ignore the possible yet unlikely revert in the receive function. _sendValue(s_clientConfig.recipient, clientAmount); emit Withdrawn(serviceAmount, clientAmount, referrerAmount); } /** * @dev Returns the factory address */ function factory() external view returns (address) { return address(i_factory); } /** * @dev Returns the service address */ function service() external view returns (address) { return i_service; } /** * @dev Returns the client address */ function client() external view returns (address) { return s_clientConfig.recipient; } /** * @dev Returns the client basis points */ function clientBasisPoints() external view returns (uint256) { return s_clientConfig.basisPoints; } /** * @dev Returns the referrer address */ function referrer() external view returns (address) { return s_referrerConfig.recipient; } /** * @dev Returns the referrer basis points */ function referrerBasisPoints() external view returns (uint256) { return s_referrerConfig.basisPoints; } /** * @dev Returns First Validator Id */ function firstValidatorId() external view returns (uint256) { return s_validatorData.firstValidatorId; } /** * @dev Returns a portion of CL rewards that should not be counted during withdraw (belongs to client only) */ function clientOnlyClRewards() external view returns (uint256) { return s_validatorData.clientOnlyClRewards; } /** * @dev Returns validator count */ function validatorCount() external view returns (uint256) { return s_validatorData.validatorCount; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IFeeDistributor).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns the address of the current owner. */ function owner() public view override returns (address) { return i_factory.owner(); } function _sendValue(address payable _recipient, uint256 _amount) internal returns (bool) { (bool success, ) = _recipient.call{ value: _amount, gas: gasleft() / 4 // to prevent DOS, should be enough in normal cases }(""); return success; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity 0.8.10; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity 0.8.10; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 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); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.2) (utils/introspection/ERC165Checker.sol) pragma solidity 0.8.10; import "./IERC165.sol"; /** * @dev Library used to query support of an interface declared via {IERC165}. * * Note that these functions return the actual result of the query: they do not * `revert` if an interface is not supported. It is up to the caller to decide * what to do in these cases. */ library ERC165Checker { // As per the EIP-165 spec, no interface should ever match 0xffffffff bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; /** * @dev Returns true if `account` supports the {IERC165} interface, */ function supportsERC165(address account) internal view returns (bool) { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return _supportsERC165Interface(account, type(IERC165).interfaceId) && !_supportsERC165Interface(account, _INTERFACE_ID_INVALID); } /** * @dev Returns true if `account` supports the interface defined by * `interfaceId`. Support for {IERC165} itself is queried automatically. * * See {IERC165-supportsInterface}. */ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { // query support of both ERC165 as per the spec and support of _interfaceId return supportsERC165(account) && _supportsERC165Interface(account, interfaceId); } /** * @dev Returns a boolean array where each value corresponds to the * interfaces passed in and whether they're supported or not. This allows * you to batch check interfaces for a contract where your expectation * is that some interfaces may not be supported. * * See {IERC165-supportsInterface}. * * _Available since v3.4._ */ function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool[] memory) { // an array of booleans corresponding to interfaceIds and whether they're supported or not bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); // query support of ERC165 itself if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]); } } return interfaceIdsSupported; } /** * @dev Returns true if `account` supports all the interfaces defined in * `interfaceIds`. Support for {IERC165} itself is queried automatically. * * Batch-querying can lead to gas savings by skipping repeated checks for * {IERC165} support. * * See {IERC165-supportsInterface}. */ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { // query support of ERC165 itself if (!supportsERC165(account)) { return false; } // query support of each interface in _interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { if (!_supportsERC165Interface(account, interfaceIds[i])) { return false; } } // all interfaces supported return true; } /** * @notice Query if a contract implements an interface, does not check ERC165 support * @param account The address of the contract to query for support of an interface * @param interfaceId The interface identifier, as specified in ERC-165 * @return true if the contract at account indicates support of the interface with * identifier interfaceId, false otherwise * @dev Assumes that account contains a contract that supports ERC165, otherwise * the behavior of this method is undefined. This precondition can be checked * with {supportsERC165}. * Interface identification is specified in ERC-165. */ function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) { // prepare call bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); // perform static call bool success; uint256 returnSize; uint256 returnValue; assembly { success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) returnSize := returndatasize() returnValue := mload(0x00) } return success && returnSize >= 0x20 && returnValue > 0; } }
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../@openzeppelin/contracts/utils/introspection/IERC165.sol"; import "../access/IOwnable.sol"; import "../feeDistributor/IFeeDistributor.sol"; /** * @dev External interface of FeeDistributorFactory declared to support ERC165 detection. */ interface IFeeDistributorFactory is IOwnable, IERC165 { // Events /** * @notice Emits when a new FeeDistributor instance has been created for a client * @param _newFeeDistributorAddress address of the newly created FeeDistributor contract instance * @param _clientAddress address of the client for whom the new instance was created */ event FeeDistributorCreated(address indexed _newFeeDistributorAddress, address indexed _clientAddress); /** * @notice Emits when a new FeeDistributor contract address has been set as a reference instance. * @param _referenceFeeDistributor the address of the new reference implementation contract */ event ReferenceInstanceSet(address indexed _referenceFeeDistributor); /** * @notice Emits when a new P2pEth2Depositor contract address has been set. * @param _p2pEth2Depositor the address of the new P2pEth2Depositor contract */ event P2pEth2DepositorSet(address indexed _p2pEth2Depositor); // Functions /** * @notice Set a new reference implementation of FeeDistributor contract * @param _referenceFeeDistributor the address of the new reference implementation contract */ function setReferenceInstance(address _referenceFeeDistributor) external; /** * @notice Creates a FeeDistributor instance for a client * @dev Emits `FeeDistributorCreated` event with the address of the newly created instance * @dev _referrerConfig can be zero if there is no referrer. * @param _clientConfig address and basis points (percent * 100) of the client * @param _referrerConfig address and basis points (percent * 100) of the referrer. * @param _validatorData clientOnlyClRewards, firstValidatorId, and validatorCount * @return newFeeDistributorAddress user FeeDistributor instance that has just been deployed */ function createFeeDistributor( IFeeDistributor.FeeRecipient calldata _clientConfig, IFeeDistributor.FeeRecipient calldata _referrerConfig, IFeeDistributor.ValidatorData calldata _validatorData ) external returns (address newFeeDistributorAddress); /** * @dev Returns the reference FeeDistributor contract address */ function getReferenceFeeDistributor() external view returns (address); }
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>, Lido <[email protected]> // SPDX-License-Identifier: MIT // https://github.com/lidofinance/lido-otc-seller/blob/master/contracts/lib/AssetRecoverer.sol pragma solidity 0.8.10; import "./TokenRecoverer.sol"; import "../access/OwnableBase.sol"; /// @title Token Recoverer with public functions callable by assetAccessingAddress /// @notice Recover ERC20, ERC721 and ERC1155 from a derived contract abstract contract OwnableTokenRecoverer is TokenRecoverer, OwnableBase { // Functions /** * @notice transfer an ERC20 token from this contract * @dev `SafeERC20.safeTransfer` doesn't always return a bool * as it performs an internal `require` check * @param _token address of the ERC20 token * @param _recipient address to transfer the tokens to * @param _amount amount of tokens to transfer */ function transferERC20( address _token, address _recipient, uint256 _amount ) external onlyOwner { _transferERC20(_token, _recipient, _amount); } /** * @notice transfer an ERC721 token from this contract * @dev `IERC721.safeTransferFrom` doesn't always return a bool * as it performs an internal `require` check * @param _token address of the ERC721 token * @param _recipient address to transfer the token to * @param _tokenId id of the individual token * @param _data data to transfer along */ function transferERC721( address _token, address _recipient, uint256 _tokenId, bytes calldata _data ) external onlyOwner { _transferERC721(_token, _recipient, _tokenId, _data); } /** * @notice transfer an ERC1155 token from this contract * @dev see `AssetRecoverer` * @param _token address of the ERC1155 token that is being recovered * @param _recipient address to transfer the token to * @param _tokenId id of the individual token to transfer * @param _amount amount of tokens to transfer * @param _data data to transfer along */ function transferERC1155( address _token, address _recipient, uint256 _tokenId, uint256 _amount, bytes calldata _data ) external onlyOwner { _transferERC1155(_token, _recipient, _tokenId, _amount, _data); } }
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @dev External interface of FeeDistributor declared to support ERC165 detection. */ interface IFeeDistributor is IERC165 { /** * @dev 256bits-wide structure to store recipient address along with its basisPoints */ struct FeeRecipient { /** * @notice basis points (percent * 100) of EL rewards that should go to the recipient */ uint96 basisPoints; /** * @notice address of the recipient */ address payable recipient; } /** * @dev 256bits-wide structure to store clientOnlyClRewards, firstValidatorId, and validatorCount */ struct ValidatorData { /** * @notice amount of CL rewards (in Wei) that should belong to the client only * and should not be considered for splitting between the service and the referrer */ uint176 clientOnlyClRewards; /** * @notice Validator Id (number of all deposits previously made to ETH2 DepositContract plus 1) */ uint64 firstValidatorId; /** * @notice Number of validators corresponding to a given FeeDistributor instance, equal to the number of ETH2 deposits made with 1 P2pEth2Depositor's deposit */ uint16 validatorCount; } // Events /** * @notice Emits on successful withdrawal * @param _serviceAmount how much wei service received * @param _clientAmount how much wei client received * @param _referrerAmount how much wei referrer received */ event Withdrawn(uint256 _serviceAmount, uint256 _clientAmount, uint256 _referrerAmount); /** * @notice Emits once the client and the optional referrer have been set. * @param _client address of the client. * @param _clientBasisPoints basis points (percent * 100) of EL rewards that should go to the client * @param _referrer address of the referrer. * @param _referrerBasisPoints basis points (percent * 100) of EL rewards that should go to the referrer */ event Initialized( address indexed _client, uint96 _clientBasisPoints, address indexed _referrer, uint96 _referrerBasisPoints ); /** * @notice Emits if case there was some ether left after `withdraw` and it has been sent successfully. * @param _to destination address for ether. * @param _amount how much wei the destination address received. */ event EtherRecovered(address indexed _to, uint256 _amount); /** * @notice Emits if case there was some ether left after `withdraw` and it has failed to recover. * @param _to destination address for ether. * @param _amount how much wei the destination address should have received, but didn't. */ event EtherRecoveryFailed(address indexed _to, uint256 _amount); // Functions /** * @notice Set client address. * @dev Could not be in the constructor since it is different for different clients. * @dev _referrerConfig can be zero if there is no referrer. * @param _clientConfig address and basis points (percent * 100) of the client * @param _referrerConfig address and basis points (percent * 100) of the referrer. * @param _validatorData clientOnlyClRewards, firstValidatorId, and validatorCount */ function initialize( FeeRecipient calldata _clientConfig, FeeRecipient calldata _referrerConfig, ValidatorData calldata _validatorData ) external; /** * @notice Withdraw the whole balance of the contract according to the pre-defined basis points. * @dev In case someone (either service, or client, or referrer) fails to accept ether, * the owner will be able to recover some of their share. * This scenario is very unlikely. It can only happen if that someone is a contract * whose receive function changed its behavior since FeeDistributor's initialization. * It can never happen unless the receiving party themselves wants it to happen. * We strongly recommend against intentional reverts in the receive function * because the remaining parties might call `withdraw` again multiple times without waiting * for the owner to recover ether for the reverting party. * In fact, as a punishment for the reverting party, before the recovering, * 1 more regular `withdraw` will happen, rewarding the non-reverting parties again. * `recoverEther` function is just an emergency backup plan and does not replace `withdraw`. * * @param _proof Merkle proof (the leaf's sibling, and each non-leaf hash that could not otherwise be calculated without additional leaf nodes) * @param _amount total CL rewards earned by all validators (see _validatorCount) */ function withdraw( bytes32[] calldata _proof, uint256 _amount ) external; /** * @dev Returns the factory address */ function factory() external view returns (address); /** * @dev Returns the service address */ function service() external view returns (address); /** * @dev Returns the client address */ function client() external view returns (address); /** * @dev Returns the client basis points */ function clientBasisPoints() external view returns (uint256); /** * @dev Returns the referrer address */ function referrer() external view returns (address); /** * @dev Returns the referrer basis points */ function referrerBasisPoints() external view returns (uint256); /** * @dev Returns First Validator Id */ function firstValidatorId() external view returns (uint256); /** * @dev Returns a portion of CL rewards that should not be counted during withdraw (belongs to client only) */ function clientOnlyClRewards() external view returns (uint256); /** * @dev Returns validator count */ function validatorCount() external view returns (uint256); }
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../@openzeppelin/contracts/utils/introspection/IERC165.sol"; import "../access/IOwnable.sol"; /** * @dev External interface of Oracle declared to support ERC165 detection. */ interface IOracle is IOwnable, IERC165 { // Events /** * @notice Emits when a new oracle report (Merkle root) recorded * @param _root Merkle root */ event Reported(bytes32 indexed _root); // Functions /** * @notice Set a new oracle report (Merkle root) * @param _root Merkle root */ function report(bytes32 _root) external; /** * @notice Verify Merkle proof (that the leaf belongs to the tree) * @param _proof Merkle proof (the leaf's sibling, and each non-leaf hash that could not otherwise be calculated without additional leaf nodes) * @param _firstValidatorId Validator Id (number of all deposits previously made to ETH2 DepositContract plus 1) * @param _validatorCount (number of validators corresponding to a given FeeDistributor instance, equal to the number of ETH2 deposits made with 1 P2pEth2Depositor's deposit) * @param _amountInGwei total CL rewards earned by all validators in GWei (see _validatorCount) */ function verify( bytes32[] calldata _proof, uint64 _firstValidatorId, uint16 _validatorCount, uint256 _amountInGwei ) external view; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity 0.8.10; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * 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[EIP 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-FileCopyrightText: 2023 P2P Validator <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.10; /** * @dev External interface of Ownable. */ interface IOwnable { /** * @dev Returns the address of the current owner. */ function owner() external view returns (address); }
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>, Lido <[email protected]> // SPDX-License-Identifier: MIT // https://github.com/lidofinance/lido-otc-seller/blob/master/contracts/lib/AssetRecoverer.sol pragma solidity 0.8.10; import {IERC20} from "../@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC721} from "../@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {IERC1155} from "../@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import {SafeERC20} from "../@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @notice prevents burn for transfer functions * @dev _recipient should not be a zero address */ error TokenRecoverer__NoBurn(); /// @title Token Recoverer /// @notice Recover ERC20, ERC721 and ERC1155 from a derived contract abstract contract TokenRecoverer { using SafeERC20 for IERC20; event ERC20Transferred(address indexed _token, address indexed _recipient, uint256 _amount); event ERC721Transferred(address indexed _token, address indexed _recipient, uint256 _tokenId, bytes _data); event ERC1155Transferred(address indexed _token, address indexed _recipient, uint256 _tokenId, uint256 _amount, bytes _data); /** * @notice prevents burn for transfer functions * @dev checks for zero address and reverts if true * @param _recipient address of the transfer recipient */ modifier burnDisallowed(address _recipient) { if (_recipient == address(0)) { revert TokenRecoverer__NoBurn(); } _; } /** * @notice transfer an ERC20 token from this contract * @dev `SafeERC20.safeTransfer` doesn't always return a bool * as it performs an internal `require` check * @param _token address of the ERC20 token * @param _recipient address to transfer the tokens to * @param _amount amount of tokens to transfer */ function _transferERC20( address _token, address _recipient, uint256 _amount ) internal virtual burnDisallowed(_recipient) { IERC20(_token).safeTransfer(_recipient, _amount); emit ERC20Transferred(_token, _recipient, _amount); } /** * @notice transfer an ERC721 token from this contract * @dev `IERC721.safeTransferFrom` doesn't always return a bool * as it performs an internal `require` check * @param _token address of the ERC721 token * @param _recipient address to transfer the token to * @param _tokenId id of the individual token * @param _data data to transfer along */ function _transferERC721( address _token, address _recipient, uint256 _tokenId, bytes calldata _data ) internal virtual burnDisallowed(_recipient) { IERC721(_token).safeTransferFrom(address(this), _recipient, _tokenId, _data); emit ERC721Transferred(_token, _recipient, _tokenId, _data); } /** * @notice transfer an ERC1155 token from this contract * @dev `IERC1155.safeTransferFrom` doesn't always return a bool * as it performs an internal `require` check * @param _token address of the ERC1155 token that is being recovered * @param _recipient address to transfer the token to * @param _tokenId id of the individual token to transfer * @param _amount amount of tokens to transfer * @param _data data to transfer along */ function _transferERC1155( address _token, address _recipient, uint256 _tokenId, uint256 _amount, bytes calldata _data ) internal virtual burnDisallowed(_recipient) { IERC1155(_token).safeTransferFrom(address(this), _recipient, _tokenId, _amount, _data); emit ERC1155Transferred(_token, _recipient, _tokenId, _amount, _data); } }
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../@openzeppelin/contracts/utils/Context.sol"; import "./IOwnable.sol"; /** * @notice Throws if called by any account other than the owner. * @param _caller address of the caller * @param _owner address of the owner */ error OwnableBase__CallerNotOwner(address _caller, address _owner); /** * @dev minimalistic version of OpenZeppelin's Ownable. * The owner is abstract and is not persisted in storage. * Needs to be overridden in a child contract. */ abstract contract OwnableBase is Context, IOwnable { /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { address caller = _msgSender(); address currentOwner = owner(); if (currentOwner != caller) { revert OwnableBase__CallerNotOwner(caller, currentOwner); } _; } /** * @dev Returns the address of the current owner. * Needs to be overridden in a child contract. */ function owner() public view virtual override returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity 0.8.10; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity 0.8.10; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol) pragma solidity 0.8.10; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity 0.8.10; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity 0.8.10; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 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. */ 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]. */ 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 v4.7.0) (utils/Address.sol) pragma solidity 0.8.10; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity 0.8.10; /** * @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; } }
{ "optimizer": { "enabled": false, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address payable","name":"_service","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_caller","type":"address"},{"internalType":"address","name":"_client","type":"address"}],"name":"FeeDistributor__CallerNotClient","type":"error"},{"inputs":[{"internalType":"address","name":"_passedAddress","type":"address"}],"name":"FeeDistributor__ClientAddressEqualsService","type":"error"},{"inputs":[{"internalType":"address","name":"_existingClient","type":"address"}],"name":"FeeDistributor__ClientAlreadySet","type":"error"},{"inputs":[{"internalType":"address","name":"_client","type":"address"}],"name":"FeeDistributor__ClientCannotReceiveEther","type":"error"},{"inputs":[],"name":"FeeDistributor__ClientNotSet","type":"error"},{"inputs":[{"internalType":"uint96","name":"_clientBasisPoints","type":"uint96"},{"internalType":"uint96","name":"_referralBasisPoints","type":"uint96"}],"name":"FeeDistributor__ClientPlusReferralBasisPointsExceed10000","type":"error"},{"inputs":[{"internalType":"uint96","name":"_clientBasisPoints","type":"uint96"}],"name":"FeeDistributor__InvalidClientBasisPoints","type":"error"},{"inputs":[{"internalType":"uint64","name":"_firstValidatorId","type":"uint64"}],"name":"FeeDistributor__InvalidFirstValidatorId","type":"error"},{"inputs":[{"internalType":"uint16","name":"_validatorCount","type":"uint16"}],"name":"FeeDistributor__InvalidValidatorCount","type":"error"},{"inputs":[{"internalType":"address","name":"_passedAddress","type":"address"}],"name":"FeeDistributor__NotFactory","type":"error"},{"inputs":[{"internalType":"address","name":"_msgSender","type":"address"},{"internalType":"contract IFeeDistributorFactory","name":"_actualFactory","type":"address"}],"name":"FeeDistributor__NotFactoryCalled","type":"error"},{"inputs":[{"internalType":"address","name":"_passedAddress","type":"address"}],"name":"FeeDistributor__NotOracle","type":"error"},{"inputs":[],"name":"FeeDistributor__NothingToWithdraw","type":"error"},{"inputs":[{"internalType":"address","name":"_passedAddress","type":"address"}],"name":"FeeDistributor__ReferrerAddressEqualsClient","type":"error"},{"inputs":[{"internalType":"address","name":"_passedAddress","type":"address"}],"name":"FeeDistributor__ReferrerAddressEqualsService","type":"error"},{"inputs":[{"internalType":"uint96","name":"_referrerBasisPoints","type":"uint96"}],"name":"FeeDistributor__ReferrerBasisPointsMustBeZeroIfAddressIsZero","type":"error"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"}],"name":"FeeDistributor__ReferrerCannotReceiveEther","type":"error"},{"inputs":[{"internalType":"address","name":"_service","type":"address"}],"name":"FeeDistributor__ServiceCannotReceiveEther","type":"error"},{"inputs":[],"name":"FeeDistributor__WaitForEnoughRewardsToWithdraw","type":"error"},{"inputs":[],"name":"FeeDistributor__ZeroAddressClient","type":"error"},{"inputs":[],"name":"FeeDistributor__ZeroAddressService","type":"error"},{"inputs":[{"internalType":"address","name":"_caller","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"OwnableBase__CallerNotOwner","type":"error"},{"inputs":[],"name":"TokenRecoverer__NoBurn","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"}],"name":"ERC1155Transferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"ERC20Transferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"}],"name":"ERC721Transferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"EtherRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"EtherRecoveryFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_client","type":"address"},{"indexed":false,"internalType":"uint96","name":"_clientBasisPoints","type":"uint96"},{"indexed":true,"internalType":"address","name":"_referrer","type":"address"},{"indexed":false,"internalType":"uint96","name":"_referrerBasisPoints","type":"uint96"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_serviceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_clientAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_referrerAmount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"client","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"clientBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"clientOnlyClRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyEtherRecoveryWithoutOracleData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstValidatorId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"basisPoints","type":"uint96"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct IFeeDistributor.FeeRecipient","name":"_clientConfig","type":"tuple"},{"components":[{"internalType":"uint96","name":"basisPoints","type":"uint96"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct IFeeDistributor.FeeRecipient","name":"_referrerConfig","type":"tuple"},{"components":[{"internalType":"uint176","name":"clientOnlyClRewards","type":"uint176"},{"internalType":"uint64","name":"firstValidatorId","type":"uint64"},{"internalType":"uint16","name":"validatorCount","type":"uint16"}],"internalType":"struct IFeeDistributor.ValidatorData","name":"_validatorData","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"uint256","name":"_amountInGwei","type":"uint256"}],"name":"recoverEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"referrer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referrerBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"service","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"transferERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"transferERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"validatorCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"uint256","name":"_amountInGwei","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60e06040523480156200001157600080fd5b50604051620043df380380620043df833981810160405281019062000037919062000531565b600160008190555062000076837f418844d5000000000000000000000000000000000000000000000000000000006200029f60201b62001d881760201c565b620000ba57816040517fd5fe67da000000000000000000000000000000000000000000000000000000008152600401620000b191906200059e565b60405180910390fd5b620000f1827f3139eff4000000000000000000000000000000000000000000000000000000006200029f60201b62001d881760201c565b6200013557816040517f93bfc6460000000000000000000000000000000000000000000000000000000081526004016200012c91906200059e565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156200019d576040517f58d36f3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250508173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff168152505060006200024e826000620002d560201b60201c565b9050806200029557816040517f9ebcdf560000000000000000000000000000000000000000000000000000000081526004016200028c919062000626565b60405180910390fd5b505050506200075a565b6000620002b2836200036160201b60201c565b8015620002cd5750620002cc8383620003bf60201b60201c565b5b905092915050565b6000808373ffffffffffffffffffffffffffffffffffffffff168360045a620002ff91906200067c565b906040516200030e90620006e9565b600060405180830381858888f193505050503d80600081146200034e576040519150601f19603f3d011682016040523d82523d6000602084013e62000353565b606091505b505090508091505092915050565b600062000395827f01ffc9a700000000000000000000000000000000000000000000000000000000620003bf60201b60201c565b8015620003b85750620003b68263ffffffff60e01b620003bf60201b60201c565b155b9050919050565b6000806301ffc9a760e01b83604051602401620003dd91906200073d565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000806000602060008551602087018a617530fa92503d9150600051905082801562000469575060208210155b8015620004765750600081115b94505050505092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620004b48262000487565b9050919050565b620004c681620004a7565b8114620004d257600080fd5b50565b600081519050620004e681620004bb565b92915050565b6000620004f98262000487565b9050919050565b6200050b81620004ec565b81146200051757600080fd5b50565b6000815190506200052b8162000500565b92915050565b6000806000606084860312156200054d576200054c62000482565b5b60006200055d86828701620004d5565b93505060206200057086828701620004d5565b925050604062000583868287016200051a565b9150509250925092565b6200059881620004a7565b82525050565b6000602082019050620005b560008301846200058d565b92915050565b6000819050919050565b6000620005e6620005e0620005da8462000487565b620005bb565b62000487565b9050919050565b6000620005fa82620005c5565b9050919050565b60006200060e82620005ed565b9050919050565b620006208162000601565b82525050565b60006020820190506200063d600083018462000615565b92915050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000620006898262000643565b9150620006968362000643565b925082620006a957620006a86200064d565b5b828204905092915050565b600081905092915050565b50565b6000620006d1600083620006b4565b9150620006de82620006bf565b600082019050919050565b6000620006f682620006c2565b9150819050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b620007378162000700565b82525050565b60006020820190506200075460008301846200072c565b92915050565b60805160a05160c051613c24620007bb600039600081816106c3015281816109d401528181611142015281816117440152611ce5015260006113e3015260008181610598015281816105ec01528181610f4301526110ef0152613c246000f3fe60806040526004361061010d5760003560e01c80639db5dbe411610095578063d598d4c911610064578063d598d4c9146103e0578063dbecc6161461040b578063dd83edc314610434578063ddc9d3071461045d578063fad34b3714610486576101a0565b80639db5dbe414610336578063ac407bbc1461035f578063c45a01551461038a578063cade2ab8146103b5576101a0565b80635d5ef4ea116100dc5780635d5ef4ea1461026357806363eed7d01461028c57806368447c93146102b55780638da5cb5b146102e05780639261eda61461030b576101a0565b806301ffc9a7146101a55780630f43a677146101e2578063109e94cf1461020d578063470cc5f214610238576101a0565b366101a057600073ffffffffffffffffffffffffffffffffffffffff166001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561019e576040517f27438ff100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b600080fd5b3480156101b157600080fd5b506101cc60048036038101906101c791906126b1565b61049d565b6040516101d991906126f9565b60405180910390f35b3480156101ee57600080fd5b506101f7610517565b604051610204919061272d565b60405180910390f35b34801561021957600080fd5b50610222610536565b60405161022f9190612789565b60405180910390f35b34801561024457600080fd5b5061024d610563565b60405161025a919061272d565b60405180910390f35b34801561026f57600080fd5b5061028a600480360381019061028591906127e7565b610596565b005b34801561029857600080fd5b506102b360048036038101906102ae91906128f7565b610e72565b005b3480156102c157600080fd5b506102ca610f12565b6040516102d79190612789565b60405180910390f35b3480156102ec57600080fd5b506102f5610f3f565b6040516103029190612789565b60405180910390f35b34801561031757600080fd5b50610320610fd5565b60405161032d919061272d565b60405180910390f35b34801561034257600080fd5b5061035d6004803603810190610358919061297f565b611008565b005b34801561036b57600080fd5b506103746110a4565b604051610381919061272d565b60405180910390f35b34801561039657600080fd5b5061039f6110eb565b6040516103ac9190612789565b60405180910390f35b3480156103c157600080fd5b506103ca611113565b6040516103d7919061272d565b60405180910390f35b3480156103ec57600080fd5b506103f561113e565b6040516104029190612789565b60405180910390f35b34801561041757600080fd5b50610432600480360381019061042d91906129d2565b611166565b005b34801561044057600080fd5b5061045b60048036038101906104569190612ac2565b611208565b005b34801561046957600080fd5b50610484600480360381019061047f9190612b60565b6117eb565b005b34801561049257600080fd5b5061049b6119b3565b005b60007f5575fbce000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610510575061050f82611dad565b5b9050919050565b60006003600001601e9054906101000a900461ffff1661ffff16905090565b60006001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000600260000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff16905090565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461064857337f00000000000000000000000000000000000000000000000000000000000000006040517f459bd43e00000000000000000000000000000000000000000000000000000000815260040161063f929190612c33565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168360200160208101906106739190612c5c565b73ffffffffffffffffffffffffffffffffffffffff1614156106c1576040517f3d8e75ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1683602001602081019061070b9190612c5c565b73ffffffffffffffffffffffffffffffffffffffff1614156107765782602001602081019061073a9190612c5c565b6040517faf3d5b8700000000000000000000000000000000000000000000000000000000815260040161076d9190612caa565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610831576001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040517f0ce83aa80000000000000000000000000000000000000000000000000000000081526004016108289190612caa565b60405180910390fd5b6127108360000160208101906108479190612d09565b6bffffffffffffffffffffffff1611156108aa5782600001602081019061086e9190612d09565b6040517f27d660610000000000000000000000000000000000000000000000000000000081526004016108a19190612d45565b60405180910390fd5b60008160200160208101906108bf9190612da0565b67ffffffffffffffff16141561091e578060200160208101906108e29190612da0565b6040517fc4f9c5430000000000000000000000000000000000000000000000000000000081526004016109159190612ddc565b60405180910390fd5b60008160400160208101906109339190612e31565b61ffff16141561098c578060400160208101906109509190612e31565b6040517f058765f00000000000000000000000000000000000000000000000000000000081526004016109839190612e6d565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168260200160208101906109b79190612c5c565b73ffffffffffffffffffffffffffffffffffffffff1614610bef577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826020016020810190610a1c9190612c5c565b73ffffffffffffffffffffffffffffffffffffffff161415610a8757816020016020810190610a4b9190612c5c565b6040517f308fa9ec000000000000000000000000000000000000000000000000000000008152600401610a7e9190612caa565b60405180910390fd5b826020016020810190610a9a9190612c5c565b73ffffffffffffffffffffffffffffffffffffffff16826020016020810190610ac39190612c5c565b73ffffffffffffffffffffffffffffffffffffffff161415610b2e57816020016020810190610af29190612c5c565b6040517fd9013c13000000000000000000000000000000000000000000000000000000008152600401610b259190612caa565b60405180910390fd5b612710826000016020810190610b449190612d09565b846000016020810190610b579190612d09565b610b619190612eb7565b6bffffffffffffffffffffffff161115610bd857826000016020810190610b889190612d09565b826000016020810190610b9b9190612d09565b6040517fb1de779c000000000000000000000000000000000000000000000000000000008152600401610bcf929190612ef9565b60405180910390fd5b8160028181610be791906130be565b905050610c67565b6000826000016020810190610c049190612d09565b6bffffffffffffffffffffffff1614610c6657816000016020810190610c2a9190612d09565b6040517fc67d2aa7000000000000000000000000000000000000000000000000000000008152600401610c5d9190612d45565b60405180910390fd5b5b8260018181610c7691906130be565b9050508060038181610c88919061336f565b905050816020016020810190610c9e9190612c5c565b73ffffffffffffffffffffffffffffffffffffffff16836020016020810190610cc79190612c5c565b73ffffffffffffffffffffffffffffffffffffffff167f59c009a9d93ae8943511e542ad2389ff6beaa04118ad25d6b8d00b9c741f1df5856000016020810190610d119190612d09565b856000016020810190610d249190612d09565b604051610d32929190612ef9565b60405180910390a36000610d59846020016020810190610d529190612c5c565b6000611e17565b905080610daf57836020016020810190610d739190612c5c565b6040517f38c42f9a000000000000000000000000000000000000000000000000000000008152600401610da69190612caa565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16836020016020810190610dda9190612c5c565b73ffffffffffffffffffffffffffffffffffffffff1614610e6c576000610e14846020016020810190610e0d9190612c5c565b6000611e17565b905080610e6a57836020016020810190610e2e9190612c5c565b6040517fd8a749d5000000000000000000000000000000000000000000000000000000008152600401610e619190612caa565b60405180910390fd5b505b50505050565b6000610e7c611e9d565b90506000610e88610f3f565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610efc5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610ef392919061337d565b60405180910390fd5b610f098787878787611ea5565b50505050505050565b60006002600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd091906133bb565b905090565b6000600160000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff16905090565b6000611012611e9d565b9050600061101e610f3f565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146110925781816040517f078c725900000000000000000000000000000000000000000000000000000000815260040161108992919061337d565b60405180910390fd5b61109d858585611ff1565b5050505050565b6000600360000160009054906101000a900475ffffffffffffffffffffffffffffffffffffffffffff1675ffffffffffffffffffffffffffffffffffffffffffff16905090565b60007f0000000000000000000000000000000000000000000000000000000000000000905090565b6000600360000160169054906101000a900467ffffffffffffffff1667ffffffffffffffff16905090565b60007f0000000000000000000000000000000000000000000000000000000000000000905090565b6000611170611e9d565b9050600061117c610f3f565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146111f05781816040517f078c72590000000000000000000000000000000000000000000000000000000081526004016111e792919061337d565b60405180910390fd5b6111fe8888888888886120ef565b5050505050505050565b6002600054141561124e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124590613445565b60405180910390fd5b6002600081905550600073ffffffffffffffffffffffffffffffffffffffff166001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156112e2576040517f27438ff100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60004790506000811415611322576040517f851c981300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060036040518060600160405290816000820160009054906101000a900475ffffffffffffffffffffffffffffffffffffffffffff1675ffffffffffffffffffffffffffffffffffffffffffff1675ffffffffffffffffffffffffffffffffffffffffffff1681526020016000820160169054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff16815260200160008201601e9054906101000a900461ffff1661ffff1661ffff168152505090507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663678b4ee1868684602001518560400151886040518663ffffffff1660e01b815260040161144a9594939291906134e6565b60006040518083038186803b15801561146257600080fd5b505afa158015611476573d6000803e3d6000fd5b505050506000633b9aca008461148c9190613534565b9050816000015175ffffffffffffffffffffffffffffffffffffffffffff1681846114b7919061358e565b10156114ef576040517fec18f3ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826000015175ffffffffffffffffffffffffffffffffffffffffffff16828561151a919061358e565b61152491906135e4565b90506000600160000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff169050600061271082846115679190613534565b6115719190613647565b8361157c91906135e4565b9050600060028761158d9190613647565b90506000818311156115d75781905081886115a891906135e4565b9250836127106115b891906135e4565b612710836115c69190613534565b6115d09190613647565b94506115e6565b82886115e391906135e4565b90505b87856115f291906135e4565b876000015175ffffffffffffffffffffffffffffffffffffffffffff16611619919061358e565b600360000160006101000a81548175ffffffffffffffffffffffffffffffffffffffffffff021916908375ffffffffffffffffffffffffffffffffffffffffffff16021790555060008073ffffffffffffffffffffffffffffffffffffffff166002600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461173f57612710600260000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff16876116f49190613534565b6116fe9190613647565b9050808461170c91906135e4565b935061173d6002600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682611e17565b505b6117697f000000000000000000000000000000000000000000000000000000000000000085611e17565b506117996001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683611e17565b507fabd2ab552bc04cdbfa4a54107fa44ac8c9cb06f6d21da11933ac05a653be19e98483836040516117cd93929190613678565b60405180910390a15050505050505050506001600081905550505050565b60006117f5611e9d565b90506000611801610f3f565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146118755781816040517f078c725900000000000000000000000000000000000000000000000000000000815260040161186c92919061337d565b60405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff1663dd83edc38686866040518463ffffffff1660e01b81526004016118b2939291906136af565b600060405180830381600087803b1580156118cc57600080fd5b505af11580156118e0573d6000803e3d6000fd5b50505050600047905060008111156119aa5760006118fe8883611e17565b90508015611959578773ffffffffffffffffffffffffffffffffffffffff167f8e274e42262a7f013b700b35c2b4629ccce1702f8fe83f8dfb7eacbb26a4382c8360405161194c919061272d565b60405180910390a26119a8565b8773ffffffffffffffffffffffffffffffffffffffff167fe96418167cc28aef7483feb5e41f0edc3fa107506c9cc1b144ed0336c58b7bdb8360405161199f919061272d565b60405180910390a25b505b50505050505050565b60006119bd611e9d565b905060006001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611a5b5781816040517fa96b080e000000000000000000000000000000000000000000000000000000008152600401611a5292919061337d565b60405180910390fd5b60026000541415611aa1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a9890613445565b60405180910390fd5b600260008190555060004790506000811415611ae9576040517f851c981300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600282611af89190613647565b9050600081905060008284611b0d91906135e4565b90506000600160000160009054906101000a90046bffffffffffffffffffffffff16612710611b3c91906136e1565b6bffffffffffffffffffffffff1661271085611b589190613534565b611b629190613647565b90508481611b7091906135e4565b600360000160009054906101000a900475ffffffffffffffffffffffffffffffffffffffffffff1675ffffffffffffffffffffffffffffffffffffffffffff16611bba919061358e565b600360000160006101000a81548175ffffffffffffffffffffffffffffffffffffffffffff021916908375ffffffffffffffffffffffffffffffffffffffffffff16021790555060008073ffffffffffffffffffffffffffffffffffffffff166002600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611ce057612710600260000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff1683611c959190613534565b611c9f9190613647565b90508083611cad91906135e4565b9250611cde6002600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682611e17565b505b611d0a7f000000000000000000000000000000000000000000000000000000000000000084611e17565b50611d3a6001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1685611e17565b507fabd2ab552bc04cdbfa4a54107fa44ac8c9cb06f6d21da11933ac05a653be19e9838583604051611d6e93929190613678565b60405180910390a150505050505060016000819055505050565b6000611d9383612240565b8015611da55750611da4838361228d565b5b905092915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6000808373ffffffffffffffffffffffffffffffffffffffff168360045a611e3f9190613647565b90604051611e4c90613746565b600060405180830381858888f193505050503d8060008114611e8a576040519150601f19603f3d011682016040523d82523d6000602084013e611e8f565b606091505b505090508091505092915050565b600033905090565b83600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611f0d576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff1663b88d4fde30878787876040518663ffffffff1660e01b8152600401611f4e9594939291906137aa565b600060405180830381600087803b158015611f6857600080fd5b505af1158015611f7c573d6000803e3d6000fd5b505050508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f958eb1a535a90a0667f75726379cbcb8498dc301be9ba2c585e69907bb3027c9868686604051611fe1939291906137f8565b60405180910390a3505050505050565b81600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612059576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61208483838673ffffffffffffffffffffffffffffffffffffffff1661234c9092919063ffffffff16565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fe8de91d538b06154a2c48315768c5046f47e127d7fd3f726fd85cc723f29b052846040516120e1919061272d565b60405180910390a350505050565b84600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612157576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff1663f242432a3088888888886040518763ffffffff1660e01b815260040161219a9695949392919061382a565b600060405180830381600087803b1580156121b457600080fd5b505af11580156121c8573d6000803e3d6000fd5b505050508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f1c84289b4389ba8251b26974eaec89409eb21a1198ca5eb281c86388da2e778b8787878760405161222f9493929190613886565b60405180910390a350505050505050565b600061226c827f01ffc9a70000000000000000000000000000000000000000000000000000000061228d565b801561228657506122848263ffffffff60e01b61228d565b155b9050919050565b6000806301ffc9a760e01b836040516024016122a991906138d5565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000806000602060008551602087018a617530fa92503d91506000519050828015612334575060208210155b80156123405750600081115b94505050505092915050565b6123cd8363a9059cbb60e01b848460405160240161236b9291906138f0565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506123d2565b505050565b6000612434826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166124999092919063ffffffff16565b905060008151111561249457808060200190518101906124549190613945565b612493576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161248a906139e4565b60405180910390fd5b5b505050565b60606124a884846000856124b1565b90509392505050565b6060824710156124f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124ed90613a76565b60405180910390fd5b6124ff856125c5565b61253e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161253590613ae2565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516125679190613b71565b60006040518083038185875af1925050503d80600081146125a4576040519150601f19603f3d011682016040523d82523d6000602084013e6125a9565b606091505b50915091506125b98282866125e8565b92505050949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b606083156125f857829050612648565b60008351111561260b5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161263f9190613bcc565b60405180910390fd5b9392505050565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61268e81612659565b811461269957600080fd5b50565b6000813590506126ab81612685565b92915050565b6000602082840312156126c7576126c661264f565b5b60006126d58482850161269c565b91505092915050565b60008115159050919050565b6126f3816126de565b82525050565b600060208201905061270e60008301846126ea565b92915050565b6000819050919050565b61272781612714565b82525050565b6000602082019050612742600083018461271e565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061277382612748565b9050919050565b61278381612768565b82525050565b600060208201905061279e600083018461277a565b92915050565b600080fd5b6000604082840312156127bf576127be6127a4565b5b81905092915050565b6000606082840312156127de576127dd6127a4565b5b81905092915050565b600080600060e08486031215612800576127ff61264f565b5b600061280e868287016127a9565b935050604061281f868287016127a9565b9250506080612830868287016127c8565b9150509250925092565b61284381612768565b811461284e57600080fd5b50565b6000813590506128608161283a565b92915050565b61286f81612714565b811461287a57600080fd5b50565b60008135905061288c81612866565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126128b7576128b6612892565b5b8235905067ffffffffffffffff8111156128d4576128d3612897565b5b6020830191508360018202830111156128f0576128ef61289c565b5b9250929050565b6000806000806000608086880312156129135761291261264f565b5b600061292188828901612851565b955050602061293288828901612851565b94505060406129438882890161287d565b935050606086013567ffffffffffffffff81111561296457612963612654565b5b612970888289016128a1565b92509250509295509295909350565b6000806000606084860312156129985761299761264f565b5b60006129a686828701612851565b93505060206129b786828701612851565b92505060406129c88682870161287d565b9150509250925092565b60008060008060008060a087890312156129ef576129ee61264f565b5b60006129fd89828a01612851565b9650506020612a0e89828a01612851565b9550506040612a1f89828a0161287d565b9450506060612a3089828a0161287d565b935050608087013567ffffffffffffffff811115612a5157612a50612654565b5b612a5d89828a016128a1565b92509250509295509295509295565b60008083601f840112612a8257612a81612892565b5b8235905067ffffffffffffffff811115612a9f57612a9e612897565b5b602083019150836020820283011115612abb57612aba61289c565b5b9250929050565b600080600060408486031215612adb57612ada61264f565b5b600084013567ffffffffffffffff811115612af957612af8612654565b5b612b0586828701612a6c565b93509350506020612b188682870161287d565b9150509250925092565b6000612b2d82612748565b9050919050565b612b3d81612b22565b8114612b4857600080fd5b50565b600081359050612b5a81612b34565b92915050565b60008060008060608587031215612b7a57612b7961264f565b5b6000612b8887828801612b4b565b945050602085013567ffffffffffffffff811115612ba957612ba8612654565b5b612bb587828801612a6c565b93509350506040612bc88782880161287d565b91505092959194509250565b6000819050919050565b6000612bf9612bf4612bef84612748565b612bd4565b612748565b9050919050565b6000612c0b82612bde565b9050919050565b6000612c1d82612c00565b9050919050565b612c2d81612c12565b82525050565b6000604082019050612c48600083018561277a565b612c556020830184612c24565b9392505050565b600060208284031215612c7257612c7161264f565b5b6000612c8084828501612b4b565b91505092915050565b6000612c9482612c00565b9050919050565b612ca481612c89565b82525050565b6000602082019050612cbf6000830184612c9b565b92915050565b60006bffffffffffffffffffffffff82169050919050565b612ce681612cc5565b8114612cf157600080fd5b50565b600081359050612d0381612cdd565b92915050565b600060208284031215612d1f57612d1e61264f565b5b6000612d2d84828501612cf4565b91505092915050565b612d3f81612cc5565b82525050565b6000602082019050612d5a6000830184612d36565b92915050565b600067ffffffffffffffff82169050919050565b612d7d81612d60565b8114612d8857600080fd5b50565b600081359050612d9a81612d74565b92915050565b600060208284031215612db657612db561264f565b5b6000612dc484828501612d8b565b91505092915050565b612dd681612d60565b82525050565b6000602082019050612df16000830184612dcd565b92915050565b600061ffff82169050919050565b612e0e81612df7565b8114612e1957600080fd5b50565b600081359050612e2b81612e05565b92915050565b600060208284031215612e4757612e4661264f565b5b6000612e5584828501612e1c565b91505092915050565b612e6781612df7565b82525050565b6000602082019050612e826000830184612e5e565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612ec282612cc5565b9150612ecd83612cc5565b9250826bffffffffffffffffffffffff03821115612eee57612eed612e88565b5b828201905092915050565b6000604082019050612f0e6000830185612d36565b612f1b6020830184612d36565b9392505050565b60008135612f2f81612cdd565b80915050919050565b60008160001b9050919050565b60006bffffffffffffffffffffffff612f5d84612f38565b9350801983169250808416831791505092915050565b6000612f8e612f89612f8484612cc5565b612bd4565b612cc5565b9050919050565b6000819050919050565b612fa882612f73565b612fbb612fb482612f95565b8354612f45565b8255505050565b60008135612fcf81612b34565b80915050919050565b60008160601b9050919050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000061301184612fd8565b9350801983169250808416831791505092915050565b600061303282612bde565b9050919050565b600061304482613027565b9050919050565b6000819050919050565b61305e82613039565b61307161306a8261304b565b8354612fe5565b8255505050565b60008101600083018061308a81612f22565b90506130968184612f9f565b5050506000810160208301806130ab81612fc2565b90506130b78184613055565b5050505050565b6130c88282613078565b5050565b600075ffffffffffffffffffffffffffffffffffffffffffff82169050919050565b6130f7816130cc565b811461310257600080fd5b50565b60008135613112816130ee565b80915050919050565b600075ffffffffffffffffffffffffffffffffffffffffffff61313d84612f38565b9350801983169250808416831791505092915050565b600061316e613169613164846130cc565b612bd4565b6130cc565b9050919050565b6000819050919050565b61318882613153565b61319b61319482613175565b835461311b565b8255505050565b600081356131af81612d74565b80915050919050565b60008160b01b9050919050565b60007dffffffffffffffff000000000000000000000000000000000000000000006131ef846131b8565b9350801983169250808416831791505092915050565b600061322061321b61321684612d60565b612bd4565b612d60565b9050919050565b6000819050919050565b61323a82613205565b61324d61324682613227565b83546131c5565b8255505050565b6000813561326181612e05565b80915050919050565b60008160f01b9050919050565b60007fffff0000000000000000000000000000000000000000000000000000000000006132a38461326a565b9350801983169250808416831791505092915050565b60006132d46132cf6132ca84612df7565b612bd4565b612df7565b9050919050565b6000819050919050565b6132ee826132b9565b6133016132fa826132db565b8354613277565b8255505050565b60008101600083018061331a81613105565b9050613326818461317f565b50505060008101602083018061333b816131a2565b90506133478184613231565b50505060008101604083018061335c81613254565b905061336881846132e5565b5050505050565b6133798282613308565b5050565b6000604082019050613392600083018561277a565b61339f602083018461277a565b9392505050565b6000815190506133b58161283a565b92915050565b6000602082840312156133d1576133d061264f565b5b60006133df848285016133a6565b91505092915050565b600082825260208201905092915050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b600061342f601f836133e8565b915061343a826133f9565b602082019050919050565b6000602082019050818103600083015261345e81613422565b9050919050565b600082825260208201905092915050565b600080fd5b82818337600083830152505050565b60006134968385613465565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156134c9576134c8613476565b5b6020830292506134da83858461347b565b82840190509392505050565b6000608082019050818103600083015261350181878961348a565b90506135106020830186612dcd565b61351d6040830185612e5e565b61352a606083018461271e565b9695505050505050565b600061353f82612714565b915061354a83612714565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561358357613582612e88565b5b828202905092915050565b600061359982612714565b91506135a483612714565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156135d9576135d8612e88565b5b828201905092915050565b60006135ef82612714565b91506135fa83612714565b92508282101561360d5761360c612e88565b5b828203905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061365282612714565b915061365d83612714565b92508261366d5761366c613618565b5b828204905092915050565b600060608201905061368d600083018661271e565b61369a602083018561271e565b6136a7604083018461271e565b949350505050565b600060408201905081810360008301526136ca81858761348a565b90506136d9602083018461271e565b949350505050565b60006136ec82612cc5565b91506136f783612cc5565b92508282101561370a57613709612e88565b5b828203905092915050565b600081905092915050565b50565b6000613730600083613715565b915061373b82613720565b600082019050919050565b600061375182613723565b9150819050919050565b600082825260208201905092915050565b6000601f19601f8301169050919050565b6000613789838561375b565b935061379683858461347b565b61379f8361376c565b840190509392505050565b60006080820190506137bf600083018861277a565b6137cc602083018761277a565b6137d9604083018661271e565b81810360608301526137ec81848661377d565b90509695505050505050565b600060408201905061380d600083018661271e565b818103602083015261382081848661377d565b9050949350505050565b600060a08201905061383f600083018961277a565b61384c602083018861277a565b613859604083018761271e565b613866606083018661271e565b818103608083015261387981848661377d565b9050979650505050505050565b600060608201905061389b600083018761271e565b6138a8602083018661271e565b81810360408301526138bb81848661377d565b905095945050505050565b6138cf81612659565b82525050565b60006020820190506138ea60008301846138c6565b92915050565b6000604082019050613905600083018561277a565b613912602083018461271e565b9392505050565b613922816126de565b811461392d57600080fd5b50565b60008151905061393f81613919565b92915050565b60006020828403121561395b5761395a61264f565b5b600061396984828501613930565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b60006139ce602a836133e8565b91506139d982613972565b604082019050919050565b600060208201905081810360008301526139fd816139c1565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b6000613a606026836133e8565b9150613a6b82613a04565b604082019050919050565b60006020820190508181036000830152613a8f81613a53565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000613acc601d836133e8565b9150613ad782613a96565b602082019050919050565b60006020820190508181036000830152613afb81613abf565b9050919050565b600081519050919050565b60005b83811015613b2b578082015181840152602081019050613b10565b83811115613b3a576000848401525b50505050565b6000613b4b82613b02565b613b558185613715565b9350613b65818560208601613b0d565b80840191505092915050565b6000613b7d8284613b40565b915081905092915050565b600081519050919050565b6000613b9e82613b88565b613ba881856133e8565b9350613bb8818560208601613b0d565b613bc18161376c565b840191505092915050565b60006020820190508181036000830152613be68184613b93565b90509291505056fea2646970667358221220ac95a9781558424f757cfc65d1e29735200e893acfe1b98782cf62ec1f9349e164736f6c634300080a0033000000000000000000000000105d2f6c358d185d1d81a73c1f76a75a2cc500ed000000000000000000000000d5b7680f95c5a6caecdbbeb1dee580960c4f891b0000000000000000000000006bb8b45a1c6ea816b70d76f83f7dc4f0f87365ff
Deployed Bytecode
0x60806040526004361061010d5760003560e01c80639db5dbe411610095578063d598d4c911610064578063d598d4c9146103e0578063dbecc6161461040b578063dd83edc314610434578063ddc9d3071461045d578063fad34b3714610486576101a0565b80639db5dbe414610336578063ac407bbc1461035f578063c45a01551461038a578063cade2ab8146103b5576101a0565b80635d5ef4ea116100dc5780635d5ef4ea1461026357806363eed7d01461028c57806368447c93146102b55780638da5cb5b146102e05780639261eda61461030b576101a0565b806301ffc9a7146101a55780630f43a677146101e2578063109e94cf1461020d578063470cc5f214610238576101a0565b366101a057600073ffffffffffffffffffffffffffffffffffffffff166001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561019e576040517f27438ff100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b600080fd5b3480156101b157600080fd5b506101cc60048036038101906101c791906126b1565b61049d565b6040516101d991906126f9565b60405180910390f35b3480156101ee57600080fd5b506101f7610517565b604051610204919061272d565b60405180910390f35b34801561021957600080fd5b50610222610536565b60405161022f9190612789565b60405180910390f35b34801561024457600080fd5b5061024d610563565b60405161025a919061272d565b60405180910390f35b34801561026f57600080fd5b5061028a600480360381019061028591906127e7565b610596565b005b34801561029857600080fd5b506102b360048036038101906102ae91906128f7565b610e72565b005b3480156102c157600080fd5b506102ca610f12565b6040516102d79190612789565b60405180910390f35b3480156102ec57600080fd5b506102f5610f3f565b6040516103029190612789565b60405180910390f35b34801561031757600080fd5b50610320610fd5565b60405161032d919061272d565b60405180910390f35b34801561034257600080fd5b5061035d6004803603810190610358919061297f565b611008565b005b34801561036b57600080fd5b506103746110a4565b604051610381919061272d565b60405180910390f35b34801561039657600080fd5b5061039f6110eb565b6040516103ac9190612789565b60405180910390f35b3480156103c157600080fd5b506103ca611113565b6040516103d7919061272d565b60405180910390f35b3480156103ec57600080fd5b506103f561113e565b6040516104029190612789565b60405180910390f35b34801561041757600080fd5b50610432600480360381019061042d91906129d2565b611166565b005b34801561044057600080fd5b5061045b60048036038101906104569190612ac2565b611208565b005b34801561046957600080fd5b50610484600480360381019061047f9190612b60565b6117eb565b005b34801561049257600080fd5b5061049b6119b3565b005b60007f5575fbce000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610510575061050f82611dad565b5b9050919050565b60006003600001601e9054906101000a900461ffff1661ffff16905090565b60006001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000600260000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff16905090565b7f000000000000000000000000d5b7680f95c5a6caecdbbeb1dee580960c4f891b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461064857337f000000000000000000000000d5b7680f95c5a6caecdbbeb1dee580960c4f891b6040517f459bd43e00000000000000000000000000000000000000000000000000000000815260040161063f929190612c33565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168360200160208101906106739190612c5c565b73ffffffffffffffffffffffffffffffffffffffff1614156106c1576040517f3d8e75ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000006bb8b45a1c6ea816b70d76f83f7dc4f0f87365ff73ffffffffffffffffffffffffffffffffffffffff1683602001602081019061070b9190612c5c565b73ffffffffffffffffffffffffffffffffffffffff1614156107765782602001602081019061073a9190612c5c565b6040517faf3d5b8700000000000000000000000000000000000000000000000000000000815260040161076d9190612caa565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610831576001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040517f0ce83aa80000000000000000000000000000000000000000000000000000000081526004016108289190612caa565b60405180910390fd5b6127108360000160208101906108479190612d09565b6bffffffffffffffffffffffff1611156108aa5782600001602081019061086e9190612d09565b6040517f27d660610000000000000000000000000000000000000000000000000000000081526004016108a19190612d45565b60405180910390fd5b60008160200160208101906108bf9190612da0565b67ffffffffffffffff16141561091e578060200160208101906108e29190612da0565b6040517fc4f9c5430000000000000000000000000000000000000000000000000000000081526004016109159190612ddc565b60405180910390fd5b60008160400160208101906109339190612e31565b61ffff16141561098c578060400160208101906109509190612e31565b6040517f058765f00000000000000000000000000000000000000000000000000000000081526004016109839190612e6d565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168260200160208101906109b79190612c5c565b73ffffffffffffffffffffffffffffffffffffffff1614610bef577f0000000000000000000000006bb8b45a1c6ea816b70d76f83f7dc4f0f87365ff73ffffffffffffffffffffffffffffffffffffffff16826020016020810190610a1c9190612c5c565b73ffffffffffffffffffffffffffffffffffffffff161415610a8757816020016020810190610a4b9190612c5c565b6040517f308fa9ec000000000000000000000000000000000000000000000000000000008152600401610a7e9190612caa565b60405180910390fd5b826020016020810190610a9a9190612c5c565b73ffffffffffffffffffffffffffffffffffffffff16826020016020810190610ac39190612c5c565b73ffffffffffffffffffffffffffffffffffffffff161415610b2e57816020016020810190610af29190612c5c565b6040517fd9013c13000000000000000000000000000000000000000000000000000000008152600401610b259190612caa565b60405180910390fd5b612710826000016020810190610b449190612d09565b846000016020810190610b579190612d09565b610b619190612eb7565b6bffffffffffffffffffffffff161115610bd857826000016020810190610b889190612d09565b826000016020810190610b9b9190612d09565b6040517fb1de779c000000000000000000000000000000000000000000000000000000008152600401610bcf929190612ef9565b60405180910390fd5b8160028181610be791906130be565b905050610c67565b6000826000016020810190610c049190612d09565b6bffffffffffffffffffffffff1614610c6657816000016020810190610c2a9190612d09565b6040517fc67d2aa7000000000000000000000000000000000000000000000000000000008152600401610c5d9190612d45565b60405180910390fd5b5b8260018181610c7691906130be565b9050508060038181610c88919061336f565b905050816020016020810190610c9e9190612c5c565b73ffffffffffffffffffffffffffffffffffffffff16836020016020810190610cc79190612c5c565b73ffffffffffffffffffffffffffffffffffffffff167f59c009a9d93ae8943511e542ad2389ff6beaa04118ad25d6b8d00b9c741f1df5856000016020810190610d119190612d09565b856000016020810190610d249190612d09565b604051610d32929190612ef9565b60405180910390a36000610d59846020016020810190610d529190612c5c565b6000611e17565b905080610daf57836020016020810190610d739190612c5c565b6040517f38c42f9a000000000000000000000000000000000000000000000000000000008152600401610da69190612caa565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16836020016020810190610dda9190612c5c565b73ffffffffffffffffffffffffffffffffffffffff1614610e6c576000610e14846020016020810190610e0d9190612c5c565b6000611e17565b905080610e6a57836020016020810190610e2e9190612c5c565b6040517fd8a749d5000000000000000000000000000000000000000000000000000000008152600401610e619190612caa565b60405180910390fd5b505b50505050565b6000610e7c611e9d565b90506000610e88610f3f565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610efc5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610ef392919061337d565b60405180910390fd5b610f098787878787611ea5565b50505050505050565b60006002600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60007f000000000000000000000000d5b7680f95c5a6caecdbbeb1dee580960c4f891b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd091906133bb565b905090565b6000600160000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff16905090565b6000611012611e9d565b9050600061101e610f3f565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146110925781816040517f078c725900000000000000000000000000000000000000000000000000000000815260040161108992919061337d565b60405180910390fd5b61109d858585611ff1565b5050505050565b6000600360000160009054906101000a900475ffffffffffffffffffffffffffffffffffffffffffff1675ffffffffffffffffffffffffffffffffffffffffffff16905090565b60007f000000000000000000000000d5b7680f95c5a6caecdbbeb1dee580960c4f891b905090565b6000600360000160169054906101000a900467ffffffffffffffff1667ffffffffffffffff16905090565b60007f0000000000000000000000006bb8b45a1c6ea816b70d76f83f7dc4f0f87365ff905090565b6000611170611e9d565b9050600061117c610f3f565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146111f05781816040517f078c72590000000000000000000000000000000000000000000000000000000081526004016111e792919061337d565b60405180910390fd5b6111fe8888888888886120ef565b5050505050505050565b6002600054141561124e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124590613445565b60405180910390fd5b6002600081905550600073ffffffffffffffffffffffffffffffffffffffff166001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156112e2576040517f27438ff100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60004790506000811415611322576040517f851c981300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060036040518060600160405290816000820160009054906101000a900475ffffffffffffffffffffffffffffffffffffffffffff1675ffffffffffffffffffffffffffffffffffffffffffff1675ffffffffffffffffffffffffffffffffffffffffffff1681526020016000820160169054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff16815260200160008201601e9054906101000a900461ffff1661ffff1661ffff168152505090507f000000000000000000000000105d2f6c358d185d1d81a73c1f76a75a2cc500ed73ffffffffffffffffffffffffffffffffffffffff1663678b4ee1868684602001518560400151886040518663ffffffff1660e01b815260040161144a9594939291906134e6565b60006040518083038186803b15801561146257600080fd5b505afa158015611476573d6000803e3d6000fd5b505050506000633b9aca008461148c9190613534565b9050816000015175ffffffffffffffffffffffffffffffffffffffffffff1681846114b7919061358e565b10156114ef576040517fec18f3ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826000015175ffffffffffffffffffffffffffffffffffffffffffff16828561151a919061358e565b61152491906135e4565b90506000600160000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff169050600061271082846115679190613534565b6115719190613647565b8361157c91906135e4565b9050600060028761158d9190613647565b90506000818311156115d75781905081886115a891906135e4565b9250836127106115b891906135e4565b612710836115c69190613534565b6115d09190613647565b94506115e6565b82886115e391906135e4565b90505b87856115f291906135e4565b876000015175ffffffffffffffffffffffffffffffffffffffffffff16611619919061358e565b600360000160006101000a81548175ffffffffffffffffffffffffffffffffffffffffffff021916908375ffffffffffffffffffffffffffffffffffffffffffff16021790555060008073ffffffffffffffffffffffffffffffffffffffff166002600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461173f57612710600260000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff16876116f49190613534565b6116fe9190613647565b9050808461170c91906135e4565b935061173d6002600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682611e17565b505b6117697f0000000000000000000000006bb8b45a1c6ea816b70d76f83f7dc4f0f87365ff85611e17565b506117996001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683611e17565b507fabd2ab552bc04cdbfa4a54107fa44ac8c9cb06f6d21da11933ac05a653be19e98483836040516117cd93929190613678565b60405180910390a15050505050505050506001600081905550505050565b60006117f5611e9d565b90506000611801610f3f565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146118755781816040517f078c725900000000000000000000000000000000000000000000000000000000815260040161186c92919061337d565b60405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff1663dd83edc38686866040518463ffffffff1660e01b81526004016118b2939291906136af565b600060405180830381600087803b1580156118cc57600080fd5b505af11580156118e0573d6000803e3d6000fd5b50505050600047905060008111156119aa5760006118fe8883611e17565b90508015611959578773ffffffffffffffffffffffffffffffffffffffff167f8e274e42262a7f013b700b35c2b4629ccce1702f8fe83f8dfb7eacbb26a4382c8360405161194c919061272d565b60405180910390a26119a8565b8773ffffffffffffffffffffffffffffffffffffffff167fe96418167cc28aef7483feb5e41f0edc3fa107506c9cc1b144ed0336c58b7bdb8360405161199f919061272d565b60405180910390a25b505b50505050505050565b60006119bd611e9d565b905060006001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611a5b5781816040517fa96b080e000000000000000000000000000000000000000000000000000000008152600401611a5292919061337d565b60405180910390fd5b60026000541415611aa1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a9890613445565b60405180910390fd5b600260008190555060004790506000811415611ae9576040517f851c981300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600282611af89190613647565b9050600081905060008284611b0d91906135e4565b90506000600160000160009054906101000a90046bffffffffffffffffffffffff16612710611b3c91906136e1565b6bffffffffffffffffffffffff1661271085611b589190613534565b611b629190613647565b90508481611b7091906135e4565b600360000160009054906101000a900475ffffffffffffffffffffffffffffffffffffffffffff1675ffffffffffffffffffffffffffffffffffffffffffff16611bba919061358e565b600360000160006101000a81548175ffffffffffffffffffffffffffffffffffffffffffff021916908375ffffffffffffffffffffffffffffffffffffffffffff16021790555060008073ffffffffffffffffffffffffffffffffffffffff166002600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611ce057612710600260000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff1683611c959190613534565b611c9f9190613647565b90508083611cad91906135e4565b9250611cde6002600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682611e17565b505b611d0a7f0000000000000000000000006bb8b45a1c6ea816b70d76f83f7dc4f0f87365ff84611e17565b50611d3a6001600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1685611e17565b507fabd2ab552bc04cdbfa4a54107fa44ac8c9cb06f6d21da11933ac05a653be19e9838583604051611d6e93929190613678565b60405180910390a150505050505060016000819055505050565b6000611d9383612240565b8015611da55750611da4838361228d565b5b905092915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6000808373ffffffffffffffffffffffffffffffffffffffff168360045a611e3f9190613647565b90604051611e4c90613746565b600060405180830381858888f193505050503d8060008114611e8a576040519150601f19603f3d011682016040523d82523d6000602084013e611e8f565b606091505b505090508091505092915050565b600033905090565b83600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611f0d576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff1663b88d4fde30878787876040518663ffffffff1660e01b8152600401611f4e9594939291906137aa565b600060405180830381600087803b158015611f6857600080fd5b505af1158015611f7c573d6000803e3d6000fd5b505050508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f958eb1a535a90a0667f75726379cbcb8498dc301be9ba2c585e69907bb3027c9868686604051611fe1939291906137f8565b60405180910390a3505050505050565b81600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612059576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61208483838673ffffffffffffffffffffffffffffffffffffffff1661234c9092919063ffffffff16565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fe8de91d538b06154a2c48315768c5046f47e127d7fd3f726fd85cc723f29b052846040516120e1919061272d565b60405180910390a350505050565b84600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612157576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff1663f242432a3088888888886040518763ffffffff1660e01b815260040161219a9695949392919061382a565b600060405180830381600087803b1580156121b457600080fd5b505af11580156121c8573d6000803e3d6000fd5b505050508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f1c84289b4389ba8251b26974eaec89409eb21a1198ca5eb281c86388da2e778b8787878760405161222f9493929190613886565b60405180910390a350505050505050565b600061226c827f01ffc9a70000000000000000000000000000000000000000000000000000000061228d565b801561228657506122848263ffffffff60e01b61228d565b155b9050919050565b6000806301ffc9a760e01b836040516024016122a991906138d5565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000806000602060008551602087018a617530fa92503d91506000519050828015612334575060208210155b80156123405750600081115b94505050505092915050565b6123cd8363a9059cbb60e01b848460405160240161236b9291906138f0565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506123d2565b505050565b6000612434826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166124999092919063ffffffff16565b905060008151111561249457808060200190518101906124549190613945565b612493576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161248a906139e4565b60405180910390fd5b5b505050565b60606124a884846000856124b1565b90509392505050565b6060824710156124f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124ed90613a76565b60405180910390fd5b6124ff856125c5565b61253e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161253590613ae2565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516125679190613b71565b60006040518083038185875af1925050503d80600081146125a4576040519150601f19603f3d011682016040523d82523d6000602084013e6125a9565b606091505b50915091506125b98282866125e8565b92505050949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b606083156125f857829050612648565b60008351111561260b5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161263f9190613bcc565b60405180910390fd5b9392505050565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61268e81612659565b811461269957600080fd5b50565b6000813590506126ab81612685565b92915050565b6000602082840312156126c7576126c661264f565b5b60006126d58482850161269c565b91505092915050565b60008115159050919050565b6126f3816126de565b82525050565b600060208201905061270e60008301846126ea565b92915050565b6000819050919050565b61272781612714565b82525050565b6000602082019050612742600083018461271e565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061277382612748565b9050919050565b61278381612768565b82525050565b600060208201905061279e600083018461277a565b92915050565b600080fd5b6000604082840312156127bf576127be6127a4565b5b81905092915050565b6000606082840312156127de576127dd6127a4565b5b81905092915050565b600080600060e08486031215612800576127ff61264f565b5b600061280e868287016127a9565b935050604061281f868287016127a9565b9250506080612830868287016127c8565b9150509250925092565b61284381612768565b811461284e57600080fd5b50565b6000813590506128608161283a565b92915050565b61286f81612714565b811461287a57600080fd5b50565b60008135905061288c81612866565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126128b7576128b6612892565b5b8235905067ffffffffffffffff8111156128d4576128d3612897565b5b6020830191508360018202830111156128f0576128ef61289c565b5b9250929050565b6000806000806000608086880312156129135761291261264f565b5b600061292188828901612851565b955050602061293288828901612851565b94505060406129438882890161287d565b935050606086013567ffffffffffffffff81111561296457612963612654565b5b612970888289016128a1565b92509250509295509295909350565b6000806000606084860312156129985761299761264f565b5b60006129a686828701612851565b93505060206129b786828701612851565b92505060406129c88682870161287d565b9150509250925092565b60008060008060008060a087890312156129ef576129ee61264f565b5b60006129fd89828a01612851565b9650506020612a0e89828a01612851565b9550506040612a1f89828a0161287d565b9450506060612a3089828a0161287d565b935050608087013567ffffffffffffffff811115612a5157612a50612654565b5b612a5d89828a016128a1565b92509250509295509295509295565b60008083601f840112612a8257612a81612892565b5b8235905067ffffffffffffffff811115612a9f57612a9e612897565b5b602083019150836020820283011115612abb57612aba61289c565b5b9250929050565b600080600060408486031215612adb57612ada61264f565b5b600084013567ffffffffffffffff811115612af957612af8612654565b5b612b0586828701612a6c565b93509350506020612b188682870161287d565b9150509250925092565b6000612b2d82612748565b9050919050565b612b3d81612b22565b8114612b4857600080fd5b50565b600081359050612b5a81612b34565b92915050565b60008060008060608587031215612b7a57612b7961264f565b5b6000612b8887828801612b4b565b945050602085013567ffffffffffffffff811115612ba957612ba8612654565b5b612bb587828801612a6c565b93509350506040612bc88782880161287d565b91505092959194509250565b6000819050919050565b6000612bf9612bf4612bef84612748565b612bd4565b612748565b9050919050565b6000612c0b82612bde565b9050919050565b6000612c1d82612c00565b9050919050565b612c2d81612c12565b82525050565b6000604082019050612c48600083018561277a565b612c556020830184612c24565b9392505050565b600060208284031215612c7257612c7161264f565b5b6000612c8084828501612b4b565b91505092915050565b6000612c9482612c00565b9050919050565b612ca481612c89565b82525050565b6000602082019050612cbf6000830184612c9b565b92915050565b60006bffffffffffffffffffffffff82169050919050565b612ce681612cc5565b8114612cf157600080fd5b50565b600081359050612d0381612cdd565b92915050565b600060208284031215612d1f57612d1e61264f565b5b6000612d2d84828501612cf4565b91505092915050565b612d3f81612cc5565b82525050565b6000602082019050612d5a6000830184612d36565b92915050565b600067ffffffffffffffff82169050919050565b612d7d81612d60565b8114612d8857600080fd5b50565b600081359050612d9a81612d74565b92915050565b600060208284031215612db657612db561264f565b5b6000612dc484828501612d8b565b91505092915050565b612dd681612d60565b82525050565b6000602082019050612df16000830184612dcd565b92915050565b600061ffff82169050919050565b612e0e81612df7565b8114612e1957600080fd5b50565b600081359050612e2b81612e05565b92915050565b600060208284031215612e4757612e4661264f565b5b6000612e5584828501612e1c565b91505092915050565b612e6781612df7565b82525050565b6000602082019050612e826000830184612e5e565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612ec282612cc5565b9150612ecd83612cc5565b9250826bffffffffffffffffffffffff03821115612eee57612eed612e88565b5b828201905092915050565b6000604082019050612f0e6000830185612d36565b612f1b6020830184612d36565b9392505050565b60008135612f2f81612cdd565b80915050919050565b60008160001b9050919050565b60006bffffffffffffffffffffffff612f5d84612f38565b9350801983169250808416831791505092915050565b6000612f8e612f89612f8484612cc5565b612bd4565b612cc5565b9050919050565b6000819050919050565b612fa882612f73565b612fbb612fb482612f95565b8354612f45565b8255505050565b60008135612fcf81612b34565b80915050919050565b60008160601b9050919050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000061301184612fd8565b9350801983169250808416831791505092915050565b600061303282612bde565b9050919050565b600061304482613027565b9050919050565b6000819050919050565b61305e82613039565b61307161306a8261304b565b8354612fe5565b8255505050565b60008101600083018061308a81612f22565b90506130968184612f9f565b5050506000810160208301806130ab81612fc2565b90506130b78184613055565b5050505050565b6130c88282613078565b5050565b600075ffffffffffffffffffffffffffffffffffffffffffff82169050919050565b6130f7816130cc565b811461310257600080fd5b50565b60008135613112816130ee565b80915050919050565b600075ffffffffffffffffffffffffffffffffffffffffffff61313d84612f38565b9350801983169250808416831791505092915050565b600061316e613169613164846130cc565b612bd4565b6130cc565b9050919050565b6000819050919050565b61318882613153565b61319b61319482613175565b835461311b565b8255505050565b600081356131af81612d74565b80915050919050565b60008160b01b9050919050565b60007dffffffffffffffff000000000000000000000000000000000000000000006131ef846131b8565b9350801983169250808416831791505092915050565b600061322061321b61321684612d60565b612bd4565b612d60565b9050919050565b6000819050919050565b61323a82613205565b61324d61324682613227565b83546131c5565b8255505050565b6000813561326181612e05565b80915050919050565b60008160f01b9050919050565b60007fffff0000000000000000000000000000000000000000000000000000000000006132a38461326a565b9350801983169250808416831791505092915050565b60006132d46132cf6132ca84612df7565b612bd4565b612df7565b9050919050565b6000819050919050565b6132ee826132b9565b6133016132fa826132db565b8354613277565b8255505050565b60008101600083018061331a81613105565b9050613326818461317f565b50505060008101602083018061333b816131a2565b90506133478184613231565b50505060008101604083018061335c81613254565b905061336881846132e5565b5050505050565b6133798282613308565b5050565b6000604082019050613392600083018561277a565b61339f602083018461277a565b9392505050565b6000815190506133b58161283a565b92915050565b6000602082840312156133d1576133d061264f565b5b60006133df848285016133a6565b91505092915050565b600082825260208201905092915050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b600061342f601f836133e8565b915061343a826133f9565b602082019050919050565b6000602082019050818103600083015261345e81613422565b9050919050565b600082825260208201905092915050565b600080fd5b82818337600083830152505050565b60006134968385613465565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156134c9576134c8613476565b5b6020830292506134da83858461347b565b82840190509392505050565b6000608082019050818103600083015261350181878961348a565b90506135106020830186612dcd565b61351d6040830185612e5e565b61352a606083018461271e565b9695505050505050565b600061353f82612714565b915061354a83612714565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561358357613582612e88565b5b828202905092915050565b600061359982612714565b91506135a483612714565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156135d9576135d8612e88565b5b828201905092915050565b60006135ef82612714565b91506135fa83612714565b92508282101561360d5761360c612e88565b5b828203905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061365282612714565b915061365d83612714565b92508261366d5761366c613618565b5b828204905092915050565b600060608201905061368d600083018661271e565b61369a602083018561271e565b6136a7604083018461271e565b949350505050565b600060408201905081810360008301526136ca81858761348a565b90506136d9602083018461271e565b949350505050565b60006136ec82612cc5565b91506136f783612cc5565b92508282101561370a57613709612e88565b5b828203905092915050565b600081905092915050565b50565b6000613730600083613715565b915061373b82613720565b600082019050919050565b600061375182613723565b9150819050919050565b600082825260208201905092915050565b6000601f19601f8301169050919050565b6000613789838561375b565b935061379683858461347b565b61379f8361376c565b840190509392505050565b60006080820190506137bf600083018861277a565b6137cc602083018761277a565b6137d9604083018661271e565b81810360608301526137ec81848661377d565b90509695505050505050565b600060408201905061380d600083018661271e565b818103602083015261382081848661377d565b9050949350505050565b600060a08201905061383f600083018961277a565b61384c602083018861277a565b613859604083018761271e565b613866606083018661271e565b818103608083015261387981848661377d565b9050979650505050505050565b600060608201905061389b600083018761271e565b6138a8602083018661271e565b81810360408301526138bb81848661377d565b905095945050505050565b6138cf81612659565b82525050565b60006020820190506138ea60008301846138c6565b92915050565b6000604082019050613905600083018561277a565b613912602083018461271e565b9392505050565b613922816126de565b811461392d57600080fd5b50565b60008151905061393f81613919565b92915050565b60006020828403121561395b5761395a61264f565b5b600061396984828501613930565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b60006139ce602a836133e8565b91506139d982613972565b604082019050919050565b600060208201905081810360008301526139fd816139c1565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b6000613a606026836133e8565b9150613a6b82613a04565b604082019050919050565b60006020820190508181036000830152613a8f81613a53565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000613acc601d836133e8565b9150613ad782613a96565b602082019050919050565b60006020820190508181036000830152613afb81613abf565b9050919050565b600081519050919050565b60005b83811015613b2b578082015181840152602081019050613b10565b83811115613b3a576000848401525b50505050565b6000613b4b82613b02565b613b558185613715565b9350613b65818560208601613b0d565b80840191505092915050565b6000613b7d8284613b40565b915081905092915050565b600081519050919050565b6000613b9e82613b88565b613ba881856133e8565b9350613bb8818560208601613b0d565b613bc18161376c565b840191505092915050565b60006020820190508181036000830152613be68184613b93565b90509291505056fea2646970667358221220ac95a9781558424f757cfc65d1e29735200e893acfe1b98782cf62ec1f9349e164736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000105d2f6c358d185d1d81a73c1f76a75a2cc500ed000000000000000000000000d5b7680f95c5a6caecdbbeb1dee580960c4f891b0000000000000000000000006bb8b45a1c6ea816b70d76f83f7dc4f0f87365ff
-----Decoded View---------------
Arg [0] : _oracle (address): 0x105D2F6C358d185d1D81a73c1F76a75a2Cc500ed
Arg [1] : _factory (address): 0xd5B7680f95c5A6CAeCdBBEB1DeE580960C4F891b
Arg [2] : _service (address): 0x6Bb8b45a1C6eA816B70d76f83f7dC4f0f87365Ff
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000105d2f6c358d185d1d81a73c1f76a75a2cc500ed
Arg [1] : 000000000000000000000000d5b7680f95c5a6caecdbbeb1dee580960c4f891b
Arg [2] : 0000000000000000000000006bb8b45a1c6ea816b70d76f83f7dc4f0f87365ff
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.