Source Code
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
FeeRecipient
Compiler Version
v0.8.13+commit.abaa5c0e
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.10;
import "./interfaces/IFeeDispatcher.sol";
contract FeeRecipient {
/// @notice Constructor replay prevention
bool internal initialized;
/// @notice Address where funds are sent to be dispatched
IFeeDispatcher internal dispatcher;
/// @notice Public Key root assigned to this receiver
bytes32 internal publicKeyRoot;
error AlreadyInitialized();
/// @notice Initializes the receiver
/// @param _dispatcher Address that will handle the fee dispatching
/// @param _publicKeyRoot Public Key root assigned to this receiver
function init(address _dispatcher, bytes32 _publicKeyRoot) external {
if (initialized) {
revert AlreadyInitialized();
}
initialized = true;
dispatcher = IFeeDispatcher(_dispatcher);
publicKeyRoot = _publicKeyRoot;
}
/// @notice Empty calldata fallback
receive() external payable {}
/// @notice Non-empty calldata fallback
fallback() external payable {}
/// @notice Triggers a withdrawal by sending its funds + its public key root to the dispatcher
/// @dev Can be called by any wallet as recipients are not parameters
function withdraw() external {
dispatcher.dispatch{value: address(this).balance}(publicKeyRoot);
}
/// @notice Retrieve the assigned public key root
function getPublicKeyRoot() external view returns (bytes32) {
return publicKeyRoot;
}
/// @notice retrieve the assigned withdrawer
function getWithdrawer() external view returns (address) {
return dispatcher.getWithdrawer(publicKeyRoot);
}
}//SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.10;
import "./libs/DispatchersStorageLib.sol";
import "./interfaces/IStakingContractFeeDetails.sol";
import "./interfaces/IFeeDispatcher.sol";
/// @title Consensus Layer Fee Recipient
/// @author Kiln
/// @notice This contract can be used to receive fees from a validator and split them with a node operator
contract ConsensusLayerFeeDispatcher is IFeeDispatcher {
using DispatchersStorageLib for bytes32;
event Withdrawal(
address indexed withdrawer,
address indexed feeRecipient,
bytes32 pubKeyRoot,
uint256 rewards,
uint256 nodeOperatorFee,
uint256 treasuryFee
);
error TreasuryReceiveError(bytes errorData);
error FeeRecipientReceiveError(bytes errorData);
error WithdrawerReceiveError(bytes errorData);
error ZeroBalanceWithdrawal();
error AlreadyInitialized();
error InvalidCall();
error NotImplemented();
bytes32 internal constant STAKING_CONTRACT_ADDRESS_SLOT =
keccak256("ConsensusLayerFeeRecipient.stakingContractAddress");
uint256 internal constant BASIS_POINTS = 10_000;
bytes32 internal constant VERSION_SLOT = keccak256("ConsensusLayerFeeRecipient.version");
/// @notice Ensures an initialisation call has been called only once per _version value
/// @param _version The current initialisation value
modifier init(uint256 _version) {
if (_version != VERSION_SLOT.getUint256() + 1) {
revert AlreadyInitialized();
}
VERSION_SLOT.setUint256(_version);
_;
}
/// @notice Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version
constructor(uint256 _version) {
VERSION_SLOT.setUint256(_version);
}
/// @notice Initialize the contract by storing the staking contract
/// @param _stakingContract Address of the Staking Contract
function initCLD(address _stakingContract) external init(1) {
STAKING_CONTRACT_ADDRESS_SLOT.setAddress(_stakingContract);
}
/// @notice Performs a withdrawal on this contract's balance
function dispatch(bytes32) external payable {
revert NotImplemented();
/*
uint256 balance = address(this).balance; // this has taken into account msg.value
if (balance == 0) {
revert ZeroBalanceWithdrawal();
}
IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(
STAKING_CONTRACT_ADDRESS_SLOT.getAddress()
);
address withdrawer = stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);
address operator = stakingContract.getOperatorFeeRecipient(_publicKeyRoot);
address treasury = stakingContract.getTreasury();
uint256 globalFee;
if (balance >= 32 ether) {
// withdrawing a healthy & exited validator
globalFee = ((balance - 32 ether) * stakingContract.getGlobalFee()) / BASIS_POINTS;
} else if (balance <= 16 ether) {
// withdrawing from what looks like skimming
globalFee = (balance * stakingContract.getGlobalFee()) / BASIS_POINTS;
}
uint256 operatorFee = (globalFee * stakingContract.getOperatorFee()) / BASIS_POINTS;
(bool status, bytes memory data) = withdrawer.call{value: balance - globalFee}("");
if (status == false) {
revert WithdrawerReceiveError(data);
}
if (globalFee > 0) {
(status, data) = treasury.call{value: globalFee - operatorFee}("");
if (status == false) {
revert FeeRecipientReceiveError(data);
}
}
if (operatorFee > 0) {
(status, data) = operator.call{value: operatorFee}("");
if (status == false) {
revert TreasuryReceiveError(data);
}
}
emit Withdrawal(withdrawer, operator, balance - globalFee, operatorFee, globalFee - operatorFee);
*/
}
/// @notice Retrieve the staking contract address
function getStakingContract() external view returns (address) {
return STAKING_CONTRACT_ADDRESS_SLOT.getAddress();
}
/// @notice Retrieve the assigned withdrawer for the given public key root
/// @param _publicKeyRoot Public key root to get the owner
function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address) {
IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(
STAKING_CONTRACT_ADDRESS_SLOT.getAddress()
);
return stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);
}
receive() external payable {
revert InvalidCall();
}
fallback() external payable {
revert InvalidCall();
}
}//SPDX-License-Identifier: MIT
pragma solidity >=0.8.10;
library DispatchersStorageLib {
function getUint256(bytes32 position) internal view returns (uint256 data) {
assembly {
data := sload(position)
}
}
function setUint256(bytes32 position, uint256 data) internal {
assembly {
sstore(position, data)
}
}
function getAddress(bytes32 position) internal view returns (address data) {
assembly {
data := sload(position)
}
}
function setAddress(bytes32 position, address data) internal {
assembly {
sstore(position, data)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.10;
interface IStakingContractFeeDetails {
function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address);
function getTreasury() external view returns (address);
function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address);
function getGlobalFee() external view returns (uint256);
function getOperatorFee() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.10;
interface IFeeDispatcher {
function dispatch(bytes32 _publicKeyRoot) external payable;
function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address);
}//SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.10;
import "./libs/DispatchersStorageLib.sol";
import "./interfaces/IStakingContractFeeDetails.sol";
import "./interfaces/IFeeDispatcher.sol";
/// @title Execution Layer Fee Recipient
/// @author Kiln
/// @notice This contract can be used to receive fees from a validator and split them with a node operator
contract ExecutionLayerFeeDispatcher is IFeeDispatcher {
using DispatchersStorageLib for bytes32;
event Withdrawal(
address indexed withdrawer,
address indexed feeRecipient,
bytes32 pubKeyRoot,
uint256 rewards,
uint256 nodeOperatorFee,
uint256 treasuryFee
);
error TreasuryReceiveError(bytes errorData);
error FeeRecipientReceiveError(bytes errorData);
error WithdrawerReceiveError(bytes errorData);
error ZeroBalanceWithdrawal();
error AlreadyInitialized();
error InvalidCall();
bytes32 internal constant STAKING_CONTRACT_ADDRESS_SLOT =
keccak256("ExecutionLayerFeeRecipient.stakingContractAddress");
uint256 internal constant BASIS_POINTS = 10_000;
bytes32 internal constant VERSION_SLOT = keccak256("ExecutionLayerFeeRecipient.version");
/// @notice Ensures an initialisation call has been called only once per _version value
/// @param _version The current initialisation value
modifier init(uint256 _version) {
if (_version != VERSION_SLOT.getUint256() + 1) {
revert AlreadyInitialized();
}
VERSION_SLOT.setUint256(_version);
_;
}
/// @notice Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version
constructor(uint256 _version) {
VERSION_SLOT.setUint256(_version);
}
/// @notice Initialize the contract by storing the staking contract and the public key in storage
/// @param _stakingContract Address of the Staking Contract
function initELD(address _stakingContract) external init(1) {
STAKING_CONTRACT_ADDRESS_SLOT.setAddress(_stakingContract);
}
/// @notice Performs a withdrawal on this contract's balance
function dispatch(bytes32 _publicKeyRoot) external payable {
uint256 balance = address(this).balance;
if (balance == 0) {
revert ZeroBalanceWithdrawal();
}
IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(
STAKING_CONTRACT_ADDRESS_SLOT.getAddress()
);
address withdrawer = stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);
address operator = stakingContract.getOperatorFeeRecipient(_publicKeyRoot);
address treasury = stakingContract.getTreasury();
uint256 globalFee = (balance * stakingContract.getGlobalFee()) / BASIS_POINTS;
uint256 operatorFee = (globalFee * stakingContract.getOperatorFee()) / BASIS_POINTS;
(bool status, bytes memory data) = withdrawer.call{value: balance - globalFee}("");
if (status == false) {
revert WithdrawerReceiveError(data);
}
if (globalFee > 0) {
(status, data) = treasury.call{value: globalFee - operatorFee}("");
if (status == false) {
revert FeeRecipientReceiveError(data);
}
}
if (operatorFee > 0) {
(status, data) = operator.call{value: operatorFee}("");
if (status == false) {
revert TreasuryReceiveError(data);
}
}
emit Withdrawal(
withdrawer,
operator,
_publicKeyRoot,
balance - globalFee,
operatorFee,
globalFee - operatorFee
);
}
/// @notice Retrieve the staking contract address
function getStakingContract() external view returns (address) {
return STAKING_CONTRACT_ADDRESS_SLOT.getAddress();
}
/// @notice Retrieve the assigned withdrawer for the given public key root
/// @param _publicKeyRoot Public key root to get the owner
function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address) {
IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(
STAKING_CONTRACT_ADDRESS_SLOT.getAddress()
);
return stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);
}
receive() external payable {
revert InvalidCall();
}
fallback() external payable {
revert InvalidCall();
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"getPublicKeyRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_dispatcher","type":"address"},{"internalType":"bytes32","name":"_publicKeyRoot","type":"bytes32"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
608060405234801561001057600080fd5b506102a3806100206000396000f3fe6080604052600436106100405760003560e01c80632cc0b254146100495780633ccfd60b146100695780637d38d21f1461007e5780637f763702146100b057005b3661004757005b005b34801561005557600080fd5b5061004761006436600461021d565b6100ce565b34801561007557600080fd5b50610047610120565b34801561008a57600080fd5b5061009361018a565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100bc57600080fd5b506001546040519081526020016100a7565b60005460ff16156100f15760405162dc149f60e41b815260040160405180910390fd5b600080546001600160a01b03909316610100026001600160a81b03199093169290921760019081179092559055565b600054600154604051630ce1206560e41b815260048101919091526101009091046001600160a01b03169063ce1206509047906024016000604051808303818588803b15801561016f57600080fd5b505af1158015610183573d6000803e3d6000fd5b5050505050565b600080546001546040516313ef480b60e11b815260048101919091526101009091046001600160a01b0316906327de901690602401602060405180830381865afa1580156101dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102009190610249565b905090565b6001600160a01b038116811461021a57600080fd5b50565b6000806040838503121561023057600080fd5b823561023b81610205565b946020939093013593505050565b60006020828403121561025b57600080fd5b815161026681610205565b939250505056fea26469706673582212208eb3032a325d9c07889449598ba3999e3438d216376d0fb3031dbfbf383d522964736f6c634300080d0033
Deployed Bytecode
0x6080604052600436106100405760003560e01c80632cc0b254146100495780633ccfd60b146100695780637d38d21f1461007e5780637f763702146100b057005b3661004757005b005b34801561005557600080fd5b5061004761006436600461021d565b6100ce565b34801561007557600080fd5b50610047610120565b34801561008a57600080fd5b5061009361018a565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100bc57600080fd5b506001546040519081526020016100a7565b60005460ff16156100f15760405162dc149f60e41b815260040160405180910390fd5b600080546001600160a01b03909316610100026001600160a81b03199093169290921760019081179092559055565b600054600154604051630ce1206560e41b815260048101919091526101009091046001600160a01b03169063ce1206509047906024016000604051808303818588803b15801561016f57600080fd5b505af1158015610183573d6000803e3d6000fd5b5050505050565b600080546001546040516313ef480b60e11b815260048101919091526101009091046001600160a01b0316906327de901690602401602060405180830381865afa1580156101dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102009190610249565b905090565b6001600160a01b038116811461021a57600080fd5b50565b6000806040838503121561023057600080fd5b823561023b81610205565b946020939093013593505050565b60006020828403121561025b57600080fd5b815161026681610205565b939250505056fea26469706673582212208eb3032a325d9c07889449598ba3999e3438d216376d0fb3031dbfbf383d522964736f6c634300080d0033
Deployed Bytecode Sourcemap
106:1569:2:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;626:271;;;;;;;;;;-1:-1:-1;626:271:2;;;;;:::i;:::-;;:::i;1231:110::-;;;;;;;;;;;;;:::i;1553:120::-;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;634:32:6;;;616:51;;604:2;589:18;1553:120:2;;;;;;;;1401:97;;;;;;;;;;-1:-1:-1;1478:13:2;;1401:97;;824:25:6;;;812:2;797:18;1401:97:2;678:177:6;626:271:2;708:11;;;;704:69;;;742:20;;-1:-1:-1;;;742:20:2;;;;;;;;;;;704:69;782:11;:18;;-1:-1:-1;;;;;810:40:2;;;782:18;810:40;-1:-1:-1;;;;;;810:40:2;;;;;;;796:4;810:40;;;;;;860:30;;626:271::o;1231:110::-;1270:10;;;1320:13;1270:64;;-1:-1:-1;;;1270:64:2;;;;;824:25:6;;;;1270:10:2;;;;-1:-1:-1;;;;;1270:10:2;;:19;;1297:21;;797:18:6;;1270:64:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1231:110::o;1553:120::-;1601:7;1627:10;;;1652:13;1627:39;;-1:-1:-1;;;1627:39:2;;;;;824:25:6;;;;1627:10:2;;;;-1:-1:-1;;;;;1627:10:2;;:24;;797:18:6;;1627:39:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1620:46;;1553:120;:::o;14:131:6:-;-1:-1:-1;;;;;89:31:6;;79:42;;69:70;;135:1;132;125:12;69:70;14:131;:::o;150:315::-;218:6;226;279:2;267:9;258:7;254:23;250:32;247:52;;;295:1;292;285:12;247:52;334:9;321:23;353:31;378:5;353:31;:::i;:::-;403:5;455:2;440:18;;;;427:32;;-1:-1:-1;;;150:315:6:o;860:251::-;930:6;983:2;971:9;962:7;958:23;954:32;951:52;;;999:1;996;989:12;951:52;1031:9;1025:16;1050:31;1075:5;1050:31;:::i;:::-;1100:5;860:251;-1:-1:-1;;;860:251:6:o
Swarm Source
ipfs://8eb3032a325d9c07889449598ba3999e3438d216376d0fb3031dbfbf383d5229
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.