// 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-License-Identifier: CC0-1.0
pragma solidity 0.8.10;
// This interface is designed to be compatible with the Vyper version.
/// @notice This is the Ethereum 2.0 deposit contract interface.
/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
interface IDepositContract {
/// @notice A processed deposit event.
event DepositEvent(
bytes pubkey,
bytes withdrawal_credentials,
bytes amount,
bytes signature,
bytes index
);
/// @notice Submit a Phase 0 DepositData object.
/// @param pubkey A BLS12-381 public key.
/// @param withdrawal_credentials Commitment to a public key for withdrawals.
/// @param signature A BLS12-381 signature.
/// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
/// Used as a protection against malformed input.
function deposit(
bytes calldata pubkey,
bytes calldata withdrawal_credentials,
bytes calldata signature,
bytes32 deposit_data_root
) external payable;
/// @notice Query the current deposit root hash.
/// @return The deposit root hash.
function get_deposit_root() external view returns (bytes32);
/// @notice Query the current deposit count.
/// @return The deposit count encoded as a little endian 64-bit number.
function get_deposit_count() external view returns (bytes memory);
}
// 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 <info@p2p.org>
// 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 <info@p2p.org>
// 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 <info@p2p.org>
// 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 <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "../@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../feeDistributor/IFeeDistributor.sol";
/**
* @dev External interface of P2pEth2Depositor declared to support ERC165 detection.
*/
interface IP2pEth2Depositor is IERC165 {
// Events
/**
* @notice Emits when a new batch deposit has been made successfully
* @param _from the address of the depositor
* @param _newFeeDistributorAddress user FeeDistributor instance that has just been deployed
* @param _firstValidatorId validator Id (number of all deposits previously made to ETH2 DepositContract plus 1)
* @param _validatorCount number of ETH2 deposits made with 1 P2pEth2Depositor's deposit
*/
event P2pEth2DepositEvent(
address indexed _from,
address indexed _newFeeDistributorAddress,
uint64 indexed _firstValidatorId,
uint256 _validatorCount
);
/**
* @dev Function that allows to deposit up to 1000 nodes at once.
*
* - pubkeys - Array of BLS12-381 public keys.
* - withdrawal_credentials - Array of commitments to a public keys for withdrawals.
* - signatures - Array of BLS12-381 signatures.
* - deposit_data_roots - Array of the SHA-256 hashes of the SSZ-encoded DepositData objects.
*/
function deposit(
bytes[] calldata pubkeys,
bytes calldata withdrawal_credentials, // 1, same for all
bytes[] calldata signatures,
bytes32[] calldata deposit_data_roots,
IFeeDistributor.FeeRecipient calldata _clientConfig,
IFeeDistributor.FeeRecipient calldata _referrerConfig
) external payable;
}
// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "../@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import "../@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "./interfaces/IDepositContract.sol";
import "../feeDistributorFactory/IFeeDistributorFactory.sol";
import "./IP2pEth2Depositor.sol";
/**
* @notice Should be a FeeDistributorFactory contract
* @param _passedAddress passed address that does not support IFeeDistributorFactory interface
*/
error P2pEth2Depositor__NotFactory(address _passedAddress);
/**
* @notice do not send ETH directly here
*/
error P2pEth2Depositor__DoNotSendEthDirectlyHere();
/**
* @notice you can deposit only 1 to 400 validators per transaction
*/
error P2pEth2Depositor__ValidatorCountError();
/**
* @notice the amount of ETH does not match the amount of validators
*/
error P2pEth2Depositor__EtherValueError();
/**
* @notice amount of parameters do no match
*/
error P2pEth2Depositor__AmountOfParametersError();
/**
* @title Batch deposit contract
* @dev Makes up to 400 ETH2 DepositContract calls within 1 transaction
* @dev Create a FeeDistributor instance (1 for batch)
*/
contract P2pEth2Depositor is ERC165, IP2pEth2Depositor {
/**
* @dev 400 deposits (12800 ETH) is determined by calldata size limit of 128 kb
* @dev https://ethereum.stackexchange.com/questions/144120/maximum-calldata-size-per-block
*/
uint256 public constant validatorsMaxAmount = 400;
/**
* @dev Collateral size of one node.
*/
uint256 public constant collateral = 32 ether;
/**
* @dev Eth2 Deposit Contract address.
*/
IDepositContract public immutable i_depositContract;
/**
* @dev Factory for cloning (EIP-1167) FeeDistributor instances pre client
*/
IFeeDistributorFactory public immutable i_feeDistributorFactory;
/**
* @dev Setting Eth2 Smart Contract address during construction.
*/
constructor(bool _mainnet, address _depositContract, address _feeDistributorFactory) {
if (!ERC165Checker.supportsInterface(_feeDistributorFactory, type(IFeeDistributorFactory).interfaceId)) {
revert P2pEth2Depositor__NotFactory(_feeDistributorFactory);
}
i_depositContract = _mainnet
? IDepositContract(0x00000000219ab540356cBB839Cbe05303d7705Fa) // real Mainnet DepositContract
: (_depositContract == 0x0000000000000000000000000000000000000000)
? IDepositContract(0xff50ed3d0ec03aC01D4C79aAd74928BFF48a7b2b) // real Goerli DepositContract
: IDepositContract(_depositContract);
i_feeDistributorFactory = IFeeDistributorFactory(_feeDistributorFactory);
}
/**
* @dev This contract will not accept direct ETH transactions.
*/
receive() external payable {
revert P2pEth2Depositor__DoNotSendEthDirectlyHere();
}
/**
* @notice Function that allows to deposit up to 400 validators at once.
*
* @dev In _clientConfig, recipient is mandatory.
* @dev In _clientConfig, basisPoints can be 0, defaultClientBasisPoints from FeeDistributorFactory will be applied in that case.
* @dev In _referrerConfig, both recipient and basisPoints can be 0 if there is no referrer.
*
* @param _pubkeys Array of BLS12-381 public keys.
* @param _withdrawal_credentials Commitment to a public keys for withdrawals. 1, same for all
* @param _signatures Array of BLS12-381 signatures.
* @param _deposit_data_roots Array of the SHA-256 hashes of the SSZ-encoded DepositData objects.
* @param _clientConfig Address and basis points (percent * 100) of the client
* @param _referrerConfig Address and basis points (percent * 100) of the referrer.
*/
function deposit(
bytes[] calldata _pubkeys,
bytes calldata _withdrawal_credentials, // 1, same for all
bytes[] calldata _signatures,
bytes32[] calldata _deposit_data_roots,
IFeeDistributor.FeeRecipient calldata _clientConfig,
IFeeDistributor.FeeRecipient calldata _referrerConfig
) external payable {
uint256 validatorCount = _pubkeys.length;
if (validatorCount == 0 || validatorCount > validatorsMaxAmount) {
revert P2pEth2Depositor__ValidatorCountError();
}
if (msg.value != collateral * validatorCount) {
revert P2pEth2Depositor__EtherValueError();
}
if (!(
_signatures.length == validatorCount &&
_deposit_data_roots.length == validatorCount
)) {
revert P2pEth2Depositor__AmountOfParametersError();
}
uint64 firstValidatorId = toUint64(i_depositContract.get_deposit_count()) + 1;
for (uint256 i = 0; i < validatorCount;) {
// pubkey, withdrawal_credentials, signature lengths are already checked inside ETH DepositContract
i_depositContract.deposit{value : collateral}(
_pubkeys[i],
_withdrawal_credentials,
_signatures[i],
_deposit_data_roots[i]
);
// An array can't have a total length
// larger than the max uint256 value.
unchecked {
++i;
}
}
// First, make sure all the deposits are successful, then deploy FeeDistributor
address newFeeDistributorAddress = i_feeDistributorFactory.createFeeDistributor(
_clientConfig,
_referrerConfig,
IFeeDistributor.ValidatorData({
clientOnlyClRewards : 0,
firstValidatorId : firstValidatorId,
validatorCount : uint16(validatorCount)
})
);
emit P2pEth2DepositEvent(msg.sender, newFeeDistributorAddress, firstValidatorId, validatorCount);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IP2pEth2Depositor).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Convert deposit_count from ETH2 DepositContract to uint64
* ETH2 DepositContract returns inverted bytes. Need to invert them back.
*/
function toUint64(bytes memory b) internal pure returns (uint64) {
uint64 result;
assembly {
let x := mload(add(b, 8))
result := or(
or (
or(
and(0xff, shr(56, x)),
and(0xff00, shr(40, x))
),
or(
and(0xff0000, shr(24, x)),
and(0xff000000, shr(8, x))
)
),
or (
or(
and(0xff00000000, shl(8, x)),
and(0xff0000000000, shl(24, x))
),
or(
and(0xff000000000000, shl(40, x)),
and(0xff00000000000000, shl(56, x))
)
)
)
}
return result;
}
}
{
"compilationTarget": {
"contracts/p2pEth2Depositor/P2pEth2Depositor.sol": "P2pEth2Depositor"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"bool","name":"_mainnet","type":"bool"},{"internalType":"address","name":"_depositContract","type":"address"},{"internalType":"address","name":"_feeDistributorFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"P2pEth2Depositor__AmountOfParametersError","type":"error"},{"inputs":[],"name":"P2pEth2Depositor__DoNotSendEthDirectlyHere","type":"error"},{"inputs":[],"name":"P2pEth2Depositor__EtherValueError","type":"error"},{"inputs":[{"internalType":"address","name":"_passedAddress","type":"address"}],"name":"P2pEth2Depositor__NotFactory","type":"error"},{"inputs":[],"name":"P2pEth2Depositor__ValidatorCountError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_newFeeDistributorAddress","type":"address"},{"indexed":true,"internalType":"uint64","name":"_firstValidatorId","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"_validatorCount","type":"uint256"}],"name":"P2pEth2DepositEvent","type":"event"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_pubkeys","type":"bytes[]"},{"internalType":"bytes","name":"_withdrawal_credentials","type":"bytes"},{"internalType":"bytes[]","name":"_signatures","type":"bytes[]"},{"internalType":"bytes32[]","name":"_deposit_data_roots","type":"bytes32[]"},{"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"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"i_depositContract","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"i_feeDistributorFactory","outputs":[{"internalType":"contract IFeeDistributorFactory","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":[],"name":"validatorsMaxAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]