More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 151 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer | 21459562 | 7 days ago | IN | 0.02877294 ETH | 0.00016124 | ||||
Transfer | 21435365 | 10 days ago | IN | 0.06753359 ETH | 0.00026684 | ||||
Withdraw | 21413467 | 13 days ago | IN | 0 ETH | 0.00069841 | ||||
Transfer | 21399940 | 15 days ago | IN | 0.02615483 ETH | 0.00020473 | ||||
Transfer | 21391760 | 16 days ago | IN | 0.02794492 ETH | 0.00029785 | ||||
Transfer | 21389667 | 16 days ago | IN | 0.05961256 ETH | 0.0003372 | ||||
Transfer | 21386620 | 17 days ago | IN | 0.40004059 ETH | 0.00058038 | ||||
Transfer | 21380905 | 17 days ago | IN | 0.06588253 ETH | 0.00056287 | ||||
Transfer | 21373262 | 19 days ago | IN | 0.03512329 ETH | 0.00164783 | ||||
Transfer | 21370901 | 19 days ago | IN | 0.02378162 ETH | 0.00034429 | ||||
Withdraw | 21308435 | 28 days ago | IN | 0 ETH | 0.00158005 | ||||
Transfer | 21298828 | 29 days ago | IN | 0.07609028 ETH | 0.00018749 | ||||
Transfer | 21285386 | 31 days ago | IN | 0.03961774 ETH | 0.00017213 | ||||
Withdraw | 21195672 | 43 days ago | IN | 0 ETH | 0.00232058 | ||||
Transfer | 21162341 | 48 days ago | IN | 0.08210409 ETH | 0.00040165 | ||||
Transfer | 21125868 | 53 days ago | IN | 0.10884951 ETH | 0.00179283 | ||||
Withdraw | 21085375 | 59 days ago | IN | 0 ETH | 0.00056606 | ||||
Transfer | 21082134 | 59 days ago | IN | 0.02456412 ETH | 0.00024823 | ||||
Transfer | 21056213 | 63 days ago | IN | 0.03622178 ETH | 0.00018103 | ||||
Transfer | 20977693 | 74 days ago | IN | 0.05481268 ETH | 0.00031832 | ||||
Withdraw | 20970421 | 75 days ago | IN | 0 ETH | 0.00094 | ||||
Transfer | 20908106 | 84 days ago | IN | 0.038557 ETH | 0.00019958 | ||||
Transfer | 20884783 | 87 days ago | IN | 0.06620274 ETH | 0.00011434 | ||||
Transfer | 20872370 | 88 days ago | IN | 0.1254364 ETH | 0.00068784 | ||||
Transfer | 20867158 | 89 days ago | IN | 0.01832453 ETH | 0.00013537 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
21413467 | 13 days ago | 0.31927019 ETH | ||||
21413467 | 13 days ago | 0.31927019 ETH | ||||
21308435 | 28 days ago | 0.05785401 ETH | ||||
21308435 | 28 days ago | 0.05785401 ETH | ||||
21195672 | 43 days ago | 0.0954768 ETH | ||||
21195672 | 43 days ago | 0.0954768 ETH | ||||
21085375 | 59 days ago | 0.05779929 ETH | ||||
21085375 | 59 days ago | 0.05779929 ETH | ||||
20970421 | 75 days ago | 0.12426034 ETH | ||||
20970421 | 75 days ago | 0.12426034 ETH | ||||
20864556 | 90 days ago | 0.0262934 ETH | ||||
20864556 | 90 days ago | 0.0262934 ETH | ||||
20762205 | 104 days ago | 0.08386411 ETH | ||||
20762205 | 104 days ago | 0.08386411 ETH | ||||
20655593 | 119 days ago | 0.02636901 ETH | ||||
20655593 | 119 days ago | 0.02636901 ETH | ||||
20536465 | 135 days ago | 0.11817611 ETH | ||||
20536465 | 135 days ago | 0.11817611 ETH | ||||
20429154 | 150 days ago | 0.11049551 ETH | ||||
20429154 | 150 days ago | 0.11049551 ETH | ||||
20310414 | 167 days ago | 0.15755632 ETH | ||||
20310414 | 167 days ago | 0.15755632 ETH | ||||
20204312 | 182 days ago | 0.05982872 ETH | ||||
20204312 | 182 days ago | 0.05982872 ETH | ||||
20106801 | 195 days ago | 0.07721102 ETH |
Loading...
Loading
Minimal Proxy Contract for 0xc4aed615614f26c8df4eaaf4a1caea9184aeb3de
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": {} }
[{"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"}]
Latest 13 blocks produced
Block | Transaction | Difficulty | Gas Used | Reward | |
---|---|---|---|---|---|
20521480 | 137 days ago | 148 | 0.00 TH | 13,360,938 (44.54%) | 0.024976781913924748 ETH |
20425267 | 151 days ago | 174 | 0.00 TH | 17,860,320 (59.53%) | 0.055064249569702148 ETH |
19583206 | 269 days ago | 389 | 0.00 TH | 28,327,041 (94.42%) | 0.048456557924526557 ETH |
19424729 | 291 days ago | 205 | 0.00 TH | 17,495,671 (58.32%) | 0.045547039904501863 ETH |
18710418 | 391 days ago | 112 | 0.00 TH | 10,830,478 (36.10%) | 0.024544625293885498 ETH |
18681846 | 395 days ago | 142 | 0.00 TH | 12,512,933 (41.71%) | 0.325249584000047428 ETH |
18509892 | 419 days ago | 114 | 0.00 TH | 11,436,453 (38.12%) | 0.050265499846175894 ETH |
17769062 | 523 days ago | 136 | 0.00 TH | 21,355,252 (71.18%) | 0.057155001267869102 ETH |
17721769 | 529 days ago | 166 | 0.00 TH | 11,920,782 (39.74%) | 0.033601659286578915 ETH |
17625633 | 543 days ago | 103 | 0.00 TH | 12,748,601 (42.50%) | 0.06113453983730037 ETH |
17621272 | 544 days ago | 208 | 0.00 TH | 14,347,352 (47.82%) | 0.043264698130801526 ETH |
17593226 | 548 days ago | 283 | 0.00 TH | 20,926,935 (69.76%) | 0.077146889370020654 ETH |
17475554 | 564 days ago | 112 | 0.00 TH | 10,652,206 (35.51%) | 0.039519024794787848 ETH |
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | Ether (ETH) | 100.00% | $3,356.48 | 0.0963 | $323.25 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.